jaseci 1.4.2.6__py3-none-any.whl → 2.0.0__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.
Potentially problematic release.
This version of jaseci might be problematic. Click here for more details.
- jaseci/__init__.py +3 -37
- jaseci-2.0.0.dist-info/METADATA +65 -0
- jaseci-2.0.0.dist-info/RECORD +4 -0
- {jaseci-1.4.2.6.dist-info → jaseci-2.0.0.dist-info}/WHEEL +1 -2
- jaseci/VERSION +0 -1
- jaseci/cli_tools/__init__.py +0 -0
- jaseci/cli_tools/book_tools.py +0 -457
- jaseci/cli_tools/jsctl.py +0 -500
- jaseci/cli_tools/tests/__init__.py +0 -0
- jaseci/cli_tools/tests/test_jsctl.py +0 -556
- jaseci/extens/__init__.py +0 -0
- jaseci/extens/act_lib/__init__.py +0 -0
- jaseci/extens/act_lib/date.py +0 -118
- jaseci/extens/act_lib/elastic.py +0 -87
- jaseci/extens/act_lib/file.py +0 -77
- jaseci/extens/act_lib/file_handler.py +0 -190
- jaseci/extens/act_lib/internal.py +0 -19
- jaseci/extens/act_lib/jaseci.py +0 -62
- jaseci/extens/act_lib/mail.py +0 -10
- jaseci/extens/act_lib/maths.py +0 -168
- jaseci/extens/act_lib/net.py +0 -192
- jaseci/extens/act_lib/rand.py +0 -83
- jaseci/extens/act_lib/regex.py +0 -85
- jaseci/extens/act_lib/request.py +0 -170
- jaseci/extens/act_lib/std.py +0 -236
- jaseci/extens/act_lib/storage.py +0 -53
- jaseci/extens/act_lib/stripe.py +0 -338
- jaseci/extens/act_lib/task.py +0 -14
- jaseci/extens/act_lib/tests/__init__.py +0 -0
- jaseci/extens/act_lib/tests/std_test_code.py +0 -37
- jaseci/extens/act_lib/tests/test_date.py +0 -26
- jaseci/extens/act_lib/tests/test_elastic.py +0 -159
- jaseci/extens/act_lib/tests/test_file.py +0 -116
- jaseci/extens/act_lib/tests/test_file_lib.py +0 -40
- jaseci/extens/act_lib/tests/test_mail_lib.py +0 -33
- jaseci/extens/act_lib/tests/test_maths.py +0 -147
- jaseci/extens/act_lib/tests/test_net_lib.py +0 -62
- jaseci/extens/act_lib/tests/test_regex.py +0 -61
- jaseci/extens/act_lib/tests/test_std.py +0 -51
- jaseci/extens/act_lib/tests/test_std_lib.py +0 -36
- jaseci/extens/act_lib/tests/test_url.py +0 -32
- jaseci/extens/act_lib/tests/test_vector.py +0 -36
- jaseci/extens/act_lib/tests/test_webtool.py +0 -44
- jaseci/extens/act_lib/tests/test_zlib.py +0 -24
- jaseci/extens/act_lib/url.py +0 -80
- jaseci/extens/act_lib/vector.py +0 -158
- jaseci/extens/act_lib/webtool.py +0 -29
- jaseci/extens/act_lib/zip.py +0 -34
- jaseci/extens/api/__init__.py +0 -0
- jaseci/extens/api/actions_api.py +0 -171
- jaseci/extens/api/alias_api.py +0 -140
- jaseci/extens/api/architype_api.py +0 -197
- jaseci/extens/api/config_api.py +0 -129
- jaseci/extens/api/global_api.py +0 -85
- jaseci/extens/api/graph_api.py +0 -168
- jaseci/extens/api/health_api.py +0 -21
- jaseci/extens/api/interface.py +0 -269
- jaseci/extens/api/jac_api.py +0 -172
- jaseci/extens/api/jsorc_api.py +0 -317
- jaseci/extens/api/logger_api.py +0 -90
- jaseci/extens/api/master_api.py +0 -134
- jaseci/extens/api/object_api.py +0 -102
- jaseci/extens/api/prometheus_api.py +0 -75
- jaseci/extens/api/queue_api.py +0 -141
- jaseci/extens/api/sentinel_api.py +0 -271
- jaseci/extens/api/share_api.py +0 -64
- jaseci/extens/api/super_api.py +0 -65
- jaseci/extens/api/tests/__init__.py +0 -0
- jaseci/extens/api/tests/test_architype_api.py +0 -66
- jaseci/extens/api/tests/test_global_api.py +0 -179
- jaseci/extens/api/tests/test_graph_api.py +0 -64
- jaseci/extens/api/tests/test_logger_api.py +0 -43
- jaseci/extens/api/tests/test_object_api.py +0 -20
- jaseci/extens/api/tests/test_sentinel_api.py +0 -66
- jaseci/extens/api/tests/test_uncommon.py +0 -107
- jaseci/extens/api/tests/test_user_api.py +0 -32
- jaseci/extens/api/tests/test_walker_api.py +0 -316
- jaseci/extens/api/user_api.py +0 -166
- jaseci/extens/api/walker_api.py +0 -299
- jaseci/extens/api/webhook_api.py +0 -77
- jaseci/extens/svc/__init__.py +0 -0
- jaseci/extens/svc/elastic_svc.py +0 -366
- jaseci/extens/svc/kube_svc.py +0 -432
- jaseci/extens/svc/mail_svc.py +0 -156
- jaseci/extens/svc/prome_svc.py +0 -378
- jaseci/extens/svc/redis_svc.py +0 -63
- jaseci/extens/svc/storage_svc.py +0 -193
- jaseci/extens/svc/stripe_svc.py +0 -51
- jaseci/extens/svc/task_svc.py +0 -155
- jaseci/extens/svc/tasks.py +0 -302
- jaseci/jac/__init__.py +0 -0
- jaseci/jac/interpreter/__init__.py +0 -0
- jaseci/jac/interpreter/architype_interp.py +0 -219
- jaseci/jac/interpreter/interp.py +0 -1784
- jaseci/jac/interpreter/sentinel_interp.py +0 -260
- jaseci/jac/interpreter/tests/__init__.py +0 -0
- jaseci/jac/interpreter/tests/test_interp.py +0 -42
- jaseci/jac/interpreter/walker_interp.py +0 -249
- jaseci/jac/ir/__init__.py +0 -0
- jaseci/jac/ir/ast.py +0 -73
- jaseci/jac/ir/ast_builder.py +0 -249
- jaseci/jac/ir/jac_code.py +0 -151
- jaseci/jac/ir/passes/__init__.py +0 -6
- jaseci/jac/ir/passes/ast_prune_pass.py +0 -9
- jaseci/jac/ir/passes/codegen_pass.py +0 -244
- jaseci/jac/ir/passes/ir_pass.py +0 -29
- jaseci/jac/ir/passes/printer_pass.py +0 -23
- jaseci/jac/ir/passes/pt_prune_pass.py +0 -29
- jaseci/jac/ir/passes/schedule.py +0 -23
- jaseci/jac/ir/passes/stats_pass.py +0 -16
- jaseci/jac/jac.g4 +0 -450
- jaseci/jac/jac_parse/__init__.py +0 -0
- jaseci/jac/jac_parse/jacLexer.py +0 -809
- jaseci/jac/jac_parse/jacListener.py +0 -853
- jaseci/jac/jac_parse/jacParser.py +0 -9192
- jaseci/jac/jac_set.py +0 -120
- jaseci/jac/jsci_vm/__init__.py +0 -0
- jaseci/jac/jsci_vm/disasm.py +0 -94
- jaseci/jac/jsci_vm/inst_ptr.py +0 -31
- jaseci/jac/jsci_vm/machine.py +0 -188
- jaseci/jac/jsci_vm/op_codes.py +0 -82
- jaseci/jac/jsci_vm/tests/__init__.py +0 -0
- jaseci/jac/jsci_vm/tests/test_codegen.py +0 -31
- jaseci/jac/machine/__init__.py +0 -0
- jaseci/jac/machine/jac_scope.py +0 -86
- jaseci/jac/machine/jac_value.py +0 -227
- jaseci/jac/machine/machine_state.py +0 -386
- jaseci/jac/tests/__init__.py +0 -0
- jaseci/jac/tests/book_code.py +0 -624
- jaseci/jac/tests/test_book.py +0 -380
- jaseci/jac/tests/test_lang_14.py +0 -49
- jaseci/jsorc/__init__.py +0 -7
- jaseci/jsorc/jsorc.py +0 -642
- jaseci/jsorc/jsorc_settings.py +0 -211
- jaseci/jsorc/jsorc_utils.py +0 -298
- jaseci/jsorc/live_actions.py +0 -365
- jaseci/jsorc/manifests/__init__.py +0 -0
- jaseci/jsorc/manifests/database.yaml +0 -109
- jaseci/jsorc/manifests/elastic.yaml +0 -6029
- jaseci/jsorc/manifests/prometheus.yaml +0 -1383
- jaseci/jsorc/manifests/redis.yaml +0 -64
- jaseci/jsorc/memory.py +0 -258
- jaseci/jsorc/redis.py +0 -140
- jaseci/jsorc/remote_actions.py +0 -158
- jaseci/jsorc/tests/__init__.py +0 -0
- jaseci/jsorc/tests/test_actions.py +0 -542
- jaseci/jsorc/tests/test_jsorc.py +0 -112
- jaseci/prim/__init__.py +0 -0
- jaseci/prim/ability.py +0 -94
- jaseci/prim/architype.py +0 -90
- jaseci/prim/edge.py +0 -173
- jaseci/prim/element.py +0 -233
- jaseci/prim/graph.py +0 -27
- jaseci/prim/master.py +0 -67
- jaseci/prim/node.py +0 -533
- jaseci/prim/obj_mixins.py +0 -238
- jaseci/prim/sentinel.py +0 -282
- jaseci/prim/super_master.py +0 -31
- jaseci/prim/walker.py +0 -261
- jaseci/svc/__init__.py +0 -0
- jaseci/tests/__init__.py +0 -0
- jaseci/tests/infer.py +0 -39
- jaseci/tests/jac_test_code.py +0 -1293
- jaseci/tests/jac_test_progs.py +0 -774
- jaseci/tests/test_core.py +0 -153
- jaseci/tests/test_jac.py +0 -824
- jaseci/tests/test_node.py +0 -89
- jaseci/tests/test_progs.py +0 -702
- jaseci/tests/test_stack.py +0 -220
- jaseci/tests/test_stripe.py +0 -225
- jaseci/utils/__init__.py +0 -0
- jaseci/utils/actions/__init__.py +0 -0
- jaseci/utils/actions/actions_manager.py +0 -254
- jaseci/utils/actions/actions_optimizer.py +0 -517
- jaseci/utils/actions/actions_state.py +0 -95
- jaseci/utils/file_handler.py +0 -171
- jaseci/utils/gprof2dot.py +0 -3786
- jaseci/utils/id_list.py +0 -169
- jaseci/utils/json_handler.py +0 -70
- jaseci/utils/log_utils.py +0 -57
- jaseci/utils/test_core.py +0 -62
- jaseci/utils/utils.py +0 -387
- jaseci-1.4.2.6.dist-info/LICENSE +0 -21
- jaseci-1.4.2.6.dist-info/METADATA +0 -39
- jaseci-1.4.2.6.dist-info/RECORD +0 -185
- jaseci-1.4.2.6.dist-info/entry_points.txt +0 -3
- jaseci-1.4.2.6.dist-info/top_level.txt +0 -1
jaseci/prim/node.py
DELETED
|
@@ -1,533 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Node class for Jaseci
|
|
3
|
-
|
|
4
|
-
Each node has an id, name, timestamp and it's set of edges.
|
|
5
|
-
First node in list of 'member_node_ids' is designated root node
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from collections import OrderedDict
|
|
9
|
-
from jaseci.prim.element import Element
|
|
10
|
-
from jaseci.prim.obj_mixins import Anchored
|
|
11
|
-
from jaseci.prim.edge import Edge
|
|
12
|
-
from jaseci.utils.id_list import IdList
|
|
13
|
-
from jaseci.utils.utils import logger
|
|
14
|
-
|
|
15
|
-
import uuid
|
|
16
|
-
|
|
17
|
-
TO = 0
|
|
18
|
-
FROM = 1
|
|
19
|
-
BI = 2
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class Node(Element, Anchored):
|
|
23
|
-
"""Node class for Jaseci"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, dimension=0, **kwargs):
|
|
26
|
-
self.edge_ids = IdList(self)
|
|
27
|
-
self.fast_edges = {} # {name: [[NODEID, DIR, EDGEID, CONTEXT],...]}
|
|
28
|
-
self._fast_edge_ids = IdList(self)
|
|
29
|
-
self.parent_node_ids = IdList(self)
|
|
30
|
-
self.member_node_ids = IdList(self)
|
|
31
|
-
self.dimension = dimension # Nodes are always hdgd 0
|
|
32
|
-
Element.__init__(self, **kwargs)
|
|
33
|
-
Anchored.__init__(self)
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def smart_edges(self):
|
|
37
|
-
obj_list = self.smart_edge_list.obj_list()
|
|
38
|
-
for i in obj_list:
|
|
39
|
-
if i.is_fast() and i.jid in self.edge_ids:
|
|
40
|
-
self.edge_ids.remove_obj(i)
|
|
41
|
-
self._fast_edge_ids.remove_obj(i)
|
|
42
|
-
self.smart_add_edge(i)
|
|
43
|
-
return obj_list
|
|
44
|
-
|
|
45
|
-
@property
|
|
46
|
-
def smart_edge_list(self):
|
|
47
|
-
if not len(self._fast_edge_ids):
|
|
48
|
-
self.smart_build_fast_edge_ids()
|
|
49
|
-
return self._fast_edge_ids
|
|
50
|
-
|
|
51
|
-
def smart_build_fast_edge_ids(self):
|
|
52
|
-
self._fast_edge_ids = IdList(self, in_list=self.edge_ids)
|
|
53
|
-
for k in self.fast_edges.keys():
|
|
54
|
-
for v in self.fast_edges[k]:
|
|
55
|
-
link_order = [v[0], self.jid] if v[1] == FROM else [self.jid, v[0]]
|
|
56
|
-
if len(v) > 2 and self._h.has_obj(v[2]):
|
|
57
|
-
edge = self._h.get_obj(self._m_id, v[2])
|
|
58
|
-
if len(v) > 3:
|
|
59
|
-
v[3] = edge.context
|
|
60
|
-
else:
|
|
61
|
-
v.append(edge.context)
|
|
62
|
-
else:
|
|
63
|
-
edge = Edge(
|
|
64
|
-
m_id=self._m_id, h=self._h, kind="edge", name=k, auto_save=False
|
|
65
|
-
)
|
|
66
|
-
edge.from_node_id = link_order[0]
|
|
67
|
-
edge.to_node_id = link_order[1]
|
|
68
|
-
edge.bidirected = v[1] == BI
|
|
69
|
-
edge.jid = v[2] if len(v) > 2 else uuid.uuid4().urn
|
|
70
|
-
edge.context = v[3] if len(v) > 3 else {}
|
|
71
|
-
# old `edge.save()` might be confusing
|
|
72
|
-
# this line doesn't mean it has to be saved on db
|
|
73
|
-
# it only needs to be available on cache (memory, redis)
|
|
74
|
-
self._h.commit_obj_to_cache(edge, True)
|
|
75
|
-
self._fast_edge_ids.add_obj(edge, bypass=True)
|
|
76
|
-
|
|
77
|
-
def smart_add_edge(self, obj):
|
|
78
|
-
# make sure fast edges built
|
|
79
|
-
if not len(self._fast_edge_ids):
|
|
80
|
-
self.smart_build_fast_edge_ids()
|
|
81
|
-
# add new edge
|
|
82
|
-
self._fast_edge_ids.add_obj(obj)
|
|
83
|
-
# then store how needed
|
|
84
|
-
if obj.is_fast():
|
|
85
|
-
self.smart_edge_to_fast_edge(obj)
|
|
86
|
-
else:
|
|
87
|
-
self.edge_ids.add_obj(obj)
|
|
88
|
-
|
|
89
|
-
def smart_edge_to_fast_edge(self, obj):
|
|
90
|
-
if obj.name not in self.fast_edges:
|
|
91
|
-
self.fast_edges[obj.name] = []
|
|
92
|
-
details = [
|
|
93
|
-
obj.opposing_node(self).jid,
|
|
94
|
-
BI if obj.is_bidirected() else TO if obj.from_node() == self else FROM,
|
|
95
|
-
obj.jid,
|
|
96
|
-
obj.context,
|
|
97
|
-
]
|
|
98
|
-
self.fast_edges[obj.name].append(details)
|
|
99
|
-
|
|
100
|
-
def smart_remove_edge(self, obj):
|
|
101
|
-
if obj.is_fast():
|
|
102
|
-
pluck = None
|
|
103
|
-
for i in self.fast_edges[obj.name]:
|
|
104
|
-
other_node_id = obj.to_node_id if i[1] == TO else obj.from_node_id
|
|
105
|
-
if i[0] == other_node_id:
|
|
106
|
-
if obj.is_bidirected() or not (
|
|
107
|
-
i[1] == TO and obj.to_node() == self
|
|
108
|
-
):
|
|
109
|
-
pluck = i
|
|
110
|
-
break
|
|
111
|
-
self.fast_edges[obj.name].remove(pluck)
|
|
112
|
-
if not len(self.fast_edges[obj.name]):
|
|
113
|
-
del self.fast_edges[obj.name]
|
|
114
|
-
elif obj and obj.jid in self.edge_ids:
|
|
115
|
-
self.edge_ids.remove_obj(obj)
|
|
116
|
-
self.clear_fast_edge_ids()
|
|
117
|
-
self.save()
|
|
118
|
-
|
|
119
|
-
def clear_fast_edge_ids(self):
|
|
120
|
-
self._fast_edge_ids = IdList(self)
|
|
121
|
-
|
|
122
|
-
def attach(self, node_obj, edge_set=None, as_outbound=True, as_bidirected=False):
|
|
123
|
-
"""
|
|
124
|
-
Generalized attach function for attaching nodes with edges
|
|
125
|
-
"""
|
|
126
|
-
if edge_set is None:
|
|
127
|
-
edge_set = [
|
|
128
|
-
Edge(
|
|
129
|
-
m_id=self._m_id,
|
|
130
|
-
h=self._h,
|
|
131
|
-
kind="edge",
|
|
132
|
-
name="generic",
|
|
133
|
-
)
|
|
134
|
-
]
|
|
135
|
-
link_order = [self, node_obj] if as_outbound else [node_obj, self]
|
|
136
|
-
for e in edge_set:
|
|
137
|
-
if not e.connect(link_order[0], link_order[1]):
|
|
138
|
-
# Node not found error logged in set node function
|
|
139
|
-
return []
|
|
140
|
-
e.set_bidirected(as_bidirected)
|
|
141
|
-
# save and return
|
|
142
|
-
self.save()
|
|
143
|
-
node_obj.save()
|
|
144
|
-
return edge_set
|
|
145
|
-
|
|
146
|
-
def attach_outbound(self, node_obj, edge_set=None):
|
|
147
|
-
"""
|
|
148
|
-
Creates edge to a node and returns the edge
|
|
149
|
-
edge_set is the list of edges to be used to make connections
|
|
150
|
-
new edge is created if edge_set is empty
|
|
151
|
-
"""
|
|
152
|
-
return self.attach(node_obj, edge_set, as_outbound=True)
|
|
153
|
-
|
|
154
|
-
def attach_inbound(self, node_obj, edge_set=None):
|
|
155
|
-
"""
|
|
156
|
-
Creates edge from a node and returns the edge
|
|
157
|
-
edge_set is the list of edges to be used to make connections
|
|
158
|
-
new edge is created if edge_set is empty
|
|
159
|
-
"""
|
|
160
|
-
return self.attach(node_obj, edge_set, as_outbound=False)
|
|
161
|
-
|
|
162
|
-
def attach_bidirected(self, node_obj, edge_set=None):
|
|
163
|
-
"""
|
|
164
|
-
Creates bidirected edge to node returns the edge
|
|
165
|
-
edge_set is the list of edges to be used to make connections
|
|
166
|
-
new edge is created if edge_set is empty
|
|
167
|
-
"""
|
|
168
|
-
return self.attach(node_obj, edge_set, as_bidirected=True)
|
|
169
|
-
|
|
170
|
-
def detach(
|
|
171
|
-
self,
|
|
172
|
-
node_obj,
|
|
173
|
-
edge_set=None,
|
|
174
|
-
as_outbound=True,
|
|
175
|
-
as_bidirected=False,
|
|
176
|
-
ignore_direction=False,
|
|
177
|
-
silent=True,
|
|
178
|
-
):
|
|
179
|
-
"""
|
|
180
|
-
Generalized detach function for detaching nodes with edges
|
|
181
|
-
"""
|
|
182
|
-
if edge_set is None:
|
|
183
|
-
edge_set = self.attached_edges(node_obj)
|
|
184
|
-
link_order = [self, node_obj] if as_outbound else [node_obj, self]
|
|
185
|
-
num_detached = 0
|
|
186
|
-
for e in edge_set:
|
|
187
|
-
# validate edge connection exists
|
|
188
|
-
if not e.connects(
|
|
189
|
-
link_order[0], link_order[1], ignore_direction=ignore_direction
|
|
190
|
-
):
|
|
191
|
-
if not silent:
|
|
192
|
-
logger.warning(
|
|
193
|
-
str(
|
|
194
|
-
f"{e} does not connect "
|
|
195
|
-
f"{link_order[0]} to {link_order[1]}"
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
continue
|
|
199
|
-
if as_bidirected and not ignore_direction and not e.is_bidirected():
|
|
200
|
-
if not silent:
|
|
201
|
-
logger.warning(str(f"{e} is not a bidirected edge "))
|
|
202
|
-
continue
|
|
203
|
-
# destroy edge
|
|
204
|
-
num_detached += 1
|
|
205
|
-
e.destroy()
|
|
206
|
-
return num_detached
|
|
207
|
-
|
|
208
|
-
def detach_outbound(self, node_obj, edge_set=None, silent=True):
|
|
209
|
-
"""
|
|
210
|
-
Destroy edges to a node
|
|
211
|
-
edge_set is the list of edges to be detached (and distroyed)
|
|
212
|
-
all edges are deteached and destroyed if edge_set empty
|
|
213
|
-
returns number of detachments
|
|
214
|
-
"""
|
|
215
|
-
return self.detach(node_obj, edge_set, as_outbound=True)
|
|
216
|
-
|
|
217
|
-
def detach_inbound(self, node_obj, edge_set=None, silent=True):
|
|
218
|
-
"""
|
|
219
|
-
Destroy edges from a node
|
|
220
|
-
edge_set is the list of edges to be detached (and distroyed)
|
|
221
|
-
all edges are deteached and destroyed if edge_set empty
|
|
222
|
-
returns number of detachments
|
|
223
|
-
"""
|
|
224
|
-
return self.detach(node_obj, edge_set, as_outbound=False)
|
|
225
|
-
|
|
226
|
-
def detach_bidirected(self, node_obj, edge_set=None, silent=True):
|
|
227
|
-
"""
|
|
228
|
-
Destroy bidirected edges between nodes
|
|
229
|
-
edge_set is the list of edges to be detached (and distroyed)
|
|
230
|
-
all edges are deteached and destroyed if edge_set empty
|
|
231
|
-
returns number of detachments
|
|
232
|
-
"""
|
|
233
|
-
return self.detach(node_obj, edge_set, as_bidirected=True)
|
|
234
|
-
|
|
235
|
-
def detach_edges(self, node_obj, edge_set=None, silent=True):
|
|
236
|
-
"""
|
|
237
|
-
Destroy given edges between nodes without checking orientation
|
|
238
|
-
edge_set is the list of edges to be detached (and distroyed)
|
|
239
|
-
all edges are deteached and destroyed if edge_set empty
|
|
240
|
-
returns number of detachments
|
|
241
|
-
"""
|
|
242
|
-
return self.detach(node_obj, edge_set, ignore_direction=True)
|
|
243
|
-
|
|
244
|
-
def destroy_outbound(self, node_obj, edge_set=None):
|
|
245
|
-
"""
|
|
246
|
-
Destroys attached node and all relevant edges
|
|
247
|
-
Node and all edges are destroyed if edge_set empty
|
|
248
|
-
"""
|
|
249
|
-
if edge_set is None:
|
|
250
|
-
edge_set = self.outbound_edges(node_obj)
|
|
251
|
-
if self.detach_outbound(node_obj, edge_set):
|
|
252
|
-
node_obj.destroy()
|
|
253
|
-
|
|
254
|
-
def destroy_inbound(self, node_obj, edge_set=None):
|
|
255
|
-
"""
|
|
256
|
-
Destroys attached node and all relevant edges
|
|
257
|
-
Node and all edges are destroyed if edge_set empty
|
|
258
|
-
"""
|
|
259
|
-
if edge_set is None:
|
|
260
|
-
edge_set = self.inbound_edges(node_obj)
|
|
261
|
-
if self.detach_inbound(node_obj, edge_set):
|
|
262
|
-
node_obj.destroy()
|
|
263
|
-
|
|
264
|
-
def destroy_bidirected(self, node_obj, edge_set=None):
|
|
265
|
-
"""
|
|
266
|
-
Destroys attached node and all relevant edges
|
|
267
|
-
Node and all edges are destroyed if edge_set empty
|
|
268
|
-
"""
|
|
269
|
-
if edge_set is None:
|
|
270
|
-
edge_set = self.bidirected_edges(node_obj)
|
|
271
|
-
if self.detach_bidirected(node_obj, edge_set):
|
|
272
|
-
node_obj.destroy()
|
|
273
|
-
|
|
274
|
-
def is_attached_out(self, node_obj, edge_set=None):
|
|
275
|
-
"""
|
|
276
|
-
Tests whether edges attach to a node
|
|
277
|
-
"""
|
|
278
|
-
out_set = self.outbound_edges(node_obj)
|
|
279
|
-
if edge_set is None:
|
|
280
|
-
return len(out_set)
|
|
281
|
-
else:
|
|
282
|
-
for e in edge_set:
|
|
283
|
-
if e not in out_set:
|
|
284
|
-
return False
|
|
285
|
-
return True
|
|
286
|
-
|
|
287
|
-
def is_attached_in(self, node_obj, edge_set=None):
|
|
288
|
-
"""
|
|
289
|
-
Tests whether edges attach from a node
|
|
290
|
-
"""
|
|
291
|
-
in_set = self.inbound_edges(node_obj)
|
|
292
|
-
if edge_set is None:
|
|
293
|
-
return len(in_set)
|
|
294
|
-
else:
|
|
295
|
-
for e in edge_set:
|
|
296
|
-
if e not in in_set:
|
|
297
|
-
return False
|
|
298
|
-
return True
|
|
299
|
-
|
|
300
|
-
def is_attached_bi(self, node_obj, edge_set=None):
|
|
301
|
-
"""
|
|
302
|
-
Tests whether edges attach either to or from a node
|
|
303
|
-
"""
|
|
304
|
-
bi_set = self.bidirected_edges(node_obj)
|
|
305
|
-
if edge_set is None:
|
|
306
|
-
return len(bi_set)
|
|
307
|
-
else:
|
|
308
|
-
for e in edge_set:
|
|
309
|
-
if e not in bi_set:
|
|
310
|
-
return False
|
|
311
|
-
return True
|
|
312
|
-
|
|
313
|
-
def outbound_edges(self, node_obj=None):
|
|
314
|
-
"""Returns list of all edges out of node"""
|
|
315
|
-
edge_set = []
|
|
316
|
-
for e in self.smart_edges:
|
|
317
|
-
if not e.is_bidirected() and e.connects(self, node_obj):
|
|
318
|
-
edge_set.append(e)
|
|
319
|
-
return edge_set
|
|
320
|
-
|
|
321
|
-
def inbound_edges(self, node_obj=None):
|
|
322
|
-
"""Returns list of all edges in to node"""
|
|
323
|
-
edge_set = []
|
|
324
|
-
for e in self.smart_edges:
|
|
325
|
-
if not e.is_bidirected() and e.connects(node_obj, self):
|
|
326
|
-
edge_set.append(e)
|
|
327
|
-
return edge_set
|
|
328
|
-
|
|
329
|
-
def bidirected_edges(self, node_obj=None):
|
|
330
|
-
"""Returns list of all edges between nodes"""
|
|
331
|
-
edge_set = []
|
|
332
|
-
for e in self.smart_edges:
|
|
333
|
-
if e.is_bidirected() and e.connects(self, node_obj):
|
|
334
|
-
edge_set.append(e)
|
|
335
|
-
return edge_set
|
|
336
|
-
|
|
337
|
-
def attached_edges(self, node_obj=None, silent=False):
|
|
338
|
-
"""
|
|
339
|
-
Returns the edges connecting self to or from a node
|
|
340
|
-
|
|
341
|
-
silent is used to indicate whther the edge is intened to be used.
|
|
342
|
-
(effectively turns off error checking when false)
|
|
343
|
-
"""
|
|
344
|
-
edge_set = (
|
|
345
|
-
self.outbound_edges(node_obj)
|
|
346
|
-
+ self.inbound_edges(node_obj)
|
|
347
|
-
+ self.bidirected_edges(node_obj)
|
|
348
|
-
)
|
|
349
|
-
if not silent and edge_set is None:
|
|
350
|
-
logger.error(str(f"No edges found between {self} and {node_obj}"))
|
|
351
|
-
return edge_set
|
|
352
|
-
|
|
353
|
-
def outbound_nodes(self, edge_set=None):
|
|
354
|
-
"""Returns list of all nodes connected by edges out"""
|
|
355
|
-
if edge_set is None:
|
|
356
|
-
edge_set = self.smart_edges
|
|
357
|
-
ret_list = []
|
|
358
|
-
for e in edge_set:
|
|
359
|
-
if not e.is_bidirected() and e.connects(source=self):
|
|
360
|
-
ret_list.append(e.to_node())
|
|
361
|
-
return ret_list
|
|
362
|
-
|
|
363
|
-
def inbound_nodes(self, edge_set=None):
|
|
364
|
-
"""Returns list of all nodes connected by edges in"""
|
|
365
|
-
if edge_set is None:
|
|
366
|
-
edge_set = self.smart_edges
|
|
367
|
-
ret_list = []
|
|
368
|
-
for e in edge_set:
|
|
369
|
-
if not e.is_bidirected() and e.connects(target=self):
|
|
370
|
-
ret_list.append(e.from_node())
|
|
371
|
-
return ret_list
|
|
372
|
-
|
|
373
|
-
def bidirected_nodes(self, edge_set=None):
|
|
374
|
-
"""Returns list of all nodes connected by edges"""
|
|
375
|
-
if edge_set is None:
|
|
376
|
-
edge_set = self.smart_edges
|
|
377
|
-
ret_list = []
|
|
378
|
-
for e in edge_set:
|
|
379
|
-
if e.is_bidirected():
|
|
380
|
-
ret_list.append(e.opposing_node(self))
|
|
381
|
-
return ret_list
|
|
382
|
-
|
|
383
|
-
def attached_nodes(self):
|
|
384
|
-
"""Returns list of all nodes connected"""
|
|
385
|
-
edge_set = self.smart_edges
|
|
386
|
-
ret_list = []
|
|
387
|
-
for e in edge_set:
|
|
388
|
-
ret_list.append(e.opposing_node(self))
|
|
389
|
-
return ret_list
|
|
390
|
-
|
|
391
|
-
def dimension_matches(self, node_obj, silent=True):
|
|
392
|
-
"""Test if dimension matches another node"""
|
|
393
|
-
matches = self.dimension == node_obj.dimension
|
|
394
|
-
if not matches and not silent:
|
|
395
|
-
logger.error(
|
|
396
|
-
str(
|
|
397
|
-
"'{}' cant connect to '{}' - dim mismatch {}->{}".format(
|
|
398
|
-
self, node_obj, self.dimension, node_obj.dimension
|
|
399
|
-
)
|
|
400
|
-
)
|
|
401
|
-
)
|
|
402
|
-
return matches
|
|
403
|
-
|
|
404
|
-
def make_member_of(self, node_obj):
|
|
405
|
-
"""
|
|
406
|
-
Adds node to higher dimension node and does relevant checks
|
|
407
|
-
"""
|
|
408
|
-
# check if valid inclusion
|
|
409
|
-
if node_obj.dimension != self.dimension + 1:
|
|
410
|
-
logger.error(
|
|
411
|
-
str(
|
|
412
|
-
"'{}' cant be member to '{}' - dimension mismatch {}->{}".format(
|
|
413
|
-
self, node_obj, self.dimension, node_obj.dimension
|
|
414
|
-
)
|
|
415
|
-
)
|
|
416
|
-
)
|
|
417
|
-
# adds self to hdgd and hdgd to list of owners
|
|
418
|
-
else:
|
|
419
|
-
node_obj.member_node_ids.add_obj(self)
|
|
420
|
-
self.parent_node_ids.add_obj(node_obj)
|
|
421
|
-
|
|
422
|
-
def make_owner_of(self, node_obj):
|
|
423
|
-
"""
|
|
424
|
-
Adds node to lower dimension node and does relevant checks
|
|
425
|
-
"""
|
|
426
|
-
node_obj.make_member_of(self)
|
|
427
|
-
|
|
428
|
-
def leave_memebership_of(self, node_obj):
|
|
429
|
-
"""Remove node from higher dimension node"""
|
|
430
|
-
node_obj.member_node_ids.remove_obj(self)
|
|
431
|
-
self.parent_node_ids.remove_obj(node_obj)
|
|
432
|
-
|
|
433
|
-
def disown(self, node_obj):
|
|
434
|
-
"""Remove node from higher dimension node"""
|
|
435
|
-
node_obj.leave_membership_of(self)
|
|
436
|
-
|
|
437
|
-
def destroy(self):
|
|
438
|
-
"""
|
|
439
|
-
Destroys self from memory and persistent storage
|
|
440
|
-
"""
|
|
441
|
-
for i in self.smart_edges:
|
|
442
|
-
i.destroy()
|
|
443
|
-
super().destroy()
|
|
444
|
-
|
|
445
|
-
def dot_str(self, node_map=None, detailed=False):
|
|
446
|
-
"""
|
|
447
|
-
DOT representation
|
|
448
|
-
"""
|
|
449
|
-
|
|
450
|
-
def handle_str(str):
|
|
451
|
-
return str[:32].replace('"', '\\"')
|
|
452
|
-
|
|
453
|
-
if node_map is None:
|
|
454
|
-
nid = f"{uuid.UUID(self.jid).hex}"
|
|
455
|
-
else:
|
|
456
|
-
nid = f"{node_map.index(self.jid)}"
|
|
457
|
-
|
|
458
|
-
dstr = f'"n{nid}" [ '
|
|
459
|
-
|
|
460
|
-
if detailed:
|
|
461
|
-
dstr += f'id="{uuid.UUID(self.jid).hex}", '
|
|
462
|
-
|
|
463
|
-
dstr += f'label="n{nid}:{self.name}" '
|
|
464
|
-
|
|
465
|
-
node_dict = self.context
|
|
466
|
-
for i in self.private_values():
|
|
467
|
-
node_dict.pop(i)
|
|
468
|
-
|
|
469
|
-
if node_dict and detailed:
|
|
470
|
-
for k, v in node_dict.items():
|
|
471
|
-
if not isinstance(v, str) or v == "":
|
|
472
|
-
continue
|
|
473
|
-
dstr += f', {k}="{handle_str(v)}"'
|
|
474
|
-
|
|
475
|
-
dstr += " ]"
|
|
476
|
-
|
|
477
|
-
return dstr + "\n"
|
|
478
|
-
|
|
479
|
-
def get_all_architypes(self, depth: int = 0):
|
|
480
|
-
"""
|
|
481
|
-
Returns all reachable architypes
|
|
482
|
-
"""
|
|
483
|
-
|
|
484
|
-
childs = {self.jid: self}
|
|
485
|
-
|
|
486
|
-
edges = OrderedDict()
|
|
487
|
-
nodes = OrderedDict(childs)
|
|
488
|
-
|
|
489
|
-
depth -= 1
|
|
490
|
-
|
|
491
|
-
while len(childs) and depth != 0:
|
|
492
|
-
new_childs = OrderedDict()
|
|
493
|
-
|
|
494
|
-
for node in childs.values():
|
|
495
|
-
for edge in node.attached_edges():
|
|
496
|
-
if not (edge.jid in edges):
|
|
497
|
-
n_node = False
|
|
498
|
-
to_node = edge.to_node()
|
|
499
|
-
|
|
500
|
-
if to_node == node:
|
|
501
|
-
n_node = edge.from_node()
|
|
502
|
-
else:
|
|
503
|
-
n_node = to_node
|
|
504
|
-
|
|
505
|
-
if not (n_node.jid in nodes):
|
|
506
|
-
edges.update({edge.jid: edge})
|
|
507
|
-
new_childs.update({n_node.jid: n_node})
|
|
508
|
-
else:
|
|
509
|
-
edges.update({edge.jid: edge})
|
|
510
|
-
|
|
511
|
-
childs = new_childs
|
|
512
|
-
nodes.update(childs)
|
|
513
|
-
depth -= 1
|
|
514
|
-
|
|
515
|
-
return nodes, edges
|
|
516
|
-
|
|
517
|
-
def traversing_dot_str(self, detailed=False, depth: int = 0):
|
|
518
|
-
"""
|
|
519
|
-
DOT representation for graph.
|
|
520
|
-
NOTE: This is different from the dot_str method for node intentionally
|
|
521
|
-
because graph inherits node.
|
|
522
|
-
"""
|
|
523
|
-
nodes, edges = self.get_all_architypes(depth)
|
|
524
|
-
|
|
525
|
-
# Construct the graph string
|
|
526
|
-
dstr = ""
|
|
527
|
-
dstr += f"strict digraph {self.name} {{\n"
|
|
528
|
-
for n in nodes.values():
|
|
529
|
-
dstr += f" {n.dot_str(list(nodes.keys()), detailed)}"
|
|
530
|
-
for e in edges.values():
|
|
531
|
-
dstr += f" {e.dot_str(list(nodes.keys()), list(edges.keys()), detailed)}"
|
|
532
|
-
dstr += "}"
|
|
533
|
-
return dstr
|