diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index e12c2a1b0454fd..638e1f8e2e83b3 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -254,6 +254,11 @@ pdb identified and executed. (Contributed by Tian Gao in :gh:`108464`.) +* ``sys.path[0]`` will no longer be replaced by the directory of the script + being debugged when ``sys.flags.safe_path`` is set (via the :option:`-P` + command line option or :envvar:`PYTHONSAFEPATH` environment variable). + (Contributed by Tian Gao and Christian Walther in :gh:`111762`.) + sqlite3 ------- diff --git a/Lib/pdb.py b/Lib/pdb.py index a4b02e010a6be6..f72251ded6067d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -142,8 +142,10 @@ def check(self): print('Error:', self.orig, 'is a directory') sys.exit(1) - # Replace pdb's dir with script's dir in front of module search path. - sys.path[0] = os.path.dirname(self) + # If safe_path(-P) is not set, sys.path[0] is the directory + # of pdb, and we should replace it with the directory of the script + if not sys.flags.safe_path: + sys.path[0] = os.path.dirname(self) @property def filename(self): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 5508f7bff37994..480dd5bb9e09b7 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -2493,15 +2493,21 @@ def tearDown(self): @unittest.skipIf(sys.flags.safe_path, 'PYTHONSAFEPATH changes default sys.path') - def _run_pdb(self, pdb_args, commands, expected_returncode=0): + def _run_pdb(self, pdb_args, commands, + expected_returncode=0, + extra_env=None): self.addCleanup(os_helper.rmtree, '__pycache__') cmd = [sys.executable, '-m', 'pdb'] + pdb_args + if extra_env is not None: + env = os.environ | extra_env + else: + env = os.environ with subprocess.Popen( cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, - env = {**os.environ, 'PYTHONIOENCODING': 'utf-8'} + env = {**env, 'PYTHONIOENCODING': 'utf-8'} ) as proc: stdout, stderr = proc.communicate(str.encode(commands)) stdout = stdout and bytes.decode(stdout) @@ -2513,13 +2519,15 @@ def _run_pdb(self, pdb_args, commands, expected_returncode=0): ) return stdout, stderr - def run_pdb_script(self, script, commands, expected_returncode=0): + def run_pdb_script(self, script, commands, + expected_returncode=0, + extra_env=None): """Run 'script' lines with pdb and the pdb 'commands'.""" filename = 'main.py' with open(filename, 'w') as f: f.write(textwrap.dedent(script)) self.addCleanup(os_helper.unlink, filename) - return self._run_pdb([filename], commands, expected_returncode) + return self._run_pdb([filename], commands, expected_returncode, extra_env) def run_pdb_module(self, script, commands): """Runs the script code as part of a module""" @@ -3104,6 +3112,23 @@ def test_issue42384_symlink(self): self.assertEqual(stdout.split('\n')[2].rstrip('\r'), expected) + def test_safe_path(self): + """ With safe_path set, pdb should not mangle sys.path[0]""" + + script = textwrap.dedent(""" + import sys + import random + print('sys.path[0] is', sys.path[0]) + """) + commands = 'c\n' + + + with os_helper.temp_cwd() as cwd: + stdout, _ = self.run_pdb_script(script, commands, extra_env={'PYTHONSAFEPATH': '1'}) + + unexpected = f'sys.path[0] is {os.path.realpath(cwd)}' + self.assertNotIn(unexpected, stdout) + def test_issue42383(self): with os_helper.temp_cwd() as cwd: with open('foo.py', 'w') as f: diff --git a/Misc/NEWS.d/next/Library/2023-11-05-20-09-27.gh-issue-99367.HLaWKo.rst b/Misc/NEWS.d/next/Library/2023-11-05-20-09-27.gh-issue-99367.HLaWKo.rst new file mode 100644 index 00000000000000..0920da221e423f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-05-20-09-27.gh-issue-99367.HLaWKo.rst @@ -0,0 +1 @@ +Do not mangle ``sys.path[0]`` in :mod:`pdb` if safe_path is set