Skip to main content

Generates an invocation tree of functions calls.

Project description

Installation

Install (or upgrade) invocation_tree using pip:

pip install --upgrade invocation_tree

Additionally Graphviz needs to be installed.

Invocation Tree

The invocation_tree package is designed to help with program understanding and debugging by visualizing the tree of function invocations that occur during program execution. Here’s a simple example of how it works, we start with a = 1 and compute:

    (a - 3 + 9) * 6
import invocation_tree as ivt

def main():
    a = 1
    a = expression(a)
    return multiply(a, 6)
    
def expression(a):
    a = subtract(a, 3)
    return add(a, 9)
    
def subtract(a, b):
    return a - b

def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

tree = ivt.blocking()
print( tree(main) ) # show invocation tree starting at main

Running the program and pressing <Enter> a number of times results in: compute

42

Each node in the tree represents a function call, and the node's color indicates its state:

  • White: The function is currently being executed (it is at the top of the call stack).
  • Green: The function is paused and will resume execution later (it is lower down on the call stack).
  • Red: The function has completed execution and returned (it has been removed from the call stack).

For every function, the package displays its local variables and return value. Changes to these values over time are highlighted using bold text and gray shading to make them easy to track.

Chapters

Comprehensions

Debugger

Recursion

Configuration

Troubleshooting

Author

Bas Terwijn

Inspiration

Inspired by rcviz.

Supported by

University of Amsterdam

Comprehensions

In this more interesting example we compute which students pass a course by using list and dictionary comprehensions.

import invocation_tree as ivt
from decimal import Decimal, ROUND_HALF_UP

def main():
    students = {'Ann':[7.5, 8.0], 
                'Bob':[4.5, 6.0], 
                'Coy':[7.5, 6.0]}
    averages = {student:compute_average(grades)
                for student, grades in students.items()}
    passing = passing_students(averages)
    print(passing)

def compute_average(grades):
    average = sum(grades)/len(grades)
    return half_up_round(average, 1)
    
def half_up_round(value, digits=0):
    """ High-precision half-up rounding of 'value' to a specified number of 'digits'. """
    return float(Decimal(str(value)).quantize(Decimal(f"1e-{digits}"),
                                              rounding=ROUND_HALF_UP))

def passing_students(averages):
    return [student 
        for student, average in averages.items() 
        if average >= 5.5]

if __name__ == '__main__':
    tree = ivt.blocking()
    tree(main)

students

['Ann', 'Coy']

Blocking

The program blocks execution at every function call and return statement, printing the current location in the source code. Press the <Enter> key to continue execution. To block at every line of the program (like in a debugger tool) and only where a change of value occured, use instead:

    tree = ivt.blocking_each_change()

Debugger

To visualize the invocation tree in a debugger tool, such as the integrated debugger in Visual Studio Code, use instead:

    tree = ivt.debugger()

and open the 'tree.pdf' file manually. Visual Studio Code debugger

Recursion

An invocation tree is particularly helpful to better understand recursion. A simple factorial() example:

import invocation_tree as ivt

def factorial(n):
    if n <= 1:
        return 1
    prev_result = factorial(n - 1)
    return n * prev_result

tree = ivt.blocking()
print( tree(factorial, 4) ) # show invocation tree of calling factorial(4)

factorial

24

Permutations

This permutations() example shows the depth-first nature of recursive execution:

import invocation_tree as ivt

def permutations(elements, perm, n):
    if n==0:
        return [perm]
    all_perms = []
    for element in elements:
        all_perms.extend(permutations(elements, perm + element, n-1))
    return all_perms

tree = ivt.blocking()
result = tree(permutations, ['L','R'], '', 2)
print(result) # all permutations of going Left or Right of length 2

permutations

['LL', 'LR', 'RL', 'RR']

Hidding

It can be useful to hide certian variables or functions to avoid unnecessary complexity. This can for example be done with:

tree = ivt.blocking()
tree.hide_vars.add('permutations.elements')
tree.hide_vars.add('permutations.element')
tree.hide_vars.add('permutations.all_perms')

Or hide certain function calls:

tree = ivt.blocking()
tree.hide_calls.add('namespace.functionname')

Or ignore certain function calls so that all it's children are hidden too:

tree = ivt.blocking()
tree.ignore_calls.add('namespace.functionname')

Configuration

These invocation_tree configurations are available for an Invocation_Tree objects:

tree = ivt.Invocation_Tree()
  • tree.filename : str
    • filename to save the tree to, defaults to 'tree.pdf'
  • tree.show : bool
    • if True the default application is open to view 'tree.filename'
  • tree.block : bool
    • if True program execution is blocked after the tree is saved
  • tree.src_loc : bool
    • if True the source location is printed when blocking
  • tree.each_line : bool
    • if True each line of the program is stepped through
  • tree.max_string_len : int
    • the maximum string length, only the end is shown of longer strings
  • tree.gifcount : int
    • if >=0 the out filename is numbered for animated gif making
  • tree.indent : string
    • the string used for identing the local variables
  • tree.color_active : string
    • HTML color for active function
  • tree.color_paused* : string
    • HTML color for paused functions
  • tree.color_returned*: string
    • HTML color for returned functions
  • tree.hide : set()
    • set of all variables names that are not shown in the tree
  • tree.to_string : dict[str, fun]
    • mapping from type/name to a to_string() function for custom printing of values

For convenience we provide these functions to set common configurations:

  • ivt.blocking(filename), blocks on function call and return
  • ivt.blocking_each_change(filename), blocks on each change of value
  • ivt.debugger(filename), non-blocking for use in debugger tool (open <filename> manually)
  • ivt.gif(filename), generates many output files on function call and return for gif creation
  • ivt.gif_each_change(filename), generates many output files on each change of value for gif creation
  • ivt.non_blocking(filename), non-blocking on each function call and return

Troubleshooting

  • Adobe Acrobat Reader doesn't refresh a PDF file when it changes on disk and blocks updates which results in an Could not open 'somefile.pdf' for writing : Permission denied error. One solution is to install a PDF reader that does refresh (SumatraPDF, Okular, ...) and set it as the default PDF reader. Another solution is to render() the graph to a different output format and to open it manually.

Memory_Graph Package

The invocation_tree package visualizes function calls at different moments in time. If instead you want a detailed visualization of your data at the current time, check out the memory_graph package.

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

invocation_tree-0.0.24.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

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

invocation_tree-0.0.24-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file invocation_tree-0.0.24.tar.gz.

File metadata

  • Download URL: invocation_tree-0.0.24.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for invocation_tree-0.0.24.tar.gz
Algorithm Hash digest
SHA256 010009f0501ec4a875637bdae1786c23fe1dfa09732b62e89d082386d2887d20
MD5 e4b7eec9100b6ad69f339d88b56961cb
BLAKE2b-256 73d80abf97e533f640f87cf93d7c100d15a0a6a86f05f751ea300964931a56b2

See more details on using hashes here.

File details

Details for the file invocation_tree-0.0.24-py3-none-any.whl.

File metadata

File hashes

Hashes for invocation_tree-0.0.24-py3-none-any.whl
Algorithm Hash digest
SHA256 68469b47a43d4f35e37659a7205f8d6dca3648bbf07e7365172e236188847111
MD5 8fdd04bfe9031ba7a75092c5f7f5d742
BLAKE2b-256 b5109057e71075b634cda913f944d2ae2eb51d319b5fea52dd2b366309de5699

See more details on using hashes here.

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