0

So I'm receiving the error,

_tkinter.TclError: can not find channel named "stdout"

by running this code:

from tkinter import Tcl

tcl = Tcl()
tcl.eval('''
puts hello
''') 

For others it seems to work. I wonder if it is because I'm on windows and the distinction between console and gui application ? An interesting approach that I have found in a book, where they state it is possible to have a console and a window at the same time via console show, but this got me into another error:

_tkinter.TclError: invalid command name "console"

How to fix this ?

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • here they provide a lot of information that should help you: https://stackoverflow.com/questions/41266226/getting-can-not-find-channel-named-stdout-error-while-using-c-sharp-wpf – user13322060 Nov 25 '22 at 11:31
  • @user13322060 thanks, but I already saw that and came to the conclusion it isn't related to my issue. In the linked question they load the dll's for themselves, things that come already with python. So I searched further and found out that it is actually possible with python and the proof of concept is linked above. – Thingamabobs Nov 25 '22 at 11:40
  • How are you launching Python? Windows has a distinction between different types of application that affects how standard channels are made. – Donal Fellows Nov 25 '22 at 12:30
  • @DonalFellows via IDLE, the standard code editor/IDE of python. I thought about that, but I'm actually not fully aware of the technical meaning and or implementation of it, even if I did researched it in the past. – Thingamabobs Nov 25 '22 at 12:33
  • It matters because `pythonw` behaves quite differently to `python` in relation to interaction with consoles (much as `wish` and `tclsh` behave differently for Tcl programmers). Other platforms basically don't have the difference that's adapting to (and signal whether things are running from a command line in other ways). – Donal Fellows Nov 25 '22 at 13:58
  • @DonalFellows While I still don't know why the [stdout](https://docs.python.org/3/library/sys.html#sys.stdin) differ from each other, I've found a sufficient work around. BTW, thanks for your time and service. Is there by any chance something like a nonofficial release date for tkinter 8.7? I know it is in alpha state for tcl and I'm looking forward to use it in python. Or is there something like a prebuilt or something that can be used, didn't found a hint online yet. – Thingamabobs Nov 26 '22 at 02:38

1 Answers1

0

I have found a sufficient solutions by combining two of Bryan's outstanding answers and the tutorial that I watch. To summarize the code below:

  1. wrap a python function into a tcl proc via register
  2. overwrite the tcl puts command
  3. take a list as input and join the items with empty space between
  4. call the wrapped python function in tcl by its name returned by register

from tkinter import Tcl


tcl = Tcl()
cmd = tcl.register(lambda inp:print(inp))
tcl.eval(
    'proc puts {args} {' +
        f'{cmd} [join $args " "]' +
    '}')

tcl.eval('puts "hello"') 

Note: Whitespace is a styling choice and has no effect in this code. Only important thing to note is the f-string (formatted string). This needs to be encapsulated due the curly barces, otherwise tcl interprets it as list or python's format string protest about the curly braces.

For clarification a normal function is used in the code below:

from tkinter import Tcl

def puts(inp):
    print(inp)

tcl = Tcl()
cmd = tcl.register(puts)
tcl.eval(
    'proc puts {args} {' +
        f'{cmd} [join $args " "]' +
    '}')

tcl.eval('puts "hello, world"')

For gets you can do the same, but at exit it might throw an error because the interpreter can't close a connection to a function, as it expects a socket/file descriptor. Anyway, for playground:

def gets():
    return input()

cmd = tcl.register(gets)
tcl.tk.eval(
    'proc gets {} {' +
        f'{cmd}' +
    '}')
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54