memory-graph 0.3.73__tar.gz → 0.3.75__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.
Files changed (42) hide show
  1. {memory_graph-0.3.73 → memory_graph-0.3.75}/PKG-INFO +124 -19
  2. {memory_graph-0.3.73 → memory_graph-0.3.75}/README.md +123 -18
  3. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/__init__.py +1 -1
  4. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/config.py +0 -7
  5. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/config_default.py +9 -5
  6. memory_graph-0.3.75/memory_graph/config_helpers.py +72 -0
  7. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/html_table.py +11 -15
  8. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/memory_to_nodes.py +6 -10
  9. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/node_base.py +1 -1
  10. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/node_key_value.py +1 -1
  11. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/node_linear.py +1 -1
  12. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/utils.py +37 -0
  13. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph.egg-info/PKG-INFO +124 -19
  14. {memory_graph-0.3.73 → memory_graph-0.3.75}/pyproject.toml +1 -1
  15. memory_graph-0.3.73/memory_graph/config_helpers.py +0 -44
  16. {memory_graph-0.3.73 → memory_graph-0.3.75}/LICENSE.txt +0 -0
  17. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/call_stack.py +0 -0
  18. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/extension_numpy.py +0 -0
  19. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/extension_pandas.py +0 -0
  20. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/extension_torch.py +0 -0
  21. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/list_view.py +0 -0
  22. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/node_leaf.py +0 -0
  23. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/node_table.py +0 -0
  24. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/sequence.py +0 -0
  25. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/slicer.py +0 -0
  26. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/slices.py +0 -0
  27. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/slices_iterator.py +0 -0
  28. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/slices_table_iterator.py +0 -0
  29. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test.py +0 -0
  30. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_max_graph_depth.py +0 -0
  31. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_memory_graph.py +0 -0
  32. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_memory_to_nodes.py +0 -0
  33. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_sequence.py +0 -0
  34. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_slicer.py +0 -0
  35. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_slices.py +0 -0
  36. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph/test_slices_iterator.py +0 -0
  37. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph.egg-info/SOURCES.txt +0 -0
  38. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph.egg-info/dependency_links.txt +0 -0
  39. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph.egg-info/requires.txt +0 -0
  40. {memory_graph-0.3.73 → memory_graph-0.3.75}/memory_graph.egg-info/top_level.txt +0 -0
  41. {memory_graph-0.3.73 → memory_graph-0.3.75}/setup.cfg +0 -0
  42. {memory_graph-0.3.73 → memory_graph-0.3.75}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memory_graph
3
- Version: 0.3.73
3
+ Version: 0.3.75
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
- ![images/bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
37
+ ![bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
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&timestep=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(), mg.stack())
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(), mg.stack())
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 "/home/bterwijn/temp/e.py", line 18, in <module>
589
+ File "exception_example.py", line 18, in <module>
590
590
  raise e # raise to print traceback
591
591
  ^^^^^^^
592
- File "/home/bterwijn/temp/e.py", line 15, in <module>
592
+ File "exception_example.py", line 15, in <module>
593
593
  fun1()
594
- File "/home/bterwijn/temp/e.py", line 12, in fun1
594
+ File "exception_example.py", line 12, in fun1
595
595
  fun2()
596
- File "/home/bterwijn/temp/e.py", line 9, in fun2
596
+ File "exception_example.py", line 9, in fun2
597
597
  fun3()
598
- File "/home/bterwijn/temp/e.py", line 6, in fun3
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
@@ -772,7 +772,6 @@ This example shows the flow of control when using inheritance with:
772
772
  - class variable `message_count`
773
773
 
774
774
  ```python
775
- from datetime import datetime
776
775
 
777
776
  class Notification_Service:
778
777
  message_count = 0
@@ -810,14 +809,14 @@ class SMS_Notification(Notification_Service):
810
809
  email = Email_Notification(3, 'support@company.com')
811
810
  email.send('customer@email.com', 'Your report is ready')
812
811
  email.send('customer@email.com', 'Update to Privacy Policy')
813
- sms = Email_Notification(3, '0123456789')
812
+ sms = SMS_Notification(3, '0123456789')
814
813
  sms.send('001122334455', 'Update to Privacy Policy')
815
814
  ```
816
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
815
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
817
816
 
818
817
  ## Decorator ##
819
818
 
820
- This example shows the flow of control when using a decorator.
819
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
821
820
 
822
821
  ```python
823
822
  def log_call(function):
@@ -851,29 +850,135 @@ This example shows the flow of control when using exception handling.
851
850
  def fun2():
852
851
  try:
853
852
  d = [0] * 3
854
- for i in range(4):
853
+ for i in range(6):
855
854
  try:
856
- d[i] = i # raises IndexError when i=3
857
- except TypeError as e:
855
+ print(f'{i=}')
856
+ d[i] = i # raises IndexError when i>=3
857
+ except ZeroDivisionError as e:
858
858
  print(type(e), e)
859
859
  except AssertionError as e:
860
860
  print(type(e), e)
861
-
861
+ print('fun2() returns')
862
+
862
863
  def fun1():
863
864
  try:
864
865
  return fun2()
865
866
  except NameError as e:
866
867
  print(type(e), e)
867
-
868
+ print('fun1() returns')
869
+
868
870
  try:
869
871
  fun1()
870
872
  except LookupError as e:
871
873
  print(type(e), e)
874
+ print('program ended cleanly')
872
875
  ```
873
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
876
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
874
877
 
875
878
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
876
879
 
880
+ ## Lazy Evaluation ##
881
+
882
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
883
+
884
+ ```python
885
+ def pr(tag, v):
886
+ print(tag, v)
887
+ return v
888
+ ```
889
+
890
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
891
+
892
+ <table>
893
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
894
+ <tr><td width="50%" valign="top">
895
+
896
+ ```python
897
+ def fun():
898
+ result = []
899
+ for i in range(3):
900
+ result.append(pr('create:', i))
901
+ return result
902
+
903
+ for i in fun():
904
+ pr('use:', i)
905
+ ```
906
+
907
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
908
+
909
+ </td><td width="50%" valign="top">
910
+
911
+ ```python
912
+ def fun():
913
+ for i in range(3):
914
+ yield pr('create:', i)
915
+
916
+
917
+
918
+ for i in fun():
919
+ pr('use:', i)
920
+ ```
921
+
922
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
923
+
924
+ </td></tr>
925
+ <tr><td width="50%" valign="top">
926
+
927
+ ```python
928
+ def fun():
929
+ return [
930
+ pr('create:', i)
931
+ for i in range(3)
932
+ ]
933
+
934
+ for i in fun():
935
+ pr('use:', i)
936
+ ```
937
+
938
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
939
+
940
+ </td><td width="50%" valign="top">
941
+
942
+ ```python
943
+ def fun():
944
+ return (
945
+ pr('create:', i)
946
+ for i in range(3)
947
+ )
948
+
949
+ for i in fun():
950
+ pr('use:', i)
951
+ ```
952
+
953
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
954
+
955
+ </td></tr>
956
+ <tr><td width="50%" valign="top">
957
+
958
+ ```text
959
+ create: 0
960
+ create: 1
961
+ create: 2
962
+ use: 0
963
+ use: 1
964
+ use: 2
965
+ ```
966
+
967
+ </td><td width="50%" valign="top">
968
+
969
+ ```text
970
+ create: 0
971
+ use: 0
972
+ create: 1
973
+ use: 1
974
+ create: 2
975
+ use: 2
976
+ ```
977
+
978
+ </td></tr>
979
+ </table>
980
+
981
+
877
982
  # Configuration #
878
983
  Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
879
984
 
@@ -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
- ![images/bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
17
+ ![bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
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&timestep=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(), mg.stack())
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(), mg.stack())
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 "/home/bterwijn/temp/e.py", line 18, in <module>
569
+ File "exception_example.py", line 18, in <module>
570
570
  raise e # raise to print traceback
571
571
  ^^^^^^^
572
- File "/home/bterwijn/temp/e.py", line 15, in <module>
572
+ File "exception_example.py", line 15, in <module>
573
573
  fun1()
574
- File "/home/bterwijn/temp/e.py", line 12, in fun1
574
+ File "exception_example.py", line 12, in fun1
575
575
  fun2()
576
- File "/home/bterwijn/temp/e.py", line 9, in fun2
576
+ File "exception_example.py", line 9, in fun2
577
577
  fun3()
578
- File "/home/bterwijn/temp/e.py", line 6, in fun3
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
@@ -752,7 +752,6 @@ This example shows the flow of control when using inheritance with:
752
752
  - class variable `message_count`
753
753
 
754
754
  ```python
755
- from datetime import datetime
756
755
 
757
756
  class Notification_Service:
758
757
  message_count = 0
@@ -790,14 +789,14 @@ class SMS_Notification(Notification_Service):
790
789
  email = Email_Notification(3, 'support@company.com')
791
790
  email.send('customer@email.com', 'Your report is ready')
792
791
  email.send('customer@email.com', 'Update to Privacy Policy')
793
- sms = Email_Notification(3, '0123456789')
792
+ sms = SMS_Notification(3, '0123456789')
794
793
  sms.send('001122334455', 'Update to Privacy Policy')
795
794
  ```
796
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
795
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
797
796
 
798
797
  ## Decorator ##
799
798
 
800
- This example shows the flow of control when using a decorator.
799
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
801
800
 
802
801
  ```python
803
802
  def log_call(function):
@@ -831,29 +830,135 @@ This example shows the flow of control when using exception handling.
831
830
  def fun2():
832
831
  try:
833
832
  d = [0] * 3
834
- for i in range(4):
833
+ for i in range(6):
835
834
  try:
836
- d[i] = i # raises IndexError when i=3
837
- except TypeError as e:
835
+ print(f'{i=}')
836
+ d[i] = i # raises IndexError when i>=3
837
+ except ZeroDivisionError as e:
838
838
  print(type(e), e)
839
839
  except AssertionError as e:
840
840
  print(type(e), e)
841
-
841
+ print('fun2() returns')
842
+
842
843
  def fun1():
843
844
  try:
844
845
  return fun2()
845
846
  except NameError as e:
846
847
  print(type(e), e)
847
-
848
+ print('fun1() returns')
849
+
848
850
  try:
849
851
  fun1()
850
852
  except LookupError as e:
851
853
  print(type(e), e)
854
+ print('program ended cleanly')
852
855
  ```
853
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
856
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
854
857
 
855
858
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
856
859
 
860
+ ## Lazy Evaluation ##
861
+
862
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
863
+
864
+ ```python
865
+ def pr(tag, v):
866
+ print(tag, v)
867
+ return v
868
+ ```
869
+
870
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
871
+
872
+ <table>
873
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
874
+ <tr><td width="50%" valign="top">
875
+
876
+ ```python
877
+ def fun():
878
+ result = []
879
+ for i in range(3):
880
+ result.append(pr('create:', i))
881
+ return result
882
+
883
+ for i in fun():
884
+ pr('use:', i)
885
+ ```
886
+
887
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
888
+
889
+ </td><td width="50%" valign="top">
890
+
891
+ ```python
892
+ def fun():
893
+ for i in range(3):
894
+ yield pr('create:', i)
895
+
896
+
897
+
898
+ for i in fun():
899
+ pr('use:', i)
900
+ ```
901
+
902
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
903
+
904
+ </td></tr>
905
+ <tr><td width="50%" valign="top">
906
+
907
+ ```python
908
+ def fun():
909
+ return [
910
+ pr('create:', i)
911
+ for i in range(3)
912
+ ]
913
+
914
+ for i in fun():
915
+ pr('use:', i)
916
+ ```
917
+
918
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
919
+
920
+ </td><td width="50%" valign="top">
921
+
922
+ ```python
923
+ def fun():
924
+ return (
925
+ pr('create:', i)
926
+ for i in range(3)
927
+ )
928
+
929
+ for i in fun():
930
+ pr('use:', i)
931
+ ```
932
+
933
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
934
+
935
+ </td></tr>
936
+ <tr><td width="50%" valign="top">
937
+
938
+ ```text
939
+ create: 0
940
+ create: 1
941
+ create: 2
942
+ use: 0
943
+ use: 1
944
+ use: 2
945
+ ```
946
+
947
+ </td><td width="50%" valign="top">
948
+
949
+ ```text
950
+ create: 0
951
+ use: 0
952
+ create: 1
953
+ use: 1
954
+ create: 2
955
+ use: 2
956
+ ```
957
+
958
+ </td></tr>
959
+ </table>
960
+
961
+
857
962
  # Configuration #
858
963
  Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
859
964
 
@@ -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.73"
5
+ __version__ = "0.3.75"
6
6
  __author__ = 'Bas Terwijn'
7
7
 
8
8
  import memory_graph.memory_to_nodes as memory_to_nodes
@@ -27,13 +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
- data_type = type(data)
33
- if data_type in type_to_string:
34
- return type_to_string[data_type](data)
35
- return str(data)
36
-
37
30
  type_to_node = { }
38
31
 
39
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(s):
16
- """ Helper function to format the string s to be shown in the graph. Setting the max_string_length and escaping html characters. """
17
- s = config.to_string(s)
18
- s = (s[:config.max_string_length] + '...') if len(s) > config.max_string_length else s
19
- return html.escape(s)
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, s, rounded=False, border=1):
82
- """ Helper function to add a value s to the table. """
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(s)} </TD>'
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.add_string(' ')
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(data_id, data_type, data):
23
+ def data_to_node(data):
24
24
  """ Returns the Node for 'data' based on it's id or type. """
25
- if data_id in config.type_to_node: # for ids
26
- return config.type_to_node[data_id](data)
27
- elif data_type in config.type_to_node: # for predefined types
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(data_id, data_type, data)
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.get_color(node)
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(),
@@ -105,7 +105,7 @@ class Node_Base(ABC):
105
105
  return html_table
106
106
 
107
107
  def get_slicer(self):
108
- return config_helpers.get_slicer(self, self.get_data())
108
+ return config_helpers.get_node_slicer(self, self.get_data())
109
109
 
110
110
  def is_hidden_node(self):
111
111
  """
@@ -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.get_vertical(self, None)
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.get_vertical(self, None)
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,42 @@
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
+ return re.sub(
28
+ r'(^\s*File ")(.*?)(")',
29
+ lambda m: f'{m.group(1)}{m.group(2).replace("\\", "/").rsplit("/", 1)[-1]}{m.group(3)}',
30
+ s,
31
+ flags=re.MULTILINE,
32
+ )
33
+
34
+ def exception_to_string_short(e):
35
+ """ Helper function to convert an exception to a short string. """
36
+ return f'{type(e).__name__}: {e}'
37
+
38
+ def get_all_types(obj):
39
+ cls = type(obj)
40
+ if hasattr(cls, '__mro__'):
41
+ return cls.__mro__
42
+ else:
43
+ return [cls]
8
44
 
9
45
  def has_dict_attributes(value):
10
46
  """ Returns 'True' if 'value' has a '__dict__' attribute. """
@@ -15,6 +51,7 @@ def get_dict_attributes(value):
15
51
  return getattr(value,"__dict__")
16
52
 
17
53
  def is_not_state(obj):
54
+ """ Returns 'True' if 'obj' is not considered state, e.g. a function or method. """
18
55
  if isinstance(obj, (types.FunctionType, types.MethodType,
19
56
  types.BuiltinFunctionType, types.BuiltinMethodType,
20
57
  classmethod, staticmethod,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memory_graph
3
- Version: 0.3.73
3
+ Version: 0.3.75
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
- ![images/bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
37
+ ![bin_tree_vs.gif](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/bin_tree_vs.gif)
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&timestep=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(), mg.stack())
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(), mg.stack())
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 "/home/bterwijn/temp/e.py", line 18, in <module>
589
+ File "exception_example.py", line 18, in <module>
590
590
  raise e # raise to print traceback
591
591
  ^^^^^^^
592
- File "/home/bterwijn/temp/e.py", line 15, in <module>
592
+ File "exception_example.py", line 15, in <module>
593
593
  fun1()
594
- File "/home/bterwijn/temp/e.py", line 12, in fun1
594
+ File "exception_example.py", line 12, in fun1
595
595
  fun2()
596
- File "/home/bterwijn/temp/e.py", line 9, in fun2
596
+ File "exception_example.py", line 9, in fun2
597
597
  fun3()
598
- File "/home/bterwijn/temp/e.py", line 6, in fun3
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
@@ -772,7 +772,6 @@ This example shows the flow of control when using inheritance with:
772
772
  - class variable `message_count`
773
773
 
774
774
  ```python
775
- from datetime import datetime
776
775
 
777
776
  class Notification_Service:
778
777
  message_count = 0
@@ -810,14 +809,14 @@ class SMS_Notification(Notification_Service):
810
809
  email = Email_Notification(3, 'support@company.com')
811
810
  email.send('customer@email.com', 'Your report is ready')
812
811
  email.send('customer@email.com', 'Update to Privacy Policy')
813
- sms = Email_Notification(3, '0123456789')
812
+ sms = SMS_Notification(3, '0123456789')
814
813
  sms.send('001122334455', 'Update to Privacy Policy')
815
814
  ```
816
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=36&continues=1&play).
815
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/inheritance.py&breakpoints=35&continues=1&play).
817
816
 
818
817
  ## Decorator ##
819
818
 
820
- This example shows the flow of control when using a decorator.
819
+ This example shows the flow of control when using a decorator. A decorator wraps a function and is active before and after the function is called.
821
820
 
822
821
  ```python
823
822
  def log_call(function):
@@ -851,29 +850,135 @@ This example shows the flow of control when using exception handling.
851
850
  def fun2():
852
851
  try:
853
852
  d = [0] * 3
854
- for i in range(4):
853
+ for i in range(6):
855
854
  try:
856
- d[i] = i # raises IndexError when i=3
857
- except TypeError as e:
855
+ print(f'{i=}')
856
+ d[i] = i # raises IndexError when i>=3
857
+ except ZeroDivisionError as e:
858
858
  print(type(e), e)
859
859
  except AssertionError as e:
860
860
  print(type(e), e)
861
-
861
+ print('fun2() returns')
862
+
862
863
  def fun1():
863
864
  try:
864
865
  return fun2()
865
866
  except NameError as e:
866
867
  print(type(e), e)
867
-
868
+ print('fun1() returns')
869
+
868
870
  try:
869
871
  fun1()
870
872
  except LookupError as e:
871
873
  print(type(e), e)
874
+ print('program ended cleanly')
872
875
  ```
873
- Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=19&continues=1&play). In the program an `IndexError` is raise and matched with various exceptions in the exception hierarchy below. It matches with the 'LookupError' exception and is handled there by just printing it. Exceptions that are not handled stop the execution of a program.
876
+ Run it in the [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/exceptions.py&breakpoints=22&continues=1&play). In the program an `IndexError` exception is raised which propagates up the call stack until it reaches an except clause that matches its type where it is handled. Here, it is handled by the `LookupError` except clause because `IndexError` is a subclass of `LookupError`. Exceptions that are not handled terminate the execution of a program while its traceback is shown for analyses.
874
877
 
875
878
  ![exception_tree.png](https://raw.githubusercontent.com/bterwijn/memory_graph/main/images/exception_tree.png)
876
879
 
880
+ ## Lazy Evaluation ##
881
+
882
+ In the following Eager and Lazy ealuation examples, we use this `pr()` function to print in what order things are created and used.
883
+
884
+ ```python
885
+ def pr(tag, v):
886
+ print(tag, v)
887
+ return v
888
+ ```
889
+
890
+ With eager evaluation, the function creates all three elements up front and stores them in a list before iteration begins. With lazy evaluation, the function returns a generator that creates each element only when it is needed.
891
+
892
+ <table>
893
+ <tr> <td width="50%" valign="top"><strong>Eager</strong></td> <td width="50%" valign="top"><strong>Lazy</strong></td></tr>
894
+ <tr><td width="50%" valign="top">
895
+
896
+ ```python
897
+ def fun():
898
+ result = []
899
+ for i in range(3):
900
+ result.append(pr('create:', i))
901
+ return result
902
+
903
+ for i in fun():
904
+ pr('use:', i)
905
+ ```
906
+
907
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_return.py&play)
908
+
909
+ </td><td width="50%" valign="top">
910
+
911
+ ```python
912
+ def fun():
913
+ for i in range(3):
914
+ yield pr('create:', i)
915
+
916
+
917
+
918
+ for i in fun():
919
+ pr('use:', i)
920
+ ```
921
+
922
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_yield.py&play)
923
+
924
+ </td></tr>
925
+ <tr><td width="50%" valign="top">
926
+
927
+ ```python
928
+ def fun():
929
+ return [
930
+ pr('create:', i)
931
+ for i in range(3)
932
+ ]
933
+
934
+ for i in fun():
935
+ pr('use:', i)
936
+ ```
937
+
938
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/eager_compri.py&play)
939
+
940
+ </td><td width="50%" valign="top">
941
+
942
+ ```python
943
+ def fun():
944
+ return (
945
+ pr('create:', i)
946
+ for i in range(3)
947
+ )
948
+
949
+ for i in fun():
950
+ pr('use:', i)
951
+ ```
952
+
953
+ Run in [Memory Graph Web Debugger](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/lazy_express.py&play)
954
+
955
+ </td></tr>
956
+ <tr><td width="50%" valign="top">
957
+
958
+ ```text
959
+ create: 0
960
+ create: 1
961
+ create: 2
962
+ use: 0
963
+ use: 1
964
+ use: 2
965
+ ```
966
+
967
+ </td><td width="50%" valign="top">
968
+
969
+ ```text
970
+ create: 0
971
+ use: 0
972
+ create: 1
973
+ use: 1
974
+ create: 2
975
+ use: 2
976
+ ```
977
+
978
+ </td></tr>
979
+ </table>
980
+
981
+
877
982
  # Configuration #
878
983
  Different aspects of memory_graph can be configured. The default configuration can be reset by calling 'mg.config_default.reset()'. The Memory Graph Web Debugger gives examples of the [most important configurations](https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/config.py&play).
879
984
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "memory_graph"
7
- version = "0.3.73"
7
+ version = "0.3.75"
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