# pytracecall
[](https://pypi.org/project/pytracecall/)
[](https://pypi.org/project/pytracecall/)
[](https://pypi.org/project/pytracecall/)
[](https://coveralls.io/github/alexsemenyaka/calltracer?branch=main)
[](https://github.com/alexsemenyaka/calltracer/actions/workflows/ci.yml)
# Python Call Tracer Module
A debugging module with decorators (`CallTracer`, `aCallTracer`) and a function (`stack`) for tracing function calls and logging the call stack.
This module provides simple yet powerful tools to help you understand your code's execution flow without the need for a full step-by-step debugger. It is designed to integrate seamlessly with Python's standard `logging` module.
***
## Features
- **Synchronous and Asynchronous Tracing**: Decorators for both standard (`def`) and asynchronous (`async def`) functions.
- **Concurrency Safe**: The async tracer (`aCallTracer`) uses `contextvars` to safely trace concurrent tasks without mixing up logs.
- **Data Flow Visibility**: Logs function arguments and return values.
- **Recursion Visualization**: Automatically indents log messages to clearly show recursion depth, even in concurrent contexts.
- **Stack Inspection**: Use the `stack()` function to log the current call stack at any point in your code.
- **Logging Integration**: Works with the standard `logging` module.
***
## Installation
You can install the package from the Python Package Index (PyPI) using **`pip`**.
```bash
pip install pytracecall
```
To ensure you have the latest version, you can use the `--upgrade` flag:
```bash
pip install --upgrade pytracecall
```
***
## Synchronous Usage
First, ensure you configure Python's `logging` module to see the output.
### Basic Configuration
```python
import logging
# Configure logging to display DEBUG level messages
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%H:%M:%S'
)
```
### Basic Tracing
Use the `CallTracer` instance as a decorator to trace a synchronous function.
```python
from calltracer import CallTracer
trace = CallTracer()
@trace
def add(x, y):
return x + y
add(10, 5)
```
**Output:**
```
21:15:10 - DEBUG - --> Calling add(10, 5)
21:15:10 - DEBUG - <-- Exiting add, returned: 15
```
***
## Asynchronous Usage
The `aCallTracer` decorator is designed specifically for `async def` functions and is safe for concurrent execution.
### Async Example
```python
import asyncio
import logging
from calltracer import aCallTracer, stack
# Basic logging configuration (can be done once)
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%H:%M:%S",
)
# Create an instance of the ASYNCHRONOUS tracer
async_trace = aCallTracer(level=logging.DEBUG)
class AsyncDataFetcher:
@async_trace
async def process_item(self, item_id: str, delay: float):
await asyncio.sleep(delay)
return f"Processed {item_id}"
async def main():
fetcher = AsyncDataFetcher()
print("\n--- Running two tasks concurrently to show task-safety ---")
results = await asyncio.gather(
fetcher.process_item(item_id="A", delay=0.2),
fetcher.process_item(item_id="B", delay=0.1),
)
logging.info("Concurrent results: %s", results)
if __name__ == "__main__":
asyncio.run(main())
```
### Example Output (Async)
Note how the logs from Task A and B are interleaved, but the indentation remains correct for each independent task.
```
--- Running two tasks concurrently to show task-safety ---
22:01:05 - calltracer.async_tracer - DEBUG - --> Calling AsyncDataFetcher.process_item(<...>, item_id='A', delay=0.2)
22:01:05 - calltracer.async_tracer - DEBUG - --> Calling AsyncDataFetcher.process_item(<...>, item_id='B', delay=0.1)
22:01:05 - calltracer.async_tracer - DEBUG - <-- Exiting AsyncDataFetcher.process_item, returned: 'Processed B'
22:01:05 - calltracer.async_tracer - DEBUG - <-- Exiting AsyncDataFetcher.process_item, returned: 'Processed A'
22:01:05 - root - INFO - Concurrent results: ['Processed A', 'Processed B']
```
***
## API Reference
### `CallTracer` Class (Synchronous)
A factory for creating decorators that trace synchronous (`def`) function/method calls.
#### Initialization
```python
from calltracer import CallTracer
trace = CallTracer(level=logging.INFO)
```
### `aCallTracer` Class (Asynchronous)
A factory for creating decorators that trace asynchronous (`async def`) function/method calls. This tracer is task-safe for concurrent code using `contextvars`.
#### Initialization
```python
from calltracer import aCallTracer
async_trace = aCallTracer(level=logging.INFO)
```
**Parameters for both classes:**
- **`level`** (`int`, optional): The logging level for trace messages. Defaults to `logging.DEBUG`.
- **`trace_chain`** (`bool`, optional): If True, accumulates and logs the call chain. Default to False.
- **`logger`** (`logging.Logger`, optional): The logger instance to use. Defaults to the internal module logger.
### `stack()` Function
Logs the current call stack to the specified logger. This function works in both synchronous and asynchronous code.
#### Signature
```python
stack(level=logging.DEBUG, logger=None, limit=None, start=0)
```
- **`level`** (`int`, optional): The logging level for the message. Defaults to `logging.DEBUG`.
- **`logger`** (`logging.Logger`, optional): The logger instance to use. Defaults to the internal module logger.
- **`limit`** (`int`, optional): The maximum number of frames to display. Defaults to `None` (all frames).
- **`start`** (`int`, optional): The offset of the first frame to display. Defaults to `0`.
Raw data
{
"_id": null,
"home_page": null,
"name": "pytracecall",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "debug, debugging, trace, tracer, decorator, logging, stacktrace, callstack, inspect, recursion",
"author": null,
"author_email": "Alex Semenyaka <alex.semenyaka@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/61/4b/670df9fa923741ec6e690bc2027572aa7f0f9c4a25b5c8ecdf3df4ba52d2/pytracecall-3.0.2.tar.gz",
"platform": null,
"description": "# pytracecall\n[](https://pypi.org/project/pytracecall/)\n[](https://pypi.org/project/pytracecall/)\n[](https://pypi.org/project/pytracecall/)\n[](https://coveralls.io/github/alexsemenyaka/calltracer?branch=main)\n[](https://github.com/alexsemenyaka/calltracer/actions/workflows/ci.yml)\n\n# Python Call Tracer Module\n\nA debugging module with decorators (`CallTracer`, `aCallTracer`) and a function (`stack`) for tracing function calls and logging the call stack.\n\nThis module provides simple yet powerful tools to help you understand your code's execution flow without the need for a full step-by-step debugger. It is designed to integrate seamlessly with Python's standard `logging` module.\n\n***\n\n## Features\n\n- **Synchronous and Asynchronous Tracing**: Decorators for both standard (`def`) and asynchronous (`async def`) functions.\n- **Concurrency Safe**: The async tracer (`aCallTracer`) uses `contextvars` to safely trace concurrent tasks without mixing up logs.\n- **Data Flow Visibility**: Logs function arguments and return values.\n- **Recursion Visualization**: Automatically indents log messages to clearly show recursion depth, even in concurrent contexts.\n- **Stack Inspection**: Use the `stack()` function to log the current call stack at any point in your code.\n- **Logging Integration**: Works with the standard `logging` module.\n\n***\n\n## Installation\n\nYou can install the package from the Python Package Index (PyPI) using **`pip`**.\n\n```bash\npip install pytracecall\n```\n\nTo ensure you have the latest version, you can use the `--upgrade` flag:\n\n```bash\npip install --upgrade pytracecall\n```\n\n***\n\n## Synchronous Usage\n\nFirst, ensure you configure Python's `logging` module to see the output.\n\n### Basic Configuration\n\n```python\nimport logging\n\n# Configure logging to display DEBUG level messages\nlogging.basicConfig(\n level=logging.DEBUG,\n format='%(asctime)s - %(levelname)s - %(message)s',\n datefmt='%H:%M:%S'\n)\n```\n\n### Basic Tracing\n\nUse the `CallTracer` instance as a decorator to trace a synchronous function.\n\n```python\nfrom calltracer import CallTracer\n\ntrace = CallTracer()\n\n@trace\ndef add(x, y):\n return x + y\n\nadd(10, 5)\n```\n\n**Output:**\n\n```\n21:15:10 - DEBUG - --> Calling add(10, 5)\n21:15:10 - DEBUG - <-- Exiting add, returned: 15\n```\n\n***\n\n## Asynchronous Usage\n\nThe `aCallTracer` decorator is designed specifically for `async def` functions and is safe for concurrent execution.\n\n### Async Example\n\n```python\nimport asyncio\nimport logging\nfrom calltracer import aCallTracer, stack\n\n# Basic logging configuration (can be done once)\nlogging.basicConfig(\n level=logging.DEBUG,\n format=\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\",\n datefmt=\"%H:%M:%S\",\n)\n\n# Create an instance of the ASYNCHRONOUS tracer\nasync_trace = aCallTracer(level=logging.DEBUG)\n\nclass AsyncDataFetcher:\n @async_trace\n async def process_item(self, item_id: str, delay: float):\n await asyncio.sleep(delay)\n return f\"Processed {item_id}\"\n\nasync def main():\n fetcher = AsyncDataFetcher()\n print(\"\\n--- Running two tasks concurrently to show task-safety ---\")\n results = await asyncio.gather(\n fetcher.process_item(item_id=\"A\", delay=0.2),\n fetcher.process_item(item_id=\"B\", delay=0.1),\n )\n logging.info(\"Concurrent results: %s\", results)\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Example Output (Async)\n\nNote how the logs from Task A and B are interleaved, but the indentation remains correct for each independent task.\n\n```\n--- Running two tasks concurrently to show task-safety ---\n22:01:05 - calltracer.async_tracer - DEBUG - --> Calling AsyncDataFetcher.process_item(<...>, item_id='A', delay=0.2)\n22:01:05 - calltracer.async_tracer - DEBUG - --> Calling AsyncDataFetcher.process_item(<...>, item_id='B', delay=0.1)\n22:01:05 - calltracer.async_tracer - DEBUG - <-- Exiting AsyncDataFetcher.process_item, returned: 'Processed B'\n22:01:05 - calltracer.async_tracer - DEBUG - <-- Exiting AsyncDataFetcher.process_item, returned: 'Processed A'\n22:01:05 - root - INFO - Concurrent results: ['Processed A', 'Processed B']\n```\n\n***\n\n## API Reference\n\n### `CallTracer` Class (Synchronous)\n\nA factory for creating decorators that trace synchronous (`def`) function/method calls.\n\n#### Initialization\n\n```python\nfrom calltracer import CallTracer\ntrace = CallTracer(level=logging.INFO)\n```\n\n### `aCallTracer` Class (Asynchronous)\n\nA factory for creating decorators that trace asynchronous (`async def`) function/method calls. This tracer is task-safe for concurrent code using `contextvars`.\n\n#### Initialization\n\n```python\nfrom calltracer import aCallTracer\nasync_trace = aCallTracer(level=logging.INFO)\n```\n\n**Parameters for both classes:**\n\n- **`level`** (`int`, optional): The logging level for trace messages. Defaults to `logging.DEBUG`.\n- **`trace_chain`** (`bool`, optional): If True, accumulates and logs the call chain. Default to False.\n- **`logger`** (`logging.Logger`, optional): The logger instance to use. Defaults to the internal module logger.\n\n### `stack()` Function\n\nLogs the current call stack to the specified logger. This function works in both synchronous and asynchronous code.\n\n#### Signature\n\n```python\nstack(level=logging.DEBUG, logger=None, limit=None, start=0)\n```\n\n- **`level`** (`int`, optional): The logging level for the message. Defaults to `logging.DEBUG`.\n- **`logger`** (`logging.Logger`, optional): The logger instance to use. Defaults to the internal module logger.\n- **`limit`** (`int`, optional): The maximum number of frames to display. Defaults to `None` (all frames).\n- **`start`** (`int`, optional): The offset of the first frame to display. Defaults to `0`.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "pytracecall: A debugging module with sync and async decorators (CallTracer and aCallTracer) for tracing function calls, and a function (stack) for logging the current call stack",
"version": "3.0.2",
"project_urls": null,
"split_keywords": [
"debug",
" debugging",
" trace",
" tracer",
" decorator",
" logging",
" stacktrace",
" callstack",
" inspect",
" recursion"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "62bc5803c37cde6d71ed561e034df985c339787ac2820cfc97bfebf9a8887332",
"md5": "73056db9c30be9dddc257a42c16b7677",
"sha256": "07ea8a84719849acb7efbad590f2b096b2a82cda55194b100465b980a0695685"
},
"downloads": -1,
"filename": "pytracecall-3.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "73056db9c30be9dddc257a42c16b7677",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 11927,
"upload_time": "2025-08-03T00:44:28",
"upload_time_iso_8601": "2025-08-03T00:44:28.789215Z",
"url": "https://files.pythonhosted.org/packages/62/bc/5803c37cde6d71ed561e034df985c339787ac2820cfc97bfebf9a8887332/pytracecall-3.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "614b670df9fa923741ec6e690bc2027572aa7f0f9c4a25b5c8ecdf3df4ba52d2",
"md5": "db5c8aa09cb79aa02b8341f5fa6a3bcf",
"sha256": "50fed4401185f2ea5c397b83dac02afc7779e95556afbedaade3cd1755483a87"
},
"downloads": -1,
"filename": "pytracecall-3.0.2.tar.gz",
"has_sig": false,
"md5_digest": "db5c8aa09cb79aa02b8341f5fa6a3bcf",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 11373,
"upload_time": "2025-08-03T00:44:29",
"upload_time_iso_8601": "2025-08-03T00:44:29.929969Z",
"url": "https://files.pythonhosted.org/packages/61/4b/670df9fa923741ec6e690bc2027572aa7f0f9c4a25b5c8ecdf3df4ba52d2/pytracecall-3.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-03 00:44:29",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "pytracecall"
}