Skip to main content

An expression tracer for debugging lambdas, list comprehensions, method chaining, and expressions

Project description

Description

PyPI - Version GitHub Actions Workflow Status

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 and name callback.
  • Display Result method with allow, before and after callbacks.

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 expression if the generated output has the text 10
d__([c__(x) for x in ['10', '20']], before=lambda data: '10' in data['output__'])

# Display expression 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 "")

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}`',
    '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 executed
  • allow_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 for after callback.
  • output__: Text passed to before without new_line.
  • name: name parameter

Documentation

Package Documentation

Support this Project

If you find this project useful, consider supporting it:

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

pytracetoix-1.0.0.tar.gz (7.4 kB view details)

Uploaded Source

Built Distribution

pytracetoix-1.0.0-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file pytracetoix-1.0.0.tar.gz.

File metadata

  • Download URL: pytracetoix-1.0.0.tar.gz
  • Upload date:
  • Size: 7.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.3

File hashes

Hashes for pytracetoix-1.0.0.tar.gz
Algorithm Hash digest
SHA256 09754af6bc30618c2fe2c5273e70e64cf8f34f9275d1abfa689ce463285d0c71
MD5 de7b74e9417e8ea626700b532510f035
BLAKE2b-256 d07747b8b01b4454296fd78ea9a0704cf5f4cb2c837b204509eddb04343b17a5

See more details on using hashes here.

File details

Details for the file pytracetoix-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pytracetoix-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.3

File hashes

Hashes for pytracetoix-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3078d5c3a6a24a6ac9ae2bbefd6dc26c7b1045dfb27d6ccb86c946f5202fc839
MD5 f3632a49f52ddb35d52589b3202aa429
BLAKE2b-256 100ca9ac613e53d2e3d2619016488709767095c91b46751b896894291eaefa27

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page