Skip to content

Commit 61d9128

Browse files
authored
Merge pull request #17 from cocolato/dev
[ENH] Provides command line tool for pydumpling
2 parents be5cd36 + 8fb841a commit 61d9128

File tree

9 files changed

+111
-22
lines changed

9 files changed

+111
-22
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ __pycache__
55
*.dump
66
test.py
77
/my
8-
.vscode
8+
.vscode
9+
.idea
1.63 KB
Binary file not shown.

dist/pydumpling-0.1.1.tar.gz

741 Bytes
Binary file not shown.

poetry.lock

Lines changed: 14 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pydumpling/__main__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .cli import main
2+
3+
main()

pydumpling/cli.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import argparse
2+
import os.path
3+
from .debug_dumpling import debug_dumpling, load_dumpling
4+
from .helpers import print_traceback_and_except
5+
6+
DUMP_FILE_EXTENSION: str = ".dump"
7+
8+
9+
def validate_file_name(file_name: str) -> str:
10+
"""check file extension name and exists"""
11+
if not file_name.endswith(DUMP_FILE_EXTENSION):
12+
raise argparse.ArgumentTypeError("File must be .dump file")
13+
if not os.path.exists(file_name):
14+
raise argparse.ArgumentTypeError(f"File {file_name} not found")
15+
return file_name
16+
17+
18+
parser = argparse.ArgumentParser(
19+
description="pydumpling cli tools",
20+
prog="pydumpling",
21+
usage="%(prog)s [options] filename"
22+
)
23+
24+
# print or debug
25+
pydumpling_cli_action_group = parser.add_mutually_exclusive_group(required=True)
26+
27+
pydumpling_cli_action_group.add_argument(
28+
"--print",
29+
action="store_true",
30+
help="print traceback information"
31+
)
32+
33+
pydumpling_cli_action_group.add_argument(
34+
"--debug",
35+
action="store_true",
36+
help="enter pdb debugging interface"
37+
)
38+
39+
parser.add_argument(
40+
"filename",
41+
type=validate_file_name,
42+
help="the .dump file"
43+
)
44+
45+
46+
def main() -> None:
47+
args = parser.parse_args()
48+
file_name = args.filename
49+
if args.print:
50+
dumpling_ = load_dumpling(file_name)
51+
print_traceback_and_except(dumpling_)
52+
elif args.debug:
53+
debug_dumpling(file_name)

pydumpling/fake_types.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def __init__(self, traceback=None):
6666
self.tb_lineno = traceback.tb_lineno if traceback else None
6767
self.tb_next = FakeTraceback(
6868
traceback.tb_next) if traceback and traceback.tb_next else None
69-
self.tb_lasti = 0
69+
self.tb_lasti = traceback.tb_lasti if traceback else 0
7070

7171

7272
class FakeFrame(FakeType):
@@ -78,6 +78,8 @@ def __init__(self, frame):
7878
self.f_globals = self._convert_dict(frame.f_globals)
7979
self.f_lineno = frame.f_lineno
8080
self.f_back = FakeFrame(frame.f_back) if frame.f_back else None
81+
self.f_lasti = frame.f_lasti
82+
self.f_builtins = frame.f_builtins
8183

8284

8385
class FakeClass(FakeType):
@@ -107,6 +109,8 @@ def __init__(self, code):
107109
code, "co_lines") else []
108110
if hasattr(code, "co_kwonlyargcount"):
109111
self.co_kwonlyargcount = code.co_kwonlyargcount
112+
if hasattr(code, "co_positions"):
113+
self.co_positions = code.co_positions
110114

111115
def co_lines(self):
112116
return iter(self._co_lines)

pydumpling/helpers.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import linecache
2+
3+
4+
def print_traceback_and_except(dumpling_result):
5+
traceback_obj = dumpling_result["traceback"]
6+
except_extra = dumpling_result["exc_extra"]
7+
except_type = except_extra["exc_type"]
8+
except_value = except_extra["exc_value"]
9+
10+
print("Traceback (most recent call last):")
11+
while traceback_obj:
12+
frame = traceback_obj.tb_frame
13+
lineno = traceback_obj.tb_lineno
14+
filename = frame.f_code.co_filename
15+
function_name = frame.f_code.co_name
16+
line = linecache.getline(filename, lineno).strip()
17+
mid_index = len(line) // 2
18+
19+
print(f"File \"{filename}\", line {lineno}, in {function_name}")
20+
print(f" {line}")
21+
print(" " * 4 + "~" * mid_index + "^" + "~" * mid_index)
22+
traceback_obj = traceback_obj.tb_next
23+
24+
if traceback_obj is None:
25+
break
26+
print(f"{except_type.__name__}: {except_value}")

pydumpling/pydumpling.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
def save_dumping(filename=None, tb=None):
1515
try:
1616
if tb is None:
17-
tb = sys.exc_info()[2]
17+
exc_type, exc_value, exc_tb = sys.exc_info()
1818

1919
if filename is None:
2020
filename = "%s:%d.dump" % (
21-
tb.tb_frame.f_code.co_filename, tb.tb_frame.f_lineno)
21+
exc_tb.tb_frame.f_code.co_filename, exc_tb.tb_frame.f_lineno)
2222

23-
fake_tb = FakeTraceback(tb)
23+
fake_tb = FakeTraceback(exc_tb)
2424
dumpling = {
2525
"traceback": fake_tb,
2626
"version": __version__,
27+
"exc_extra": {
28+
"exc_type": exc_type,
29+
"exc_value": exc_value,
30+
},
2731
"dump_type": "DILL"
2832
}
2933
with gzip.open(filename, "wb") as f:
@@ -68,7 +72,7 @@ def gen_tb_from_frame(f):
6872
f = f.f_back
6973
if f is None:
7074
return tb
71-
while f and "python" not in f.f_code.co_filename.lower():
75+
while f:
7276
tb = FakeTraceback()
7377
tb.tb_frame = FakeFrame(f)
7478
tb.tb_lasti = f.f_lasti

0 commit comments

Comments
 (0)