8484import traceback
8585import linecache
8686
87+ from typing import Union
88+
8789
8890class 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
151170class 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
0 commit comments