Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[explore] nested config with defaults #26603

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ def infer_schema_from_config_class(

check.param_invariant(
safe_is_subclass(model_cls, Config),
"model_cls",
"Config type annotation must inherit from dagster.Config",
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ def _convert_pydantic_field(
if get_origin(pydantic_field.annotation) == Literal:
return _convert_typing_literal_field(pydantic_field)

field_type = pydantic_field.annotation
field_type = (
pydantic_field.annotation
) # here by just passing the field_type is where we lose any default values
if safe_is_subclass(field_type, Config):
inferred_field = infer_schema_from_config_class(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was that we'd pass the default values to infer_schema_from_config_class and then propogate those down the recursion until they reach the intended non-Config fields. We'd have to deal with overrides, but that seems simple enough - the default set at the higher level would override one set on a lower model.

field_type,
description=pydantic_field.description,
)
# but once we have the non-default inferred field, i'm not sure how we can then apply the defaults
return inferred_field
else:
if not pydantic_field.is_required() and not is_closed_python_optional_type(field_type):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -999,3 +999,41 @@ def echo_job():
d = {"test": "test"}
result = echo_job.execute_in_process(resources={"my_resource": ConfigWithAlias(alias_name=d)})
assert result.output_for_node("echo_config") == d


def test_nested_config_with_defaults() -> None:
class NestedConfig(Config):
a: str
b: int

class ConfigClassToConvert(Config):
nested: NestedConfig = Field(default=NestedConfig(a="a", b=1))
an_int: int = 2

fields = ConfigClassToConvert.to_fields_dict()

assert isinstance(fields, dict)
assert set(fields.keys()) == {
"nested",
"an_int",
}
assert fields["nested"].default_value == {"a": "a", "b": 1}
assert fields["an_int"].default_value == 2

class NestedConfigWithDefaults(Config):
a: str = "a"
b: int = 1

class ConfigClassToConvert(Config):
nested: NestedConfigWithDefaults
an_int: int = 2

fields = ConfigClassToConvert.to_fields_dict()

assert isinstance(fields, dict)
assert set(fields.keys()) == {
"nested",
"an_int",
}
assert fields["nested"].default_value == {"a": "a", "b": 1}
assert fields["an_int"].default_value == 2