diff --git a/pydumpling/cli.py b/pydumpling/cli.py index d342e29..6c25e7a 100644 --- a/pydumpling/cli.py +++ b/pydumpling/cli.py @@ -3,7 +3,7 @@ from .debug_dumpling import debug_dumpling, load_dumpling from .helpers import print_traceback_and_except, validate_file_name from .rpdb import r_post_mortem - +from .vis import generate_vis parser = argparse.ArgumentParser( description="pydumpling cli tools", @@ -32,6 +32,10 @@ help="enter rpdb debugging interface" ) +pydumpling_cli_action_group.add_argument( + "--vis", action="store_true", help="visualize the traceback" +) + parser.add_argument( "filename", type=validate_file_name, @@ -49,3 +53,5 @@ def main() -> None: debug_dumpling(file_name) elif args.rdebug: r_post_mortem(file_name) + elif args.vis: + generate_vis(file_name) diff --git a/pydumpling/fake_types.py b/pydumpling/fake_types.py index 4cc1e18..e35a7d0 100644 --- a/pydumpling/fake_types.py +++ b/pydumpling/fake_types.py @@ -70,6 +70,13 @@ def __init__(self, traceback=None): traceback.tb_next) if traceback and traceback.tb_next else None self.tb_lasti = traceback.tb_lasti if traceback else 0 + def serialize(self): + return { + 'tb_frame': self.tb_frame.serialize() if self.tb_frame else None, + 'tb_lineno': self.tb_lineno, + 'tb_next': self.tb_next.serialize() if self.tb_next else None, + } + class FakeFrame(FakeType): def __init__(self, frame): @@ -83,6 +90,12 @@ def __init__(self, frame): self.f_lasti = frame.f_lasti self.f_builtins = frame.f_builtins + def serialize(self): + return { + 'f_code': self.f_code.serialize(), + 'f_lineno': self.f_lineno, + } + class FakeClass(FakeType): @@ -116,3 +129,9 @@ def __init__(self, code): def co_lines(self): return iter(self._co_lines) + + def serialize(self): + return { + 'co_filename': self.co_filename, + 'co_name': self.co_name, + } \ No newline at end of file diff --git a/pydumpling/templates/traceback.html b/pydumpling/templates/traceback.html new file mode 100644 index 0000000..4ead394 --- /dev/null +++ b/pydumpling/templates/traceback.html @@ -0,0 +1,161 @@ + + + +
+{{exc_type}}
+ {{exc_value}}
+ {raw_code}
'
+
+def _generate_label(f_code,lineno) -> str:
+ return f'line: {lineno} \n{_wrap_code("func: " + f_code["co_name"])} \n{_wrap_code(getline(f_code["co_filename"], lineno).strip())}'
+
+
+def extract_frame(traceback: dict) -> list[dict]:
+ frames = []
+ for key, value in traceback.items():
+ if key == 'tb_frame':
+ f_code = value['f_code']
+ frames.append(
+ {
+ 'id': str(uuid4()),
+ 'label': _generate_label(f_code, value["f_lineno"]),
+ 'extra': {
+ 'co_filename': f_code['co_filename'],
+ 'co_type': f_code['co_name'] == '