From 7588d8bb4912f4eb5d8e494e2f891106753e287a Mon Sep 17 00:00:00 2001 From: thomasborgen Date: Sun, 21 Dec 2025 12:50:19 +0100 Subject: [PATCH 1/2] Allow None in children, but ignore it in output --- hypermedia/models/base.py | 7 ++++--- hypermedia/types/types.py | 2 +- tests/integration/test_formatting.py | 7 +++++++ tests/models/element/test_extend.py | 17 +++++++++++++++++ tests/models/element/test_render_children.py | 1 + 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/hypermedia/models/base.py b/hypermedia/models/base.py index fd002e2..59048d2 100644 --- a/hypermedia/models/base.py +++ b/hypermedia/models/base.py @@ -101,7 +101,7 @@ def __init__( **attributes: Any, ) -> None: """Initialize Root with children.""" - self.children = children + self.children = tuple(c for c in children if c is not None) self.slot = slot self.slots = get_slots(self) self.attributes = attributes @@ -117,10 +117,11 @@ def extend(self, slot: str, *children: AnyChildren) -> Self: raise ValueError(f"Could not find a slot with name: {slot}") element = self.slots[slot] - element.children = element.children + children + new_children = tuple(child for child in children if child is not None) + element.children = element.children + new_children get_child_slots( - self.slots, [c for c in children if isinstance(c, Element)] + self.slots, [c for c in new_children if isinstance(c, Element)] ) return self diff --git a/hypermedia/types/types.py b/hypermedia/types/types.py index 693565e..e4b1e10 100644 --- a/hypermedia/types/types.py +++ b/hypermedia/types/types.py @@ -25,7 +25,7 @@ class SafeString(str): ComplexChildren: TypeAlias = "Element" """Type alias for elements that are allowed to have only non-primitive children.""" # noqa: E501 -AnyChildren: TypeAlias = Union[PrimitiveChildren, ComplexChildren] +AnyChildren: TypeAlias = Union[PrimitiveChildren, ComplexChildren, None] """Type alias for elements that are allowed to have any children.""" # PLC0105 `TypeVar` name "TChildren" does not reflect its covariance; diff --git a/tests/integration/test_formatting.py b/tests/integration/test_formatting.py index 62079b0..ad3cee6 100644 --- a/tests/integration/test_formatting.py +++ b/tests/integration/test_formatting.py @@ -111,3 +111,10 @@ def test_void_elements_and_aliases( ) -> None: assert element().dump() == result assert alias().dump() == result + + +def test_none_children_are_skipped() -> None: + assert Bold(None).dump() == "" + assert Bold("Test", None).dump() == "Test" + assert Bold(None, "Test").dump() == "Test" + assert Bold(None, None).dump() == "" diff --git a/tests/models/element/test_extend.py b/tests/models/element/test_extend.py index 7994b1c..359ebdd 100644 --- a/tests/models/element/test_extend.py +++ b/tests/models/element/test_extend.py @@ -10,6 +10,23 @@ def test_extend_adds_child_to_slot() -> None: assert element.children == (child,) +def test_extend_skips_adding_none_child_to_slot() -> None: + element = TestElement(slot="my_slot") + + element.extend("my_slot", None) + + assert element.children == () + + +def test_extend_skips_only_none_values() -> None: + element = TestElement(slot="my_slot") + child = TestElement() + + element.extend("my_slot", child, None) + + assert element.children == (child,) + + def test_extend_adds_children_to_slot() -> None: element = TestElement(slot="my_slot") child_1 = TestElement() diff --git a/tests/models/element/test_render_children.py b/tests/models/element/test_render_children.py index 6a542c2..9a25706 100644 --- a/tests/models/element/test_render_children.py +++ b/tests/models/element/test_render_children.py @@ -30,6 +30,7 @@ def test_renders_safe_string_children_as_is() -> None: def test_primitive_types_are_rendered() -> None: assert TestElement(1)._render_children() == "1" assert TestElement(1.1)._render_children() == "1.1" + assert TestElement(None)._render_children() == "" assert TestElement(True)._render_children() == "True" assert TestElement(False)._render_children() == "False" assert TestElement("test")._render_children() == "test" From 9675e0711706cd8175a985bde0798cb3e6b31e87 Mon Sep 17 00:00:00 2001 From: thomasborgen Date: Sun, 21 Dec 2025 13:51:37 +0100 Subject: [PATCH 2/2] Add Changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b6654..b45825e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Features +* Allow None values through and skip them. * Allow primitives through without having to cast them to str first. * Add Decimal as an allowed primitive.