traceflow-py 1.2.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.
- traceflow_py-1.2.0/LICENSE +11 -0
- traceflow_py-1.2.0/PKG-INFO +409 -0
- traceflow_py-1.2.0/README.md +381 -0
- traceflow_py-1.2.0/pyproject.toml +47 -0
- traceflow_py-1.2.0/setup.cfg +4 -0
- traceflow_py-1.2.0/src/traceflow/__init__.py +22 -0
- traceflow_py-1.2.0/src/traceflow/core.py +227 -0
- traceflow_py-1.2.0/src/traceflow_py.egg-info/PKG-INFO +409 -0
- traceflow_py-1.2.0/src/traceflow_py.egg-info/SOURCES.txt +9 -0
- traceflow_py-1.2.0/src/traceflow_py.egg-info/dependency_links.txt +1 -0
- traceflow_py-1.2.0/src/traceflow_py.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
All Rights Reserved
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aarav Agarwal
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") may not be
|
|
6
|
+
copied, modified, merged, published, distributed, sublicensed, or sold without
|
|
7
|
+
the express written permission of the copyright holder.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
10
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
11
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: traceflow-py
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: A lightweight decorator for visually tracing Python function calls with indented call trees, timing, variable tracking, and async support.
|
|
5
|
+
Author: Aarav Agarwal
|
|
6
|
+
License: All Rights Reserved
|
|
7
|
+
Project-URL: Homepage, https://github.com/Firestar3/TraceFlow
|
|
8
|
+
Project-URL: Repository, https://github.com/Firestar3/TraceFlow
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/Firestar3/TraceFlow/issues
|
|
10
|
+
Keywords: tracing,debugging,decorator,call-tree,profiling,recursion,async,logging
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Operating System :: OS Independent
|
|
24
|
+
Requires-Python: >=3.7
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# TraceFlow
|
|
30
|
+
|
|
31
|
+
**TraceFlow** is a lightweight, zero-dependency Python decorator library for visually tracing function execution. It renders beautiful, indented call trees directly to your console — making debugging recursive, nested, and async code effortless.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
fibonacci(3)
|
|
35
|
+
├── fibonacci(2)
|
|
36
|
+
│ ├── fibonacci(1)
|
|
37
|
+
│ │ └── return 1 [0.0003s]
|
|
38
|
+
│ ├── fibonacci(0)
|
|
39
|
+
│ │ └── return 0 [0.0000s]
|
|
40
|
+
│ └── return 1 [0.0006s]
|
|
41
|
+
├── fibonacci(1)
|
|
42
|
+
│ └── return 1 [0.0000s]
|
|
43
|
+
└── return 2 [0.0008s]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
| Feature | Description |
|
|
51
|
+
|---|---|
|
|
52
|
+
| 🌳 **Call Trees** | Nested, indented tree visualization for every function call |
|
|
53
|
+
| ⏱️ **Execution Time** | Per-call timing with `[0.0042s]` annotations |
|
|
54
|
+
| 📐 **Truncation** | Smart character-limit truncation for large arguments and returns |
|
|
55
|
+
| 💥 **Exception Tracing** | Captures and renders exceptions inline in the call tree |
|
|
56
|
+
| 🔁 **Async Support** | Safely traces `async`/`await` functions and `asyncio.gather` |
|
|
57
|
+
| 🔒 **Depth Limiting** | Cap tracing depth with `max_depth` to reduce noise |
|
|
58
|
+
| 📁 **File Export** | Redirect trace output to a file instead of the console |
|
|
59
|
+
| 🔇 **Global Toggle** | `traceflow.disable()` / `traceflow.enable()` to control all tracing at runtime |
|
|
60
|
+
| 🔬 **Variable Tracking** | `track_vars=True` to log every local variable assignment inside a function |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Clone the repo
|
|
68
|
+
git clone https://github.com/Firestar3/TraceFlow.git
|
|
69
|
+
cd TraceFlow
|
|
70
|
+
|
|
71
|
+
# Install locally
|
|
72
|
+
pip install .
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or simply drop the `traceflow/` folder into your project — no dependencies required.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Quick Start
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from traceflow import watch
|
|
83
|
+
|
|
84
|
+
@watch()
|
|
85
|
+
def fibonacci(n):
|
|
86
|
+
if n <= 1:
|
|
87
|
+
return n
|
|
88
|
+
return fibonacci(n - 1) + fibonacci(n - 2)
|
|
89
|
+
|
|
90
|
+
fibonacci(3)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Output:**
|
|
94
|
+
```
|
|
95
|
+
fibonacci(3)
|
|
96
|
+
├── fibonacci(2)
|
|
97
|
+
│ ├── fibonacci(1)
|
|
98
|
+
│ │ └── return 1 [0.0003s]
|
|
99
|
+
│ ├── fibonacci(0)
|
|
100
|
+
│ │ └── return 0 [0.0000s]
|
|
101
|
+
│ └── return 1 [0.0006s]
|
|
102
|
+
├── fibonacci(1)
|
|
103
|
+
│ └── return 1 [0.0000s]
|
|
104
|
+
└── return 2 [0.0008s]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Feature Guide
|
|
110
|
+
|
|
111
|
+
### 1. Execution Time Tracking
|
|
112
|
+
|
|
113
|
+
Every traced call automatically measures wall-clock time.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from traceflow import watch
|
|
117
|
+
import time
|
|
118
|
+
|
|
119
|
+
@watch(track_time=True)
|
|
120
|
+
def slow_add(a, b):
|
|
121
|
+
time.sleep(0.05)
|
|
122
|
+
return a + b
|
|
123
|
+
|
|
124
|
+
slow_add(10, 20)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
slow_add(10, 20)
|
|
129
|
+
└── return 30 [0.0502s]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Set `track_time=False` to disable timing:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
@watch(track_time=False)
|
|
136
|
+
def add(a, b):
|
|
137
|
+
return a + b
|
|
138
|
+
|
|
139
|
+
add(1, 2)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
add(1, 2)
|
|
144
|
+
└── return 3
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### 2. Argument & Return Truncation
|
|
150
|
+
|
|
151
|
+
Prevent massive data structures from flooding your console with `truncate_len`.
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
@watch(truncate_len=30)
|
|
155
|
+
def process(data):
|
|
156
|
+
return [x * 2 for x in data]
|
|
157
|
+
|
|
158
|
+
process(list(range(50)))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
process([0, 1, 2, 3, 4, 5, 6, 7, 8,...)
|
|
163
|
+
└── return [0, 2, 4, 6, 8, 10, 12, 14,... [0.0000s]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The character limit applies to both arguments and return values. Set `truncate_len=None` or `truncate_len=0` to disable truncation entirely.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 3. Exception Tracing
|
|
171
|
+
|
|
172
|
+
Exceptions are captured, rendered in the tree, and re-raised — so your error handling works normally while you get full visibility.
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
@watch()
|
|
176
|
+
def divide(a, b):
|
|
177
|
+
return a / b
|
|
178
|
+
|
|
179
|
+
@watch()
|
|
180
|
+
def safe_math(x, y):
|
|
181
|
+
return divide(x, y)
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
safe_math(10, 0)
|
|
185
|
+
except ZeroDivisionError:
|
|
186
|
+
pass
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
safe_math(10, 0)
|
|
191
|
+
├── divide(10, 0)
|
|
192
|
+
│ └── ZeroDivisionError: division by zero [0.0000s]
|
|
193
|
+
└── ZeroDivisionError: division by zero [0.0000s]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The exception propagates through each level of the call tree, showing exactly where it originated and how it bubbled up.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### 4. Max Depth Limiting
|
|
201
|
+
|
|
202
|
+
Reduce noise in deeply recursive functions by capping the trace depth.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
@watch(max_depth=2)
|
|
206
|
+
def deep_fib(n):
|
|
207
|
+
if n <= 1:
|
|
208
|
+
return n
|
|
209
|
+
return deep_fib(n - 1) + deep_fib(n - 2)
|
|
210
|
+
|
|
211
|
+
deep_fib(4)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
deep_fib(4)
|
|
216
|
+
├── deep_fib(3)
|
|
217
|
+
│ └── return 2 [0.0000s]
|
|
218
|
+
├── deep_fib(2)
|
|
219
|
+
│ └── return 1 [0.0000s]
|
|
220
|
+
└── return 3 [0.0000s]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Calls beyond `max_depth` still execute normally — they just aren't traced.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### 5. Async Function Support
|
|
228
|
+
|
|
229
|
+
TraceFlow natively supports `async` functions. Concurrent tasks from `asyncio.gather` are traced cleanly.
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
import asyncio
|
|
233
|
+
from traceflow import watch
|
|
234
|
+
|
|
235
|
+
@watch()
|
|
236
|
+
async def fetch_data(id):
|
|
237
|
+
await asyncio.sleep(0.01)
|
|
238
|
+
return f"data_{id}"
|
|
239
|
+
|
|
240
|
+
@watch()
|
|
241
|
+
async def fetch_all():
|
|
242
|
+
return await asyncio.gather(fetch_data(1), fetch_data(2), fetch_data(3))
|
|
243
|
+
|
|
244
|
+
asyncio.run(fetch_all())
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
fetch_all()
|
|
249
|
+
├── fetch_data(1)
|
|
250
|
+
│ └── return 'data_1' [0.0123s]
|
|
251
|
+
├── fetch_data(2)
|
|
252
|
+
│ └── return 'data_2' [0.0123s]
|
|
253
|
+
├── fetch_data(3)
|
|
254
|
+
│ └── return 'data_3' [0.0123s]
|
|
255
|
+
└── return ['data_1', 'data_2', 'data_3'] [0.0126s]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### 6. File Export
|
|
261
|
+
|
|
262
|
+
Redirect all trace output to a text file instead of the console.
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
@watch(export_path="trace_output.txt")
|
|
266
|
+
def fibonacci(n):
|
|
267
|
+
if n <= 1:
|
|
268
|
+
return n
|
|
269
|
+
return fibonacci(n - 1) + fibonacci(n - 2)
|
|
270
|
+
|
|
271
|
+
fibonacci(3)
|
|
272
|
+
# -> Trace written to trace_output.txt
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The file is appended to, so multiple runs accumulate in the same file.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### 7. Global Enable / Disable
|
|
280
|
+
|
|
281
|
+
Turn all tracing on or off at runtime without removing decorators. Functions still execute normally when tracing is disabled — only the output is suppressed.
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
import traceflow
|
|
285
|
+
from traceflow import watch
|
|
286
|
+
|
|
287
|
+
@watch()
|
|
288
|
+
def add(a, b):
|
|
289
|
+
return a + b
|
|
290
|
+
|
|
291
|
+
add(1, 2) # Trace is printed
|
|
292
|
+
|
|
293
|
+
traceflow.disable()
|
|
294
|
+
add(3, 4) # No trace output, but returns 7 normally
|
|
295
|
+
|
|
296
|
+
traceflow.enable()
|
|
297
|
+
add(5, 6) # Trace resumes
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
add(1, 2)
|
|
302
|
+
└── return 3 [0.0000s]
|
|
303
|
+
|
|
304
|
+
add(5, 6)
|
|
305
|
+
└── return 11 [0.0000s]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Also available: `traceflow.is_enabled()` to check current state.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
### 8. Variable State Tracking
|
|
313
|
+
|
|
314
|
+
See exactly how local variables change inside a function, line by line. Parameters are captured as a baseline and not logged (they're already visible in the call signature).
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
@watch(track_vars=True)
|
|
318
|
+
def compute(x, y):
|
|
319
|
+
total = x + y
|
|
320
|
+
doubled = total * 2
|
|
321
|
+
message = f"Result: {doubled}"
|
|
322
|
+
return doubled
|
|
323
|
+
|
|
324
|
+
compute(5, 3)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
compute(5, 3)
|
|
329
|
+
│ · total = 8
|
|
330
|
+
│ · doubled = 16
|
|
331
|
+
│ · message = 'Result: 16'
|
|
332
|
+
└── return 16 [0.0002s]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Variable tracking inside a loop:
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
@watch(track_vars=True)
|
|
339
|
+
def sum_list(items):
|
|
340
|
+
total = 0
|
|
341
|
+
for val in items:
|
|
342
|
+
total += val
|
|
343
|
+
return total
|
|
344
|
+
|
|
345
|
+
sum_list([10, 20, 30])
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
sum_list([10, 20, 30])
|
|
350
|
+
│ · total = 0
|
|
351
|
+
│ · val = 10
|
|
352
|
+
│ · total = 10
|
|
353
|
+
│ · val = 20
|
|
354
|
+
│ · total = 30
|
|
355
|
+
│ · val = 30
|
|
356
|
+
│ · total = 60
|
|
357
|
+
└── return 60 [0.0001s]
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
> **Note:** Variable tracking uses `sys.settrace` and is only available for synchronous functions. It adds overhead and is best used for targeted debugging, not production code.
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
### 9. Keyword Arguments
|
|
365
|
+
|
|
366
|
+
TraceFlow displays both positional and keyword arguments.
|
|
367
|
+
|
|
368
|
+
```python
|
|
369
|
+
@watch()
|
|
370
|
+
def greet(name, greeting="Hello", punctuation="!"):
|
|
371
|
+
return f"{greeting}, {name}{punctuation}"
|
|
372
|
+
|
|
373
|
+
greet("Aarav", greeting="Hey", punctuation="!!")
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
```
|
|
377
|
+
greet('Aarav', greeting='Hey', punctuation='!!')
|
|
378
|
+
└── return 'Hey, Aarav!!' [0.0000s]
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Configuration Reference
|
|
384
|
+
|
|
385
|
+
| Parameter | Type | Default | Description |
|
|
386
|
+
|---|---|---|---|
|
|
387
|
+
| `track_time` | `bool` | `True` | Append `[0.0042s]` execution time to each return line |
|
|
388
|
+
| `truncate_len` | `int` | `50` | Max characters for argument/return repr. `0` or `None` to disable |
|
|
389
|
+
| `max_depth` | `int` | `None` | Stop tracing beyond this call depth. `None` for unlimited |
|
|
390
|
+
| `export_path` | `str` | `None` | Write trace to a file instead of stdout |
|
|
391
|
+
| `track_vars` | `bool` | `False` | Log local variable assignments inside the function (sync only) |
|
|
392
|
+
|
|
393
|
+
### Global Functions
|
|
394
|
+
|
|
395
|
+
| Function | Description |
|
|
396
|
+
|---|---|
|
|
397
|
+
| `traceflow.enable()` | Enable all tracing (default state) |
|
|
398
|
+
| `traceflow.disable()` | Disable all tracing — decorated functions still run normally |
|
|
399
|
+
| `traceflow.is_enabled()` | Returns `True` if tracing is currently active |
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Author
|
|
404
|
+
|
|
405
|
+
**Aarav Agarwal**
|
|
406
|
+
|
|
407
|
+
## License
|
|
408
|
+
|
|
409
|
+
All Rights Reserved.
|