An expression tracer for debugging lambdas, list comprehensions, method chaining, and expressions
Project description
Description
PyTraceToIX is an expression tracer for debugging lambdas, list comprehensions, method chaining, and expressions.
Code editors can't set breakpoints inside expressions, lambda functions, list comprehensions, and chained methods, forcing significant code changes to debug such code.
PyTraceToIX provides a straightforward solution to this problem.
It was designed to be simple, with easily identifiable functions that can be removed once the bug is found.
PyTraceToIX has 2 major functions:
c__
capture the input of an expression input. ex:c__(x)
d__
display the result of an expression and all the captured inputs. ex:d__(c__(x) + c__(y))
And 2 optional functions:
init__
initializes display format, output stream and multithreading.t__
defines a name for the current thread.
If you find this project useful, please, read the Support this Project on how to contribute.
Features
- Multithreading support.
- Simple and short minimalist function names.
- Result with Inputs tracing.
- Configurable formatting at global level and at function level.
- Configurable result and input naming.
- Output to the stdout or a stream.
- Multiple levels.
- Capture Input method with
allow
andname
callback. - Display Result method with
allow
,before
andafter
callbacks. - Input and Result output can be formatted and overridden.
Installation
pip install pytracetoix
Usage
from pytracetoix import d__, c__
[x, y, w, k, u] = [1, 2, 3, 4 + 4, lambda x:x]
# expression
z = x + y * w + (k * u(5))
# Display expression with no inputs
z = d__(x + y * w + (k * u(5)))
# Output:
# _:`47`
# Display expression result with inputs
z = d__(c__(x) + y * c__(w) + (k * u(5)))
# Output:
# i0:`1` | i1:`3` | _:`47`
# Display expression result with inputs within an expression
z = d__(c__(x) + y * c__(w) + d__(k * c__(u(5), level=1)))
# Output:
# i0:`5` | _:`40`
# i0:`1` | i1:`3` | _:`47`
# lambda function
f = lambda x, y: x + (y + 1)
f(5, 6)
# Display lambda function result and inputs
f = lambda x, y: d__(c__(x) + c__(y + 1))
f(5, 6)
# Output:
# i0:`5` | i1:`7` | _:`12`
# Display lambda function inputs and result with input and result names
f = lambda x, y: d__(c__(x, name='x') + c__(y + 1, name='y+1'), name='f')
f(5, 6)
# Output:
# x:`5` | y+1:`7` | f:`12`
# list comprehension
l = [5 * y * x for x, y in [(10, 20), (30, 40)]]
# Display list comprehension with input and result names
l = d__([5 * c__(y, name=f"y{y}") * c__(x, name=lambda index, _, __: f'v{index}') for x, y in [(10, 20), (30, 40)]])
# Output:
# y20:`20` | v1:`10` | y40:`40` | v3:`30` | _:`[1000, 6000]`
# Display expression if `input count` is 2
d__(c__(x) + c__(y), allow=lambda data: data['input_count__'] == 2)
# Display expression if the first input value is 10.0
d__(c__(x) + c__(y), allow=lambda data: data['i0'] == 10.0)
# Display expression if the `allow_input_count` is 2, in this case if `x > 10`
d__(c__(x, allow=lambda index, name, value: value > 10) + c__(y),
allow=lambda data: data['allow_input_count__'] == 2)
# Display list comprehension if the generated output has the text 10
d__([c__(x) for x in ['10', '20']], before=lambda data: '10' in data['output__'])
# Display list comprehension and after call `call_after` if it was allowed to display
d__([c__(x) for x in ['10', '20']], allow=lambda data: data['allow_input_count__'] == 2,
after=lambda data: call_after(data) if data['allow__'] else "")
# Display list comprehension with allow input override
d__([c__(x, allow=lambda index, name, value:value[0]) \
for x in [('10', '20'), ('30', '40'), ('50', '60')]])
# i0:`10` | i1:`30` | i2:`50` | _:`[('10', '20'), ('30', '40'), ('50', '60')]`
# Display list comprehension with allow result override
d__([c__(x) for x in [('10', '20'), ('30', '40'), ('50', '60')]], \
allow=lambda data:data['_'][0:2])
# i0:`('10', '20')` | i1:`('30', '40')` | i2:`('50', '60')` | _:`[('10', '20'), ('30', '40')]`
class Chain:
def __init__(self, data):
self.data = data
def map(self, func):
self.data = list(map(func, self.data))
return self
def filter(self, func):
self.data = list(filter(func, self.data))
return self
# A class with chain methods
Chain([10, 20, 30, 40, 50]).map(lambda x: x * 2).filter(lambda x: x > 70)
# Display the result and capture the map and filter inputs
d__(Chain([10, 20, 30, 40, 50]).map(lambda x: c__(x * 2)).filter(lambda x: c__(x > 70)).data)
# Output:
# i0:`20` | i1:`40` | i2:`60` | i3:`80` | i4:`100` | i5:`False` | i6:`False` | i7:`False` | i8:`True` | i9:`True` | _:`[80, 100]`
Formatting
The d__
function can override the default formatting, and it can also be defined at global level.
from pytracetoix import init__
init__(format={
'result': '{name}:`{value}`',
'input': '{name}:`{value}`',
'thread': '{id}: ',
'sep': ' | ',
'new_line': True
})
Formatting parameters:
result
: The result value format will be displayed.input
: The result value format will be displayed.sep
: The separator text between each input and the result.new_line
: If True it will add a new line at the end of output.
Multithreading
To activate the multithreading support:
from pytracetoix import d__, c__, t__, init__
init__(multithreading=True)
## It displays the threadId: i0: `4` | _: `5`
def thread_function():
d__(c__(4) + 1)
## It displays the something: i0: `4` | _: `5`
def thread_function_with_name():
t__("something")
d__(c__(4) + 1)
threads = []
for _ in range(5):
thread = threading.Thread(target=thread_function)
threads.append(thread)
threads.append(threading.Thread(target=thread_function_with_name))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
Metadata
The allow
, before
and after
will receive a parameter data
with the allowed inputs plus the following meta
items:
meta__
: list of meta keys including the name key.thread_id__
: thread_id being executedallow_input_count__
: total number of inputs that are allowed.input_count__
: total number of inputs being captured.allow__
: If false it was allowed. Use this forafter
callback.output__
: Text passed tobefore
withoutnew_line
.- name: name parameter
Documentation
Support this Project
If you find this project useful, consider supporting it:
- Donate:
License
MIT License
Copyrights
(c) 2024 Alexandre Bento Freire
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file pytracetoix-1.1.0.tar.gz
.
File metadata
- Download URL: pytracetoix-1.1.0.tar.gz
- Upload date:
- Size: 7.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9cba73f9ac7042ea01bc4d054ce2e28d73a05d29731df44b796d449e6f47d3ef |
|
MD5 | b4d70b4e98ba498c13521c90ae8db476 |
|
BLAKE2b-256 | 47ae51d13c7a138b2fc84a79842944eae25a4a614ba1f8e99d27a22a27485f7a |
File details
Details for the file PyTraceToIX-1.1.0-py3-none-any.whl
.
File metadata
- Download URL: PyTraceToIX-1.1.0-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ca470ce54139d5d99fe4d5e8fde65d62dcf09cdec5be6fba192a151eeb8a1846 |
|
MD5 | 6fcbafc17001b701ae2a82888a83a294 |
|
BLAKE2b-256 | 9948af24c3cf3e0c478c44453d5926e1ee66ff2832d02f1da51ddd4a8f26368b |