Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Lib/test/test_tkinter/test_stdin_pipe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import unittest
import subprocess
import sys
from test import support
from test.support import import_helper

tkinter = import_helper.import_module("tkinter")


@unittest.skipUnless(support.has_subprocess_support, "test requires subprocess")
class TkStdinPipe(unittest.TestCase):

def test_pipe_stdin(self):
proc = subprocess.Popen([sys.executable, "-i"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
proc.stdin.write(b"import tkinter\n")
proc.stdin.write(b"interpreter = tkinter.Tcl()\n")
proc.stdin.write(b"print('hello')\n")
proc.stdin.write(b"quit()\n")

stdout, stderr = proc.communicate()
stdout = stdout.decode()
stderr = stderr.decode()

if proc.returncode != 0:
self.fail(f"Child exited with {proc.returncode}\nSTDOUT:\n{out}\nSTDERR:\n{err}")

self.assertEqual(stdout.rstrip(), "hello")


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Replaces ``Tcl_CreateFileHandler`` in the ``EventHook`` function in ``Modules/_tkinter.c`` by ``Tcl_CreateChannelHandler``, as the former is Unix-specific and the latter is platform-independent. This cleans up the code in ``Modules/_tkinter.c``, and also allows stdin to be used as a pipe on all platforms. Patch by Michiel de Hoon.
52 changes: 7 additions & 45 deletions Modules/_tkinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,6 @@ typedef int Tcl_Size;
#define TCL_SIZE_MAX INT_MAX
#endif

#if !(defined(MS_WINDOWS) || defined(__CYGWIN__))
#define HAVE_CREATEFILEHANDLER
#endif

#ifdef HAVE_CREATEFILEHANDLER

/* If Tcl can wait for a Unix file descriptor, define the EventHook() routine
which uses this to handle Tcl events while the user is typing commands. */

#define WAIT_FOR_STDIN

#endif /* HAVE_CREATEFILEHANDLER */

/* Use OS native encoding for converting between Python strings and
Tcl objects.
Expand All @@ -108,8 +96,6 @@ typedef int Tcl_Size;
#endif

#ifdef MS_WINDOWS
#include <conio.h>
#define WAIT_FOR_STDIN

static PyObject *
_get_tcl_lib_path(void)
Expand Down Expand Up @@ -3325,41 +3311,25 @@ static PyMethodDef moduleMethods[] =
{NULL, NULL}
};

#ifdef WAIT_FOR_STDIN

static int stdin_ready = 0;

#ifndef MS_WINDOWS
static void
MyFileProc(void *clientData, int mask)
MyChannelProc(void *clientData, int mask)
{
stdin_ready = 1;
int* stdin_ready = clientData;
*stdin_ready = 1;
}
#endif

static PyThreadState *event_tstate = NULL;

static int
EventHook(void)
{
#ifndef MS_WINDOWS
int tfile;
#endif
int stdin_ready = 0;
Tcl_Channel channel = Tcl_GetStdChannel(TCL_STDIN);
PyEval_RestoreThread(event_tstate);
stdin_ready = 0;
errorInCmd = 0;
#ifndef MS_WINDOWS
tfile = fileno(stdin);
Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL);
#endif
Tcl_CreateChannelHandler(channel, TCL_READABLE, MyChannelProc, &stdin_ready);
while (!errorInCmd && !stdin_ready) {
int result;
#ifdef MS_WINDOWS
if (_kbhit()) {
stdin_ready = 1;
break;
}
#endif
Py_BEGIN_ALLOW_THREADS
if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1);
tcl_tstate = event_tstate;
Expand All @@ -3375,9 +3345,7 @@ EventHook(void)
if (result < 0)
break;
}
#ifndef MS_WINDOWS
Tcl_DeleteFileHandler(tfile);
#endif
Tcl_DeleteChannelHandler(channel, MyChannelProc, &stdin_ready);
if (errorInCmd) {
errorInCmd = 0;
PyErr_SetRaisedException(excInCmd);
Expand All @@ -3388,27 +3356,21 @@ EventHook(void)
return 0;
}

#endif

static void
EnableEventHook(void)
{
#ifdef WAIT_FOR_STDIN
if (PyOS_InputHook == NULL) {
event_tstate = PyThreadState_Get();
PyOS_InputHook = EventHook;
}
#endif
}

static void
DisableEventHook(void)
{
#ifdef WAIT_FOR_STDIN
if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) {
PyOS_InputHook = NULL;
}
#endif
}

static int
Expand Down
Loading