memory-graph 0.3.74__tar.gz → 0.3.76__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.
- {memory_graph-0.3.74 → memory_graph-0.3.76}/PKG-INFO +9 -9
- {memory_graph-0.3.74 → memory_graph-0.3.76}/README.md +8 -8
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/__init__.py +1 -1
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/config.py +0 -10
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/config_default.py +9 -5
- memory_graph-0.3.76/memory_graph/config_helpers.py +72 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/html_table.py +11 -15
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/memory_to_nodes.py +6 -10
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/node_base.py +1 -1
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/node_key_value.py +1 -1
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/node_linear.py +1 -1
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/utils.py +41 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph.egg-info/PKG-INFO +9 -9
- {memory_graph-0.3.74 → memory_graph-0.3.76}/pyproject.toml +1 -1
- memory_graph-0.3.74/memory_graph/config_helpers.py +0 -44
- {memory_graph-0.3.74 → memory_graph-0.3.76}/LICENSE.txt +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph.egg-info/SOURCES.txt +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/setup.cfg +0 -0
- {memory_graph-0.3.74 → memory_graph-0.3.76}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.76
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -34,7 +34,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
34
34
|
- understand function calls, variable scope, and the **complete program state** through call stack visualization
|
|
35
35
|
|
|
36
36
|
An example Binary Tree data structure:
|
|
37
|
-

|
|
38
38
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
39
39
|
|
|
40
40
|
# Videos #
|
|
@@ -433,12 +433,12 @@ import memory_graph as mg
|
|
|
433
433
|
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
434
434
|
|
|
435
435
|
def binary(value: int) -> list[int]:
|
|
436
|
-
mg.block(mg.show
|
|
436
|
+
mg.block(mg.show, mg.stack())
|
|
437
437
|
if value == 0:
|
|
438
438
|
return []
|
|
439
439
|
quotient, remainder = divmod(value, 2)
|
|
440
440
|
result = binary(quotient) + [remainder]
|
|
441
|
-
mg.block(mg.show
|
|
441
|
+
mg.block(mg.show, mg.stack())
|
|
442
442
|
return result
|
|
443
443
|
|
|
444
444
|
print( binary(100) )
|
|
@@ -586,16 +586,16 @@ except Exception as e:
|
|
|
586
586
|
```
|
|
587
587
|
$ python exception_example.py
|
|
588
588
|
Traceback (most recent call last):
|
|
589
|
-
File "
|
|
589
|
+
File "exception_example.py", line 18, in <module>
|
|
590
590
|
raise e # raise to print traceback
|
|
591
591
|
^^^^^^^
|
|
592
|
-
File "
|
|
592
|
+
File "exception_example.py", line 15, in <module>
|
|
593
593
|
fun1()
|
|
594
|
-
File "
|
|
594
|
+
File "exception_example.py", line 12, in fun1
|
|
595
595
|
fun2()
|
|
596
|
-
File "
|
|
596
|
+
File "exception_example.py", line 9, in fun2
|
|
597
597
|
fun3()
|
|
598
|
-
File "
|
|
598
|
+
File "exception_example.py", line 6, in fun3
|
|
599
599
|
d[i] = i # throws IndexError when i = 3
|
|
600
600
|
~^^^
|
|
601
601
|
IndexError: list assignment index out of range
|
|
@@ -14,7 +14,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
14
14
|
- understand function calls, variable scope, and the **complete program state** through call stack visualization
|
|
15
15
|
|
|
16
16
|
An example Binary Tree data structure:
|
|
17
|
-

|
|
18
18
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
19
19
|
|
|
20
20
|
# Videos #
|
|
@@ -413,12 +413,12 @@ import memory_graph as mg
|
|
|
413
413
|
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
414
414
|
|
|
415
415
|
def binary(value: int) -> list[int]:
|
|
416
|
-
mg.block(mg.show
|
|
416
|
+
mg.block(mg.show, mg.stack())
|
|
417
417
|
if value == 0:
|
|
418
418
|
return []
|
|
419
419
|
quotient, remainder = divmod(value, 2)
|
|
420
420
|
result = binary(quotient) + [remainder]
|
|
421
|
-
mg.block(mg.show
|
|
421
|
+
mg.block(mg.show, mg.stack())
|
|
422
422
|
return result
|
|
423
423
|
|
|
424
424
|
print( binary(100) )
|
|
@@ -566,16 +566,16 @@ except Exception as e:
|
|
|
566
566
|
```
|
|
567
567
|
$ python exception_example.py
|
|
568
568
|
Traceback (most recent call last):
|
|
569
|
-
File "
|
|
569
|
+
File "exception_example.py", line 18, in <module>
|
|
570
570
|
raise e # raise to print traceback
|
|
571
571
|
^^^^^^^
|
|
572
|
-
File "
|
|
572
|
+
File "exception_example.py", line 15, in <module>
|
|
573
573
|
fun1()
|
|
574
|
-
File "
|
|
574
|
+
File "exception_example.py", line 12, in fun1
|
|
575
575
|
fun2()
|
|
576
|
-
File "
|
|
576
|
+
File "exception_example.py", line 9, in fun2
|
|
577
577
|
fun3()
|
|
578
|
-
File "
|
|
578
|
+
File "exception_example.py", line 6, in fun3
|
|
579
579
|
d[i] = i # throws IndexError when i = 3
|
|
580
580
|
~^^^
|
|
581
581
|
IndexError: list assignment index out of range
|
|
@@ -27,16 +27,6 @@ no_index_types = {}
|
|
|
27
27
|
|
|
28
28
|
type_to_string = { }
|
|
29
29
|
|
|
30
|
-
def to_string(data):
|
|
31
|
-
""" Convert data to string. """
|
|
32
|
-
try:
|
|
33
|
-
data_type = type(data)
|
|
34
|
-
if data_type in type_to_string:
|
|
35
|
-
return type_to_string[data_type](data)
|
|
36
|
-
return str(data)
|
|
37
|
-
except Exception as e:
|
|
38
|
-
return f'no stringification, {type(e).__name__}: {e}'
|
|
39
|
-
|
|
40
30
|
type_to_node = { }
|
|
41
31
|
|
|
42
32
|
type_to_color = { }
|
|
@@ -60,11 +60,12 @@ def reset():
|
|
|
60
60
|
|
|
61
61
|
""" Types that need a special conversion """
|
|
62
62
|
config.type_to_string = {
|
|
63
|
-
types.FunctionType: lambda data: data.__qualname__,
|
|
64
|
-
types.MethodType: lambda data: data.__qualname__,
|
|
65
|
-
classmethod: lambda data: data.__qualname__,
|
|
66
|
-
staticmethod: lambda data: data.__qualname__,
|
|
67
|
-
type(len): lambda data: data.__qualname__,
|
|
63
|
+
types.FunctionType: lambda data: utils.limit_string(data.__qualname__),
|
|
64
|
+
types.MethodType: lambda data: utils.limit_string(data.__qualname__),
|
|
65
|
+
classmethod: lambda data: utils.limit_string(data.__qualname__),
|
|
66
|
+
staticmethod: lambda data: utils.limit_string(data.__qualname__),
|
|
67
|
+
type(len): lambda data: utils.limit_string(data.__qualname__),
|
|
68
|
+
BaseException: lambda data: utils.exception_to_string(data),
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
""" Conversion from type to Node objects. """
|
|
@@ -78,6 +79,7 @@ def reset():
|
|
|
78
79
|
if dict in config.embedding_types else
|
|
79
80
|
Node_Linear(data, utils.filter_dict(data) )
|
|
80
81
|
),
|
|
82
|
+
BaseException: lambda data: Node_Leaf(data, data),
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
""" Colors of different types in the graph. """
|
|
@@ -103,6 +105,8 @@ def reset():
|
|
|
103
105
|
dict : "#60a5ff",
|
|
104
106
|
types.MappingProxyType : "dodgerblue2", # not used
|
|
105
107
|
range : "cornsilk2",
|
|
108
|
+
# ================= exception
|
|
109
|
+
BaseException : "#ff5555",
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# This file is part of memory_graph.
|
|
2
|
+
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
+
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
+
|
|
5
|
+
""" This module provides helper functions to access the configuration of the memory graph. """
|
|
6
|
+
import memory_graph.utils as utils
|
|
7
|
+
from memory_graph.slicer import Slicer
|
|
8
|
+
import memory_graph.config as config
|
|
9
|
+
import memory_graph.utils as utils
|
|
10
|
+
|
|
11
|
+
def get_property(data_id, data_types, node_type, dictionary, default):
|
|
12
|
+
if data_id in dictionary:
|
|
13
|
+
return dictionary[data_id]
|
|
14
|
+
for data_type in data_types:
|
|
15
|
+
if data_type in dictionary:
|
|
16
|
+
return dictionary[data_type]
|
|
17
|
+
if node_type in dictionary:
|
|
18
|
+
return dictionary[node_type]
|
|
19
|
+
return default
|
|
20
|
+
|
|
21
|
+
def get_data_to_node(data, default=None):
|
|
22
|
+
return get_property(id(data),
|
|
23
|
+
utils.get_all_types(data),
|
|
24
|
+
None,
|
|
25
|
+
config.type_to_node,
|
|
26
|
+
default )
|
|
27
|
+
|
|
28
|
+
def default_to_string(data):
|
|
29
|
+
""" Convert data to string. """
|
|
30
|
+
try:
|
|
31
|
+
if isinstance(data, str):
|
|
32
|
+
s = data
|
|
33
|
+
else:
|
|
34
|
+
s = str(data)
|
|
35
|
+
return utils.limit_string(s)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
return f'no stringification, {type(e).__name__}: {e}'
|
|
38
|
+
|
|
39
|
+
def get_to_string(data, default=lambda s: default_to_string(s)):
|
|
40
|
+
return get_property(id(data),
|
|
41
|
+
utils.get_all_types(data),
|
|
42
|
+
None,
|
|
43
|
+
config.type_to_string,
|
|
44
|
+
default )
|
|
45
|
+
|
|
46
|
+
def get_node_color(node, default='white'):
|
|
47
|
+
return get_property(node.get_id(),
|
|
48
|
+
utils.get_all_types(node.get_data()),
|
|
49
|
+
type(node),
|
|
50
|
+
config.type_to_color,
|
|
51
|
+
default)
|
|
52
|
+
|
|
53
|
+
def get_node_vertical(node, default):
|
|
54
|
+
horizontal = get_property(node.get_id(),
|
|
55
|
+
utils.get_all_types(node.get_data()),
|
|
56
|
+
type(node),
|
|
57
|
+
config.type_to_horizontal,
|
|
58
|
+
None)
|
|
59
|
+
if isinstance(horizontal, bool):
|
|
60
|
+
return not horizontal
|
|
61
|
+
return get_property(node.get_id(),
|
|
62
|
+
utils.get_all_types(node.get_data()),
|
|
63
|
+
type(node),
|
|
64
|
+
config.type_to_vertical,
|
|
65
|
+
default)
|
|
66
|
+
|
|
67
|
+
def get_node_slicer(node, data, default=Slicer(3,2,3)):
|
|
68
|
+
return get_property(id(data),
|
|
69
|
+
utils.get_all_types(node.get_data()),
|
|
70
|
+
type(node),
|
|
71
|
+
config.type_to_slicer,
|
|
72
|
+
default)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
from memory_graph.node_base import Node_Base
|
|
6
6
|
import memory_graph.node_base
|
|
7
7
|
import memory_graph.config as config
|
|
8
|
+
import memory_graph.config_helpers as config_helpers
|
|
8
9
|
import html
|
|
9
10
|
|
|
10
11
|
def html_table_frame(s, border, color, spacing=5):
|
|
@@ -12,11 +13,11 @@ def html_table_frame(s, border, color, spacing=5):
|
|
|
12
13
|
return (f'<\n<TABLE BORDER="{border}" CELLBORDER="1" CELLSPACING="{spacing}" CELLPADDING="0" BGCOLOR="{color}" PORT="table">\n <TR>' +
|
|
13
14
|
s + '</TR>\n</TABLE>\n>')
|
|
14
15
|
|
|
15
|
-
def format_string(
|
|
16
|
-
""" Helper function to format
|
|
17
|
-
|
|
18
|
-
s =
|
|
19
|
-
return
|
|
16
|
+
def format_string(value):
|
|
17
|
+
""" Helper function to format 'value' to be shown in the graph. We escape html characters and convert newlines to <BR/> tags. """
|
|
18
|
+
to_string = config_helpers.get_to_string(value)
|
|
19
|
+
s = html.escape(to_string(value))
|
|
20
|
+
return s.replace('\n', ' <BR/> ')
|
|
20
21
|
|
|
21
22
|
class HTML_Table:
|
|
22
23
|
"""
|
|
@@ -54,11 +55,6 @@ class HTML_Table:
|
|
|
54
55
|
self.html += '</TR>\n <TR>'
|
|
55
56
|
self.add_new_line_flag = False
|
|
56
57
|
|
|
57
|
-
def add_string(self, s, border=0):
|
|
58
|
-
""" Add a string s to the table. """
|
|
59
|
-
self.html += f'<TD BORDER="{border}">'+format_string(s)+'</TD>'
|
|
60
|
-
self.is_empty = False
|
|
61
|
-
|
|
62
58
|
def add_index(self, s):
|
|
63
59
|
""" Add an index s to the table. """
|
|
64
60
|
self.check_add_new_line()
|
|
@@ -67,7 +63,6 @@ class HTML_Table:
|
|
|
67
63
|
|
|
68
64
|
def add_entry(self, node, nodes, child, id_to_slices, rounded=False, border=1, dashed=False, embed=False):
|
|
69
65
|
""" Add child to the table either as reference if it is a Node_Base or as a value otherwise. """
|
|
70
|
-
#print('child:', child)
|
|
71
66
|
child_id = id(child)
|
|
72
67
|
if not embed and child_id in nodes:
|
|
73
68
|
child = nodes[child_id]
|
|
@@ -78,11 +73,12 @@ class HTML_Table:
|
|
|
78
73
|
else:
|
|
79
74
|
self.add_value(child, rounded, border)
|
|
80
75
|
|
|
81
|
-
def add_value(self,
|
|
82
|
-
""" Helper function to add
|
|
76
|
+
def add_value(self, value, rounded=False, border=1):
|
|
77
|
+
""" Helper function to add 'value' to the table. """
|
|
83
78
|
self.check_add_new_line()
|
|
84
79
|
r = ' STYLE="ROUNDED"' if rounded else ''
|
|
85
|
-
self.html += f'<TD BORDER="{border}"{r}> {format_string(
|
|
80
|
+
self.html += f'<TD BORDER="{border}"{r}> {format_string(value)} </TD>'
|
|
81
|
+
self.is_empty = False
|
|
86
82
|
self.col_count += 1
|
|
87
83
|
|
|
88
84
|
def add_reference(self, node, child, rounded=False, border=1, dashed=False):
|
|
@@ -106,7 +102,7 @@ class HTML_Table:
|
|
|
106
102
|
""" Construct the HTML table string with the 'border' and 'color' settings. """
|
|
107
103
|
if self.col_count == 0 and self.row_count == 0:
|
|
108
104
|
if self.is_empty:
|
|
109
|
-
self.
|
|
105
|
+
self.add_value('', border=0)
|
|
110
106
|
return html_table_frame(self.html, border, color, spacing=0)
|
|
111
107
|
return html_table_frame(self.html, border, color)
|
|
112
108
|
|
|
@@ -20,15 +20,11 @@ def read_nodes(data):
|
|
|
20
20
|
- the id of 'data' as root node.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
def data_to_node(
|
|
23
|
+
def data_to_node(data):
|
|
24
24
|
""" Returns the Node for 'data' based on it's id or type. """
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return config.type_to_node[data_type](data)
|
|
29
|
-
elif isinstance(data, type) and type in config.type_to_node:
|
|
30
|
-
# Handle classes with custom metaclasses (for example abc.ABCMeta).
|
|
31
|
-
return config.type_to_node[type](data)
|
|
25
|
+
to_node = config_helpers.get_data_to_node(data)
|
|
26
|
+
if (to_node):
|
|
27
|
+
return to_node(data)
|
|
32
28
|
elif utils.has_dict_attributes(data): # for user defined classes
|
|
33
29
|
return Node_Key_Value(data, utils.filter_dict(utils.get_dict_attributes(data)) )
|
|
34
30
|
elif utils.is_finite_iterable(data): # for lists, tuples, sets, ...
|
|
@@ -46,7 +42,7 @@ def read_nodes(data):
|
|
|
46
42
|
if data_id in nodes:
|
|
47
43
|
node = nodes[data_id]
|
|
48
44
|
else:
|
|
49
|
-
node = data_to_node(
|
|
45
|
+
node = data_to_node(data)
|
|
50
46
|
if isinstance(node, Node_Key_Value):
|
|
51
47
|
nodes_key_value.append(data_id)
|
|
52
48
|
nodes[data_id] = node
|
|
@@ -219,7 +215,7 @@ def build_graph(graphviz_graph, nodes, root_id, id_to_slices):
|
|
|
219
215
|
""" Adds 'node' to 'graphviz_graph' with its children and edges. """
|
|
220
216
|
html_table = node.get_html_table(nodes, slices, id_to_slices)
|
|
221
217
|
edges = html_table.get_edges()
|
|
222
|
-
color = config_helpers.
|
|
218
|
+
color = config_helpers.get_node_color(node)
|
|
223
219
|
border = 3 if node.is_root() else 1
|
|
224
220
|
if config.type_labels:
|
|
225
221
|
graphviz_graph.node(node.get_name(),
|
|
@@ -46,7 +46,7 @@ class Node_Key_Value(Node_Base):
|
|
|
46
46
|
"""
|
|
47
47
|
Return if the node is vertical or horizontal based on the orientation of the children.
|
|
48
48
|
"""
|
|
49
|
-
vertical = config_helpers.
|
|
49
|
+
vertical = config_helpers.get_node_vertical(self, None)
|
|
50
50
|
if vertical is None:
|
|
51
51
|
vertical = not self.has_references(nodes, slices, id_to_slices)
|
|
52
52
|
return vertical
|
|
@@ -37,7 +37,7 @@ class Node_Linear(Node_Base):
|
|
|
37
37
|
"""
|
|
38
38
|
Return if the node is vertical or horizontal based on the orientation of the children.
|
|
39
39
|
"""
|
|
40
|
-
vertical = config_helpers.
|
|
40
|
+
vertical = config_helpers.get_node_vertical(self, None)
|
|
41
41
|
if vertical is None:
|
|
42
42
|
vertical = not self.has_references(nodes, slices)
|
|
43
43
|
return vertical
|
|
@@ -5,6 +5,47 @@
|
|
|
5
5
|
import math
|
|
6
6
|
import types
|
|
7
7
|
import functools
|
|
8
|
+
import traceback
|
|
9
|
+
import re
|
|
10
|
+
|
|
11
|
+
import memory_graph.config as config
|
|
12
|
+
|
|
13
|
+
def limit_string(s):
|
|
14
|
+
""" Helper function to limit the length of a string s to the 'max_string_length' in the config. """
|
|
15
|
+
if len(s) > config.max_string_length:
|
|
16
|
+
return s[:config.max_string_length] + '...'
|
|
17
|
+
return s
|
|
18
|
+
|
|
19
|
+
def exception_to_string(e):
|
|
20
|
+
""" Helper function to convert the traceback of an exception to a string. """
|
|
21
|
+
return ''.join(traceback.format_exception(type(e), e, e.__traceback__)).strip()
|
|
22
|
+
|
|
23
|
+
def exception_to_string_no_path(e):
|
|
24
|
+
""" Helper function to convert the traceback of an exception to a string without file paths. """
|
|
25
|
+
s = exception_to_string(e)
|
|
26
|
+
# Convert traceback file paths like File "/a/b/c.py" to File "c.py".
|
|
27
|
+
def _strip_path(match):
|
|
28
|
+
file_path = match.group(2).replace('\\', '/') # for Windows paths
|
|
29
|
+
file_name = file_path.rsplit('/', 1)[-1]
|
|
30
|
+
return f'{match.group(1)}{file_name}{match.group(3)}'
|
|
31
|
+
|
|
32
|
+
return re.sub(
|
|
33
|
+
r'(^\s*File ")(.*?)(")',
|
|
34
|
+
_strip_path,
|
|
35
|
+
s,
|
|
36
|
+
flags=re.MULTILINE,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def exception_to_string_short(e):
|
|
40
|
+
""" Helper function to convert an exception to a short string. """
|
|
41
|
+
return f'{type(e).__name__}: {e}'
|
|
42
|
+
|
|
43
|
+
def get_all_types(obj):
|
|
44
|
+
cls = type(obj)
|
|
45
|
+
if hasattr(cls, '__mro__'):
|
|
46
|
+
return cls.__mro__
|
|
47
|
+
else:
|
|
48
|
+
return [cls]
|
|
8
49
|
|
|
9
50
|
def has_dict_attributes(value):
|
|
10
51
|
""" Returns 'True' if 'value' has a '__dict__' attribute. """
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.76
|
|
4
4
|
Summary: Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy.
|
|
5
5
|
Author-email: Bas Terwijn <bterwijn@gmail.com>
|
|
6
6
|
License-Expression: BSD-2-Clause
|
|
@@ -34,7 +34,7 @@ Run a live demo in the 👉 [**Memory Graph Web Debugger**](https://memory-graph
|
|
|
34
34
|
- understand function calls, variable scope, and the **complete program state** through call stack visualization
|
|
35
35
|
|
|
36
36
|
An example Binary Tree data structure:
|
|
37
|
-

|
|
38
38
|
Or see it in the [Memory Grah Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bin_tree.py×tep=0.2&play).
|
|
39
39
|
|
|
40
40
|
# Videos #
|
|
@@ -433,12 +433,12 @@ import memory_graph as mg
|
|
|
433
433
|
mg.config.type_to_horizontal[list] = True # horizontal lists
|
|
434
434
|
|
|
435
435
|
def binary(value: int) -> list[int]:
|
|
436
|
-
mg.block(mg.show
|
|
436
|
+
mg.block(mg.show, mg.stack())
|
|
437
437
|
if value == 0:
|
|
438
438
|
return []
|
|
439
439
|
quotient, remainder = divmod(value, 2)
|
|
440
440
|
result = binary(quotient) + [remainder]
|
|
441
|
-
mg.block(mg.show
|
|
441
|
+
mg.block(mg.show, mg.stack())
|
|
442
442
|
return result
|
|
443
443
|
|
|
444
444
|
print( binary(100) )
|
|
@@ -586,16 +586,16 @@ except Exception as e:
|
|
|
586
586
|
```
|
|
587
587
|
$ python exception_example.py
|
|
588
588
|
Traceback (most recent call last):
|
|
589
|
-
File "
|
|
589
|
+
File "exception_example.py", line 18, in <module>
|
|
590
590
|
raise e # raise to print traceback
|
|
591
591
|
^^^^^^^
|
|
592
|
-
File "
|
|
592
|
+
File "exception_example.py", line 15, in <module>
|
|
593
593
|
fun1()
|
|
594
|
-
File "
|
|
594
|
+
File "exception_example.py", line 12, in fun1
|
|
595
595
|
fun2()
|
|
596
|
-
File "
|
|
596
|
+
File "exception_example.py", line 9, in fun2
|
|
597
597
|
fun3()
|
|
598
|
-
File "
|
|
598
|
+
File "exception_example.py", line 6, in fun3
|
|
599
599
|
d[i] = i # throws IndexError when i = 3
|
|
600
600
|
~^^^
|
|
601
601
|
IndexError: list assignment index out of range
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "memory_graph"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.76"
|
|
8
8
|
description = "Teaching tool and debugging aid in context of references, mutable data types, and shallow and deep copy."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Bas Terwijn", email = "bterwijn@gmail.com"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# This file is part of memory_graph.
|
|
2
|
-
# Copyright (c) 2023, Bas Terwijn.
|
|
3
|
-
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
|
-
|
|
5
|
-
""" This module provides helper functions to access the configuration of the memory graph. """
|
|
6
|
-
from memory_graph.slicer import Slicer
|
|
7
|
-
import memory_graph.config as config
|
|
8
|
-
|
|
9
|
-
def get_property(data_id, data_type, node_type, dictionary, default):
|
|
10
|
-
if data_id in dictionary:
|
|
11
|
-
return dictionary[data_id]
|
|
12
|
-
if data_type in dictionary:
|
|
13
|
-
return dictionary[data_type]
|
|
14
|
-
if node_type in dictionary:
|
|
15
|
-
return dictionary[node_type]
|
|
16
|
-
return default
|
|
17
|
-
|
|
18
|
-
def get_color(node, default='white'):
|
|
19
|
-
return get_property(node.get_id(),
|
|
20
|
-
node.get_type(),
|
|
21
|
-
type(node),
|
|
22
|
-
config.type_to_color,
|
|
23
|
-
default)
|
|
24
|
-
|
|
25
|
-
def get_vertical(node, default):
|
|
26
|
-
horizontal = get_property(node.get_id(),
|
|
27
|
-
node.get_type(),
|
|
28
|
-
type(node),
|
|
29
|
-
config.type_to_horizontal,
|
|
30
|
-
None)
|
|
31
|
-
if isinstance(horizontal, bool):
|
|
32
|
-
return not horizontal
|
|
33
|
-
return get_property(node.get_id(),
|
|
34
|
-
node.get_type(),
|
|
35
|
-
type(node),
|
|
36
|
-
config.type_to_vertical,
|
|
37
|
-
default)
|
|
38
|
-
|
|
39
|
-
def get_slicer(node, data, default=Slicer(3,2,3)):
|
|
40
|
-
return get_property(id(data),
|
|
41
|
-
type(data),
|
|
42
|
-
type(node),
|
|
43
|
-
config.type_to_slicer,
|
|
44
|
-
default)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|