Coverage for pyquickhelper/pycode/tkinter_helper.py: 93%
15 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-03 02:21 +0200
1"""
2@file
3@brief Helpers for tkinter
4"""
5import os
6import sys
7import warnings
8import ctypes
10_first_execution = False
13def fix_tkinter_issues_virtualenv(exc=True, fLOG=None):
14 """
15 Fix an issue which happens in a virtual environment,
16 see `Fix Tcl inside a virtualenv on Windows <https://github.com/pypa/virtualenv/pull/627>`_
18 @param exc raise an exception instead of a warning
19 @param fLOG logging function
20 @return list of environment variables
22 We try to deal with the following issue on Linux::
24 _tkinter.TclError: no display name and no $DISPLAY
26 On Linux, the solution is to run::
28 import matplotlib as mpl
29 mpl.use('Agg')
31 But it does not work if matplotlib was already imported.
32 It is recommended to delay its import
33 whenever it is possible.
34 """
35 global _first_execution
37 def location(): # pragma: no cover
38 site = os.path.normpath(os.path.dirname(
39 os.path.join(os.path.abspath(ctypes.__file__))))
40 rev = os.path.join(site, "..", "..")
41 if sys.platform.startswith("win"):
42 site = os.path.join(rev, "tcl")
43 if not os.path.exists(site):
44 site2 = os.path.join(rev, "..", "tcl")
45 if os.path.exists(site2):
46 site = site2
47 else:
48 mes = ", ".join(os.listdir(rev))
49 raise FileNotFoundError(
50 f"Unable to find: {site},\nsubfolders: {mes}")
51 else:
52 site = os.path.join(rev, "..", "tcl")
53 if not os.path.exists(site):
54 mes = ", ".join(os.listdir(os.path.join(rev, "..")))
55 raise FileNotFoundError(
56 f"unable to find: {site},\nsubfolders: {mes}")
57 return os.path.normpath(site)
59 def look_for(where, prefix): # pragma: no cover
60 lst = sorted(os.listdir(where), reverse=True)
61 lp = len(prefix)
62 for _ in lst:
63 if _.startswith(prefix) and "0" <= _[lp] <= "9" and ".lib" not in _:
64 return os.path.join(where, _)
65 raise FileNotFoundError("Unable to find any folder starting with {0} in {1}\nLIST:\n{2}".format(
66 prefix, where, ", ".join(lst)))
68 if sys.platform.startswith("win"): # pragma: no cover
69 if "matplotlib" in sys.modules:
70 if _first_execution:
71 warnings.warn(
72 "Cannot fix matplotlib display because it was already imported.", UserWarning)
73 if exc:
74 raise RuntimeError(
75 "Cannot fix matplotlib display because it was already imported.")
77 if "TCL_LIBRARY" not in os.environ:
78 loc = location()
79 p = look_for(loc, "tcl")
80 if fLOG:
81 fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TCL_LIBRARY",
82 os.environ.get("TCL_LIBRARY", None), p))
83 os.environ["TCL_LIBRARY"] = p
84 if fLOG:
85 fLOG("[fix_tkinter_issues_virtualenv] TCL_LIBRARY='{0}'".format(
86 os.environ["TCL_LIBRARY"]))
88 if "TK_LIBRARY" not in os.environ:
89 loc = location()
90 p = look_for(loc, "tk")
91 if fLOG:
92 fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TK_LIBRARY",
93 os.environ.get("TK_LIBRARY", None), p))
94 os.environ["TK_LIBRARY"] = p
95 if fLOG:
96 fLOG("[fix_tkinter_issues_virtualenv] TK_LIBRARY='{0}'".format(
97 os.environ["TK_LIBRARY"]))
99 if "TIX_LIBRARY" not in os.environ:
100 loc = location()
101 p = look_for(loc, "tix")
102 if fLOG:
103 fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TIX_LIBRARY",
104 os.environ.get("TIX_LIBRARY", None), p))
105 os.environ["TIX_LIBRARY"] = p
106 if fLOG:
107 fLOG("[fix_tkinter_issues_virtualenv] TIX_LIBRARY='{0}'".format(
108 os.environ["TIX_LIBRARY"]))
110 if "DISPLAY" not in os.environ:
111 p = ":0"
112 if fLOG:
113 fLOG(
114 f"Change DISPLAY: '{os.environ.get('DISPLAY', None)}' --> '{p}'")
115 os.environ["DISPLAY"] = p
116 else:
117 # if "DISPLAY" not in os.environ:
118 # os.environ["DISPLAY"] = ':10.0'
119 if fLOG:
120 fLOG("[fix_tkinter_issues_virtualenv] Call mpl.use('Agg')")
121 if "matplotlib" in sys.modules:
122 if _first_execution:
123 warnings.warn( # pragma: no cover
124 "Cannot fix matplotlib display because it was already imported.", UserWarning)
125 if exc:
126 raise RuntimeError( # pragma: no cover
127 "Cannot fix matplotlib display because it was already imported.")
128 import matplotlib as mpl
129 mpl.use('Agg')
130 else: # pragma: no cover
131 import matplotlib as mpl
132 mpl.use('Agg')
134 _first_execution = False
136 return os.environ.get("TCL_LIBRARY", None), os.environ.get("TK_LIBRARY", None), \
137 os.environ.get("TIX_LIBRARY", None), os.environ.get("DISPLAY", None)