Skip to content

Commit f0ee3cd

Browse files
Copilotminitriga
andcommitted
Fix optional attributes not being set when using object templates
- Modified _generate_input_data() to skip adding None for optional relationships on new nodes - For existing nodes, still include None to allow clearing relationships (preserves PR #515 behavior) - Updated tests to reflect new behavior - Added test to verify existing nodes still work correctly Co-authored-by: minitriga <26367336+minitriga@users.noreply.github.com>
1 parent 01ed925 commit f0ee3cd

2 files changed

Lines changed: 39 additions & 5 deletions

File tree

infrahub_sdk/node/node.py

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

195-
def _generate_input_data( # noqa: C901
195+
def _generate_input_data( # noqa: C901, PLR0915
196196
self,
197197
exclude_unmodified: bool = False,
198198
exclude_hfid: bool = False,
@@ -235,7 +235,10 @@ def _generate_input_data( # noqa: C901
235235
rel: RelatedNodeBase | RelationshipManagerBase = getattr(self, item_name)
236236

237237
if rel_schema.cardinality == RelationshipCardinality.ONE and rel_schema.optional and not rel.initialized:
238-
data[item_name] = None
238+
# Only include None for existing nodes to allow clearing relationships
239+
# For new nodes, omit the field to allow object template defaults to be applied
240+
if self._existing:
241+
data[item_name] = None
239242
continue
240243

241244
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
@@ -1365,7 +1365,6 @@ async def test_create_input_data(client, location_schema: NodeSchemaAPI, client_
13651365
"name": {"value": "JFK1"},
13661366
"description": {"value": "JFK Airport"},
13671367
"type": {"value": "SITE"},
1368-
"primary_tag": None,
13691368
}
13701369
}
13711370

@@ -1393,6 +1392,38 @@ async def test_create_input_data_with_dropdown(client, location_schema_with_drop
13931392
"description": {"value": "JFK Airport"},
13941393
"type": {"value": "SITE"},
13951394
"status": {"value": None},
1395+
}
1396+
}
1397+
1398+
1399+
@pytest.mark.parametrize("client_type", client_types)
1400+
async def test_update_input_data_existing_node_with_optional_relationship(
1401+
client, location_schema: NodeSchemaAPI, client_type
1402+
) -> None:
1403+
"""Validate that existing nodes include None for uninitialized optional relationships.
1404+
1405+
This ensures that we can explicitly clear optional relationships when updating existing nodes.
1406+
"""
1407+
# Simulate an existing node by including an id
1408+
data = {
1409+
"id": "existing-node-id",
1410+
"name": {"value": "JFK1"},
1411+
"description": {"value": "JFK Airport"},
1412+
"type": {"value": "SITE"},
1413+
}
1414+
1415+
if client_type == "standard":
1416+
node = InfrahubNode(client=client, schema=location_schema, data=data)
1417+
else:
1418+
node = InfrahubNodeSync(client=client, schema=location_schema, data=data)
1419+
1420+
# For existing nodes, optional uninitialized relationships should include None
1421+
assert node._generate_input_data()["data"] == {
1422+
"data": {
1423+
"id": "existing-node-id",
1424+
"name": {"value": "JFK1"},
1425+
"description": {"value": "JFK Airport"},
1426+
"type": {"value": "SITE"},
13961427
"primary_tag": None,
13971428
}
13981429
}
@@ -1641,7 +1672,7 @@ async def test_create_input_data_with_IPHost_attribute(client, ipaddress_schema,
16411672
ip_address = InfrahubNodeSync(client=client, schema=ipaddress_schema, data=data)
16421673

16431674
assert ip_address._generate_input_data()["data"] == {
1644-
"data": {"address": {"value": "1.1.1.1/24", "is_protected": True}, "interface": None}
1675+
"data": {"address": {"value": "1.1.1.1/24", "is_protected": True}}
16451676
}
16461677

16471678

@@ -1655,7 +1686,7 @@ async def test_create_input_data_with_IPNetwork_attribute(client, ipnetwork_sche
16551686
ip_network = InfrahubNodeSync(client=client, schema=ipnetwork_schema, data=data)
16561687

16571688
assert ip_network._generate_input_data()["data"] == {
1658-
"data": {"network": {"value": "1.1.1.0/24", "is_protected": True}, "site": None}
1689+
"data": {"network": {"value": "1.1.1.0/24", "is_protected": True}}
16591690
}
16601691

16611692

0 commit comments

Comments
 (0)