pyiboot01_bootstrap.py
4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#-----------------------------------------------------------------------------
# Copyright (c) 2005-2021, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
### Start bootstrap process
# Only python built-in modules can be used.
import sys
import pyimod03_importers
# Extend Python import machinery by adding PEP302 importers to sys.meta_path.
pyimod03_importers.install()
### Bootstrap process is complete.
# We can use other python modules (e.g. os)
import os
# Let other python modules know that the code is running in frozen mode.
if not hasattr(sys, 'frozen'):
sys.frozen = True
# sys._MEIPASS is now set in the bootloader. Hooray.
# Python 3 C-API function Py_SetPath() resets sys.prefix to empty string.
# Python 2 was using PYTHONHOME for sys.prefix. Let's do the same for Python 3.
sys.prefix = sys._MEIPASS
sys.exec_prefix = sys.prefix
# Python 3.3+ defines also sys.base_prefix. Let's set them too.
sys.base_prefix = sys.prefix
sys.base_exec_prefix = sys.exec_prefix
# Some packages behaves differently when running inside virtual environment.
# E.g. IPython tries to append path VIRTUAL_ENV to sys.path.
# For the frozen app we want to prevent this behavior.
VIRTENV = 'VIRTUAL_ENV'
if VIRTENV in os.environ:
# On some platforms (e.g. AIX) 'os.unsetenv()' is not available and then
# deleting the var from os.environ does not delete it from the environment.
os.environ[VIRTENV] = ''
del os.environ[VIRTENV]
# Ensure sys.path contains absolute paths. Otherwise import of other python
# modules will fail when current working directory is changed by frozen
# application.
python_path = []
for pth in sys.path:
python_path.append(os.path.abspath(pth))
sys.path = python_path
# Implement workaround for prints in non-console mode. In non-console mode
# (with "pythonw"), print randomly fails with "[errno 9] Bad file descriptor"
# when the printed text is flushed (eg: buffer full); this is because the
# sys.stdout object is bound to an invalid file descriptor.
# Python 3000 has a fix for it (http://bugs.python.org/issue1415), but we
# feel that a workaround in PyInstaller is a good thing since most people
# found this problem for the first time with PyInstaller as they don't
# usually run their code with "pythonw" (and it's hard to debug anyway).
class NullWriter:
softspace = 0
encoding = 'UTF-8'
def write(*args):
pass
def flush(*args):
pass
# Some packages are checking if stdout/stderr is available.
# e.g. youtube-dl for details see #1883
def isatty(self):
return False
# sys.stdout/err is None in GUI mode on Windows.
if sys.stdout is None:
sys.stdout = NullWriter()
if sys.stderr is None:
sys.stderr = NullWriter()
# At least on Windows, Python seems to hook up the codecs on this
# import, so it's not enough to just package up all the encodings.
#
# It was also reported that without 'encodings' module the frozen executable
# will fail to load in some configurations:
#
# http://www.pyinstaller.org/ticket/651
#
# Import 'encodings' module in a run-time hook is not enough since some
# run-time hooks require this module and the order of running code from
# from run-time hooks is not defined.
try:
import encodings
except ImportError:
pass
# In the Python interpreter 'warnings' module is imported when 'sys.warnoptions'
# is not empty. Mimic this behavior in PyInstaller.
if sys.warnoptions:
import warnings
# Install the hooks for ctypes
import pyimod04_ctypes # noqa: E402
pyimod04_ctypes.install()
# Make .eggs and zipfiles available at runtime
d = "eggs"
d = os.path.join(sys._MEIPASS, d)
# Test if the 'eggs' directory exists. This allows to
# opportunistically including this script into the packaged exe, even
# if no eggs as found when packaging the program. (Which may be a
# use-case, see issue #653.
if os.path.isdir(d):
for fn in os.listdir(d):
sys.path.append(os.path.join(d, fn))