def __init__(self, namespace): if namespace not in ['PyQt5', 'PyQt6', 'PySide2', 'PySide6']: raise Exception('Invalid namespace: {0}'.format(namespace)) self.namespace = namespace # Distinction between PyQt5/6 and PySide2/6 self.is_pyqt = namespace in {'PyQt5', 'PyQt6'} # Distinction between Qt5 and Qt6 self.qt_major = 6 if namespace in {'PyQt6', 'PySide6'} else 5 # Determine relative path where Qt libraries and data need to be collected in the frozen application. This # varies between PyQt5/PyQt6/PySide2/PySide6, their versions, and platforms. NOTE: it is tempting to consider # deriving this path as simply the value of QLibraryInfo.PrefixPath, taken relative to the package's root # directory. However, we also need to support non-wheel deployments (e.g., with Qt installed in custom path on # Windows, or with Qt and PyQt5 installed on linux using native package manager), and in those, the Qt # PrefixPath does not reflect the required relative target path for the frozen application. if namespace == 'PyQt5': # PyQt5 uses PyQt5/Qt on all platforms, or PyQt5/Qt5 from version 5.15.4 on try: # The call below might fail with AttributeError on some PyQt5 versions (e.g., 5.9.2 from conda's main # channel); missing dist information forces a fallback codepath that tries to check for __version__ # attribute that does not exist, either. So handle the error gracefully and assume old layout. new_layout = hooks.is_module_satisfies("PyQt5 >= 5.15.4") except AttributeError: new_layout = False if new_layout: self.qt_rel_dir = os.path.join('PyQt5', 'Qt5') else: self.qt_rel_dir = os.path.join('PyQt5', 'Qt') elif namespace == 'PyQt6': # Similarly to PyQt5, PyQt6 switched from PyQt6/Qt to PyQt6/Qt6 in 6.0.3 try: # The call below might fail with AttributeError in case of a partial PyQt6 installation. For example, # user installs PyQt6 via pip, which also installs PyQt6-Qt6 and PyQt6-sip. Then they naively uninstall # PyQt6 package, which leaves the other two behind. PyQt6 now becomes a namespace package and there is # no dist metadata, so a fallback codepath in is_module_satisfies tries to check for __version__ # attribute that does not exist, either. Handle such errors gracefully and assume new layout (with # PyQt6, the new layout is more likely); it does not really matter what layout we assume, as library is # not usable anyway, but we do neeed to be able to return an instance of QtLibraryInfo with "version" # attribute set to a falsey value. new_layout = hooks.is_module_satisfies("PyQt6 >= 6.0.3") except AttributeError: new_layout = True if new_layout: self.qt_rel_dir = os.path.join('PyQt6', 'Qt6') else: self.qt_rel_dir = os.path.join('PyQt6', 'Qt') elif namespace == 'PySide2': # PySide2 uses PySide2/Qt on linux and macOS, and PySide2 on Windows if compat.is_win: self.qt_rel_dir = 'PySide2' else: self.qt_rel_dir = os.path.join('PySide2', 'Qt') else: # PySide6 follows the same logic as PySide2 if compat.is_win: self.qt_rel_dir = 'PySide6' else: self.qt_rel_dir = os.path.join('PySide6', 'Qt')
def hook(hook_api): """ SQLAlchemy 0.9 introduced the decorator 'util.dependencies'. This decorator does imports. eg: @util.dependencies("sqlalchemy.sql.schema") This hook scans for included SQLAlchemy modules and then scans those modules for any util.dependencies and marks those modules as hidden imports. """ if not is_module_satisfies('sqlalchemy >= 0.9'): return # this parser is very simplistic but seems to catch all cases as of V1.1 depend_regex = re.compile(r'@util.dependencies\([\'"](.*?)[\'"]\)') hidden_imports_set = set() known_imports = set() for node in hook_api.module_graph.flatten(start=hook_api.module): if isinstance(node, SourceModule) and \ node.identifier.startswith('sqlalchemy.'): known_imports.add(node.identifier) with open(node.filename) as f: for match in depend_regex.findall(f.read()): hidden_imports_set.add(match) hidden_imports_set -= known_imports if len(hidden_imports_set): logger.info(" Found %d sqlalchemy hidden imports", len(hidden_imports_set)) hook_api.add_imports(*list(hidden_imports_set))
def __init__(self, namespace): if namespace not in ['PyQt5', 'PyQt6', 'PySide2', 'PySide6']: raise Exception('Invalid namespace: {0}'.format(namespace)) self.namespace = namespace # Distinction between PyQt5/6 and PySide2/6 self.is_pyqt = namespace in {'PyQt5', 'PyQt6'} # Distinction between Qt5 and Qt6 self.qt_major = 6 if namespace in {'PyQt6', 'PySide6'} else 5 # Determine relative path where Qt libraries and data need to # be collected in the frozen application. This varies between # PyQt5/PyQt6/PySide2/PySide6, their versions, and platforms. # NOTE: it is tempting to consider deriving this path as simply the # value of QLibraryInfo.PrefixPath, taken relative to the package's # root directory. However, we also need to support non-wheel # deployments (e.g., with Qt installed in custom path on Windows, # or with Qt and PyQt5 installed on linux using native package # manager), and in those, the Qt PrefixPath does not reflect # the required relative target path for the frozen application. if namespace == 'PyQt5': # PyQt5 uses PyQt5/Qt on all platforms, or PyQt5/Qt5 from # version 5.15.4 on if hooks.is_module_satisfies("PyQt5 >= 5.15.4"): self.qt_rel_dir = os.path.join('PyQt5', 'Qt5') else: self.qt_rel_dir = os.path.join('PyQt5', 'Qt') elif namespace == 'PyQt6': # Similarly to PyQt5, PyQt6 switched from PyQt6/Qt to PyQt6/Qt6 # in 6.0.3 if hooks.is_module_satisfies("PyQt6 >= 6.0.3"): self.qt_rel_dir = os.path.join('PyQt6', 'Qt6') else: self.qt_rel_dir = os.path.join('PyQt6', 'Qt') elif namespace == 'PySide2': # PySide2 uses PySide2/Qt on linux and macOS, and PySide2 # on Windows if compat.is_win: self.qt_rel_dir = 'PySide2' else: self.qt_rel_dir = os.path.join('PySide2', 'Qt') else: # PySide6 follows the same logic as PySide2 if compat.is_win: self.qt_rel_dir = 'PySide6' else: self.qt_rel_dir = os.path.join('PySide6', 'Qt')
def pre_safe_import_module(api): # As of tensorflow 2.8.0, the `tensorflow.keras` is entirely gone, replaced by a lazy-loaded alias for # `keras.api._v2.keras`. Without us registering the alias here, a program that imports only from # `tensorflow.keras` fails to collect `tensorflow`. # See: https://github.com/pyinstaller/pyinstaller/discussions/6890 # The alias was already present in earlier releases, but it does not seem to be causing problems there, # so keep this specific to tensorflow >= 2.8.0 to avoid accidentally breaking something else. if is_module_satisfies("tensorflow >= 2.8.0"): api.add_alias_module('keras.api._v2.keras', 'tensorflow.keras')
from PyInstaller import compat # Necessary when using the vectorized subpackage hiddenimports = ['shapely.prepared'] pkg_base, pkg_dir = get_package_paths('shapely') binaries = [] if compat.is_win: if compat.is_conda: lib_dir = os.path.join(compat.base_prefix, 'Library', 'bin') else: lib_dir = os.path.join(pkg_dir, 'DLLs') dll_files = ['geos_c.dll', 'geos.dll'] binaries += [(os.path.join(lib_dir, f), '.') for f in dll_files] elif compat.is_linux: lib_dir = os.path.join(pkg_dir, '.libs') dest_dir = os.path.join('shapely', '.libs') # This duplicates the libgeos*.so* files in the build. PyInstaller will # copy them into the root of the build by default, but shapely cannot load # them from there in linux IF shapely was installed via a whl file. The # whl bundles its' own libgeos with a different name, something like # libgeos_c-*.so.* but shapely tries to load libgeos_c.so if there isn't a # ./libs directory under its' package. There is a proposed fix for this in # shapely but it has not been accepted it: # https://github.com/Toblerity/Shapely/pull/485 if is_module_satisfies('shapely <= 1.6'): binaries += [(os.path.join(lib_dir, f), dest_dir) for f in os.listdir(lib_dir)]
pyi_builder.test_source(""" import publicsuffix2 publicsuffix2.PublicSuffixList() """) @importorskip('pydivert') def test_pydivert(pyi_builder): pyi_builder.test_source(""" import pydivert pydivert.WinDivert.check_filter("inbound") """) @importorskip('skimage') @pytest.mark.skipif(not is_module_satisfies('skimage >= 0.16.0'), reason='The test supports only skimage 0.16.0 or newer.') @pytest.mark.parametrize('submodule', [ 'color', 'data', 'draw', 'exposure', 'feature', 'filters', 'future', 'graph', 'io', 'measure', 'metrics', 'morphology', 'registration', 'restoration', 'segmentation', 'transform', 'util', 'viewer' ]) def test_skimage(pyi_builder, submodule): pyi_builder.test_source(""" import skimage.{0} """.format(submodule)) @importorskip('sklearn') @pytest.mark.skipif(not is_module_satisfies('sklearn >= 0.21'), reason='The test supports only scikit-learn >= 0.21.')
# From sphinx.websupport line 100: # # mod = 'sphinx.websupport.search.' + mod # SearchClass = getattr(__import__(mod, None, None, [cls]), cls) # # So, include modules under "sphinx.websupport.search". collect_submodules('sphinx.websupport.search') + # # From sphinx.util.inspect line 21: # # inspect = __import__('inspect') # # And from sphinx.cmdline line 173: # # locale = __import__('locale') # due to submodule of the same name # # Add these two modules. ['inspect', 'locale'] ) # Sphinx also relies on a number of data files in its directory hierarchy: for # example, *.html and *.conf files in sphinx.themes, translation files in # sphinx.locale, etc. datas = collect_data_files('sphinx') # Sphinx 1.3.1 adds additional mandatory dependencies unconditionally imported # by the "sphinx.themes" module regardless of the current Sphinx configuration: # the "alabaster" and "sphinx_rtd_theme" themes, each relying on data files. if is_module_satisfies('sphinx >= 1.3.1'): datas.extend(collect_data_files('alabaster')) datas.extend(collect_data_files('sphinx_rtd_theme'))
# # So, we need all the languages in "sphinx.search". collect_submodules('sphinx.search') + collect_submodules('sphinx.websupport.search') + collect_submodules('sphinx.domains') + # # From sphinx.util.inspect line 21: # # inspect = __import__('inspect') # # And from sphinx.cmdline line 173: # # locale = __import__('locale') # due to submodule of the same name # # Add these two modules. ['inspect', 'locale'] ) # Sphinx also relies on a number of data files in its directory hierarchy: for # example, *.html and *.conf files in sphinx.themes, translation files in # sphinx.locale, etc. datas = collect_data_files('sphinx') # Sphinx 1.3.1 adds additional mandatory dependencies unconditionally imported # by the "sphinx.themes" module regardless of the current Sphinx configuration: # the "alabaster" and "sphinx_rtd_theme" themes, each relying on data files. if is_module_satisfies('sphinx >= 1.3.1') and is_module_satisfies('sphinx < 1.4'): datas.extend(collect_data_files('alabaster')) datas.extend(collect_data_files('sphinx_rtd_theme')) elif is_module_satisfies('sphinx >= 1.3.1'): datas.extend(collect_data_files('alabaster'))
#----------------------------------------------------------------------------- import os from PyInstaller.utils.hooks import ( get_module_attribute, is_module_satisfies, qt5_menu_nib_dir) 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. if is_darwin: # Version of the currently installed Qt 5.x shared library. qt_version = get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR') if is_module_satisfies('Qt < 5.4', qt_version): datas = [(qt5_menu_nib_dir(), '')]
# ------------------------------------------------------------------ # Copyright (c) 2020 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ """ APScheduler uses entry points to dynamically load executors, job stores and triggers. This hook was tested against APScheduler 3.6.3. """ from PyInstaller.utils.hooks import (collect_submodules, copy_metadata, is_module_satisfies) if is_module_satisfies("apscheduler < 4"): if is_module_satisfies("pyinstaller >= 4.4"): datas = copy_metadata('APScheduler', recursive=True) else: datas = copy_metadata('APScheduler') hiddenimports = collect_submodules('apscheduler')
view = QWebView() view.show() # Exit Qt when the main loop becomes idle. QTimer.singleShot(0, app.exit) # Run the main loop, displaying the WebKit widget. app.exec_() """) @importorskip('PyQt4') def test_PyQt4_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt4-uic.py') @pytest.mark.skipif(is_module_satisfies( 'Qt >= 5.6', get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR')), reason='QtWebKit is depreciated in Qt 5.6+') @importorskip('PyQt5') def test_PyQt5_QtWebKit(pyi_builder): pyi_builder.test_script('pyi_lib_PyQt5-QtWebKit.py') @importorskip('PyQt5') def test_PyQt5_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt5-uic.py') @xfail(is_darwin, reason='Please help debug this. See issue #3233.') @importorskip('PyQt5') def test_PyQt5_QWebEngine(pyi_builder, data_dir):
#----------------------------------------------------------------------------- # Copyright (c) 2013-2021, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License (version 2 # or later) with exception for distributing the bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import is_module_satisfies if is_module_satisfies("scipy >= 1.5.0"): hiddenimports = ['scipy.special.cython_special']
import re from PyInstaller.utils.hooks import (exec_statement, is_module_satisfies, logger) from PyInstaller.lib.modulegraph.modulegraph import SourceModule # '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'] # 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)
#----------------------------------------------------------------------------- # Copyright (c) 2017-2021, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License (version 2 # or later) with exception for distributing the bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies # Pandas keeps Python extensions loaded with dynamic imports here. hiddenimports = collect_submodules('pandas._libs') # Pandas 1.2.0 and later require cmath hidden import on linux and macOS. On Windows, this is not strictly required, but # we add it anyway to keep things simple (and future-proof). if is_module_satisfies('pandas >= 1.2.0'): hiddenimports += ['cmath']
from PyInstaller.utils.hooks import get_module_attribute, collect_submodules from PyInstaller.utils.hooks import is_module_satisfies # By default, pydantic from PyPi comes with all modules compiled as # cpython extensions, which seems to prevent pyinstaller from automatically # picking up the submodules. # NOTE: in PyInstaller 4.x and earlier, get_module_attribute() returns the # string representation of the value ('True'), while in PyInstaller 5.x # and later, the actual value is returned (True). is_compiled = get_module_attribute('pydantic', 'compiled') in {'True', True} if is_compiled: # Compiled version; we need to manually collect the submodules from # pydantic... hiddenimports = collect_submodules('pydantic') # ... as well as the following modules from the standard library hiddenimports += [ 'colorsys', 'dataclasses', 'decimal', 'json', 'ipaddress', 'pathlib', 'uuid', ] # Older releases (prior 1.4) also import distutils.version if not is_module_satisfies('pydantic >= 1.4'): hiddenimports += ['distutils.version'] # Version 1.8.0 introduced additional dependency on typing_extensions if is_module_satisfies('pydantic >= 1.8'): hiddenimports += ['typing_extensions']
# # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ import os import sys from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies from PyInstaller.compat import is_win hiddenimports = ["pyproj.datadir"] # Versions prior to 2.3.0 also require pyproj._datadir if not is_module_satisfies("pyproj >= 2.3.0"): hiddenimports += ["pyproj._datadir"] # Starting with version 3.0.0, pyproj._compat is needed if is_module_satisfies("pyproj >= 3.0.0"): hiddenimports += ["pyproj._compat"] # Linux and macOS also require distutils. if not is_win: hiddenimports += ["distutils.util"] # Data collection datas = collect_data_files('pyproj') if hasattr(sys, 'real_prefix'): # check if in a virtual environment root_path = sys.real_prefix else:
# # So, include modules under "sphinx.websupport.search". collect_submodules("sphinx.websupport.search") + # # From sphinx.util.inspect line 21: # # inspect = __import__('inspect') # # And from sphinx.cmdline line 173: # # locale = __import__('locale') # due to submodule of the same name # # Add these two modules. ["inspect", "locale"] ) # Sphinx also relies on a number of data files in its directory hierarchy: for # example, *.html and *.conf files in sphinx.themes, translation files in # sphinx.locale, etc. datas = collect_data_files("sphinx") # Sphinx 1.3.1 adds additional mandatory dependencies unconditionally imported # by the "sphinx.themes" module regardless of the current Sphinx configuration: # the "alabaster" and "sphinx_rtd_theme" themes, each relying on data files. if is_module_satisfies("sphinx >= 1.3.1") and is_module_satisfies("sphinx < 1.4"): datas.extend(collect_data_files("alabaster")) datas.extend(collect_data_files("sphinx_rtd_theme")) elif is_module_satisfies("sphinx >= 1.3.1"): datas.extend(collect_data_files("alabaster"))
view = QWebView() view.show() # Exit Qt when the main loop becomes idle. QTimer.singleShot(0, app.exit) # Run the main loop, displaying the WebKit widget. app.exec_() """) @importorskip('PyQt4') def test_PyQt4_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt4-uic.py') @pytest.mark.skipif(is_module_satisfies('Qt >= 5.6', get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR')), reason='QtWebKit is depreciated in Qt 5.6+') @importorskip('PyQt5') def test_PyQt5_QtWebKit(pyi_builder): pyi_builder.test_script('pyi_lib_PyQt5-QtWebKit.py') PYQT5_NEED_OPENGL = pytest.mark.skipif(is_module_satisfies('PyQt5 <= 5.10.1'), reason='PyQt5 v5.10.1 and older does not package ``opengl32sw.dll``, the ' 'OpenGL software renderer, which this test requires.') @PYQT5_NEED_OPENGL @importorskip('PyQt5') def test_PyQt5_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test.
def test_is_module_satisfies_package_not_installed(): assert is_module_satisfies('pytest') assert not is_module_satisfies('magnumopus-no-package-test-case')
def check_cefpython3_version(): if not is_module_satisfies("cefpython3 >= %s" % CEFPYTHON_MIN_VERSION): raise SystemExit("Error: cefpython3 %s or higher is required" % CEFPYTHON_MIN_VERSION)
# ------------------------------------------------------------------ # Copyright (c) 2021 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ from PyInstaller.utils.hooks import is_module_satisfies # The following missing module prevents import of skimage.feature # with skimage 0.18.x. if is_module_satisfies("scikit_image >= 0.18.0"): hiddenimports = [ 'skimage.filters.rank.core_cy_3d', ]
view = QWebView() view.show() # Exit Qt when the main loop becomes idle. QTimer.singleShot(0, app.exit) # Run the main loop, displaying the WebKit widget. app.exec_() """) @importorskip('PyQt4') def test_PyQt4_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt4-uic.py') @pytest.mark.skipif(is_module_satisfies('Qt >= 5.6', get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR')), reason='QtWebKit is depreciated in Qt 5.6+') @importorskip('PyQt5') def test_PyQt5_QtWebKit(pyi_builder): pyi_builder.test_script('pyi_lib_PyQt5-QtWebKit.py') @pytest.mark.skipif(is_module_satisfies('Qt >= 5.6', get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR')), reason='QtWebKit is depreciated in Qt 5.6+') @importorskip('PyQt5') def test_PyQt5_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt5-uic.py') @xfail(is_linux and is_py35, reason="Fails on linux >3.5") @xfail(is_darwin, reason="Fails on OSX")
#----------------------------------------------------------------------------- # Copyright (c) 2019-2020, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License (version 2 # or later) with exception for distributing the bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) #----------------------------------------------------------------------------- # hook for https://github.com/openstack/sqlalchemy-migrate # Since v0.12.0 importing migrate requires metadata to resolve __version__ # attribute from PyInstaller.utils.hooks import copy_metadata, is_module_satisfies if is_module_satisfies('sqlalchemy-migrate >= 0.12.0'): datas = copy_metadata('sqlalchemy-migrate')
# Copyright (c) 2020 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ from PyInstaller.utils.hooks import is_module_satisfies hiddenimports = [] if is_module_satisfies("scikit_learn >= 0.22"): # 0.22 and later hiddenimports += [ 'sklearn.neighbors._typedefs', 'sklearn.neighbors._quad_tree', ] else: # 0.21 hiddenimports += [ 'sklearn.neighbors.typedefs', 'sklearn.neighbors.quad_tree', ] # The following hidden import must be added here # (as opposed to sklearn.tree) hiddenimports += ['sklearn.tree._criterion']
# ------------------------------------------------------------------ # Copyright (c) 2020 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ from PyInstaller.utils.hooks import is_module_satisfies # sklearn.cluster in scikit-learn 0.23.x has a hidden import of # threadpoolctl if is_module_satisfies("sklearn >= 0.23"): hiddenimports = [ 'threadpoolctl', ]
# Copyright (c) 2015-2017, 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. #----------------------------------------------------------------------------- # # gevent is a coroutine -based Python networking library that uses greenlet to # provide a high-level synchronous API on top of the libev event loop. # # http://www.gevent.org/ # # Tested with gevent 1.0.2 and 1.1b6 from PyInstaller.utils.hooks import is_module_satisfies # monkey patching in gevent 1.1 uses dynamic imports if is_module_satisfies('gevent >= 1.1b0'): hiddenimports = [ 'gevent.builtins', 'gevent.os', 'gevent.select', 'gevent.signal', 'gevent.socket', 'gevent.subprocess', 'gevent.ssl', 'gevent.thread', 'gevent.threading' ]
import re from PyInstaller.utils.hooks import ( exec_statement, is_module_satisfies, logger) from PyInstaller.lib.modulegraph.modulegraph import SourceModule # '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'] # 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):
# 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. #----------------------------------------------------------------------------- import os from PyInstaller.utils.hooks import (get_module_attribute, is_module_satisfies, qt5_menu_nib_dir) 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. if is_darwin: # Version of the currently installed Qt 5.x shared library. qt_version = get_module_attribute('PyQt5.QtCore', 'QT_VERSION_STR') if is_module_satisfies('Qt < 5.4', qt_version): datas = [(qt5_menu_nib_dir(), '')]
# Distributed under the terms of the GNU General Public License (version 2 # or later) with exception for distributing the bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) #----------------------------------------------------------------------------- """ `importlib_resources` is a backport of the 3.9+ module `importlib.resources` """ import os from PyInstaller.utils.hooks import get_module_file_attribute, \ is_module_satisfies, copy_metadata if is_module_satisfies("importlib_resources >= 1.2.0"): # since 1.2.0 importlib.metadata is used datas = copy_metadata('importlib_resources') else: # include the version.txt file, used to set __version__ res_loc = os.path.dirname(get_module_file_attribute('importlib_resources')) datas = [ (os.path.join(res_loc, 'version.txt'), 'importlib_resources'), ] if is_module_satisfies("importlib_resources >= 1.3.1"): hiddenimports = ['importlib_resources.trees'] # this is only required for python2 support excludedimports = ['importlib_resources._py2']
#----------------------------------------------------------------------------- # Copyright (c) 2015-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 is_module_satisfies from PyInstaller import log as logging if is_module_satisfies('kivy >= 1.9.1'): from kivy.tools.packaging.pyinstaller_hooks import ( add_dep_paths, excludedimports, datas, get_deps_all, get_factory_modules, kivy_modules) add_dep_paths() hiddenimports = get_deps_all()['hiddenimports'] hiddenimports = list(set(get_factory_modules() + kivy_modules + hiddenimports)) else: logger = logging.getLogger(__name__) logger.warning('Hook disabled because of Kivy version < 1.9.1')
@importorskip('iminuit') def test_iminuit(pyi_builder): pyi_builder.test_source(""" from iminuit import Minuit """) @importorskip('av') def test_av(pyi_builder): pyi_builder.test_source(""" import av """) @importorskip('passlib') @xfail(is_linux and is_py39 and not is_module_satisfies('passlib > 1.7.4'), reason='Passlib does not account for crypt() behavior change that ' 'was introduced in 3.9.x (python #39289).') def test_passlib(pyi_builder): pyi_builder.test_source(""" import passlib.apache """) @importorskip('publicsuffix2') def test_publicsuffix2(pyi_builder): pyi_builder.test_source(""" import publicsuffix2 publicsuffix2.PublicSuffixList() """)
# ------------------------------------------------------------------ # Copyright (c) 2020 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ from PyInstaller.utils.hooks import is_module_satisfies, \ collect_submodules, collect_data_files tf_pre_1_15_0 = is_module_satisfies("tensorflow < 1.15.0") tf_post_1_15_0 = is_module_satisfies("tensorflow >= 1.15.0") tf_pre_2_0_0 = is_module_satisfies("tensorflow < 2.0.0") tf_pre_2_2_0 = is_module_satisfies("tensorflow < 2.2.0") # Exclude from data collection: # - development headers in include subdirectory # - XLA AOT runtime sources # - libtensorflow_framework shared library (to avoid duplication) data_excludes = [ "include", "xla_aot_runtime_src", "libtensorflow_framework.*" ]
#----------------------------------------------------------------------------- # Copyright (c) 2015-2021, PyInstaller Development Team. # # Distributed under the terms of the GNU General Public License (version 2 # or later) with exception for distributing the bootloader. # # The full license is in the file COPYING.txt, distributed with this software. # # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) #----------------------------------------------------------------------------- from PyInstaller.utils.hooks import is_module_satisfies from PyInstaller import log as logging if is_module_satisfies('kivy >= 1.9.1'): from kivy.tools.packaging.pyinstaller_hooks import ( add_dep_paths, excludedimports, datas, get_deps_all, get_factory_modules, kivy_modules) add_dep_paths() hiddenimports = get_deps_all()['hiddenimports'] hiddenimports = list(set(get_factory_modules() + kivy_modules + hiddenimports)) else: logger = logging.getLogger(__name__) logger.warning('Hook disabled because of Kivy version < 1.9.1')
view = QWebView() view.show() # Exit Qt when the main loop becomes idle. QTimer.singleShot(0, app.exit) # Run the main loop, displaying the WebKit widget. app.exec_() """) @importorskip('PyQt4') def test_PyQt4_uic(tmpdir, pyi_builder, data_dir): # Note that including the data_dir fixture copies files needed by this test. pyi_builder.test_script('pyi_lib_PyQt4-uic.py') PYQT5_NEED_OPENGL = pytest.mark.skipif(is_module_satisfies('PyQt5 <= 5.10.1'), reason='PyQt5 v5.10.1 and older does not package ``opengl32sw.dll``, the ' 'OpenGL software renderer, which this test requires.') # Parametrize test to run the same basic code on both Python Qt libraries. QtPyLibs = pytest.mark.parametrize('QtPyLib', ['PyQt5', 'PySide2']) # OS X bundles, produced by the ``--windowed`` flag, invoke a unique code path # that sometimes causes failures in Qt applications. USE_WINDOWED_KWARG = dict(pyi_args=['--windowed']) if is_darwin else {} # Define a function to remove paths with ``path_to_clean`` in them during a test so that PyQt5/PySide2 tests pass. Only remove them in Windows, since Mac/Linux Qt libraries don't rely on the path to find libraries. def path_clean(monkeypatch, path_to_clean): if is_win:
# ------------------------------------------------------------------ # Copyright (c) 2020 PyInstaller Development Team. # # This file is distributed under the terms of the GNU General Public # License (version 2.0 or later). # # The full license is available in LICENSE.GPL.txt, distributed with # this software. # # SPDX-License-Identifier: GPL-2.0-or-later # ------------------------------------------------------------------ from PyInstaller.utils.hooks import is_module_satisfies, collect_submodules hiddenimports = collect_submodules('markdown.extensions') # Markdown 3.3 introduced markdown.htmlparser submodule with hidden # dependency on html.parser if is_module_satisfies("markdown >= 3.3"): hiddenimports += ['html.parser']
@importorskip('pygments') def test_pygments(pyi_builder): pyi_builder.test_source(""" # This sample code is taken from http://pygments.org/docs/quickstart/. from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import HtmlFormatter code = 'print "Hello World"' print(highlight(code, PythonLexer(), HtmlFormatter())) """) PYQT5_NEED_OPENGL = pytest.mark.skipif( is_module_satisfies('PyQt5 <= 5.10.1'), reason='PyQt5 v5.10.1 and older does not package ``opengl32sw.dll``, the ' 'OpenGL software renderer, which this test requires.') # Parametrize test to run the same basic code on both Python Qt libraries. QtPyLibs = pytest.mark.parametrize('QtPyLib', ['PyQt5', 'PySide2']) # OS X bundles, produced by the ``--windowed`` flag, invoke a unique code path # that sometimes causes failures in Qt applications. USE_WINDOWED_KWARG = dict(pyi_args=['--windowed']) if is_darwin else {} # Define a function to remove paths with ``path_to_clean`` in them during a # test so that PyQt5/PySide2 tests pass. Only remove them in Windows, since # Mac/Linux Qt libraries don't rely on the path to find libraries. def path_clean(monkeypatch, path_to_clean):
#----------------------------------------------------------------------------- # Copyright (c) 2015-2016, 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. #----------------------------------------------------------------------------- # # gevent is a coroutine -based Python networking library that uses greenlet to # provide a high-level synchronous API on top of the libev event loop. # # http://www.gevent.org/ # # Tested with gevent 1.0.2 and 1.1b6 from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies # monkey patching in gevent 1.1 uses dynamic imports if is_module_satisfies('gevent >= 1.1b0'): hiddenimports = [ 'gevent.builtins', 'gevent.os', 'gevent.select', 'gevent.signal', 'gevent.socket', 'gevent.subprocess', 'gevent.ssl', 'gevent.thread', 'gevent.threading' ]
# Copyright (c) 2015-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. #----------------------------------------------------------------------------- # # Botocore is a low-level interface to a growing number of Amazon Web Services. # Botocore serves as the foundation for the AWS-CLI command line utilities. It # will also play an important role in the boto3.x project. # # The botocore package is compatible with Python versions 2.6.5, Python 2.7.x, # and Python 3.3.x and higher. # # https://botocore.readthedocs.org/en/latest/ # # Tested with botocore 1.4.36 from PyInstaller.utils.hooks import collect_data_files from PyInstaller.compat import is_py2 from PyInstaller.utils.hooks import is_module_satisfies if is_module_satisfies('botocore >= 1.4.36'): if is_py2: hiddenimports = ['HTMLParser'] else: hiddenimports = ['html.parser'] datas = collect_data_files('botocore')
assert pyi_testmod_dynamic.foo is not None assert pyi_testmod_dynamic.foo == 'A new value!' """) def test_email(pyi_builder): pyi_builder.test_source(""" from email import utils from email.header import Header from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.nonmultipart import MIMENonMultipart """) @skipif(is_module_satisfies('Crypto >= 3'), reason='Bytecode encryption is not ' 'compatible with pycryptodome.') @importorskip('Crypto') def test_feature_crypto(pyi_builder): pyi_builder.test_source(""" from pyimod00_crypto_key import key from pyimod02_archive import CRYPT_BLOCK_SIZE # Issue 1663: Crypto feature caused issues when using PyCrypto module. import Crypto.Cipher.AES assert type(key) is str # The test runner uses 'test_key' as key. assert key == 'test_key'.zfill(CRYPT_BLOCK_SIZE) """,
def test_email(pyi_builder): # Test import of new-style email module names. # This should work on Python 2.5+ pyi_builder.test_source( """ from email import utils from email.header import Header from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.nonmultipart import MIMENonMultipart """) @skipif(is_module_satisfies('Crypto >= 3'), reason='Bytecode encryption is not ' 'compatible with pycryptodome.') @importorskip('Crypto') def test_feature_crypto(pyi_builder): pyi_builder.test_source( """ from pyimod00_crypto_key import key from pyimod02_archive import CRYPT_BLOCK_SIZE # Issue 1663: Crypto feature caused issues when using PyCrypto module. import Crypto.Cipher.AES assert type(key) is str # The test runner uses 'test_key' as key. assert key == 'test_key'.zfill(CRYPT_BLOCK_SIZE) """,