|
65 | 65 | # NOTE: the actual command documentation is collected from docstrings of the |
66 | 66 | # commands and is appended to __doc__ after the class has been defined. |
67 | 67 |
|
68 | | -import os |
69 | | -import io |
70 | | -import re |
71 | | -import sys |
72 | | -import cmd |
| 68 | +import asyncio |
| 69 | +import atexit |
73 | 70 | import bdb |
74 | | -import dis |
| 71 | +import builtins |
| 72 | +import cmd |
75 | 73 | import code |
| 74 | +import codeop |
| 75 | +import dis |
76 | 76 | import glob |
| 77 | +import inspect |
| 78 | +import io |
| 79 | +import itertools |
77 | 80 | import json |
78 | | -import stat |
79 | | -import token |
80 | | -import types |
81 | | -import atexit |
82 | | -import codeop |
| 81 | +import linecache |
| 82 | +import os |
83 | 83 | import pprint |
| 84 | +import re |
| 85 | +import selectors |
84 | 86 | import signal |
85 | 87 | import socket |
86 | | -import typing |
87 | | -import asyncio |
88 | | -import inspect |
89 | | -import weakref |
90 | | -import builtins |
| 88 | +import stat |
| 89 | +import sys |
91 | 90 | import tempfile |
92 | 91 | import textwrap |
| 92 | +import threading |
| 93 | +import token |
93 | 94 | import tokenize |
94 | | -import itertools |
95 | 95 | import traceback |
96 | | -import linecache |
97 | | -import selectors |
98 | | -import threading |
99 | | -import _colorize |
100 | | -import _pyrepl.utils |
101 | | - |
| 96 | +import types |
| 97 | +import typing |
| 98 | +import weakref |
102 | 99 | from contextlib import ExitStack, closing, contextmanager |
103 | 100 | from types import CodeType |
104 | 101 | from warnings import deprecated |
105 | 102 |
|
| 103 | +import _colorize |
| 104 | +import _pyrepl.utils |
| 105 | + |
106 | 106 |
|
107 | 107 | class Restart(Exception): |
108 | 108 | """Causes a debugger to be restarted for the debugged python program.""" |
@@ -184,25 +184,34 @@ class _ExecutableTarget: |
184 | 184 | class _ScriptTarget(_ExecutableTarget): |
185 | 185 | def __init__(self, target): |
186 | 186 | if not os.path.exists(target): |
187 | | - print(f'Error: {target} does not exist') |
| 187 | + print(f"Error: {target} does not exist") |
188 | 188 | sys.exit(1) |
189 | 189 | if os.path.isdir(target): |
190 | | - print(f'Error: {target} is a directory') |
| 190 | + print(f"Error: {target} is a directory") |
191 | 191 | sys.exit(1) |
192 | 192 |
|
193 | | - # Use the original path for files like anonymous pipes |
194 | | - # from process substitution (GH-142315). |
195 | | - realpath = os.path.realpath(target) |
196 | | - self._target = realpath if os.path.exists(realpath) else target |
| 193 | + self._target = self._safe_realpath(target) |
197 | 194 |
|
198 | | - # If safe_path(-P) is not set, sys.path[0] is the directory |
| 195 | + # If PYTHONSAFEPATH (-P) is not set, sys.path[0] is the directory |
199 | 196 | # of pdb, and we should replace it with the directory of the script |
200 | 197 | if not sys.flags.safe_path: |
201 | 198 | sys.path[0] = os.path.dirname(self._target) |
202 | 199 |
|
203 | 200 | def __repr__(self): |
204 | 201 | return self._target |
205 | 202 |
|
| 203 | + @staticmethod |
| 204 | + def _safe_realpath(path): |
| 205 | + """ |
| 206 | + Return the canonical path (realpath) if it is accessible from the userspace. |
| 207 | + Otherwise (for example, if the path is a symlink to an anonymous pipe), |
| 208 | + return the original path. |
| 209 | +
|
| 210 | + See GH-142315. |
| 211 | + """ |
| 212 | + realpath = os.path.realpath(path) |
| 213 | + return realpath if os.path.exists(realpath) else path |
| 214 | + |
206 | 215 | @property |
207 | 216 | def filename(self): |
208 | 217 | return self._target |
|
0 commit comments