Skip to content

Commit fe8aea5

Browse files
committed
Replace singledispatch _run with a unified implementation selecting on properties of the Target object.
1 parent e21f085 commit fe8aea5

File tree

2 files changed

+60
-40
lines changed

2 files changed

+60
-40
lines changed

Lib/pdb.py

+59-39
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484
import traceback
8585
import linecache
8686

87+
from typing import Union
88+
8789

8890
class Restart(Exception):
8991
"""Causes a debugger to be restarted for the debugged python program."""
@@ -147,6 +149,23 @@ def check(self):
147149
# Replace pdb's dir with script's dir in front of module search path.
148150
sys.path[0] = os.path.dirname(self)
149151

152+
@property
153+
def filename(self):
154+
return self
155+
156+
@property
157+
def namespace(self):
158+
return dict(
159+
__name__='__main__',
160+
__file__=self,
161+
__builtins__=__builtins__,
162+
)
163+
164+
@property
165+
def code(self):
166+
with io.open(self) as fp:
167+
return f"exec(compile({fp.read()!r}, {self!r}, 'exec'))"
168+
150169

151170
class ModuleTarget(str):
152171
def check(self):
@@ -157,6 +176,31 @@ def details(self):
157176
import runpy
158177
return runpy._get_module_details(self)
159178

179+
@property
180+
def filename(self):
181+
return self.code.co_filename
182+
183+
@property
184+
def code(self):
185+
name, spec, code = self.details
186+
return code
187+
188+
@property
189+
def spec(self):
190+
name, spec, code = self.details
191+
return spec
192+
193+
@property
194+
def namespace(self):
195+
return dict(
196+
__name__='__main__',
197+
__file__=os.path.normcase(os.path.abspath(self.filename)),
198+
__package__=self.spec.parent,
199+
__loader__=self.spec.loader,
200+
__spec__=self.spec,
201+
__builtins__=__builtins__,
202+
)
203+
160204

161205
# Interaction prompt line will separate file and call info from code
162206
# text using value of line_prefix string. A newline and arrow may
@@ -1564,50 +1608,26 @@ def lookupmodule(self, filename):
15641608
return fullname
15651609
return None
15661610

1567-
@functools.singledispatchmethod
1568-
def _run(self, target: 'ModuleTarget'):
1611+
def _run(self, target: Union[ModuleTarget, ScriptTarget]):
1612+
# When bdb sets tracing, a number of call and line events happen
1613+
# BEFORE debugger even reaches user's code (and the exact sequence of
1614+
# events depends on python version). Take special measures to
1615+
# avoid stopping before reaching the main script (see user_line and
1616+
# user_call for details).
15691617
self._wait_for_mainpyfile = True
15701618
self._user_requested_quit = False
1571-
mod_name, mod_spec, code = target.details
1572-
self.mainpyfile = self.canonic(code.co_filename)
1573-
import __main__
1574-
__main__.__dict__.clear()
1575-
__main__.__dict__.update({
1576-
"__name__": "__main__",
1577-
"__file__": self.mainpyfile,
1578-
"__package__": mod_spec.parent,
1579-
"__loader__": mod_spec.loader,
1580-
"__spec__": mod_spec,
1581-
"__builtins__": __builtins__,
1582-
})
1583-
self.run(code)
1584-
1585-
@_run.register
1586-
def _(self, filename: 'ScriptTarget'):
1587-
# The script has to run in __main__ namespace (or imports from
1588-
# __main__ will break).
1589-
#
1590-
# So we clear up the __main__ and set several special variables
1591-
# (this gets rid of pdb's globals and cleans old variables on restarts).
1619+
1620+
self.mainpyfile = self.canonic(target.filename)
1621+
1622+
# The target has to run in __main__ namespace (or imports from
1623+
# __main__ will break). Clear __main__ and replace with
1624+
# the target namespace.
15921625
import __main__
15931626
__main__.__dict__.clear()
1594-
__main__.__dict__.update({"__name__" : "__main__",
1595-
"__file__" : filename,
1596-
"__builtins__": __builtins__,
1597-
})
1627+
__main__.__dict__.update(target.namespace)
1628+
1629+
self.run(target.code)
15981630

1599-
# When bdb sets tracing, a number of call and line events happens
1600-
# BEFORE debugger even reaches user's code (and the exact sequence of
1601-
# events depends on python version). So we take special measures to
1602-
# avoid stopping before we reach the main script (see user_line and
1603-
# user_call for details).
1604-
self._wait_for_mainpyfile = True
1605-
self.mainpyfile = self.canonic(filename)
1606-
self._user_requested_quit = False
1607-
with io.open_code(filename) as fp:
1608-
statement = "exec(compile(%r, %r, 'exec'))" % \
1609-
(fp.read(), self.mainpyfile)
1610-
self.run(statement)
16111631

16121632
# Collect all command help into docstring, if not run with -OO
16131633

Lib/test/test_pdb.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions():
362362
1 breakpoint keep yes at ...test_pdb.py:...
363363
2 breakpoint keep yes at ...test_pdb.py:...
364364
(Pdb) break pdb.find_function
365-
Breakpoint 3 at ...pdb.py:95
365+
Breakpoint 3 at ...pdb.py:97
366366
(Pdb) break
367367
Num Type Disp Enb Where
368368
1 breakpoint keep yes at ...test_pdb.py:...

0 commit comments

Comments
 (0)