clevis 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.
- clevis-0.1.0/.claude/settings.local.json +19 -0
- clevis-0.1.0/.github/workflows/test.yml +37 -0
- clevis-0.1.0/.gitignore +28 -0
- clevis-0.1.0/.python-version +1 -0
- clevis-0.1.0/.readthedocs.yaml +16 -0
- clevis-0.1.0/LICENSE +21 -0
- clevis-0.1.0/Makefile +71 -0
- clevis-0.1.0/PKG-INFO +263 -0
- clevis-0.1.0/README.md +223 -0
- clevis-0.1.0/REQUIREMENTS.md +89 -0
- clevis-0.1.0/TODO.md +129 -0
- clevis-0.1.0/analysis/functional.md +298 -0
- clevis-0.1.0/docs/api.rst +71 -0
- clevis-0.1.0/docs/conf.py +36 -0
- clevis-0.1.0/docs/index.rst +59 -0
- clevis-0.1.0/docs/installation.rst +189 -0
- clevis-0.1.0/docs/usage.rst +572 -0
- clevis-0.1.0/main.py +50 -0
- clevis-0.1.0/project.toml +15 -0
- clevis-0.1.0/pyproject.toml +83 -0
- clevis-0.1.0/reporting/add-twine-dependency/development-summary.md +57 -0
- clevis-0.1.0/src/clevis/__init__.py +359 -0
- clevis-0.1.0/src/clevis/py.typed +0 -0
- clevis-0.1.0/tests/test_clevis.py +226 -0
- clevis-0.1.0/tests/test_parser.py +68 -0
- clevis-0.1.0/uv.lock +1710 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(git pull *)",
|
|
5
|
+
"Bash(gh pr *)",
|
|
6
|
+
"Bash(gh issue *)",
|
|
7
|
+
"Bash(uv run *)",
|
|
8
|
+
"Bash(git commit *)",
|
|
9
|
+
"Bash(uv sync *)",
|
|
10
|
+
"Bash(make typecheck *)",
|
|
11
|
+
"Bash(make check *)",
|
|
12
|
+
"Bash(git push *)",
|
|
13
|
+
"Bash(make build *)",
|
|
14
|
+
"Bash(git tag *)",
|
|
15
|
+
"Bash(make help *)",
|
|
16
|
+
"Bash(make publish *)"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master, main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@v4
|
|
21
|
+
with:
|
|
22
|
+
version: "latest"
|
|
23
|
+
|
|
24
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
25
|
+
run: uv python install ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --all-extras
|
|
29
|
+
|
|
30
|
+
- name: Run tests
|
|
31
|
+
run: uv run pytest -v --cov=src --cov-report=xml
|
|
32
|
+
|
|
33
|
+
- name: Upload coverage to Coveralls
|
|
34
|
+
uses: coverallsapp/github-action@v2
|
|
35
|
+
if: matrix.python-version == '3.11'
|
|
36
|
+
with:
|
|
37
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
clevis-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Testing
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.coverage
|
|
15
|
+
htmlcov/
|
|
16
|
+
.tox/
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.vscode/
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
|
|
24
|
+
# OS
|
|
25
|
+
.DS_Store
|
|
26
|
+
|
|
27
|
+
# Documentation
|
|
28
|
+
docs/_build/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11
|
clevis-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christophe Van Ginneken
|
|
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.
|
clevis-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
-include ~/.claude/Makefile
|
|
2
|
+
|
|
3
|
+
.PHONY: help env-dev env-run test test-cov test-all run format lint typecheck check build pre-publish publish publish-test clean clean-all
|
|
4
|
+
|
|
5
|
+
help: ## Show this help message
|
|
6
|
+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
|
|
7
|
+
|
|
8
|
+
env-dev: ## Install all dependencies (dev + docs)
|
|
9
|
+
uv sync --all-extras
|
|
10
|
+
|
|
11
|
+
env-run: ## Install runtime dependencies only
|
|
12
|
+
uv sync --no-dev
|
|
13
|
+
|
|
14
|
+
test: ## Run tests (usage: make test TEST=file|file:test_name)
|
|
15
|
+
@if [ -n "$(TEST)" ]; then \
|
|
16
|
+
uv run pytest $(TEST); \
|
|
17
|
+
else \
|
|
18
|
+
uv run pytest; \
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
test-cov: ## Run tests with coverage
|
|
22
|
+
uv run pytest --cov=src --cov-report=html
|
|
23
|
+
|
|
24
|
+
test-all: ## Run tests on all Python versions
|
|
25
|
+
uv run tox
|
|
26
|
+
|
|
27
|
+
run: ## Run the example application
|
|
28
|
+
uv run python main.py
|
|
29
|
+
|
|
30
|
+
format: ## Format code and fix linting issues
|
|
31
|
+
uv run ruff format src/
|
|
32
|
+
uv run ruff check --fix src/
|
|
33
|
+
|
|
34
|
+
lint: ## Check code for linting issues
|
|
35
|
+
uv run ruff check src/
|
|
36
|
+
|
|
37
|
+
typecheck: ## Run type checking
|
|
38
|
+
uv run mypy src/
|
|
39
|
+
|
|
40
|
+
check: format lint typecheck test ## Run all quality checks
|
|
41
|
+
|
|
42
|
+
build: ## Build distribution packages
|
|
43
|
+
uv build
|
|
44
|
+
|
|
45
|
+
pre-publish: check ## Pre-publication checks (run before publishing)
|
|
46
|
+
@echo "Checking for relative image paths in README..."
|
|
47
|
+
@grep -n '!\[.*](media/' README.md && (echo "ERROR: Relative image paths found - use raw GitHub URLs for PyPI"; exit 1) || echo "OK: No relative image paths"
|
|
48
|
+
@echo "Checking version sync..."
|
|
49
|
+
@VERSION_PY=$$(grep '^version =' pyproject.toml | cut -d'"' -f2); \
|
|
50
|
+
VERSION_INIT=$$(grep '^__version__ = ' src/clevis/__init__.py | cut -d'"' -f2); \
|
|
51
|
+
if [ "$$VERSION_PY" != "$$VERSION_INIT" ]; then \
|
|
52
|
+
echo "ERROR: Version mismatch - pyproject.toml ($$VERSION_PY) vs __init__.py ($$VERSION_INIT)"; \
|
|
53
|
+
exit 1; \
|
|
54
|
+
fi; \
|
|
55
|
+
echo "OK: Versions match ($$VERSION_PY)"
|
|
56
|
+
@echo "Pre-publication checks passed"
|
|
57
|
+
|
|
58
|
+
publish: clean build ## Publish to PyPI (runs pre-publish checks)
|
|
59
|
+
@$(MAKE) pre-publish
|
|
60
|
+
uv run twine upload dist/*
|
|
61
|
+
|
|
62
|
+
publish-test: build ## Publish to TestPyPI
|
|
63
|
+
uv run twine upload --repository testpypi dist/*
|
|
64
|
+
|
|
65
|
+
clean: ## Remove build artifacts
|
|
66
|
+
rm -rf dist/ *.egg-info .pytest_cache .coverage htmlcov/ .mypy_cache .ruff_cache
|
|
67
|
+
|
|
68
|
+
clean-all: clean ## Remove virtualenv and lock file
|
|
69
|
+
rm -rf .venv uv.lock
|
|
70
|
+
|
|
71
|
+
|
clevis-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clevis
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Configuration management for Python projects with dataclass-based schemas
|
|
5
|
+
Project-URL: Homepage, https://github.com/christophevg/clevis
|
|
6
|
+
Project-URL: Documentation, https://clevis.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/christophevg/clevis
|
|
8
|
+
Author-email: Christophe Van Ginneken <christophe@christophe.vg>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: argparse,cli,configuration,dataclass,toml
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: dacite
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
27
|
+
Requires-Dist: tox; extra == 'dev'
|
|
28
|
+
Requires-Dist: twine; extra == 'dev'
|
|
29
|
+
Provides-Extra: docs
|
|
30
|
+
Requires-Dist: myst-parser>=2.0.0; extra == 'docs'
|
|
31
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == 'docs'
|
|
32
|
+
Requires-Dist: sphinx>=7.0.0; extra == 'docs'
|
|
33
|
+
Provides-Extra: envtoml
|
|
34
|
+
Requires-Dist: envtoml; extra == 'envtoml'
|
|
35
|
+
Provides-Extra: tomlev
|
|
36
|
+
Requires-Dist: tomlev; extra == 'tomlev'
|
|
37
|
+
Provides-Extra: tomli
|
|
38
|
+
Requires-Dist: tomli; extra == 'tomli'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# Clevis
|
|
42
|
+
|
|
43
|
+
[![PyPI][pypi-badge]][pypi]
|
|
44
|
+
[![Python][python-badge]][python]
|
|
45
|
+
[![CI][ci-badge]][ci]
|
|
46
|
+
[![Coverage][coverage-badge]][coverage]
|
|
47
|
+
[![License][license-badge]][license]
|
|
48
|
+
[![Agentic][agentic-badge]][agentic]
|
|
49
|
+
|
|
50
|
+
> Configuration management for Python projects with dataclass-based schemas
|
|
51
|
+
|
|
52
|
+
Clevis provides type-safe configuration management for Python applications:
|
|
53
|
+
|
|
54
|
+
- **Dataclass schemas** — Define config structure with Python dataclasses
|
|
55
|
+
- **TOML support** — Load from `.toml` files
|
|
56
|
+
- **Env vars** — `${VAR}` interpolation (with envtoml/tomlev)
|
|
57
|
+
- **CLI generation** — Auto-generate argparse from dataclass
|
|
58
|
+
- **Layered config** — User config < project config < CLI args
|
|
59
|
+
|
|
60
|
+
## About the Name
|
|
61
|
+
|
|
62
|
+
A **clevis** is a U-shaped mechanical fastener that connects components while allowing pivoting. It's used in everything from agricultural equipment to aerospace control systems — a simple, robust connector that provides flexibility without compromising strength.
|
|
63
|
+
|
|
64
|
+
This library follows the same principle: it **connects** multiple configuration sources (TOML files, environment variables, CLI arguments) into a single, cohesive interface. Just as a mechanical clevis allows articulation, Clevis allows your configuration to flex and adapt — user-level defaults, project-level settings, and runtime overrides all pivot around a single dataclass schema.
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Install (Python 3.11+)
|
|
70
|
+
pip install clevis
|
|
71
|
+
|
|
72
|
+
# Or with env var support
|
|
73
|
+
pip install clevis[envtoml]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from dataclasses import dataclass
|
|
78
|
+
from clevis import get_config
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class Config:
|
|
82
|
+
name: str = "MyApp"
|
|
83
|
+
debug: bool = False
|
|
84
|
+
|
|
85
|
+
config = get_config(Config, name="app")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
Choose your TOML parser based on needs:
|
|
91
|
+
|
|
92
|
+
| Extra | Features | Use When |
|
|
93
|
+
|-------|----------|----------|
|
|
94
|
+
| *(none)* | Stdlib `tomllib` | Python 3.11+, minimal deps |
|
|
95
|
+
| [`tomli`][tomli] | Pure Python TOML | Python 3.10 compatibility |
|
|
96
|
+
| [`envtoml`][envtoml] | `${VAR}` interpolation | Environment-based config |
|
|
97
|
+
| [`tomlev`][tomlev] | `${VAR\|default}` syntax | Env vars with defaults |
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Python 3.11+ - no extras needed
|
|
101
|
+
pip install clevis
|
|
102
|
+
|
|
103
|
+
# Python 3.10
|
|
104
|
+
pip install clevis[tomli]
|
|
105
|
+
|
|
106
|
+
# Environment variable support
|
|
107
|
+
pip install clevis[envtoml]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Usage
|
|
111
|
+
|
|
112
|
+
### Define Your Config
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from dataclasses import dataclass, field
|
|
116
|
+
|
|
117
|
+
@dataclass
|
|
118
|
+
class DatabaseConfig:
|
|
119
|
+
host: str = "localhost"
|
|
120
|
+
port: int = 5432
|
|
121
|
+
user: str | None = None
|
|
122
|
+
password: str | None = None
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class AppConfig:
|
|
126
|
+
name: str = "MyApp"
|
|
127
|
+
debug: bool = False
|
|
128
|
+
database: DatabaseConfig = field(default_factory=DatabaseConfig)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Load Configuration
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from clevis import get_config
|
|
135
|
+
|
|
136
|
+
# Load from ~/.myapp.toml and ./myapp.toml
|
|
137
|
+
config = get_config(AppConfig, name="myapp")
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Configuration layers (lowest to highest priority):
|
|
141
|
+
|
|
142
|
+
1. **Dataclass defaults**
|
|
143
|
+
2. **User-level TOML** — `~/.{name}.toml`
|
|
144
|
+
3. **Project-level TOML** — `./{name}.toml`
|
|
145
|
+
4. **CLI arguments** — `--database-host`, `--debug`
|
|
146
|
+
|
|
147
|
+
### TOML Files
|
|
148
|
+
|
|
149
|
+
Create `myapp.toml`:
|
|
150
|
+
|
|
151
|
+
```toml
|
|
152
|
+
name = "Production App"
|
|
153
|
+
debug = true
|
|
154
|
+
|
|
155
|
+
[database]
|
|
156
|
+
host = "db.example.com"
|
|
157
|
+
port = 5432
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
With env var support (`clevis[envtoml]` or `clevis[tomlev]`):
|
|
161
|
+
|
|
162
|
+
```toml
|
|
163
|
+
[database]
|
|
164
|
+
password = "${DB_PASSWORD}" # envtoml
|
|
165
|
+
host = "${DB_HOST|localhost}" # tomlev (with default)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### CLI Arguments
|
|
169
|
+
|
|
170
|
+
Clevis auto-generates CLI arguments:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
python app.py --database-host localhost
|
|
174
|
+
python app.py --database-port 5432
|
|
175
|
+
python app.py --debug
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Nested dataclasses become dashed arguments: `database.host` → `--database-host`
|
|
179
|
+
|
|
180
|
+
## Testing
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Run tests
|
|
184
|
+
make test
|
|
185
|
+
|
|
186
|
+
# Run with coverage
|
|
187
|
+
make test-cov
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## API Reference
|
|
191
|
+
|
|
192
|
+
### `get_config(data_class, name="project", user=True, project=True, args=None)`
|
|
193
|
+
|
|
194
|
+
Load configuration from TOML files and CLI arguments.
|
|
195
|
+
|
|
196
|
+
**Parameters:**
|
|
197
|
+
- `data_class` — The dataclass type to populate
|
|
198
|
+
- `name` — Config file name (without `.toml`)
|
|
199
|
+
- `user` — Load user-level config (`~/.{name}.toml`)
|
|
200
|
+
- `project` — Load project-level config (`./{name}.toml`)
|
|
201
|
+
- `args` — CLI arguments (defaults to `sys.argv[1:]`)
|
|
202
|
+
|
|
203
|
+
**Returns:** Instance of the dataclass with merged configuration
|
|
204
|
+
|
|
205
|
+
**Raises:**
|
|
206
|
+
- `ConfigError` — Missing required fields or wrong types
|
|
207
|
+
- `ImportError` — No TOML parser available
|
|
208
|
+
|
|
209
|
+
## Error Messages
|
|
210
|
+
|
|
211
|
+
Clevis provides helpful, actionable errors:
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
======================================================================
|
|
215
|
+
Configuration Error
|
|
216
|
+
======================================================================
|
|
217
|
+
|
|
218
|
+
Field: database.host
|
|
219
|
+
Issue: Required field has no value
|
|
220
|
+
|
|
221
|
+
Provide this value in one of these ways:
|
|
222
|
+
|
|
223
|
+
1. Project config: ./project.toml
|
|
224
|
+
[database]
|
|
225
|
+
host = "your_value"
|
|
226
|
+
|
|
227
|
+
2. User config: ~/.project.toml
|
|
228
|
+
(same format as above)
|
|
229
|
+
|
|
230
|
+
3. CLI argument: --database-host <value>
|
|
231
|
+
|
|
232
|
+
======================================================================
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Acknowledgments
|
|
236
|
+
|
|
237
|
+
Clevis builds on excellent work from the Python community:
|
|
238
|
+
|
|
239
|
+
- **[tomllib](https://docs.python.org/3/library/tomllib.html)** — Python 3.11+ stdlib
|
|
240
|
+
- **[tomli](https://github.com/hukkin/tomli)** — Pure Python TOML 1.0
|
|
241
|
+
- **[envtoml](https://github.com/sank8m/envtoml)** — Env var interpolation
|
|
242
|
+
- **[tomlev](https://github.com/thesimj/tomlev)** — Env vars with defaults
|
|
243
|
+
- **[dacite](https://github.com/konradhalas/dacite)** — Dict-to-dataclass conversion
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT
|
|
248
|
+
|
|
249
|
+
[pypi]: https://pypi.org/project/clevis/
|
|
250
|
+
[pypi-badge]: https://img.shields.io/pypi/v/clevis.svg
|
|
251
|
+
[python]: https://www.python.org/
|
|
252
|
+
[python-badge]: https://img.shields.io/badge/Python-3.10+-blue.svg
|
|
253
|
+
[ci]: https://github.com/christophevg/clevis/actions/workflows/test.yml
|
|
254
|
+
[ci-badge]: https://img.shields.io/github/actions/workflow/status/christophevg/clevis/test.yml.svg
|
|
255
|
+
[coverage]: https://coveralls.io/github/christophevg/clevis
|
|
256
|
+
[coverage-badge]: https://img.shields.io/coveralls/github/christophevg/clevis.svg
|
|
257
|
+
[license]: LICENSE
|
|
258
|
+
[license-badge]: https://img.shields.io/github/license/christophevg/clevis.svg
|
|
259
|
+
[agentic]: https://christophe.vg/about/Agentic-Workflow
|
|
260
|
+
[agentic-badge]: https://img.shields.io/badge/workflow-agentic-blueviolet?style=flat-square
|
|
261
|
+
[tomli]: https://github.com/hukkin/tomli
|
|
262
|
+
[envtoml]: https://github.com/sank8m/envtoml
|
|
263
|
+
[tomlev]: https://github.com/thesimj/tomlev
|
clevis-0.1.0/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Clevis
|
|
2
|
+
|
|
3
|
+
[![PyPI][pypi-badge]][pypi]
|
|
4
|
+
[![Python][python-badge]][python]
|
|
5
|
+
[![CI][ci-badge]][ci]
|
|
6
|
+
[![Coverage][coverage-badge]][coverage]
|
|
7
|
+
[![License][license-badge]][license]
|
|
8
|
+
[![Agentic][agentic-badge]][agentic]
|
|
9
|
+
|
|
10
|
+
> Configuration management for Python projects with dataclass-based schemas
|
|
11
|
+
|
|
12
|
+
Clevis provides type-safe configuration management for Python applications:
|
|
13
|
+
|
|
14
|
+
- **Dataclass schemas** — Define config structure with Python dataclasses
|
|
15
|
+
- **TOML support** — Load from `.toml` files
|
|
16
|
+
- **Env vars** — `${VAR}` interpolation (with envtoml/tomlev)
|
|
17
|
+
- **CLI generation** — Auto-generate argparse from dataclass
|
|
18
|
+
- **Layered config** — User config < project config < CLI args
|
|
19
|
+
|
|
20
|
+
## About the Name
|
|
21
|
+
|
|
22
|
+
A **clevis** is a U-shaped mechanical fastener that connects components while allowing pivoting. It's used in everything from agricultural equipment to aerospace control systems — a simple, robust connector that provides flexibility without compromising strength.
|
|
23
|
+
|
|
24
|
+
This library follows the same principle: it **connects** multiple configuration sources (TOML files, environment variables, CLI arguments) into a single, cohesive interface. Just as a mechanical clevis allows articulation, Clevis allows your configuration to flex and adapt — user-level defaults, project-level settings, and runtime overrides all pivot around a single dataclass schema.
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install (Python 3.11+)
|
|
30
|
+
pip install clevis
|
|
31
|
+
|
|
32
|
+
# Or with env var support
|
|
33
|
+
pip install clevis[envtoml]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from dataclasses import dataclass
|
|
38
|
+
from clevis import get_config
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class Config:
|
|
42
|
+
name: str = "MyApp"
|
|
43
|
+
debug: bool = False
|
|
44
|
+
|
|
45
|
+
config = get_config(Config, name="app")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Choose your TOML parser based on needs:
|
|
51
|
+
|
|
52
|
+
| Extra | Features | Use When |
|
|
53
|
+
|-------|----------|----------|
|
|
54
|
+
| *(none)* | Stdlib `tomllib` | Python 3.11+, minimal deps |
|
|
55
|
+
| [`tomli`][tomli] | Pure Python TOML | Python 3.10 compatibility |
|
|
56
|
+
| [`envtoml`][envtoml] | `${VAR}` interpolation | Environment-based config |
|
|
57
|
+
| [`tomlev`][tomlev] | `${VAR\|default}` syntax | Env vars with defaults |
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Python 3.11+ - no extras needed
|
|
61
|
+
pip install clevis
|
|
62
|
+
|
|
63
|
+
# Python 3.10
|
|
64
|
+
pip install clevis[tomli]
|
|
65
|
+
|
|
66
|
+
# Environment variable support
|
|
67
|
+
pip install clevis[envtoml]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
### Define Your Config
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from dataclasses import dataclass, field
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class DatabaseConfig:
|
|
79
|
+
host: str = "localhost"
|
|
80
|
+
port: int = 5432
|
|
81
|
+
user: str | None = None
|
|
82
|
+
password: str | None = None
|
|
83
|
+
|
|
84
|
+
@dataclass
|
|
85
|
+
class AppConfig:
|
|
86
|
+
name: str = "MyApp"
|
|
87
|
+
debug: bool = False
|
|
88
|
+
database: DatabaseConfig = field(default_factory=DatabaseConfig)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Load Configuration
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from clevis import get_config
|
|
95
|
+
|
|
96
|
+
# Load from ~/.myapp.toml and ./myapp.toml
|
|
97
|
+
config = get_config(AppConfig, name="myapp")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Configuration layers (lowest to highest priority):
|
|
101
|
+
|
|
102
|
+
1. **Dataclass defaults**
|
|
103
|
+
2. **User-level TOML** — `~/.{name}.toml`
|
|
104
|
+
3. **Project-level TOML** — `./{name}.toml`
|
|
105
|
+
4. **CLI arguments** — `--database-host`, `--debug`
|
|
106
|
+
|
|
107
|
+
### TOML Files
|
|
108
|
+
|
|
109
|
+
Create `myapp.toml`:
|
|
110
|
+
|
|
111
|
+
```toml
|
|
112
|
+
name = "Production App"
|
|
113
|
+
debug = true
|
|
114
|
+
|
|
115
|
+
[database]
|
|
116
|
+
host = "db.example.com"
|
|
117
|
+
port = 5432
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
With env var support (`clevis[envtoml]` or `clevis[tomlev]`):
|
|
121
|
+
|
|
122
|
+
```toml
|
|
123
|
+
[database]
|
|
124
|
+
password = "${DB_PASSWORD}" # envtoml
|
|
125
|
+
host = "${DB_HOST|localhost}" # tomlev (with default)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### CLI Arguments
|
|
129
|
+
|
|
130
|
+
Clevis auto-generates CLI arguments:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
python app.py --database-host localhost
|
|
134
|
+
python app.py --database-port 5432
|
|
135
|
+
python app.py --debug
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Nested dataclasses become dashed arguments: `database.host` → `--database-host`
|
|
139
|
+
|
|
140
|
+
## Testing
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Run tests
|
|
144
|
+
make test
|
|
145
|
+
|
|
146
|
+
# Run with coverage
|
|
147
|
+
make test-cov
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## API Reference
|
|
151
|
+
|
|
152
|
+
### `get_config(data_class, name="project", user=True, project=True, args=None)`
|
|
153
|
+
|
|
154
|
+
Load configuration from TOML files and CLI arguments.
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
- `data_class` — The dataclass type to populate
|
|
158
|
+
- `name` — Config file name (without `.toml`)
|
|
159
|
+
- `user` — Load user-level config (`~/.{name}.toml`)
|
|
160
|
+
- `project` — Load project-level config (`./{name}.toml`)
|
|
161
|
+
- `args` — CLI arguments (defaults to `sys.argv[1:]`)
|
|
162
|
+
|
|
163
|
+
**Returns:** Instance of the dataclass with merged configuration
|
|
164
|
+
|
|
165
|
+
**Raises:**
|
|
166
|
+
- `ConfigError` — Missing required fields or wrong types
|
|
167
|
+
- `ImportError` — No TOML parser available
|
|
168
|
+
|
|
169
|
+
## Error Messages
|
|
170
|
+
|
|
171
|
+
Clevis provides helpful, actionable errors:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
======================================================================
|
|
175
|
+
Configuration Error
|
|
176
|
+
======================================================================
|
|
177
|
+
|
|
178
|
+
Field: database.host
|
|
179
|
+
Issue: Required field has no value
|
|
180
|
+
|
|
181
|
+
Provide this value in one of these ways:
|
|
182
|
+
|
|
183
|
+
1. Project config: ./project.toml
|
|
184
|
+
[database]
|
|
185
|
+
host = "your_value"
|
|
186
|
+
|
|
187
|
+
2. User config: ~/.project.toml
|
|
188
|
+
(same format as above)
|
|
189
|
+
|
|
190
|
+
3. CLI argument: --database-host <value>
|
|
191
|
+
|
|
192
|
+
======================================================================
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Acknowledgments
|
|
196
|
+
|
|
197
|
+
Clevis builds on excellent work from the Python community:
|
|
198
|
+
|
|
199
|
+
- **[tomllib](https://docs.python.org/3/library/tomllib.html)** — Python 3.11+ stdlib
|
|
200
|
+
- **[tomli](https://github.com/hukkin/tomli)** — Pure Python TOML 1.0
|
|
201
|
+
- **[envtoml](https://github.com/sank8m/envtoml)** — Env var interpolation
|
|
202
|
+
- **[tomlev](https://github.com/thesimj/tomlev)** — Env vars with defaults
|
|
203
|
+
- **[dacite](https://github.com/konradhalas/dacite)** — Dict-to-dataclass conversion
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT
|
|
208
|
+
|
|
209
|
+
[pypi]: https://pypi.org/project/clevis/
|
|
210
|
+
[pypi-badge]: https://img.shields.io/pypi/v/clevis.svg
|
|
211
|
+
[python]: https://www.python.org/
|
|
212
|
+
[python-badge]: https://img.shields.io/badge/Python-3.10+-blue.svg
|
|
213
|
+
[ci]: https://github.com/christophevg/clevis/actions/workflows/test.yml
|
|
214
|
+
[ci-badge]: https://img.shields.io/github/actions/workflow/status/christophevg/clevis/test.yml.svg
|
|
215
|
+
[coverage]: https://coveralls.io/github/christophevg/clevis
|
|
216
|
+
[coverage-badge]: https://img.shields.io/coveralls/github/christophevg/clevis.svg
|
|
217
|
+
[license]: LICENSE
|
|
218
|
+
[license-badge]: https://img.shields.io/github/license/christophevg/clevis.svg
|
|
219
|
+
[agentic]: https://christophe.vg/about/Agentic-Workflow
|
|
220
|
+
[agentic-badge]: https://img.shields.io/badge/workflow-agentic-blueviolet?style=flat-square
|
|
221
|
+
[tomli]: https://github.com/hukkin/tomli
|
|
222
|
+
[envtoml]: https://github.com/sank8m/envtoml
|
|
223
|
+
[tomlev]: https://github.com/thesimj/tomlev
|