Repository: mit-ll-responsible-ai/hydra-zen

Issue:
Typing Error for `builds` using ART
I was hoping to make a simple example but I'm not sure what is causing the error:

```python
from art.estimators.classification import PyTorchClassifier

builds(PyTorchClassifier)  # the config is actually incomplete but it never gets to that error
```

error:

```python
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-81-0ae74d8b49b2> in <module>
----> 1 builds(PyTorchClassifier)

~/projects/raiden/hydra_zen/src/hydra_zen/structured_configs/_implementations.py in builds(target, populate_full_signature, hydra_partial, hydra_recursive, hydra_convert, frozen, dataclass_name, builds_bases, *pos_args, **kwargs_for_target)
    645             # target is class object...
    646             # calling `get_type_hints(target)` returns empty dict
--> 647             type_hints = get_type_hints(target.__init__)
    648         else:
    649             type_hints = get_type_hints(target)

~/.conda/envs/trusted_analytics/lib/python3.8/typing.py in get_type_hints(obj, globalns, localns)
   1262         if isinstance(value, str):
   1263             value = ForwardRef(value)
-> 1264         value = _eval_type(value, globalns, localns)
   1265         if name in defaults and defaults[name] is None:
   1266             value = Optional[value]

~/.conda/envs/trusted_analytics/lib/python3.8/typing.py in _eval_type(t, globalns, localns)
    268     """
    269     if isinstance(t, ForwardRef):
--> 270         return t._evaluate(globalns, localns)
    271     if isinstance(t, _GenericAlias):
    272         ev_args = tuple(_eval_type(a, globalns, localns) for a in t.__args__)

~/.conda/envs/trusted_analytics/lib/python3.8/typing.py in _evaluate(self, globalns, localns)
    516                 localns = globalns
    517             self.__forward_value__ = _type_check(
--> 518                 eval(self.__forward_code__, globalns, localns),
    519                 "Forward references must evaluate to types.",
    520                 is_argument=self.__forward_is_argument__)

~/software/adversarial-robustness-toolbox/art/estimators/classification/pytorch.py in <module>

NameError: name 'torch' is not defined
```

No issues when trying to load a `PyTorchClassifier` normally.

Discussion:

Patch:
diff --git a/src/hydra_zen/structured_configs/_implementations.py b/src/hydra_zen/structured_configs/_implementations.py
index d13fcf6f..2afbc11c 100644
--- a/src/hydra_zen/structured_configs/_implementations.py
+++ b/src/hydra_zen/structured_configs/_implementations.py
@@ -647,8 +647,9 @@ def builds(
             type_hints = get_type_hints(target.__init__)
         else:
             type_hints = get_type_hints(target)
-    except TypeError:
-        # Covers case for ufuncs, which do not have inspectable type hints
+    except (TypeError, NameError):
+        # TypeError: Covers case for ufuncs, which do not have inspectable type hints
+        # NameError: Covers case for unresolved forward reference
         type_hints = defaultdict(lambda: Any)
 
     sig_by_kind: Dict[Any, List[inspect.Parameter]] = {


Test patch:
diff --git a/tests/test_signature_parsing.py b/tests/test_signature_parsing.py
index e84f757b..65fba138 100644
--- a/tests/test_signature_parsing.py
+++ b/tests/test_signature_parsing.py
@@ -258,3 +258,18 @@ def test_builds_partial_with_full_sig_excludes_non_specified_params(
 
     assert isinstance(Conf.a_function, Just) and "func" in Conf.a_function.path
     assert isinstance(Conf.a_class, Just) and "dict" in Conf.a_class.path
+
+
+def f_with_fwd_ref(x: "torch.optim.Optimizer"):  # noqa: F821
+    return
+
+
+class A_w_fwd_ref:
+    def __init__(self, x: "torch.optim.Optimizer"):  # noqa: F821
+        pass
+
+
+@pytest.mark.parametrize("obj", [f_with_fwd_ref, A_w_fwd_ref])
+def test_sig_with_unresolved_fwd_ref(obj):
+    # builds should gracefully skip signature parsing for unresolved fwd-references
+    instantiate(builds(obj, x=1))