Skip to main content

Create documentation of your function call stack from their docstrings

Project description

docstringer

A simple decorator to create documentation of your function calls from their docstrings

Scope

What package does?

This utility allows you to add a simple @docstringer decorator to any function calls you wish to document when you are running your code. This will then track the calls to these functions and output documentation of the call-stack flow.

This utility is focused on documentation of the call stack of functions and uses the function doc strings to document the call order.

What package does not do?

This function is purely focused on documenting the call order, the call parameters and the return values and using the docstrings to make this auto documentation.

This package does not intermediate values tracked at each stage within functions. There are many great packages already available to do this such as snoop.

This package also does not profile the time taken to run each function in the call stack. There are many great packages already available to do this such as profiling.

Quickstart

Install the package using:

pip install docstringer

On any function in your code that you wish to document the calling order, add the @docstringer decorator. By default the docstringer package will print the output.

An example

We have a simple program that rolls a number of dice and returns the result.

We decorate the functions we want to document function calls to using the @docstringer decorator.

@docstringer
def roll_the_dice(rolls: int, sides: int = 6) -> tuple:
    """
    Rolls a number of dice and returns the result.
    """
    results = []
    for _ in range(rolls):
        results.append(roll(sides))

    return (sum(results), results)

@docstringer
def roll(sides: int = 6) -> int:
    """
    An individual die (of side count=sides) roll.
    """
    return random.randint(1, sides)

An example output from running this code:

CALL to roll_the_dice (id=4441740768)
with {'args': (), 'kwargs': {'rolls': 2, 'sides': 6}}

    Rolls a number of dice and returns the result.

CALL to roll (id=4442233152)
with {'args': (6,), 'kwargs': {}}

    An individual die (of side count=sides) roll.

RETURN from roll (id=4442233152
result = 5

CALL to roll (id=4442233152)
with {'args': (6,), 'kwargs': {}}

    An individual die (of side count=sides) roll.

RETURN from roll (id=4442233152
result = 3

RETURN from roll_the_dice (id=4441740768
result = (8, [5, 3])

Deactivating docstringer in production

By default docstringer is active and will log the call stack on the decorated functions. When using in production you will want to switch this off. This will also speed up running.

To switch off the @docstringer decorator without removing it, pass the active=False parameter to the decorator. This can be done globally using a configuration. For example:

DEBUG = False  # Set to True in debug mode when decorator should be active\

@docstringer(active=DEBUG)
def my_function():
    """ My function to be documented when it is called """
    ...

Different output formats

Different Formatters can be used to push the output in different formats by passing an instance of the Formatter you want to the DOCSTRINGER_FORMATTER variable.

By default docstringer outputs the function call information as print statements to the console. This default formatter is the PrintFormatter

You can set a different formatter by passing this to the formatter parameter in the docstring. The built in formatters are outlined below. Or you can customise your own

from docstringer.formatters import LoggerFormatter

formatter = LoggerFormatter(logger=logger, log_level='info')

@docstringer(formatter=formatter)
def my_function():
    """ My function to be documented when it is called """
    ...

LoggerFormatter

This formatter outputs the function call information to the logger of your choice instead of printing to the screen. When instantiating the LoggerFormatter, pass it the logger and log=level you want to use:

from docstringer.formatters import LoggerFormatter
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s - %(message)s")

@docstringer(formatter=LoggerFormatter(logger=logging, log_level='info')
def my_function():
    ...

This will now output function calls as log items.

EventListFormatter

The EventListFormatter will return the function call information a a list of FunctionEvent objects. These objects contain the name, docstring, call values and return values of each function call in the order that they were called.

This formatter is passed a list (usually an empty list) when it is instantiated and it will populate this list with the FunctionEvent objects that occur on decorated functions.

from docstringer.formatters import EventListFormatter

event_list = []

@docstringer(formatter=EventListFormatter(event_list))
def my_function():
    ...

Combining with other tracing or introspection packages

This package focuses on documenting the call stack and showing the docstring for the decorated functions.

This can be combined with a more detailed tracing or profiling package to give a combined output. We recommend that the tracing decorator is placed inside the docstringer decorator.

Example combining with snoop

In this example we use the PrintSimpleFormatter which does not show the parameters and return values as these are already provided by snoop. We also configure snoop to print in a similar format

import snoop
from docstringer import docstringer

snoop_formatted = snoop.Config(color=False, prefix="", columns=[]).snoop

@docstringer(formatter=PrintSimpleFormatter())
@snoop_formatted
def roll(sides: int = 6) -> int:
    """
    An individual die (of side count=sides) roll.
    """
    return random.randint(1, sides)

The output contains both the snoop and docstringer outputs:

...

CALL to roll (id=4343471264)

    An individual die roll.

    Parameters:
    - sides (int) - the number of sides on the dice (default = 6)

    Returns:
    - the value of the die roll


>>> Call to roll in File "/Users/matt/Projects/docstringer/demo.py", line 50
...... sides = 6
50 | def roll(sides: int = 6) -> int:
60 |     return random.randint(1, sides)
<<< Return value from roll: 1

...

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

docstringer-0.1.1.tar.gz (6.6 kB view hashes)

Uploaded Source

Built Distribution

docstringer-0.1.1-py3-none-any.whl (6.2 kB view hashes)

Uploaded Python 3

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