Source code for pyquickhelper.pycode.tkinter_helper

"""
Helpers for tkinter


:githublink:`%|py|5`
"""
import os
import sys
import warnings
import ctypes

_first_execution = False


[docs]def fix_tkinter_issues_virtualenv(exc=True, fLOG=None): """ Fix an issue which happens in a virtual environment, see `Fix Tcl inside a virtualenv on Windows <https://github.com/pypa/virtualenv/pull/627>`_ :param exc: raise an exception instead of a warning :param fLOG: logging function :return: list of environment variables We try to deal with the following issue on Linux:: _tkinter.TclError: no display name and no $DISPLAY On Linux, the solution is to run:: import matplotlib as mpl mpl.use('Agg') But it does not work if matplotlib was already imported. It is recommended to delay its import whenever it is possible. :githublink:`%|py|34` """ global _first_execution def location(): site = os.path.normpath(os.path.dirname( os.path.join(os.path.abspath(ctypes.__file__)))) rev = os.path.join(site, "..", "..") if sys.platform.startswith("win"): site = os.path.join(rev, "tcl") if not os.path.exists(site): site2 = os.path.join(rev, "..", "tcl") if os.path.exists(site2): site = site2 else: mes = ", ".join(os.listdir(rev)) raise FileNotFoundError( "Unable to find: {0},\nsubfolders: {1}".format(site, mes)) else: site = os.path.join(rev, "..", "tcl") if not os.path.exists(site): mes = ", ".join(os.listdir(os.path.join(rev, ".."))) raise FileNotFoundError( "unable to find: {0},\nsubfolders: {1}".format(site, mes)) return os.path.normpath(site) def look_for(where, prefix): lst = sorted(os.listdir(where), reverse=True) lp = len(prefix) for _ in lst: if _.startswith(prefix) and "0" <= _[lp] <= "9" and ".lib" not in _: return os.path.join(where, _) raise FileNotFoundError("Unable to find any folder starting with {0} in {1}\nLIST:\n{2}".format( prefix, where, ", ".join(lst))) if sys.platform.startswith("win"): if "matplotlib" in sys.modules: if _first_execution: warnings.warn( "Cannot fix matplotlib display because it was already imported.", UserWarning) if exc: raise Exception( "Cannot fix matplotlib display because it was already imported.") if "TCL_LIBRARY" not in os.environ: loc = location() p = look_for(loc, "tcl") if fLOG: fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TCL_LIBRARY", os.environ.get("TCL_LIBRARY", None), p)) os.environ["TCL_LIBRARY"] = p if fLOG: fLOG("[fix_tkinter_issues_virtualenv] TCL_LIBRARY='{0}'".format( os.environ["TCL_LIBRARY"])) if "TK_LIBRARY" not in os.environ: loc = location() p = look_for(loc, "tk") if fLOG: fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TK_LIBRARY", os.environ.get("TK_LIBRARY", None), p)) os.environ["TK_LIBRARY"] = p if fLOG: fLOG("[fix_tkinter_issues_virtualenv] TK_LIBRARY='{0}'".format( os.environ["TK_LIBRARY"])) if "TIX_LIBRARY" not in os.environ: loc = location() p = look_for(loc, "tix") if fLOG: fLOG("[fix_tkinter_issues_virtualenv] Change {0}: '{1}' --> '{2}'".format("TIX_LIBRARY", os.environ.get("TIX_LIBRARY", None), p)) os.environ["TIX_LIBRARY"] = p if fLOG: fLOG("[fix_tkinter_issues_virtualenv] TIX_LIBRARY='{0}'".format( os.environ["TIX_LIBRARY"])) if "DISPLAY" not in os.environ: p = ":0" if fLOG: fLOG("Change {0}: '{1}' --> '{2}'".format("DISPLAY", os.environ.get("DISPLAY", None), p)) os.environ["DISPLAY"] = p else: # if "DISPLAY" not in os.environ: # os.environ["DISPLAY"] = ':10.0' if fLOG: fLOG("[fix_tkinter_issues_virtualenv] Call mpl.use('Agg')") if "matplotlib" in sys.modules: if _first_execution: warnings.warn( "Cannot fix matplotlib display because it was already imported.", UserWarning) if exc: raise Exception( "Cannot fix matplotlib display because it was already imported.") import matplotlib as mpl mpl.use('Agg') else: import matplotlib as mpl mpl.use('Agg') _first_execution = False return os.environ.get("TCL_LIBRARY", None), os.environ.get("TK_LIBRARY", None), \ os.environ.get("TIX_LIBRARY", None), os.environ.get("DISPLAY", None)