memory-graph 0.3.66__tar.gz → 0.3.68__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.66 → memory_graph-0.3.68}/PKG-INFO +49 -4
- {memory_graph-0.3.66 → memory_graph-0.3.68}/README.md +48 -3
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/__init__.py +112 -1
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph.egg-info/PKG-INFO +49 -4
- {memory_graph-0.3.66 → memory_graph-0.3.68}/pyproject.toml +1 -1
- {memory_graph-0.3.66 → memory_graph-0.3.68}/LICENSE.txt +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/call_stack.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/config.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/config_default.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/config_helpers.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/extension_numpy.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/extension_pandas.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/extension_torch.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/html_table.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/list_view.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/memory_to_nodes.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/node_base.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/node_key_value.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/node_leaf.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/node_linear.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/node_table.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/sequence.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/slicer.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/slices.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/slices_iterator.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/slices_table_iterator.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_max_graph_depth.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_memory_graph.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_memory_to_nodes.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_sequence.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_slicer.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_slices.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/test_slices_iterator.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph/utils.py +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph.egg-info/SOURCES.txt +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph.egg-info/dependency_links.txt +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph.egg-info/requires.txt +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/memory_graph.egg-info/top_level.txt +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/setup.cfg +0 -0
- {memory_graph-0.3.66 → memory_graph-0.3.68}/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.68
|
|
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
|
|
@@ -176,7 +176,7 @@ ___
|
|
|
176
176
|
# Python Data Model #
|
|
177
177
|
Learn the right **mental model** to think about Python data. The [Python Data Model](https://docs.python.org/3/reference/datamodel.html) makes a distiction between immutable and mutable types:
|
|
178
178
|
|
|
179
|
-
* **immutable**: bool, int, float, complex, str, tuple,
|
|
179
|
+
* **immutable**: bool, int, float, complex, str, tuple, frozenset, frozendict, bytes
|
|
180
180
|
* **mutable**: list, set, dict, classes, ... (most other types)
|
|
181
181
|
|
|
182
182
|
|
|
@@ -500,6 +500,7 @@ The ```mg.stack()``` doesn't work well in **watch** context in most debuggers be
|
|
|
500
500
|
|:---|:---|
|
|
501
501
|
| [pdb](https://docs.python.org/3/library/pdb.html), [pudb](https://pypi.org/project/pudb/) | `mg.stack_pdb()` |
|
|
502
502
|
| [Visual Studio Code](https://code.visualstudio.com/docs/languages/python) | `mg.stack_vscode()` |
|
|
503
|
+
| [Jupyter Notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks) | `mg.stack_vscode_jupyter()` |
|
|
503
504
|
| [Cursor AI](https://www.cursor.com/) | `mg.stack_cursor()` |
|
|
504
505
|
| [PyCharm](https://www.jetbrains.com/pycharm/) | `mg.stack_pycharm()` |
|
|
505
506
|
| [Wing](https://wingware.com/) | `mg.stack_wing()` |
|
|
@@ -556,6 +557,48 @@ and pressing <Enter> a number of times, results in:
|
|
|
556
557
|
|
|
557
558
|

|
|
558
559
|
|
|
560
|
+
## Debugging using Exceptions ##
|
|
561
|
+
|
|
562
|
+
To get the call stack at the point where exception `e` was thrown use `mg.stack_exception(e)`. This allows you to graph the trace back for easier debugging, for example:
|
|
563
|
+
|
|
564
|
+
``` python
|
|
565
|
+
import memory_graph as mg
|
|
566
|
+
import traceback;
|
|
567
|
+
|
|
568
|
+
def fun3():
|
|
569
|
+
d = [0] * 3
|
|
570
|
+
for i in range(4):
|
|
571
|
+
d[i] = i # throws IndexError when i = 3
|
|
572
|
+
|
|
573
|
+
def fun2():
|
|
574
|
+
fun3()
|
|
575
|
+
|
|
576
|
+
def fun1():
|
|
577
|
+
fun2()
|
|
578
|
+
|
|
579
|
+
try:
|
|
580
|
+
fun1()
|
|
581
|
+
except Exception as e:
|
|
582
|
+
traceback.print_exc() # print trace back
|
|
583
|
+
mg.show(mg.stack_exception(e)) # graph trace back
|
|
584
|
+
```
|
|
585
|
+
```
|
|
586
|
+
$ python exception_example.py
|
|
587
|
+
Traceback (most recent call last):
|
|
588
|
+
File "exception_example.py", line 16, in <module>
|
|
589
|
+
fun1()
|
|
590
|
+
File "exception_example.py", line 13, in fun1
|
|
591
|
+
fun2()
|
|
592
|
+
File "exception_example.py", line 10, in fun2
|
|
593
|
+
fun3()
|
|
594
|
+
File "exception_example.py", line 7, in fun3
|
|
595
|
+
d[i] = i # throws IndexError when i = 3
|
|
596
|
+
~^^^
|
|
597
|
+
IndexError: list assignment index out of range
|
|
598
|
+
```
|
|
599
|
+

|
|
600
|
+
|
|
601
|
+
|
|
559
602
|
# Data Structure Examples #
|
|
560
603
|
Package memory_graph can **visualize the structure of your data** to easily understand and debug data structures, some examples:
|
|
561
604
|
|
|
@@ -695,6 +738,8 @@ Visualization of different sorting algorithms in Memory Graph Web Debugger.
|
|
|
695
738
|
- [insertion sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/insertion_sort.py&breakpoints=13,29&continues=1×tep=0.2&play)
|
|
696
739
|
- [bubble sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bubble_sort.py&breakpoints=29,38&continues=1×tep=0.2&play)
|
|
697
740
|
- [cocktail shaker sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/cocktail_sort.py&breakpoints=16,45&continues=1×tep=0.2&play)
|
|
741
|
+
- [bucket sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bucket_sort.py×tep=0.2&play)
|
|
742
|
+
- [radix sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/radix_sort.py×tep=0.2&play)
|
|
698
743
|
|
|
699
744
|
|
|
700
745
|
# Bitwise Operators #
|
|
@@ -709,7 +754,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
709
754
|
|
|
710
755
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
711
756
|
|
|
712
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=
|
|
757
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
713
758
|
|
|
714
759
|

|
|
715
760
|
|
|
@@ -1049,7 +1094,7 @@ import memory_graph as mg
|
|
|
1049
1094
|
|
|
1050
1095
|
data = []
|
|
1051
1096
|
x = ['x']
|
|
1052
|
-
for i in range(
|
|
1097
|
+
for i in range(35):
|
|
1053
1098
|
data.append(x)
|
|
1054
1099
|
|
|
1055
1100
|
mg.show(locals())
|
|
@@ -156,7 +156,7 @@ ___
|
|
|
156
156
|
# Python Data Model #
|
|
157
157
|
Learn the right **mental model** to think about Python data. The [Python Data Model](https://docs.python.org/3/reference/datamodel.html) makes a distiction between immutable and mutable types:
|
|
158
158
|
|
|
159
|
-
* **immutable**: bool, int, float, complex, str, tuple,
|
|
159
|
+
* **immutable**: bool, int, float, complex, str, tuple, frozenset, frozendict, bytes
|
|
160
160
|
* **mutable**: list, set, dict, classes, ... (most other types)
|
|
161
161
|
|
|
162
162
|
|
|
@@ -480,6 +480,7 @@ The ```mg.stack()``` doesn't work well in **watch** context in most debuggers be
|
|
|
480
480
|
|:---|:---|
|
|
481
481
|
| [pdb](https://docs.python.org/3/library/pdb.html), [pudb](https://pypi.org/project/pudb/) | `mg.stack_pdb()` |
|
|
482
482
|
| [Visual Studio Code](https://code.visualstudio.com/docs/languages/python) | `mg.stack_vscode()` |
|
|
483
|
+
| [Jupyter Notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks) | `mg.stack_vscode_jupyter()` |
|
|
483
484
|
| [Cursor AI](https://www.cursor.com/) | `mg.stack_cursor()` |
|
|
484
485
|
| [PyCharm](https://www.jetbrains.com/pycharm/) | `mg.stack_pycharm()` |
|
|
485
486
|
| [Wing](https://wingware.com/) | `mg.stack_wing()` |
|
|
@@ -536,6 +537,48 @@ and pressing <Enter> a number of times, results in:
|
|
|
536
537
|
|
|
537
538
|

|
|
538
539
|
|
|
540
|
+
## Debugging using Exceptions ##
|
|
541
|
+
|
|
542
|
+
To get the call stack at the point where exception `e` was thrown use `mg.stack_exception(e)`. This allows you to graph the trace back for easier debugging, for example:
|
|
543
|
+
|
|
544
|
+
``` python
|
|
545
|
+
import memory_graph as mg
|
|
546
|
+
import traceback;
|
|
547
|
+
|
|
548
|
+
def fun3():
|
|
549
|
+
d = [0] * 3
|
|
550
|
+
for i in range(4):
|
|
551
|
+
d[i] = i # throws IndexError when i = 3
|
|
552
|
+
|
|
553
|
+
def fun2():
|
|
554
|
+
fun3()
|
|
555
|
+
|
|
556
|
+
def fun1():
|
|
557
|
+
fun2()
|
|
558
|
+
|
|
559
|
+
try:
|
|
560
|
+
fun1()
|
|
561
|
+
except Exception as e:
|
|
562
|
+
traceback.print_exc() # print trace back
|
|
563
|
+
mg.show(mg.stack_exception(e)) # graph trace back
|
|
564
|
+
```
|
|
565
|
+
```
|
|
566
|
+
$ python exception_example.py
|
|
567
|
+
Traceback (most recent call last):
|
|
568
|
+
File "exception_example.py", line 16, in <module>
|
|
569
|
+
fun1()
|
|
570
|
+
File "exception_example.py", line 13, in fun1
|
|
571
|
+
fun2()
|
|
572
|
+
File "exception_example.py", line 10, in fun2
|
|
573
|
+
fun3()
|
|
574
|
+
File "exception_example.py", line 7, in fun3
|
|
575
|
+
d[i] = i # throws IndexError when i = 3
|
|
576
|
+
~^^^
|
|
577
|
+
IndexError: list assignment index out of range
|
|
578
|
+
```
|
|
579
|
+

|
|
580
|
+
|
|
581
|
+
|
|
539
582
|
# Data Structure Examples #
|
|
540
583
|
Package memory_graph can **visualize the structure of your data** to easily understand and debug data structures, some examples:
|
|
541
584
|
|
|
@@ -675,6 +718,8 @@ Visualization of different sorting algorithms in Memory Graph Web Debugger.
|
|
|
675
718
|
- [insertion sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/insertion_sort.py&breakpoints=13,29&continues=1×tep=0.2&play)
|
|
676
719
|
- [bubble sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bubble_sort.py&breakpoints=29,38&continues=1×tep=0.2&play)
|
|
677
720
|
- [cocktail shaker sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/cocktail_sort.py&breakpoints=16,45&continues=1×tep=0.2&play)
|
|
721
|
+
- [bucket sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bucket_sort.py×tep=0.2&play)
|
|
722
|
+
- [radix sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/radix_sort.py×tep=0.2&play)
|
|
678
723
|
|
|
679
724
|
|
|
680
725
|
# Bitwise Operators #
|
|
@@ -689,7 +734,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
689
734
|
|
|
690
735
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
691
736
|
|
|
692
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=
|
|
737
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
693
738
|
|
|
694
739
|

|
|
695
740
|
|
|
@@ -1029,7 +1074,7 @@ import memory_graph as mg
|
|
|
1029
1074
|
|
|
1030
1075
|
data = []
|
|
1031
1076
|
x = ['x']
|
|
1032
|
-
for i in range(
|
|
1077
|
+
for i in range(35):
|
|
1033
1078
|
data.append(x)
|
|
1034
1079
|
|
|
1035
1080
|
mg.show(locals())
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Copyright (c) 2023, Bas Terwijn.
|
|
3
3
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
4
4
|
|
|
5
|
-
__version__ = "0.3.
|
|
5
|
+
__version__ = "0.3.68"
|
|
6
6
|
__author__ = 'Bas Terwijn'
|
|
7
7
|
|
|
8
8
|
import memory_graph.memory_to_nodes as memory_to_nodes
|
|
@@ -13,6 +13,7 @@ import memory_graph.utils as utils
|
|
|
13
13
|
import inspect
|
|
14
14
|
import sys
|
|
15
15
|
import itertools as it
|
|
16
|
+
import types
|
|
16
17
|
from memory_graph.call_stack import call_stack
|
|
17
18
|
|
|
18
19
|
import graphviz
|
|
@@ -241,9 +242,63 @@ def stack_slice(begin_functions : List[Tuple[str, int]] = [],
|
|
|
241
242
|
end_index = stack_end_index(stack_functions, begin_index, end_functions)
|
|
242
243
|
return stack_frames_to_dict(reversed(frameInfos[begin_index+stack_index:end_index+1]))
|
|
243
244
|
|
|
245
|
+
def stack_multi_slice(drop_functions : List[Tuple[str, int]] = [],
|
|
246
|
+
end_functions : List[str] = ["<module>"],
|
|
247
|
+
stack_index : int = 0,
|
|
248
|
+
frameInfos : List[inspect.FrameInfo] = None,
|
|
249
|
+
ignore_frame_condition = None):
|
|
250
|
+
"""
|
|
251
|
+
Returns a slice of the call stack, dropping all occurrences of the specified drop_functions.
|
|
252
|
+
Parameters:
|
|
253
|
+
drop_functions - list of (function-name, offset), drops all matching 'function-name' frames
|
|
254
|
+
including 'offset' number of parent frames for each match.
|
|
255
|
+
end_functions - list of function-names, ends at the index of the first 'function-name'
|
|
256
|
+
that is found in the call stack after stack index (inclusive),
|
|
257
|
+
otherwise ends at the last index
|
|
258
|
+
stack_index - number of frames removed from the beginning
|
|
259
|
+
ignore_frame_condition - optional callable that takes an inspect.FrameInfo and returns True if the frame should be dropped
|
|
260
|
+
"""
|
|
261
|
+
if frameInfos is None:
|
|
262
|
+
frameInfos = inspect.stack()
|
|
263
|
+
|
|
264
|
+
stack_functions = [s.function for s in frameInfos]
|
|
265
|
+
|
|
266
|
+
# establish where to start (skipping innermost debugger eval frames)
|
|
267
|
+
begin_index = stack_begin_index(stack_functions, drop_functions)
|
|
268
|
+
if begin_index == 0:
|
|
269
|
+
begin_index += stack_index
|
|
270
|
+
|
|
271
|
+
end_index = stack_end_index(stack_functions, begin_index, end_functions)
|
|
272
|
+
|
|
273
|
+
drop_indices = set()
|
|
274
|
+
for drop_func, offset in drop_functions:
|
|
275
|
+
for i, func in enumerate(stack_functions[begin_index:end_index+1]):
|
|
276
|
+
actual_i = i + begin_index
|
|
277
|
+
if func == drop_func:
|
|
278
|
+
for j in range(actual_i, actual_i + offset):
|
|
279
|
+
drop_indices.add(j)
|
|
280
|
+
|
|
281
|
+
if ignore_frame_condition:
|
|
282
|
+
for i in range(begin_index, end_index + 1):
|
|
283
|
+
if i not in drop_indices and ignore_frame_condition(frameInfos[i]):
|
|
284
|
+
drop_indices.add(i)
|
|
285
|
+
|
|
286
|
+
filtered_frames = [frameInfos[i] for i in range(begin_index, end_index + 1) if i not in drop_indices]
|
|
287
|
+
|
|
288
|
+
return stack_frames_to_dict(reversed(filtered_frames))
|
|
289
|
+
|
|
244
290
|
def stack(end_functions=["<module>"], stack_index=0):
|
|
245
291
|
return stack_slice([], end_functions, stack_index+2)
|
|
246
292
|
|
|
293
|
+
def stack_exception(exception):
|
|
294
|
+
""" Get the call stack at the point 'exception' was thrown. """
|
|
295
|
+
tb = exception.__traceback__
|
|
296
|
+
frame_infos = []
|
|
297
|
+
while tb is not None:
|
|
298
|
+
frame_infos.append(types.SimpleNamespace(frame=tb.tb_frame))
|
|
299
|
+
tb = tb.tb_next
|
|
300
|
+
return stack_frames_to_dict(frame_infos)
|
|
301
|
+
|
|
247
302
|
def stack_pdb(begin_functions=[("trace_dispatch",1)],
|
|
248
303
|
end_functions=["<module>"],
|
|
249
304
|
stack_index=0):
|
|
@@ -275,6 +330,56 @@ def stack_wing(begin_functions=[("_py_line_event",1), ("_py_return_event",1)],
|
|
|
275
330
|
return stack_slice(begin_functions, end_functions, stack_index)
|
|
276
331
|
|
|
277
332
|
|
|
333
|
+
banned_vscode_jupyter_strings = ['pydevd', 'debugpy', 'ipython', 'ipykernel', 'asyncio', 'tornado', 'traitlets', 'runpy']
|
|
334
|
+
|
|
335
|
+
def is_vscode_jupyter_banned(frameInfo):
|
|
336
|
+
module_name = frameInfo.frame.f_globals.get('__name__', '')
|
|
337
|
+
filename = frameInfo.filename
|
|
338
|
+
func_name = frameInfo.function
|
|
339
|
+
|
|
340
|
+
module_name_lower = module_name.lower()
|
|
341
|
+
func_name_lower = func_name.lower()
|
|
342
|
+
filename_lower = filename.lower()
|
|
343
|
+
|
|
344
|
+
# Exempt user notebook/cell code from being banned.
|
|
345
|
+
if module_name == '__main__' or filename_lower.startswith('<ipython-input'):
|
|
346
|
+
return False
|
|
347
|
+
|
|
348
|
+
for b in banned_vscode_jupyter_strings:
|
|
349
|
+
if b in module_name_lower or b in func_name_lower or b in filename_lower:
|
|
350
|
+
return True
|
|
351
|
+
|
|
352
|
+
return False
|
|
353
|
+
|
|
354
|
+
def stack_vscode_jupyter(drop_functions=[("trace_dispatch",1), ("_line_event",1), ("_return_event",1), ("do_wait_suspend",1), ("_do_wait_suspend",2)],
|
|
355
|
+
end_functions=["<module>"],
|
|
356
|
+
stack_index=0):
|
|
357
|
+
""" Get the call stack natively in a 'vscode' debugging 'jupyter' notebook session,
|
|
358
|
+
filtering out the noisy environment specific functions and modules that pollute the graph. """
|
|
359
|
+
# stack_index + 2 to account for stack_vscode_jupyter and stack_multi_slice
|
|
360
|
+
call_stack_dict = stack_multi_slice(drop_functions, end_functions, stack_index + 2, ignore_frame_condition=is_vscode_jupyter_banned)
|
|
361
|
+
|
|
362
|
+
for level_key, local_dict in call_stack_dict.items():
|
|
363
|
+
if '__pydevd_ret_val_dict' in local_dict:
|
|
364
|
+
ret_vals = local_dict.pop('__pydevd_ret_val_dict')
|
|
365
|
+
if isinstance(ret_vals, dict):
|
|
366
|
+
for k, v in ret_vals.items():
|
|
367
|
+
# filter out Jupyter internal return values, particularly I/O stream writes
|
|
368
|
+
if not any(b in k.lower() for b in banned_vscode_jupyter_strings) and 'write' not in k.lower():
|
|
369
|
+
# Place return value in the function's own frame if it is still on the stack
|
|
370
|
+
target_dict = local_dict
|
|
371
|
+
for l_key, l_dict in call_stack_dict.items():
|
|
372
|
+
if ": " in l_key and l_key.split(": ", 1)[1] == k:
|
|
373
|
+
target_dict = l_dict
|
|
374
|
+
break
|
|
375
|
+
target_dict[f"<return> {k}"] = v
|
|
376
|
+
|
|
377
|
+
if "<module>" in level_key:
|
|
378
|
+
call_stack_dict[level_key] = jupyter_locals_filter(local_dict)
|
|
379
|
+
|
|
380
|
+
return call_stack_dict
|
|
381
|
+
|
|
382
|
+
|
|
278
383
|
def save_call_stack(filename):
|
|
279
384
|
""" Saves the call stack to 'filename' for inspection to see what functions need to be
|
|
280
385
|
filtered out to create the desired graph. """
|
|
@@ -310,6 +415,12 @@ def wing(filename=None, data=None):
|
|
|
310
415
|
data = stack_wing()
|
|
311
416
|
render(data, filename)
|
|
312
417
|
|
|
418
|
+
def vscode_jupyter(filename=None, data=None):
|
|
419
|
+
if data is None:
|
|
420
|
+
# stack_index=1 since this function counts as an extra stack frame
|
|
421
|
+
data = stack_vscode_jupyter(stack_index=1)
|
|
422
|
+
render(data, filename)
|
|
423
|
+
|
|
313
424
|
def locals_filter(locals, keys):
|
|
314
425
|
""" Filter out the jupyter specific keys that polute the graph. """
|
|
315
426
|
return {k:v for k,v in utils.filter_dict(jupyter_locals)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: memory_graph
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.68
|
|
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
|
|
@@ -176,7 +176,7 @@ ___
|
|
|
176
176
|
# Python Data Model #
|
|
177
177
|
Learn the right **mental model** to think about Python data. The [Python Data Model](https://docs.python.org/3/reference/datamodel.html) makes a distiction between immutable and mutable types:
|
|
178
178
|
|
|
179
|
-
* **immutable**: bool, int, float, complex, str, tuple,
|
|
179
|
+
* **immutable**: bool, int, float, complex, str, tuple, frozenset, frozendict, bytes
|
|
180
180
|
* **mutable**: list, set, dict, classes, ... (most other types)
|
|
181
181
|
|
|
182
182
|
|
|
@@ -500,6 +500,7 @@ The ```mg.stack()``` doesn't work well in **watch** context in most debuggers be
|
|
|
500
500
|
|:---|:---|
|
|
501
501
|
| [pdb](https://docs.python.org/3/library/pdb.html), [pudb](https://pypi.org/project/pudb/) | `mg.stack_pdb()` |
|
|
502
502
|
| [Visual Studio Code](https://code.visualstudio.com/docs/languages/python) | `mg.stack_vscode()` |
|
|
503
|
+
| [Jupyter Notebooks in VS Code](https://code.visualstudio.com/docs/datascience/jupyter-notebooks) | `mg.stack_vscode_jupyter()` |
|
|
503
504
|
| [Cursor AI](https://www.cursor.com/) | `mg.stack_cursor()` |
|
|
504
505
|
| [PyCharm](https://www.jetbrains.com/pycharm/) | `mg.stack_pycharm()` |
|
|
505
506
|
| [Wing](https://wingware.com/) | `mg.stack_wing()` |
|
|
@@ -556,6 +557,48 @@ and pressing <Enter> a number of times, results in:
|
|
|
556
557
|
|
|
557
558
|

|
|
558
559
|
|
|
560
|
+
## Debugging using Exceptions ##
|
|
561
|
+
|
|
562
|
+
To get the call stack at the point where exception `e` was thrown use `mg.stack_exception(e)`. This allows you to graph the trace back for easier debugging, for example:
|
|
563
|
+
|
|
564
|
+
``` python
|
|
565
|
+
import memory_graph as mg
|
|
566
|
+
import traceback;
|
|
567
|
+
|
|
568
|
+
def fun3():
|
|
569
|
+
d = [0] * 3
|
|
570
|
+
for i in range(4):
|
|
571
|
+
d[i] = i # throws IndexError when i = 3
|
|
572
|
+
|
|
573
|
+
def fun2():
|
|
574
|
+
fun3()
|
|
575
|
+
|
|
576
|
+
def fun1():
|
|
577
|
+
fun2()
|
|
578
|
+
|
|
579
|
+
try:
|
|
580
|
+
fun1()
|
|
581
|
+
except Exception as e:
|
|
582
|
+
traceback.print_exc() # print trace back
|
|
583
|
+
mg.show(mg.stack_exception(e)) # graph trace back
|
|
584
|
+
```
|
|
585
|
+
```
|
|
586
|
+
$ python exception_example.py
|
|
587
|
+
Traceback (most recent call last):
|
|
588
|
+
File "exception_example.py", line 16, in <module>
|
|
589
|
+
fun1()
|
|
590
|
+
File "exception_example.py", line 13, in fun1
|
|
591
|
+
fun2()
|
|
592
|
+
File "exception_example.py", line 10, in fun2
|
|
593
|
+
fun3()
|
|
594
|
+
File "exception_example.py", line 7, in fun3
|
|
595
|
+
d[i] = i # throws IndexError when i = 3
|
|
596
|
+
~^^^
|
|
597
|
+
IndexError: list assignment index out of range
|
|
598
|
+
```
|
|
599
|
+

|
|
600
|
+
|
|
601
|
+
|
|
559
602
|
# Data Structure Examples #
|
|
560
603
|
Package memory_graph can **visualize the structure of your data** to easily understand and debug data structures, some examples:
|
|
561
604
|
|
|
@@ -695,6 +738,8 @@ Visualization of different sorting algorithms in Memory Graph Web Debugger.
|
|
|
695
738
|
- [insertion sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/insertion_sort.py&breakpoints=13,29&continues=1×tep=0.2&play)
|
|
696
739
|
- [bubble sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bubble_sort.py&breakpoints=29,38&continues=1×tep=0.2&play)
|
|
697
740
|
- [cocktail shaker sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/cocktail_sort.py&breakpoints=16,45&continues=1×tep=0.2&play)
|
|
741
|
+
- [bucket sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/bucket_sort.py×tep=0.2&play)
|
|
742
|
+
- [radix sort](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/radix_sort.py×tep=0.2&play)
|
|
698
743
|
|
|
699
744
|
|
|
700
745
|
# Bitwise Operators #
|
|
@@ -709,7 +754,7 @@ In this configuration example we show the decimal, binary and [two's complement
|
|
|
709
754
|
|
|
710
755
|
A sliding puzzle solver as a challenging example showing how memory_graph deals with large amounts of data. Click "Continue" to step through the breadth-first search generations until a solution path is found:
|
|
711
756
|
|
|
712
|
-
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=
|
|
757
|
+
- [sliding puzzle solver](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/sliding_puzzle.py&breakpoints=16,26,28,39&continues=1)
|
|
713
758
|
|
|
714
759
|

|
|
715
760
|
|
|
@@ -1049,7 +1094,7 @@ import memory_graph as mg
|
|
|
1049
1094
|
|
|
1050
1095
|
data = []
|
|
1051
1096
|
x = ['x']
|
|
1052
|
-
for i in range(
|
|
1097
|
+
for i in range(35):
|
|
1053
1098
|
data.append(x)
|
|
1054
1099
|
|
|
1055
1100
|
mg.show(locals())
|
|
@@ -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.68"
|
|
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"}
|
|
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
|
|
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
|