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))
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 )
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.')