Skip to main content

hydr8

Decorator-based config injection for Hydra.

hydr8 lets you push Hydra config (or any config as long as it's a dict) values into function parameters automatically, so your functions stay clean and testable without manually threading cfg everywhere.

Installation

pip install hydr8
# or
uv add hydr8

Quick start

import hydra
from omegaconf import DictConfig
import hydr8

@hydr8.use("db")
def connect(host: str, port: int):
    print(f"Connecting to {host}:{port}")

@hydra.main(config_path="conf", config_name="config", version_base=None)
def main(cfg: DictConfig):
    hydr8.init(cfg)
    connect()  # host and port injected from cfg.db

if __name__ == "__main__":
    main()

With a config like:

db:
  host: localhost
  port: 5432

Usage

hydr8.use() is the core function. It can be used as a decorator to inject config into function parameters, or called directly to access a config sub-tree as a dict.

As a decorator

Explicit path

Pass a dot-separated path to resolve a specific config node. Config keys are matched to function parameter names. Extra config keys that don't match any named parameter are silently ignored (unless the function accepts **kwargs — see below).

@hydr8.use("db.postgres")
def connect(host: str, port: int, user: str):
    ...

connect()              # all three injected from cfg.db.postgres
connect(host="remote") # host overridden, port and user from config

List indexing is supported:

@hydr8.use("db.replicas[0]")
def connect(host: str, port: int):
    ...

Implicit path (auto-resolve)

When no path is given, hydr8 derives it from the function's __module__. If the first segment of the module isn't a top-level config key, it's treated as the project name and stripped — so auto-resolve works whether you run with python -m or python file.py:

# In myproject/data/loaders.py
@hydr8.use()
def build_loader(batch_size: int, shuffle: bool):
    ...
# Resolves to cfg.data.loaders
# config.yaml
data:
  loaders:
    batch_size: 32
    shuffle: true

By default, scope="module" — the path resolves to the module's config node, and config keys are matched to function parameters. Multiple functions in the same module share the same config node.

With scope="fn", the function's qualname is appended to the path:

# In myproject/data/loaders.py
@hydr8.use(scope="fn")
def build_loader(batch_size: int, shuffle: bool):
    ...
# Resolves to cfg.data.loaders.build_loader
# config.yaml
data:
  loaders:
    build_loader:
      batch_size: 32
      shuffle: true

This works with methods too:

# In myproject/db/client.py
class Client:
    @hydr8.use(scope="fn")
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
# Resolves to cfg.db.client.Client.__init__

as_dict mode

Pass the entire resolved sub-config as a single dict argument instead of matching individual keys:

@hydr8.use("db.postgres", as_dict="config")
def connect(config: dict):
    host = config["host"]
    port = config["port"]
    ...

**kwargs passthrough

When the decorated function accepts **kwargs, config keys that don't match any named parameter automatically flow into **kwargs:

@hydr8.use("db")
def connect(host: str, **kwargs):
    # host matched by name; port and any other config keys land in kwargs
    print(host, kwargs)

connect()  # host="localhost", kwargs={"port": 5432}

Caller overrides

Caller-provided arguments always take precedence over injected config. If every required parameter is supplied by the caller, config is never accessed at all:

@hydr8.use("db")
def connect(host: str, port: int):
    ...

connect(host="remote")       # port from config, host = "remote"
connect("localhost", 5432)   # config not accessed

As a direct call

hydr8.use("path") returns a lazy, dict-like proxy. The config is resolved on first access, not at call time, so you can call use() before init().

import hydr8

db = hydr8.use("db")

hydr8.init(cfg)
db["host"]        # "localhost"
db["port"]        # 5432

This is useful when you want to read config values without decorating a function:

def connect():
    db = hydr8.use("db")
    engine = create_engine(f"postgresql://{db['host']}:{db['port']}")
    ...

An explicit path is required when using use() as a direct call. Calling use() without a path and accessing it raises TypeError, since there is no function to derive the path from.

Testing

Option A: Supply all arguments directly

When every required parameter is provided by the caller, config injection is skipped entirely — no init needed:

def test_connect():
    assert connect("localhost", 5432) == expected

Option B: override context manager

Temporarily replace the global config for a test:

from hydr8 import override

def test_connect():
    with override({"db": {"host": "test-host", "port": 9999}}):
        result = connect()
        assert result == expected

API reference

Function Description
init(cfg) Store the config globally (accepts any dict or OmegaConf DictConfig)
get() Retrieve the stored config (raises RuntimeError if uninitialized)
override(overrides) Context manager that temporarily replaces the config
use(path, *, as_dict, scope) Decorator or direct config accessor for a config sub-tree

Metadata

Release files for hydr8 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hydr8 0.2.0
File Size Uploaded
hydr8-0.2.0.tar.gz 24.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hydr8 0.2.0
File Interpreter ABI Platform
hydr8-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.6 kB

Release files / hydr8-0.2.0.tar.gz

Download URL hydr8-0.2.0.tar.gz
Size 24.6 kB
Tags Source
SHA-256 checksum
How to use checksums
4a161049fe85419f98be865cf5d925ba4f2fad59d74b4ca5f3846f4198d9c3eb
BLAKE2b-256 checksum
How to use checksums
f57d23053272b418dee760c66a07aad3e5b9469428e473ca775196c268b3ac58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 11, 2026.

Transparency log

Release files / hydr8-0.2.0-py3-none-any.whl

Download URL hydr8-0.2.0-py3-none-any.whl
Size 7.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7543042ef0d1a3bbcf7ccaebcf534abb9a28a6826cffdf8fbe8bae548b2b2caf
BLAKE2b-256 checksum
How to use checksums
2b5f71d500c684d21a6d6987a99112b4e174b7175204f100f9f20aa79bd57155
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page