From 3be3169074e8eef19db473aa26f61c8dac5c65d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Kali=C5=84ski?= Date: Mon, 18 Nov 2024 13:06:41 +0100 Subject: [PATCH] Update State as_dict --- pyproject.toml | 2 +- src/haiway/state/structure.py | 10 ++++++++-- tests/test_state.py | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index aea04e9..e997fe9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "haiway" description = "Framework for dependency injection and state management within structured concurrency model." -version = "0.5.0" +version = "0.5.1" readme = "README.md" maintainers = [ { name = "Kacper KaliƄski", email = "kacper.kalinski@miquido.com" }, diff --git a/src/haiway/state/structure.py b/src/haiway/state/structure.py index a8ceb46..5ee9cb1 100644 --- a/src/haiway/state/structure.py +++ b/src/haiway/state/structure.py @@ -16,7 +16,7 @@ from haiway.state.attributes import AttributeAnnotation, attribute_annotations from haiway.state.validation import attribute_type_validator -from haiway.types.missing import MISSING, Missing +from haiway.types import MISSING, Missing, not_missing __all__ = [ "State", @@ -184,7 +184,13 @@ def updated( return self.__replace__(**kwargs) def as_dict(self) -> dict[str, Any]: - return vars(self) + dict_result: dict[str, Any] = {} + for key in self.__ATTRIBUTES__.keys(): + value: Any | Missing = getattr(self, key, MISSING) + if not_missing(value): + dict_result[key] = value + + return dict_result def __str__(self) -> str: attributes: str = ", ".join([f"{key}: {value}" for key, value in vars(self).items()]) diff --git a/tests/test_state.py b/tests/test_state.py index 839fed9..cd158ce 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -1,7 +1,7 @@ from collections.abc import Callable from typing import Literal, Protocol, Self, TypedDict, runtime_checkable -from haiway import State, frozenlist +from haiway import MISSING, Missing, State, frozenlist def test_basic_initializes_with_arguments() -> None: @@ -63,6 +63,17 @@ class Basics(State): assert basic.optional is None +def test_basic_equals_checks_properties() -> None: + class Basics(State): + string: str + integer: int + + assert Basics(string="a", integer=1) == Basics(string="a", integer=1) + assert Basics(string="a", integer=1) != Basics(string="b", integer=1) + assert Basics(string="a", integer=1) != Basics(string="a", integer=2) + assert Basics(string="a", integer=1) != Basics(string="b", integer=2) + + def test_basic_initializes_with_arguments_and_defaults() -> None: class Basics(State): string: str @@ -119,3 +130,23 @@ class Recursive(State): recursion=None, self_recursion=None, ) + + +def test_dict_skips_missing_properties() -> None: + class Basics(State): + string: str + integer: int | Missing | None + + assert Basics(string="a", integer=1).as_dict() == {"string": "a", "integer": 1} + assert Basics(string="a", integer=MISSING).as_dict() == {"string": "a"} + assert Basics(string="a", integer=None).as_dict() == {"string": "a", "integer": None} + + +def test_initialization_allows_missing_properties() -> None: + class Basics(State): + string: str + integer: int | Missing | None + + assert Basics(**{"string": "a", "integer": 1}) == Basics(string="a", integer=1) + assert Basics(**{"string": "a", "integer": None}) == Basics(string="a", integer=None) + assert Basics(**{"string": "a"}) == Basics(string="a", integer=MISSING)