From 8d8c44a33b84a6921e36c37aa157c49f7f754b89 Mon Sep 17 00:00:00 2001 From: Chris White Date: Tue, 4 Feb 2025 10:32:12 -0800 Subject: [PATCH 1/4] Remove switching logic within settings config --- src/prefect/_internal/schemas/bases.py | 14 +++----------- src/prefect/server/utilities/schemas/bases.py | 14 +++----------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/prefect/_internal/schemas/bases.py b/src/prefect/_internal/schemas/bases.py index 67f0a233b2ac..b34409478676 100644 --- a/src/prefect/_internal/schemas/bases.py +++ b/src/prefect/_internal/schemas/bases.py @@ -3,7 +3,6 @@ """ import datetime -import os from typing import Any, ClassVar, Optional, TypeVar, cast from uuid import UUID, uuid4 @@ -25,9 +24,7 @@ class PrefectBaseModel(BaseModel): fields that are passed to it at instantiation. Because adding new fields to API payloads is not considered a breaking change, this ensures that any Prefect client loading data from a server running a possibly-newer version - of Prefect will be able to process those new fields gracefully. However, - when PREFECT_TEST_MODE is on, extra fields are forbidden in order to catch - subtle unintentional testing errors. + of Prefect will be able to process those new fields gracefully. """ _reset_fields: ClassVar[set[str]] = set() @@ -35,16 +32,11 @@ class PrefectBaseModel(BaseModel): model_config: ClassVar[ConfigDict] = ConfigDict( ser_json_timedelta="float", defer_build=True, - extra=( - "ignore" - if os.getenv("PREFECT_TEST_MODE", "0").lower() not in ["true", "1"] - and os.getenv("PREFECT_TESTING_TEST_MODE", "0").lower() not in ["true", "1"] - else "forbid" - ), + extra="ignore", ) def __eq__(self, other: Any) -> bool: - """Equaltiy operator that ignores the resettable fields of the PrefectBaseModel. + """Equality operator that ignores the resettable fields of the PrefectBaseModel. NOTE: this equality operator will only be applied if the PrefectBaseModel is the left-hand operand. This is a limitation of Python. diff --git a/src/prefect/server/utilities/schemas/bases.py b/src/prefect/server/utilities/schemas/bases.py index 98298b1f7a40..4b2e232029a8 100644 --- a/src/prefect/server/utilities/schemas/bases.py +++ b/src/prefect/server/utilities/schemas/bases.py @@ -1,5 +1,4 @@ import datetime -import os from abc import ABC, abstractmethod from functools import partial from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar @@ -65,26 +64,19 @@ class PrefectBaseModel(BaseModel): fields that are passed to it at instantiation. Because adding new fields to API payloads is not considered a breaking change, this ensures that any Prefect client loading data from a server running a possibly-newer version - of Prefect will be able to process those new fields gracefully. However, - when PREFECT_TEST_MODE is on, extra fields are forbidden in order to catch - subtle unintentional testing errors. + of Prefect will be able to process those new fields gracefully. """ _reset_fields: ClassVar[set[str]] = set() model_config: ClassVar[ConfigDict] = ConfigDict( ser_json_timedelta="float", - extra=( - "ignore" - if os.getenv("PREFECT_TEST_MODE", "0").lower() not in ["true", "1"] - and os.getenv("PREFECT_TESTING_TEST_MODE", "0").lower() not in ["true", "1"] - else "forbid" - ), + extra="ignore", ignored_types=(PrefectDescriptorBase,), ) def __eq__(self, other: Any) -> bool: - """Equaltiy operator that ignores the resettable fields of the PrefectBaseModel. + """Equality operator that ignores the resettable fields of the PrefectBaseModel. NOTE: this equality operator will only be applied if the PrefectBaseModel is the left-hand operand. This is a limitation of Python. From 395bd2f5cd15634d62b76038391b1879d564c1ae Mon Sep 17 00:00:00 2001 From: Chris White Date: Tue, 4 Feb 2025 10:35:35 -0800 Subject: [PATCH 2/4] Update ref to string in labeler --- .github/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 5b49503caca3..080e60c9cdf6 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -19,4 +19,4 @@ upstream dependency: ui-replatform: - changed-files: - any-glob-to-any-file: ui-v2/** - - all-globs-to-all-files: !ui-v2/src/api/prefect.ts \ No newline at end of file + - all-globs-to-all-files: '!ui-v2/src/api/prefect.ts' \ No newline at end of file From ba84a5cd35bd7b25629b5f2945e852e2e33579d9 Mon Sep 17 00:00:00 2001 From: Chris White Date: Tue, 4 Feb 2025 11:06:31 -0800 Subject: [PATCH 3/4] Bring back server logic because its implicitly relied on --- src/prefect/server/utilities/schemas/bases.py | 13 ++++++-- tests/server/utilities/test_schemas.py | 31 ++----------------- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/src/prefect/server/utilities/schemas/bases.py b/src/prefect/server/utilities/schemas/bases.py index 4b2e232029a8..2b6405f78d00 100644 --- a/src/prefect/server/utilities/schemas/bases.py +++ b/src/prefect/server/utilities/schemas/bases.py @@ -1,4 +1,5 @@ import datetime +import os from abc import ABC, abstractmethod from functools import partial from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar @@ -64,14 +65,22 @@ class PrefectBaseModel(BaseModel): fields that are passed to it at instantiation. Because adding new fields to API payloads is not considered a breaking change, this ensures that any Prefect client loading data from a server running a possibly-newer version - of Prefect will be able to process those new fields gracefully. + of Prefect will be able to process those new fields gracefully. However, + when PREFECT_TEST_MODE is on, extra fields are forbidden in order to catch + subtle unintentional testing errors. """ _reset_fields: ClassVar[set[str]] = set() + # TODO: investigate why removing this fails composite trigger tests? model_config: ClassVar[ConfigDict] = ConfigDict( ser_json_timedelta="float", - extra="ignore", + extra=( + "ignore" + if os.getenv("PREFECT_TEST_MODE", "0").lower() not in ["true", "1"] + and os.getenv("PREFECT_TESTING_TEST_MODE", "0").lower() not in ["true", "1"] + else "forbid" + ), ignored_types=(PrefectDescriptorBase,), ) diff --git a/tests/server/utilities/test_schemas.py b/tests/server/utilities/test_schemas.py index d7df54b185ce..771e1b506f1d 100644 --- a/tests/server/utilities/test_schemas.py +++ b/tests/server/utilities/test_schemas.py @@ -48,40 +48,13 @@ def reload_prefect_base_model( class TestExtraForbidden: - def test_extra_attributes_are_forbidden_during_unit_tests(self): + @pytest.mark.parametrize("falsey_value", ["0", "False", "", None]) + def test_extra_attributes_are_allowed(self, falsey_value: Optional[str]): class Model(PrefectBaseModel): x: int - with pytest.raises( - pydantic.ValidationError, match="Extra inputs are not permitted" - ): - Model(x=1, y=2) - - @pytest.mark.parametrize("falsey_value", ["0", "False", "", None]) - def test_extra_attributes_are_allowed_outside_test_mode( - self, falsey_value: Optional[str] - ): - with reload_prefect_base_model(falsey_value) as PrefectBaseModel: - - class Model(PrefectBaseModel): - x: int - Model(x=1, y=2) - @pytest.mark.parametrize("truthy_value", ["1", "True", "true"]) - def test_extra_attributes_are_not_allowed_with_truthy_test_mode( - self, truthy_value: Optional[str] - ): - with reload_prefect_base_model(truthy_value) as PrefectBaseModel: - - class Model(PrefectBaseModel): - x: int - - with pytest.raises( - pydantic.ValidationError, match="Extra inputs are not permitted" - ): - Model(x=1, y=2) - class TestNestedDict: @pytest.fixture() From 3fe5a6b2ed0c8c881d2a8c2aecbd1c1431e67b97 Mon Sep 17 00:00:00 2001 From: Chris White Date: Tue, 4 Feb 2025 11:17:06 -0800 Subject: [PATCH 4/4] Revert test schemas file too --- tests/server/utilities/test_schemas.py | 31 ++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/server/utilities/test_schemas.py b/tests/server/utilities/test_schemas.py index 771e1b506f1d..d7df54b185ce 100644 --- a/tests/server/utilities/test_schemas.py +++ b/tests/server/utilities/test_schemas.py @@ -48,13 +48,40 @@ def reload_prefect_base_model( class TestExtraForbidden: - @pytest.mark.parametrize("falsey_value", ["0", "False", "", None]) - def test_extra_attributes_are_allowed(self, falsey_value: Optional[str]): + def test_extra_attributes_are_forbidden_during_unit_tests(self): class Model(PrefectBaseModel): x: int + with pytest.raises( + pydantic.ValidationError, match="Extra inputs are not permitted" + ): + Model(x=1, y=2) + + @pytest.mark.parametrize("falsey_value", ["0", "False", "", None]) + def test_extra_attributes_are_allowed_outside_test_mode( + self, falsey_value: Optional[str] + ): + with reload_prefect_base_model(falsey_value) as PrefectBaseModel: + + class Model(PrefectBaseModel): + x: int + Model(x=1, y=2) + @pytest.mark.parametrize("truthy_value", ["1", "True", "true"]) + def test_extra_attributes_are_not_allowed_with_truthy_test_mode( + self, truthy_value: Optional[str] + ): + with reload_prefect_base_model(truthy_value) as PrefectBaseModel: + + class Model(PrefectBaseModel): + x: int + + with pytest.raises( + pydantic.ValidationError, match="Extra inputs are not permitted" + ): + Model(x=1, y=2) + class TestNestedDict: @pytest.fixture()