Skip to content

Commit 8904071

Browse files
authored
Merge pull request #708 from mit-ll-responsible-ai/support-class-in-class
Update _get_obj_path to support ClassA.ClassB
2 parents 2e7e253 + cd4c987 commit 8904071

2 files changed

Lines changed: 32 additions & 6 deletions

File tree

src/hydra_zen/structured_configs/_implementations.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ def _get_obj_path(cls, target: Any) -> str:
948948
949949
Override this to control how `builds` determines the _target_ field
950950
in the configs that it produces."""
951+
951952
name = _utils.safe_name(target, repr_allowed=False)
952953

953954
if name == _utils.UNKNOWN_NAME:
@@ -986,12 +987,14 @@ def _get_obj_path(cls, target: Any) -> str:
986987

987988
if not _utils.is_classmethod(target):
988989
if (
989-
inspect.isfunction(target)
990+
(inspect.isfunction(target) or isinstance(target, type))
990991
and isinstance(qualname, str)
991992
and "." in qualname
992993
and all(x.isidentifier() for x in qualname.split("."))
993994
):
994-
# this looks like it is a staticmethod. E.g. qualname: SomeClass.func
995+
# This looks like it is a staticmethod or a class defined within
996+
# a class namespace. E.g. qualname: SomeClass.func or
997+
# SomeClass.NestedClass
995998
return f"{module}.{qualname}"
996999
return f"{module}.{name}"
9971000
else:
@@ -1050,7 +1053,7 @@ def _mutable_value(cls, x: _T, *, zen_convert: Optional[ZenConvert] = None) -> _
10501053
@classmethod
10511054
def _make_hydra_compatible(
10521055
cls,
1053-
value: Any,
1056+
value: object,
10541057
*,
10551058
allow_zen_conversion: bool = True,
10561059
error_prefix: str = "",
@@ -1080,7 +1083,7 @@ def _make_hydra_compatible(
10801083
# We check exhaustively for all Hydra-supported primitives below but seek to
10811084
# speedup checks for common types here.
10821085
if value is None or type(value) in {str, int, bool, float}:
1083-
return value
1086+
return cast(Union[None, str, int, float, bool], value)
10841087

10851088
# non-str collection
10861089
if hasattr(value, "__iter__"):
@@ -1204,7 +1207,7 @@ def _make_hydra_compatible(
12041207
or isinstance(resolved_value, (Enum, ListConfig, DictConfig))
12051208
)
12061209
):
1207-
return resolved_value
1210+
return resolved_value # type: ignore
12081211

12091212
# pydantic objects
12101213
pydantic = sys.modules.get("pydantic")

tests/test_staticmethod_support.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) 2024 Massachusetts Institute of Technology
22
# SPDX-License-Identifier: MIT
33

4+
from dataclasses import dataclass
5+
46
import pytest
57

68
from hydra_zen import builds, instantiate, just
@@ -11,6 +13,10 @@ class A1:
1113
def foo(x: int):
1214
return "A.foo" * x
1315

16+
@dataclass(frozen=True)
17+
class Foo:
18+
y: int
19+
1420

1521
class B1(A1):
1622
pass
@@ -21,21 +27,38 @@ class C1(A1):
2127
def foo(x: int):
2228
return "C.foo" * x
2329

30+
@dataclass
31+
class Foo:
32+
y: int
33+
34+
def __post_init__(self):
35+
self.y = self.y * 2
36+
2437

2538
class A2:
2639
class B2:
2740
@staticmethod
2841
def f():
2942
return "nested"
3043

44+
@dataclass(frozen=True)
45+
class Foo:
46+
y: int
47+
48+
49+
def test_builds_inner_class():
50+
assert instantiate(builds(A1.Foo, 2)).y == 2
51+
assert instantiate(builds(B1.Foo, 3)).y == 3
52+
assert instantiate(builds(C1.Foo, 4)).y == 8
53+
3154

3255
def test_builds_static_methods():
3356
assert instantiate(builds(A1.foo, 2)) == "A.foo" * 2
3457
assert instantiate(builds(B1.foo, 3)) == "A.foo" * 3
3558
assert instantiate(builds(C1.foo, 4)) == "C.foo" * 4
3659

3760

38-
@pytest.mark.parametrize("obj", [C1.foo, A2.B2.f])
61+
@pytest.mark.parametrize("obj", [C1.foo, A2.B2.f, A1.Foo, A2.B2.Foo])
3962
def test_just_static_method(obj):
4063
assert instantiate(just(obj)) is obj
4164

0 commit comments

Comments
 (0)