Skip to main content

Lightweight Python tracing utility — trace function calls, variables, expressions, and code blocks via console and webhook

Project description

pyfollow

PyPI version Python License: MIT

Lightweight Python tracing utility. Trace function calls, variables, expressions, and code blocks — output to console, webhook, or both.

Zero dependencies. Pure stdlib.



Installation

pip install pyfollow

Or copy the pyfollow/ directory into your project.

from pyfollow import follow

Quick Start

Console tracing

from pyfollow import follow

t = follow.init()

@t.function
def add(a, b):
    return a + b

x = 1
t.var(x)

x = x + 5
r = add(3, 7)

t.flush()

Output:

[pyfollow.function] add:
[pyfollow.function] call add(a=3, b=7)
[pyfollow.var] x = 1
[pyfollow.var] x change: 6 [changed from 1]
[pyfollow.function] add -> 10

Webhook tracing

from pyfollow import follow

t = follow.init({"webhook_url": "http://localhost:8000/webhook"})

@t.function(usecode="batch1")
def compute(n):
    return n * 2

compute(5)
t.sync("batch1")
t.flush()

Variable watching

from pyfollow import follow

t = follow.init()

x = 10
t.var(x)          # trace init: x = 10

x = 20            # auto-detect: x changed from 10 to 20

print(repr(x))    # auto-detect: x read

t.unvar("x")      # stop watching

Block tracing

from pyfollow import follow

t = follow.init()

with t:
    a = 42
    b = a + 1
    print(b)

Expression tracing

from pyfollow import follow

t = follow.init()

t(1 + 2)          # [pyfollow] t(1 + 2) -> 3
t(sorted([3,1,2])) # [pyfollow] t(sorted([3,1,2])) -> [1, 2, 3]

API Reference

follow.init(config=None)

Create a new Follow instance.

t = follow.init()                                        # default
t = follow.init({"webhook_url": "http://...", "uselogs": False})

t.config(**kwargs)

Update configuration at runtime.

t.config(uselogs=False)
t.config(webhook_url="http://localhost:8000/webhook")

@t.function

Decorator that traces function calls and returns.

@t.function
def my_func(x):
    return x + 1

@t.function(usecode="tag")

Decorator with deferred sync — events are buffered under a tag until t.sync("tag") is called.

@t.function(usecode="batch1")
def compute(n):
    return n * 2

compute(5)         # buffered, not sent
t.sync("batch1")   # flush only batch1 events

t.var(value, name=None)

Watch a variable. Detects init, changes, and reads (via repr()/str()).

x = 1
t.var(x)    # log: x = 1
x = 2       # log: x changed from 1 to 2

t.unvar(name)

Stop watching a variable.

t.unvar("x")

t(expr)

Trace an expression — logs the source code line and its result.

t(1 + 2)    # log: t(1 + 2) -> 3

with t:

Context manager that traces every line inside the block.

with t:
    x = 1
    y = x + 1

t.sync(code=None)

Flush buffered events to webhook.

  • t.sync() — flush all untagged events
  • t.sync("tag") — flush only events with matching tag

t.flush()

Block until all pending webhook sends complete.


Configuration

Key Type Default Description
webhook_url str None URL for HTTP POST event delivery
uselogs bool True Print trace events to console
# Console only (default)
t = follow.init()

# Webhook only
t = follow.init({"webhook_url": "http://localhost:8000/webhook", "uselogs": False})

# Both
t = follow.init({"webhook_url": "http://localhost:8000/webhook"})

Webhook

Event types

type Trigger
var_init t.var(x) called
var (change) Variable reassigned
var (read) Variable accessed via repr()/str()
function_call Traced function called
function_return Traced function returned
block_start with t: entered
block_line Line executed inside block
block_end with t: exited
expression t(expr) evaluated

Event payload example

{
  "type": "function_call",
  "name": "add",
  "args": "a=2, b=3",
  "source": "def add(a, b):\n    return a + b"
}

Server example (FastAPI)

cd examples/server
uvicorn main:app --reload
# examples/server/main.py
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    events = await request.json()
    for event in events:
        print(event)
    return {"status": "ok"}

Client example

python examples/webhook_client.py

Project Structure

trace-module-python/
├── pyproject.toml              # Build config
├── README.md                   # Documentation
├── LICENSE                     # MIT License
├── TODO.md                     # Task tracking
├── pyfollow/                   # Package
│   ├── __init__.py             # Public API + metadata
│   ├── follow.py               # Follow class (core orchestrator)
│   ├── watcher.py              # _FollowedVar proxy + VarWatcher (bytecode)
│   └── sender.py               # WebhookSender (async queue + retry)
├── tests/
│   └── test_trace.py           # 17 pytest tests
└── examples/
    ├── simple.py               # Console demo
    ├── webhook_client.py       # Webhook demo
    └── server/
        └── main.py             # FastAPI webhook receiver

Tests

pip install pytest
python -m pytest tests/ -v

How It Works

pyfollow hooks into Python's sys.settrace machinery to intercept line execution events. For variable watching, it uses dis (bytecode disassembly) to detect LOAD_FAST/LOAD_GLOBAL instructions that read watched variables.

The _FollowedVar proxy wraps values transparently — all dunder methods are forwarded to the original object, making the wrapper invisible to user code. Reads are detected when repr() or str() is called on the proxy.

Webhook delivery runs on a background daemon thread with a queue, retrying failed requests up to 2 times with 1-second backoff.


Contributing

Contributions welcome. Open an issue or submit a PR on GitHub.


Author

Rayan RavGitHub · Website


License

MIT © 2026 Rayan Rav

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

pyfollow-0.1.2.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyfollow-0.1.2-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

Details for the file pyfollow-0.1.2.tar.gz.

File metadata

  • Download URL: pyfollow-0.1.2.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyfollow-0.1.2.tar.gz
Algorithm Hash digest
SHA256 efcecc5b37df77855de0763fab847f283aa67b260628596f6b5708a8bc864825
MD5 247fc52ec9d011026e72a9aabbf349dd
BLAKE2b-256 c5457eb0ff64f41a50508f640f02a696eed46e277665ce181a6f0e614f8e7f9d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfollow-0.1.2.tar.gz:

Publisher: release.yml on RayanBO/trace-module-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyfollow-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: pyfollow-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 9.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyfollow-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0b7ea6d8374318093debceb6c0d71bd2cdddba1404ba33c0bb3bffe6706a8bde
MD5 67ea048f50c6ab9e5f840012f35bb8f1
BLAKE2b-256 7b4f0cdaac18065068b8c673dd70ceeada496488ba0a71f39eec1246924605f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfollow-0.1.2-py3-none-any.whl:

Publisher: release.yml on RayanBO/trace-module-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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