Skip to content

Commit b7fceca

Browse files
committed
pdb: Initial micropython support.
1 parent 3eeda0a commit b7fceca

File tree

1 file changed

+62
-46
lines changed

1 file changed

+62
-46
lines changed

python-stdlib/pdb/pdb.py

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,28 @@
6666
"""
6767
# NOTE: the actual command documentation is collected from docstrings of the
6868
# commands and is appended to __doc__ after the class has been defined.
69-
69+
import builtins as __builtins__
7070
import os
7171
import io
7272
import re
7373
import sys
7474
import cmd
7575
import bdb
76-
import dis
76+
# import dis # MPY: dis not currently available
7777
import code
7878
import glob
7979
import pprint
80-
import signal
81-
import inspect
80+
# import signal # MPY: signal not currently available
81+
# import inspect # MPY: inspect not currently available
8282
import tokenize
83-
import functools
83+
# import functools
8484
import traceback
8585
import linecache
8686

87-
from typing import Union
87+
try:
88+
from typing import Union
89+
except ImportError:
90+
pass
8891

8992

9093
class Restart(Exception):
@@ -104,7 +107,9 @@ def find_function(funcname, filename):
104107
with fp:
105108
for lineno, line in enumerate(fp, start=1):
106109
if cre.match(line):
107-
return funcname, filename, lineno
110+
## MPY: increment line number by 1 as we want to break on the
111+
# first line of the function, not the function def line itself
112+
return funcname, filename, lineno + 1
108113
return None
109114

110115
def getsourcelines(obj):
@@ -117,11 +122,12 @@ def getsourcelines(obj):
117122
return inspect.getblock(lines[lineno:]), lineno+1
118123

119124
def lasti2lineno(code, lasti):
120-
linestarts = list(dis.findlinestarts(code))
121-
linestarts.reverse()
122-
for i, lineno in linestarts:
123-
if lasti >= i:
124-
return lineno
125+
## MPY: dis not currently available
126+
# linestarts = list(dis.findlinestarts(code))
127+
# linestarts.reverse()
128+
# for i, lineno in linestarts:
129+
# if lasti >= i:
130+
# return lineno
125131
return 0
126132

127133

@@ -131,40 +137,39 @@ def __repr__(self):
131137
return self
132138

133139

134-
class ScriptTarget(str):
135-
def __new__(cls, val):
140+
class ScriptTarget:
141+
def __init__(self, val):
136142
# Mutate self to be the "real path".
137-
res = super().__new__(cls, os.path.realpath(val))
143+
self.path = os.path.realpath(val)
138144

139145
# Store the original path for error reporting.
140-
res.orig = val
141-
142-
return res
146+
self.orig = val
143147

144148
def check(self):
145-
if not os.path.exists(self):
149+
if not os.path.exists(self.path):
146150
print('Error:', self.orig, 'does not exist')
147151
sys.exit(1)
148152

149153
# Replace pdb's dir with script's dir in front of module search path.
150-
sys.path[0] = os.path.dirname(self)
154+
sys.path[0] = os.path.dirname(self.path)
151155

152156
@property
153157
def filename(self):
154-
return self
158+
return self.path
155159

156160
@property
157161
def namespace(self):
158162
return dict(
159163
__name__='__main__',
160-
__file__=self,
164+
__file__=self.path,
161165
__builtins__=__builtins__,
162166
)
163167

164168
@property
165169
def code(self):
166-
with io.open(self) as fp:
167-
return f"exec(compile({fp.read()!r}, {self!r}, 'exec'))"
170+
with io.open(self.path) as fp:
171+
## MPY: f-string !r syntax not supported
172+
return f"exec(compile({repr(fp.read())}, {repr(self.path)}, 'exec'))"
168173

169174

170175
class ModuleTarget(str):
@@ -175,7 +180,7 @@ def check(self):
175180
traceback.print_exc()
176181
sys.exit(1)
177182

178-
@functools.cached_property
183+
# @functools.cached_property
179184
def _details(self):
180185
import runpy
181186
return runpy._get_module_details(self)
@@ -219,9 +224,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
219224

220225
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
221226
nosigint=False, readrc=True):
222-
bdb.Bdb.__init__(self, skip=skip)
227+
bdb.Bdb.__init__(self, skip)
223228
cmd.Cmd.__init__(self, completekey, stdin, stdout)
224-
sys.audit("pdb.Pdb")
229+
# sys.audit("pdb.Pdb")
225230
if stdout:
226231
self.use_rawinput = 0
227232
self.prompt = '(Pdb) '
@@ -422,7 +427,7 @@ def interaction(self, frame, traceback):
422427
if Pdb._previous_sigint_handler:
423428
try:
424429
signal.signal(signal.SIGINT, Pdb._previous_sigint_handler)
425-
except ValueError: # ValueError: signal only works in main thread
430+
except (ValueError, NameError): # ValueError: signal only works in main thread
426431
pass
427432
else:
428433
Pdb._previous_sigint_handler = None
@@ -573,7 +578,9 @@ def _complete_expression(self, text, line, begidx, endidx):
573578
# Collect globals and locals. It is usually not really sensible to also
574579
# complete builtins, and they clutter the namespace quite heavily, so we
575580
# leave them out.
576-
ns = {**self.curframe.f_globals, **self.curframe_locals}
581+
ns = {}
582+
ns.update(self.curframe.f_globals)
583+
ns.update(self.curframe_locals)
577584
if '.' in text:
578585
# Walk an attribute chain up to the last part, similar to what
579586
# rlcompleter does. This will bail if any of the parts are not
@@ -1137,7 +1144,7 @@ def do_continue(self, arg):
11371144
try:
11381145
Pdb._previous_sigint_handler = \
11391146
signal.signal(signal.SIGINT, self.sigint_handler)
1140-
except ValueError:
1147+
except (ValueError, NameError):
11411148
# ValueError happens when do_continue() is invoked from
11421149
# a non-main thread in which case we just continue without
11431150
# SIGINT set. Would printing a message here (once) make
@@ -1475,7 +1482,9 @@ def do_interact(self, arg):
14751482
Start an interactive interpreter whose global namespace
14761483
contains all the (global and local) names found in the current scope.
14771484
"""
1478-
ns = {**self.curframe.f_globals, **self.curframe_locals}
1485+
ns = {}
1486+
ns.update(self.curframe.f_globals)
1487+
ns.update(self.curframe_locals)
14791488
code.interact("*interactive*", local=ns)
14801489

14811490
def do_alias(self, arg):
@@ -1640,29 +1649,34 @@ def _run(self, target: Union[ModuleTarget, ScriptTarget]):
16401649
# __main__ will break). Clear __main__ and replace with
16411650
# the target namespace.
16421651
import __main__
1652+
try:
1653+
__main__.__dict__
1654+
except AttributeError:
1655+
__main__.__dict__ = dict()
16431656
__main__.__dict__.clear()
16441657
__main__.__dict__.update(target.namespace)
1658+
16451659

16461660
self.run(target.code)
16471661

16481662

16491663
# Collect all command help into docstring, if not run with -OO
1664+
## MPY: NameError: name '__doc__' isn't defined
1665+
# if __doc__ is not None:
1666+
# # unfortunately we can't guess this order from the class definition
1667+
# _help_order = [
1668+
# 'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
1669+
# 'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
1670+
# 'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
1671+
# 'args', 'p', 'pp', 'whatis', 'source', 'display', 'undisplay',
1672+
# 'interact', 'alias', 'unalias', 'debug', 'quit',
1673+
# ]
16501674

1651-
if __doc__ is not None:
1652-
# unfortunately we can't guess this order from the class definition
1653-
_help_order = [
1654-
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
1655-
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
1656-
'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
1657-
'args', 'p', 'pp', 'whatis', 'source', 'display', 'undisplay',
1658-
'interact', 'alias', 'unalias', 'debug', 'quit',
1659-
]
1660-
1661-
for _command in _help_order:
1662-
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
1663-
__doc__ += Pdb.help_exec.__doc__
1675+
# for _command in _help_order:
1676+
# __doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
1677+
# __doc__ += Pdb.help_exec.__doc__
16641678

1665-
del _help_order, _command
1679+
# del _help_order, _command
16661680

16671681

16681682
# Simplified interface
@@ -1781,9 +1795,11 @@ def main():
17811795
sys.exit(1)
17821796
except:
17831797
traceback.print_exc()
1798+
t = sys.exc_info()[2]
1799+
if t is None:
1800+
break
17841801
print("Uncaught exception. Entering post mortem debugging")
17851802
print("Running 'cont' or 'step' will restart the program")
1786-
t = sys.exc_info()[2]
17871803
pdb.interaction(None, t)
17881804
print("Post mortem debugger finished. The " + target +
17891805
" will be restarted")

0 commit comments

Comments
 (0)