84
84
import traceback
85
85
import linecache
86
86
87
+ from typing import Union
88
+
87
89
88
90
class Restart (Exception ):
89
91
"""Causes a debugger to be restarted for the debugged python program."""
@@ -147,6 +149,23 @@ def check(self):
147
149
# Replace pdb's dir with script's dir in front of module search path.
148
150
sys .path [0 ] = os .path .dirname (self )
149
151
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
+
150
169
151
170
class ModuleTarget (str ):
152
171
def check (self ):
@@ -157,6 +176,31 @@ def details(self):
157
176
import runpy
158
177
return runpy ._get_module_details (self )
159
178
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
+
160
204
161
205
# Interaction prompt line will separate file and call info from code
162
206
# text using value of line_prefix string. A newline and arrow may
@@ -1564,50 +1608,26 @@ def lookupmodule(self, filename):
1564
1608
return fullname
1565
1609
return None
1566
1610
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).
1569
1617
self ._wait_for_mainpyfile = True
1570
1618
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.
1592
1625
import __main__
1593
1626
__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 )
1598
1630
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 )
1611
1631
1612
1632
# Collect all command help into docstring, if not run with -OO
1613
1633
0 commit comments