Skip to main content

Decorator-based config injection for Hydra

Project description

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 parameter are silently ignored.

@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"]
    ...

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hydr8-0.1.0.tar.gz (23.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hydr8-0.1.0-py3-none-any.whl (6.8 kB view details)

Uploaded Python 3

File details

Details for the file hydr8-0.1.0.tar.gz.

File metadata

  • Download URL: hydr8-0.1.0.tar.gz
  • Upload date:
  • Size: 23.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hydr8-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4db4d56de76a2335e254d9ef17929d670b5f9e850ff1e01d4afc09238cf44a93
MD5 5ce5d889dd9aa7805e907dce55071a49
BLAKE2b-256 cd9192a0335b1f775befc8c0b77498f6769bc7eea2d1e2a3760ee6eaa979f8f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for hydr8-0.1.0.tar.gz:

Publisher: publish.yml on rsamf/hydr8

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hydr8-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: hydr8-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for hydr8-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bea4ec21d1dd0d3805f13adcd67a66518706f1e4d1b1762c9fc880dd98c15839
MD5 181abaad0283db963e537b22e8ab8fee
BLAKE2b-256 5ee765b6e28860022a8a4d1f711c3210808d243906b993e033dfa2b526e1d254

See more details on using hashes here.

Provenance

The following attestation bundles were made for hydr8-0.1.0-py3-none-any.whl:

Publisher: publish.yml on rsamf/hydr8

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page