From 2f54e4549731edf1f645f17941f54d173415ee6b Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Tue, 5 Dec 2023 13:04:43 +0100 Subject: [PATCH 1/6] Fix field exclusion logic in registry class when validate is False --- confection/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/confection/__init__.py b/confection/__init__.py index 9c6922c..7edfeba 100644 --- a/confection/__init__.py +++ b/confection/__init__.py @@ -692,6 +692,7 @@ def alias_generator(name: str) -> str: return name + def copy_model_field(field: ModelField, type_: Any) -> ModelField: """Copy a model field and assign a new type, e.g. to accept an Any type even though the original value is typed differently. @@ -936,7 +937,12 @@ def _fill( # manually because .construct doesn't parse anything if schema.Config.extra in (Extra.forbid, Extra.ignore): fields = schema.__fields__.keys() - exclude = [k for k in result.__fields_set__ if k not in fields] + # If we have a reserved field, we need to use its alias + field_set = [ + k if k != ARGS_FIELD else ARGS_FIELD_ALIAS for k in result.__fields_set__ + ] + # field_set = result.__fields_set__ + exclude = [k for k in field_set if k not in fields] exclude_validation = set([ARGS_FIELD_ALIAS, *RESERVED_FIELDS.keys()]) validation.update(result.dict(exclude=exclude_validation)) filled, final = cls._update_from_parsed(validation, filled, final) From a6c9a50a67f631b3386778ca79a065cf1badf21d Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Tue, 5 Dec 2023 15:04:05 +0100 Subject: [PATCH 2/6] Fix missing field alias issue in copy_model_field() --- confection/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/confection/__init__.py b/confection/__init__.py index 7edfeba..f3f4567 100644 --- a/confection/__init__.py +++ b/confection/__init__.py @@ -705,6 +705,7 @@ def copy_model_field(field: ModelField, type_: Any) -> ModelField: default=field.default, default_factory=field.default_factory, required=field.required, + alias=field.alias, ) @@ -913,6 +914,15 @@ def _fill( # created via config blocks), only use its values validation[v_key] = list(validation[v_key].values()) final[key] = list(final[key].values()) + + if ARGS_FIELD_ALIAS in schema.__fields__ and not resolve: + # If we're not resolving the config, make sure that the field + # expecting the promise is typed Any so it doesn't fail + # validation if it doesn't receive the function return value + field = schema.__fields__[ARGS_FIELD_ALIAS] + schema.__fields__[ARGS_FIELD_ALIAS] = copy_model_field( + field, Any + ) else: filled[key] = value # Prevent pydantic from consuming generator if part of a union From 74f7d6e9e8a9f7d4251b9f0c01cccb40cc5bf6d6 Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Tue, 5 Dec 2023 18:46:53 +0100 Subject: [PATCH 3/6] Add test for filling config positional args with promise --- confection/tests/test_config.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/confection/tests/test_config.py b/confection/tests/test_config.py index 5873eb2..2d46118 100644 --- a/confection/tests/test_config.py +++ b/confection/tests/test_config.py @@ -424,6 +424,31 @@ def catsie_567(*args: Optional[str], foo: str = "bar"): assert my_registry.resolve(cfg)["config"] == "^_^" +def test_fill_config_positional_args_w_promise(): + @my_registry.cats("catsie.v568") + def catsie_568(*args: str, foo: str = "bar"): + assert args[0] == "^(*.*)^" + assert foo == "baz" + return args[0] + + @my_registry.cats("cat_promise.v568") + def cat_promise() -> str: + return "^(*.*)^" + + cfg = { + "test_fn": {"@cats": "catsie.v568", "*": {"test_arg": {"@registry": "factory"}}} + } + cfg = { + "config": { + "@cats": "catsie.v568", + "*": {"promise": {"@cats": "cat_promise.v568"}}, + } + } + filled = my_registry.fill(cfg, validate=True) + assert filled["config"]["foo"] == "bar" + assert filled["config"]["*"] == {"promise": {"@cats": "cat_promise.v568"}} + + def test_make_config_positional_args_complex(): @my_registry.cats("catsie.v890") def catsie_890(*args: Optional[Union[StrictBool, PositiveInt]]): From 7dde04d0956fd528f1f71ee256a02cf558b462f7 Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Tue, 5 Dec 2023 18:55:51 +0100 Subject: [PATCH 4/6] chore: removed comment out code --- confection/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/confection/__init__.py b/confection/__init__.py index f3f4567..04dbc05 100644 --- a/confection/__init__.py +++ b/confection/__init__.py @@ -951,7 +951,6 @@ def _fill( field_set = [ k if k != ARGS_FIELD else ARGS_FIELD_ALIAS for k in result.__fields_set__ ] - # field_set = result.__fields_set__ exclude = [k for k in field_set if k not in fields] exclude_validation = set([ARGS_FIELD_ALIAS, *RESERVED_FIELDS.keys()]) validation.update(result.dict(exclude=exclude_validation)) From d777cb4badd848b6a71ae00422859648117adcd4 Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Wed, 6 Dec 2023 10:32:59 +0100 Subject: [PATCH 5/6] formatted to black --- confection/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/confection/__init__.py b/confection/__init__.py index 04dbc05..0395498 100644 --- a/confection/__init__.py +++ b/confection/__init__.py @@ -692,7 +692,6 @@ def alias_generator(name: str) -> str: return name - def copy_model_field(field: ModelField, type_: Any) -> ModelField: """Copy a model field and assign a new type, e.g. to accept an Any type even though the original value is typed differently. @@ -949,7 +948,8 @@ def _fill( fields = schema.__fields__.keys() # If we have a reserved field, we need to use its alias field_set = [ - k if k != ARGS_FIELD else ARGS_FIELD_ALIAS for k in result.__fields_set__ + k if k != ARGS_FIELD else ARGS_FIELD_ALIAS + for k in result.__fields_set__ ] exclude = [k for k in field_set if k not in fields] exclude_validation = set([ARGS_FIELD_ALIAS, *RESERVED_FIELDS.keys()]) From 17e49ec544b384eda8e99344400ab835b8e36423 Mon Sep 17 00:00:00 2001 From: Kenneth Enevoldsen Date: Tue, 19 Dec 2023 16:25:49 +0100 Subject: [PATCH 6/6] remove unused cfg --- confection/tests/test_config.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/confection/tests/test_config.py b/confection/tests/test_config.py index 2d46118..58600cf 100644 --- a/confection/tests/test_config.py +++ b/confection/tests/test_config.py @@ -435,9 +435,6 @@ def catsie_568(*args: str, foo: str = "bar"): def cat_promise() -> str: return "^(*.*)^" - cfg = { - "test_fn": {"@cats": "catsie.v568", "*": {"test_arg": {"@registry": "factory"}}} - } cfg = { "config": { "@cats": "catsie.v568",