memory-graph 0.3.30__py3-none-any.whl

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/test.py ADDED
@@ -0,0 +1,245 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ """ Some test data to make memory graph of for test purposes. """
6
+ import memory_graph.utils as utils
7
+ import memory_graph.config as config
8
+
9
+ import numpy as np
10
+ import pandas as pd
11
+ import memory_graph.extension_numpy
12
+ import memory_graph.extension_pandas
13
+
14
+ from memory_graph.node_table import Node_Table
15
+
16
+ import random
17
+
18
+ def test_singular(fun):
19
+ data = 100
20
+ fun(data)
21
+
22
+ def test_linear(fun):
23
+ data = [None, True, 1, 2.2, complex(3,4), 'hello this is a very long string that should be cut off at some point.']
24
+ fun(data)
25
+
26
+ def test_linears(fun):
27
+ data = [(1,2), [3,4], {5,6}, frozenset((7,8)), {9:'nine', 10:'ten'} , bytes('11', 'utf-8'), bytearray('12', 'utf-8')]
28
+ data.append( [i for i in range(20)] )
29
+ fun(data)
30
+
31
+ def test_colors(fun):
32
+ data1 = [None, True, 1, 2.2, complex(3,4), 'hello']
33
+ class My_Class:
34
+ class_var = 1
35
+ def __init__(self):
36
+ self.var=2
37
+ data2 = [(1,2), [3,4], {5,6}, frozenset((7,8)), {9:'9', 10:'10'} , bytes('11', 'utf-8'), bytearray('12', 'utf-8'), My_Class(), My_Class]
38
+ restore = config.not_node_types.copy()
39
+ config.not_node_types.clear()
40
+ fun([data1, data2])
41
+ config.not_node_types = restore
42
+
43
+ def test_empty_linear(fun):
44
+ data = [tuple(), list(), set(), frozenset(), dict() , bytes(), bytearray()]
45
+ fun(data)
46
+
47
+ def test_nested_list(fun):
48
+ data = utils.nested_list([2,2,2,2,2,2,2])
49
+ fun(data)
50
+
51
+ def test_key_value(fun):
52
+ data1 = {1:'a', 2:'b', 3:'c', 4:'d'}
53
+ data2 = {10:100, 20:200, 30:300, 40:400}
54
+ data2[50] = ('c','c')
55
+ data2[60] = data1
56
+ data = {'first':data1, 'second':data2}
57
+ fun(data)
58
+
59
+ def test_class(fun):
60
+ class My_Class1:
61
+ def __init__(self):
62
+ self.foo1=10
63
+ self.bar1=20
64
+ class My_Class2:
65
+ def __init__(self):
66
+ self.foo2=10
67
+ self.bar2=20
68
+ data = [My_Class1(), My_Class2()]
69
+ fun(data)
70
+
71
+ def test_class_vars(fun):
72
+ class My_Class1:
73
+ class_var1 = 'a'
74
+ class_var2 = 'b'
75
+ def __init__(self):
76
+ self.var1=10
77
+ self.var2=20
78
+ def my_method(self):
79
+ return 100
80
+ m = My_Class1()
81
+ data = locals()
82
+ fun(data)
83
+
84
+ def test_share_tuple(fun):
85
+ class My_Class:
86
+ def __init__(self):
87
+ self.a=1
88
+ data = [('a',1), ('a',1), {'a':1}, {'a':1}, My_Class(),My_Class()]
89
+ fun(data)
90
+
91
+ def test_share_children(fun):
92
+ a=['a']
93
+ b=['b']
94
+ c=['c']
95
+ d=['d']
96
+ data = [ [a,b,c,], [a,c,d] ]
97
+ fun(data)
98
+
99
+ def test_list_split(fun):
100
+ data = [ list(range(i)) for i in range(50) ]
101
+ fun(data)
102
+
103
+ def test_key_value_split(fun):
104
+ data = { i:i*10 for i in range(1,20)}
105
+ fun(data)
106
+
107
+ def test_table(fun):
108
+ class My_Table:
109
+ def __init__(self,size):
110
+ self.size=size
111
+ self.data = [i for i in range(size[0]*size[1])]
112
+ data = My_Table((15,15))
113
+ config.type_to_color[My_Table] = 'plum1'
114
+ config.type_to_node[My_Table] = lambda data: (
115
+ Node_Table(data, data.data , data.size[0],
116
+ #column_names = [f'col{i}' for i in range(data.size[1])],
117
+ #row_names = [f'row{i}' for i in range(data.size[0])]
118
+ )
119
+ )
120
+ fun(data)
121
+
122
+ def test_numpy(fun):
123
+ a = np.array([1, 2, 3])
124
+ print(a, type(a))
125
+ data = [
126
+ np.array([1, 2, 3]),
127
+ np.matrix([[i*3+j for j in range(20)] for i in range(3)]),
128
+ np.random.rand(20,20)
129
+ ]
130
+ #data = np.matrix('1 2; 3 4')
131
+ fun(data)
132
+
133
+ def test_pandas(fun):
134
+ data = [
135
+ pd.DataFrame({ "calories": [420, 380, 390],
136
+ "duration": [50, 40, 45]
137
+ }),
138
+
139
+ pd.DataFrame({ 'Name' : [ 'Tom', 'Anna', 'Steve', 'Lisa'],
140
+ 'Age' : [ 28, 34, 29, 42],
141
+ 'Length' : [ 1.70, 1.66, 1.82, 1.73] },
142
+ index=['one', 'two', 'three', 'four']),
143
+
144
+ pd.Series( [i for i in range(20)] )
145
+ ]
146
+ fun(data)
147
+
148
+ def example_function(a):
149
+ return a*10
150
+
151
+ class Example_Class:
152
+ class_var1 = 100
153
+ class_var2 = 200
154
+ def __init__(self):
155
+ self.a=1
156
+ self.b=2
157
+ def example_method(self):
158
+ return self.a+self.b
159
+
160
+ def test_function():
161
+ return 10
162
+
163
+ def test_different_types(fun):
164
+ object = Example_Class()
165
+ object_type = type(object)
166
+ func = test_function
167
+ func_type = type(func)
168
+ method = Example_Class.example_method
169
+ method_type = type(method)
170
+ lambda_fun = lambda x: x*10
171
+ lambda_fun_type = type(lambda_fun)
172
+ data = memory_graph.stack()
173
+ fun(data)
174
+
175
+
176
+ class Node:
177
+ shared_data = [1,2,3]
178
+
179
+ def __init__(self, value):
180
+ self.smaller = None
181
+ self.shared = Node.shared_data
182
+ self.value = value
183
+ self.larger = None
184
+
185
+ class BinTree:
186
+
187
+ def __init__(self):
188
+ self.root = None
189
+
190
+ def insert_recursive(self, node, value):
191
+ nn = None
192
+ if value < node.value:
193
+ if node.smaller is None:
194
+ nn = Node(value)
195
+ node.smaller = nn
196
+ else:
197
+ nn = self.insert_recursive(node.smaller, value)
198
+ else:
199
+ if node.larger is None:
200
+ nn = Node(value)
201
+ node.larger = nn
202
+ else:
203
+ nn = self.insert_recursive(node.larger, value)
204
+ return nn
205
+
206
+ def insert(self, value):
207
+ nn = None
208
+ if self.root is None:
209
+ nn = Node(value)
210
+ self.root = nn
211
+ else:
212
+ nn = self.insert_recursive(self.root, value)
213
+ return nn
214
+
215
+ def test_missing_edges(fun):
216
+ random.seed(0)
217
+ config.max_graph_depth = 7
218
+ config.max_missing_edges = 5
219
+ tree = BinTree()
220
+ last_node = None
221
+ n = 200
222
+ for i in range(n):
223
+ last_node = tree.insert(random.randint(0,n*10))
224
+ fun( memory_graph.stack() )
225
+
226
+ def test_all(fun):
227
+ pass
228
+ test_singular(fun)
229
+ test_linear(fun)
230
+ test_linears(fun)
231
+ test_colors(fun)
232
+ test_empty_linear(fun)
233
+ test_nested_list(fun)
234
+ test_key_value(fun)
235
+ test_class(fun)
236
+ test_class_vars(fun)
237
+ test_share_tuple(fun)
238
+ test_share_children(fun)
239
+ test_list_split(fun)
240
+ test_key_value_split(fun)
241
+ test_table(fun)
242
+ test_numpy(fun)
243
+ test_pandas(fun)
244
+ test_different_types(fun)
245
+ test_missing_edges(fun)
@@ -0,0 +1,27 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph as mg
6
+
7
+ def build_nested_list(depth = 15):
8
+ first = [1,2]
9
+ last = first
10
+ if depth>0:
11
+ first2, last = build_nested_list(depth-1)
12
+ first.append(first2)
13
+ return first, last
14
+
15
+ first,last = build_nested_list(15)
16
+ for i in range(20):
17
+ last.append('X')
18
+
19
+ child = ('who', 'are', 'my', 'parents?')
20
+ last[4] = child
21
+ last[5] = child
22
+ last[6] = child
23
+ last[7] = child
24
+ last[8] = child
25
+
26
+ mg.show([first,child])
27
+ #mg.show([first])
@@ -0,0 +1,15 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import memory_graph
6
+
7
+ import memory_graph.test as test
8
+
9
+ if __name__ == '__main__':
10
+ test_fun_count = 0
11
+ def test_fun(data):
12
+ global test_fun_count
13
+ memory_graph.render(data, f'test_graph{test_fun_count}.png')
14
+ test_fun_count += 1
15
+ test.test_all(test_fun)
@@ -0,0 +1,15 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+
6
+ import memory_graph.memory_to_nodes as memory_to_nodes
7
+ import memory_graph.config_helpers as config_helper
8
+
9
+ config_helper.set_config()
10
+
11
+ l1 = [1,2]
12
+ l2 = [3,4]
13
+ data = [l1,l2,l1,[5,l2]]
14
+ nodes = memory_to_nodes.memory_to_nodes(data)
15
+ #print(nodes)
@@ -0,0 +1,37 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ from memory_graph.sequence import Sequence1D, Sequence2D
6
+ from memory_graph.slicer import Slicer
7
+
8
+ def status(index):
9
+ if type(index) == tuple:
10
+ return index[0]
11
+ return index
12
+
13
+ def test_slicing(sequence, slicer):
14
+ print(sequence)
15
+ print(slicer)
16
+ for i in sequence.indices_all():
17
+ print(i, sequence[i])
18
+ slices = sequence.slice(slicer)
19
+ print('slices:',slices)
20
+ for index in slices:
21
+ print(index, ':', sequence[index])
22
+ for index in slices.table_iter(sequence.size()):
23
+ print(f'{index}: {sequence[index] if status(index)>=0 else None}')
24
+
25
+ def test_sequence():
26
+ sequence = Sequence1D([i for i in range(8)])
27
+ slicer = Slicer(2,3)
28
+ test_slicing(sequence, slicer)
29
+
30
+ width = 5
31
+ height = 6
32
+ sequence = Sequence2D([[x+y*width for x in range(width)] for y in range(height)])
33
+ slicer = (Slicer(1,2), Slicer(2,1))
34
+ test_slicing(sequence, slicer)
35
+
36
+ if __name__ == '__main__':
37
+ test_sequence()
@@ -0,0 +1,50 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ from memory_graph.slicer import Slicer
6
+
7
+ def test_slicer():
8
+ slicer = Slicer(0.1, 0.2, 0.3)
9
+ slices = slicer.get_slices(100)
10
+ assert slices.get_slices() == [[0, 10], [40, 60], [70, 100]], "Slicer error"
11
+
12
+ slicer = Slicer(10, 20, 30)
13
+ slices = slicer.get_slices(100)
14
+ assert slices.get_slices() == [[0, 10], [40, 60], [70, 100]], "Slicer error"
15
+
16
+ slicer = Slicer(0.1, 0.3)
17
+ slices = slicer.get_slices(100)
18
+ assert slices.get_slices() == [[0, 10], [70, 100]], "Slicer error"
19
+
20
+ slicer = Slicer(10, 30)
21
+ slices = slicer.get_slices(100)
22
+ assert slices.get_slices() == [[0, 10], [70, 100]], "Slicer error"
23
+
24
+ slicer = Slicer(0.1)
25
+ slices = slicer.get_slices(100)
26
+ assert slices.get_slices() == [[0, 10]], "Slicer error"
27
+
28
+ slicer = Slicer(10)
29
+ slices = slicer.get_slices(100)
30
+ assert slices.get_slices() == [[0, 10]], "Slicer error"
31
+
32
+ slicer = Slicer()
33
+ slices = slicer.get_slices(100)
34
+ assert slices.get_slices() == [[0, 100]], "Slicer error"
35
+
36
+ slicer = Slicer(2,2)
37
+ slices = slicer.get_slices(0)
38
+ assert slices.get_slices() == [], "Slicer error"
39
+
40
+ slicer = Slicer(2,2)
41
+ slices = slicer.get_slices(5)
42
+ assert slices.get_slices() == [[0,5]], "Slicer error"
43
+
44
+ slicer = Slicer(2,2)
45
+ slices = slicer.get_slices(6)
46
+ assert slices.get_slices() == [[0,2],[4,6]], "Slicer error"
47
+
48
+ if __name__ == '__main__':
49
+ test_slicer()
50
+ print('Slicer test passed')
@@ -0,0 +1,91 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+
6
+ from memory_graph.slices import Slices1D, Slices2D
7
+
8
+ def test_slices1d():
9
+ test = Slices1D( [[10,20], [30,40], [60,70], [80,90]] )
10
+ slices = test.copy()
11
+ slices.add_slice([21,79])
12
+ assert slices.get_slices() == [[10,90]], "Slice error: merging begin and end"
13
+
14
+ slices = test.copy()
15
+ slices.add_slice([31,39])
16
+ assert slices.get_slices() == [[10,20], [30,40], [60,70], [80,90]], "Slice error: merging begin and end"
17
+
18
+ slices = test.copy()
19
+ slices.add_slice([15,50])
20
+ assert slices.get_slices() == [[10,50], [60,70], [80,90]], "Slice error: merging begin"
21
+
22
+ slices = test.copy()
23
+ slices.add_slice([15,65])
24
+ assert slices.get_slices() == [[10,70], [80,90]], "Slice error: merging begin"
25
+
26
+ slices = test.copy()
27
+ slices.add_slice([35,45])
28
+ assert slices.get_slices() == [[10,20], [30,45], [60,70], [80,90]], "Slice error: merging begin"
29
+
30
+ slices = test.copy()
31
+ slices.add_slice([25,65])
32
+ assert slices.get_slices() == [[10,20], [25,70], [80,90]], "Slice error: merging end"
33
+
34
+ slices = test.copy()
35
+ slices.add_slice([15,65])
36
+ assert slices.get_slices() == [[10,70], [80,90]], "Slice error: merging end"
37
+
38
+ slices = test.copy()
39
+ slices.add_slice([55,65])
40
+ assert slices.get_slices() == [[10,20], [30,40], [55,70], [80,90]], "Slice error: merging end"
41
+
42
+ slices = test.copy()
43
+ slices.add_slice([25,75])
44
+ assert slices.get_slices() == [[10,20], [25,75], [80,90]], "Slice error: merging none"
45
+
46
+ slices = test.copy()
47
+ slices.add_slice([5,6])
48
+ assert slices.get_slices() == [[5,6], [10,20], [30,40], [60,70], [80,90]], "Slice error: merging none"
49
+
50
+ slices = test.copy()
51
+ slices.add_slice([95,96])
52
+ assert slices.get_slices() == [[10,20], [30,40], [60,70], [80,90], [95,96]], "Slice error: merging none"
53
+
54
+ slices = test.copy()
55
+ assert not slices.add_slice([10,11])
56
+ assert not slices.add_slice([19,20])
57
+ assert not slices.add_slice([30,31])
58
+ assert not slices.add_slice([39,40])
59
+ assert not slices.add_slice([65,66])
60
+ assert slices.add_slice([9,10])
61
+ assert slices.add_slice([20,21])
62
+ assert slices.add_slice([28,29])
63
+ assert slices.add_slice([41,42])
64
+ assert slices.add_slice([75,76])
65
+ assert slices.add_slice([100,200])
66
+
67
+ test = Slices1D( [ [i,i+2] for i in range(0,30,4)] )
68
+ #print('test:',test)
69
+ for index in range(30):
70
+ #print('index:',index, 'has_index:',test.has_index(index))
71
+ assert test.has_index(index) == ((index//2) % 2 == 0), f"Error: {index}"
72
+
73
+ def test_slices2d():
74
+ from memory_graph.slices import Slices
75
+ slices2d = Slices2D( Slices1D([[20,30]]),
76
+ Slices1D([[20,30]])
77
+ )
78
+
79
+ slices2d.add_index((19,19))
80
+ slices2d.add_index((31,31))
81
+ print(slices2d)
82
+ slices2d.add_index((18,19))
83
+ print(slices2d)
84
+ slices2d.add_index((19,18))
85
+ slices2d.add_index((30,30))
86
+ print(slices2d)
87
+
88
+ if __name__ == "__main__":
89
+ test_slices1d()
90
+ test_slices2d()
91
+ print("Slices: All tests pass")
@@ -0,0 +1,28 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+
6
+ from memory_graph.slices_iterator import Slices_Iterator1D, Slices_Iterator2D
7
+ from memory_graph.slices import Slices1D, Slices2D
8
+
9
+ def test_slices_iterator1d():
10
+ slices1d = Slices1D( [[10,20], [30,40], [60,70], [80,90]] )
11
+ iter = Slices_Iterator1D(slices1d)
12
+ for i in iter:
13
+ print(i)
14
+ assert list(Slices_Iterator1D(slices1d)) == [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89], "Slices_Iterator: Error in iteration"
15
+
16
+ def test_slices_iterator2d():
17
+ slices2d = Slices2D( Slices1D( [[10,12], [20,22]] ),
18
+ Slices1D( [[10,12], [30,32]] ) )
19
+ iter = Slices_Iterator2D(slices2d)
20
+ for i in iter:
21
+ print(i)
22
+ assert list(Slices_Iterator2D(slices2d)) == [(10, 10), (10, 11), (10, 30), (10, 31), (11, 10), (11, 11), (11, 30), (11, 31), (20, 10), (20, 11), (20, 30), (20, 31), (21, 10), (21, 11), (21, 30), (21, 31)]
23
+
24
+
25
+ if __name__ == '__main__':
26
+ test_slices_iterator1d()
27
+ test_slices_iterator2d()
28
+ print("Slices_Iterator: All tests pass")
memory_graph/utils.py ADDED
@@ -0,0 +1,105 @@
1
+ # This file is part of memory_graph.
2
+ # Copyright (c) 2023, Bas Terwijn.
3
+ # SPDX-License-Identifier: BSD-2-Clause
4
+
5
+ import math
6
+ import types
7
+
8
+ def has_dict_attributes(value):
9
+ """ Returns 'True' if 'value' has a '__dict__' attribute. """
10
+ return hasattr(value,"__dict__")
11
+
12
+ def get_dict_attributes(value):
13
+ """ Returns the items of the '__dict__' attribute of 'value'."""
14
+ return getattr(value,"__dict__")
15
+
16
+ def is_function(obj):
17
+ if isinstance(obj, types.FunctionType) or isinstance(obj, types.MethodType):
18
+ return True
19
+ return type(obj).__name__ in {'method_descriptor', 'builtin_function_or_method', 'getset_descriptor', 'classmethod_descriptor'}
20
+
21
+ def filter_dict(dictionary):
22
+ """ Filters out the unwanted dict attributes. """
23
+ if '__name__' in dictionary: # only filter stack frames, for example locals()
24
+ return [
25
+ (k,v) for k, v in dictionary.items() if
26
+ not (type(k) is str and k.startswith('__')) and
27
+ not isinstance(v,types.ModuleType) and
28
+ not is_function(v)
29
+ ]
30
+ return [
31
+ (k,v) for k, v in dictionary.items() if
32
+ not (type(k) is str and k.startswith('__'))
33
+ ]
34
+
35
+ def filter_type_attributes(tuples):
36
+ """ Filters out the unwanted type attributes (class/static methods). """
37
+ return [
38
+ (k,v) for k, v in tuples if
39
+ not (type(k) is str and k.startswith('__')) and
40
+ not type(v) in {classmethod, staticmethod} and
41
+ not callable(v)
42
+ ]
43
+
44
+ def make_sliceable(data):
45
+ """ Returns a sliceble version of data, convert to list if not yet sliceble. """
46
+ try:
47
+ data[0:0]
48
+ return data
49
+ except TypeError:
50
+ return list(data)
51
+
52
+ def is_finite_iterable(data):
53
+ """ Returns 'True' if 'data' is finite iterable. """
54
+ try:
55
+ iter(data) # iterable
56
+ len(data) # and not infinite (not a strong test, but what else?)
57
+ return True
58
+ except TypeError:
59
+ return False
60
+
61
+ def get_type_name(data):
62
+ """ Returns the name of the type of 'data'. """
63
+ return type(data).__name__
64
+
65
+ def nested_list(sizes, i=0, value=[0]):
66
+ """ Returns a nested list with the given 'sizes' for test purposes. """
67
+ if i == len(sizes)-1:
68
+ data = []
69
+ for _ in range(sizes[i]):
70
+ data.append( value[0] )
71
+ value[0]+=1
72
+ else:
73
+ data = []
74
+ for size in range(sizes[i]):
75
+ data.append( nested_list(sizes,i+1) )
76
+ return data
77
+
78
+ def my_round(value):
79
+ """ Rounds the value to the nearest integer rounding '.5' up consistantly. """
80
+ return math.floor(value + 0.5)
81
+
82
+ def generator_has_data(generator):
83
+ """ Returns 'True' if the generator has data. """
84
+ try:
85
+ next(generator)
86
+ return True
87
+ except StopIteration:
88
+ return False
89
+
90
+ def take_through(condition, iterable):
91
+ for i in iterable:
92
+ yield i
93
+ if condition(i):
94
+ return
95
+
96
+ def take_after(condition, iterable):
97
+ taking = False
98
+ for i in iterable:
99
+ if taking:
100
+ yield i
101
+ elif condition(i):
102
+ taking = True
103
+
104
+ if __name__ == '__main__':
105
+ print( nested_list([4,3,2]) )