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

Issue:
`zen_wrapper` should support partial'd wrappers
This should work:

```python
builds(something, zen_wrappers=partial(my_wrapper, param=100))
```

Currently, one would have to write:

```python
builds(something, zen_wrappers=builds(my_wrapper, param=100, zen_partial=True))
```

we just need to check if a wrapper is an instance of `partial` and auto-apply `hydra_zen.just` if so.

Discussion:

Patch:
diff --git a/docs/source/changes.rst b/docs/source/changes.rst
index ac757753..c928b5b1 100644
--- a/docs/source/changes.rst
+++ b/docs/source/changes.rst
@@ -134,6 +134,7 @@ New Features
 - Adds `hyda_zen.store`, which is a pre-initialized instance of :class:`~hydra_zen.ZenStore` (see :pull:`331`)
 - The option `hydra_convert='object'` is now supported by all of hydra-zen's config-creation functions. So that an instantiated structured config can be converted to an instance of its backing dataclass. This feature was added by `Hydra 1.3.0 <https://github.com/facebookresearch/hydra/issues/1719>`_.
 - Adds auto-config support for `torch.optim.optimizer.required` so that the common pattern `builds(<torch_optimizer_type>, populate_full_signature=True, zen_partial=True)` works and exposes `lr` as a required configurable parameter. Thanks to @addisonklinke for requesting this in :issue:`257`.
+- :ref:`builds([...], zen_wrapper=...) <zen-wrapper>` can now accept a partial'd function as a wrapper.
 
 Improvements
 ------------
diff --git a/src/hydra_zen/structured_configs/_implementations.py b/src/hydra_zen/structured_configs/_implementations.py
index cc7bffe2..5645210b 100644
--- a/src/hydra_zen/structured_configs/_implementations.py
+++ b/src/hydra_zen/structured_configs/_implementations.py
@@ -1501,6 +1501,9 @@ def builds(
                 continue
             # We are intentionally keeping each condition branched
             # so that test-coverage will be checked for each one
+            if isinstance(wrapper, functools.partial):
+                wrapper = ZEN_VALUE_CONVERSION[functools.partial](wrapper)
+
             if is_builds(wrapper):
                 # If Hydra's locate function starts supporting importing literals
                 # – or if we decide to ship our own locate function –


Test patch:
diff --git a/tests/test_zen_processing/test_zen_wrappers.py b/tests/test_zen_processing/test_zen_wrappers.py
index 45028f83..088ba092 100644
--- a/tests/test_zen_processing/test_zen_wrappers.py
+++ b/tests/test_zen_processing/test_zen_wrappers.py
@@ -2,6 +2,7 @@
 # SPDX-License-Identifier: MIT
 import string
 import warnings
+from functools import partial
 from typing import Any, Callable, Dict, List, TypeVar, Union
 
 import hypothesis.strategies as st
@@ -299,3 +300,19 @@ def test_bad_relative_interp_warns(wrappers, expected_match):
 def test_interp_doesnt_warn(wrappers):
     with warnings.catch_warnings():
         builds(dict, zen_wrappers=wrappers, zen_meta=dict(s=1))
+
+
+def pmy_wrapper(func, repeat):
+    def w(*a, **k):
+        return [func(*a, **k)] * repeat
+
+    return w
+
+
+def ptarget():
+    return "moo"
+
+
+def test_partial_zen_wrapper():
+    out = instantiate(builds(ptarget, zen_wrappers=partial(pmy_wrapper, repeat=3)))
+    assert out == ["moo"] * 3