Skip to content

Commit a5609e6

Browse files
committed
pythongh-100247: Fix py.exe launcher not using entire shebang command for finding custom commands.
1 parent 762745a commit a5609e6

File tree

3 files changed

+127
-82
lines changed

3 files changed

+127
-82
lines changed

Lib/test/test_launcher.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@
6767
)
6868

6969

70-
TEST_PY_COMMANDS = "\n".join([
70+
TEST_PY_DEFAULTS = "\n".join([
7171
"[defaults]",
72-
*[f"{k[3:].lower()}={v}" for k, v in TEST_PY_ENV.items()]
72+
*[f"{k[3:].lower()}={v}" for k, v in TEST_PY_ENV.items()],
7373
])
7474

7575

76+
TEST_PY_COMMANDS = "\n".join([
77+
"[commands]",
78+
"test-command=TEST_EXE.exe",
79+
])
80+
7681
def create_registry_data(root, data):
7782
def _create_registry_data(root, key, value):
7883
if isinstance(value, dict):
@@ -429,21 +434,21 @@ def test_search_major_2(self):
429434
self.assertTrue(data["env.tag"].startswith("2."), data["env.tag"])
430435

431436
def test_py_default(self):
432-
with self.py_ini(TEST_PY_COMMANDS):
437+
with self.py_ini(TEST_PY_DEFAULTS):
433438
data = self.run_py(["-arg"])
434439
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
435440
self.assertEqual("3.100", data["SearchInfo.tag"])
436441
self.assertEqual("X.Y.exe -arg", data["stdout"].strip())
437442

438443
def test_py2_default(self):
439-
with self.py_ini(TEST_PY_COMMANDS):
444+
with self.py_ini(TEST_PY_DEFAULTS):
440445
data = self.run_py(["-2", "-arg"])
441446
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
442447
self.assertEqual("3.100-32", data["SearchInfo.tag"])
443448
self.assertEqual("X.Y-32.exe -arg", data["stdout"].strip())
444449

445450
def test_py3_default(self):
446-
with self.py_ini(TEST_PY_COMMANDS):
451+
with self.py_ini(TEST_PY_DEFAULTS):
447452
data = self.run_py(["-3", "-arg"])
448453
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
449454
self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
@@ -468,7 +473,7 @@ def test_py3_default_env(self):
468473
self.assertEqual("X.Y-arm64.exe -X fake_arg_for_test -arg", data["stdout"].strip())
469474

470475
def test_py_default_short_argv0(self):
471-
with self.py_ini(TEST_PY_COMMANDS):
476+
with self.py_ini(TEST_PY_DEFAULTS):
472477
for argv0 in ['"py.exe"', 'py.exe', '"py"', 'py']:
473478
with self.subTest(argv0):
474479
data = self.run_py(["--version"], argv=f'{argv0} --version')
@@ -518,63 +523,63 @@ def test_virtualenv_with_env(self):
518523
self.assertNotEqual(data2["SearchInfo.lowPriorityTag"], "True")
519524

520525
def test_py_shebang(self):
521-
with self.py_ini(TEST_PY_COMMANDS):
526+
with self.py_ini(TEST_PY_DEFAULTS):
522527
with self.script("#! /usr/bin/python -prearg") as script:
523528
data = self.run_py([script, "-postarg"])
524529
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
525530
self.assertEqual("3.100", data["SearchInfo.tag"])
526531
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
527532

528533
def test_python_shebang(self):
529-
with self.py_ini(TEST_PY_COMMANDS):
534+
with self.py_ini(TEST_PY_DEFAULTS):
530535
with self.script("#! python -prearg") as script:
531536
data = self.run_py([script, "-postarg"])
532537
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
533538
self.assertEqual("3.100", data["SearchInfo.tag"])
534539
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
535540

536541
def test_py2_shebang(self):
537-
with self.py_ini(TEST_PY_COMMANDS):
542+
with self.py_ini(TEST_PY_DEFAULTS):
538543
with self.script("#! /usr/bin/python2 -prearg") as script:
539544
data = self.run_py([script, "-postarg"])
540545
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
541546
self.assertEqual("3.100-32", data["SearchInfo.tag"])
542547
self.assertEqual(f"X.Y-32.exe -prearg {script} -postarg", data["stdout"].strip())
543548

544549
def test_py3_shebang(self):
545-
with self.py_ini(TEST_PY_COMMANDS):
550+
with self.py_ini(TEST_PY_DEFAULTS):
546551
with self.script("#! /usr/bin/python3 -prearg") as script:
547552
data = self.run_py([script, "-postarg"])
548553
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
549554
self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
550555
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip())
551556

552557
def test_py_shebang_nl(self):
553-
with self.py_ini(TEST_PY_COMMANDS):
558+
with self.py_ini(TEST_PY_DEFAULTS):
554559
with self.script("#! /usr/bin/python -prearg\n") as script:
555560
data = self.run_py([script, "-postarg"])
556561
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
557562
self.assertEqual("3.100", data["SearchInfo.tag"])
558563
self.assertEqual(f"X.Y.exe -prearg {script} -postarg", data["stdout"].strip())
559564

560565
def test_py2_shebang_nl(self):
561-
with self.py_ini(TEST_PY_COMMANDS):
566+
with self.py_ini(TEST_PY_DEFAULTS):
562567
with self.script("#! /usr/bin/python2 -prearg\n") as script:
563568
data = self.run_py([script, "-postarg"])
564569
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
565570
self.assertEqual("3.100-32", data["SearchInfo.tag"])
566571
self.assertEqual(f"X.Y-32.exe -prearg {script} -postarg", data["stdout"].strip())
567572

568573
def test_py3_shebang_nl(self):
569-
with self.py_ini(TEST_PY_COMMANDS):
574+
with self.py_ini(TEST_PY_DEFAULTS):
570575
with self.script("#! /usr/bin/python3 -prearg\n") as script:
571576
data = self.run_py([script, "-postarg"])
572577
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
573578
self.assertEqual("3.100-arm64", data["SearchInfo.tag"])
574579
self.assertEqual(f"X.Y-arm64.exe -X fake_arg_for_test -prearg {script} -postarg", data["stdout"].strip())
575580

576581
def test_py_shebang_short_argv0(self):
577-
with self.py_ini(TEST_PY_COMMANDS):
582+
with self.py_ini(TEST_PY_DEFAULTS):
578583
with self.script("#! /usr/bin/python -prearg") as script:
579584
# Override argv to only pass "py.exe" as the command
580585
data = self.run_py([script, "-postarg"], argv=f'"py.exe" "{script}" -postarg')
@@ -591,7 +596,7 @@ def test_py_handle_64_in_ini(self):
591596

592597
def test_search_path(self):
593598
stem = Path(sys.executable).stem
594-
with self.py_ini(TEST_PY_COMMANDS):
599+
with self.py_ini(TEST_PY_DEFAULTS):
595600
with self.script(f"#! /usr/bin/env {stem} -prearg") as script:
596601
data = self.run_py(
597602
[script, "-postarg"],
@@ -602,7 +607,7 @@ def test_search_path(self):
602607
def test_search_path_exe(self):
603608
# Leave the .exe on the name to ensure we don't add it a second time
604609
name = Path(sys.executable).name
605-
with self.py_ini(TEST_PY_COMMANDS):
610+
with self.py_ini(TEST_PY_DEFAULTS):
606611
with self.script(f"#! /usr/bin/env {name} -prearg") as script:
607612
data = self.run_py(
608613
[script, "-postarg"],
@@ -612,7 +617,7 @@ def test_search_path_exe(self):
612617

613618
def test_recursive_search_path(self):
614619
stem = self.get_py_exe().stem
615-
with self.py_ini(TEST_PY_COMMANDS):
620+
with self.py_ini(TEST_PY_DEFAULTS):
616621
with self.script(f"#! /usr/bin/env {stem}") as script:
617622
data = self.run_py(
618623
[script],
@@ -673,3 +678,21 @@ def test_literal_shebang_quoted_escape(self):
673678
f'"{script.parent}\\some\\ random app" -witharg {script}',
674679
data["stdout"].strip(),
675680
)
681+
682+
def test_literal_shebang_command(self):
683+
with self.py_ini(TEST_PY_COMMANDS):
684+
with self.script('#! test-command arg1') as script:
685+
data = self.run_py([script])
686+
self.assertEqual(
687+
f"TEST_EXE.exe arg1 {script}",
688+
data["stdout"].strip(),
689+
)
690+
691+
def test_literal_shebang_invalid_template(self):
692+
with self.script('#! /usr/bin/not-python arg1') as script:
693+
data = self.run_py([script])
694+
expect = Path.cwd() / "/usr/bin/not-python"
695+
self.assertEqual(
696+
f"{expect} arg1 {script}",
697+
data["stdout"].strip(),
698+
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Restores support for the :file:`py.exe` launcher finding shebang commands in
2+
its configuration file using the full command name.

0 commit comments

Comments
 (0)