pyiboot01_bootstrap.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2005-2023, PyInstaller Development Team.
  3. #
  4. # Distributed under the terms of the GNU General Public License (version 2
  5. # or later) with exception for distributing the bootloader.
  6. #
  7. # The full license is in the file COPYING.txt, distributed with this software.
  8. #
  9. # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
  10. #-----------------------------------------------------------------------------
  11. def _pyi_bootstrap():
  12. #-- Start bootstrap process
  13. # Only python built-in modules and modules from base_library.zip can be used at this point.
  14. import sys # built-in
  15. import os # base_library.zip
  16. # Extend Python import machinery with our importer(s).
  17. import pyimod02_importers
  18. pyimod02_importers.install()
  19. #-- Bootstrap process is complete.
  20. # We can now use python modules that were collected into PYZ archive.
  21. # Let other python modules know that the code is running in frozen mode.
  22. if not hasattr(sys, 'frozen'):
  23. sys.frozen = True
  24. # NOTE: sys._MEIPASS is set by the bootloader.
  25. # Some packages behave differently when running inside virtual environment. E.g., IPython tries to append path
  26. # VIRTUAL_ENV to sys.path. For the frozen app we want to prevent this behavior.
  27. VIRTENV = 'VIRTUAL_ENV'
  28. if VIRTENV in os.environ:
  29. # On some platforms (e.g., AIX) 'os.unsetenv()' is unavailable and deleting the var from os.environ does not
  30. # delete it from the environment.
  31. os.environ[VIRTENV] = ''
  32. del os.environ[VIRTENV]
  33. # At least on Windows, Python seems to hook up the codecs on this import, so it is not enough to just package up all
  34. # the encodings.
  35. #
  36. # It was also reported that without 'encodings' module, the frozen executable fails to load in some configurations:
  37. # http://www.pyinstaller.org/ticket/651
  38. #
  39. # Importing 'encodings' module in a run-time hook is not enough, since some run-time hooks require this module, and
  40. # the order of running the code from the run-time hooks is not defined.
  41. try:
  42. import encodings
  43. except ImportError:
  44. encodings = None
  45. # Starting with python 3.15.0b1, the `encodings` package is frozen (in the cpython sense), along with some of its
  46. # submodules; see https://github.com/python/cpython/commit/0012686d92fe51f426bcd6797e2f2a50ad4ac74. Consequently,
  47. # the `encodings/__init__.pyc` module from our `base_library.zip` is not used anymore, and so the `encodings`
  48. # directory in our base library archive is not searched, albeit it contains all non-frozen encoding modules.
  49. # Therefore, we need to manually add that directory to `encodings.__path__`, otherwise we end up missing support
  50. # for most of encodings.
  51. if encodings and hasattr(encodings, '__path__'):
  52. encodings_dir = os.path.join(sys._MEIPASS, 'base_library.zip', 'encodings')
  53. if encodings_dir not in encodings.__path__:
  54. encodings.__path__.append(encodings_dir)
  55. # In the Python interpreter 'warnings' module is imported when 'sys.warnoptions' is not empty. Mimic this behavior.
  56. if sys.warnoptions:
  57. try:
  58. import warnings # noqa: F401
  59. except ImportError:
  60. pass
  61. # Install the hooks for ctypes
  62. import pyimod03_ctypes # noqa: E402
  63. pyimod03_ctypes.install()
  64. # Install the hooks for pywin32 (Windows only)
  65. if sys.platform.startswith('win'):
  66. import pyimod04_pywin32
  67. pyimod04_pywin32.install()
  68. # Apply a hack for metadata that was collected from (unzipped) python eggs; the EGG-INFO directories are collected
  69. # into their parent directories (my_package-version.egg/EGG-INFO), and for metadata to be discoverable by
  70. # `importlib.metadata`, the .egg directory needs to be in `sys.path`. The deprecated `pkg_resources` does not have
  71. # this limitation, and seems to work as long as the .egg directory's parent directory (in our case `sys._MEIPASS`
  72. # is in `sys.path`).
  73. for entry in os.listdir(sys._MEIPASS):
  74. entry = os.path.join(sys._MEIPASS, entry)
  75. if not os.path.isdir(entry):
  76. continue
  77. if entry.endswith('.egg'):
  78. sys.path.append(entry)
  79. _pyi_bootstrap()
  80. del _pyi_bootstrap