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

Commitae961ae

Browse files
authored
[3.11]gh-124651: Quote template strings invenv activation scripts (GH-124712) (GH-126185) (#126269)
1 parente84015f commitae961ae

File tree

7 files changed

+135
-21
lines changed

7 files changed

+135
-21
lines changed

‎Lib/test/test_venv.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
importsys
1818
importsysconfig
1919
importtempfile
20-
fromtest.supportimport (captured_stdout,captured_stderr,requires_zlib,
20+
importshlex
21+
fromtest.supportimport (captured_stdout,captured_stderr,
2122
skip_if_broken_multiprocessing_synchronize,verbose,
2223
requires_subprocess,is_emscripten,is_wasi,
2324
requires_venv_with_pip,TEST_HOME_DIR,
@@ -96,6 +97,10 @@ def get_text_file_contents(self, *args, encoding='utf-8'):
9697
result=f.read()
9798
returnresult
9899

100+
defassertEndsWith(self,string,tail):
101+
ifnotstring.endswith(tail):
102+
self.fail(f"String{string!r} does not end with{tail!r}")
103+
99104
classBasicTest(BaseTest):
100105
"""Test venv module functionality."""
101106

@@ -446,6 +451,82 @@ def test_executable_symlinks(self):
446451
'import sys; print(sys.executable)'])
447452
self.assertEqual(out.strip(),envpy.encode())
448453

454+
# gh-124651: test quoted strings
455+
@unittest.skipIf(os.name=='nt','contains invalid characters on Windows')
456+
deftest_special_chars_bash(self):
457+
"""
458+
Test that the template strings are quoted properly (bash)
459+
"""
460+
rmtree(self.env_dir)
461+
bash=shutil.which('bash')
462+
ifbashisNone:
463+
self.skipTest('bash required for this test')
464+
env_name='"\';&&$e|\'"'
465+
env_dir=os.path.join(os.path.realpath(self.env_dir),env_name)
466+
builder=venv.EnvBuilder(clear=True)
467+
builder.create(env_dir)
468+
activate=os.path.join(env_dir,self.bindir,'activate')
469+
test_script=os.path.join(self.env_dir,'test_special_chars.sh')
470+
withopen(test_script,"w")asf:
471+
f.write(f'source{shlex.quote(activate)}\n'
472+
'python -c\'import sys; print(sys.executable)\'\n'
473+
'python -c\'import os; print(os.environ["VIRTUAL_ENV"])\'\n'
474+
'deactivate\n')
475+
out,err=check_output([bash,test_script])
476+
lines=out.splitlines()
477+
self.assertTrue(env_name.encode()inlines[0])
478+
self.assertEndsWith(lines[1],env_name.encode())
479+
480+
# gh-124651: test quoted strings
481+
@unittest.skipIf(os.name=='nt','contains invalid characters on Windows')
482+
deftest_special_chars_csh(self):
483+
"""
484+
Test that the template strings are quoted properly (csh)
485+
"""
486+
rmtree(self.env_dir)
487+
csh=shutil.which('tcsh')orshutil.which('csh')
488+
ifcshisNone:
489+
self.skipTest('csh required for this test')
490+
env_name='"\';&&$e|\'"'
491+
env_dir=os.path.join(os.path.realpath(self.env_dir),env_name)
492+
builder=venv.EnvBuilder(clear=True)
493+
builder.create(env_dir)
494+
activate=os.path.join(env_dir,self.bindir,'activate.csh')
495+
test_script=os.path.join(self.env_dir,'test_special_chars.csh')
496+
withopen(test_script,"w")asf:
497+
f.write(f'source{shlex.quote(activate)}\n'
498+
'python -c\'import sys; print(sys.executable)\'\n'
499+
'python -c\'import os; print(os.environ["VIRTUAL_ENV"])\'\n'
500+
'deactivate\n')
501+
out,err=check_output([csh,test_script])
502+
lines=out.splitlines()
503+
self.assertTrue(env_name.encode()inlines[0])
504+
self.assertEndsWith(lines[1],env_name.encode())
505+
506+
# gh-124651: test quoted strings on Windows
507+
@unittest.skipUnless(os.name=='nt','only relevant on Windows')
508+
deftest_special_chars_windows(self):
509+
"""
510+
Test that the template strings are quoted properly on Windows
511+
"""
512+
rmtree(self.env_dir)
513+
env_name="'&&^$e"
514+
env_dir=os.path.join(os.path.realpath(self.env_dir),env_name)
515+
builder=venv.EnvBuilder(clear=True)
516+
builder.create(env_dir)
517+
activate=os.path.join(env_dir,self.bindir,'activate.bat')
518+
test_batch=os.path.join(self.env_dir,'test_special_chars.bat')
519+
withopen(test_batch,"w")asf:
520+
f.write('@echo off\n'
521+
f'"{activate}" & '
522+
f'{self.exe} -c "import sys; print(sys.executable)" & '
523+
f'{self.exe} -c "import os; print(os.environ[\'VIRTUAL_ENV\'])" & '
524+
'deactivate')
525+
out,err=check_output([test_batch])
526+
lines=out.splitlines()
527+
self.assertTrue(env_name.encode()inlines[0])
528+
self.assertEndsWith(lines[1],env_name.encode())
529+
449530
@unittest.skipUnless(os.name=='nt','only relevant on Windows')
450531
deftest_unicode_in_batch_file(self):
451532
"""

‎Lib/venv/__init__.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
importsys
1212
importsysconfig
1313
importtypes
14+
importshlex
1415

1516

1617
CORE_VENV_DEPS= ('pip','setuptools')
@@ -394,11 +395,41 @@ def replace_variables(self, text, context):
394395
:param context: The information for the environment creation request
395396
being processed.
396397
"""
397-
text=text.replace('__VENV_DIR__',context.env_dir)
398-
text=text.replace('__VENV_NAME__',context.env_name)
399-
text=text.replace('__VENV_PROMPT__',context.prompt)
400-
text=text.replace('__VENV_BIN_NAME__',context.bin_name)
401-
text=text.replace('__VENV_PYTHON__',context.env_exe)
398+
replacements= {
399+
'__VENV_DIR__':context.env_dir,
400+
'__VENV_NAME__':context.env_name,
401+
'__VENV_PROMPT__':context.prompt,
402+
'__VENV_BIN_NAME__':context.bin_name,
403+
'__VENV_PYTHON__':context.env_exe,
404+
}
405+
406+
defquote_ps1(s):
407+
"""
408+
This should satisfy PowerShell quoting rules [1], unless the quoted
409+
string is passed directly to Windows native commands [2].
410+
[1]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules
411+
[2]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_parsing#passing-arguments-that-contain-quote-characters
412+
"""
413+
s=s.replace("'","''")
414+
returnf"'{s}'"
415+
416+
defquote_bat(s):
417+
returns
418+
419+
# gh-124651: need to quote the template strings properly
420+
quote=shlex.quote
421+
script_path=context.script_path
422+
ifscript_path.endswith('.ps1'):
423+
quote=quote_ps1
424+
elifscript_path.endswith('.bat'):
425+
quote=quote_bat
426+
else:
427+
# fallbacks to POSIX shell compliant quote
428+
quote=shlex.quote
429+
430+
replacements= {key:quote(s)forkey,sinreplacements.items()}
431+
forkey,quotedinreplacements.items():
432+
text=text.replace(key,quoted)
402433
returntext
403434

404435
definstall_scripts(self,context,path):
@@ -438,6 +469,7 @@ def install_scripts(self, context, path):
438469
withopen(srcfile,'rb')asf:
439470
data=f.read()
440471
ifnotsrcfile.endswith(('.exe','.pdb')):
472+
context.script_path=srcfile
441473
try:
442474
data=data.decode('utf-8')
443475
data=self.replace_variables(data,context)

‎Lib/venv/scripts/common/activate

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ deactivate () {
3535
# unset irrelevant variables
3636
deactivate nondestructive
3737

38-
VIRTUAL_ENV="__VENV_DIR__"
38+
VIRTUAL_ENV=__VENV_DIR__
3939
export VIRTUAL_ENV
4040

4141
_OLD_VIRTUAL_PATH="$PATH"
42-
PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH"
42+
PATH="$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH"
4343
export PATH
4444

4545
# unset PYTHONHOME if set
@@ -52,9 +52,9 @@ fi
5252

5353
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
5454
_OLD_VIRTUAL_PS1="${PS1:-}"
55-
PS1="__VENV_PROMPT__${PS1:-}"
55+
PS1=__VENV_PROMPT__"${PS1:-}"
5656
export PS1
57-
VIRTUAL_ENV_PROMPT="__VENV_PROMPT__"
57+
VIRTUAL_ENV_PROMPT=__VENV_PROMPT__
5858
export VIRTUAL_ENV_PROMPT
5959
fi
6060

‎Lib/venv/scripts/nt/activate.bat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if defined _OLD_CODEPAGE (
88
"%SystemRoot%\System32\chcp.com"65001>nul
99
)
1010

11-
setVIRTUAL_ENV=__VENV_DIR__
11+
set"VIRTUAL_ENV=__VENV_DIR__"
1212

1313
ifnotdefinedPROMPTsetPROMPT=$P$G
1414

@@ -24,8 +24,8 @@ set PYTHONHOME=
2424
ifdefined _OLD_VIRTUAL_PATHsetPATH=%_OLD_VIRTUAL_PATH%
2525
ifnotdefined _OLD_VIRTUAL_PATHset_OLD_VIRTUAL_PATH=%PATH%
2626

27-
setPATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%
28-
setVIRTUAL_ENV_PROMPT=__VENV_PROMPT__
27+
set"PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%"
28+
set"VIRTUAL_ENV_PROMPT=__VENV_PROMPT__"
2929

3030
:END
3131
ifdefined _OLD_CODEPAGE (

‎Lib/venv/scripts/posix/activate.csh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
88
# Unset irrelevant variables.
99
deactivate nondestructive
1010

11-
setenv VIRTUAL_ENV"__VENV_DIR__"
11+
setenv VIRTUAL_ENV __VENV_DIR__
1212

1313
set _OLD_VIRTUAL_PATH="$PATH"
14-
setenv PATH"$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH"
14+
setenv PATH"$VIRTUAL_ENV/"__VENV_BIN_NAME__":$PATH"
1515

1616

1717
set _OLD_VIRTUAL_PROMPT="$prompt"
1818

1919
if (!"$?VIRTUAL_ENV_DISABLE_PROMPT")then
20-
set prompt ="__VENV_PROMPT__$prompt"
21-
setenv VIRTUAL_ENV_PROMPT"__VENV_PROMPT__"
20+
set prompt = __VENV_PROMPT__"$prompt"
21+
setenv VIRTUAL_ENV_PROMPT __VENV_PROMPT__
2222
endif
2323

2424
alias pydoc python -m pydoc

‎Lib/venv/scripts/posix/activate.fish

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ end
3333
# Unset irrelevant variables.
3434
deactivate nondestructive
3535

36-
set-gx VIRTUAL_ENV"__VENV_DIR__"
36+
set-gx VIRTUAL_ENV __VENV_DIR__
3737

3838
set-gx _OLD_VIRTUAL_PATH$PATH
39-
set-gx PATH"$VIRTUAL_ENV/__VENV_BIN_NAME__"$PATH
39+
set-gx PATH"$VIRTUAL_ENV/"__VENV_BIN_NAME__$PATH
4040

4141
# Unset PYTHONHOME if set.
4242
ifset-q PYTHONHOME
@@ -56,7 +56,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
5656
set-l old_status$status
5757

5858
# Output the venv prompt; color taken from the blue of the Python logo.
59-
printf"%s%s%s" (set_color 4B8BBE)"__VENV_PROMPT__" (set_color normal)
59+
printf"%s%s%s" (set_color 4B8BBE) __VENV_PROMPT__ (set_color normal)
6060

6161
# Restore the return status of the previous command.
6262
echo"exit$old_status"| .
@@ -65,5 +65,5 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
6565
end
6666

6767
set-gx _OLD_FISH_PROMPT_OVERRIDE"$VIRTUAL_ENV"
68-
set-gx VIRTUAL_ENV_PROMPT"__VENV_PROMPT__"
68+
set-gx VIRTUAL_ENV_PROMPT __VENV_PROMPT__
6969
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Properly quote template strings in:mod:`venv` activation scripts.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp