Skip to main content

Typed, provenance-aware configuration for ML runs: drafts, interpolation, one validation boundary. Powered by Pydantic.

Project description

nshconfig

Typed, provenance-aware configuration for ML runs, powered by Pydantic.

Documentation

One verb family and one value:

  • Cls.config_draft() gives a mutable draft: plain Python assignment, nested configs auto-create, validation deferred.
  • C.interp(lambda c: ...) is a value that resolves against the config tree at validation. It is legal anywhere a value sits: assigned on a draft, inside a model_validate dict, or as a class default. This is Hydra-style interpolation, in Python, mostly type-checked.
  • draft.config_finalize() resolves interpolation, validates once, and returns a frozen, hashable, fully-concrete config.

Plus provenance: final.config_explain("optim.lr") answers "why did this run use that value?" down to file, line, function, source text, and the interpolation's "because" chain.

Install

pip install nshconfig            # pydantic>=2.13, Python>=3.10
pip install nshconfig[treescope] # optional rich notebook rendering

Quickstart

import nshconfig as C

class LNConfig(C.Config):
    dim: int = 32                  # plain default; leaf classes need no interpolation
    eps: float = 1e-5

class EncoderConfig(C.Config):
    ln: LNConfig

class HeadConfig(C.Config):
    # class-level interpolation: a value sitting in the default slot
    dim: int = C.interp(lambda c: c.nearest(ModelConfig).dim)

class ModelConfig(C.Config):
    dim: int = 768
    encoder: EncoderConfig
    head: HeadConfig

class TrainConfig(C.Config):
    batch: int = 8
    model: ModelConfig

# compose in a notebook; helpers are plain functions (your "config groups")
def large(cfg: TrainConfig) -> None:
    cfg.model.dim = 1024

cfg = TrainConfig.config_draft()
large(cfg)
# instance-level interpolation: wire THIS tree only, at composition time
cfg.model.encoder.ln.dim = C.interp(lambda c: c.nearest(ModelConfig).dim)

final = cfg.config_finalize()            # the one validation boundary
assert final.model.encoder.ln.dim == 1024   # followed the knob
assert final.model.head.dim == 1024         # class-default rule, same machinery
final.model_dump_json()                     # concrete values only: the run record

# why did this run use that value?
print(final.config_explain("model.head.dim"))
# model.head.dim = 1024
#   interpolated to 1024 by <lambda> @ configs.py:11 (class default)
#       because model.dim = 1024
#   class-default rule: interp(<<lambda> @ configs.py:11>)   (active)

Explicit always beats interpolation (presence in the input slot beats the default slot; last write wins; del re-arms). Nothing pending can reach a final, a dump, an f-string, or an if without a loud error naming the dotted path and the source line. Drafts cloudpickle to clusters mid-composition and finalize on the far side, provenance included.

The Ctx API (what the lambda sees)

Accessor Hydra equivalent Sees
c.data same level own fields, earlier markers already resolved
c.parent ${..x} one level up, resolved
c.root ${a.b} the validation root, incl. sibling subtrees
c.nearest(Cls) (none: better) nearest enclosing Cls; survives restructuring

License

MIT

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distribution

nshconfig-2.0.0a1.tar.gz (16.5 kB view details)

Uploaded Source

Built Distribution

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

nshconfig-2.0.0a1-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file nshconfig-2.0.0a1.tar.gz.

File metadata

  • Download URL: nshconfig-2.0.0a1.tar.gz
  • Upload date:
  • Size: 16.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for nshconfig-2.0.0a1.tar.gz
Algorithm Hash digest
SHA256 b5ede94b3965c4d0367a0c2a3968770c7af4c2899b1ac0b764ea291e249f7664
MD5 514a7c8837f46674484e0edc1470cb25
BLAKE2b-256 930c8765b91427fe92145fa07e788025c4a19b0b77fc8bfa852bf0bf61794cc4

See more details on using hashes here.

File details

Details for the file nshconfig-2.0.0a1-py3-none-any.whl.

File metadata

  • Download URL: nshconfig-2.0.0a1-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for nshconfig-2.0.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 e23cb3773f43e8bb4950ba3240517a97b0445da85cb3bcf3cbd624d1437b931b
MD5 5e0a3a907fb443c4f4fe8beb42f789cd
BLAKE2b-256 cf4754db59a0c6ef5345fb094b3e8d9b647a999b33614945ab4250573e068f64

See more details on using hashes here.

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