-
Notifications
You must be signed in to change notification settings - Fork 15
/
_hydra_overloads.py
362 lines (260 loc) · 10 KB
/
_hydra_overloads.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# Copyright (c) 2022 Massachusetts Institute of Technology
# SPDX-License-Identifier: MIT
"""
Provides annotation overloads for various hydra functions, using the types defined in `hydra_zen.typing`.
This enables tools like IDEs to be more incisive during static analysis and to provide users with additional
context about their code.
E.g.
.. code::
from hydra_zen import builds, instantiate
DictConfig = builds(dict, a=1, b=2) # type: Type[Builds[Type[dict]]]
# static analysis tools can provide useful type information
# about the object that is instantiated from the config
out = instantiate(DictConfig) # type: dict
"""
# pyright: strict
import pathlib
from typing import IO, Any, Callable, Type, TypeVar, Union, overload
from hydra.utils import instantiate as hydra_instantiate
from omegaconf import MISSING, DictConfig, ListConfig, OmegaConf
from .structured_configs._value_conversion import ConfigComplex, ConfigPath
from .typing import Builds, Just, Partial
from .typing._implementations import DataClass_, HasTarget, InstOrType, IsPartial
__all__ = ["instantiate", "to_yaml", "save_as_yaml", "load_from_yaml", "MISSING"]
T = TypeVar("T")
@overload
def instantiate(
config: InstOrType[ConfigPath], *args: Any, **kwargs: Any
) -> pathlib.Path: # pragma: no cover
...
@overload
def instantiate(
config: InstOrType[ConfigComplex], *args: Any, **kwargs: Any
) -> complex: # pragma: no cover
...
@overload
def instantiate(
config: InstOrType[Just[T]], *args: Any, **kwargs: Any
) -> T: # pragma: no cover
...
@overload
def instantiate(
config: InstOrType[IsPartial[Callable[..., T]]], *args: Any, **kwargs: Any
) -> Partial[T]: # pragma: no cover
...
@overload
def instantiate(
config: InstOrType[Builds[Callable[..., T]]], *args: Any, **kwargs: Any
) -> T: # pragma: no cover
...
@overload
def instantiate(
config: Union[HasTarget, ListConfig, DictConfig, DataClass_, Type[DataClass_]],
*args: Any,
**kwargs: Any
) -> Any: # pragma: no cover
...
def instantiate(config: Any, *args: Any, **kwargs: Any) -> Any:
"""
Instantiates the target of a targeted config.
This is an alias of :func:`hydra.utils.instantiate` [1]_.
By default, `instantiate` will recursively instantiate nested configurations [1]_.
Parameters
----------
config : Builds[Type[T] | Callable[..., T]]
The targeted config whose target will be instantiated/called.
*args: Any
Override values, specified by-position. Take priority over
the positional values provided by ``config``.
**kwargs : Any
Override values, specified by-name. Take priority over
the named values provided by ``config``.
Returns
-------
instantiated : T
The instantiated target. Instantiated using the values provided
by ``config`` and/or overridden via ``*args`` and ``**kwargs``.
See Also
--------
builds: Returns a config, which describes how to instantiate/call ``<hydra_target>``.
just: Produces a config that, when instantiated by Hydra, "just" returns the un-instantiated target-object
Notes
-----
This is an alias for ``hydra.utils.instantiate``, but adds additional static type
information.
During instantiation, Hydra performs runtime validation of data based on a limited set of
type-annotations that can be associated with the fields of the provided config [2]_ [3]_.
Hydra supports a string-based syntax for variable interpolation, which enables configured
values to be set in a self-referential and dynamic manner [4]_.
References
----------
.. [1] https://hydra.cc/docs/next/advanced/instantiate_objects/overview
.. [2] https://omegaconf.readthedocs.io/en/latest/structured_config.html#simple-types
.. [3] https://omegaconf.readthedocs.io/en/latest/structured_config.html#runtime-type-validation-and-conversion
.. [4] https://omegaconf.readthedocs.io/en/latest/usage.html#variable-interpolation
Examples
--------
>>> from hydra_zen import builds, instantiate, just
**Basic Usage**
Instantiating a config that targets a class/type.
>>> ConfDict = builds(dict, x=1) # a targeted config
>>> instantiate(ConfDict) # calls `dict(x=1)`
{'x': 1}
Instantiating a config that targets a function.
>>> def f(z): return z
>>> ConfF = builds(f, z=22) # a targeted config
>>> instantiate(ConfF) # calls `f(z=22)`
22
Providing a manual override, via ``instantiate(..., **kwargs)``
>>> instantiate(ConfF, z='foo') # calls `f(z='foo')`
'foo'
Recursive instantiation through nested configs.
>>> inner = builds(dict, b="hi")
>>> outer = builds(dict, a=inner)
>>> instantiate(outer) # calls `dict(a=dict(b='hi))`
{'a': {'b': 'hi'}}
**Leveraging Variable Interpolation**
Hydra provides a powerful language for absolute and relative
interpolated variables among configs [4]_. Let's make a config
where multiple fields reference the field ``name`` via absolute
interpolation.
>>> from hydra_zen import make_config
>>> Conf = make_config("name", a="${name}", b=builds(dict, x="${name}"))
Resolving the interpolation key: ``name``
>>> instantiate(Conf, name="Jeff")
{'a': 'Jeff', 'b': {'x': 'Jeff'}, 'name': 'Jeff'}
**Runtime Data Validation via Hydra**
>>> def g(x: float): return x # note the annotation: float
>>> Conf_g = builds(g, populate_full_signature=True)
>>> instantiate(Conf_g, x=1.0)
1.0
Passing a non-float to ``x`` will produce a validation error upon instantiation
>>> instantiate(Conf_g, x='hi')
ValidationError: Value 'hi' could not be converted to Float
full_key: x
object_type=Builds_g
Only a subset of primitive types are supported by Hydra's validation system [2]_.
See :ref:`data-val` for more general data validation capabilities via hydra-zen.
"""
return hydra_instantiate(config, *args, **kwargs)
def to_yaml(cfg: Any, *, resolve: bool = False, sort_keys: bool = False) -> str:
"""
Serialize a config as a yaml-formatted string.
This is an alias of ``omegaconf.Omegaconf.to_yaml``.
Parameters
----------
cfg : Any
A valid configuration object (e.g. DictConfig, ListConfig, dataclass).
resolve : bool, optional (default=False)
If `True`, interpolated fields in `cfg` will be resolved in the yaml.
sort_keys : bool, optional (default=False)
If `True`, the yaml's entries will alphabetically ordered.
Returns
-------
yaml : str
See Also
--------
save_as_yaml: Save a config to a yaml-format file.
load_from_yaml: Load a config from a yaml-format file.
Examples
--------
>>> from hydra_zen import builds, make_config, to_yaml
**Basic usage**
The yaml of a config with both an un-configured field
and a configured field:
>>> c1 = make_config("a", b=1)
>>> print(to_yaml(c1))
a: ???
b: 1
The yaml of a targeted config:
>>> c2 = builds(dict, y=10)
>>> print(to_yaml(c2))
_target_: builtins.dict
'y': 10
**Specifying resolve**
The following is a config with interpolated fields.
>>> c3 = make_config(a=builds(dict, b="${c}"), c=1)
>>> print(to_yaml(c3, resolve=False))
a:
_target_: builtins.dict
b: ${c}
c: 1
>>> print(to_yaml(c3, resolve=True))
a:
_target_: builtins.dict
b: 1
c: 1
**Specifying sort_keys**
>>> c4 = make_config("b", "a") # field order: b then a
>>> print(to_yaml(c4, sort_keys=False))
b: ???
a: ???
>>> print(to_yaml(c4, sort_keys=True))
a: ???
b: ???
"""
return OmegaConf.to_yaml(cfg=cfg, resolve=resolve, sort_keys=sort_keys)
def save_as_yaml(
config: Any, f: Union[str, pathlib.Path, IO[Any]], resolve: bool = False
) -> None:
"""
Save a config to a yaml-format file
This is an alias of ``omegaconf.Omegaconf.save`` [1]_.
Parameters
----------
config : Any
A config object.
f : str | pathlib.Path | IO[Any]
The path of the file file, or a file object, to be written to.
resolve : bool, optional (default=None)
If ``True`` interpolations will be resolved in the config prior to serialization [2]_.
See Examples section of `to_yaml` for details.
See Also
--------
to_yaml: Serialize a config as a yaml-formatted string.
load_from_yaml: Load a config from a yaml-format file.
References
----------
.. [1] https://omegaconf.readthedocs.io/en/2.0_branch/usage.html#save-load-yaml-file
.. [2] https://omegaconf.readthedocs.io/en/2.0_branch/usage.html#variable-interpolation
Examples
--------
>>> from hydra_zen import make_config, save_as_yaml, load_from_yaml
**Basic usage**
>>> Conf = make_config(a=1, b="foo")
>>> save_as_yaml(Conf, "test.yaml") # file written to: test.yaml
>>> load_from_yaml("test.yaml")
{'a': 1, 'b': 'foo'}
"""
return OmegaConf.save(config=config, f=f, resolve=resolve)
def load_from_yaml(
file_: Union[str, pathlib.Path, IO[Any]]
) -> Union[DictConfig, ListConfig]:
"""
Load a config from a yaml-format file
This is an alias of ``omegaconf.OmegaConf.load``.
Parameters
----------
file_ : str | pathlib.Path | IO[Any]
The path to the yaml-formatted file, or the file object, that the config
will be loaded from.
Returns
-------
loaded_conf : DictConfig | ListConfig
See Also
--------
save_as_yaml: Save a config to a yaml-format file.
to_yaml: Serialize a config as a yaml-formatted string.
References
----------
.. [1] https://omegaconf.readthedocs.io/en/2.0_branch/usage.html#save-load-yaml-file
Examples
--------
>>> from hydra_zen import make_config, save_as_yaml, load_from_yaml
**Basic usage**
>>> Conf = make_config(a=1, b="foo")
>>> save_as_yaml(Conf, "test.yaml") # file written to: test.yaml
>>> load_from_yaml("test.yaml")
{'a': 1, 'b': 'foo'}
"""
return OmegaConf.load(file_)