infrahub-server 1.3.0b5__py3-none-any.whl → 1.3.0b6__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.
Files changed (47) hide show
  1. infrahub/actions/constants.py +36 -79
  2. infrahub/actions/schema.py +2 -0
  3. infrahub/core/constraint/node/runner.py +3 -1
  4. infrahub/core/convert_object_type/conversion.py +2 -0
  5. infrahub/core/diff/query/delete_query.py +8 -4
  6. infrahub/core/diff/repository/repository.py +4 -0
  7. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -2
  8. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -2
  9. infrahub/core/migrations/graph/m028_delete_diffs.py +1 -2
  10. infrahub/core/node/__init__.py +65 -36
  11. infrahub/core/path.py +14 -0
  12. infrahub/core/relationship/constraints/count.py +10 -9
  13. infrahub/core/relationship/constraints/interface.py +2 -1
  14. infrahub/core/relationship/constraints/peer_kind.py +2 -1
  15. infrahub/core/relationship/constraints/peer_parent.py +56 -0
  16. infrahub/core/relationship/constraints/peer_relatives.py +1 -1
  17. infrahub/core/relationship/constraints/profiles_kind.py +1 -1
  18. infrahub/core/schema/definitions/internal.py +8 -1
  19. infrahub/core/schema/generated/relationship_schema.py +6 -1
  20. infrahub/core/schema/schema_branch.py +36 -8
  21. infrahub/core/validators/__init__.py +2 -1
  22. infrahub/core/validators/relationship/peer.py +174 -4
  23. infrahub/database/__init__.py +0 -1
  24. infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
  25. infrahub/dependencies/builder/constraint/relationship_manager/peer_parent.py +8 -0
  26. infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
  27. infrahub/dependencies/builder/constraint/schema/relationship_peer.py +8 -0
  28. infrahub/dependencies/registry.py +2 -0
  29. infrahub/git/tasks.py +1 -0
  30. infrahub/graphql/mutations/convert_object_type.py +16 -7
  31. infrahub/graphql/mutations/relationship.py +32 -0
  32. infrahub/graphql/queries/convert_object_type_mapping.py +3 -5
  33. infrahub/message_bus/operations/refresh/registry.py +3 -6
  34. infrahub/pools/models.py +14 -0
  35. infrahub/pools/tasks.py +71 -1
  36. infrahub_sdk/ctl/generator.py +4 -4
  37. infrahub_sdk/ctl/repository.py +1 -1
  38. infrahub_sdk/node/node.py +146 -92
  39. infrahub_sdk/pytest_plugin/items/python_transform.py +2 -1
  40. infrahub_sdk/query_groups.py +4 -3
  41. infrahub_sdk/utils.py +7 -20
  42. infrahub_sdk/yaml.py +6 -5
  43. {infrahub_server-1.3.0b5.dist-info → infrahub_server-1.3.0b6.dist-info}/METADATA +2 -2
  44. {infrahub_server-1.3.0b5.dist-info → infrahub_server-1.3.0b6.dist-info}/RECORD +47 -43
  45. {infrahub_server-1.3.0b5.dist-info → infrahub_server-1.3.0b6.dist-info}/LICENSE.txt +0 -0
  46. {infrahub_server-1.3.0b5.dist-info → infrahub_server-1.3.0b6.dist-info}/WHEEL +0 -0
  47. {infrahub_server-1.3.0b5.dist-info → infrahub_server-1.3.0b6.dist-info}/entry_points.txt +0 -0
@@ -74,20 +74,20 @@ async def run(
74
74
  targets = await client.get(
75
75
  kind="CoreGroup", branch=branch, include=["members"], name__value=generator_config.targets
76
76
  )
77
- await targets.members.fetch()
77
+ await targets._get_relationship_many(name="members").fetch()
78
78
 
79
- if not targets.members.peers:
79
+ if not targets._get_relationship_many(name="members").peers:
80
80
  console.print(
81
81
  f"[red]No members found within '{generator_config.targets}', not running generator '{generator_name}'"
82
82
  )
83
83
  return
84
84
 
85
- for member in targets.members.peers:
85
+ for member in targets._get_relationship_many(name="members").peers:
86
86
  check_parameter = {}
87
87
  if identifier:
88
88
  attribute = getattr(member.peer, identifier)
89
89
  check_parameter = {identifier: attribute.value}
90
- params = {"name": member.peer.name.value}
90
+ params = {"name": member.peer._get_attribute(name="name").value}
91
91
  generator = generator_class(
92
92
  query=generator_config.query,
93
93
  client=client,
@@ -45,7 +45,7 @@ def get_repository_config(repo_config_file: Path) -> InfrahubRepositoryConfig:
45
45
 
46
46
 
47
47
  def load_repository_config_file(repo_config_file: Path) -> dict:
48
- yaml_data = read_file(file_name=repo_config_file)
48
+ yaml_data = read_file(file_path=repo_config_file)
49
49
 
50
50
  try:
51
51
  data = yaml.safe_load(yaml_data)
infrahub_sdk/node/node.py CHANGED
@@ -1,13 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Iterable
3
4
  from copy import copy
4
5
  from typing import TYPE_CHECKING, Any
5
6
 
6
7
  from ..constants import InfrahubClientMode
7
- from ..exceptions import (
8
- FeatureNotSupportedError,
9
- NodeNotFoundError,
10
- )
8
+ from ..exceptions import FeatureNotSupportedError, NodeNotFoundError, ResourceNotDefinedError, SchemaNotFoundError
11
9
  from ..graphql import Mutation, Query
12
10
  from ..schema import GenericSchemaAPI, RelationshipCardinality, RelationshipKind
13
11
  from ..utils import compare_lists, generate_short_id, get_flat_value
@@ -30,48 +28,6 @@ if TYPE_CHECKING:
30
28
  from ..types import Order
31
29
 
32
30
 
33
- def generate_relationship_property(node: InfrahubNode | InfrahubNodeSync, name: str) -> property:
34
- """Generates a property that stores values under a private non-public name.
35
-
36
- Args:
37
- node (Union[InfrahubNode, InfrahubNodeSync]): The node instance.
38
- name (str): The name of the relationship property.
39
-
40
- Returns:
41
- A property object for managing the relationship.
42
-
43
- """
44
- internal_name = "_" + name.lower()
45
- external_name = name
46
-
47
- def prop_getter(self: InfrahubNodeBase) -> Any:
48
- return getattr(self, internal_name)
49
-
50
- def prop_setter(self: InfrahubNodeBase, value: Any) -> None:
51
- if isinstance(value, RelatedNodeBase) or value is None:
52
- setattr(self, internal_name, value)
53
- else:
54
- schema = [rel for rel in self._schema.relationships if rel.name == external_name][0]
55
- if isinstance(node, InfrahubNode):
56
- setattr(
57
- self,
58
- internal_name,
59
- RelatedNode(
60
- name=external_name, branch=node._branch, client=node._client, schema=schema, data=value
61
- ),
62
- )
63
- else:
64
- setattr(
65
- self,
66
- internal_name,
67
- RelatedNodeSync(
68
- name=external_name, branch=node._branch, client=node._client, schema=schema, data=value
69
- ),
70
- )
71
-
72
- return property(prop_getter, prop_setter)
73
-
74
-
75
31
  class InfrahubNodeBase:
76
32
  """Base class for InfrahubNode and InfrahubNodeSync"""
77
33
 
@@ -86,6 +42,7 @@ class InfrahubNodeBase:
86
42
  self._data = data
87
43
  self._branch = branch
88
44
  self._existing: bool = True
45
+ self._attribute_data: dict[str, Attribute] = {}
89
46
 
90
47
  # Generate a unique ID only to be used inside the SDK
91
48
  # The format if this ID is purposely different from the ID used by the API
@@ -180,12 +137,18 @@ class InfrahubNodeBase:
180
137
  def _init_attributes(self, data: dict | None = None) -> None:
181
138
  for attr_schema in self._schema.attributes:
182
139
  attr_data = data.get(attr_schema.name, None) if isinstance(data, dict) else None
183
- setattr(
184
- self,
185
- attr_schema.name,
186
- Attribute(name=attr_schema.name, schema=attr_schema, data=attr_data),
140
+ self._attribute_data[attr_schema.name] = Attribute(
141
+ name=attr_schema.name, schema=attr_schema, data=attr_data
187
142
  )
188
143
 
144
+ def __setattr__(self, name: str, value: Any) -> None:
145
+ """Set values for attributes that exist or revert to normal behaviour"""
146
+ if "_attribute_data" in self.__dict__ and name in self._attribute_data:
147
+ self._attribute_data[name].value = value
148
+ return
149
+
150
+ super().__setattr__(name, value)
151
+
189
152
  def _get_request_context(self, request_context: RequestContext | None = None) -> dict[str, Any] | None:
190
153
  if request_context:
191
154
  return request_context.model_dump(exclude_none=True)
@@ -487,6 +450,12 @@ class InfrahubNodeBase:
487
450
  }}
488
451
  """
489
452
 
453
+ def _get_attribute(self, name: str) -> Attribute:
454
+ if name in self._attribute_data:
455
+ return self._attribute_data[name]
456
+
457
+ raise ResourceNotDefinedError(message=f"The node doesn't have an attribute for {name}")
458
+
490
459
 
491
460
  class InfrahubNode(InfrahubNodeBase):
492
461
  """Represents a Infrahub node in an asynchronous context."""
@@ -506,11 +475,13 @@ class InfrahubNode(InfrahubNodeBase):
506
475
  data: Optional data to initialize the node.
507
476
  """
508
477
  self._client = client
509
- self.__class__ = type(f"{schema.kind}InfrahubNode", (self.__class__,), {})
510
478
 
511
479
  if isinstance(data, dict) and isinstance(data.get("node"), dict):
512
480
  data = data.get("node")
513
481
 
482
+ self._relationship_cardinality_many_data: dict[str, RelationshipManager] = {}
483
+ self._relationship_cardinality_one_data: dict[str, RelatedNode] = {}
484
+
514
485
  super().__init__(schema=schema, branch=branch or client.default_branch, data=data)
515
486
 
516
487
  @classmethod
@@ -535,26 +506,45 @@ class InfrahubNode(InfrahubNodeBase):
535
506
  rel_data = data.get(rel_schema.name, None) if isinstance(data, dict) else None
536
507
 
537
508
  if rel_schema.cardinality == "one":
538
- setattr(self, f"_{rel_schema.name}", None)
539
- setattr(
540
- self.__class__,
541
- rel_schema.name,
542
- generate_relationship_property(name=rel_schema.name, node=self),
509
+ self._relationship_cardinality_one_data[rel_schema.name] = RelatedNode(
510
+ name=rel_schema.name, branch=self._branch, client=self._client, schema=rel_schema, data=rel_data
543
511
  )
544
- setattr(self, rel_schema.name, rel_data)
545
512
  else:
546
- setattr(
547
- self,
548
- rel_schema.name,
549
- RelationshipManager(
550
- name=rel_schema.name,
551
- client=self._client,
552
- node=self,
553
- branch=self._branch,
554
- schema=rel_schema,
555
- data=rel_data,
556
- ),
513
+ self._relationship_cardinality_many_data[rel_schema.name] = RelationshipManager(
514
+ name=rel_schema.name,
515
+ client=self._client,
516
+ node=self,
517
+ branch=self._branch,
518
+ schema=rel_schema,
519
+ data=rel_data,
520
+ )
521
+
522
+ def __getattr__(self, name: str) -> Attribute | RelationshipManager | RelatedNode:
523
+ if "_attribute_data" in self.__dict__ and name in self._attribute_data:
524
+ return self._attribute_data[name]
525
+ if "_relationship_cardinality_many_data" in self.__dict__ and name in self._relationship_cardinality_many_data:
526
+ return self._relationship_cardinality_many_data[name]
527
+ if "_relationship_cardinality_one_data" in self.__dict__ and name in self._relationship_cardinality_one_data:
528
+ return self._relationship_cardinality_one_data[name]
529
+
530
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
531
+
532
+ def __setattr__(self, name: str, value: Any) -> None:
533
+ """Set values for relationship names that exist or revert to normal behaviour"""
534
+ if "_relationship_cardinality_one_data" in self.__dict__ and name in self._relationship_cardinality_one_data:
535
+ rel_schemas = [rel_schema for rel_schema in self._schema.relationships if rel_schema.name == name]
536
+ if not rel_schemas:
537
+ raise SchemaNotFoundError(
538
+ identifier=self._schema.kind,
539
+ message=f"Unable to find relationship schema for '{name}' on {self._schema.kind}",
557
540
  )
541
+ rel_schema = rel_schemas[0]
542
+ self._relationship_cardinality_one_data[name] = RelatedNode(
543
+ name=rel_schema.name, branch=self._branch, client=self._client, schema=rel_schema, data=value
544
+ )
545
+ return
546
+
547
+ super().__setattr__(name, value)
558
548
 
559
549
  async def generate(self, nodes: list[str] | None = None) -> None:
560
550
  self._validate_artifact_definition_support(ARTIFACT_DEFINITION_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE)
@@ -568,14 +558,14 @@ class InfrahubNode(InfrahubNodeBase):
568
558
  self._validate_artifact_support(ARTIFACT_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE)
569
559
 
570
560
  artifact = await self._client.get(kind="CoreArtifact", name__value=name, object__ids=[self.id])
571
- await artifact.definition.fetch() # type: ignore[attr-defined]
572
- await artifact.definition.peer.generate([artifact.id]) # type: ignore[attr-defined]
561
+ await artifact._get_relationship_one(name="definition").fetch()
562
+ await artifact._get_relationship_one(name="definition").peer.generate([artifact.id])
573
563
 
574
564
  async def artifact_fetch(self, name: str) -> str | dict[str, Any]:
575
565
  self._validate_artifact_support(ARTIFACT_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE)
576
566
 
577
567
  artifact = await self._client.get(kind="CoreArtifact", name__value=name, object__ids=[self.id])
578
- content = await self._client.object_store.get(identifier=artifact.storage_id.value) # type: ignore[attr-defined]
568
+ content = await self._client.object_store.get(identifier=artifact._get_attribute(name="storage_id").value)
579
569
  return content
580
570
 
581
571
  async def delete(self, timeout: int | None = None, request_context: RequestContext | None = None) -> None:
@@ -1018,6 +1008,27 @@ class InfrahubNode(InfrahubNodeBase):
1018
1008
  return [edge["node"] for edge in response[graphql_query_name]["edges"]]
1019
1009
  return []
1020
1010
 
1011
+ def _get_relationship_many(self, name: str) -> RelationshipManager:
1012
+ if name in self._relationship_cardinality_many_data:
1013
+ return self._relationship_cardinality_many_data[name]
1014
+
1015
+ raise ResourceNotDefinedError(message=f"The node doesn't have a cardinality=many relationship for {name}")
1016
+
1017
+ def _get_relationship_one(self, name: str) -> RelatedNode:
1018
+ if name in self._relationship_cardinality_one_data:
1019
+ return self._relationship_cardinality_one_data[name]
1020
+
1021
+ raise ResourceNotDefinedError(message=f"The node doesn't have a cardinality=one relationship for {name}")
1022
+
1023
+ def __dir__(self) -> Iterable[str]:
1024
+ base = list(super().__dir__())
1025
+ return sorted(
1026
+ base
1027
+ + list(self._attribute_data.keys())
1028
+ + list(self._relationship_cardinality_many_data.keys())
1029
+ + list(self._relationship_cardinality_one_data.keys())
1030
+ )
1031
+
1021
1032
 
1022
1033
  class InfrahubNodeSync(InfrahubNodeBase):
1023
1034
  """Represents a Infrahub node in a synchronous context."""
@@ -1036,12 +1047,14 @@ class InfrahubNodeSync(InfrahubNodeBase):
1036
1047
  branch (Optional[str]): The branch where the node resides.
1037
1048
  data (Optional[dict]): Optional data to initialize the node.
1038
1049
  """
1039
- self.__class__ = type(f"{schema.kind}InfrahubNodeSync", (self.__class__,), {})
1040
1050
  self._client = client
1041
1051
 
1042
1052
  if isinstance(data, dict) and isinstance(data.get("node"), dict):
1043
1053
  data = data.get("node")
1044
1054
 
1055
+ self._relationship_cardinality_many_data: dict[str, RelationshipManagerSync] = {}
1056
+ self._relationship_cardinality_one_data: dict[str, RelatedNodeSync] = {}
1057
+
1045
1058
  super().__init__(schema=schema, branch=branch or client.default_branch, data=data)
1046
1059
 
1047
1060
  @classmethod
@@ -1066,27 +1079,47 @@ class InfrahubNodeSync(InfrahubNodeBase):
1066
1079
  rel_data = data.get(rel_schema.name, None) if isinstance(data, dict) else None
1067
1080
 
1068
1081
  if rel_schema.cardinality == "one":
1069
- setattr(self, f"_{rel_schema.name}", None)
1070
- setattr(
1071
- self.__class__,
1072
- rel_schema.name,
1073
- generate_relationship_property(name=rel_schema.name, node=self),
1082
+ self._relationship_cardinality_one_data[rel_schema.name] = RelatedNodeSync(
1083
+ name=rel_schema.name, branch=self._branch, client=self._client, schema=rel_schema, data=rel_data
1074
1084
  )
1075
- setattr(self, rel_schema.name, rel_data)
1085
+
1076
1086
  else:
1077
- setattr(
1078
- self,
1079
- rel_schema.name,
1080
- RelationshipManagerSync(
1081
- name=rel_schema.name,
1082
- client=self._client,
1083
- node=self,
1084
- branch=self._branch,
1085
- schema=rel_schema,
1086
- data=rel_data,
1087
- ),
1087
+ self._relationship_cardinality_many_data[rel_schema.name] = RelationshipManagerSync(
1088
+ name=rel_schema.name,
1089
+ client=self._client,
1090
+ node=self,
1091
+ branch=self._branch,
1092
+ schema=rel_schema,
1093
+ data=rel_data,
1088
1094
  )
1089
1095
 
1096
+ def __getattr__(self, name: str) -> Attribute | RelationshipManagerSync | RelatedNodeSync:
1097
+ if "_attribute_data" in self.__dict__ and name in self._attribute_data:
1098
+ return self._attribute_data[name]
1099
+ if "_relationship_cardinality_many_data" in self.__dict__ and name in self._relationship_cardinality_many_data:
1100
+ return self._relationship_cardinality_many_data[name]
1101
+ if "_relationship_cardinality_one_data" in self.__dict__ and name in self._relationship_cardinality_one_data:
1102
+ return self._relationship_cardinality_one_data[name]
1103
+
1104
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
1105
+
1106
+ def __setattr__(self, name: str, value: Any) -> None:
1107
+ """Set values for relationship names that exist or revert to normal behaviour"""
1108
+ if "_relationship_cardinality_one_data" in self.__dict__ and name in self._relationship_cardinality_one_data:
1109
+ rel_schemas = [rel_schema for rel_schema in self._schema.relationships if rel_schema.name == name]
1110
+ if not rel_schemas:
1111
+ raise SchemaNotFoundError(
1112
+ identifier=self._schema.kind,
1113
+ message=f"Unable to find relationship schema for '{name}' on {self._schema.kind}",
1114
+ )
1115
+ rel_schema = rel_schemas[0]
1116
+ self._relationship_cardinality_one_data[name] = RelatedNodeSync(
1117
+ name=rel_schema.name, branch=self._branch, client=self._client, schema=rel_schema, data=value
1118
+ )
1119
+ return
1120
+
1121
+ super().__setattr__(name, value)
1122
+
1090
1123
  def generate(self, nodes: list[str] | None = None) -> None:
1091
1124
  self._validate_artifact_definition_support(ARTIFACT_DEFINITION_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE)
1092
1125
  nodes = nodes or []
@@ -1097,13 +1130,13 @@ class InfrahubNodeSync(InfrahubNodeBase):
1097
1130
  def artifact_generate(self, name: str) -> None:
1098
1131
  self._validate_artifact_support(ARTIFACT_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE)
1099
1132
  artifact = self._client.get(kind="CoreArtifact", name__value=name, object__ids=[self.id])
1100
- artifact.definition.fetch() # type: ignore[attr-defined]
1101
- artifact.definition.peer.generate([artifact.id]) # type: ignore[attr-defined]
1133
+ artifact._get_relationship_one(name="definition").fetch()
1134
+ artifact._get_relationship_one(name="definition").peer.generate([artifact.id])
1102
1135
 
1103
1136
  def artifact_fetch(self, name: str) -> str | dict[str, Any]:
1104
1137
  self._validate_artifact_support(ARTIFACT_FETCH_FEATURE_NOT_SUPPORTED_MESSAGE)
1105
1138
  artifact = self._client.get(kind="CoreArtifact", name__value=name, object__ids=[self.id])
1106
- content = self._client.object_store.get(identifier=artifact.storage_id.value) # type: ignore[attr-defined]
1139
+ content = self._client.object_store.get(identifier=artifact._get_attribute(name="storage_id").value)
1107
1140
  return content
1108
1141
 
1109
1142
  def delete(self, timeout: int | None = None, request_context: RequestContext | None = None) -> None:
@@ -1545,3 +1578,24 @@ class InfrahubNodeSync(InfrahubNodeBase):
1545
1578
  if response[graphql_query_name].get("count", 0):
1546
1579
  return [edge["node"] for edge in response[graphql_query_name]["edges"]]
1547
1580
  return []
1581
+
1582
+ def _get_relationship_many(self, name: str) -> RelationshipManager | RelationshipManagerSync:
1583
+ if name in self._relationship_cardinality_many_data:
1584
+ return self._relationship_cardinality_many_data[name]
1585
+
1586
+ raise ResourceNotDefinedError(message=f"The node doesn't have a cardinality=many relationship for {name}")
1587
+
1588
+ def _get_relationship_one(self, name: str) -> RelatedNode | RelatedNodeSync:
1589
+ if name in self._relationship_cardinality_one_data:
1590
+ return self._relationship_cardinality_one_data[name]
1591
+
1592
+ raise ResourceNotDefinedError(message=f"The node doesn't have a cardinality=one relationship for {name}")
1593
+
1594
+ def __dir__(self) -> Iterable[str]:
1595
+ base = list(super().__dir__())
1596
+ return sorted(
1597
+ base
1598
+ + list(self._attribute_data.keys())
1599
+ + list(self._relationship_cardinality_many_data.keys())
1600
+ + list(self._relationship_cardinality_one_data.keys())
1601
+ )
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Any
7
7
  import ujson
8
8
  from httpx import HTTPStatusError
9
9
 
10
+ from ...node import InfrahubNode
10
11
  from ..exceptions import OutputMatchError, PythonTransformDefinitionError
11
12
  from ..models import InfrahubTestExpectedResult
12
13
  from .base import InfrahubItem
@@ -41,7 +42,7 @@ class InfrahubPythonTransformItem(InfrahubItem):
41
42
  )
42
43
  client = self.session.infrahub_client # type: ignore[attr-defined]
43
44
  # TODO: Look into seeing how a transform class may use the branch, but set as a empty string for the time being to keep current behaviour
44
- self.transform_instance = transform_class(branch="", client=client)
45
+ self.transform_instance = transform_class(branch="", client=client, infrahub_node=InfrahubNode)
45
46
 
46
47
  def run_transform(self, variables: dict[str, Any]) -> Any:
47
48
  self.instantiate_transform()
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Sequence
3
4
  from typing import TYPE_CHECKING, Any
4
5
 
5
6
  from .constants import InfrahubClientMode
@@ -19,7 +20,7 @@ class InfrahubGroupContextBase:
19
20
  self.related_node_ids: list[str] = []
20
21
  self.related_group_ids: list[str] = []
21
22
  self.unused_member_ids: list[str] | None = None
22
- self.previous_members: list[RelatedNodeBase] | None = None
23
+ self.previous_members: Sequence[RelatedNodeBase] | None = None
23
24
  self.previous_children: list[RelatedNodeBase] | None = None
24
25
  self.identifier: str | None = None
25
26
  self.params: dict[str, str] = {}
@@ -101,7 +102,7 @@ class InfrahubGroupContext(InfrahubGroupContextBase):
101
102
  if not store_peers:
102
103
  return group
103
104
 
104
- self.previous_members = group.members.peers # type: ignore[attr-defined]
105
+ self.previous_members = group._get_relationship_many(name="members").peers
105
106
  return group
106
107
 
107
108
  async def delete_unused(self) -> None:
@@ -195,7 +196,7 @@ class InfrahubGroupContextSync(InfrahubGroupContextBase):
195
196
  if not store_peers:
196
197
  return group
197
198
 
198
- self.previous_members = group.members.peers # type: ignore[attr-defined]
199
+ self.previous_members = group._get_relationship_many(name="members").peers
199
200
  return group
200
201
 
201
202
  def delete_unused(self) -> None:
infrahub_sdk/utils.py CHANGED
@@ -240,21 +240,6 @@ def is_valid_url(url: str) -> bool:
240
240
  return False
241
241
 
242
242
 
243
- def find_files(extension: str | list[str], directory: str | Path = ".") -> list[Path]:
244
- files: list[Path] = []
245
-
246
- if isinstance(extension, str):
247
- extension = [extension]
248
- if isinstance(directory, str):
249
- directory = Path(directory)
250
-
251
- for ext in extension:
252
- files.extend(list(directory.glob(f"**/*.{ext}")))
253
- files.extend(list(directory.glob(f"**/.*.{ext}")))
254
-
255
- return files
256
-
257
-
258
243
  def get_branch(branch: str | None = None, directory: str | Path = ".") -> str:
259
244
  """If branch isn't provide, return the name of the local Git branch."""
260
245
  if branch:
@@ -351,14 +336,16 @@ def write_to_file(path: Path, value: Any) -> bool:
351
336
  return written is not None
352
337
 
353
338
 
354
- def read_file(file_name: Path) -> str:
355
- if not file_name.is_file():
356
- raise FileNotValidError(name=str(file_name), message=f"{file_name} is not a valid file")
339
+ def read_file(file_path: Path) -> str:
340
+ if not file_path.is_file():
341
+ raise FileNotValidError(name=str(file_path.name), message=f"{file_path.name}: not found at {file_path.parent}")
357
342
  try:
358
- with Path.open(file_name, encoding="utf-8") as fobj:
343
+ with Path.open(file_path, encoding="utf-8") as fobj:
359
344
  return fobj.read()
360
345
  except UnicodeDecodeError as exc:
361
- raise FileNotValidError(name=str(file_name), message=f"Unable to read {file_name} with utf-8 encoding") from exc
346
+ raise FileNotValidError(
347
+ name=str(file_path.name), message=f"Unable to read {file_path.name} with utf-8 encoding"
348
+ ) from exc
362
349
 
363
350
 
364
351
  def get_user_permissions(data: list[dict]) -> dict:
infrahub_sdk/yaml.py CHANGED
@@ -10,7 +10,7 @@ from typing_extensions import Self
10
10
  from yaml.parser import ParserError
11
11
 
12
12
  from .exceptions import FileNotValidError
13
- from .utils import find_files, read_file
13
+ from .utils import read_file
14
14
 
15
15
 
16
16
  class InfrahubFileApiVersion(str, Enum):
@@ -121,12 +121,13 @@ class YamlFile(LocalFile):
121
121
  def load_from_disk(cls, paths: list[Path]) -> list[Self]:
122
122
  yaml_files: list[Self] = []
123
123
  for file_path in paths:
124
- if file_path.is_file():
124
+ if file_path.is_file() and file_path.suffix in [".yaml", ".yml", ".json"]:
125
125
  yaml_files.extend(cls.load_file_from_disk(path=file_path))
126
126
  elif file_path.is_dir():
127
- files = find_files(extension=["yaml", "yml", "json"], directory=file_path)
128
- for item in files:
129
- yaml_files.extend(cls.load_file_from_disk(path=item))
127
+ sub_paths = [Path(sub_file_path) for sub_file_path in file_path.glob("*")]
128
+ sub_files = cls.load_from_disk(paths=sub_paths)
129
+ sorted_sub_files = sorted(sub_files, key=lambda x: x.location)
130
+ yaml_files.extend(sorted_sub_files)
130
131
  else:
131
132
  raise FileNotValidError(name=str(file_path), message=f"{file_path} does not exist!")
132
133
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: infrahub-server
3
- Version: 1.3.0b5
3
+ Version: 1.3.0b6
4
4
  Summary: Infrahub is taking a new approach to Infrastructure Management by providing a new generation of datastore to organize and control all the data that defines how an infrastructure should run.
5
5
  License: AGPL-3.0-only
6
6
  Author: OpsMill
@@ -55,7 +55,7 @@ Requires-Dist: toml (>=0.10,<0.11)
55
55
  Requires-Dist: typer (==0.12.5)
56
56
  Requires-Dist: ujson (>=5,<6)
57
57
  Requires-Dist: uvicorn[standard] (>=0.32,<0.33)
58
- Requires-Dist: whenever (==0.7.2)
58
+ Requires-Dist: whenever (==0.7.3)
59
59
  Project-URL: Documentation, https://docs.infrahub.app/
60
60
  Project-URL: Homepage, https://opsmill.com
61
61
  Project-URL: Repository, https://github.com/opsmill/infrahub