oracletrace 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oracletrace-0.1.0/PKG-INFO +43 -0
- oracletrace-0.1.0/README.md +34 -0
- oracletrace-0.1.0/oracletrace/__init__.py +3 -0
- oracletrace-0.1.0/oracletrace/cli.py +31 -0
- oracletrace-0.1.0/oracletrace/tracer.py +107 -0
- oracletrace-0.1.0/oracletrace.egg-info/PKG-INFO +43 -0
- oracletrace-0.1.0/oracletrace.egg-info/SOURCES.txt +11 -0
- oracletrace-0.1.0/oracletrace.egg-info/dependency_links.txt +1 -0
- oracletrace-0.1.0/oracletrace.egg-info/entry_points.txt +2 -0
- oracletrace-0.1.0/oracletrace.egg-info/requires.txt +1 -0
- oracletrace-0.1.0/oracletrace.egg-info/top_level.txt +1 -0
- oracletrace-0.1.0/pyproject.toml +15 -0
- oracletrace-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oracletrace
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simple logic path tracer
|
|
5
|
+
Author: Kayk Caputo, André Gustavo
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: rich
|
|
9
|
+
|
|
10
|
+
# OracleTrace
|
|
11
|
+
|
|
12
|
+
**OracleTrace** is a simple logic path tracer for Python applications. It visualizes the execution flow of your code, helping you understand function calls and performance bottlenecks.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install oracletrace
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Run `oracletrace` on your Python script:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
oracletrace your_script.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or run it as a module:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m oracletrace.cli your_script.py
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Logic Flow Visualization**: See a tree structure of function calls.
|
|
37
|
+
- **Performance Metrics**: View execution time and call counts for each function.
|
|
38
|
+
- **Clean Output**: Filters out internal Python calls for better readability.
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
- Python >= 3.10
|
|
43
|
+
- [rich](https://github.com/Textualize/rich)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# OracleTrace
|
|
2
|
+
|
|
3
|
+
**OracleTrace** is a simple logic path tracer for Python applications. It visualizes the execution flow of your code, helping you understand function calls and performance bottlenecks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install oracletrace
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Run `oracletrace` on your Python script:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
oracletrace your_script.py
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or run it as a module:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m oracletrace.cli your_script.py
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Logic Flow Visualization**: See a tree structure of function calls.
|
|
28
|
+
- **Performance Metrics**: View execution time and call counts for each function.
|
|
29
|
+
- **Clean Output**: Filters out internal Python calls for better readability.
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Python >= 3.10
|
|
34
|
+
- [rich](https://github.com/Textualize/rich)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import runpy
|
|
4
|
+
from .tracer import start_trace, stop_trace, show_results
|
|
5
|
+
|
|
6
|
+
def main():
|
|
7
|
+
if len(sys.argv) < 2:
|
|
8
|
+
print("Usage: oracletrace <file.py>")
|
|
9
|
+
return 1
|
|
10
|
+
|
|
11
|
+
target = sys.argv[1]
|
|
12
|
+
|
|
13
|
+
if not isinstance(target, str) or not os.path.exists(target):
|
|
14
|
+
print(f"Target not found: {target}")
|
|
15
|
+
return 1
|
|
16
|
+
|
|
17
|
+
target = os.path.abspath(target)
|
|
18
|
+
root = os.getcwd()
|
|
19
|
+
target_dir = os.path.dirname(target)
|
|
20
|
+
sys.path.insert(0, target_dir)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
start_trace(root)
|
|
24
|
+
runpy.run_path(target, run_name="__main__")
|
|
25
|
+
stop_trace()
|
|
26
|
+
show_results()
|
|
27
|
+
|
|
28
|
+
return 0
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
sys.exit(main())
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import time
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from rich.tree import Tree
|
|
6
|
+
from rich import print
|
|
7
|
+
|
|
8
|
+
_enabled = False
|
|
9
|
+
_root_path = ""
|
|
10
|
+
_call_stack = []
|
|
11
|
+
_func_calls = defaultdict(int)
|
|
12
|
+
_func_time = defaultdict(float)
|
|
13
|
+
_call_map = defaultdict(lambda: defaultdict(int))
|
|
14
|
+
|
|
15
|
+
def _is_user_code(filename):
|
|
16
|
+
if not filename.startswith(_root_path):
|
|
17
|
+
return False
|
|
18
|
+
if "site-packages" in filename or "dist-packages" in filename:
|
|
19
|
+
return False
|
|
20
|
+
return True
|
|
21
|
+
|
|
22
|
+
def _get_key(frame):
|
|
23
|
+
co_filename = frame.f_code.co_filename
|
|
24
|
+
if co_filename.startswith("<"):
|
|
25
|
+
return None
|
|
26
|
+
filename = os.path.abspath(co_filename)
|
|
27
|
+
if not _is_user_code(filename):
|
|
28
|
+
return None
|
|
29
|
+
rel_path = os.path.relpath(filename, _root_path)
|
|
30
|
+
return f"{rel_path}:{frame.f_code.co_name}"
|
|
31
|
+
|
|
32
|
+
def _trace(frame, event, arg):
|
|
33
|
+
if not _enabled:
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
if event == "call":
|
|
37
|
+
key = _get_key(frame)
|
|
38
|
+
if not key:
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
caller = _call_stack[-1][1] if _call_stack else "<module>"
|
|
42
|
+
_call_map[caller][key] += 1
|
|
43
|
+
_func_calls[key] += 1
|
|
44
|
+
_call_stack.append((id(frame), key, time.perf_counter()))
|
|
45
|
+
|
|
46
|
+
elif event == "return":
|
|
47
|
+
if not _call_stack:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
if id(frame) == _call_stack[-1][0]:
|
|
51
|
+
_, key, start = _call_stack.pop()
|
|
52
|
+
_func_time[key] += time.perf_counter() - start
|
|
53
|
+
else:
|
|
54
|
+
fid = id(frame)
|
|
55
|
+
found = False
|
|
56
|
+
for i in range(len(_call_stack) - 1, -1, -1):
|
|
57
|
+
if _call_stack[i][0] == fid:
|
|
58
|
+
found = True
|
|
59
|
+
break
|
|
60
|
+
|
|
61
|
+
if found:
|
|
62
|
+
while _call_stack:
|
|
63
|
+
top_fid, key, start = _call_stack.pop()
|
|
64
|
+
_func_time[key] += time.perf_counter() - start
|
|
65
|
+
if top_fid == fid:
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
def start_trace(root_dir):
|
|
69
|
+
global _enabled, _root_path, _call_stack, _func_calls, _func_time, _call_map
|
|
70
|
+
_root_path = os.path.abspath(root_dir)
|
|
71
|
+
_call_stack = []
|
|
72
|
+
_func_calls = defaultdict(int)
|
|
73
|
+
_func_time = defaultdict(float)
|
|
74
|
+
_call_map = defaultdict(lambda: defaultdict(int))
|
|
75
|
+
_enabled = True
|
|
76
|
+
sys.setprofile(_trace)
|
|
77
|
+
|
|
78
|
+
def stop_trace():
|
|
79
|
+
global _enabled
|
|
80
|
+
_enabled = False
|
|
81
|
+
sys.setprofile(None)
|
|
82
|
+
|
|
83
|
+
def show_results():
|
|
84
|
+
if not _func_calls:
|
|
85
|
+
print("[yellow]No calls traced.[/]")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
print("\n[bold green]Logic Flow:[/]")
|
|
89
|
+
|
|
90
|
+
tree = Tree("[bold yellow]<module>[/]")
|
|
91
|
+
|
|
92
|
+
def add_nodes(parent_node, parent_key, current_path):
|
|
93
|
+
children = _call_map.get(parent_key, {})
|
|
94
|
+
sorted_children = sorted(children.items(), key=lambda x: _func_time[x[0]], reverse=True)
|
|
95
|
+
|
|
96
|
+
for child_key, count in sorted_children:
|
|
97
|
+
total_time = _func_time[child_key]
|
|
98
|
+
if child_key in current_path:
|
|
99
|
+
parent_node.add(f"[red]↻ {child_key}[/] ({count}x)")
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
node_text = f"{child_key} [dim]({count}x, {total_time:.4f}s)[/]"
|
|
103
|
+
child_node = parent_node.add(node_text)
|
|
104
|
+
add_nodes(child_node, child_key, current_path | {child_key})
|
|
105
|
+
|
|
106
|
+
add_nodes(tree, "<module>", {"<module>"})
|
|
107
|
+
print(tree)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oracletrace
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Simple logic path tracer
|
|
5
|
+
Author: Kayk Caputo, André Gustavo
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: rich
|
|
9
|
+
|
|
10
|
+
# OracleTrace
|
|
11
|
+
|
|
12
|
+
**OracleTrace** is a simple logic path tracer for Python applications. It visualizes the execution flow of your code, helping you understand function calls and performance bottlenecks.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install oracletrace
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Run `oracletrace` on your Python script:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
oracletrace your_script.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or run it as a module:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m oracletrace.cli your_script.py
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Logic Flow Visualization**: See a tree structure of function calls.
|
|
37
|
+
- **Performance Metrics**: View execution time and call counts for each function.
|
|
38
|
+
- **Clean Output**: Filters out internal Python calls for better readability.
|
|
39
|
+
|
|
40
|
+
## Requirements
|
|
41
|
+
|
|
42
|
+
- Python >= 3.10
|
|
43
|
+
- [rich](https://github.com/Textualize/rich)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
oracletrace/__init__.py
|
|
4
|
+
oracletrace/cli.py
|
|
5
|
+
oracletrace/tracer.py
|
|
6
|
+
oracletrace.egg-info/PKG-INFO
|
|
7
|
+
oracletrace.egg-info/SOURCES.txt
|
|
8
|
+
oracletrace.egg-info/dependency_links.txt
|
|
9
|
+
oracletrace.egg-info/entry_points.txt
|
|
10
|
+
oracletrace.egg-info/requires.txt
|
|
11
|
+
oracletrace.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rich
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
oracletrace
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "oracletrace"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Simple logic path tracer"
|
|
9
|
+
authors = [{ name = "Kayk Caputo" }, { name = "André Gustavo" }]
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = ["rich"]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
oracletrace = "oracletrace.cli:main"
|