Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7dc9dea

Browse files
committed
Issue #20035: Reimplement tkinter._fix module as a C function.
The new private C function makes no permanent changes to the environment and is #ifdef'd out on non-Windows platforms.
1 parent 3cfec2e commit 7dc9dea

12 files changed

Lines changed: 134 additions & 99 deletions

File tree

Doc/whatsnew/3.5.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
****************************
1+
****************************
22
What's New In Python 3.5
33
****************************
44

@@ -659,6 +659,14 @@ time
659659
* The :func:`time.monotonic` function is now always available. (Contributed by
660660
Victor Stinner in :issue:`22043`.)
661661

662+
tkinter
663+
-------
664+
665+
* The :module:`tkinter._fix` module used for setting up the Tcl/Tk environment
666+
on Windows has been replaced by a private function in the :module:`_tkinter`
667+
module which makes no permanent changes to environment variables.
668+
(Contributed by Zachary Ware in :issue:`20035`.)
669+
662670
types
663671
-----
664672

Lib/test/test_tcl.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
# Skip this test if the _tkinter module wasn't built.
88
_tkinter = support.import_module('_tkinter')
99

10-
# Make sure tkinter._fix runs to set up the environment
11-
tkinter = support.import_fresh_module('tkinter')
12-
10+
import tkinter
1311
from tkinter import Tcl
1412
from _tkinter import TclError
1513

Lib/test/test_tk.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
# Skip test if _tkinter wasn't built.
33
support.import_module('_tkinter')
44

5-
# Make sure tkinter._fix runs to set up the environment
6-
support.import_fresh_module('tkinter')
7-
85
# Skip test if tk cannot be initialized.
96
support.requires('gui')
107

Lib/test/test_ttk_guionly.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
# Skip this test if _tkinter wasn't built.
66
support.import_module('_tkinter')
77

8-
# Make sure tkinter._fix runs to set up the environment
9-
tkinter = support.import_fresh_module('tkinter')
10-
118
# Skip test if tk cannot be initialized.
129
support.requires('gui')
1310

11+
import tkinter
1412
from _tkinter import TclError
1513
from tkinter import ttk
1614
from tkinter.test import runtktests

Lib/test/test_ttk_textonly.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
# Skip this test if _tkinter does not exist.
55
support.import_module('_tkinter')
66

7-
# Make sure tkinter._fix runs to set up the environment
8-
support.import_fresh_module('tkinter')
9-
107
from tkinter.test import runtktests
118

129
def test_main():

Lib/tkinter/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@
3131
"""
3232

3333
import sys
34-
if sys.platform == "win32":
35-
# Attempt to configure Tcl/Tk without requiring PATH
36-
from tkinter import _fix
3734

3835
import _tkinter # If this fails your Python may not be configured for Tk
3936
TclError = _tkinter.TclError

Lib/tkinter/_fix.py

Lines changed: 0 additions & 78 deletions
This file was deleted.

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ Core and Builtins
5858
Library
5959
-------
6060

61+
- Issue #20035: Replaced the ``tkinter._fix`` module used for setting up the
62+
Tcl/Tk environment on Windows with a private function in the ``_tkinter``
63+
module that makes no permanent changes to the environment.
64+
6165
- Issue #24257: Fixed segmentation fault in sqlite3.Row constructor with faked
6266
cursor type.
6367

Modules/_tkinter.c

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,65 @@ Copyright (C) 1994 Steen Lumholt.
101101
#ifdef MS_WINDOWS
102102
#include <conio.h>
103103
#define WAIT_FOR_STDIN
104+
105+
static PyObject *
106+
_get_tcl_lib_path()
107+
{
108+
static PyObject *tcl_library_path = NULL;
109+
static int already_checked = 0;
110+
111+
if (already_checked == 0) {
112+
PyObject *prefix;
113+
struct stat stat_buf;
114+
int stat_return_value;
115+
116+
prefix = PyUnicode_FromWideChar(Py_GetPrefix(), -1);
117+
if (prefix == NULL) {
118+
return NULL;
119+
}
120+
121+
/* Check expected location for an installed Python first */
122+
tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
123+
if (tcl_library_path == NULL) {
124+
return NULL;
125+
}
126+
tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
127+
if (tcl_library_path == NULL) {
128+
return NULL;
129+
}
130+
stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
131+
if (stat_return_value == -2) {
132+
return NULL;
133+
}
134+
if (stat_return_value == -1) {
135+
/* install location doesn't exist, reset errno and see if
136+
we're a repository build */
137+
errno = 0;
138+
#ifdef Py_TCLTK_DIR
139+
tcl_library_path = PyUnicode_FromString(
140+
Py_TCLTK_DIR "\\lib\\tcl" TCL_VERSION);
141+
if (tcl_library_path == NULL) {
142+
return NULL;
143+
}
144+
stat_return_value = _Py_stat(tcl_library_path, &stat_buf);
145+
if (stat_return_value == -2) {
146+
return NULL;
147+
}
148+
if (stat_return_value == -1) {
149+
/* tcltkDir for a repository build doesn't exist either,
150+
reset errno and leave Tcl to its own devices */
151+
errno = 0;
152+
tcl_library_path = NULL;
153+
}
154+
#else
155+
tcl_library_path = NULL;
104156
#endif
157+
}
158+
already_checked = 1;
159+
}
160+
return tcl_library_path;
161+
}
162+
#endif /* MS_WINDOWS */
105163

106164
#ifdef WITH_THREAD
107165

@@ -681,6 +739,33 @@ Tkapp_New(const char *screenName, const char *className,
681739
PyMem_Free(args);
682740
}
683741

742+
#ifdef MS_WINDOWS
743+
{
744+
PyObject *str_path;
745+
PyObject *utf8_path;
746+
DWORD ret;
747+
748+
ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
749+
if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
750+
str_path = _get_tcl_lib_path();
751+
if (str_path == NULL && PyErr_Occurred()) {
752+
return NULL;
753+
}
754+
if (str_path != NULL) {
755+
utf8_path = PyUnicode_AsUTF8String(str_path);
756+
if (utf8_path == NULL) {
757+
return NULL;
758+
}
759+
Tcl_SetVar(v->interp,
760+
"tcl_library",
761+
PyBytes_AsString(utf8_path),
762+
TCL_GLOBAL_ONLY);
763+
Py_DECREF(utf8_path);
764+
}
765+
}
766+
}
767+
#endif
768+
684769
if (Tcl_AppInit(v->interp) != TCL_OK) {
685770
PyObject *result = Tkinter_Error((PyObject *)v);
686771
#ifdef TKINTER_PROTECT_LOADTK
@@ -3517,8 +3602,40 @@ PyInit__tkinter(void)
35173602
uexe = PyUnicode_FromWideChar(Py_GetProgramName(), -1);
35183603
if (uexe) {
35193604
cexe = PyUnicode_EncodeFSDefault(uexe);
3520-
if (cexe)
3605+
if (cexe) {
3606+
#ifdef MS_WINDOWS
3607+
int set_var = 0;
3608+
PyObject *str_path;
3609+
wchar_t *wcs_path;
3610+
DWORD ret;
3611+
3612+
ret = GetEnvironmentVariableW(L"TCL_LIBRARY", NULL, 0);
3613+
3614+
if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
3615+
str_path = _get_tcl_lib_path();
3616+
if (str_path == NULL && PyErr_Occurred()) {
3617+
return NULL;
3618+
}
3619+
if (str_path != NULL) {
3620+
wcs_path = PyUnicode_AsWideCharString(str_path, NULL);
3621+
if (wcs_path == NULL) {
3622+
return NULL;
3623+
}
3624+
SetEnvironmentVariableW(L"TCL_LIBRARY", wcs_path);
3625+
set_var = 1;
3626+
}
3627+
}
3628+
35213629
Tcl_FindExecutable(PyBytes_AsString(cexe));
3630+
3631+
if (set_var) {
3632+
SetEnvironmentVariableW(L"TCL_LIBRARY", NULL);
3633+
PyMem_Free(wcs_path);
3634+
}
3635+
#else
3636+
Tcl_FindExecutable(PyBytes_AsString(cexe));
3637+
#endif /* MS_WINDOWS */
3638+
}
35223639
Py_XDECREF(cexe);
35233640
Py_DECREF(uexe);
35243641
}

PCbuild/_tkinter.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<ClCompile>
6464
<AdditionalIncludeDirectories>$(tcltkDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
6565
<PreprocessorDefinitions>WITH_APPINIT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
66+
<PreprocessorDefinitions Condition="'$(BuildForRelease)' != 'true'">Py_TCLTK_DIR="$(tcltkDir.TrimEnd('\').Replace('\', '\\'))";%(PreprocessorDefinitions)</PreprocessorDefinitions>
6667
</ClCompile>
6768
<Link>
6869
<AdditionalDependencies>$(tcltkLib);%(AdditionalDependencies)</AdditionalDependencies>

0 commit comments

Comments
 (0)