diff --git a/changelog/535.fixed.md b/changelog/535.fixed.md index fdbd499e..56c8fd43 100644 --- a/changelog/535.fixed.md +++ b/changelog/535.fixed.md @@ -1 +1 @@ -Fix branch handling in `_run_transform` and `execute_graphql_query` functions in Infrahubctl to use environment variables for branch management. \ No newline at end of file +Fix branch handling in `_run_transform` and `execute_graphql_query` functions in Infrahubctl to use environment variables for branch management. \ No newline at end of file diff --git a/changelog/549.fixed.md b/changelog/549.fixed.md new file mode 100644 index 00000000..1a4f975c --- /dev/null +++ b/changelog/549.fixed.md @@ -0,0 +1 @@ +Allow the ability to clear optional attributes by setting them to None if they have been mutated by the user. \ No newline at end of file diff --git a/infrahub_sdk/node/attribute.py b/infrahub_sdk/node/attribute.py index 5ddc5cbe..9c752521 100644 --- a/infrahub_sdk/node/attribute.py +++ b/infrahub_sdk/node/attribute.py @@ -76,6 +76,8 @@ def _generate_input_data(self) -> dict | None: variables: dict[str, Any] = {} if self.value is None: + if self._schema.optional and self.value_has_been_mutated: + data["value"] = None return data if isinstance(self.value, str): diff --git a/tests/unit/sdk/conftest.py b/tests/unit/sdk/conftest.py index 5f0d7c2a..92749412 100644 --- a/tests/unit/sdk/conftest.py +++ b/tests/unit/sdk/conftest.py @@ -177,6 +177,48 @@ async def location_schema() -> NodeSchemaAPI: return NodeSchema(**data).convert_api() # type: ignore +@pytest.fixture +async def location_schema_with_dropdown() -> NodeSchemaAPI: + data = { + "name": "Location", + "namespace": "Builtin", + "default_filter": "name__value", + "attributes": [ + {"name": "name", "kind": "String", "unique": True}, + {"name": "description", "kind": "String", "optional": True}, + {"name": "type", "kind": "String"}, + { + "name": "status", + "kind": "Dropdown", + "optional": True, + "choices": [{"name": "active", "label": "Active"}, {"name": "planning", "label": "Planning"}], + }, + ], + "relationships": [ + { + "name": "tags", + "peer": "BuiltinTag", + "optional": True, + "cardinality": "many", + }, + { + "name": "primary_tag", + "peer": "BuiltinTag", + "optional": True, + "cardinality": "one", + }, + { + "name": "member_of_groups", + "peer": "CoreGroup", + "optional": True, + "cardinality": "many", + "kind": "Group", + }, + ], + } + return NodeSchema(**data).convert_api() # type: ignore + + @pytest.fixture async def schema_with_hfid() -> dict[str, NodeSchemaAPI]: data = { diff --git a/tests/unit/sdk/test_node.py b/tests/unit/sdk/test_node.py index c5c75052..e4192871 100644 --- a/tests/unit/sdk/test_node.py +++ b/tests/unit/sdk/test_node.py @@ -1370,6 +1370,34 @@ async def test_create_input_data(client, location_schema: NodeSchemaAPI, client_ } +@pytest.mark.parametrize("client_type", client_types) +async def test_create_input_data_with_dropdown(client, location_schema_with_dropdown, client_type) -> None: + """Validate input data including dropdown field""" + data = { + "name": {"value": "JFK1"}, + "description": {"value": "JFK Airport"}, + "type": {"value": "SITE"}, + "status": {"value": "active"}, + } + + if client_type == "standard": + node = InfrahubNode(client=client, schema=location_schema_with_dropdown, data=data) + else: + node = InfrahubNodeSync(client=client, schema=location_schema_with_dropdown, data=data) + + assert node.status.value == "active" + node.status = None + assert node._generate_input_data()["data"] == { + "data": { + "name": {"value": "JFK1"}, + "description": {"value": "JFK Airport"}, + "type": {"value": "SITE"}, + "status": {"value": None}, + "primary_tag": None, + } + } + + @pytest.mark.parametrize("client_type", client_types) async def test_create_input_data__with_relationships_02(client, location_schema, client_type) -> None: """Validate input data with variables that needs replacements"""