Exemplo n.º 1
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)
            # Determine the encoding of the source file.
            with open_file(node.filename, 'rb') as f:
                encoding = guess_encoding(f)
            # Use that to open the file.
            with open_file(node.filename, text_read_mode,
                           encoding=encoding) 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))
Exemplo n.º 2
0
def _warn_if_activetcl_or_teapot_installed(tcl_root, tcltree):
    """
    If the current Tcl installation is a Teapot-distributed version of ActiveTcl
    *and* the current platform is OS X, log a non-fatal warning that the
    resulting executable will (probably) fail to run on non-host systems.

    PyInstaller does *not* freeze all ActiveTcl dependencies -- including
    Teapot, which is typically ignorable. Since Teapot is *not* ignorable in
    this case, this function warns of impending failure.

    See Also
    -------
    https://github.com/pyinstaller/pyinstaller/issues/621
    """
    from macholib import util

    # System libraries do not experience this problem.
    if util.in_system_path(tcl_root):
        return

    # Absolute path of the "init.tcl" script.
    try:
        init_resource = [r[1] for r in tcltree if r[1].endswith("init.tcl")][0]
    # If such script could not be found, silently return.
    except IndexError:
        return

    mentions_activetcl = False
    mentions_teapot = False
    # TCL/TK reads files using the `system encoding <https://www.tcl.tk/doc/howto/i18n.html#system_encoding>`_.
    with open_file(
        init_resource, text_read_mode, encoding=locale.getpreferredencoding()
    ) as init_file:
        for line in init_file.readlines():
            line = line.strip().lower()
            if line.startswith("#"):
                continue
            if "activetcl" in line:
                mentions_activetcl = True
            if "teapot" in line:
                mentions_teapot = True
            if mentions_activetcl and mentions_teapot:
                break

    if mentions_activetcl and mentions_teapot:
        logger.warning(
            """
You appear to be using an ActiveTcl build of Tcl/Tk, which PyInstaller has
difficulty freezing. To fix this, comment out all references to "teapot" in:

     %s

See https://github.com/pyinstaller/pyinstaller/issues/621 for more information.
            """
            % init_resource
        )
Exemplo 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)
            # Determine the encoding of the source file.
            with open_file(node.filename, 'rb') as f:
                encoding = guess_encoding(f)
            # Use that to open the file.
            with open_file(node.filename, text_read_mode,
                           encoding=encoding) 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))
Exemplo n.º 4
0
            plen = len(prefix)

            # For each line in the updated loader cache...
            for line in cachedata.splitlines():
                if line.startswith('#'):
                    continue
                if line.startswith(prefix):
                    line = '"@executable_path/' + cachedest + line[plen:]
                cd.append(line)

            # Rejoin these lines in a manner preserving this object's "unicode"
            # type under Python 2.
            cachedata = u'\n'.join(cd)

            # Write the updated loader cache to this file.
            with open_file(cachefile, 'w') as fp:
                fp.write(cachedata)
        # Else, GdkPixbuf will do the right thing on Windows, so no changes to
        # the loader cache are required. For efficiency and reliability, this
        # command's encoded byte output is written as is without being decoded.
        else:
            with open_file(cachefile, 'wb') as fp:
                fp.write(subprocess.check_output(gdk_pixbuf_query_loaders))

        # Bundle this loader cache with this frozen application.
        datas.append((cachefile, cachedest))
    # Else, loader detection is unsupported on this platform.
    else:
        logger.warning(
            'GdkPixbuf loader bundling unsupported on your platform.')
            prefix = '"' + os.path.join(libdir, 'gdk-pixbuf-2.0', '2.10.0')
            plen = len(prefix)

            # For each line in the updated loader cache...
            for line in cachedata.splitlines():
                if line.startswith('#'):
                    continue
                if line.startswith(prefix):
                    line = '"@executable_path/lib/gdk-pixbuf' + line[plen:]
                cd.append(line)

            # Rejoin these lines in a manner preserving this object's "unicode"
            # type under Python 2.
            cachedata = u'\n'.join(cd)

            # Write the updated loader cache to this file.
            with open_file(cachefile, 'w') as fp:
                fp.write(cachedata)
        # Else, GdkPixbuf will do the right thing on Windows, so no changes to
        # the loader cache are required. For efficiency and reliability, this
        # command's encoded byte output is written as is without being decoded.
        else:
            with open_file(cachefile, 'wb') as fp:
                fp.write(subprocess.check_output(gdk_pixbuf_query_loaders))

        # Bundle this loader cache with this frozen application.
        datas.append((cachefile, 'lib/gdk-pixbuf'))
    # Else, loader detection is unsupported on this platform.
    else:
        logger.warning('GdkPixbuf loader bundling unsupported on your platform.')