compat.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2005-2021, 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. """
  12. Various classes and functions to provide some backwards-compatibility
  13. with previous versions of Python onward.
  14. """
  15. import os
  16. import platform
  17. import site
  18. import subprocess
  19. import sys
  20. import errno
  21. import importlib.machinery
  22. from PyInstaller.exceptions import ExecCommandFailed
  23. from PyInstaller._shared_with_waf import _pyi_machine
  24. # Copied from https://docs.python.org/3/library/platform.html#cross-platform.
  25. is_64bits = sys.maxsize > 2**32
  26. # Distinguish specific code for various Python versions.
  27. # Variables 'is_pyXY' mean that Python X.Y and up is supported.
  28. # Keep even unsupported versions here to keep 3rd-party hooks working.
  29. is_py35 = sys.version_info >= (3, 5)
  30. is_py36 = sys.version_info >= (3, 6)
  31. is_py37 = sys.version_info >= (3, 7)
  32. is_py38 = sys.version_info >= (3, 8)
  33. is_py39 = sys.version_info >= (3, 9)
  34. is_win = sys.platform.startswith('win')
  35. is_win_10 = is_win and (platform.win32_ver()[0] == '10')
  36. is_cygwin = sys.platform == 'cygwin'
  37. is_darwin = sys.platform == 'darwin' # Mac OS X
  38. # Unix platforms
  39. is_linux = sys.platform.startswith('linux')
  40. is_solar = sys.platform.startswith('sun') # Solaris
  41. is_aix = sys.platform.startswith('aix')
  42. is_freebsd = sys.platform.startswith('freebsd')
  43. is_openbsd = sys.platform.startswith('openbsd')
  44. is_hpux = sys.platform.startswith('hp-ux')
  45. # Some code parts are similar to several unix platforms
  46. # (e.g. Linux, Solaris, AIX)
  47. # Mac OS X is not considered as unix since there are many
  48. # platform specific details for Mac in PyInstaller.
  49. is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux or is_openbsd
  50. # On different platforms is different file for dynamic python library.
  51. # TODO: When removing support for is_py37, the "m" variants can be
  52. # removed, see
  53. # <https://docs.python.org/3/whatsnew/3.8.html#build-and-c-api-changes>
  54. _pyver = sys.version_info[:2]
  55. if is_win or is_cygwin:
  56. PYDYLIB_NAMES = {'python%d%d.dll' % _pyver,
  57. 'libpython%d%d.dll' % _pyver,
  58. 'libpython%d%dm.dll' % _pyver,
  59. 'libpython%d.%d.dll' % _pyver,
  60. 'libpython%d.%dm.dll' % _pyver} # For MSYS2 environment
  61. elif is_darwin:
  62. # libpython%d.%dm.dylib for Conda virtual environment installations
  63. PYDYLIB_NAMES = {'Python', '.Python',
  64. 'Python%d' % _pyver[0],
  65. 'libpython%d.%d.dylib' % _pyver,
  66. 'libpython%d.%dm.dylib' % _pyver}
  67. elif is_aix:
  68. # Shared libs on AIX may be archives with shared object members,
  69. # hence the ".a" suffix. However, starting with python 2.7.11
  70. # libpython?.?.so and Python3 libpython?.?m.so files are produced.
  71. PYDYLIB_NAMES = {'libpython%d.%d.a' % _pyver,
  72. 'libpython%d.%dm.a' % _pyver,
  73. 'libpython%d.%d.so' % _pyver,
  74. 'libpython%d.%dm.so' % _pyver}
  75. elif is_freebsd:
  76. PYDYLIB_NAMES = {'libpython%d.%d.so.1' % _pyver,
  77. 'libpython%d.%dm.so.1' % _pyver,
  78. 'libpython%d.%d.so.1.0' % _pyver,
  79. 'libpython%d.%dm.so.1.0' % _pyver}
  80. elif is_openbsd:
  81. PYDYLIB_NAMES = {'libpython%d.%d.so.0.0' % _pyver,
  82. 'libpython%d.%dm.so.0.0' % _pyver}
  83. elif is_hpux:
  84. PYDYLIB_NAMES = {'libpython%d.%d.so' % _pyver}
  85. elif is_unix:
  86. # Other *nix platforms.
  87. # Python 2 .so library on Linux is: libpython2.7.so.1.0
  88. # Python 3 .so library on Linux is: libpython3.2mu.so.1.0, libpython3.3m.so.1.0
  89. PYDYLIB_NAMES = {'libpython%d.%d.so.1.0' % _pyver,
  90. 'libpython%d.%dm.so.1.0' % _pyver,
  91. 'libpython%d.%dmu.so.1.0' % _pyver,
  92. 'libpython%d.%dm.so' % _pyver,
  93. 'libpython%d.%d.so' % _pyver}
  94. else:
  95. raise SystemExit('Your platform is not yet supported. '
  96. 'Please define constant PYDYLIB_NAMES for your platform.')
  97. # Function with which to open files.
  98. open_file = open
  99. text_read_mode = 'r'
  100. # In Python 3 built-in function raw_input() was renamed to just 'input()'.
  101. stdin_input = input
  102. # Safe repr that always outputs ascii
  103. safe_repr = ascii
  104. # String types to replace `isinstance(foo, str)`
  105. # Use `isinstance(foo, string_types)` instead.
  106. string_types = str
  107. # Correct extension ending: 'c' or 'o'
  108. if __debug__:
  109. PYCO = 'c'
  110. else:
  111. PYCO = 'o'
  112. # Options for python interpreter when invoked in a subprocess.
  113. if __debug__:
  114. # Python started *without* -O
  115. _PYOPTS = ''
  116. else:
  117. _PYOPTS = '-O'
  118. # In a virtual environment created by virtualenv (github.com/pypa/virtualenv)
  119. # there exists sys.real_prefix with the path to the base Python
  120. # installation from which the virtual environment was created.
  121. # This is true regardless of
  122. # the version of Python used to execute the virtualenv command.
  123. #
  124. # In a virtual environment created by the venv module available in
  125. # the Python standard lib, there exists sys.base_prefix with the path to
  126. # the base implementation. This does not exist in
  127. # a virtual environment created by virtualenv.
  128. #
  129. # The following code creates compat.is_venv and is.virtualenv
  130. # that are True when running a virtual environment, and also
  131. # compat.base_prefix with the path to the
  132. # base Python installation.
  133. base_prefix = os.path.abspath(
  134. getattr(sys, 'real_prefix', getattr(sys, 'base_prefix', sys.prefix))
  135. )
  136. # Ensure `base_prefix` is not containing any relative parts.
  137. is_venv = is_virtualenv = base_prefix != os.path.abspath(sys.prefix)
  138. # Conda environments sometimes have different paths or apply patches to
  139. # packages that can affect how a hook or package should access resources.
  140. # Method for determining conda taken from:
  141. # https://stackoverflow.com/questions/47610844#47610844
  142. is_conda = os.path.isdir(os.path.join(base_prefix, 'conda-meta'))
  143. # Similar to ``is_conda`` but is ``False`` using another ``venv``-like manager
  144. # on top. In this case, no packages encountered will be conda packages meaning
  145. # that the default non-conda behaviour is generally desired from PyInstaller.
  146. is_pure_conda = os.path.isdir(os.path.join(sys.prefix, 'conda-meta'))
  147. # Full path to python interpreter.
  148. python_executable = getattr(sys, '_base_executable', sys.executable)
  149. # Is this Python from Microsoft App Store (Windows only)?
  150. # Python from Microsoft App Store has executable pointing at empty shims.
  151. is_ms_app_store = is_win and os.path.getsize(python_executable) == 0
  152. if is_ms_app_store:
  153. # Locate the actual executable inside base_prefix.
  154. python_executable = os.path.join(
  155. base_prefix, os.path.basename(python_executable))
  156. if not os.path.exists(python_executable):
  157. raise SystemExit('PyInstaller cannot locate real python executable '
  158. 'belonging to Python from Microsoft App Store!')
  159. # In Python 3.4 module 'imp' is deprecated and there is another way how
  160. # to obtain magic value.
  161. import importlib.util
  162. BYTECODE_MAGIC = importlib.util.MAGIC_NUMBER
  163. # List of suffixes for Python C extension modules.
  164. from importlib.machinery import EXTENSION_SUFFIXES, all_suffixes
  165. ALL_SUFFIXES = all_suffixes()
  166. # In Python 3 'Tkinter' has been made lowercase - 'tkinter'.
  167. # TODO: remove once all references are gone from both pyinstaller and
  168. # pyinstaller-hooks-contrib!
  169. modname_tkinter = 'tkinter'
  170. # On Windows we require pywin32-ctypes
  171. # -> all pyinstaller modules should use win32api from PyInstaller.compat to
  172. # ensure that it can work on MSYS2 (which requires pywin32-ctypes)
  173. if is_win:
  174. try:
  175. from win32ctypes.pywin32 import pywintypes # noqa: F401
  176. from win32ctypes.pywin32 import win32api
  177. except ImportError:
  178. # This environment variable is set by setup.py
  179. # - It's not an error for pywin32 to not be installed at that point
  180. if not os.environ.get('PYINSTALLER_NO_PYWIN32_FAILURE'):
  181. raise SystemExit('PyInstaller cannot check for assembly dependencies.\n'
  182. 'Please install pywin32-ctypes.\n\n'
  183. 'pip install pywin32-ctypes\n')
  184. # macOS's platform.architecture() can be buggy, so we do this manually here.
  185. # Based off the python documentation:
  186. # https://docs.python.org/3/library/platform.html#platform.architecture
  187. architecture = '64bit' if sys.maxsize > 2**32 and is_darwin else \
  188. '32bit' if is_darwin else platform.architecture()[0]
  189. # Cygwin needs special handling, because platform.system() contains
  190. # identifiers such as MSYS_NT-10.0-19042 and CYGWIN_NT-10.0-19042 that
  191. # do not fit PyInstaller's OS naming scheme. Explicitly set `system` to
  192. # 'Cygwin'.
  193. if is_cygwin:
  194. system = 'Cygwin'
  195. else:
  196. system = platform.system()
  197. # Machine suffix for bootloader.
  198. machine = _pyi_machine(platform.machine(), platform.system())
  199. # Set and get environment variables does not handle unicode strings correctly
  200. # on Windows.
  201. # Acting on os.environ instead of using getenv()/setenv()/unsetenv(),
  202. # as suggested in <http://docs.python.org/library/os.html#os.environ>:
  203. # "Calling putenv() directly does not change os.environ, so it's
  204. # better to modify os.environ." (Same for unsetenv.)
  205. def getenv(name, default=None):
  206. """
  207. Returns unicode string containing value of environment variable 'name'.
  208. """
  209. return os.environ.get(name, default)
  210. def setenv(name, value):
  211. """
  212. Accepts unicode string and set it as environment variable 'name' containing
  213. value 'value'.
  214. """
  215. os.environ[name] = value
  216. def unsetenv(name):
  217. """
  218. Delete the environment variable 'name'.
  219. """
  220. # Some platforms (e.g. AIX) do not support `os.unsetenv()` and
  221. # thus `del os.environ[name]` has no effect onto the real
  222. # environment. For this case we set the value to the empty string.
  223. os.environ[name] = ""
  224. del os.environ[name]
  225. # Exec commands in subprocesses.
  226. def exec_command(*cmdargs, **kwargs):
  227. """
  228. Run the command specified by the passed positional arguments, optionally
  229. configured by the passed keyword arguments.
  230. .. DANGER::
  231. **Ignore this function's return value** -- unless this command's standard
  232. output contains _only_ pathnames, in which case this function returns the
  233. correct filesystem-encoded string expected by PyInstaller. In all other
  234. cases, this function's return value is _not_ safely usable. Consider
  235. calling the general-purpose `exec_command_stdout()` function instead.
  236. For backward compatibility, this function's return value non-portably
  237. depends on the current Python version and passed keyword arguments:
  238. * Under Python 2.7, this value is an **encoded `str` string** rather than
  239. a decoded `unicode` string. This value _cannot_ be safely used for any
  240. purpose (e.g., string manipulation or parsing), except to be passed
  241. directly to another non-Python command.
  242. * Under Python 3.x, this value is a **decoded `str` string**. However,
  243. even this value is _not_ necessarily safely usable:
  244. * If the `encoding` parameter is passed, this value is guaranteed to be
  245. safely usable.
  246. * Else, this value _cannot_ be safely used for any purpose (e.g.,
  247. string manipulation or parsing), except to be passed directly to
  248. another non-Python command. Why? Because this value has been decoded
  249. with the encoding specified by `sys.getfilesystemencoding()`, the
  250. encoding used by `os.fsencode()` and `os.fsdecode()` to convert from
  251. platform-agnostic to platform-specific pathnames. This is _not_
  252. necessarily the encoding with which this command's standard output
  253. was encoded. Cue edge-case decoding exceptions.
  254. Parameters
  255. ----------
  256. cmdargs :
  257. Variadic list whose:
  258. 1. Mandatory first element is the absolute path, relative path,
  259. or basename in the current `${PATH}` of the command to run.
  260. 1. Optional remaining elements are arguments to pass to this command.
  261. encoding : str, optional
  262. Optional keyword argument specifying the encoding with which to decode
  263. this command's standard output under Python 3. As this function's return
  264. value should be ignored, this argument should _never_ be passed.
  265. __raise_ENOENT__ : boolean, optional
  266. Optional keyword argument to simply raise the exception if the
  267. executing the command fails since to the command is not found. This is
  268. useful to checking id a command exists.
  269. All remaining keyword arguments are passed as is to the `subprocess.Popen()`
  270. constructor.
  271. Returns
  272. ----------
  273. str
  274. Ignore this value. See discussion above.
  275. """
  276. encoding = kwargs.pop('encoding', None)
  277. raise_ENOENT = kwargs.pop('__raise_ENOENT__', None)
  278. try:
  279. proc = subprocess.Popen(cmdargs, stdout=subprocess.PIPE, **kwargs)
  280. out = proc.communicate(timeout=60)[0]
  281. except OSError as e:
  282. if raise_ENOENT and e.errno == errno.ENOENT:
  283. raise
  284. print('--' * 20, file=sys.stderr)
  285. print("Error running '%s':" % " ".join(cmdargs), file=sys.stderr)
  286. print(e, file=sys.stderr)
  287. print('--' * 20, file=sys.stderr)
  288. raise ExecCommandFailed("Error: Executing command failed!") from e
  289. except subprocess.TimeoutExpired:
  290. proc.kill()
  291. raise
  292. # stdout/stderr are returned as a byte array NOT as string.
  293. # Thus we need to convert that to proper encoding.
  294. try:
  295. if encoding:
  296. out = out.decode(encoding)
  297. else:
  298. # If no encoding is given, assume we're reading filenames from
  299. # stdout only because it's the common case.
  300. out = os.fsdecode(out)
  301. except UnicodeDecodeError as e:
  302. # The sub-process used a different encoding,
  303. # provide more information to ease debugging.
  304. print('--' * 20, file=sys.stderr)
  305. print(str(e), file=sys.stderr)
  306. print('These are the bytes around the offending byte:',
  307. file=sys.stderr)
  308. print('--' * 20, file=sys.stderr)
  309. raise
  310. return out
  311. def exec_command_rc(*cmdargs, **kwargs):
  312. """
  313. Return the exit code of the command specified by the passed positional
  314. arguments, optionally configured by the passed keyword arguments.
  315. Parameters
  316. ----------
  317. cmdargs : list
  318. Variadic list whose:
  319. 1. Mandatory first element is the absolute path, relative path,
  320. or basename in the current `${PATH}` of the command to run.
  321. 1. Optional remaining elements are arguments to pass to this command.
  322. All keyword arguments are passed as is to the `subprocess.call()` function.
  323. Returns
  324. ----------
  325. int
  326. This command's exit code as an unsigned byte in the range `[0, 255]`,
  327. where 0 signifies success and all other values failure.
  328. """
  329. # 'encoding' keyword is not supported for 'subprocess.call'.
  330. # Remove it thus from kwargs.
  331. if 'encoding' in kwargs:
  332. kwargs.pop('encoding')
  333. return subprocess.call(cmdargs, **kwargs)
  334. def exec_command_stdout(*command_args, **kwargs):
  335. """
  336. Capture and return the standard output of the command specified by the
  337. passed positional arguments, optionally configured by the passed keyword
  338. arguments.
  339. Unlike the legacy `exec_command()` and `exec_command_all()` functions, this
  340. modern function is explicitly designed for cross-platform portability. The
  341. return value may be safely used for any purpose, including string
  342. manipulation and parsing.
  343. .. NOTE::
  344. If this command's standard output contains _only_ pathnames, this
  345. function does _not_ return the correct filesystem-encoded string expected
  346. by PyInstaller. If this is the case, consider calling the
  347. filesystem-specific `exec_command()` function instead.
  348. Parameters
  349. ----------
  350. cmdargs : list
  351. Variadic list whose:
  352. 1. Mandatory first element is the absolute path, relative path,
  353. or basename in the current `${PATH}` of the command to run.
  354. 1. Optional remaining elements are arguments to pass to this command.
  355. encoding : str, optional
  356. Optional name of the encoding with which to decode this command's
  357. standard output (e.g., `utf8`), passed as a keyword argument. If
  358. unpassed , this output will be decoded in a portable manner specific to
  359. to the current platform, shell environment, and system settings with
  360. Python's built-in `universal_newlines` functionality.
  361. All remaining keyword arguments are passed as is to the
  362. `subprocess.check_output()` function.
  363. Returns
  364. ----------
  365. str
  366. Unicode string of this command's standard output decoded according to
  367. the "encoding" keyword argument.
  368. """
  369. # Value of the passed "encoding" parameter, defaulting to None.
  370. encoding = kwargs.pop('encoding', None)
  371. # If no encoding was specified, the current locale is defaulted to. Else, an
  372. # encoding was specified. To ensure this encoding is respected, the
  373. # "universal_newlines" option is disabled if also passed. Nice, eh?
  374. kwargs['universal_newlines'] = encoding is None
  375. # Standard output captured from this command as a decoded Unicode string if
  376. # "universal_newlines" is enabled or an encoded byte array otherwise.
  377. stdout = subprocess.check_output(command_args, **kwargs)
  378. # Return a Unicode string, decoded from this encoded byte array if needed.
  379. return stdout if encoding is None else stdout.decode(encoding)
  380. def exec_command_all(*cmdargs, **kwargs):
  381. """
  382. Run the command specified by the passed positional arguments, optionally
  383. configured by the passed keyword arguments.
  384. .. DANGER::
  385. **Ignore this function's return value.** If this command's standard
  386. output consists solely of pathnames, consider calling `exec_command()`;
  387. else, consider calling `exec_command_stdout()`.
  388. Parameters
  389. ----------
  390. cmdargs : list
  391. Variadic list whose:
  392. 1. Mandatory first element is the absolute path, relative path,
  393. or basename in the current `${PATH}` of the command to run.
  394. 1. Optional remaining elements are arguments to pass to this command.
  395. encoding : str, optional
  396. Optional keyword argument specifying the encoding with which to decode
  397. this command's standard output. As this function's return
  398. value should be ignored, this argument should _never_ be passed.
  399. All remaining keyword arguments are passed as is to the `subprocess.Popen()`
  400. constructor.
  401. Returns
  402. ----------
  403. (int, str, str)
  404. Ignore this 3-element tuple `(exit_code, stdout, stderr)`. See the
  405. `exec_command()` function for discussion.
  406. """
  407. encoding = kwargs.pop('encoding', None)
  408. proc = subprocess.Popen(cmdargs, bufsize=-1, # Default OS buffer size.
  409. stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
  410. # Waits for subprocess to complete.
  411. try:
  412. out, err = proc.communicate(timeout=60)
  413. except subprocess.TimeoutExpired:
  414. proc.kill()
  415. raise
  416. # stdout/stderr are returned as a byte array NOT as string.
  417. # Thus we need to convert that to proper encoding.
  418. try:
  419. if encoding:
  420. out = out.decode(encoding)
  421. err = err.decode(encoding)
  422. else:
  423. # If no encoding is given, assume we're reading filenames from
  424. # stdout only because it's the common case.
  425. out = os.fsdecode(out)
  426. err = os.fsdecode(err)
  427. except UnicodeDecodeError as e:
  428. # The sub-process used a different encoding,
  429. # provide more information to ease debugging.
  430. print('--' * 20, file=sys.stderr)
  431. print(str(e), file=sys.stderr)
  432. print('These are the bytes around the offending byte:',
  433. file=sys.stderr)
  434. print('--' * 20, file=sys.stderr)
  435. raise
  436. return proc.returncode, out, err
  437. def __wrap_python(args, kwargs):
  438. cmdargs = [sys.executable]
  439. # Mac OS X supports universal binaries (binary for multiple architectures.
  440. # We need to ensure that subprocess binaries are running for the same
  441. # architecture as python executable.
  442. # It is necessary to run binaries with 'arch' command.
  443. if is_darwin:
  444. if architecture == '64bit':
  445. if platform.machine() == 'arm64':
  446. py_prefix = ['arch', '-arm64'] # Apple M1
  447. else:
  448. py_prefix = ['arch', '-x86_64'] # Intel
  449. elif architecture == '32bit':
  450. py_prefix = ['arch', '-i386']
  451. else:
  452. py_prefix = []
  453. # Since OS X 10.11 the environment variable DYLD_LIBRARY_PATH is no
  454. # more inherited by child processes, so we proactively propagate
  455. # the current value using the `-e` option of the `arch` command.
  456. if 'DYLD_LIBRARY_PATH' in os.environ:
  457. path = os.environ['DYLD_LIBRARY_PATH']
  458. py_prefix += ['-e', 'DYLD_LIBRARY_PATH=%s' % path]
  459. cmdargs = py_prefix + cmdargs
  460. if _PYOPTS:
  461. cmdargs.append(_PYOPTS)
  462. cmdargs.extend(args)
  463. env = kwargs.get('env')
  464. if env is None:
  465. env = dict(**os.environ)
  466. # Ensure python 3 subprocess writes 'str' as utf-8
  467. env['PYTHONIOENCODING'] = 'UTF-8'
  468. # ... and ensure we read output as utf-8
  469. kwargs['encoding'] = 'UTF-8'
  470. return cmdargs, kwargs
  471. def exec_python(*args, **kwargs):
  472. """
  473. Wrap running python script in a subprocess.
  474. Return stdout of the invoked command.
  475. """
  476. cmdargs, kwargs = __wrap_python(args, kwargs)
  477. return exec_command(*cmdargs, **kwargs)
  478. def exec_python_rc(*args, **kwargs):
  479. """
  480. Wrap running python script in a subprocess.
  481. Return exit code of the invoked command.
  482. """
  483. cmdargs, kwargs = __wrap_python(args, kwargs)
  484. return exec_command_rc(*cmdargs, **kwargs)
  485. ## Path handling.
  486. def expand_path(path):
  487. """
  488. Replace initial tilde '~' in path with user's home directory and also
  489. expand environment variables (${VARNAME} - Unix, %VARNAME% - Windows).
  490. """
  491. return os.path.expandvars(os.path.expanduser(path))
  492. # Site-packages functions - use native function if available.
  493. def getsitepackages(prefixes=None):
  494. """Returns a list containing all global site-packages directories.
  495. For each directory present in ``prefixes`` (or the global ``PREFIXES``),
  496. this function will find its `site-packages` subdirectory depending on the
  497. system environment, and will return a list of full paths.
  498. """
  499. # This implementation was copied from the ``site`` module, python 3.7.3.
  500. sitepackages = []
  501. seen = set()
  502. if prefixes is None:
  503. prefixes = [sys.prefix, sys.exec_prefix]
  504. for prefix in prefixes:
  505. if not prefix or prefix in seen:
  506. continue
  507. seen.add(prefix)
  508. if os.sep == '/':
  509. sitepackages.append(
  510. os.path.join(
  511. prefix, "lib", "python%d.%d" % sys.version_info[:2],
  512. "site-packages"
  513. )
  514. )
  515. else:
  516. sitepackages.append(prefix)
  517. sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
  518. return sitepackages
  519. # Backported for virtualenv.
  520. # Module 'site' in virtualenv might not have this attribute.
  521. getsitepackages = getattr(site, 'getsitepackages', getsitepackages)
  522. # Wrapper to load a module from a Python source file.
  523. # This function loads import hooks when processing them.
  524. def importlib_load_source(name, pathname):
  525. # Import module from a file.
  526. mod_loader = importlib.machinery.SourceFileLoader(name, pathname)
  527. return mod_loader.load_module()
  528. # Patterns of module names that should be bundled into the base_library.zip.
  529. PY3_BASE_MODULES = {
  530. # Python 3.x
  531. # These modules are direct or indirect dependencies of encodings.* modules.
  532. # encodings modules must be recursively included to set the I/O encoding during
  533. # python startup.
  534. '_bootlocale',
  535. '_collections_abc',
  536. '_weakrefset',
  537. 'abc',
  538. 'codecs',
  539. 'collections',
  540. 'copyreg',
  541. 'encodings',
  542. 'enum',
  543. 'functools',
  544. 'io',
  545. 'heapq',
  546. 'keyword',
  547. 'linecache',
  548. 'locale',
  549. 'operator',
  550. 're',
  551. 'reprlib',
  552. 'sre_compile',
  553. 'sre_constants',
  554. 'sre_parse',
  555. 'traceback', # for startup errors
  556. 'types',
  557. 'weakref',
  558. 'warnings',
  559. }
  560. # Object types of Pure Python modules in modulegraph dependency graph.
  561. # Pure Python modules have code object (attribute co_code).
  562. PURE_PYTHON_MODULE_TYPES = {
  563. 'SourceModule',
  564. 'CompiledModule',
  565. 'Package',
  566. 'NamespacePackage',
  567. # Deprecated.
  568. # TODO Could these module types be removed?
  569. 'FlatPackage',
  570. 'ArchiveModule',
  571. }
  572. # Object types of special Python modules (built-in, run-time, namespace package)
  573. # in modulegraph dependency graph that do not have code object.
  574. SPECIAL_MODULE_TYPES = {
  575. 'AliasNode',
  576. 'BuiltinModule',
  577. 'RuntimeModule',
  578. 'RuntimePackage',
  579. # PyInstaller handles scripts differently and not as standard Python modules.
  580. 'Script',
  581. }
  582. # Object types of Binary Python modules (extensions, etc) in modulegraph
  583. # dependency graph.
  584. BINARY_MODULE_TYPES = {
  585. 'Extension',
  586. 'ExtensionPackage',
  587. }
  588. # Object types of valid Python modules in modulegraph dependency graph.
  589. VALID_MODULE_TYPES = PURE_PYTHON_MODULE_TYPES | SPECIAL_MODULE_TYPES | BINARY_MODULE_TYPES
  590. # Object types of bad/missing/invalid Python modules in modulegraph
  591. # dependency graph.
  592. # TODO Should be 'Invalid' module types also in the 'MISSING' set?
  593. BAD_MODULE_TYPES = {
  594. 'BadModule',
  595. 'ExcludedModule',
  596. 'InvalidSourceModule',
  597. 'InvalidCompiledModule',
  598. 'MissingModule',
  599. # Runtime modules and packages are technically valid rather than bad, but
  600. # exist only in-memory rather than on-disk (typically due to
  601. # pre_safe_import_module() hooks) and hence cannot be physically frozen.
  602. # For simplicity, these nodes are categorized as bad rather than valid.
  603. 'RuntimeModule',
  604. 'RuntimePackage',
  605. }
  606. ALL_MODULE_TYPES = VALID_MODULE_TYPES | BAD_MODULE_TYPES
  607. # TODO Review this mapping to TOC, remove useless entries.
  608. # Dict to map ModuleGraph node types to TOC typecodes
  609. MODULE_TYPES_TO_TOC_DICT = {
  610. # Pure modules.
  611. 'AliasNode': 'PYMODULE',
  612. 'Script': 'PYSOURCE',
  613. 'SourceModule': 'PYMODULE',
  614. 'CompiledModule': 'PYMODULE',
  615. 'Package': 'PYMODULE',
  616. 'FlatPackage': 'PYMODULE',
  617. 'ArchiveModule': 'PYMODULE',
  618. # Binary modules.
  619. 'Extension': 'EXTENSION',
  620. 'ExtensionPackage': 'EXTENSION',
  621. # Special valid modules.
  622. 'BuiltinModule': 'BUILTIN',
  623. 'NamespacePackage': 'PYMODULE',
  624. # Bad modules.
  625. 'BadModule': 'bad',
  626. 'ExcludedModule': 'excluded',
  627. 'InvalidSourceModule': 'invalid',
  628. 'InvalidCompiledModule': 'invalid',
  629. 'MissingModule': 'missing',
  630. 'RuntimeModule': 'runtime',
  631. 'RuntimePackage': 'runtime',
  632. # Other.
  633. 'does not occur': 'BINARY',
  634. }
  635. def check_requirements():
  636. """
  637. Verify that all requirements to run PyInstaller are met.
  638. Fail hard if any requirement is not met.
  639. """
  640. # Fail hard if Python does not have minimum required version
  641. if sys.version_info < (3, 6):
  642. raise EnvironmentError('PyInstaller requires at Python 3.6 or newer.')