hydra-fast 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. hydra_fast-0.1.0/LICENSE +40 -0
  2. hydra_fast-0.1.0/PKG-INFO +362 -0
  3. hydra_fast-0.1.0/README.md +324 -0
  4. hydra_fast-0.1.0/pyproject.toml +230 -0
  5. hydra_fast-0.1.0/setup.cfg +4 -0
  6. hydra_fast-0.1.0/src/hydra_fast/__init__.py +157 -0
  7. hydra_fast-0.1.0/src/hydra_fast/_cache.py +302 -0
  8. hydra_fast-0.1.0/src/hydra_fast/_copy.py +40 -0
  9. hydra_fast-0.1.0/src/hydra_fast/_internal/__init__.py +0 -0
  10. hydra_fast-0.1.0/src/hydra_fast/_internal/config_loader.py +555 -0
  11. hydra_fast-0.1.0/src/hydra_fast/_internal/config_repository.py +216 -0
  12. hydra_fast-0.1.0/src/hydra_fast/_internal/config_search_path.py +111 -0
  13. hydra_fast-0.1.0/src/hydra_fast/_internal/config_source.py +602 -0
  14. hydra_fast-0.1.0/src/hydra_fast/_internal/default_element.py +585 -0
  15. hydra_fast-0.1.0/src/hydra_fast/_internal/defaults_list.py +1145 -0
  16. hydra_fast-0.1.0/src/hydra_fast/_internal/fingerprint.py +158 -0
  17. hydra_fast-0.1.0/src/hydra_fast/_internal/job_runtime.py +30 -0
  18. hydra_fast-0.1.0/src/hydra_fast/_structured.py +120 -0
  19. hydra_fast-0.1.0/src/hydra_fast/_typing.py +405 -0
  20. hydra_fast-0.1.0/src/hydra_fast/_yaml.py +294 -0
  21. hydra_fast-0.1.0/src/hydra_fast/api.py +278 -0
  22. hydra_fast-0.1.0/src/hydra_fast/compat/__init__.py +11 -0
  23. hydra_fast-0.1.0/src/hydra_fast/compat/oc_utils.py +287 -0
  24. hydra_fast-0.1.0/src/hydra_fast/compat/omegaconf_shim.py +394 -0
  25. hydra_fast-0.1.0/src/hydra_fast/conf/__init__.py +158 -0
  26. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/env/default.yaml +0 -0
  27. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/help/default.yaml +34 -0
  28. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/hydra_help/default.yaml +25 -0
  29. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/hydra_logging/default.yaml +18 -0
  30. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/hydra_logging/disabled.yaml +4 -0
  31. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/hydra_logging/hydra_debug.yaml +22 -0
  32. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/hydra_logging/none.yaml +3 -0
  33. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/job_logging/default.yaml +20 -0
  34. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/job_logging/disabled.yaml +4 -0
  35. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/job_logging/none.yaml +3 -0
  36. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/job_logging/stdout.yaml +15 -0
  37. hydra_fast-0.1.0/src/hydra_fast/conf/hydra/output/default.yaml +7 -0
  38. hydra_fast-0.1.0/src/hydra_fast/container.py +1209 -0
  39. hydra_fast-0.1.0/src/hydra_fast/core/__init__.py +1 -0
  40. hydra_fast-0.1.0/src/hydra_fast/core/config_store.py +155 -0
  41. hydra_fast-0.1.0/src/hydra_fast/core/object_type.py +8 -0
  42. hydra_fast-0.1.0/src/hydra_fast/core/override_parser/__init__.py +1 -0
  43. hydra_fast-0.1.0/src/hydra_fast/core/override_parser/overrides_parser.py +99 -0
  44. hydra_fast-0.1.0/src/hydra_fast/core/singleton.py +25 -0
  45. hydra_fast-0.1.0/src/hydra_fast/errors.py +183 -0
  46. hydra_fast-0.1.0/src/hydra_fast/grammar/__init__.py +17 -0
  47. hydra_fast-0.1.0/src/hydra_fast/grammar/antlr_errors.py +99 -0
  48. hydra_fast-0.1.0/src/hydra_fast/grammar/functions.py +134 -0
  49. hydra_fast-0.1.0/src/hydra_fast/grammar/interpolation.py +993 -0
  50. hydra_fast-0.1.0/src/hydra_fast/grammar/override.py +1444 -0
  51. hydra_fast-0.1.0/src/hydra_fast/grammar/override_functions.py +361 -0
  52. hydra_fast-0.1.0/src/hydra_fast/grammar/utils.py +44 -0
  53. hydra_fast-0.1.0/src/hydra_fast/merge.py +219 -0
  54. hydra_fast-0.1.0/src/hydra_fast/nodes.py +274 -0
  55. hydra_fast-0.1.0/src/hydra_fast/omegaconf_api.py +832 -0
  56. hydra_fast-0.1.0/src/hydra_fast/py.typed +0 -0
  57. hydra_fast-0.1.0/src/hydra_fast/resolvers.py +263 -0
  58. hydra_fast-0.1.0/src/hydra_fast/utils.py +348 -0
  59. hydra_fast-0.1.0/src/hydra_fast/version.py +137 -0
  60. hydra_fast-0.1.0/src/hydra_fast.egg-info/PKG-INFO +362 -0
  61. hydra_fast-0.1.0/src/hydra_fast.egg-info/SOURCES.txt +81 -0
  62. hydra_fast-0.1.0/src/hydra_fast.egg-info/dependency_links.txt +1 -0
  63. hydra_fast-0.1.0/src/hydra_fast.egg-info/requires.txt +12 -0
  64. hydra_fast-0.1.0/src/hydra_fast.egg-info/top_level.txt +1 -0
  65. hydra_fast-0.1.0/tests/test_analysis.py +214 -0
  66. hydra_fast-0.1.0/tests/test_attrs.py +153 -0
  67. hydra_fast-0.1.0/tests/test_cache.py +329 -0
  68. hydra_fast-0.1.0/tests/test_compoconf.py +373 -0
  69. hydra_fast-0.1.0/tests/test_compose.py +590 -0
  70. hydra_fast-0.1.0/tests/test_container_api.py +890 -0
  71. hydra_fast-0.1.0/tests/test_defaults_list.py +157 -0
  72. hydra_fast-0.1.0/tests/test_errors.py +376 -0
  73. hydra_fast-0.1.0/tests/test_instantiate.py +147 -0
  74. hydra_fast-0.1.0/tests/test_internals.py +192 -0
  75. hydra_fast-0.1.0/tests/test_interpolation.py +246 -0
  76. hydra_fast-0.1.0/tests/test_nodes.py +172 -0
  77. hydra_fast-0.1.0/tests/test_overrides.py +167 -0
  78. hydra_fast-0.1.0/tests/test_packaging.py +143 -0
  79. hydra_fast-0.1.0/tests/test_realistic_tree.py +345 -0
  80. hydra_fast-0.1.0/tests/test_shim.py +131 -0
  81. hydra_fast-0.1.0/tests/test_typing.py +179 -0
  82. hydra_fast-0.1.0/tests/test_upstream.py +220 -0
  83. hydra_fast-0.1.0/tests/test_version_base.py +108 -0
@@ -0,0 +1,40 @@
1
+ MIT License
2
+
3
+ Copyright (c) the hydra-fast authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ --------------------------------------------------------------------------------
24
+
25
+ This project is a derivative work of Hydra and OmegaConf. See ATTRIBUTION/
26
+ for the full upstream license texts:
27
+
28
+ * Hydra (hydra-core) -- Copyright (c) Facebook, Inc. and its affiliates.
29
+ MIT License. See ATTRIBUTION/LICENSE-hydra.
30
+ Portions of hydra-fast are ported from Hydra, in particular the Defaults
31
+ List algorithm (src/hydra_fast/_internal/defaults_list.py and
32
+ src/hydra_fast/_internal/default_element.py), Hydra's configuration schema
33
+ (src/hydra_fast/conf/), and the config search path, repository and loader
34
+ structure.
35
+
36
+ * OmegaConf -- Copyright (c) 2018, Omry Yadan. BSD 3-Clause License.
37
+ See ATTRIBUTION/LICENSE-omegaconf.
38
+ hydra-fast reimplements OmegaConf's container API, interpolation grammar
39
+ and merge semantics; the grammar token rules and reduction behaviour are
40
+ transcribed from OmegaConf's ANTLR grammar and visitor.
@@ -0,0 +1,362 @@
1
+ Metadata-Version: 2.4
2
+ Name: hydra-fast
3
+ Version: 0.1.0
4
+ Summary: Hydra-compatible config composition, 10-100x faster, with process-wide file caching
5
+ Author: the hydra-fast authors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/kpoeppel/hydra_fast
8
+ Project-URL: Repository, https://github.com/kpoeppel/hydra_fast
9
+ Project-URL: Changelog, https://github.com/kpoeppel/hydra_fast/blob/main/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/kpoeppel/hydra_fast/issues
11
+ Keywords: hydra,omegaconf,configuration,yaml,sweep,hyperparameter
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Typing :: Typed
23
+ Classifier: Operating System :: POSIX :: Linux
24
+ Classifier: Operating System :: MacOS
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: PyYAML>=5.1
29
+ Provides-Extra: test
30
+ Requires-Dist: pytest<8.4,>=7.0; extra == "test"
31
+ Requires-Dist: hydra-core<1.4,>=1.3; extra == "test"
32
+ Requires-Dist: omegaconf<2.4,>=2.3; extra == "test"
33
+ Provides-Extra: attrs
34
+ Requires-Dist: attrs>=21.0; extra == "attrs"
35
+ Provides-Extra: compoconf
36
+ Requires-Dist: compoconf>=0.1.16; extra == "compoconf"
37
+ Dynamic: license-file
38
+
39
+ # hydra-fast
40
+
41
+ [![CI](https://github.com/kpoeppel/hydra_fast/actions/workflows/ci.yml/badge.svg)](https://github.com/kpoeppel/hydra_fast/actions/workflows/ci.yml)
42
+ [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)](https://pypi.org/project/hydra-fast/)
43
+ [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/kpoeppel/hydra_fast/blob/main/LICENSE)
44
+
45
+ Hydra-compatible config composition, built for the case Hydra is slowest at:
46
+ composing the same config tree hundreds of times to build a parameter sweep.
47
+
48
+ ```python
49
+ from hydra_fast import compose, initialize_config_dir
50
+
51
+ with initialize_config_dir(config_dir="/path/to/conf", version_base=None):
52
+ cfg = compose(config_name="config", overrides=["db=postgres", "db.port=5433"])
53
+ ```
54
+
55
+ Same config file syntax, same `${...}` interpolation grammar, same override
56
+ grammar, same `OmegaConf`/`compose` API. Roughly 100x faster on a sweep.
57
+
58
+ It reimplements the composition and interpolation core — including
59
+ `instantiate`/`_target_` — but not job launching or sweeper plugins. Within
60
+ that scope it is validated against the
61
+ real packages — including running **hydra's own override-grammar suite** and
62
+ **omegaconf's own grammar corpus** against it.
63
+ [docs/compatibility.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/compatibility.md) is explicit about the boundary.
64
+
65
+ ## The numbers
66
+
67
+ Composing one config tree once per sweep point, then fully resolving it —
68
+ which is what building a sweep does. `hydra 1.3.2 + omegaconf 2.3.0`,
69
+ CPython 3.12, Linux, best-of-N wall clock.
70
+
71
+ **A 75-point sweep over a real production config tree** ([OpenEuroLLM
72
+ `oellm-autoexp`](https://github.com/OpenEuroLLM/oellm-autoexp): 239 YAML
73
+ files, deep group nesting, ~30 custom resolvers):
74
+
75
+ | | total | per point |
76
+ | --- | --- | --- |
77
+ | hydra + omegaconf | **23.0 s** | 306 ms |
78
+ | hydra-fast | **0.19 s** | 2.5 ms |
79
+
80
+ Seconds to milliseconds — **~120x**.
81
+
82
+ Per point on the same tree, by configuration:
83
+
84
+ | | per point | vs stock |
85
+ | --- | --- | --- |
86
+ | hydra + omegaconf | 306 ms | 1x |
87
+ | hydra + omegaconf, with a hand-written cache layer monkeypatched in [^1] | 71 ms | 4x |
88
+ | **hydra-fast** | **2.5 ms** | **~120x** |
89
+
90
+ The default `validation="stat"` — which re-checks the filesystem on every cache
91
+ lookup, so a config edited mid-process is picked up — costs nothing measurable
92
+ here: best-of-5 over this sweep gives 2.72 ms/point with validation and
93
+ 2.78 ms/point without. The validation work is amortized to a handful of
94
+ `stat()` calls per composition (see
95
+ [docs/architecture.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/architecture.md)), so there is no safety-for-speed
96
+ trade to make. Keep the default.
97
+
98
+ [^1]: `oellm-autoexp` ships seven monkeypatched cache layers over Hydra
99
+ (`hydra_staged_sweep/config/cache.py`). hydra-fast is ~25x faster than
100
+ that, because caching alone cannot get past Hydra's object model — see
101
+ [docs/architecture.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/architecture.md).
102
+
103
+ Across repeated runs on a shared machine the speedup landed between **60x and
104
+ 130x**, with the low end being runs where the box was busy. Treat ~100x as the
105
+ expected figure and measure on your own tree; the ratio depends on how much of
106
+ your config is interpolation (where hydra-fast wins most) versus custom
107
+ resolvers doing real work (where it cannot help).
108
+
109
+ Reproduce without any private config tree:
110
+
111
+ ```console
112
+ $ python bench/bench_synthetic.py --points 100 --repeat 3
113
+ tree: 25 yaml files, 400 keys in base, 6 groups x 4 options; 100 sweep points
114
+ equivalence on first 3 points: OK
115
+ hydra+omegaconf total= 46762.6 ms per_point= 467.63 ms
116
+ hydra-fast total= 368.6 ms per_point= 3.69 ms
117
+
118
+ speedup: 126.9x
119
+ yaml parses: 13 (vs 161 reads requested)
120
+ ```
121
+
122
+ The benchmark verifies both implementations produce identical output before
123
+ reporting a time.
124
+
125
+ ## Why it is faster
126
+
127
+ Three things, in rough order of impact. [docs/architecture.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/architecture.md)
128
+ has the detail.
129
+
130
+ **Each file is read and parsed once per process.** Stock Hydra re-reads and
131
+ re-parses every YAML file in the tree on *every* `compose()` call — about 150
132
+ parses per call on the tree above, so ~11,000 parses for a 75-point sweep.
133
+ hydra-fast parses each file once: 9 parses for the whole sweep. This was the
134
+ single biggest cost, about half of stock Hydra's time.
135
+
136
+ **Interpolations compile to closures.** OmegaConf re-walks an ANTLR parse tree
137
+ every time it resolves `${a.b}`. hydra-fast has a hand-written parser that
138
+ compiles each distinct string *once* into a Python closure, cached on the
139
+ string. A sweep typically has a few dozen distinct interpolation strings and
140
+ resolves them thousands of times. (Having no parse tree costs nothing
141
+ functionally: parse-once-resolve-many works the same way, and
142
+ `analyze_interpolation()` recovers static introspection — see
143
+ [docs/architecture.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/architecture.md#what-replaces-the-parse-tree).)
144
+
145
+ **Configs are plain dicts.** OmegaConf wraps every value in a `Node` object
146
+ with its own metadata and parent pointer. A 600-key config is 600+ objects to
147
+ allocate, link, and later deep-copy. In hydra-fast the storage *is* a
148
+ `dict`/`list` tree and `DictConfig` is a two-slot view over it, so merging is a
149
+ dict walk and copying is a data copy.
150
+
151
+ On top of that, the defaults list and the merged config are memoized on exactly
152
+ what can change them — notably *not* on the `++key=value` overrides a sweep
153
+ varies per point, which cannot affect either.
154
+
155
+ ## Correctness
156
+
157
+ Speed is only interesting if the answer is the same. Every result is checked
158
+ against the real Hydra and OmegaConf:
159
+
160
+ ```console
161
+ $ pytest
162
+ 1022 passed, 3 skipped
163
+ ```
164
+
165
+ 1025 tests, and **no test needs anything outside the repository**. The three
166
+ that skip above need compoconf 0.3.1+, which CI installs. The upstream-suite
167
+ tests need the hydra and omegaconf source checkouts fetched (see *Running the
168
+ differential tests*); `HYDRA_FAST_REQUIRE_UPSTREAM=1` turns those skips into
169
+ errors, as CI does.
170
+
171
+ - **Upstream suites run against hydra-fast** (`tests/test_upstream.py`):
172
+ hydra's own `test_overrides_parser.py` — **508 cases, fully green**;
173
+ omegaconf's own grammar corpus driven through the public API — **131/131**;
174
+ omegaconf's `test_readonly.py`, `test_struct.py`, `test_oc_select.py` run
175
+ verbatim — **all green**.
176
+ - **70 structured-config typing cases** against an oracle captured from
177
+ omegaconf — coercion, rejection, `Optional`, `Enum`, `List[X]`, `Dict[K,V]`,
178
+ nested dataclasses, and through a full composition.
179
+ - **~60 interpolation cases** resolved through both OmegaConf and hydra-fast and
180
+ compared — node references, relative references (`${..a}`), nested keys
181
+ (`${a.${k}}`), escapes, quoting, every argument form, all built-in resolvers.
182
+ - **Exception types and messages** compared case by case, including omegaconf's
183
+ `full_key`/`object_type` trailer — and, for malformed input, ANTLR's own
184
+ phrasing reproduced without ANTLR: **744/744** inputs accepted or rejected
185
+ identically and **459/459** messages character-identical across 62 malformed
186
+ inputs x 12 grammar rules (`bench/oracle_errors.py`).
187
+ - **66 override cases** parsed by both Hydra's ANTLR parser and hydra-fast, with
188
+ the full parsed shape compared — type, key, package, value type, value.
189
+ - **33 composition cases** over 12 config trees covering `_self_` ordering,
190
+ `@package` headers, `override`/`optional` keywords, deletions, option lists,
191
+ interpolated group names, nested groups.
192
+ - **A realistic config tree that ships with the repository**
193
+ (`tests/realistic_config/`): nested groups, `# @package` headers named and
194
+ `_global_`, profiles using `override`, relative and root-reaching
195
+ interpolations, six custom resolvers, a `_target_`, and a `???` a sweep must
196
+ fill — twelve override shapes compared against hydra, plus a generated
197
+ large tree for scale. No private checkout needed.
198
+ - Cache-correctness tests: that a file edited mid-process is picked up, that
199
+ group overrides are not served a cached merge, and that one sweep point's
200
+ overrides cannot leak into another's.
201
+ - **Packaging and handoff tests**: that every shipped config file is tracked by
202
+ git (not just present on disk), and that the plain dict handed to an external
203
+ typing layer such as [compoconf](https://pypi.org/project/compoconf/) matches
204
+ hydra's in both values and types.
205
+
206
+ What this still does not prove: omegaconf's `test_grammar.py` asserts against
207
+ ANTLR parse trees, which hydra-fast has none of by design, and several
208
+ omegaconf suites import private internals that are only partially shimmed. Both
209
+ boundaries are itemised in
210
+ [docs/compatibility.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/compatibility.md) — treat it as the contract.
211
+
212
+ ### Contributing
213
+
214
+ ```console
215
+ $ pip install -e ".[test,attrs,compoconf]" pre-commit
216
+ $ pre-commit install
217
+ ```
218
+
219
+ `pre-commit run --all-files` runs what CI runs: ruff (lint and format), mypy,
220
+ pylint, bandit, yamllint, and the usual whitespace/YAML checks — all
221
+ configured in `pyproject.toml`, at 95 columns.
222
+
223
+ ruff stands in for black, flake8 and isort, which it subsumes. pylint is *not*
224
+ subsumed, so it runs as well: ruff's `PL` family covers most of it, the
225
+ overlap is disabled in `pyproject.toml`, and what remains are the checks ruff
226
+ has no equivalent for. pylint is clean at 10.00/10 and mypy reports no issues
227
+ across all 41 modules.
228
+
229
+ Two files are exempt from both the linter and the formatter:
230
+ `_internal/defaults_list.py` and `_internal/default_element.py` are ported from
231
+ hydra essentially verbatim so they stay diffable against upstream, and
232
+ reformatting them would defeat that.
233
+
234
+ ### Running the differential tests
235
+
236
+ ```console
237
+ $ pip install -e ".[test,attrs,compoconf]"
238
+ $ python .github/scripts/fetch_upstream.py # upstream suites + grammar corpus
239
+ $ pytest
240
+ ```
241
+
242
+ The second step matters. Upstream's own test suites and grammar corpus ship in
243
+ their sdists, not their wheels, so they are downloaded into a gitignored
244
+ `.upstream/`. Without them the strongest checks here **skip**, and a green run
245
+ means much less. Set `HYDRA_FAST_REQUIRE_UPSTREAM=1` to turn those skips into
246
+ errors — CI always does.
247
+
248
+ `bench/_sources.py` is the one place that decides where those trees live
249
+ (`HYDRA_SRC`, `OMEGACONF_SRC`, `OELLM_AUTOEXP`, else `.upstream/`) and which
250
+ versions are expected.
251
+
252
+ Two skips are expected and harmless: `tests/test_real_world.py` needs the
253
+ `oellm-autoexp` config tree, which is not public.
254
+
255
+ ## Install
256
+
257
+ ```console
258
+ pip install hydra-fast
259
+ ```
260
+
261
+ Only dependency is PyYAML. Install it built against libyaml (the usual binary
262
+ wheels are) and hydra-fast uses the C scanner automatically.
263
+
264
+ ## Using it
265
+
266
+ ### As itself
267
+
268
+ ```python
269
+ import hydra_fast
270
+ from hydra_fast import OmegaConf, compose, initialize_config_dir
271
+
272
+ with initialize_config_dir(config_dir="/abs/path/to/conf", version_base=None):
273
+ cfg = compose(config_name="config", overrides=["group=option", "++key=value"])
274
+ print(OmegaConf.to_yaml(cfg, resolve=True))
275
+ ```
276
+
277
+ `initialize`, `initialize_config_dir`, `initialize_config_module`, `compose`,
278
+ `main`, and the `OmegaConf` static API all match their Hydra/OmegaConf
279
+ counterparts.
280
+
281
+ ### Under a library written against omegaconf
282
+
283
+ If a library you depend on does `from omegaconf import OmegaConf` to register
284
+ its resolvers, install the shim **before importing it**:
285
+
286
+ ```python
287
+ import hydra_fast.compat.omegaconf_shim as shim
288
+ shim.install()
289
+
290
+ import that_library # its OmegaConf is now hydra-fast's
291
+ ```
292
+
293
+ `install()` is always explicit — importing `hydra_fast` never redirects
294
+ anything on its own. Only the public surface is shimmed; code reaching into
295
+ `omegaconf._utils` or `omegaconf.basecontainer` needs to target hydra-fast
296
+ directly.
297
+
298
+ ### Cache control
299
+
300
+ ```python
301
+ import hydra_fast
302
+
303
+ hydra_fast.set_validation("never") # trust the first read; fastest
304
+ hydra_fast.clear_caches() # drop everything
305
+ hydra_fast.cache_stats() # hit/miss counters per layer
306
+ hydra_fast.get_validation() # "stat" or "never"
307
+ ```
308
+
309
+ `"stat"` is the default: every cache lookup re-`stat()`s the files it depends
310
+ on, so editing a config on disk mid-process invalidates exactly the entries
311
+ that depend on it. No explicit reload call is needed.
312
+
313
+ That covers more than edits. A file *added* to a group, a file *removed* from
314
+ one, a whole new group directory, and a changed `defaults:` list are all
315
+ picked up, because existence is cached against the parent directory's mtime --
316
+ which changes exactly when an entry is added or removed. `tests/test_cache.py`
317
+ pins each case.
318
+
319
+ `"never"` skips all of that and trusts the first read for the life of the
320
+ process, so a config edited afterwards is *not* seen; `clear_caches()` is the
321
+ only way to pick it up. `get_validation()` reports the current mode, which
322
+ matters if something else set it.
323
+
324
+ On the benchmarks above `"never"` is **not** measurably faster — the
325
+ validation is already amortized down to a few `stat()` calls per composition.
326
+ It exists for workloads with much larger config trees, where the per-file
327
+ checks could still show up. Measure before switching; the default is safe.
328
+
329
+ ## Compatibility
330
+
331
+ Target is **hydra 1.3 / omegaconf 2.3** — the widely deployed pair.
332
+ [docs/compatibility.md](https://github.com/kpoeppel/hydra_fast/blob/main/docs/compatibility.md) lists what is covered, the few
333
+ deliberate deviations, and what is out of scope (job launching, sweeper
334
+ plugins, `instantiate`).
335
+
336
+ The short version: config **composition, parsing and syntax** are covered and
337
+ differentially tested. hydra-fast composes configs; it does not run jobs.
338
+
339
+ ## Repository layout
340
+
341
+ ```
342
+ src/hydra_fast/ the package
343
+ tests/ differential and unit tests
344
+ bench/ benchmarks and standalone differential checks
345
+ docs/ architecture.md, compatibility.md
346
+ ATTRIBUTION/ upstream licenses and what came from where
347
+ hydra/, omegaconf/ upstream source checkouts, for reference only
348
+ ```
349
+
350
+ The `hydra/` and `omegaconf/` directories at the root are upstream checkouts
351
+ kept for reading and diffing. They are **not** part of the distribution, and
352
+ they are not what the tests compare against — the tests use the *installed*
353
+ `hydra-core` / `omegaconf`. Note that with the repo root on `sys.path` those
354
+ directories shadow the installed packages as empty namespace packages;
355
+ `tests/conftest.py` drops the root from `sys.path` for exactly that reason.
356
+
357
+ ## Licensing
358
+
359
+ MIT. hydra-fast is a derivative work of Hydra (MIT) and OmegaConf (BSD
360
+ 3-Clause); the Defaults List algorithm in particular is ported from Hydra
361
+ rather than re-derived, because that algorithm *is* the composition spec. See
362
+ [ATTRIBUTION/](https://github.com/kpoeppel/hydra_fast/tree/main/ATTRIBUTION) for exactly what came from where.