eqxconfig
eqxconfig is a small utility for constructing an
Equinox module from TOML without writing a
second configuration class. It derives a Pydantic model from the concrete
module's annotated __init__ signature, validates the configuration, and calls
the unchanged constructor.
TOML
↓
dynamically generated Pydantic schema
↓
validated constructor arguments
↓
Equinox __init__
↓
ordinary eqx.Module / JAX PyTree
The package requires Python 3.14 or newer.
Installation
python -m pip install eqxconfig
Usage
import equinox as eqx
import jax
from eqxconfig import ConfigurableModule
class MLP(ConfigurableModule):
mlp: eqx.nn.MLP
def __init__(
self,
in_size: int,
out_size: int,
width_size: int = 128,
depth: int = 3,
seed: int = 0,
) -> None:
self.mlp = eqx.nn.MLP(
in_size=in_size,
out_size=out_size,
width_size=width_size,
depth=depth,
key=jax.random.key(seed),
)
model = MLP.from_toml("model.toml")
model_with_overrides = MLP.from_toml(
"model.toml",
width_size=512,
depth=6,
)
model.toml contains constructor arguments at its root:
in_size = 32
out_size = 10
width_size = 256
depth = 4
seed = 42
Precedence is:
__init__ defaults < TOML < explicit from_toml overrides
The final configuration—including constructor defaults, TOML values, and
explicit overrides—goes through one Pydantic v2 validation pass. The generated
schema preserves annotations and defaults, so Annotated/Field constraints,
Literal, unions, enums, constrained types, and nested Pydantic models work
normally. Unknown keys are forbidden. Pydantic validation errors, TOML decoding
errors, and file access errors retain their standard exception types.
Nested ConfigurableModule fields are derived recursively from their own
constructor signatures. Each nested value is built through its ordinary
Equinox constructor, so custom __init__ methods, field converters,
__post_init__, __check_init__, frozen-module semantics, and PyTree behavior
are preserved at every level. This also applies inside optional, list, tuple,
and dictionary fields. Passing an already constructed nested module as an
override preserves that instance without constructing or checking it again.
The schema is generated lazily once per Equinox subclass. Constructor parameters
must be annotated and must be positional-or-keyword or keyword-only. Positional-
only parameters, *args, and **kwargs are deliberately rejected with a
TypeError. Constructor defaults must be ordinary Python defaults in the
signature; defaults embedded in Field(...), private parameter names, and the
reserved name model_config are rejected because they cannot preserve a
one-to-one constructor schema. Configuration keys match constructor parameter
names; Pydantic validation aliases are not supported in v0.1.
Direct construction remains ordinary Python and Equinox:
model = MLP(in_size=32, out_size=10, width_size=512)
Configuration parsing and module construction happen before JAX transformations.
Do not call from_toml inside jax.jit; pass the resulting module into compiled
functions as a normal Equinox PyTree.
Development
Install the development dependency group with uv:
uv sync --all-groups
Run the individual checks with:
uv run ruff check .
uv run ruff format --check .
uv run pyrefly check
uv run pytest
uv build
uv run twine check dist/*
The repository uses prek for local hooks. From a fresh checkout:
prek install
prek run --all-files
Releases
The package version lives in pyproject.toml. Update it with uv version, merge
the change, and push a matching tag such as v0.1.0. The release workflow builds
and validates one wheel and one source distribution, attaches those exact files
to a GitHub Release, and publishes the same files to PyPI.
PyPI publishing uses Trusted Publishing, not an API token. Before the first release, the repository owner must:
- Create a GitHub environment named
pypi(and add any desired deployment protection rules). - In the PyPI project's publishing settings, add a GitHub Trusted Publisher for
the actual repository owner and repository name, workflow file
release.yml, and environmentpypi.
No long-lived PyPI credential should be added to GitHub secrets.
Scope
eqxconfig intentionally handles only root-level TOML-to-constructor
configuration. It is not a general configuration framework and does not add
environment variables, command-line parsing, remote sources, or configuration
work inside JAX transformations.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eqxconfig-1.0.3.tar.gz.
File metadata
- Download URL: eqxconfig-1.0.3.tar.gz
- Upload date:
- Size: 24.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03b8643738c1a3b15f231c1487e5dadb2158ee4d4cf3b48515b1907a94537a0a
|
|
| MD5 |
849b5523ff8d45cd8cedf44126325ffc
|
|
| BLAKE2b-256 |
f85dd35abf94ec35129aeb9a7d24699eab992722dd3681d4a58c4e265a23d3a0
|
Provenance
The following attestation bundles were made for eqxconfig-1.0.3.tar.gz:
Publisher:
release.yml on varchasgopalaswamy/eqxconfig
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eqxconfig-1.0.3.tar.gz -
Subject digest:
03b8643738c1a3b15f231c1487e5dadb2158ee4d4cf3b48515b1907a94537a0a - Sigstore transparency entry: 2590115728
- Sigstore integration time:
-
Permalink:
varchasgopalaswamy/eqxconfig@8f339c7c1dc2c18f9ac7d939cfb3a2cc0eacb74a -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/varchasgopalaswamy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f339c7c1dc2c18f9ac7d939cfb3a2cc0eacb74a -
Trigger Event:
push
-
Statement type:
File details
Details for the file eqxconfig-1.0.3-py3-none-any.whl.
File metadata
- Download URL: eqxconfig-1.0.3-py3-none-any.whl
- Upload date:
- Size: 18.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b09855bdbbb3b7d08661804bfc5b9660177dd05bfdcb92837eb121c00d9ff8e
|
|
| MD5 |
1a51abf83f4fa120ff05c0416469b79b
|
|
| BLAKE2b-256 |
1a669774496d192899269d5f48488b3ad312178b04d20e384d43228657de9b9e
|
Provenance
The following attestation bundles were made for eqxconfig-1.0.3-py3-none-any.whl:
Publisher:
release.yml on varchasgopalaswamy/eqxconfig
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
eqxconfig-1.0.3-py3-none-any.whl -
Subject digest:
3b09855bdbbb3b7d08661804bfc5b9660177dd05bfdcb92837eb121c00d9ff8e - Sigstore transparency entry: 2590116035
- Sigstore integration time:
-
Permalink:
varchasgopalaswamy/eqxconfig@8f339c7c1dc2c18f9ac7d939cfb3a2cc0eacb74a -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/varchasgopalaswamy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@8f339c7c1dc2c18f9ac7d939cfb3a2cc0eacb74a -
Trigger Event:
push
-
Statement type: