Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1b3bc61

Browse files
authored
gh-83180: Made launcher treat shebang 'python' tags as low priority so that active virtual environments are preferred (GH-108101)
1 parent6139bf5 commit1b3bc61

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

‎Doc/using/windows.rst‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -867,17 +867,18 @@ For example, if the first line of your script starts with
867867
868868
#! /usr/bin/python
869869
870-
The default Python will be located and used. As many Python scripts written
871-
to work on Unix will already have this line, you should find these scripts can
872-
be used by the launcher without modification. If you are writing a new script
873-
on Windows which you hope will be useful on Unix, you should use one of the
874-
shebang lines starting with ``/usr``.
870+
The default Pythonor an active virtual environmentwill be located and used.
871+
As many Python scripts writtento work on Unix will already have this line,
872+
you should find these scripts canbe used by the launcher without modification.
873+
If you are writing a new scripton Windows which you hope will be useful on
874+
Unix, you should use one of theshebang lines starting with ``/usr``.
875875

876876
Any of the above virtual commands can be suffixed with an explicit version
877877
(either just the major version, or the major and minor version).
878878
Furthermore the 32-bit version can be requested by adding "-32" after the
879879
minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the
880-
32-bit python 3.7.
880+
32-bit Python 3.7. If a virtual environment is active, the version will be
881+
ignored and the environment will be used.
881882

882883
..versionadded::3.7
883884

@@ -891,6 +892,13 @@ minor version. I.e. ``/usr/bin/python3.7-32`` will request usage of the
891892
not provably i386/32-bit". To request a specific environment, use the new
892893
:samp:`-V:{TAG}` argument with the complete tag.
893894

895+
..versionchanged::3.13
896+
897+
Virtual commands referencing ``python`` now prefer an active virtual
898+
environment rather than searching:envvar:`PATH`. This handles cases where
899+
the shebang specifies ``/usr/bin/env python3`` but:file:`python3.exe` is
900+
not present in the active environment.
901+
894902
The ``/usr/bin/env`` form of shebang line has one further special property.
895903
Before looking for installed Python interpreters, this form will search the
896904
executable:envvar:`PATH` for a Python executable matching the name provided

‎Lib/test/test_launcher.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,3 +717,25 @@ def test_literal_shebang_invalid_template(self):
717717
f"{expect} arg1{script}",
718718
data["stdout"].strip(),
719719
)
720+
721+
deftest_shebang_command_in_venv(self):
722+
stem="python-that-is-not-on-path"
723+
724+
# First ensure that our test name doesn't exist, and the launcher does
725+
# not match any installed env
726+
withself.script(f'#! /usr/bin/env{stem} arg1')asscript:
727+
data=self.run_py([script],expect_returncode=103)
728+
729+
withself.fake_venv()as (venv_exe,env):
730+
# Put a real Python (ourselves) on PATH as a distraction.
731+
# The active VIRTUAL_ENV should be preferred when the name isn't an
732+
# exact match.
733+
env["PATH"]=f"{Path(sys.executable).parent};{os.environ['PATH']}"
734+
735+
withself.script(f'#! /usr/bin/env{stem} arg1')asscript:
736+
data=self.run_py([script],env=env)
737+
self.assertEqual(data["stdout"].strip(),f"{venv_exe} arg1{script}")
738+
739+
withself.script(f'#! /usr/bin/env{Path(sys.executable).stem} arg1')asscript:
740+
data=self.run_py([script],env=env)
741+
self.assertEqual(data["stdout"].strip(),f"{sys.executable} arg1{script}")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Changes the:ref:`launcher` to prefer an active virtual environment when the
2+
launched script has a shebang line using a Unix-like virtual command, even
3+
if the command requests a specific version of Python.

‎PC/launcher2.c‎

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ join(wchar_t *buffer, size_t bufferLength, const wchar_t *fragment)
195195
}
196196

197197

198+
bool
199+
split_parent(wchar_t*buffer,size_tbufferLength)
200+
{
201+
returnSUCCEEDED(PathCchRemoveFileSpec(buffer,bufferLength));
202+
}
203+
204+
198205
int
199206
_compare(constwchar_t*x,intxLen,constwchar_t*y,intyLen)
200207
{
@@ -414,8 +421,8 @@ typedef struct {
414421
// if true, treats 'tag' as a non-PEP 514 filter
415422
boololdStyleTag;
416423
// if true, ignores 'tag' when a high priority environment is found
417-
// gh-92817: This is currently set when a tag is read from configuration or
418-
// the environment, rather than the command line or a shebang line, and the
424+
// gh-92817: This is currently set when a tag is read from configuration,
425+
// the environment,or a shebang,rather than the command line, and the
419426
// only currently possible high priority environment is an active virtual
420427
// environment
421428
boollowPriorityTag;
@@ -794,6 +801,8 @@ searchPath(SearchInfo *search, const wchar_t *shebang, int shebangLength)
794801
}
795802
}
796803

804+
debug(L"# Search PATH for %s\n",filename);
805+
797806
wchar_tpathVariable[MAXLEN];
798807
intn=GetEnvironmentVariableW(L"PATH",pathVariable,MAXLEN);
799808
if (!n) {
@@ -1031,8 +1040,11 @@ checkShebang(SearchInfo *search)
10311040
debug(L"Shebang: %s\n",shebang);
10321041

10331042
// Handle shebangs that we should search PATH for
1043+
intexecutablePathWasSetByUsrBinEnv=0;
10341044
exitCode=searchPath(search,shebang,shebangLength);
1035-
if (exitCode!=RC_NO_SHEBANG) {
1045+
if (exitCode==0) {
1046+
executablePathWasSetByUsrBinEnv=1;
1047+
}elseif (exitCode!=RC_NO_SHEBANG) {
10361048
returnexitCode;
10371049
}
10381050

@@ -1067,21 +1079,22 @@ checkShebang(SearchInfo *search)
10671079
search->tagLength=commandLength;
10681080
// If we had 'python3.12.exe' then we want to strip the suffix
10691081
// off of the tag
1070-
if (search->tagLength>4) {
1082+
if (search->tagLength >=4) {
10711083
constwchar_t*suffix=&search->tag[search->tagLength-4];
10721084
if (0==_comparePath(suffix,4,L".exe",-1)) {
10731085
search->tagLength-=4;
10741086
}
10751087
}
10761088
// If we had 'python3_d' then we want to strip the '_d' (any
10771089
// '.exe' is already gone)
1078-
if (search->tagLength>2) {
1090+
if (search->tagLength >=2) {
10791091
constwchar_t*suffix=&search->tag[search->tagLength-2];
10801092
if (0==_comparePath(suffix,2,L"_d",-1)) {
10811093
search->tagLength-=2;
10821094
}
10831095
}
10841096
search->oldStyleTag= true;
1097+
search->lowPriorityTag= true;
10851098
search->executableArgs=&command[commandLength];
10861099
search->executableArgsLength=shebangLength-commandLength;
10871100
if (search->tag&&search->tagLength) {
@@ -1095,6 +1108,11 @@ checkShebang(SearchInfo *search)
10951108
}
10961109
}
10971110

1111+
// Didn't match a template, but we found it on PATH
1112+
if (executablePathWasSetByUsrBinEnv) {
1113+
return0;
1114+
}
1115+
10981116
// Unrecognised executables are first tried as command aliases
10991117
commandLength=0;
11001118
while (commandLength<shebangLength&& !isspace(shebang[commandLength])) {
@@ -1765,7 +1783,15 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
17651783
return0;
17661784
}
17671785

1768-
if (INVALID_FILE_ATTRIBUTES==GetFileAttributesW(buffer)) {
1786+
DWORDattr=GetFileAttributesW(buffer);
1787+
if (INVALID_FILE_ATTRIBUTES==attr&&search->lowPriorityTag) {
1788+
if (!split_parent(buffer,MAXLEN)|| !join(buffer,MAXLEN,L"python.exe")) {
1789+
return0;
1790+
}
1791+
attr=GetFileAttributesW(buffer);
1792+
}
1793+
1794+
if (INVALID_FILE_ATTRIBUTES==attr) {
17691795
debug(L"Python executable %s missing from virtual env\n",buffer);
17701796
return0;
17711797
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp