def _find_tcl_tk_dir(): """ Get a platform-agnostic 2-tuple of the absolute paths of the top-level external data directories for both Tcl and Tk, respectively. Returns ------- list 2-tuple whose first element is the value of `${TCL_LIBRARY}` and whose second element is the value of `${TK_LIBRARY}`. """ # Python code to get path to TCL_LIBRARY. tcl_root = exec_statement( 'from %s import Tcl; print(Tcl().eval("info library"))' % modname_tkinter) tk_version = exec_statement( 'from _tkinter import TK_VERSION; print(TK_VERSION)') # TK_LIBRARY is in the same prefix as Tcl. tk_root = os.path.join(os.path.dirname(tcl_root), 'tk%s' % tk_version) return tcl_root, tk_root
def qt4_phonon_plugins_dir(): import os qt4_plugin_dirs = eval(exec_statement("from PySide.QtGui import QApplication; app=QApplication([]); app.setApplicationName('pyinstaller'); from PySide.phonon import Phonon; v=Phonon.VideoPlayer(Phonon.VideoCategory); print map(unicode,app.libraryPaths())")) if not qt4_plugin_dirs: print "E: Cannot find PySide phonon plugin directories" return "" for d in qt4_plugin_dirs: if os.path.isdir(d): return str(d) # must be 8-bit chars for one-file builds print "E: Cannot find existing PySide phonon plugin directory" return ""
def _module_path(mod): return exec_statement( """ import sys import os; _tmp = sys.stdout sys.stdout = open(os.devnull,"w") sys.stderr = open(os.devnull,"w") import %s; sys.stdout = _tmp print(os.path.dirname(%s.__file__)) """%(mod, mod))
# ----------------------------------------------------------------------------- # Copyright (c) 2013-2019, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # ----------------------------------------------------------------------------- from PyInstaller.utils.hooks import exec_statement mpl_data_dir = exec_statement( "import matplotlib; print(matplotlib._get_data_path())") datas = [ (mpl_data_dir, "mpl-data"), ]
from PyInstaller.utils.hooks import exec_statement #from PyInstaller.build import Tree pandas_path = exec_statement("import pandas; print pandas.__path__[0]") print pandas_path #dict_tree = Tree(pandas_path, prefix='pandas', excludes=["*.pyc"]) #datas = dict_tree #binaries = filter(lambda x: 'pandas' not in x[0], binaries)
hiddenimports = ['gi.overrides.Gio'] datas = get_typelibs('Gio', '2.0') binaries = [] statement = """ from gi.repository import Gio print(Gio.__path__) """ path = exec_statement(statement) pattern = None if is_darwin: # Use commonprefix to find common prefix between sys.prefix and the path, e.g., # /opt/local/Library/Frameworks/Python.framework/Versions/3.4, # and /opt/local/lib/girepository-1.0/Gio-2.0.typelib. # Then use that and the standard Gio modules path of <prefix>/lib/gio/modules/ to gather the modules. pattern = os.path.join(os.path.commonprefix([sys.prefix, path]), 'lib', 'gio', 'modules', '*.so') elif is_win: # Don't use common prefix since sys.prefix on Windows in usually C:\Python<version> and Gio's modules # are installed at C:\Python<version>\Lib\site-packages\gnome\lib\gio\modules which wouldn't yield a useful prefix. # By just backing up a directory level from the Gio typelib we are then in the gnome lib directory and can then # use the standard Gio modules path to gather the modules. pattern = os.path.join(os.path.dirname(path), '..', 'gio', 'modules', '*.dll')
#----------------------------------------------------------------------------- # Copyright (c) 2013-2019, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import exec_statement # This needed because comtypes wx.lib.activex generates some stuff. exec_statement("import wx.lib.activex")
# The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- import os from pkg_resources import Requirement from PyInstaller.utils.hooks import qt5_menu_nib_dir, exec_statement from PyInstaller.compat import getsitepackages, is_darwin, is_win # On Windows system PATH has to be extended to point to the PyQt5 directory. # The PySide directory contains Qt dlls. We need to avoid including different # version of Qt libraries when there is installed another application (e.g. QtCreator) if is_win: from PyInstaller.utils.win32.winutils import extend_system_path extend_system_path([os.path.join(x, 'PyQt5') for x in getsitepackages()]) # In the new consolidated mode any PyQt depends on _qt hiddenimports = ['sip', 'PyQt5.Qt'] # For Qt<5.4 to work on Mac OS X it is necessary to include `qt_menu.nib`. # This directory contains some resource files necessary to run PyQt or PySide # app. qt_version = exec_statement(""" from PyQt5.QtCore import QT_VERSION_STR print(QT_VERSION_STR) """) if is_darwin and qt_version in Requirement.parse("QT<5.4"): datas = [ (qt5_menu_nib_dir(), ''), ]
# Copyright (c) 2013, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import exec_statement, is_module_version # include most common database bindings # some database bindings are detected and include some # are not. We should explicitly include database backends. hiddenimports = ['pysqlite2', 'MySQLdb', 'psycopg2'] # sqlalchemy.dialects package from 0.6 and newer sqlachemy versions if is_module_version('sqlalchemy', '>=', '0.6'): dialects = exec_statement("import sqlalchemy.dialects;print(sqlalchemy.dialects.__all__)") dialects = eval(dialects.strip()) for n in dialects: hiddenimports.append("sqlalchemy.dialects." + n) else: # sqlalchemy.databases package from pre 0.6 sqlachemy versions databases = exec_statement("import sqlalchemy.databases; print(sqlalchemy.databases.__all__)") databases = eval(databases.strip()) for n in databases: hiddenimports.append("sqlalchemy.databases." + n)
def get_matplotlib_backend_module_names(): """ List the names of all matplotlib backend modules importable under the current Python installation. Returns ---------- list List of the fully-qualified names of all such modules. """ # Statement safely importing a single backend module. import_statement = """ import os, sys # Preserve stdout. sys_stdout = sys.stdout try: # Redirect output printed by this importation to "/dev/null", preventing # such output from being erroneously interpreted as an error. with open(os.devnull, 'w') as dev_null: sys.stdout = dev_null __import__('%s') # If this is an ImportError, print this exception's message without a traceback. # ImportError messages are human-readable and require no additional context. except ImportError as exc: sys.stdout = sys_stdout print(exc) # Else, print this exception preceded by a traceback. traceback.print_exc() # prints to stderr rather than stdout and must not be called here! except Exception: sys.stdout = sys_stdout import traceback print(traceback.format_exc()) """ # List of the human-readable names of all available backends. backend_names = eval_statement( 'import matplotlib; print(matplotlib.rcsetup.all_backends)') # List of the fully-qualified names of all importable backend modules. module_names = [] # If the current system is not OS X and the "CocoaAgg" backend is available, # remove this backend from consideration. Attempting to import this backend # on non-OS X systems halts the current subprocess without printing output # or raising exceptions, preventing its reliable detection. if not is_darwin and 'CocoaAgg' in backend_names: backend_names.remove('CocoaAgg') # For safety, attempt to import each backend in a unique subprocess. for backend_name in backend_names: module_name = 'matplotlib.backends.backend_%s' % backend_name.lower() stdout = exec_statement(import_statement % module_name) # If no output was printed, this backend is importable. if not stdout: module_names.append(module_name) logger.info(' Matplotlib backend "%s": added' % backend_name) else: logger.info(' Matplotlib backend "%s": ignored\n %s' % (backend_name, stdout)) return module_names
datas += collect_glib_share_files('gstreamer-1.0') hiddenimports += ["gi.repository.Gio"] for prog in [ 'gst-plugins-bad-1.0', 'gst-plugins-base-1.0', 'gst-plugins-good-1.0', 'gst-plugins-ugly-1.0', 'gstreamer-1.0' ]: datas += collect_glib_translations(prog) statement = """ import os import gi gi.require_version('Gst', '1.0') from gi.repository import Gst Gst.init(None) reg = Gst.Registry.get() plug = reg.find_plugin('coreelements') path = plug.get_filename() print(os.path.dirname(path)) """ plugin_path = exec_statement(statement) # Use a pattern of libgst* since all GStreamer plugins that conform to GStreamer standards start with libgst # and we may have mixed plugin extensions, e.g., .so and .dylib. for pattern in ['libgst*.dll', 'libgst*.dylib', 'libgst*.so']: pattern = os.path.join(plugin_path, pattern) binaries += [(f, os.path.join('gst_plugins')) for f in glob.glob(pattern)]
# along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # Contributed by Greg Copeland from PyInstaller.utils.hooks import exec_statement # include most common database bindings # some database bindings are detected and include some # are not. We should explicitly include database backends. hiddenimports = ['pysqlite2', 'MySQLdb']#, 'psycopg2', 'pyodbc', 'pymysql'] # print ("in custom sql alchemy hook ") # sqlalchemy.databases package from pre 0.6 sqlachemy versions databases = exec_statement("import sqlalchemy.databases;print sqlalchemy.databases.__all__") try: databases = eval(databases.strip()) for n in databases: hiddenimports.append("sqlalchemy.databases." + n) except: print ("No databases found") for n in databases: hiddenimports.append("sqlalchemy.databases." + n) # sqlalchemy.orm package from pre 0.6 sqlachemy versions orm = exec_statement("import sqlalchemy.orm;print sqlalchemy.orm.__all__") orm = eval(orm.strip())
from PyInstaller.lib.modulegraph.util import guess_encoding from PyInstaller.utils.hooks import exec_statement, is_module_satisfies, logger # 'sqlalchemy.testing' causes bundling a lot of unnecessary modules. excludedimports = ['sqlalchemy.testing'] # Include most common database bindings some database bindings are detected and include some are not. We should # explicitly include database backends. hiddenimports = ['pysqlite2', 'MySQLdb', 'psycopg2', 'sqlalchemy.ext.baked'] if is_module_satisfies('sqlalchemy >= 1.4'): hiddenimports.append("sqlalchemy.sql.default_comparator") # In SQLAlchemy >= 0.6, the "sqlalchemy.dialects" package provides dialects. if is_module_satisfies('sqlalchemy >= 0.6'): dialects = exec_statement( "import sqlalchemy.dialects;print(sqlalchemy.dialects.__all__)") dialects = eval(dialects.strip()) for n in dialects: hiddenimports.append("sqlalchemy.dialects." + n) # In SQLAlchemy <= 0.5, the "sqlalchemy.databases" package provides dialects. else: databases = exec_statement( "import sqlalchemy.databases; print(sqlalchemy.databases.__all__)") databases = eval(databases.strip()) for n in databases: hiddenimports.append("sqlalchemy.databases." + n) def hook(hook_api):
# # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ import json from PyInstaller.utils.hooks import exec_statement hiddenimports = [ "sentry_sdk.integrations.stdlib", "sentry_sdk.integrations.excepthook", "sentry_sdk.integrations.dedupe", "sentry_sdk.integrations.atexit", "sentry_sdk.integrations.modules", "sentry_sdk.integrations.argv", "sentry_sdk.integrations.logging", "sentry_sdk.integrations.threading" ] statement = """ import json import sentry_sdk.integrations as si integrations = [] if hasattr(si, '_AUTO_ENABLING_INTEGRATIONS'): # _AUTO_ENABLING_INTEGRATIONS is a list of strings with default enabled integrations # https://github.com/getsentry/sentry-python/blob/c6b6f2086b58ffc674df5c25a600b8a615079fb5/sentry_sdk/integrations/__init__.py#L54-L66 def make_integration_name(integration_name: str): return integration_name.rsplit(".", maxsplit=1)[0] integrations.extend(map(make_integration_name, si._AUTO_ENABLING_INTEGRATIONS)) print(json.dumps(integrations)) """ hiddenimports.extend(json.loads(exec_statement(statement)))
def collect_submodules_traitsui(package, filter=lambda name: True): # Accept only strings as packages. if not isinstance(package, string_types): raise ValueError logger.debug('Collecting submodules for %s' % package) # Skip a module which is not a package. if not is_package(package): logger.debug('collect_submodules - Module %s is not a package.' % package) return [] # Determine the filesystem path to the specified package. pkg_base, pkg_dir = get_package_paths(package) # Walk the package. Since this performs imports, do it in a separate # process. names = exec_statement(""" import sys import pkgutil def ignore_err(name, err): # Can't print anything because printing is captured as module names # print ("error importing %s: %s" % (name, err)) pass # ``pkgutil.walk_packages`` doesn't walk subpackages of zipped files # per https://bugs.python.org/issue14209. This is a workaround. def walk_packages(path=None, prefix='', onerror=ignore_err): def seen(p, m={{}}): if p in m: return True m[p] = True for importer, name, ispkg in pkgutil.iter_modules(path, prefix): if not name.startswith(prefix): ## Added name = prefix + name ## Added yield importer, name, ispkg if ispkg: try: __import__(name) except ImportError as e: if onerror is not None: onerror(name, e) except Exception as e: if onerror is not None: onerror(name, e) else: raise else: path = getattr(sys.modules[name], '__path__', None) or [] # don't traverse path items we've seen before path = [p for p in path if not seen(p)] ## Use Py2 code here. It still works in Py3. for item in walk_packages(path, name+'.', onerror): yield item ## This is the original Py3 code. #yield from walk_packages(path, name+'.', onerror) for module_loader, name, ispkg in walk_packages([{}], '{}.'): print(name) """.format( # Use repr to escape Windows backslashes. repr(pkg_dir), package)) # Include the package itself in the results. mods = {package} # Filter through the returend submodules. for name in names.split(): if filter(name): mods.add(name) logger.debug("collect_submodules - Found submodules: %s", mods) return list(mods)
from PyInstaller.utils.hooks import exec_statement, collect_submodules strptime_data_file = exec_statement( "import inspect; import _strptime; print(inspect.getfile(_strptime))" ) datas = [ (strptime_data_file, ".") ] hiddenimports = collect_submodules('dateparser')
def __getattr__(self, name): if 'version' in self.__dict__: # Initialization was already done, but requested attribute is not # availiable. raise AttributeError(name) else: # Ensure self.version exists, even if PyQt{5,6}/PySide{2,6} cannot # be imported. Hooks and util functions use `if .version` to check # whether package was imported and other attributes are # expected to be available. This also serves as a marker that # initialization was already done. self.version = None # Get library path information from Qt. See QLibraryInfo_. json_str = hooks.exec_statement(""" import sys # exec_statement only captures stdout. If there are # errors, capture them to stdout so they can be displayed to the # user. Do this early, in case package imports produce stderr # output. sys.stderr = sys.stdout import json try: from %s.QtCore import QLibraryInfo, QCoreApplication except Exception: print('False') raise SystemExit(0) # QLibraryInfo isn't always valid until a QCoreApplication is # instantiated. app = QCoreApplication(sys.argv) # Qt6 deprecated QLibraryInfo.location() in favor of # QLibraryInfo.path(), and QLibraryInfo.LibraryLocation # enum was replaced by QLibraryInfo.LibraryPath. if hasattr(QLibraryInfo, 'path'): # Qt6; enumerate path enum values directly from # the QLibraryInfo.LibraryPath enum. path_names = [x for x in dir(QLibraryInfo.LibraryPath) if x.endswith('Path')] location = {x: QLibraryInfo.path( getattr(QLibraryInfo.LibraryPath, x)) for x in path_names} else: # Qt5; in recent versions, location enum values # can be enumeratd from QLibraryInfo.LibraryLocation. # However, in older versions of Qt5 and its python # bindings, that is unavailable. Hence the enumeration # of "*Path"-named members of QLibraryInfo. path_names = [x for x in dir(QLibraryInfo) if x.endswith('Path')] location = {x: QLibraryInfo.location( getattr(QLibraryInfo, x)) for x in path_names} # Determine Qt version. Works for Qt 5.8 and later, where # QLibraryInfo.version() was introduced. try: version = QLibraryInfo.version().segments() except AttributeError: version = [] print(json.dumps({ 'isDebugBuild': QLibraryInfo.isDebugBuild(), 'version': version, 'location': location, })) """ % self.namespace) try: qli = json.loads(json_str) except Exception as e: logger.warning('Cannot read QLibraryInfo output: raised %s when ' 'decoding:\n%s', str(e), json_str) qli = {} for k, v in qli.items(): setattr(self, k, v) return getattr(self, name)
#----------------------------------------------------------------------------- # Copyright (c) 2013-2018, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import exec_statement # This needed because comtypes wx.lib.activex generates some stuff. exec_statement("import wx.lib.activex")
import os from pkg_resources import Requirement from PyInstaller.utils.hooks import qt5_menu_nib_dir, exec_statement from PyInstaller.compat import getsitepackages, is_darwin, is_win # On Windows system PATH has to be extended to point to the PyQt5 directory. # The PySide directory contains Qt dlls. We need to avoid including different # version of Qt libraries when there is installed another application (e.g. QtCreator) if is_win: from PyInstaller.utils.win32.winutils import extend_system_path extend_system_path([os.path.join(x, 'PyQt5') for x in getsitepackages()]) # In the new consolidated mode any PyQt depends on _qt hiddenimports = ['sip', 'PyQt5.Qt'] # For Qt<5.4 to work on Mac OS X it is necessary to include `qt_menu.nib`. # This directory contains some resource files necessary to run PyQt or PySide # app. qt_version = exec_statement(""" from PyQt5.QtCore import QT_VERSION_STR print(QT_VERSION_STR) """) if is_darwin and qt_version in Requirement.parse("QT<5.4"): datas = [ (qt5_menu_nib_dir(), ''), ]
hiddenimports += ["gi.repository.Gio"] for prog in ['gst-plugins-bad-1.0', 'gst-plugins-base-1.0', 'gst-plugins-good-1.0', 'gst-plugins-ugly-1.0', 'gstreamer-1.0']: datas += collect_glib_translations(prog) statement = """ import os import gi gi.require_version('Gst', '1.0') from gi.repository import Gst Gst.init(None) reg = Gst.Registry.get() plug = reg.find_plugin('coreelements') path = plug.get_filename() print(os.path.dirname(path)) """ plugin_path = exec_statement(statement) # Use a pattern of libgst* since all GStreamer plugins that conform to GStreamer standards start with libgst # and we may have mixed plugin extensions, e.g., .so and .dylib. pattern = os.path.join(plugin_path, 'libgst*') binaries += [(f, os.path.join('gst_plugins')) for f in glob.glob(pattern)]
from PyInstaller.utils.hooks import exec_statement, collect_submodules strptime_data_file = exec_statement( "import inspect; import _strptime; print(inspect.getfile(_strptime))" ) datas = [ (strptime_data_file, "") ] hiddenimports = collect_submodules('dateparser')
#----------------------------------------------------------------------------- # Copyright (c) 2013, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License with exception # for distributing bootloader. # # The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import exec_statement mpl_data_dir = exec_statement( "import matplotlib; print matplotlib._get_data_path()") datas = [ (mpl_data_dir, ""), ]
# package directory and this includes: # - Windows: libenchat-1.dll, libenchat_ispell.dll, libenchant_myspell.dll, other # dependent dlls and dictionaries for several languages (de, en, fr) # - Mac OS X: usually libenchant.dylib and several dictionaries when installed via pip. binaries = collect_dynamic_libs('enchant') datas = collect_data_files('enchant') excludedimports = ['enchant.tests'] # On OS X try to find files from Homebrew or Macports environments. if is_darwin: # Note: env. var. ENCHANT_PREFIX_DIR is implemented only in the development version: # https://github.com/AbiWord/enchant # https://github.com/AbiWord/enchant/pull/2 # TODO Test this hook with development version of enchant. libenchant = exec_statement(""" from enchant._enchant import e print(e._name) """).strip() installer = get_installer('enchant') if installer != 'pip': # Note: Name of detected enchant library is 'libenchant.dylib'. However, it # is just symlink to 'libenchant.1.dylib'. binaries.append((libenchant, '.')) # Collect enchant backends from Macports. Using same file structure as on Windows. backends = exec_statement(""" from enchant import Broker for provider in Broker().describe(): print(provider.file)""").strip().split() binaries.extend([(b, 'enchant/lib/enchant') for b in backends])
# package directory and this includes: # - Windows: libenchat-1.dll, libenchat_ispell.dll, libenchant_myspell.dll, other # dependent dlls and dictionaries for several languages (de, en, fr) # - Mac OS X: usually libenchant.dylib and several dictionaries when installed via pip. binaries = collect_dynamic_libs('enchant') datas = collect_data_files('enchant') # On OS X try to find files from Homebrew or Macports environments. if is_darwin: # Note: env. var. ENCHANT_PREFIX_DIR is implemented only in the development version: # https://github.com/AbiWord/enchant # https://github.com/AbiWord/enchant/pull/2 # TODO Test this hook with development version of enchant. libenchant = exec_statement(""" from enchant._enchant import e print(e._name) """).strip() # Check libenchant was not installed via pip but is somewhere on disk. # Probably it was installed from Homebrew or Macports. if not libenchant.startswith(sys.prefix): # 'libenchant' was not installed via pip. # Note: Name of detected enchant library is 'libenchant.dylib'. However, it # is just symlink to 'libenchant.1.dylib'. binaries.append((libenchant, '')) # Collect enchant backends from Macports. Using same file structure as on Windows. backends = exec_statement(""" from enchant import Broker for provider in Broker().describe(): print(provider.file)""").strip().split()