infrahub-server 1.2.5__py3-none-any.whl → 1.2.7__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.
- infrahub/cli/db.py +2 -0
- infrahub/cli/patch.py +153 -0
- infrahub/computed_attribute/models.py +81 -1
- infrahub/computed_attribute/tasks.py +34 -53
- infrahub/core/manager.py +15 -2
- infrahub/core/node/__init__.py +4 -1
- infrahub/core/query/ipam.py +7 -5
- infrahub/core/registry.py +2 -3
- infrahub/core/schema/schema_branch.py +34 -37
- infrahub/database/__init__.py +2 -0
- infrahub/graphql/manager.py +10 -0
- infrahub/graphql/mutations/main.py +4 -5
- infrahub/graphql/mutations/resource_manager.py +3 -3
- infrahub/patch/__init__.py +0 -0
- infrahub/patch/constants.py +13 -0
- infrahub/patch/edge_adder.py +64 -0
- infrahub/patch/edge_deleter.py +33 -0
- infrahub/patch/edge_updater.py +28 -0
- infrahub/patch/models.py +98 -0
- infrahub/patch/plan_reader.py +107 -0
- infrahub/patch/plan_writer.py +92 -0
- infrahub/patch/queries/__init__.py +0 -0
- infrahub/patch/queries/base.py +17 -0
- infrahub/patch/runner.py +254 -0
- infrahub/patch/vertex_adder.py +61 -0
- infrahub/patch/vertex_deleter.py +33 -0
- infrahub/patch/vertex_updater.py +28 -0
- infrahub/tasks/registry.py +4 -1
- infrahub_sdk/checks.py +1 -1
- infrahub_sdk/ctl/cli_commands.py +2 -2
- infrahub_sdk/ctl/menu.py +56 -13
- infrahub_sdk/ctl/object.py +55 -5
- infrahub_sdk/ctl/utils.py +22 -1
- infrahub_sdk/exceptions.py +19 -1
- infrahub_sdk/node.py +42 -26
- infrahub_sdk/protocols_generator/__init__.py +0 -0
- infrahub_sdk/protocols_generator/constants.py +28 -0
- infrahub_sdk/{code_generator.py → protocols_generator/generator.py} +47 -34
- infrahub_sdk/protocols_generator/template.j2 +114 -0
- infrahub_sdk/schema/__init__.py +110 -74
- infrahub_sdk/schema/main.py +36 -2
- infrahub_sdk/schema/repository.py +2 -0
- infrahub_sdk/spec/menu.py +3 -3
- infrahub_sdk/spec/object.py +522 -41
- infrahub_sdk/testing/docker.py +4 -5
- infrahub_sdk/testing/schemas/animal.py +7 -0
- infrahub_sdk/yaml.py +63 -7
- {infrahub_server-1.2.5.dist-info → infrahub_server-1.2.7.dist-info}/METADATA +1 -1
- {infrahub_server-1.2.5.dist-info → infrahub_server-1.2.7.dist-info}/RECORD +56 -39
- infrahub_testcontainers/container.py +52 -2
- infrahub_testcontainers/docker-compose.test.yml +27 -0
- infrahub_testcontainers/performance_test.py +1 -1
- infrahub_testcontainers/plugin.py +1 -1
- infrahub_sdk/ctl/constants.py +0 -115
- {infrahub_server-1.2.5.dist-info → infrahub_server-1.2.7.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.2.5.dist-info → infrahub_server-1.2.7.dist-info}/WHEEL +0 -0
- {infrahub_server-1.2.5.dist-info → infrahub_server-1.2.7.dist-info}/entry_points.txt +0 -0
infrahub_sdk/node.py
CHANGED
|
@@ -479,7 +479,7 @@ class RelationshipManagerBase:
|
|
|
479
479
|
"""
|
|
480
480
|
data: dict[str, Any] = {
|
|
481
481
|
"count": None,
|
|
482
|
-
"edges": {"node": {"id": None, "display_label": None, "__typename": None}},
|
|
482
|
+
"edges": {"node": {"id": None, "hfid": None, "display_label": None, "__typename": None}},
|
|
483
483
|
}
|
|
484
484
|
|
|
485
485
|
properties: dict[str, Any] = {}
|
|
@@ -569,7 +569,9 @@ class RelationshipManager(RelationshipManagerBase):
|
|
|
569
569
|
raise UninitializedError("Must call fetch() on RelationshipManager before editing members")
|
|
570
570
|
new_node = RelatedNode(schema=self.schema, client=self.client, branch=self.branch, data=data)
|
|
571
571
|
|
|
572
|
-
if new_node.id and new_node.id not in self.peer_ids
|
|
572
|
+
if (new_node.id and new_node.id not in self.peer_ids) or (
|
|
573
|
+
new_node.hfid and new_node.hfid not in self.peer_hfids
|
|
574
|
+
):
|
|
573
575
|
self.peers.append(new_node)
|
|
574
576
|
self._has_update = True
|
|
575
577
|
|
|
@@ -591,6 +593,14 @@ class RelationshipManager(RelationshipManagerBase):
|
|
|
591
593
|
self.peers.pop(idx)
|
|
592
594
|
self._has_update = True
|
|
593
595
|
|
|
596
|
+
elif node_to_remove.hfid and node_to_remove.hfid in self.peer_hfids:
|
|
597
|
+
idx = self.peer_hfids.index(node_to_remove.hfid)
|
|
598
|
+
if self.peers[idx].hfid != node_to_remove.hfid:
|
|
599
|
+
raise IndexError(f"Unexpected situation, the node with the index {idx} should be {node_to_remove.hfid}")
|
|
600
|
+
|
|
601
|
+
self.peers.pop(idx)
|
|
602
|
+
self._has_update = True
|
|
603
|
+
|
|
594
604
|
|
|
595
605
|
class RelationshipManagerSync(RelationshipManagerBase):
|
|
596
606
|
"""Manages relationships of a node in a synchronous context."""
|
|
@@ -664,7 +674,9 @@ class RelationshipManagerSync(RelationshipManagerBase):
|
|
|
664
674
|
raise UninitializedError("Must call fetch() on RelationshipManager before editing members")
|
|
665
675
|
new_node = RelatedNodeSync(schema=self.schema, client=self.client, branch=self.branch, data=data)
|
|
666
676
|
|
|
667
|
-
if new_node.id and new_node.id not in self.peer_ids
|
|
677
|
+
if (new_node.id and new_node.id not in self.peer_ids) or (
|
|
678
|
+
new_node.hfid and new_node.hfid not in self.peer_hfids
|
|
679
|
+
):
|
|
668
680
|
self.peers.append(new_node)
|
|
669
681
|
self._has_update = True
|
|
670
682
|
|
|
@@ -682,6 +694,13 @@ class RelationshipManagerSync(RelationshipManagerBase):
|
|
|
682
694
|
idx = self.peer_ids.index(node_to_remove.id)
|
|
683
695
|
if self.peers[idx].id != node_to_remove.id:
|
|
684
696
|
raise IndexError(f"Unexpected situation, the node with the index {idx} should be {node_to_remove.id}")
|
|
697
|
+
self.peers.pop(idx)
|
|
698
|
+
self._has_update = True
|
|
699
|
+
|
|
700
|
+
elif node_to_remove.hfid and node_to_remove.hfid in self.peer_hfids:
|
|
701
|
+
idx = self.peer_hfids.index(node_to_remove.hfid)
|
|
702
|
+
if self.peers[idx].hfid != node_to_remove.hfid:
|
|
703
|
+
raise IndexError(f"Unexpected situation, the node with the index {idx} should be {node_to_remove.hfid}")
|
|
685
704
|
|
|
686
705
|
self.peers.pop(idx)
|
|
687
706
|
self._has_update = True
|
|
@@ -793,13 +812,12 @@ class InfrahubNodeBase:
|
|
|
793
812
|
return self.get_human_friendly_id_as_string(include_kind=True)
|
|
794
813
|
|
|
795
814
|
def _init_attributes(self, data: dict | None = None) -> None:
|
|
796
|
-
for
|
|
797
|
-
|
|
798
|
-
attr_data = data.get(attr_name, None) if isinstance(data, dict) else None
|
|
815
|
+
for attr_schema in self._schema.attributes:
|
|
816
|
+
attr_data = data.get(attr_schema.name, None) if isinstance(data, dict) else None
|
|
799
817
|
setattr(
|
|
800
818
|
self,
|
|
801
|
-
|
|
802
|
-
Attribute(name=
|
|
819
|
+
attr_schema.name,
|
|
820
|
+
Attribute(name=attr_schema.name, schema=attr_schema, data=attr_data),
|
|
803
821
|
)
|
|
804
822
|
|
|
805
823
|
def _get_request_context(self, request_context: RequestContext | None = None) -> dict[str, Any] | None:
|
|
@@ -1147,24 +1165,23 @@ class InfrahubNode(InfrahubNodeBase):
|
|
|
1147
1165
|
return cls(client=client, schema=schema, branch=branch, data=cls._strip_alias(data))
|
|
1148
1166
|
|
|
1149
1167
|
def _init_relationships(self, data: dict | None = None) -> None:
|
|
1150
|
-
for
|
|
1151
|
-
|
|
1152
|
-
rel_data = data.get(rel_name, None) if isinstance(data, dict) else None
|
|
1168
|
+
for rel_schema in self._schema.relationships:
|
|
1169
|
+
rel_data = data.get(rel_schema.name, None) if isinstance(data, dict) else None
|
|
1153
1170
|
|
|
1154
1171
|
if rel_schema.cardinality == "one":
|
|
1155
|
-
setattr(self, f"_{
|
|
1172
|
+
setattr(self, f"_{rel_schema.name}", None)
|
|
1156
1173
|
setattr(
|
|
1157
1174
|
self.__class__,
|
|
1158
|
-
|
|
1159
|
-
generate_relationship_property(name=
|
|
1175
|
+
rel_schema.name,
|
|
1176
|
+
generate_relationship_property(name=rel_schema.name, node=self),
|
|
1160
1177
|
)
|
|
1161
|
-
setattr(self,
|
|
1178
|
+
setattr(self, rel_schema.name, rel_data)
|
|
1162
1179
|
else:
|
|
1163
1180
|
setattr(
|
|
1164
1181
|
self,
|
|
1165
|
-
|
|
1182
|
+
rel_schema.name,
|
|
1166
1183
|
RelationshipManager(
|
|
1167
|
-
name=
|
|
1184
|
+
name=rel_schema.name,
|
|
1168
1185
|
client=self._client,
|
|
1169
1186
|
node=self,
|
|
1170
1187
|
branch=self._branch,
|
|
@@ -1679,24 +1696,23 @@ class InfrahubNodeSync(InfrahubNodeBase):
|
|
|
1679
1696
|
return cls(client=client, schema=schema, branch=branch, data=cls._strip_alias(data))
|
|
1680
1697
|
|
|
1681
1698
|
def _init_relationships(self, data: dict | None = None) -> None:
|
|
1682
|
-
for
|
|
1683
|
-
|
|
1684
|
-
rel_data = data.get(rel_name, None) if isinstance(data, dict) else None
|
|
1699
|
+
for rel_schema in self._schema.relationships:
|
|
1700
|
+
rel_data = data.get(rel_schema.name, None) if isinstance(data, dict) else None
|
|
1685
1701
|
|
|
1686
1702
|
if rel_schema.cardinality == "one":
|
|
1687
|
-
setattr(self, f"_{
|
|
1703
|
+
setattr(self, f"_{rel_schema.name}", None)
|
|
1688
1704
|
setattr(
|
|
1689
1705
|
self.__class__,
|
|
1690
|
-
|
|
1691
|
-
generate_relationship_property(name=
|
|
1706
|
+
rel_schema.name,
|
|
1707
|
+
generate_relationship_property(name=rel_schema.name, node=self),
|
|
1692
1708
|
)
|
|
1693
|
-
setattr(self,
|
|
1709
|
+
setattr(self, rel_schema.name, rel_data)
|
|
1694
1710
|
else:
|
|
1695
1711
|
setattr(
|
|
1696
1712
|
self,
|
|
1697
|
-
|
|
1713
|
+
rel_schema.name,
|
|
1698
1714
|
RelationshipManagerSync(
|
|
1699
|
-
name=
|
|
1715
|
+
name=rel_schema.name,
|
|
1700
1716
|
client=self._client,
|
|
1701
1717
|
node=self,
|
|
1702
1718
|
branch=self._branch,
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
TEMPLATE_FILE_NAME = "template.j2"
|
|
2
|
+
|
|
3
|
+
ATTRIBUTE_KIND_MAP = {
|
|
4
|
+
"ID": "String",
|
|
5
|
+
"Text": "String",
|
|
6
|
+
"TextArea": "String",
|
|
7
|
+
"DateTime": "DateTime",
|
|
8
|
+
"Email": "String",
|
|
9
|
+
"Password": "String",
|
|
10
|
+
"HashedPassword": "HashedPassword",
|
|
11
|
+
"URL": "URL",
|
|
12
|
+
"File": "String",
|
|
13
|
+
"MacAddress": "MacAddress",
|
|
14
|
+
"Color": "String",
|
|
15
|
+
"Dropdown": "Dropdown",
|
|
16
|
+
"Number": "Integer",
|
|
17
|
+
"Bandwidth": "Integer",
|
|
18
|
+
"IPHost": "IPHost",
|
|
19
|
+
"IPNetwork": "IPNetwork",
|
|
20
|
+
"Boolean": "Boolean",
|
|
21
|
+
"Checkbox": "Boolean",
|
|
22
|
+
"List": "ListAttribute",
|
|
23
|
+
"JSON": "JSONAttribute",
|
|
24
|
+
"Any": "AnyAttribute",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# The order of the classes in the list determines the order of the classes in the generated code
|
|
28
|
+
CORE_BASE_CLASS_TO_SYNCIFY = ["CoreProfile", "CoreObjectTemplate", "CoreNode"]
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Mapping
|
|
4
|
-
from
|
|
4
|
+
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
import jinja2
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from .schema import (
|
|
8
|
+
from .. import protocols as sdk_protocols
|
|
9
|
+
from ..schema import (
|
|
11
10
|
AttributeSchemaAPI,
|
|
12
11
|
GenericSchema,
|
|
13
12
|
GenericSchemaAPI,
|
|
@@ -16,31 +15,22 @@ from .schema import (
|
|
|
16
15
|
NodeSchemaAPI,
|
|
17
16
|
ProfileSchemaAPI,
|
|
18
17
|
RelationshipSchemaAPI,
|
|
18
|
+
TemplateSchemaAPI,
|
|
19
19
|
)
|
|
20
|
+
from .constants import ATTRIBUTE_KIND_MAP, CORE_BASE_CLASS_TO_SYNCIFY, TEMPLATE_FILE_NAME
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"Dropdown": "Dropdown",
|
|
34
|
-
"Number": "Integer",
|
|
35
|
-
"Bandwidth": "Integer",
|
|
36
|
-
"IPHost": "IPHost",
|
|
37
|
-
"IPNetwork": "IPNetwork",
|
|
38
|
-
"Boolean": "Boolean",
|
|
39
|
-
"Checkbox": "Boolean",
|
|
40
|
-
"List": "ListAttribute",
|
|
41
|
-
"JSON": "JSONAttribute",
|
|
42
|
-
"Any": "AnyAttribute",
|
|
43
|
-
}
|
|
22
|
+
|
|
23
|
+
def load_template() -> str:
|
|
24
|
+
path = Path(__file__).parent / TEMPLATE_FILE_NAME
|
|
25
|
+
return path.read_text()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def move_to_end_of_list(lst: list, item: str) -> list:
|
|
29
|
+
"""Move an item to the end of a list if it exists in the list"""
|
|
30
|
+
if item in lst:
|
|
31
|
+
lst.remove(item)
|
|
32
|
+
lst.append(item)
|
|
33
|
+
return lst
|
|
44
34
|
|
|
45
35
|
|
|
46
36
|
class CodeGenerator:
|
|
@@ -48,6 +38,7 @@ class CodeGenerator:
|
|
|
48
38
|
self.generics: dict[str, GenericSchemaAPI | GenericSchema] = {}
|
|
49
39
|
self.nodes: dict[str, NodeSchemaAPI | NodeSchema] = {}
|
|
50
40
|
self.profiles: dict[str, ProfileSchemaAPI] = {}
|
|
41
|
+
self.templates: dict[str, TemplateSchemaAPI] = {}
|
|
51
42
|
|
|
52
43
|
for name, schema_type in schema.items():
|
|
53
44
|
if isinstance(schema_type, (GenericSchemaAPI, GenericSchema)):
|
|
@@ -56,6 +47,8 @@ class CodeGenerator:
|
|
|
56
47
|
self.nodes[name] = schema_type
|
|
57
48
|
if isinstance(schema_type, ProfileSchemaAPI):
|
|
58
49
|
self.profiles[name] = schema_type
|
|
50
|
+
if isinstance(schema_type, TemplateSchemaAPI):
|
|
51
|
+
self.templates[name] = schema_type
|
|
59
52
|
|
|
60
53
|
self.base_protocols = [
|
|
61
54
|
e
|
|
@@ -71,29 +64,49 @@ class CodeGenerator:
|
|
|
71
64
|
self.sorted_profiles = self._sort_and_filter_models(
|
|
72
65
|
self.profiles, filters=["CoreProfile"] + self.base_protocols
|
|
73
66
|
)
|
|
67
|
+
self.sorted_templates = self._sort_and_filter_models(
|
|
68
|
+
self.templates, filters=["CoreObjectTemplate"] + self.base_protocols
|
|
69
|
+
)
|
|
74
70
|
|
|
75
71
|
def render(self, sync: bool = True) -> str:
|
|
76
72
|
jinja2_env = jinja2.Environment(loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True)
|
|
77
|
-
jinja2_env.filters["inheritance"] = self._jinja2_filter_inheritance
|
|
78
73
|
jinja2_env.filters["render_attribute"] = self._jinja2_filter_render_attribute
|
|
79
74
|
jinja2_env.filters["render_relationship"] = self._jinja2_filter_render_relationship
|
|
75
|
+
jinja2_env.filters["syncify"] = self._jinja2_filter_syncify
|
|
80
76
|
|
|
81
|
-
template = jinja2_env.from_string(
|
|
77
|
+
template = jinja2_env.from_string(load_template())
|
|
82
78
|
return template.render(
|
|
83
79
|
generics=self.sorted_generics,
|
|
84
80
|
nodes=self.sorted_nodes,
|
|
85
81
|
profiles=self.sorted_profiles,
|
|
82
|
+
templates=self.sorted_templates,
|
|
86
83
|
base_protocols=self.base_protocols,
|
|
84
|
+
core_node_name="CoreNodeSync" if sync else "CoreNode",
|
|
87
85
|
sync=sync,
|
|
88
86
|
)
|
|
89
87
|
|
|
90
88
|
@staticmethod
|
|
91
|
-
def
|
|
92
|
-
|
|
89
|
+
def _jinja2_filter_syncify(value: str | list, sync: bool = False) -> str | list:
|
|
90
|
+
"""Filter to help with the convertion to sync
|
|
91
|
+
|
|
92
|
+
If a string is provided, append Sync to the end of the string
|
|
93
|
+
If a list is provided, search for CoreNode and replace it with CoreNodeSync
|
|
94
|
+
"""
|
|
95
|
+
if isinstance(value, list):
|
|
96
|
+
# Order the list based on the CORE_BASE_CLASS_TO_SYNCIFY list to ensure the base classes are always last
|
|
97
|
+
for item in CORE_BASE_CLASS_TO_SYNCIFY:
|
|
98
|
+
value = move_to_end_of_list(value, item)
|
|
99
|
+
|
|
100
|
+
if not sync:
|
|
101
|
+
return value
|
|
102
|
+
|
|
103
|
+
if isinstance(value, str):
|
|
104
|
+
return f"{value}Sync"
|
|
105
|
+
|
|
106
|
+
if isinstance(value, list):
|
|
107
|
+
return [f"{item}Sync" if item in CORE_BASE_CLASS_TO_SYNCIFY else item for item in value]
|
|
93
108
|
|
|
94
|
-
|
|
95
|
-
return "CoreNode"
|
|
96
|
-
return ", ".join(inherit_from)
|
|
109
|
+
return value
|
|
97
110
|
|
|
98
111
|
@staticmethod
|
|
99
112
|
def _jinja2_filter_render_attribute(value: AttributeSchemaAPI) -> str:
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Generated by "infrahubctl protocols"
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Optional
|
|
8
|
+
|
|
9
|
+
from infrahub_sdk.protocols import {{ "CoreNode" | syncify(sync) }}, {{ base_protocols | join(', ') }}
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from infrahub_sdk.node import {{ "RelatedNode" | syncify(sync) }}, {{ "RelationshipManager" | syncify(sync) }}
|
|
13
|
+
from infrahub_sdk.protocols_base import (
|
|
14
|
+
AnyAttribute,
|
|
15
|
+
AnyAttributeOptional,
|
|
16
|
+
String,
|
|
17
|
+
StringOptional,
|
|
18
|
+
Integer,
|
|
19
|
+
IntegerOptional,
|
|
20
|
+
Boolean,
|
|
21
|
+
BooleanOptional,
|
|
22
|
+
DateTime,
|
|
23
|
+
DateTimeOptional,
|
|
24
|
+
Dropdown,
|
|
25
|
+
DropdownOptional,
|
|
26
|
+
HashedPassword,
|
|
27
|
+
HashedPasswordOptional,
|
|
28
|
+
MacAddress,
|
|
29
|
+
MacAddressOptional,
|
|
30
|
+
IPHost,
|
|
31
|
+
IPHostOptional,
|
|
32
|
+
IPNetwork,
|
|
33
|
+
IPNetworkOptional,
|
|
34
|
+
JSONAttribute,
|
|
35
|
+
JSONAttributeOptional,
|
|
36
|
+
ListAttribute,
|
|
37
|
+
ListAttributeOptional,
|
|
38
|
+
URL,
|
|
39
|
+
URLOptional,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
{% for generic in generics %}
|
|
43
|
+
|
|
44
|
+
class {{ generic.namespace + generic.name }}({{core_node_name}}):
|
|
45
|
+
{% if not generic.attributes|default([]) and not generic.relationships|default([]) %}
|
|
46
|
+
pass
|
|
47
|
+
{% endif %}
|
|
48
|
+
{% for attribute in generic.attributes | sort(attribute='name') | default([]) %}
|
|
49
|
+
{{ attribute | render_attribute }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
{% for relationship in generic.relationships | sort(attribute='name') | default([]) %}
|
|
52
|
+
{{ relationship | render_relationship(sync) }}
|
|
53
|
+
{% endfor %}
|
|
54
|
+
{% if generic.hierarchical | default(false) %}
|
|
55
|
+
parent: {{ "RelatedNode" | syncify(sync) }}
|
|
56
|
+
children: {{ "RelationshipManager" | syncify(sync) }}
|
|
57
|
+
{% endif %}
|
|
58
|
+
{% endfor %}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
{% for node in nodes %}
|
|
62
|
+
|
|
63
|
+
class {{ node.namespace + node.name }}({{ node.inherit_from | syncify(sync) | join(", ") or core_node_name }}):
|
|
64
|
+
{% if not node.attributes|default([]) and not node.relationships|default([]) %}
|
|
65
|
+
pass
|
|
66
|
+
{% endif %}
|
|
67
|
+
{% for attribute in node.attributes | sort(attribute='name') | default([]) %}
|
|
68
|
+
{{ attribute | render_attribute }}
|
|
69
|
+
{% endfor %}
|
|
70
|
+
{% for relationship in node.relationships | sort(attribute='name') | default([]) %}
|
|
71
|
+
{{ relationship | render_relationship(sync) }}
|
|
72
|
+
{% endfor %}
|
|
73
|
+
{% if node.hierarchical | default(false) %}
|
|
74
|
+
parent: {{ "RelatedNode" | syncify(sync) }}
|
|
75
|
+
children: {{ "RelationshipManager" | syncify(sync) }}
|
|
76
|
+
{% endif %}
|
|
77
|
+
|
|
78
|
+
{% endfor %}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
{% for node in profiles %}
|
|
82
|
+
|
|
83
|
+
class {{ node.namespace + node.name }}({{ node.inherit_from | syncify(sync) | join(", ") or core_node_name }}):
|
|
84
|
+
{% if not node.attributes|default([]) and not node.relationships|default([]) %}
|
|
85
|
+
pass
|
|
86
|
+
{% endif %}
|
|
87
|
+
{% for attribute in node.attributes | sort(attribute='name') | default([]) %}
|
|
88
|
+
{{ attribute | render_attribute }}
|
|
89
|
+
{% endfor %}
|
|
90
|
+
{% for relationship in node.relationships | sort(attribute='name') | default([]) %}
|
|
91
|
+
{{ relationship | render_relationship(sync) }}
|
|
92
|
+
{% endfor %}
|
|
93
|
+
{% if node.hierarchical | default(false) %}
|
|
94
|
+
parent: {{ "RelatedNode" | syncify(sync) }}
|
|
95
|
+
children: {{ "RelationshipManager" | syncify(sync) }}
|
|
96
|
+
{% endif %}
|
|
97
|
+
|
|
98
|
+
{% endfor %}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
{% for node in templates %}
|
|
102
|
+
|
|
103
|
+
class {{ node.namespace + node.name }}({{ node.inherit_from | syncify(sync) | join(", ") or core_node_name }}):
|
|
104
|
+
{% if not node.attributes|default([]) and not node.relationships|default([]) %}
|
|
105
|
+
pass
|
|
106
|
+
{% endif %}
|
|
107
|
+
{% for attribute in node.attributes | sort(attribute='name') | default([]) %}
|
|
108
|
+
{{ attribute | render_attribute }}
|
|
109
|
+
{% endfor %}
|
|
110
|
+
{% for relationship in node.relationships | sort(attribute='name') | default([]) %}
|
|
111
|
+
{{ relationship | render_relationship(sync) }}
|
|
112
|
+
{% endfor %}
|
|
113
|
+
|
|
114
|
+
{% endfor %}
|