Skip to content

Commit da881b4

Browse files
committed
Merge 'develop' into 'infrahub-develop' with resolved conflicts
2 parents 7f7ee7d + a2ecdda commit da881b4

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

changelog/630.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed SDK including explicit `null` values for uninitialized optional relationships when creating nodes with object templates, which prevented the backend from applying template defaults.

infrahub_sdk/node/node.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def is_resource_pool(self) -> bool:
216216
def get_raw_graphql_data(self) -> dict | None:
217217
return self._data
218218

219-
def _generate_input_data( # noqa: C901
219+
def _generate_input_data( # noqa: C901, PLR0915
220220
self,
221221
exclude_unmodified: bool = False,
222222
exclude_hfid: bool = False,
@@ -259,7 +259,10 @@ def _generate_input_data( # noqa: C901
259259
rel: RelatedNodeBase | RelationshipManagerBase = getattr(self, item_name)
260260

261261
if rel_schema.cardinality == RelationshipCardinality.ONE and rel_schema.optional and not rel.initialized:
262-
data[item_name] = None
262+
# Only include None for existing nodes to allow clearing relationships
263+
# For new nodes, omit the field to allow object template defaults to be applied
264+
if self._existing:
265+
data[item_name] = None
263266
continue
264267

265268
if rel is None or not rel.initialized:

tests/unit/sdk/test_node.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,7 +1360,6 @@ async def test_create_input_data(client, location_schema: NodeSchemaAPI, client_
13601360
"name": {"value": "JFK1"},
13611361
"description": {"value": "JFK Airport"},
13621362
"type": {"value": "SITE"},
1363-
"primary_tag": None,
13641363
}
13651364
}
13661365

@@ -1388,6 +1387,38 @@ async def test_create_input_data_with_dropdown(client, location_schema_with_drop
13881387
"description": {"value": "JFK Airport"},
13891388
"type": {"value": "SITE"},
13901389
"status": {"value": None},
1390+
}
1391+
}
1392+
1393+
1394+
@pytest.mark.parametrize("client_type", client_types)
1395+
async def test_update_input_data_existing_node_with_optional_relationship(
1396+
clients: BothClients, location_schema: NodeSchemaAPI, client_type: str
1397+
) -> None:
1398+
"""Validate that existing nodes include None for uninitialized optional relationships.
1399+
1400+
This ensures that we can explicitly clear optional relationships when updating existing nodes.
1401+
"""
1402+
# Simulate an existing node by including an id
1403+
data = {
1404+
"id": "existing-node-id",
1405+
"name": {"value": "JFK1"},
1406+
"description": {"value": "JFK Airport"},
1407+
"type": {"value": "SITE"},
1408+
}
1409+
1410+
if client_type == "standard":
1411+
node = InfrahubNode(client=clients.standard, schema=location_schema, data=data)
1412+
else:
1413+
node = InfrahubNodeSync(client=clients.sync, schema=location_schema, data=data)
1414+
1415+
# For existing nodes, optional uninitialized relationships should include None
1416+
assert node._generate_input_data()["data"] == {
1417+
"data": {
1418+
"id": "existing-node-id",
1419+
"name": {"value": "JFK1"},
1420+
"description": {"value": "JFK Airport"},
1421+
"type": {"value": "SITE"},
13911422
"primary_tag": None,
13921423
}
13931424
}
@@ -1636,7 +1667,7 @@ async def test_create_input_data_with_IPHost_attribute(client, ipaddress_schema,
16361667
ip_address = InfrahubNodeSync(client=client, schema=ipaddress_schema, data=data)
16371668

16381669
assert ip_address._generate_input_data()["data"] == {
1639-
"data": {"address": {"value": "1.1.1.1/24", "is_protected": True}, "interface": None}
1670+
"data": {"address": {"value": "1.1.1.1/24", "is_protected": True}}
16401671
}
16411672

16421673

@@ -1650,7 +1681,7 @@ async def test_create_input_data_with_IPNetwork_attribute(client, ipnetwork_sche
16501681
ip_network = InfrahubNodeSync(client=client, schema=ipnetwork_schema, data=data)
16511682

16521683
assert ip_network._generate_input_data()["data"] == {
1653-
"data": {"network": {"value": "1.1.1.0/24", "is_protected": True}, "site": None}
1684+
"data": {"network": {"value": "1.1.1.0/24", "is_protected": True}}
16541685
}
16551686

16561687

0 commit comments

Comments
 (0)