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.0.tar.gz (12.7 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.0-py3-none-any.whl (9.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pyfollow-0.1.0.tar.gz
  • Upload date:
  • Size: 12.7 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.0.tar.gz
Algorithm Hash digest
SHA256 474cd0a109facc91dac12f213f73159974af5e916fd55f0734e56d6c9423f044
MD5 668d42f9f1c273e5964f8e1b7ce76910
BLAKE2b-256 e7c475d81501b00114fbba37cd635be9f1ce6fe0b1150e3ca48cd365d778bb52

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfollow-0.1.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: pyfollow-0.1.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b42e064d416ed3f79ef10795858adc6c160b6aea18ece8fd7eaf51d56a8786cb
MD5 d20825805fa892af653069a155873476
BLAKE2b-256 2801ab912c48d9b87ea2c37683beb7a68e34cbf4331b805b4b0e44a496d00a2e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyfollow-0.1.0-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