| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- #-----------------------------------------------------------------------------
- # Copyright (c) 2021-2023, PyInstaller Development Team.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- #
- # The full license is in the file COPYING.txt, distributed with this software.
- #
- # SPDX-License-Identifier: Apache-2.0
- #-----------------------------------------------------------------------------
- #
- # The run-time hook provides a custom module iteration function for our PyiFrozenFinder, which allows
- # `pkgutil.iter_modules()` to return entries for modules that are embedded in the PYZ archive. The non-embedded modules
- # (binary extensions, modules collected as only source .py files, etc.) are enumerated using the `fallback_finder`
- # provided by `PyiFrozenFinder` (which typically would be the python's `FileFinder`).
- def _pyi_rthook():
- import pkgutil
- import pyimod02_importers # PyInstaller's bootstrap module
- # This could, in fact, be implemented as `iter_modules()` method of the `PyiFrozenFinder`. However, we want to
- # avoid importing `pkgutil` in that bootstrap module (i.e., for the `pkgutil.iter_importer_modules()` call on the
- # fallback finder).
- def _iter_pyi_frozen_finder_modules(finder, prefix=''):
- # Fetch PYZ TOC tree from pyimod02_importers
- pyz_toc_tree = pyimod02_importers.get_pyz_toc_tree()
- # Finder has already pre-computed the package prefix implied by the search path. Use it to find the starting
- # node in the prefix tree.
- if finder._pyz_entry_prefix:
- pkg_name_parts = finder._pyz_entry_prefix.split('.')
- else:
- pkg_name_parts = []
- tree_node = pyz_toc_tree
- for pkg_name_part in pkg_name_parts:
- tree_node = tree_node.get(pkg_name_part)
- if not isinstance(tree_node, dict):
- # This check handles two cases:
- # a) path does not exist (`tree_node` is `None`)
- # b) path corresponds to a module instead of a package (`tree_node` is a leaf node (`str`)).
- tree_node = {}
- break
- # Dump the contents of the tree node.
- for entry_name, entry_data in tree_node.items():
- is_pkg = isinstance(entry_data, dict)
- yield prefix + entry_name, is_pkg
- # If our finder has a fall-back finder available, iterate its modules as well. By using the public
- # `fallback_finder` attribute, we force creation of the fallback finder as necessary.
- # NOTE: we do not care about potential duplicates here, because `pkgutil.iter_modules()` itself
- # keeps track of yielded names for purposes of de-duplication.
- if finder.fallback_finder is not None:
- yield from pkgutil.iter_importer_modules(finder.fallback_finder, prefix)
- pkgutil.iter_importer_modules.register(
- pyimod02_importers.PyiFrozenFinder,
- _iter_pyi_frozen_finder_modules,
- )
- _pyi_rthook()
- del _pyi_rthook
|