Ejemplo n.º 1
0
 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')
Ejemplo n.º 2
0
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))
Ejemplo n.º 3
0
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))
Ejemplo n.º 4
0
 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')
Ejemplo n.º 6
0
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.')
Ejemplo n.º 8
0
# 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'))
Ejemplo n.º 9
0
#
# 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'))
Ejemplo n.º 10
0
#-----------------------------------------------------------------------------


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')
Ejemplo n.º 12
0
        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']
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
#-----------------------------------------------------------------------------
# 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']
Ejemplo n.º 16
0
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:
Ejemplo n.º 18
0
    #
    # 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"))
Ejemplo n.º 19
0
        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.
Ejemplo n.º 20
0
def test_is_module_satisfies_package_not_installed():
    assert is_module_satisfies('pytest')
    assert not is_module_satisfies('magnumopus-no-package-test-case')
Ejemplo n.º 21
0
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',
    ]
Ejemplo n.º 23
0
        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')
Ejemplo n.º 25
0
# 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']
Ejemplo n.º 26
0
# ------------------------------------------------------------------
# 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',
    ]
Ejemplo n.º 27
0
# 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'
    ]
Ejemplo n.º 28
0
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):
Ejemplo n.º 29
0
# 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(), '')]
Ejemplo n.º 30
0
# 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']
Ejemplo n.º 31
0
#-----------------------------------------------------------------------------
# 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')
Ejemplo n.º 32
0
@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()
        """)
Ejemplo n.º 33
0
# ------------------------------------------------------------------
# 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.*"
]
Ejemplo n.º 34
0
#-----------------------------------------------------------------------------
# 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')
Ejemplo n.º 35
0
        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:
Ejemplo n.º 36
0
def test_is_module_satisfies_package_not_installed():
    assert is_module_satisfies('pytest')
    assert not is_module_satisfies('magnumopus-no-package-test-case')
Ejemplo n.º 37
0
# ------------------------------------------------------------------
# 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']
Ejemplo n.º 38
0
@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):
Ejemplo n.º 39
0
#-----------------------------------------------------------------------------
# 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'
    ]
Ejemplo n.º 40
0
# 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')
Ejemplo n.º 41
0
        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)
        """,
Ejemplo n.º 42
0
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)]
Ejemplo n.º 43
0

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)
        """,