kopia lustrzana https://github.com/micropython/micropython-lib
pdb: Initial micropython support.
rodzic
109711d911
commit
c3870d36fb
|
@ -66,25 +66,28 @@ Debugger commands
|
||||||
"""
|
"""
|
||||||
# NOTE: the actual command documentation is collected from docstrings of the
|
# NOTE: the actual command documentation is collected from docstrings of the
|
||||||
# commands and is appended to __doc__ after the class has been defined.
|
# commands and is appended to __doc__ after the class has been defined.
|
||||||
|
import builtins as __builtins__
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import cmd
|
import cmd
|
||||||
import bdb
|
import bdb
|
||||||
import dis
|
# import dis # MPY: dis not currently available
|
||||||
import code
|
import code
|
||||||
import glob
|
import glob
|
||||||
import pprint
|
import pprint
|
||||||
import signal
|
# import signal # MPY: signal not currently available
|
||||||
import inspect
|
# import inspect # MPY: inspect not currently available
|
||||||
import tokenize
|
import tokenize
|
||||||
import functools
|
# import functools
|
||||||
import traceback
|
import traceback
|
||||||
import linecache
|
import linecache
|
||||||
|
|
||||||
from typing import Union
|
try:
|
||||||
|
from typing import Union
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Restart(Exception):
|
class Restart(Exception):
|
||||||
|
@ -104,7 +107,9 @@ def find_function(funcname, filename):
|
||||||
with fp:
|
with fp:
|
||||||
for lineno, line in enumerate(fp, start=1):
|
for lineno, line in enumerate(fp, start=1):
|
||||||
if cre.match(line):
|
if cre.match(line):
|
||||||
return funcname, filename, lineno
|
## MPY: increment line number by 1 as we want to break on the
|
||||||
|
# first line of the function, not the function def line itself
|
||||||
|
return funcname, filename, lineno + 1
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getsourcelines(obj):
|
def getsourcelines(obj):
|
||||||
|
@ -117,11 +122,12 @@ def getsourcelines(obj):
|
||||||
return inspect.getblock(lines[lineno:]), lineno+1
|
return inspect.getblock(lines[lineno:]), lineno+1
|
||||||
|
|
||||||
def lasti2lineno(code, lasti):
|
def lasti2lineno(code, lasti):
|
||||||
linestarts = list(dis.findlinestarts(code))
|
## MPY: dis not currently available
|
||||||
linestarts.reverse()
|
# linestarts = list(dis.findlinestarts(code))
|
||||||
for i, lineno in linestarts:
|
# linestarts.reverse()
|
||||||
if lasti >= i:
|
# for i, lineno in linestarts:
|
||||||
return lineno
|
# if lasti >= i:
|
||||||
|
# return lineno
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -131,40 +137,39 @@ class _rstr(str):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class ScriptTarget(str):
|
class ScriptTarget:
|
||||||
def __new__(cls, val):
|
def __init__(self, val):
|
||||||
# Mutate self to be the "real path".
|
# Mutate self to be the "real path".
|
||||||
res = super().__new__(cls, os.path.realpath(val))
|
self.path = os.path.realpath(val)
|
||||||
|
|
||||||
# Store the original path for error reporting.
|
# Store the original path for error reporting.
|
||||||
res.orig = val
|
self.orig = val
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
if not os.path.exists(self):
|
if not os.path.exists(self.path):
|
||||||
print('Error:', self.orig, 'does not exist')
|
print('Error:', self.orig, 'does not exist')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Replace pdb's dir with script's dir in front of module search path.
|
# Replace pdb's dir with script's dir in front of module search path.
|
||||||
sys.path[0] = os.path.dirname(self)
|
sys.path[0] = os.path.dirname(self.path)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filename(self):
|
def filename(self):
|
||||||
return self
|
return self.path
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def namespace(self):
|
def namespace(self):
|
||||||
return dict(
|
return dict(
|
||||||
__name__='__main__',
|
__name__='__main__',
|
||||||
__file__=self,
|
__file__=self.path,
|
||||||
__builtins__=__builtins__,
|
__builtins__=__builtins__,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code(self):
|
def code(self):
|
||||||
with io.open(self) as fp:
|
with io.open(self.path) as fp:
|
||||||
return f"exec(compile({fp.read()!r}, {self!r}, 'exec'))"
|
## MPY: f-string !r syntax not supported
|
||||||
|
return f"exec(compile({repr(fp.read())}, {repr(self.path)}, 'exec'))"
|
||||||
|
|
||||||
|
|
||||||
class ModuleTarget(str):
|
class ModuleTarget(str):
|
||||||
|
@ -175,7 +180,7 @@ class ModuleTarget(str):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@functools.cached_property
|
# @functools.cached_property
|
||||||
def _details(self):
|
def _details(self):
|
||||||
import runpy
|
import runpy
|
||||||
return runpy._get_module_details(self)
|
return runpy._get_module_details(self)
|
||||||
|
@ -219,9 +224,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
|
|
||||||
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
|
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
|
||||||
nosigint=False, readrc=True):
|
nosigint=False, readrc=True):
|
||||||
bdb.Bdb.__init__(self, skip=skip)
|
bdb.Bdb.__init__(self, skip)
|
||||||
cmd.Cmd.__init__(self, completekey, stdin, stdout)
|
cmd.Cmd.__init__(self, completekey, stdin, stdout)
|
||||||
sys.audit("pdb.Pdb")
|
# sys.audit("pdb.Pdb")
|
||||||
if stdout:
|
if stdout:
|
||||||
self.use_rawinput = 0
|
self.use_rawinput = 0
|
||||||
self.prompt = '(Pdb) '
|
self.prompt = '(Pdb) '
|
||||||
|
@ -422,7 +427,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
if Pdb._previous_sigint_handler:
|
if Pdb._previous_sigint_handler:
|
||||||
try:
|
try:
|
||||||
signal.signal(signal.SIGINT, Pdb._previous_sigint_handler)
|
signal.signal(signal.SIGINT, Pdb._previous_sigint_handler)
|
||||||
except ValueError: # ValueError: signal only works in main thread
|
except (ValueError, NameError): # ValueError: signal only works in main thread
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
Pdb._previous_sigint_handler = None
|
Pdb._previous_sigint_handler = None
|
||||||
|
@ -573,7 +578,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
# Collect globals and locals. It is usually not really sensible to also
|
# Collect globals and locals. It is usually not really sensible to also
|
||||||
# complete builtins, and they clutter the namespace quite heavily, so we
|
# complete builtins, and they clutter the namespace quite heavily, so we
|
||||||
# leave them out.
|
# leave them out.
|
||||||
ns = {**self.curframe.f_globals, **self.curframe_locals}
|
ns = {}
|
||||||
|
ns.update(self.curframe.f_globals)
|
||||||
|
ns.update(self.curframe_locals)
|
||||||
if '.' in text:
|
if '.' in text:
|
||||||
# Walk an attribute chain up to the last part, similar to what
|
# Walk an attribute chain up to the last part, similar to what
|
||||||
# rlcompleter does. This will bail if any of the parts are not
|
# rlcompleter does. This will bail if any of the parts are not
|
||||||
|
@ -1137,7 +1144,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
try:
|
try:
|
||||||
Pdb._previous_sigint_handler = \
|
Pdb._previous_sigint_handler = \
|
||||||
signal.signal(signal.SIGINT, self.sigint_handler)
|
signal.signal(signal.SIGINT, self.sigint_handler)
|
||||||
except ValueError:
|
except (ValueError, NameError):
|
||||||
# ValueError happens when do_continue() is invoked from
|
# ValueError happens when do_continue() is invoked from
|
||||||
# a non-main thread in which case we just continue without
|
# a non-main thread in which case we just continue without
|
||||||
# SIGINT set. Would printing a message here (once) make
|
# SIGINT set. Would printing a message here (once) make
|
||||||
|
@ -1475,7 +1482,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
Start an interactive interpreter whose global namespace
|
Start an interactive interpreter whose global namespace
|
||||||
contains all the (global and local) names found in the current scope.
|
contains all the (global and local) names found in the current scope.
|
||||||
"""
|
"""
|
||||||
ns = {**self.curframe.f_globals, **self.curframe_locals}
|
ns = {}
|
||||||
|
ns.update(self.curframe.f_globals)
|
||||||
|
ns.update(self.curframe_locals)
|
||||||
code.interact("*interactive*", local=ns)
|
code.interact("*interactive*", local=ns)
|
||||||
|
|
||||||
def do_alias(self, arg):
|
def do_alias(self, arg):
|
||||||
|
@ -1640,29 +1649,34 @@ class Pdb(bdb.Bdb, cmd.Cmd):
|
||||||
# __main__ will break). Clear __main__ and replace with
|
# __main__ will break). Clear __main__ and replace with
|
||||||
# the target namespace.
|
# the target namespace.
|
||||||
import __main__
|
import __main__
|
||||||
|
try:
|
||||||
|
__main__.__dict__
|
||||||
|
except AttributeError:
|
||||||
|
__main__.__dict__ = dict()
|
||||||
__main__.__dict__.clear()
|
__main__.__dict__.clear()
|
||||||
__main__.__dict__.update(target.namespace)
|
__main__.__dict__.update(target.namespace)
|
||||||
|
|
||||||
|
|
||||||
self.run(target.code)
|
self.run(target.code)
|
||||||
|
|
||||||
|
|
||||||
# Collect all command help into docstring, if not run with -OO
|
# Collect all command help into docstring, if not run with -OO
|
||||||
|
## MPY: NameError: name '__doc__' isn't defined
|
||||||
|
# if __doc__ is not None:
|
||||||
|
# # unfortunately we can't guess this order from the class definition
|
||||||
|
# _help_order = [
|
||||||
|
# 'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
|
||||||
|
# 'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
|
||||||
|
# 'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
|
||||||
|
# 'args', 'p', 'pp', 'whatis', 'source', 'display', 'undisplay',
|
||||||
|
# 'interact', 'alias', 'unalias', 'debug', 'quit',
|
||||||
|
# ]
|
||||||
|
|
||||||
if __doc__ is not None:
|
# for _command in _help_order:
|
||||||
# unfortunately we can't guess this order from the class definition
|
# __doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
|
||||||
_help_order = [
|
# __doc__ += Pdb.help_exec.__doc__
|
||||||
'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
|
|
||||||
'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
|
|
||||||
'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
|
|
||||||
'args', 'p', 'pp', 'whatis', 'source', 'display', 'undisplay',
|
|
||||||
'interact', 'alias', 'unalias', 'debug', 'quit',
|
|
||||||
]
|
|
||||||
|
|
||||||
for _command in _help_order:
|
# del _help_order, _command
|
||||||
__doc__ += getattr(Pdb, 'do_' + _command).__doc__.strip() + '\n\n'
|
|
||||||
__doc__ += Pdb.help_exec.__doc__
|
|
||||||
|
|
||||||
del _help_order, _command
|
|
||||||
|
|
||||||
|
|
||||||
# Simplified interface
|
# Simplified interface
|
||||||
|
@ -1781,9 +1795,11 @@ def main():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
t = sys.exc_info()[2]
|
||||||
|
if t is None:
|
||||||
|
break
|
||||||
print("Uncaught exception. Entering post mortem debugging")
|
print("Uncaught exception. Entering post mortem debugging")
|
||||||
print("Running 'cont' or 'step' will restart the program")
|
print("Running 'cont' or 'step' will restart the program")
|
||||||
t = sys.exc_info()[2]
|
|
||||||
pdb.interaction(None, t)
|
pdb.interaction(None, t)
|
||||||
print("Post mortem debugger finished. The " + target +
|
print("Post mortem debugger finished. The " + target +
|
||||||
" will be restarted")
|
" will be restarted")
|
||||||
|
|
Ładowanie…
Reference in New Issue