Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py: 0%

37 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1#----------------------------------------------------------------------------- 

2# Copyright (c) 2021-2022, PyInstaller Development Team. 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); 

5# you may not use this file except in compliance with the License. 

6# 

7# The full license is in the file COPYING.txt, distributed with this software. 

8# 

9# SPDX-License-Identifier: Apache-2.0 

10#----------------------------------------------------------------------------- 

11# 

12# This rthook overrides pkgutil.iter_modules with custom implementation that uses PyInstaller's FrozenImporter to list 

13# sub-modules embedded in the PYZ archive. The non-embedded modules (binary extensions, or .pyc modules in noarchive 

14# build) are handled by original pkgutil iter_modules implementation (and consequently, python's FileFinder). 

15# 

16# The preferred way of adding support for iter_modules would be adding non-standard iter_modules() method to 

17# FrozenImporter itself. However, that seems to work only for path entry finders (for use with sys.path_hooks), while 

18# PyInstaller's FrozenImporter is registered as meta path finders (for use with sys.meta_path). Turning FrozenImporter 

19# into path entry finder, would seemingly require the latter to support on-filesystem resources (e.g., extension 

20# modules) in addition to PYZ-embedded ones. 

21# 

22# Therefore, we instead opt for overriding pkgutil.iter_modules with custom implementation that augments the output of 

23# original implementation with contents of PYZ archive from FrozenImporter's TOC. 

24 

25import os 

26import pkgutil 

27import sys 

28 

29from pyimod03_importers import FrozenImporter 

30 

31_orig_pkgutil_iter_modules = pkgutil.iter_modules 

32 

33 

34def _pyi_pkgutil_iter_modules(path=None, prefix=''): 

35 # Use original implementation to discover on-filesystem modules (binary extensions in regular builds, or both binary 

36 # extensions and compiled pyc modules in noarchive debug builds). 

37 yield from _orig_pkgutil_iter_modules(path, prefix) 

38 

39 # Find the instance of PyInstaller's FrozenImporter. 

40 for importer in pkgutil.iter_importers(): 

41 if isinstance(importer, FrozenImporter): 

42 break 

43 else: 

44 return 

45 

46 if path is None: 

47 # Search for all top-level packages/modules. These will have no dots in their entry names. 

48 for entry in importer.toc: 

49 if entry.count('.') != 0: 

50 continue 

51 is_pkg = importer.is_package(entry) 

52 yield pkgutil.ModuleInfo(importer, prefix + entry, is_pkg) 

53 else: 

54 # Declare SYS_PREFIX locally, to avoid clash with eponymous global symbol from pyi_rth_pkgutil hook. 

55 # 

56 # Use os.path.realpath() to fully resolve any symbolic links in sys._MEIPASS, in order to avoid path mis-matches 

57 # when the given search paths also contain symbolic links and are already fully resolved. See #6537 for an 

58 # example of such a problem with onefile build on macOS, where the temporary directory is placed under /var, 

59 # which is actually a symbolic link to /private/var. 

60 SYS_PREFIX = os.path.realpath(sys._MEIPASS) + os.path.sep 

61 SYS_PREFIXLEN = len(SYS_PREFIX) 

62 

63 for pkg_path in path: 

64 pkg_path = os.path.realpath(pkg_path) # Fully resolve the given path, in case it contains symbolic links. 

65 if not pkg_path.startswith(SYS_PREFIX): 

66 # if the path does not start with sys._MEIPASS then it cannot be a bundled package. 

67 continue 

68 # Construct package prefix from path... 

69 pkg_prefix = pkg_path[SYS_PREFIXLEN:] 

70 pkg_prefix = pkg_prefix.replace(os.path.sep, '.') 

71 # ... and ensure it ends with a dot (so we can directly filter out the package itself). 

72 if not pkg_prefix.endswith('.'): 

73 pkg_prefix += '.' 

74 pkg_prefix_len = len(pkg_prefix) 

75 

76 for entry in importer.toc: 

77 if not entry.startswith(pkg_prefix): 

78 continue 

79 name = entry[pkg_prefix_len:] 

80 if name.count('.') != 0: 

81 continue 

82 is_pkg = importer.is_package(entry) 

83 yield pkgutil.ModuleInfo(importer, prefix + name, is_pkg) 

84 

85 

86pkgutil.iter_modules = _pyi_pkgutil_iter_modules