mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-92817: Fix precedence of options to py.exe launcher (GH-92988)
(cherry picked from commit 73473fdeac
)
Co-authored-by: Steve Dower <steve.dower@python.org>
This commit is contained in:
parent
76fe10a89a
commit
a2ec09b7f5
3 changed files with 49 additions and 11 deletions
|
@ -244,6 +244,17 @@ class RunPyMixin:
|
||||||
finally:
|
finally:
|
||||||
file.unlink()
|
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):
|
class TestLauncher(unittest.TestCase, RunPyMixin):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -451,12 +462,8 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
|
||||||
self.assertEqual("PythonTestSuite/3.100", default)
|
self.assertEqual("PythonTestSuite/3.100", default)
|
||||||
|
|
||||||
def test_virtualenv_in_list(self):
|
def test_virtualenv_in_list(self):
|
||||||
venv = Path.cwd() / "Scripts"
|
with self.test_venv() as (venv_exe, env):
|
||||||
venv.mkdir(exist_ok=True, parents=True)
|
data = self.run_py(["-0p"], env=env)
|
||||||
venv_exe = (venv / Path(sys.executable).name)
|
|
||||||
venv_exe.touch()
|
|
||||||
try:
|
|
||||||
data = self.run_py(["-0p"], env={"VIRTUAL_ENV": str(venv.parent)})
|
|
||||||
for line in data["stdout"].splitlines():
|
for line in data["stdout"].splitlines():
|
||||||
m = re.match(r"\s*\*\s+(.+)$", line)
|
m = re.match(r"\s*\*\s+(.+)$", line)
|
||||||
if m:
|
if m:
|
||||||
|
@ -465,7 +472,7 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
|
||||||
else:
|
else:
|
||||||
self.fail("did not find active venv path")
|
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():
|
for line in data["stdout"].splitlines():
|
||||||
m = re.match(r"\s*\*\s+(.+)$", line)
|
m = re.match(r"\s*\*\s+(.+)$", line)
|
||||||
if m:
|
if m:
|
||||||
|
@ -473,8 +480,17 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.fail("did not find active venv entry")
|
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):
|
def test_py_shebang(self):
|
||||||
with self.py_ini(TEST_PY_COMMANDS):
|
with self.py_ini(TEST_PY_COMMANDS):
|
||||||
|
|
|
@ -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.
|
|
@ -386,6 +386,12 @@ typedef struct {
|
||||||
int tagLength;
|
int tagLength;
|
||||||
// if true, treats 'tag' as a non-PEP 514 filter
|
// if true, treats 'tag' as a non-PEP 514 filter
|
||||||
bool oldStyleTag;
|
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
|
// if true, we had an old-style tag with '-64' suffix, and so do not
|
||||||
// want to match tags like '3.x-32'
|
// want to match tags like '3.x-32'
|
||||||
bool exclude32Bit;
|
bool exclude32Bit;
|
||||||
|
@ -475,6 +481,7 @@ dumpSearchInfo(SearchInfo *search)
|
||||||
DEBUG_2(company, companyLength);
|
DEBUG_2(company, companyLength);
|
||||||
DEBUG_2(tag, tagLength);
|
DEBUG_2(tag, tagLength);
|
||||||
DEBUG_BOOL(oldStyleTag);
|
DEBUG_BOOL(oldStyleTag);
|
||||||
|
DEBUG_BOOL(lowPriorityTag);
|
||||||
DEBUG_BOOL(exclude32Bit);
|
DEBUG_BOOL(exclude32Bit);
|
||||||
DEBUG_BOOL(only32Bit);
|
DEBUG_BOOL(only32Bit);
|
||||||
DEBUG_BOOL(allowDefaults);
|
DEBUG_BOOL(allowDefaults);
|
||||||
|
@ -965,6 +972,9 @@ checkDefaults(SearchInfo *search)
|
||||||
if (!slash) {
|
if (!slash) {
|
||||||
search->tag = tag;
|
search->tag = tag;
|
||||||
search->tagLength = n;
|
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 {
|
} else {
|
||||||
search->company = tag;
|
search->company = tag;
|
||||||
search->companyLength = (int)(slash - tag);
|
search->companyLength = (int)(slash - tag);
|
||||||
|
@ -995,7 +1005,7 @@ typedef struct EnvironmentInfo {
|
||||||
const wchar_t *executableArgs;
|
const wchar_t *executableArgs;
|
||||||
const wchar_t *architecture;
|
const wchar_t *architecture;
|
||||||
const wchar_t *displayName;
|
const wchar_t *displayName;
|
||||||
bool isActiveVenv;
|
bool highPriority;
|
||||||
} EnvironmentInfo;
|
} EnvironmentInfo;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1481,7 +1491,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
|
||||||
if (!env) {
|
if (!env) {
|
||||||
return RC_NO_MEMORY;
|
return RC_NO_MEMORY;
|
||||||
}
|
}
|
||||||
env->isActiveVenv = true;
|
env->highPriority = true;
|
||||||
env->internalSortKey = 20;
|
env->internalSortKey = 20;
|
||||||
exitCode = copyWstr(&env->displayName, L"Active venv");
|
exitCode = copyWstr(&env->displayName, L"Active venv");
|
||||||
if (exitCode) {
|
if (exitCode) {
|
||||||
|
@ -1821,6 +1831,15 @@ _selectEnvironment(const SearchInfo *search, EnvironmentInfo *env, EnvironmentIn
|
||||||
return 0;
|
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 (!search->oldStyleTag) {
|
||||||
if (_companyMatches(search, env) && _tagMatches(search, env)) {
|
if (_companyMatches(search, env) && _tagMatches(search, env)) {
|
||||||
// Because of how our sort tree is set up, we will walk up the
|
// Because of how our sort tree is set up, we will walk up the
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue