Skip to content

gh-96559: Fixes Windows launcher handling of defaults using old-style tags, and adds What's New section #96595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,28 @@ PEP 563 May Not Be the Future
that was planned for this release has been indefinitely postponed.
See `this message <https://mail.python.org/archives/list/python-dev@python.org/message/VIZEBX5EYMSYIJNDBF6DMUMZOCWHARSO/>`_ for more information.

Windows py.exe launcher improvements
------------------------------------

The copy of :ref:`launcher` included with Python 3.11 has been significantly
updated. It now supports company/tag syntax as defined in :pep:`514` using the
``-V:<company>/<tag>`` argument instead of the limited ``-x.y`` argument. This
allows launching distributions other than ``PythonCore``, which is the one
obtained from `python.org <https://python.org>`_.

When using ``-V:`` selectors, either company or tag can be omitted, but all
installs will be searched. For example, ``-V:OtherPython/`` will select the
"best" tag registered for ``OtherPython``, while ``-V:3.11`` or ``-V:/3.11``
will select the "best" distribution with tag ``3.11``.

When using legacy ``-x``, ``-x.y``, ``-x-ZZ`` or ``-x.y-ZZ`` arguments, all
existing behaviour should be preserved from past versions. Only releases from
``PythonCore`` will be selected. However, the ``-64`` suffix now implies "not
32-bit", as there are multiple supported 64-bit platforms. 32-bit runtimes are
detected by checking its tag for a ``-32`` suffix. All releases of Python
since 3.5 have included this in their 32-bit builds.


Other Language Changes
======================

Expand Down
7 changes: 7 additions & 0 deletions Lib/test/test_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,13 @@ def test_py_shebang_short_argv0(self):
self.assertEqual("3.100", data["SearchInfo.tag"])
self.assertEqual(f'X.Y.exe -prearg "{script}" -postarg', data["stdout"].strip())

def test_py_handle_64_in_ini(self):
with self.py_ini("\n".join(["[defaults]", "python=3.999-64"])):
# Expect this to fail, but should get oldStyleTag flipped on
data = self.run_py([], allow_fail=True, expect_returncode=103)
self.assertEqual("3.999-64", data["SearchInfo.tag"])
self.assertEqual("True", data["SearchInfo.oldStyleTag"])

def test_search_path(self):
stem = Path(sys.executable).stem
with self.py_ini(TEST_PY_COMMANDS):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixes the Windows launcher not using the compatible interpretation of
default tags found in configuration files when no tag was passed to the
command.
41 changes: 19 additions & 22 deletions PC/launcher2.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,6 @@ typedef struct {
// only currently possible high priority environment is an active virtual
// environment
bool lowPriorityTag;
// if true, we had an old-style tag with '-64' suffix, and so do not
// want to match tags like '3.x-32'
bool exclude32Bit;
// if true, we had an old-style tag with '-32' suffix, and so *only*
// want to match tags like '3.x-32'
bool only32Bit;
// if true, allow PEP 514 lookup to override 'executable'
bool allowExecutableOverride;
// if true, allow a nearby pyvenv.cfg to locate the executable
Expand Down Expand Up @@ -483,8 +477,6 @@ dumpSearchInfo(SearchInfo *search)
DEBUG_2(tag, tagLength);
DEBUG_BOOL(oldStyleTag);
DEBUG_BOOL(lowPriorityTag);
DEBUG_BOOL(exclude32Bit);
DEBUG_BOOL(only32Bit);
DEBUG_BOOL(allowDefaults);
DEBUG_BOOL(allowExecutableOverride);
DEBUG_BOOL(windowed);
Expand Down Expand Up @@ -649,17 +641,6 @@ parseCommandLine(SearchInfo *search)
search->tagLength = argLen;
search->oldStyleTag = true;
search->restOfCmdLine = tail;
// If the tag ends with -64, we want to exclude 32-bit runtimes
// (If the tag ends with -32, it will be filtered later)
if (argLen > 3) {
if (0 == _compareArgument(&arg[argLen - 3], 3, L"-64", 3)) {
search->tagLength -= 3;
search->exclude32Bit = true;
} else if (0 == _compareArgument(&arg[argLen - 3], 3, L"-32", 3)) {
search->tagLength -= 3;
search->only32Bit = true;
}
}
} else if (STARTSWITH(L"V:") || STARTSWITH(L"-version:")) {
// Arguments starting with 'V:' specify company and/or tag
const wchar_t *argStart = wcschr(arg, L':') + 1;
Expand Down Expand Up @@ -1087,6 +1068,7 @@ checkDefaults(SearchInfo *search)
if (!slash) {
search->tag = tag;
search->tagLength = n;
search->oldStyleTag = true;
} else {
search->company = tag;
search->companyLength = (int)(slash - tag);
Expand Down Expand Up @@ -1966,10 +1948,25 @@ _selectEnvironment(const SearchInfo *search, EnvironmentInfo *env, EnvironmentIn
}
} else if (0 == _compare(env->company, -1, L"PythonCore", -1)) {
// Old-style tags can only match PythonCore entries
if (_startsWith(env->tag, -1, search->tag, search->tagLength)) {
if (search->exclude32Bit && _is32Bit(env)) {

// If the tag ends with -64, we want to exclude 32-bit runtimes
// (If the tag ends with -32, it will be filtered later)
int tagLength = search->tagLength;
bool exclude32Bit = false, only32Bit = false;
if (tagLength > 3) {
if (0 == _compareArgument(&search->tag[tagLength - 3], 3, L"-64", 3)) {
tagLength -= 3;
exclude32Bit = true;
} else if (0 == _compareArgument(&search->tag[tagLength - 3], 3, L"-32", 3)) {
tagLength -= 3;
only32Bit = true;
}
}

if (_startsWith(env->tag, -1, search->tag, tagLength)) {
if (exclude32Bit && _is32Bit(env)) {
debug(L"# Excluding %s/%s because it looks like 32bit\n", env->company, env->tag);
} else if (search->only32Bit && !_is32Bit(env)) {
} else if (only32Bit && !_is32Bit(env)) {
debug(L"# Excluding %s/%s because it doesn't look 32bit\n", env->company, env->tag);
} else {
*best = env;
Expand Down