Mailing List Archive

gh-92817: Fix precedence of options to py.exe launcher (GH-92988)
https://github.com/python/cpython/commit/73473fdeac3ff9d75ac9d189bb8552b7459812f1
commit: 73473fdeac3ff9d75ac9d189bb8552b7459812f1
branch: main
author: Steve Dower <steve.dower@python.org>
committer: zooba <steve.dower@microsoft.com>
date: 2022-05-19T23:45:41+01:00
summary:

gh-92817: Fix precedence of options to py.exe launcher (GH-92988)

files:
A Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst
M Lib/test/test_launcher.py
M PC/launcher2.c

diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py
index 2e10c55e339d5..aeacbbecbfa12 100644
--- a/Lib/test/test_launcher.py
+++ b/Lib/test/test_launcher.py
@@ -244,6 +244,17 @@ def script(self, content, encoding="utf-8"):
finally:
file.unlink()

+ @contextlib.contextmanager
+ def test_venv(self):
+ venv = Path.cwd() / "Scripts"
+ venv.mkdir(exist_ok=True, parents=True)
+ venv_exe = (venv / Path(sys.executable).name)
+ venv_exe.touch()
+ try:
+ yield venv_exe, {"VIRTUAL_ENV": str(venv.parent)}
+ finally:
+ shutil.rmtree(venv)
+

class TestLauncher(unittest.TestCase, RunPyMixin):
@classmethod
@@ -451,12 +462,8 @@ def test_py_default_in_list(self):
self.assertEqual("PythonTestSuite/3.100", default)

def test_virtualenv_in_list(self):
- venv = Path.cwd() / "Scripts"
- venv.mkdir(exist_ok=True, parents=True)
- venv_exe = (venv / Path(sys.executable).name)
- venv_exe.touch()
- try:
- data = self.run_py(["-0p"], env={"VIRTUAL_ENV": str(venv.parent)})
+ with self.test_venv() as (venv_exe, env):
+ data = self.run_py(["-0p"], env=env)
for line in data["stdout"].splitlines():
m = re.match(r"\s*\*\s+(.+)$", line)
if m:
@@ -465,7 +472,7 @@ def test_virtualenv_in_list(self):
else:
self.fail("did not find active venv path")

- data = self.run_py(["-0"], env={"VIRTUAL_ENV": str(venv.parent)})
+ data = self.run_py(["-0"], env=env)
for line in data["stdout"].splitlines():
m = re.match(r"\s*\*\s+(.+)$", line)
if m:
@@ -473,8 +480,17 @@ def test_virtualenv_in_list(self):
break
else:
self.fail("did not find active venv entry")
- finally:
- shutil.rmtree(venv)
+
+ def test_virtualenv_with_env(self):
+ with self.test_venv() as (venv_exe, env):
+ data1 = self.run_py([], env={**env, "PY_PYTHON": "-3"})
+ data2 = self.run_py(["-3"], env={**env, "PY_PYTHON": "-3"})
+ # Compare stdout, because stderr goes via ascii
+ self.assertEqual(data1["stdout"].strip(), str(venv_exe))
+ self.assertEqual(data1["SearchInfo.lowPriorityTag"], "True")
+ # Ensure passing the argument doesn't trigger the same behaviour
+ self.assertNotEqual(data2["stdout"].strip(), str(venv_exe))
+ self.assertNotEqual(data2["SearchInfo.lowPriorityTag"], "True")

def test_py_shebang(self):
with self.py_ini(TEST_PY_COMMANDS):
diff --git a/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst b/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst
new file mode 100644
index 0000000000000..16acba1d6274c
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2022-05-19-21-44-25.gh-issue-92817.Jrf-Kv.rst
@@ -0,0 +1,3 @@
+Ensures that :file:`py.exe` will prefer an active virtual environment over
+default tags specified with environment variables or through a
+:file:`py.ini` file.
diff --git a/PC/launcher2.c b/PC/launcher2.c
index 35c932aa329c8..763bc138ed71d 100644
--- a/PC/launcher2.c
+++ b/PC/launcher2.c
@@ -386,6 +386,12 @@ typedef struct {
int tagLength;
// if true, treats 'tag' as a non-PEP 514 filter
bool oldStyleTag;
+ // if true, ignores 'tag' when a high priority environment is found
+ // gh-92817: This is currently set when a tag is read from configuration or
+ // the environment, rather than the command line or a shebang line, and the
+ // 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;
@@ -475,6 +481,7 @@ dumpSearchInfo(SearchInfo *search)
DEBUG_2(company, companyLength);
DEBUG_2(tag, tagLength);
DEBUG_BOOL(oldStyleTag);
+ DEBUG_BOOL(lowPriorityTag);
DEBUG_BOOL(exclude32Bit);
DEBUG_BOOL(only32Bit);
DEBUG_BOOL(allowDefaults);
@@ -965,6 +972,9 @@ checkDefaults(SearchInfo *search)
if (!slash) {
search->tag = tag;
search->tagLength = n;
+ // gh-92817: allow a high priority env to be selected even if it
+ // doesn't match the tag
+ search->lowPriorityTag = true;
} else {
search->company = tag;
search->companyLength = (int)(slash - tag);
@@ -995,7 +1005,7 @@ typedef struct EnvironmentInfo {
const wchar_t *executableArgs;
const wchar_t *architecture;
const wchar_t *displayName;
- bool isActiveVenv;
+ bool highPriority;
} EnvironmentInfo;


@@ -1481,7 +1491,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
if (!env) {
return RC_NO_MEMORY;
}
- env->isActiveVenv = true;
+ env->highPriority = true;
env->internalSortKey = 20;
exitCode = copyWstr(&env->displayName, L"Active venv");
if (exitCode) {
@@ -1821,6 +1831,15 @@ _selectEnvironment(const SearchInfo *search, EnvironmentInfo *env, EnvironmentIn
return 0;
}

+ if (env->highPriority && search->lowPriorityTag) {
+ // This environment is marked high priority, and the search allows
+ // it to be selected even though a tag is specified, so select it
+ // gh-92817: this allows an active venv to be selected even when a
+ // default tag has been found in py.ini or the environment
+ *best = env;
+ return 0;
+ }
+
if (!search->oldStyleTag) {
if (_companyMatches(search, env) && _tagMatches(search, env)) {
// Because of how our sort tree is set up, we will walk up the

_______________________________________________
Python-checkins mailing list
Python-checkins@python.org
https://mail.python.org/mailman/listinfo/python-checkins