diff --git a/changelog/894.fixed.md b/changelog/894.fixed.md new file mode 100644 index 00000000..ee904ade --- /dev/null +++ b/changelog/894.fixed.md @@ -0,0 +1 @@ +Generate protocols where optional attributes with a default value renders attributes that are required, i.e. not nullable. diff --git a/infrahub_sdk/protocols_generator/generator.py b/infrahub_sdk/protocols_generator/generator.py index 38bc968f..14c8438f 100644 --- a/infrahub_sdk/protocols_generator/generator.py +++ b/infrahub_sdk/protocols_generator/generator.py @@ -117,7 +117,7 @@ def _jinja2_filter_syncify(value: str | list, sync: bool = False) -> str | list: def _jinja2_filter_render_attribute(value: AttributeSchemaAPI) -> str: attribute_kind: str = ATTRIBUTE_KIND_MAP[value.kind] - if value.optional: + if value.optional and value.default_value is None: attribute_kind += "Optional" return f"{value.name}: {attribute_kind}" diff --git a/tests/unit/sdk/test_protocols_generator.py b/tests/unit/sdk/test_protocols_generator.py index 55796db6..730f962c 100644 --- a/tests/unit/sdk/test_protocols_generator.py +++ b/tests/unit/sdk/test_protocols_generator.py @@ -1,10 +1,11 @@ from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any import pytest from infrahub_sdk import InfrahubClient from infrahub_sdk.protocols_generator.generator import CodeGenerator +from infrahub_sdk.schema import AttributeSchemaAPI if TYPE_CHECKING: from pytest_httpx import HTTPXMock @@ -36,6 +37,56 @@ class SyncifyTestCase: ] +@dataclass +class RenderAttributeTestCase: + name: str + optional: bool + default_value: Any + expected: str + + +RENDER_ATTRIBUTE_TEST_CASES = [ + RenderAttributeTestCase( + name="required-no-default", + optional=False, + default_value=None, + expected="enabled: Boolean", + ), + RenderAttributeTestCase( + name="required-with-default", + optional=False, + default_value=True, + expected="enabled: Boolean", + ), + RenderAttributeTestCase( + name="optional-no-default", + optional=True, + default_value=None, + expected="enabled: BooleanOptional", + ), + RenderAttributeTestCase( + name="optional-with-default", + optional=True, + default_value=True, + expected="enabled: Boolean", + ), +] + + +@pytest.mark.parametrize( + "test_case", + [pytest.param(tc, id=tc.name) for tc in RENDER_ATTRIBUTE_TEST_CASES], +) +async def test_filter_render_attribute(test_case: RenderAttributeTestCase) -> None: + attr = AttributeSchemaAPI( + name="enabled", + kind="Boolean", + optional=test_case.optional, + default_value=test_case.default_value, + ) + assert CodeGenerator._jinja2_filter_render_attribute(attr) == test_case.expected + + @pytest.mark.parametrize( "test_case", [pytest.param(tc, id=tc.name) for tc in SYNCIFY_TEST_CASES],