Skip to content

Commit 16825fc

Browse files
authored
Merge pull request #588 from mit-ll-responsible-ai/auto-config-fix
fix store autoconfig issue
2 parents e31c388 + 3985e35 commit 16825fc

5 files changed

Lines changed: 54 additions & 21 deletions

File tree

src/hydra_zen/structured_configs/_implementations.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ def _check_instance(*target_types: str, value: "Any", module: str): # pragma: n
560560
_check_instance, "required", module="torch.optim.optimizer"
561561
)
562562

563+
_is_pydantic_BaseModel = functools.partial(
564+
_check_instance, "BaseModel", module="pydantic"
565+
)
566+
563567

564568
def _check_for_dynamically_defined_dataclass_type(target_path: str, value: Any) -> None:
565569
if target_path.startswith("types."):
@@ -1096,13 +1100,16 @@ def _make_hydra_compatible(
10961100
pydantic = sys.modules.get("pydantic")
10971101

10981102
if pydantic is not None: # pragma: no cover
1099-
if isinstance(value, pydantic.fields.FieldInfo):
1103+
if _check_instance("FieldInfo", module="pydantic.fields", value=value):
11001104
_val = (
11011105
value.default_factory() # type: ignore
11021106
if value.default_factory is not None # type: ignore
11031107
else value.default # type: ignore
11041108
)
1105-
if isinstance(_val, pydantic.fields.UndefinedType):
1109+
1110+
if _check_instance(
1111+
"UndefinedType", module="pydantic.fields", value=_val
1112+
):
11061113
return MISSING
11071114

11081115
return cls._make_hydra_compatible(
@@ -1115,11 +1122,11 @@ def _make_hydra_compatible(
11151122
hydra_convert=hydra_convert,
11161123
hydra_recursive=hydra_recursive,
11171124
)
1118-
if isinstance(value, pydantic.BaseModel):
1125+
if _is_pydantic_BaseModel(value=value):
11191126
return cls.builds(type(value), **value.__dict__)
11201127

1121-
if isinstance(value, str) or (
1122-
pydantic is not None and isinstance(value, pydantic.AnyUrl)
1128+
if isinstance(value, str) or _check_instance(
1129+
"AnyUrl", module="pydantic", value=value
11231130
):
11241131
# Supports pydantic.AnyURL
11251132
_v = str(value)

src/hydra_zen/wrapper/_implementations.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from functools import partial, wraps
1010
from inspect import Parameter, iscoroutinefunction, signature
1111
from typing import (
12+
TYPE_CHECKING,
1213
Any,
1314
Callable,
1415
DefaultDict,
@@ -48,7 +49,7 @@
4849
from hydra_zen import instantiate
4950
from hydra_zen._compatibility import HYDRA_VERSION, Version
5051
from hydra_zen.errors import HydraZenValidationError
51-
from hydra_zen.structured_configs._implementations import BuildsFn, DefaultBuilds
52+
from hydra_zen.structured_configs._implementations import DefaultBuilds
5253
from hydra_zen.structured_configs._type_guards import safe_getattr
5354
from hydra_zen.typing._implementations import (
5455
DataClass_,
@@ -61,9 +62,12 @@
6162
from ..structured_configs._type_guards import is_dataclass
6263
from ..structured_configs._utils import safe_name
6364

65+
if TYPE_CHECKING:
66+
from hydra_zen import BuildsFn
67+
68+
6469
__all__ = ["zen", "store", "Zen"]
6570

66-
get_obj_path = BuildsFn._get_obj_path # type: ignore
6771

6872
R = TypeVar("R")
6973
P = ParamSpec("P")
@@ -830,7 +834,7 @@ def default_to_config(
830834
ListConfig,
831835
DictConfig,
832836
],
833-
BuildsFn: Type[BuildsFn[Any]] = DefaultBuilds,
837+
CustomBuildsFn: Type["BuildsFn[Any]"] = DefaultBuilds,
834838
**kw: Any,
835839
) -> Union[DataClass_, Type[DataClass_], ListConfig, DictConfig]:
836840
"""Creates a config that describes `target`.
@@ -849,7 +853,7 @@ def default_to_config(
849853
----------
850854
target : Callable[..., Any] | DataClass | Type[DataClass] | list | dict
851855
852-
BuildsFn : Type[BuildsFn[Any]], optional (default=DefaultBuilds)
856+
CustomBuildsFn : Type[BuildsFn[Any]], optional (default=DefaultBuilds)
853857
Provides the config-creation functions (`builds`, `just`) used
854858
by this function.
855859
@@ -893,21 +897,20 @@ def default_to_config(
893897
'y': ???
894898
"""
895899

900+
kw = kw.copy()
901+
896902
if is_dataclass(target):
897903
if isinstance(target, type):
898904
if issubclass(target, HydraConf):
899905
# don't auto-config HydraConf
900906
return target
901907

902-
if not kw and get_obj_path(target).startswith("types."):
908+
if not kw and CustomBuildsFn._get_obj_path(target).startswith("types."): # type: ignore
903909
# handles dataclasses returned by make_config()
904910
return target
905-
return BuildsFn.builds(
906-
target,
907-
**kw,
908-
populate_full_signature=True,
909-
builds_bases=(target,),
910-
)
911+
kw.setdefault("populate_full_signature", True)
912+
kw.setdefault("builds_bases", (target,))
913+
return CustomBuildsFn.builds(target, **kw)
911914
if kw:
912915
raise ValueError(
913916
"store(<dataclass-instance>, [...]) does not support specifying "
@@ -917,14 +920,13 @@ def default_to_config(
917920

918921
elif isinstance(target, (dict, list)):
919922
# TODO: convert to OmegaConf containers?
920-
return BuildsFn.just(target)
923+
return CustomBuildsFn.just(target)
921924
elif isinstance(target, (DictConfig, ListConfig)):
922925
return target
923926
else:
924927
t = cast(Callable[..., Any], target)
925-
return cast(
926-
Type[DataClass_], BuildsFn.builds(t, **kw, populate_full_signature=True)
927-
)
928+
kw.setdefault("populate_full_signature", True)
929+
return cast(Type[DataClass_], CustomBuildsFn.builds(t, **kw))
928930

929931

930932
class _HasName(Protocol):

tests/test_BuildsFn.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def test_zen_field():
167167

168168
def test_default_to_config():
169169
store = ZenStore("my store")(
170-
to_config=partial(default_to_config, BuildsFn=MyBuildsFn)
170+
to_config=partial(default_to_config, CustomBuildsFn=MyBuildsFn)
171171
)
172172
store(A, x=A(x=2), name="blah")
173173
assert instantiate(store[None, "blah"]) == A(x=A(x=2))

tests/test_store.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
just,
2525
make_config,
2626
store as default_store,
27+
to_yaml,
2728
)
2829
from tests.custom_strategies import new_stores, store_entries
2930

@@ -982,3 +983,19 @@ def test_merge():
982983
assert s3._queue == {(None, "a"), (None, "b"), (None, "c")}
983984
assert s3._internal_repo[None, "a"] is not s1._internal_repo[None, "a"]
984985
assert s3._internal_repo[None, "b"] is not s2._internal_repo[None, "b"]
986+
987+
988+
def test_disable_pop_sig_autoconfig():
989+
s = ZenStore()
990+
s(ZenStore, populate_full_signature=False, name="s")
991+
config = s[None, "s"]
992+
assert len(to_yaml(config).splitlines()) == 1
993+
sout = instantiate(s[None, "s"])
994+
assert isinstance(sout, ZenStore)
995+
996+
s2 = ZenStore()
997+
s2(ZenStore, name="s")
998+
config2 = s2[None, "s"]
999+
assert len(to_yaml(config2).splitlines()) > 1
1000+
sout2 = instantiate(s2[None, "s"])
1001+
assert isinstance(sout2, ZenStore)

tests/test_third_party/test_using_v1_pydantic.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) 2023 Massachusetts Institute of Technology
22
# SPDX-License-Identifier: MIT
33
import dataclasses
4+
import sys
45
from typing import Any, List, Optional
56

67
import hypothesis.strategies as st
@@ -28,6 +29,12 @@
2829
)
2930

3031

32+
def test_BaseModel():
33+
_pydantic = sys.modules.get("pydantic")
34+
assert _pydantic is not None
35+
assert _pydantic.BaseModel is BaseModel
36+
37+
3138
@parametrize_pydantic_fields
3239
def test_pydantic_specific_fields_function(custom_type, good_val, bad_val):
3340
def f(x):

0 commit comments

Comments
 (0)