invocation-tree 0.0.1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- invocation_tree-0.0.2/PKG-INFO +178 -0
- invocation_tree-0.0.2/README.md +159 -0
- invocation_tree-0.0.2/images/create_gif.sh +19 -0
- invocation_tree-0.0.2/images/create_images.sh +16 -0
- invocation_tree-0.0.2/images/create_images.sh~ +4 -0
- invocation_tree-0.0.2/images/factorial.gif +0 -0
- invocation_tree-0.0.2/images/factorial.py +9 -0
- invocation_tree-0.0.2/images/factorial.py~ +11 -0
- invocation_tree-0.0.2/images/factorial1.png +0 -0
- invocation_tree-0.0.2/images/factorial2.png +0 -0
- invocation_tree-0.0.2/images/factorial3.png +0 -0
- invocation_tree-0.0.2/images/factorial4.png +0 -0
- invocation_tree-0.0.2/images/factorial5.png +0 -0
- invocation_tree-0.0.2/images/factorial6.png +0 -0
- invocation_tree-0.0.2/images/factorial7.png +0 -0
- invocation_tree-0.0.2/images/factorial8.gv +36 -0
- invocation_tree-0.0.2/images/factorial9.gv +37 -0
- invocation_tree-0.0.2/images/invocation_tree.pdf +0 -0
- invocation_tree-0.0.2/images/invocation_tree0.pdf +0 -0
- invocation_tree-0.0.2/images/permutations.gif +0 -0
- invocation_tree-0.0.2/images/permutations.py +13 -0
- invocation_tree-0.0.2/images/permutations.py~ +8 -0
- invocation_tree-0.0.2/images/permutations1.png +0 -0
- invocation_tree-0.0.2/images/permutations10.png +0 -0
- invocation_tree-0.0.2/images/permutations11.png +0 -0
- invocation_tree-0.0.2/images/permutations12.png +0 -0
- invocation_tree-0.0.2/images/permutations13.png +0 -0
- invocation_tree-0.0.2/images/permutations14.png +0 -0
- invocation_tree-0.0.2/images/permutations15.png +0 -0
- invocation_tree-0.0.2/images/permutations16.png +0 -0
- invocation_tree-0.0.2/images/permutations17.png +0 -0
- invocation_tree-0.0.2/images/permutations18.png +0 -0
- invocation_tree-0.0.2/images/permutations19.png +0 -0
- invocation_tree-0.0.2/images/permutations2.png +0 -0
- invocation_tree-0.0.2/images/permutations20.png +0 -0
- invocation_tree-0.0.2/images/permutations21.png +0 -0
- invocation_tree-0.0.2/images/permutations22.png +0 -0
- invocation_tree-0.0.2/images/permutations22.png~ +0 -0
- invocation_tree-0.0.2/images/permutations23.png +0 -0
- invocation_tree-0.0.2/images/permutations24.png +0 -0
- invocation_tree-0.0.2/images/permutations25.png +0 -0
- invocation_tree-0.0.2/images/permutations26.png +0 -0
- invocation_tree-0.0.2/images/permutations27.png +0 -0
- invocation_tree-0.0.2/images/permutations28.png +0 -0
- invocation_tree-0.0.2/images/permutations29.png +0 -0
- invocation_tree-0.0.2/images/permutations3.png +0 -0
- invocation_tree-0.0.2/images/permutations4.png +0 -0
- invocation_tree-0.0.2/images/permutations5.png +0 -0
- invocation_tree-0.0.2/images/permutations6.png +0 -0
- invocation_tree-0.0.2/images/permutations7.png +0 -0
- invocation_tree-0.0.2/images/permutations8.png +0 -0
- invocation_tree-0.0.2/images/permutations9.png +0 -0
- invocation_tree-0.0.2/images/student.gif +0 -0
- invocation_tree-0.0.2/images/students.gif +0 -0
- invocation_tree-0.0.2/images/students.py +27 -0
- invocation_tree-0.0.2/images/students.py~ +30 -0
- invocation_tree-0.0.2/images/students1.png +0 -0
- invocation_tree-0.0.2/images/students10.png +0 -0
- invocation_tree-0.0.2/images/students11.png +0 -0
- invocation_tree-0.0.2/images/students12.png +0 -0
- invocation_tree-0.0.2/images/students13.png +0 -0
- invocation_tree-0.0.2/images/students14.png +0 -0
- invocation_tree-0.0.2/images/students15.png +0 -0
- invocation_tree-0.0.2/images/students16.gv +44 -0
- invocation_tree-0.0.2/images/students17.gv +50 -0
- invocation_tree-0.0.2/images/students18.gv +51 -0
- invocation_tree-0.0.2/images/students19.gv +58 -0
- invocation_tree-0.0.2/images/students2.png +0 -0
- invocation_tree-0.0.2/images/students20.gv +59 -0
- invocation_tree-0.0.2/images/students21.gv +60 -0
- invocation_tree-0.0.2/images/students22.gv +61 -0
- invocation_tree-0.0.2/images/students23.gv +60 -0
- invocation_tree-0.0.2/images/students24.gv +66 -0
- invocation_tree-0.0.2/images/students25.gv +68 -0
- invocation_tree-0.0.2/images/students26.gv +68 -0
- invocation_tree-0.0.2/images/students27.gv +68 -0
- invocation_tree-0.0.2/images/students28.gv +67 -0
- invocation_tree-0.0.2/images/students29.gv +68 -0
- invocation_tree-0.0.2/images/students3.png +0 -0
- invocation_tree-0.0.2/images/students30.gv +69 -0
- invocation_tree-0.0.2/images/students4.png +0 -0
- invocation_tree-0.0.2/images/students5.png +0 -0
- invocation_tree-0.0.2/images/students6.png +0 -0
- invocation_tree-0.0.2/images/students7.png +0 -0
- invocation_tree-0.0.2/images/students8.png +0 -0
- invocation_tree-0.0.2/images/students9.png +0 -0
- invocation_tree-0.0.2/images/test.py +15 -0
- invocation_tree-0.0.2/images/tree0.gv +7 -0
- invocation_tree-0.0.2/images/tree1.gv +13 -0
- invocation_tree-0.0.2/images/tree10.gv +56 -0
- invocation_tree-0.0.2/images/tree11.gv +64 -0
- invocation_tree-0.0.2/images/tree12.gv +66 -0
- invocation_tree-0.0.2/images/tree13.gv +67 -0
- invocation_tree-0.0.2/images/tree14.gv +72 -0
- invocation_tree-0.0.2/images/tree15.gv +73 -0
- invocation_tree-0.0.2/images/tree16.gv +75 -0
- invocation_tree-0.0.2/images/tree17.gv +75 -0
- invocation_tree-0.0.2/images/tree2.gv +22 -0
- invocation_tree-0.0.2/images/tree3.gv +30 -0
- invocation_tree-0.0.2/images/tree4.gv +32 -0
- invocation_tree-0.0.2/images/tree5.gv +33 -0
- invocation_tree-0.0.2/images/tree6.gv +39 -0
- invocation_tree-0.0.2/images/tree7.gv +47 -0
- invocation_tree-0.0.2/images/tree8.gv +49 -0
- invocation_tree-0.0.2/images/tree9.gv +50 -0
- invocation_tree-0.0.2/images/vscode.png +0 -0
- invocation_tree-0.0.2/invocation_tree/__init__.py +276 -0
- invocation_tree-0.0.2/invocation_tree.egg-info/PKG-INFO +178 -0
- invocation_tree-0.0.2/invocation_tree.egg-info/SOURCES.txt +115 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/setup.py +2 -2
- invocation_tree-0.0.1/PKG-INFO +0 -27
- invocation_tree-0.0.1/README.md +0 -8
- invocation_tree-0.0.1/images/invocation_tree.pdf +0 -0
- invocation_tree-0.0.1/images/permutation.py +0 -23
- invocation_tree-0.0.1/invocation_tree/__init__.py +0 -151
- invocation_tree-0.0.1/invocation_tree.egg-info/PKG-INFO +0 -27
- invocation_tree-0.0.1/invocation_tree.egg-info/SOURCES.txt +0 -13
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/LICENSE.txt +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/MANIFEST.in +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/install.txt +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/invocation_tree.egg-info/dependency_links.txt +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/invocation_tree.egg-info/requires.txt +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/invocation_tree.egg-info/top_level.txt +0 -0
- {invocation_tree-0.0.1 → invocation_tree-0.0.2}/setup.cfg +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: invocation_tree
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Generate an invocation tree of functions calls.
|
|
5
|
+
Home-page: https://github.com/bterwijn/invocation_tree
|
|
6
|
+
Author: Bas Terwijn
|
|
7
|
+
Author-email: bterwijn@gmail.com
|
|
8
|
+
License: BSD 2-clause
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Education
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Education
|
|
15
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Requires-Dist: graphviz
|
|
19
|
+
|
|
20
|
+
# Installation #
|
|
21
|
+
Install (or upgrade) `invocation_tree` using pip:
|
|
22
|
+
```
|
|
23
|
+
pip install --upgrade invocation_tree
|
|
24
|
+
```
|
|
25
|
+
Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
26
|
+
|
|
27
|
+
# Invocation Tree #
|
|
28
|
+
The [invocation_tree](https://pypi.org/project/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 an example of how it works:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import invocation_tree as invo_tree
|
|
32
|
+
import math
|
|
33
|
+
|
|
34
|
+
def main():
|
|
35
|
+
students = {'Ann':[7.5, 8.0],
|
|
36
|
+
'Bob':[4.5, 6.0],
|
|
37
|
+
'Coy':[7.5, 6.0]}
|
|
38
|
+
averages = {student:compute_average(grades)
|
|
39
|
+
for student, grades in students.items()}
|
|
40
|
+
passing = passing_students(averages)
|
|
41
|
+
print(passing)
|
|
42
|
+
|
|
43
|
+
def compute_average(grades):
|
|
44
|
+
average = sum(grades)/len(grades)
|
|
45
|
+
return my_round(average, 1)
|
|
46
|
+
|
|
47
|
+
def my_round(value, digits=0):
|
|
48
|
+
shift = 10 ** digits
|
|
49
|
+
return math.floor(value * shift + 0.5) / shift
|
|
50
|
+
|
|
51
|
+
def passing_students(avg):
|
|
52
|
+
return [student
|
|
53
|
+
for student, average in avg.items()
|
|
54
|
+
if average >= 5.5]
|
|
55
|
+
|
|
56
|
+
if __name__ == '__main__':
|
|
57
|
+
tree = invo_tree.blocking()
|
|
58
|
+
tree(main) # show invocation tree starting at main
|
|
59
|
+
```
|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
Each node in the tree represents a function call, and node's color indicates its state:
|
|
63
|
+
|
|
64
|
+
- White: The function is currently being executed (it is at the top of the call stack).
|
|
65
|
+
- Green: The function is paused and will resume execution later (it is lower down on the call stack).
|
|
66
|
+
- Red: The function has completed execution and returned (it has been removed from the call stack).
|
|
67
|
+
|
|
68
|
+
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.
|
|
69
|
+
|
|
70
|
+
The [invocation_tree](https://pypi.org/project/invocation-tree/) package visualizes function calls at different moments in time. If you want a more detailed visualization of your data at a specific moment in time, check out the [memory_graph](https://pypi.org/project/memory-graph/) package.
|
|
71
|
+
|
|
72
|
+
## Blocking ##
|
|
73
|
+
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) where a change of value occured, use instead:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
tree = invo_tree.blocking_each_line()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
# Debugger #
|
|
80
|
+
To visualize the invocation tree in a debugger tool, such as the integrated debugger in Visual Studio Code, use instead:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
tree = invo_tree.debugger()
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
and open the 'tree.pdf' file manually.
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
# Recursion #
|
|
90
|
+
An invocation tree is particularly useful to better understand recursion. A simple `factorial()` example:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import invocation_tree as invo_tree
|
|
94
|
+
|
|
95
|
+
def factorial(n):
|
|
96
|
+
if n <= 1:
|
|
97
|
+
return 1
|
|
98
|
+
return n * factorial(n - 1)
|
|
99
|
+
|
|
100
|
+
tree = invo_tree.blocking()
|
|
101
|
+
tree(factorial, 4) # calls factorial(4)
|
|
102
|
+
```
|
|
103
|
+

|
|
104
|
+
|
|
105
|
+
This `permutations()` example shows the depth-first nature of recursive execution:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import invocation_tree as invo_tree
|
|
109
|
+
|
|
110
|
+
def permutations(elements, perm, n):
|
|
111
|
+
if n==0:
|
|
112
|
+
return [perm]
|
|
113
|
+
all_perms = []
|
|
114
|
+
for element in elements:
|
|
115
|
+
all_perms.extend(permutations(elements, perm + element, n-1))
|
|
116
|
+
return all_perms
|
|
117
|
+
|
|
118
|
+
tree = invo_tree.blocking()
|
|
119
|
+
result = tree(permutations, ['L','R'], '', 3)
|
|
120
|
+
print(result) # all permutations of going Left and Right of length 3
|
|
121
|
+
```
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
## Hide variables ##
|
|
125
|
+
In an educational context it can be useful to hide certian variables to avoid unnecessary complexity. This can for example be done with:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
tree = invo_tree.blocking()
|
|
129
|
+
tree.hide.add('permutations.elements')
|
|
130
|
+
tree.hide.add('permutations.element')
|
|
131
|
+
tree.hide.add('permutations.all_perms')
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
# Configuration #
|
|
135
|
+
These configuration settings are available for an `Invocation_Tree` objects:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
tree = invo_tree.Invocation_Tree()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- **tree.filename** : str
|
|
142
|
+
- filename to save the tree to, defaults to 'tree.pdf'
|
|
143
|
+
- **tree.show** : bool
|
|
144
|
+
- if `True` the default application is open to view 'tree.filename'
|
|
145
|
+
- **tree.block** : bool
|
|
146
|
+
- if `True` program execution is blocked after the tree is saved
|
|
147
|
+
- **tree.src_loc** : bool
|
|
148
|
+
- if `True` the source location is printed when blocking
|
|
149
|
+
- **tree.each_line** : bool
|
|
150
|
+
- if `True` each line of the program is stepped through
|
|
151
|
+
- **tree.max_string_len** : int
|
|
152
|
+
- the maximum string length, only the end is shown of longer strings
|
|
153
|
+
- **tree.gifcount** : int
|
|
154
|
+
- if `>=0` the out filename is numbered for animated gif making
|
|
155
|
+
- **tree.indent** : string
|
|
156
|
+
- the string used for identing the local variables
|
|
157
|
+
- **tree.color_active** : string
|
|
158
|
+
- HTML color name for active function
|
|
159
|
+
- **tree.color_paused*** : string
|
|
160
|
+
- HTML color name for paused functions
|
|
161
|
+
- **tree.color_returned***: string
|
|
162
|
+
- HTML color name for returned functions
|
|
163
|
+
- **tree.hide** : set()
|
|
164
|
+
- set of all variables names that are not shown in the tree
|
|
165
|
+
- **tree.to_string** : dict[str, fun]
|
|
166
|
+
- mapping from type/name to a to_string() function for custom printing of values
|
|
167
|
+
|
|
168
|
+
For convenience we provide these functions to set common configurations:
|
|
169
|
+
|
|
170
|
+
- **invo_tree.blocking()**, for blocking on function call and return
|
|
171
|
+
- **invo_tree.blocking_each_line()**, for blocking on each line of the program
|
|
172
|
+
- **invo_tree.debugger()**, for use in debugger tool (open 'tree.pdf') manually
|
|
173
|
+
- **invo_tree.gif(filename)**, for generating many output files on function call and return for gif creation
|
|
174
|
+
- **invo_tree.gif_each_line(filename)**, for generating many output files on each line for gif creation
|
|
175
|
+
|
|
176
|
+
# Troubleshooting #
|
|
177
|
+
|
|
178
|
+
- Adobe Acrobat Reader [doesn't refresh a PDF file](https://superuser.com/questions/337011/windows-pdf-viewer-that-auto-refreshes-pdf-when-compiling-with-pdflatex) 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 ([Evince](https://www.fosshub.com/Evince.html), [Okular](https://okular.kde.org/), [SumatraPDF](https://www.sumatrapdfreader.org/), ...) and set it as the default PDF reader. Another solution is to save the tree to a different [Graphviz Output Format](https://graphviz.org/docs/outputs/).
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Installation #
|
|
2
|
+
Install (or upgrade) `invocation_tree` using pip:
|
|
3
|
+
```
|
|
4
|
+
pip install --upgrade invocation_tree
|
|
5
|
+
```
|
|
6
|
+
Additionally [Graphviz](https://graphviz.org/download/) needs to be installed.
|
|
7
|
+
|
|
8
|
+
# Invocation Tree #
|
|
9
|
+
The [invocation_tree](https://pypi.org/project/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 an example of how it works:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import invocation_tree as invo_tree
|
|
13
|
+
import math
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
students = {'Ann':[7.5, 8.0],
|
|
17
|
+
'Bob':[4.5, 6.0],
|
|
18
|
+
'Coy':[7.5, 6.0]}
|
|
19
|
+
averages = {student:compute_average(grades)
|
|
20
|
+
for student, grades in students.items()}
|
|
21
|
+
passing = passing_students(averages)
|
|
22
|
+
print(passing)
|
|
23
|
+
|
|
24
|
+
def compute_average(grades):
|
|
25
|
+
average = sum(grades)/len(grades)
|
|
26
|
+
return my_round(average, 1)
|
|
27
|
+
|
|
28
|
+
def my_round(value, digits=0):
|
|
29
|
+
shift = 10 ** digits
|
|
30
|
+
return math.floor(value * shift + 0.5) / shift
|
|
31
|
+
|
|
32
|
+
def passing_students(avg):
|
|
33
|
+
return [student
|
|
34
|
+
for student, average in avg.items()
|
|
35
|
+
if average >= 5.5]
|
|
36
|
+
|
|
37
|
+
if __name__ == '__main__':
|
|
38
|
+
tree = invo_tree.blocking()
|
|
39
|
+
tree(main) # show invocation tree starting at main
|
|
40
|
+
```
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
Each node in the tree represents a function call, and node's color indicates its state:
|
|
44
|
+
|
|
45
|
+
- White: The function is currently being executed (it is at the top of the call stack).
|
|
46
|
+
- Green: The function is paused and will resume execution later (it is lower down on the call stack).
|
|
47
|
+
- Red: The function has completed execution and returned (it has been removed from the call stack).
|
|
48
|
+
|
|
49
|
+
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.
|
|
50
|
+
|
|
51
|
+
The [invocation_tree](https://pypi.org/project/invocation-tree/) package visualizes function calls at different moments in time. If you want a more detailed visualization of your data at a specific moment in time, check out the [memory_graph](https://pypi.org/project/memory-graph/) package.
|
|
52
|
+
|
|
53
|
+
## Blocking ##
|
|
54
|
+
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) where a change of value occured, use instead:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
tree = invo_tree.blocking_each_line()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
# Debugger #
|
|
61
|
+
To visualize the invocation tree in a debugger tool, such as the integrated debugger in Visual Studio Code, use instead:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
tree = invo_tree.debugger()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
and open the 'tree.pdf' file manually.
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
# Recursion #
|
|
71
|
+
An invocation tree is particularly useful to better understand recursion. A simple `factorial()` example:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import invocation_tree as invo_tree
|
|
75
|
+
|
|
76
|
+
def factorial(n):
|
|
77
|
+
if n <= 1:
|
|
78
|
+
return 1
|
|
79
|
+
return n * factorial(n - 1)
|
|
80
|
+
|
|
81
|
+
tree = invo_tree.blocking()
|
|
82
|
+
tree(factorial, 4) # calls factorial(4)
|
|
83
|
+
```
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
This `permutations()` example shows the depth-first nature of recursive execution:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import invocation_tree as invo_tree
|
|
90
|
+
|
|
91
|
+
def permutations(elements, perm, n):
|
|
92
|
+
if n==0:
|
|
93
|
+
return [perm]
|
|
94
|
+
all_perms = []
|
|
95
|
+
for element in elements:
|
|
96
|
+
all_perms.extend(permutations(elements, perm + element, n-1))
|
|
97
|
+
return all_perms
|
|
98
|
+
|
|
99
|
+
tree = invo_tree.blocking()
|
|
100
|
+
result = tree(permutations, ['L','R'], '', 3)
|
|
101
|
+
print(result) # all permutations of going Left and Right of length 3
|
|
102
|
+
```
|
|
103
|
+

|
|
104
|
+
|
|
105
|
+
## Hide variables ##
|
|
106
|
+
In an educational context it can be useful to hide certian variables to avoid unnecessary complexity. This can for example be done with:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
tree = invo_tree.blocking()
|
|
110
|
+
tree.hide.add('permutations.elements')
|
|
111
|
+
tree.hide.add('permutations.element')
|
|
112
|
+
tree.hide.add('permutations.all_perms')
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
# Configuration #
|
|
116
|
+
These configuration settings are available for an `Invocation_Tree` objects:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
tree = invo_tree.Invocation_Tree()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- **tree.filename** : str
|
|
123
|
+
- filename to save the tree to, defaults to 'tree.pdf'
|
|
124
|
+
- **tree.show** : bool
|
|
125
|
+
- if `True` the default application is open to view 'tree.filename'
|
|
126
|
+
- **tree.block** : bool
|
|
127
|
+
- if `True` program execution is blocked after the tree is saved
|
|
128
|
+
- **tree.src_loc** : bool
|
|
129
|
+
- if `True` the source location is printed when blocking
|
|
130
|
+
- **tree.each_line** : bool
|
|
131
|
+
- if `True` each line of the program is stepped through
|
|
132
|
+
- **tree.max_string_len** : int
|
|
133
|
+
- the maximum string length, only the end is shown of longer strings
|
|
134
|
+
- **tree.gifcount** : int
|
|
135
|
+
- if `>=0` the out filename is numbered for animated gif making
|
|
136
|
+
- **tree.indent** : string
|
|
137
|
+
- the string used for identing the local variables
|
|
138
|
+
- **tree.color_active** : string
|
|
139
|
+
- HTML color name for active function
|
|
140
|
+
- **tree.color_paused*** : string
|
|
141
|
+
- HTML color name for paused functions
|
|
142
|
+
- **tree.color_returned***: string
|
|
143
|
+
- HTML color name for returned functions
|
|
144
|
+
- **tree.hide** : set()
|
|
145
|
+
- set of all variables names that are not shown in the tree
|
|
146
|
+
- **tree.to_string** : dict[str, fun]
|
|
147
|
+
- mapping from type/name to a to_string() function for custom printing of values
|
|
148
|
+
|
|
149
|
+
For convenience we provide these functions to set common configurations:
|
|
150
|
+
|
|
151
|
+
- **invo_tree.blocking()**, for blocking on function call and return
|
|
152
|
+
- **invo_tree.blocking_each_line()**, for blocking on each line of the program
|
|
153
|
+
- **invo_tree.debugger()**, for use in debugger tool (open 'tree.pdf') manually
|
|
154
|
+
- **invo_tree.gif(filename)**, for generating many output files on function call and return for gif creation
|
|
155
|
+
- **invo_tree.gif_each_line(filename)**, for generating many output files on each line for gif creation
|
|
156
|
+
|
|
157
|
+
# Troubleshooting #
|
|
158
|
+
|
|
159
|
+
- Adobe Acrobat Reader [doesn't refresh a PDF file](https://superuser.com/questions/337011/windows-pdf-viewer-that-auto-refreshes-pdf-when-compiling-with-pdflatex) 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 ([Evince](https://www.fosshub.com/Evince.html), [Okular](https://okular.kde.org/), [SumatraPDF](https://www.sumatrapdfreader.org/), ...) and set it as the default PDF reader. Another solution is to save the tree to a different [Graphviz Output Format](https://graphviz.org/docs/outputs/).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# install:
|
|
4
|
+
#
|
|
5
|
+
# sudo apt install imagemagick
|
|
6
|
+
|
|
7
|
+
name="$1"
|
|
8
|
+
files=$(ls -v $name*.png)
|
|
9
|
+
echo "creating gif with:"
|
|
10
|
+
echo "$files"
|
|
11
|
+
|
|
12
|
+
largest_size=$(identify -format "%Wx%H %f\n" $name*.png | sort -nr | head -n1)
|
|
13
|
+
echo "largest_size: $largest_size"
|
|
14
|
+
|
|
15
|
+
echo "resizing images"
|
|
16
|
+
mogrify -resize $largest_size -background white -gravity center -extent $largest_size $files
|
|
17
|
+
echo "creating file: $name.gif"
|
|
18
|
+
convert -delay 150 -loop 0 $files $name.gif
|
|
19
|
+
echo "done"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
rm -f students*.png
|
|
3
|
+
python students.py
|
|
4
|
+
rm -f students0.png
|
|
5
|
+
bash create_gif.sh students
|
|
6
|
+
|
|
7
|
+
rm -f factorial*.png
|
|
8
|
+
python factorial.py
|
|
9
|
+
rm -f factorial0.png
|
|
10
|
+
bash create_gif.sh factorial
|
|
11
|
+
|
|
12
|
+
rm -f permutations*.png
|
|
13
|
+
python permutations.py
|
|
14
|
+
rm -f permutations0.png
|
|
15
|
+
bash create_gif.sh permutations
|
|
16
|
+
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
digraph invocation_tree {
|
|
2
|
+
node [shape=plaintext]
|
|
3
|
+
0 [label=<
|
|
4
|
+
<TABLE BORDER="3" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffffff">
|
|
5
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
6
|
+
<TR><TD ALIGN="left"> n: 4</TD></TR>
|
|
7
|
+
</TABLE>>]
|
|
8
|
+
1 [label=<
|
|
9
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
10
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
11
|
+
<TR><TD ALIGN="left"> n: 3</TD></TR>
|
|
12
|
+
<TR><TD ALIGN="left">return <B>6</B></TD></TR>
|
|
13
|
+
</TABLE>>]
|
|
14
|
+
2 [label=<
|
|
15
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
16
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
17
|
+
<TR><TD ALIGN="left"> n: 2</TD></TR>
|
|
18
|
+
<TR><TD ALIGN="left">return 2</TD></TR>
|
|
19
|
+
</TABLE>>]
|
|
20
|
+
3 [label=<
|
|
21
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
22
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
23
|
+
<TR><TD ALIGN="left"> n: 1</TD></TR>
|
|
24
|
+
<TR><TD ALIGN="left">return 1</TD></TR>
|
|
25
|
+
</TABLE>>]
|
|
26
|
+
4 [label=<
|
|
27
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
28
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
29
|
+
<TR><TD ALIGN="left"> n: 0</TD></TR>
|
|
30
|
+
<TR><TD ALIGN="left">return 1</TD></TR>
|
|
31
|
+
</TABLE>>]
|
|
32
|
+
0 -> 1
|
|
33
|
+
1 -> 2
|
|
34
|
+
2 -> 3
|
|
35
|
+
3 -> 4
|
|
36
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
digraph invocation_tree {
|
|
2
|
+
node [shape=plaintext]
|
|
3
|
+
0 [label=<
|
|
4
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
5
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
6
|
+
<TR><TD ALIGN="left"> n: 4</TD></TR>
|
|
7
|
+
<TR><TD ALIGN="left">return <B>24</B></TD></TR>
|
|
8
|
+
</TABLE>>]
|
|
9
|
+
1 [label=<
|
|
10
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
11
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
12
|
+
<TR><TD ALIGN="left"> n: 3</TD></TR>
|
|
13
|
+
<TR><TD ALIGN="left">return 6</TD></TR>
|
|
14
|
+
</TABLE>>]
|
|
15
|
+
2 [label=<
|
|
16
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
17
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
18
|
+
<TR><TD ALIGN="left"> n: 2</TD></TR>
|
|
19
|
+
<TR><TD ALIGN="left">return 2</TD></TR>
|
|
20
|
+
</TABLE>>]
|
|
21
|
+
3 [label=<
|
|
22
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
23
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
24
|
+
<TR><TD ALIGN="left"> n: 1</TD></TR>
|
|
25
|
+
<TR><TD ALIGN="left">return 1</TD></TR>
|
|
26
|
+
</TABLE>>]
|
|
27
|
+
4 [label=<
|
|
28
|
+
<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" BGCOLOR="#ffcccc">
|
|
29
|
+
<TR><TD ALIGN="left">➤factorial</TD></TR>
|
|
30
|
+
<TR><TD ALIGN="left"> n: 0</TD></TR>
|
|
31
|
+
<TR><TD ALIGN="left">return 1</TD></TR>
|
|
32
|
+
</TABLE>>]
|
|
33
|
+
0 -> 1
|
|
34
|
+
1 -> 2
|
|
35
|
+
2 -> 3
|
|
36
|
+
3 -> 4
|
|
37
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import invocation_tree as invo_tree
|
|
2
|
+
|
|
3
|
+
def permutations(elements, perm, n):
|
|
4
|
+
if n==0:
|
|
5
|
+
return [perm]
|
|
6
|
+
all_perms = []
|
|
7
|
+
for element in elements:
|
|
8
|
+
all_perms.extend(permutations(elements, perm + element, n-1))
|
|
9
|
+
return all_perms
|
|
10
|
+
|
|
11
|
+
tree = invo_tree.gif('permutations.png')
|
|
12
|
+
result = tree(permutations, ['L','R'], '', 3)
|
|
13
|
+
print(result)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import invocation_tree as invo_tree
|
|
2
|
+
import math
|
|
3
|
+
|
|
4
|
+
def main():
|
|
5
|
+
students = {'Ann':[7.5, 8.0],
|
|
6
|
+
'Bob':[4.5, 6.0],
|
|
7
|
+
'Coy':[7.5, 6.0]}
|
|
8
|
+
averages = {student:compute_average(grades)
|
|
9
|
+
for student, grades in students.items()}
|
|
10
|
+
passing = passing_students(averages)
|
|
11
|
+
print(passing)
|
|
12
|
+
|
|
13
|
+
def compute_average(grades):
|
|
14
|
+
average = sum(grades)/len(grades)
|
|
15
|
+
return my_round(average, 1)
|
|
16
|
+
|
|
17
|
+
def my_round(value, digits=0):
|
|
18
|
+
shift = 10 ** digits
|
|
19
|
+
return math.floor(value * shift + 0.5) / shift
|
|
20
|
+
|
|
21
|
+
def passing_students(avg):
|
|
22
|
+
return [student
|
|
23
|
+
for student, average in avg.items()
|
|
24
|
+
if average >= 5.5]
|
|
25
|
+
|
|
26
|
+
if __name__ == '__main__':
|
|
27
|
+
invo_tree.gif(filename="students.png")(main)
|