Skip to content

gh-114272: Fix or skip tests that fail due to spaces in paths #114451

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 4 commits into from
Jan 25, 2024
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
7 changes: 5 additions & 2 deletions Lib/test/test_asyncio/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def test_kill(self):

def test_kill_issue43884(self):
if sys.platform == 'win32':
blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(2)"'
blocking_shell_command = f'"{sys.executable}" -c "import time; time.sleep(2)"'
else:
blocking_shell_command = 'sleep 1; sleep 1'
creationflags = 0
Expand Down Expand Up @@ -745,7 +745,10 @@ async def check_stdout_output(self, coro, output):

def test_create_subprocess_env_shell(self) -> None:
async def main() -> None:
cmd = f'''{sys.executable} -c "import os, sys; sys.stdout.write(os.getenv('FOO'))"'''
executable = sys.executable
if sys.platform == "win32":
executable = f'"{executable}"'
cmd = f'''{executable} -c "import os, sys; sys.stdout.write(os.getenv('FOO'))"'''
env = os.environ.copy()
env["FOO"] = "bar"
proc = await asyncio.create_subprocess_shell(
Expand Down
55 changes: 34 additions & 21 deletions Lib/test/test_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@
"test-command=TEST_EXE.exe",
])


def quote(s):
s = str(s)
return f'"{s}"' if " " in s else s


def create_registry_data(root, data):
def _create_registry_data(root, key, value):
if isinstance(value, dict):
Expand Down Expand Up @@ -542,10 +548,10 @@ def test_virtualenv_with_env(self):
data1 = self.run_py([], env={**env, "PY_PYTHON": "PythonTestSuite/3"})
data2 = self.run_py(["-V:PythonTestSuite/3"], env={**env, "PY_PYTHON": "PythonTestSuite/3"})
# Compare stdout, because stderr goes via ascii
self.assertEqual(data1["stdout"].strip(), str(venv_exe))
self.assertEqual(data1["stdout"].strip(), quote(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["stdout"].strip(), quote(venv_exe))
self.assertNotEqual(data2["SearchInfo.lowPriorityTag"], "True")

def test_py_shebang(self):
Expand All @@ -554,55 +560,60 @@ def test_py_shebang(self):
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100", data["SearchInfo.tag"])
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y.exe -prearg {quote(script)} -postarg", data["stdout"].strip())

def test_python_shebang(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! python -prearg") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100", data["SearchInfo.tag"])
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y.exe -prearg {quote(script)} -postarg", data["stdout"].strip())

def test_py2_shebang(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! /usr/bin/python2 -prearg") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100-32", data["SearchInfo.tag"])
self.assertEqual(f"X.Y-32.exe -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y-32.exe -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_py3_shebang(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! /usr/bin/python3 -prearg") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_py_shebang_nl(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! /usr/bin/python -prearg\n") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100", data["SearchInfo.tag"])
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y.exe -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_py2_shebang_nl(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! /usr/bin/python2 -prearg\n") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100-32", data["SearchInfo.tag"])
self.assertEqual(f"X.Y-32.exe -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y-32.exe -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_py3_shebang_nl(self):
with self.py_ini(TEST_PY_DEFAULTS):
with self.script("#! /usr/bin/python3 -prearg\n") as script:
data = self.run_py([script, "-postarg"])
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_py_shebang_short_argv0(self):
with self.py_ini(TEST_PY_DEFAULTS):
Expand Down Expand Up @@ -630,7 +641,8 @@ def test_search_path(self):
[script, "-postarg"],
env={"PATH": f"{exe.parent};{os.getenv('PATH')}"},
)
self.assertEqual(f"{exe} -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"{quote(exe)} -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_search_path_exe(self):
# Leave the .exe on the name to ensure we don't add it a second time
Expand All @@ -643,7 +655,8 @@ def test_search_path_exe(self):
[script, "-postarg"],
env={"PATH": f"{exe.parent};{os.getenv('PATH')}"},
)
self.assertEqual(f"{exe} -prearg {script} -postarg", data["stdout"].strip())
self.assertEqual(f"{quote(exe)} -prearg {quote(script)} -postarg",
data["stdout"].strip())

def test_recursive_search_path(self):
stem = self.get_py_exe().stem
Expand All @@ -654,7 +667,7 @@ def test_recursive_search_path(self):
env={"PATH": f"{self.get_py_exe().parent};{os.getenv('PATH')}"},
)
# The recursive search is ignored and we get normal "py" behavior
self.assertEqual(f"X.Y.exe {script}", data["stdout"].strip())
self.assertEqual(f"X.Y.exe {quote(script)}", data["stdout"].strip())

def test_install(self):
data = self.run_py(["-V:3.10"], env={"PYLAUNCHER_ALWAYS_INSTALL": "1"}, expect_returncode=111)
Expand All @@ -674,38 +687,38 @@ def test_literal_shebang_absolute(self):
with self.script("#! C:/some_random_app -witharg") as script:
data = self.run_py([script])
self.assertEqual(
f"C:\\some_random_app -witharg {script}",
f"C:\\some_random_app -witharg {quote(script)}",
data["stdout"].strip(),
)

def test_literal_shebang_relative(self):
with self.script("#! ..\\some_random_app -witharg") as script:
data = self.run_py([script])
self.assertEqual(
f"{script.parent.parent}\\some_random_app -witharg {script}",
f"{quote(script.parent.parent / 'some_random_app')} -witharg {quote(script)}",
data["stdout"].strip(),
)

def test_literal_shebang_quoted(self):
with self.script('#! "some random app" -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some random app" -witharg {script}',
f"{quote(script.parent / 'some random app')} -witharg {quote(script)}",
data["stdout"].strip(),
)

with self.script('#! some" random "app -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some random app" -witharg {script}',
f"{quote(script.parent / 'some random app')} -witharg {quote(script)}",
data["stdout"].strip(),
)

def test_literal_shebang_quoted_escape(self):
with self.script('#! some\\" random "app -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some\\ random app" -witharg {script}',
f"{quote(script.parent / 'some/ random app')} -witharg {quote(script)}",
data["stdout"].strip(),
)

Expand All @@ -714,7 +727,7 @@ def test_literal_shebang_command(self):
with self.script('#! test-command arg1') as script:
data = self.run_py([script])
self.assertEqual(
f"TEST_EXE.exe arg1 {script}",
f"TEST_EXE.exe arg1 {quote(script)}",
data["stdout"].strip(),
)

Expand All @@ -723,7 +736,7 @@ def test_literal_shebang_invalid_template(self):
data = self.run_py([script])
expect = script.parent / "/usr/bin/not-python"
self.assertEqual(
f"{expect} arg1 {script}",
f"{quote(expect)} arg1 {quote(script)}",
data["stdout"].strip(),
)

Expand All @@ -746,8 +759,8 @@ def test_shebang_command_in_venv(self):

with self.script(f'#! /usr/bin/env {stem} arg1') as script:
data = self.run_py([script], env=env)
self.assertEqual(data["stdout"].strip(), f"{venv_exe} arg1 {script}")
self.assertEqual(data["stdout"].strip(), f"{quote(venv_exe)} arg1 {quote(script)}")

with self.script(f'#! /usr/bin/env {exe.stem} arg1') as script:
data = self.run_py([script], env=env)
self.assertEqual(data["stdout"].strip(), f"{exe} arg1 {script}")
self.assertEqual(data["stdout"].strip(), f"{quote(exe)} arg1 {quote(script)}")
7 changes: 5 additions & 2 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -4596,8 +4596,11 @@ def test_pipe_spawnl(self):
with open(filename, "w") as fp:
print(code, file=fp, end="")

cmd = [sys.executable, filename]
exitcode = os.spawnl(os.P_WAIT, cmd[0], *cmd)
executable = sys.executable
cmd = [executable, filename]
if os.name == "nt" and " " in cmd[0]:
cmd[0] = f'"{cmd[0]}"'
exitcode = os.spawnl(os.P_WAIT, executable, *cmd)
self.assertEqual(exitcode, 0)


Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_webbrowser.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ def test_get(self):
webbrowser.get('fakebrowser')
self.assertIsNotNone(webbrowser._tryorder)

@unittest.skipIf(" " in sys.executable, "test assumes no space in path (GH-114452)")
def test_synthesize(self):
webbrowser = import_helper.import_fresh_module('webbrowser')
name = os.path.basename(sys.executable).lower()
Expand Down