Issue #28137: Renames Windows path file to ._pth
Issue #28138: Windows ._pth file should allow import site
This commit is contained in:
parent
313523ce2d
commit
ed51b26858
|
@ -720,15 +720,24 @@ installation directory. So, if you had installed Python to
|
||||||
:file:`C:\\Python\\Lib\\` and third-party modules should be stored in
|
:file:`C:\\Python\\Lib\\` and third-party modules should be stored in
|
||||||
:file:`C:\\Python\\Lib\\site-packages\\`.
|
:file:`C:\\Python\\Lib\\site-packages\\`.
|
||||||
|
|
||||||
To completely override :data:`sys.path`, create a text file named ``'sys.path'``
|
To completely override :data:`sys.path`, create a ``._pth`` file with the same
|
||||||
containing a list of paths alongside the Python executable. This will ignore all
|
name as the DLL (``python36._pth``) or the executable (``python._pth``) and
|
||||||
registry settings and environment variables, enable isolated mode, disable
|
specify one line for each path to add to :data:`sys.path`. The file based on the
|
||||||
importing :mod:`site`, and fill :data:`sys.path` with exactly the paths listed
|
DLL name overrides the one based on the executable, which allows paths to be
|
||||||
in the file. Paths may be absolute or relative to the directory containing the
|
restricted for any program loading the runtime if desired.
|
||||||
file.
|
|
||||||
|
|
||||||
When the ``'sys.path'`` file is missing, this is how :data:`sys.path` is
|
When the file exists, all registry and environment variables are ignored,
|
||||||
populated on Windows:
|
isolated mode is enabled, and :mod:`site` is not imported unless one line in the
|
||||||
|
file specifies ``import site``. Blank paths and lines starting with ``#`` are
|
||||||
|
ignored. Each path may be absolute or relative to the location of the file.
|
||||||
|
Import statements other than to ``site`` are not permitted, and arbitrary code
|
||||||
|
cannot be specified.
|
||||||
|
|
||||||
|
Note that ``.pth`` files (without leading underscore) will be processed normally
|
||||||
|
by the :mod:`site` module.
|
||||||
|
|
||||||
|
When no ``._pth`` file is found, this is how :data:`sys.path` is populated on
|
||||||
|
Windows:
|
||||||
|
|
||||||
* An empty entry is added at the start, which corresponds to the current
|
* An empty entry is added at the start, which corresponds to the current
|
||||||
directory.
|
directory.
|
||||||
|
@ -782,9 +791,10 @@ The end result of all this is:
|
||||||
For those who want to bundle Python into their application or distribution, the
|
For those who want to bundle Python into their application or distribution, the
|
||||||
following advice will prevent conflicts with other installations:
|
following advice will prevent conflicts with other installations:
|
||||||
|
|
||||||
* Include a ``sys.path`` file alongside your executable containing the
|
* Include a ``._pth`` file alongside your executable containing the
|
||||||
directories to include. This will ignore user site-packages and other paths
|
directories to include. This will ignore paths listed in the registry and
|
||||||
listed in the registry or in environment variables.
|
environment variables, and also ignore :mod:`site` unless ``import site`` is
|
||||||
|
listed.
|
||||||
|
|
||||||
* If you are loading :file:`python3.dll` or :file:`python36.dll` in your own
|
* If you are loading :file:`python3.dll` or :file:`python36.dll` in your own
|
||||||
executable, explicitly call :c:func:`Py_SetPath` or (at least)
|
executable, explicitly call :c:func:`Py_SetPath` or (at least)
|
||||||
|
|
|
@ -108,7 +108,7 @@ Windows improvements:
|
||||||
which means that when the 260 character path limit may no longer apply.
|
which means that when the 260 character path limit may no longer apply.
|
||||||
See :ref:`removing the MAX_PATH limitation <max-path>` for details.
|
See :ref:`removing the MAX_PATH limitation <max-path>` for details.
|
||||||
|
|
||||||
* A ``sys.path`` file can be added to force isolated mode and fully specify
|
* A ``._pth`` file can be added to force isolated mode and fully specify
|
||||||
all search paths to avoid registry and environment lookup. See
|
all search paths to avoid registry and environment lookup. See
|
||||||
:ref:`the documentation <finding_modules>` for more information.
|
:ref:`the documentation <finding_modules>` for more information.
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ What's New in Python 3.6.0 beta 2
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #28192: Don't import readline in isolated mode.
|
||||||
|
|
||||||
- Upgrade internal unicode databases to Unicode version 9.0.0.
|
- Upgrade internal unicode databases to Unicode version 9.0.0.
|
||||||
|
|
||||||
- Issue #28131: Fix a regression in zipimport's compile_source(). zipimport
|
- Issue #28131: Fix a regression in zipimport's compile_source(). zipimport
|
||||||
|
@ -64,6 +66,13 @@ Library
|
||||||
- Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
|
- Issue #27759: Fix selectors incorrectly retain invalid file descriptors.
|
||||||
Patch by Mark Williams.
|
Patch by Mark Williams.
|
||||||
|
|
||||||
|
Windows
|
||||||
|
-------
|
||||||
|
|
||||||
|
- Issue #28137: Renames Windows path file to ._pth
|
||||||
|
|
||||||
|
- Issue #28138: Windows ._pth file should allow import site
|
||||||
|
|
||||||
Build
|
Build
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
113
PC/getpathp.c
113
PC/getpathp.c
|
@ -6,8 +6,9 @@
|
||||||
PATH RULES FOR WINDOWS:
|
PATH RULES FOR WINDOWS:
|
||||||
This describes how sys.path is formed on Windows. It describes the
|
This describes how sys.path is formed on Windows. It describes the
|
||||||
functionality, not the implementation (ie, the order in which these
|
functionality, not the implementation (ie, the order in which these
|
||||||
are actually fetched is different). The presence of a sys.path file
|
are actually fetched is different). The presence of a python._pth or
|
||||||
alongside the program overrides these rules - see below.
|
pythonXY._pth file alongside the program overrides these rules - see
|
||||||
|
below.
|
||||||
|
|
||||||
* Python always adds an empty entry at the start, which corresponds
|
* Python always adds an empty entry at the start, which corresponds
|
||||||
to the current directory.
|
to the current directory.
|
||||||
|
@ -37,11 +38,21 @@
|
||||||
used (eg. .\Lib;.\DLLs, etc)
|
used (eg. .\Lib;.\DLLs, etc)
|
||||||
|
|
||||||
|
|
||||||
If a sys.path file exists adjacent to python.exe, it must contain a
|
If a '._pth' file exists adjacent to the executable with the same base name
|
||||||
list of paths to add to sys.path, one per line (like a .pth file but without
|
(e.g. python._pth adjacent to python.exe) or adjacent to the shared library
|
||||||
the ability to execute arbitrary code). Each path is relative to the
|
(e.g. python36._pth adjacent to python36.dll), it is used in preference to
|
||||||
directory containing the file. No other paths are added to the search path,
|
the above process. The shared library file takes precedence over the
|
||||||
and the registry finder is not enabled.
|
executable. The path file must contain a list of paths to add to sys.path,
|
||||||
|
one per line. Each path is relative to the directory containing the file.
|
||||||
|
Blank lines and comments beginning with '#' are permitted.
|
||||||
|
|
||||||
|
In the presence of this ._pth file, no other paths are added to the search
|
||||||
|
path, the registry finder is not enabled, site.py is not imported and
|
||||||
|
isolated mode is enabled. The site package can be enabled by including a
|
||||||
|
line reading "import site"; no other imports are recognized. Any invalid
|
||||||
|
entry (other than directories that do not exist) will result in immediate
|
||||||
|
termination of the program.
|
||||||
|
|
||||||
|
|
||||||
The end result of all this is:
|
The end result of all this is:
|
||||||
* When running python.exe, or any other .exe in the main Python directory
|
* When running python.exe, or any other .exe in the main Python directory
|
||||||
|
@ -61,8 +72,9 @@
|
||||||
* An embedding application can use Py_SetPath() to override all of
|
* An embedding application can use Py_SetPath() to override all of
|
||||||
these automatic path computations.
|
these automatic path computations.
|
||||||
|
|
||||||
* An isolation install of Python can disable all implicit paths by
|
* An install of Python can fully specify the contents of sys.path using
|
||||||
providing a sys.path file.
|
either a 'EXENAME._pth' or 'DLLNAME._pth' file, optionally including
|
||||||
|
"import site" to enable the site module.
|
||||||
|
|
||||||
---------------------------------------------------------------- */
|
---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -135,6 +147,33 @@ reduce(wchar_t *dir)
|
||||||
dir[i] = '\0';
|
dir[i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
change_ext(wchar_t *dest, const wchar_t *src, const wchar_t *ext)
|
||||||
|
{
|
||||||
|
size_t src_len = wcsnlen_s(src, MAXPATHLEN+1);
|
||||||
|
size_t i = src_len;
|
||||||
|
if (i >= MAXPATHLEN+1)
|
||||||
|
Py_FatalError("buffer overflow in getpathp.c's reduce()");
|
||||||
|
|
||||||
|
while (i > 0 && src[i] != '.' && !is_sep(src[i]))
|
||||||
|
--i;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
dest[0] = '\0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_sep(src[i]))
|
||||||
|
i = src_len;
|
||||||
|
|
||||||
|
if (wcsncpy_s(dest, MAXPATHLEN+1, src, i) ||
|
||||||
|
wcscat_s(dest, MAXPATHLEN+1, ext)) {
|
||||||
|
dest[0] = '\0';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
exists(wchar_t *filename)
|
exists(wchar_t *filename)
|
||||||
|
@ -499,12 +538,17 @@ find_env_config_value(FILE * env_file, const wchar_t * key, wchar_t * value)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
read_sys_path_file(const wchar_t *path, const wchar_t *prefix)
|
read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
|
||||||
{
|
{
|
||||||
FILE *sp_file = _Py_wfopen(path, L"r");
|
FILE *sp_file = _Py_wfopen(path, L"r");
|
||||||
if (sp_file == NULL)
|
if (sp_file == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
wcscpy_s(prefix, MAXPATHLEN+1, path);
|
||||||
|
reduce(prefix);
|
||||||
|
*isolated = 1;
|
||||||
|
*nosite = 1;
|
||||||
|
|
||||||
size_t bufsiz = MAXPATHLEN;
|
size_t bufsiz = MAXPATHLEN;
|
||||||
size_t prefixlen = wcslen(prefix);
|
size_t prefixlen = wcslen(prefix);
|
||||||
|
|
||||||
|
@ -516,16 +560,25 @@ read_sys_path_file(const wchar_t *path, const wchar_t *prefix)
|
||||||
char *p = fgets(line, MAXPATHLEN + 1, sp_file);
|
char *p = fgets(line, MAXPATHLEN + 1, sp_file);
|
||||||
if (!p)
|
if (!p)
|
||||||
break;
|
break;
|
||||||
|
if (*p == '\0' || *p == '#')
|
||||||
|
continue;
|
||||||
|
while (*++p) {
|
||||||
|
if (*p == '\r' || *p == '\n') {
|
||||||
|
*p = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DWORD n = strlen(line);
|
if (strcmp(line, "import site") == 0) {
|
||||||
if (n == 0 || p[n - 1] != '\n')
|
*nosite = 0;
|
||||||
break;
|
continue;
|
||||||
if (n > 2 && p[n - 1] == '\r')
|
} else if (strncmp(line, "import ", 7) == 0) {
|
||||||
--n;
|
Py_FatalError("only 'import site' is supported in ._pth file");
|
||||||
|
}
|
||||||
|
|
||||||
DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, n - 1, NULL, 0);
|
DWORD wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
|
||||||
wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
|
wchar_t *wline = (wchar_t*)PyMem_RawMalloc((wn + 1) * sizeof(wchar_t));
|
||||||
wn = MultiByteToWideChar(CP_UTF8, 0, line, n - 1, wline, wn);
|
wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
|
||||||
wline[wn] = '\0';
|
wline[wn] = '\0';
|
||||||
|
|
||||||
while (wn + prefixlen + 4 > bufsiz) {
|
while (wn + prefixlen + 4 > bufsiz) {
|
||||||
|
@ -539,8 +592,8 @@ read_sys_path_file(const wchar_t *path, const wchar_t *prefix)
|
||||||
|
|
||||||
if (buf[0])
|
if (buf[0])
|
||||||
wcscat_s(buf, bufsiz, L";");
|
wcscat_s(buf, bufsiz, L";");
|
||||||
|
|
||||||
wchar_t *b = &buf[wcslen(buf)];
|
wchar_t *b = &buf[wcslen(buf)];
|
||||||
|
|
||||||
wcscat_s(buf, bufsiz, prefix);
|
wcscat_s(buf, bufsiz, prefix);
|
||||||
join(b, wline);
|
join(b, wline);
|
||||||
|
|
||||||
|
@ -586,13 +639,12 @@ calculate_path(void)
|
||||||
{
|
{
|
||||||
wchar_t spbuffer[MAXPATHLEN+1];
|
wchar_t spbuffer[MAXPATHLEN+1];
|
||||||
|
|
||||||
wcscpy_s(spbuffer, MAXPATHLEN+1, argv0_path);
|
if ((dllpath[0] && !change_ext(spbuffer, dllpath, L"._pth") && exists(spbuffer)) ||
|
||||||
join(spbuffer, L"sys.path");
|
(progpath[0] && !change_ext(spbuffer, progpath, L"._pth") && exists(spbuffer))) {
|
||||||
if (exists(spbuffer) && read_sys_path_file(spbuffer, argv0_path) == 0) {
|
|
||||||
wcscpy_s(prefix, MAXPATHLEN + 1, argv0_path);
|
if (!read_pth_file(spbuffer, prefix, &Py_IsolatedFlag, &Py_NoSiteFlag)) {
|
||||||
Py_IsolatedFlag = 1;
|
return;
|
||||||
Py_NoSiteFlag = 1;
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,16 +683,7 @@ calculate_path(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate zip archive path from DLL or exe path */
|
/* Calculate zip archive path from DLL or exe path */
|
||||||
if (wcscpy_s(zip_path, MAXPATHLEN + 1, dllpath[0] ? dllpath : progpath)) {
|
change_ext(zip_path, dllpath[0] ? dllpath : progpath, L".zip");
|
||||||
/* exceeded buffer length - ignore zip_path */
|
|
||||||
zip_path[0] = '\0';
|
|
||||||
} else {
|
|
||||||
wchar_t *dot = wcsrchr(zip_path, '.');
|
|
||||||
if (!dot || wcscpy_s(dot, MAXPATHLEN + 1 - (dot - zip_path), L".zip")) {
|
|
||||||
/* exceeded buffer length - ignore zip_path */
|
|
||||||
zip_path[0] = L'\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pythonhome == NULL || *pythonhome == '\0') {
|
if (pythonhome == NULL || *pythonhome == '\0') {
|
||||||
if (zip_path[0] && exists(zip_path)) {
|
if (zip_path[0] && exists(zip_path)) {
|
||||||
|
|
|
@ -91,11 +91,13 @@ def include_in_tools(p):
|
||||||
|
|
||||||
return p.suffix.lower() in {'.py', '.pyw', '.txt'}
|
return p.suffix.lower() in {'.py', '.pyw', '.txt'}
|
||||||
|
|
||||||
|
BASE_NAME = 'python{0.major}{0.minor}'.format(sys.version_info)
|
||||||
|
|
||||||
FULL_LAYOUT = [
|
FULL_LAYOUT = [
|
||||||
('/', 'PCBuild/$arch', 'python.exe', is_not_debug),
|
('/', 'PCBuild/$arch', 'python.exe', is_not_debug),
|
||||||
('/', 'PCBuild/$arch', 'pythonw.exe', is_not_debug),
|
('/', 'PCBuild/$arch', 'pythonw.exe', is_not_debug),
|
||||||
('/', 'PCBuild/$arch', 'python{0.major}.dll'.format(sys.version_info), is_not_debug),
|
('/', 'PCBuild/$arch', 'python{}.dll'.format(sys.version_info.major), is_not_debug),
|
||||||
('/', 'PCBuild/$arch', 'python{0.major}{0.minor}.dll'.format(sys.version_info), is_not_debug),
|
('/', 'PCBuild/$arch', '{}.dll'.format(BASE_NAME), is_not_debug),
|
||||||
('DLLs/', 'PCBuild/$arch', '*.pyd', is_not_debug),
|
('DLLs/', 'PCBuild/$arch', '*.pyd', is_not_debug),
|
||||||
('DLLs/', 'PCBuild/$arch', '*.dll', is_not_debug_or_python),
|
('DLLs/', 'PCBuild/$arch', '*.dll', is_not_debug_or_python),
|
||||||
('include/', 'include', '*.h', None),
|
('include/', 'include', '*.h', None),
|
||||||
|
@ -109,7 +111,7 @@ EMBED_LAYOUT = [
|
||||||
('/', 'PCBuild/$arch', 'python*.exe', is_not_debug),
|
('/', 'PCBuild/$arch', 'python*.exe', is_not_debug),
|
||||||
('/', 'PCBuild/$arch', '*.pyd', is_not_debug),
|
('/', 'PCBuild/$arch', '*.pyd', is_not_debug),
|
||||||
('/', 'PCBuild/$arch', '*.dll', is_not_debug),
|
('/', 'PCBuild/$arch', '*.dll', is_not_debug),
|
||||||
('python{0.major}{0.minor}.zip'.format(sys.version_info), 'Lib', '**/*', include_in_lib),
|
('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_lib),
|
||||||
]
|
]
|
||||||
|
|
||||||
if os.getenv('DOC_FILENAME'):
|
if os.getenv('DOC_FILENAME'):
|
||||||
|
@ -209,9 +211,12 @@ def main():
|
||||||
print('Copied {} files'.format(copied))
|
print('Copied {} files'.format(copied))
|
||||||
|
|
||||||
if ns.embed:
|
if ns.embed:
|
||||||
with open(str(temp / 'sys.path'), 'w') as f:
|
with open(str(temp / (BASE_NAME + '._pth')), 'w') as f:
|
||||||
print('python{0.major}{0.minor}.zip'.format(sys.version_info), file=f)
|
print(BASE_NAME + '.zip', file=f)
|
||||||
print('.', file=f)
|
print('.', file=f)
|
||||||
|
print('', file=f)
|
||||||
|
print('# Uncomment to run site.main() automatically', file=f)
|
||||||
|
print('#import site', file=f)
|
||||||
|
|
||||||
if out:
|
if out:
|
||||||
total = copy_to_layout(out, rglob(temp, '**/*', None))
|
total = copy_to_layout(out, rglob(temp, '**/*', None))
|
||||||
|
|
Loading…
Reference in New Issue