canopee 0.0.2__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.
- canopee-0.0.2/PKG-INFO +116 -0
- canopee-0.0.2/README.md +90 -0
- canopee-0.0.2/pyproject.toml +69 -0
- canopee-0.0.2/src/canopee/__init__.py +77 -0
- canopee-0.0.2/src/canopee/cli.py +1191 -0
- canopee-0.0.2/src/canopee/core.py +263 -0
- canopee-0.0.2/src/canopee/py.typed +0 -0
- canopee-0.0.2/src/canopee/serialization.py +395 -0
- canopee-0.0.2/src/canopee/sources.py +283 -0
- canopee-0.0.2/src/canopee/store.py +254 -0
- canopee-0.0.2/src/canopee/sweep.py +645 -0
canopee-0.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: canopee
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: A type-safe python configuration library
|
|
5
|
+
Author: Alexandre Mayerowitz
|
|
6
|
+
Author-email: Alexandre Mayerowitz <alexandre.mayerowitz@gmail.com>
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Classifier: Topic :: Software Development :: Testing
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Requires-Dist: pydantic>=2.12.5
|
|
19
|
+
Requires-Dist: tomli-w>=1.2.0
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Project-URL: Repository, https://github.com/mayeroa/canopee
|
|
22
|
+
Project-URL: Homepage, https://mayeroa.github.io/canopee/
|
|
23
|
+
Project-URL: Documentation, https://mayeroa.github.io/canopee/
|
|
24
|
+
Project-URL: Issues, https://github.com/mayeroa/canopee/issues
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
<h1>🌲 Canopee</h1>
|
|
29
|
+
<p><strong>A type-safe, fluent configuration library for Python 3.11+.</strong></p>
|
|
30
|
+
<p>
|
|
31
|
+
<a href="https://pypi.org/project/canopee/"><img src="https://img.shields.io/pypi/v/canopee.svg" alt="PyPI version"></a>
|
|
32
|
+
<a href="https://pypi.org/project/canopee/"><img src="https://img.shields.io/pypi/pyversions/canopee.svg" alt="Python versions"></a>
|
|
33
|
+
<a href="https://github.com/canopee-py/canopee/actions"><img src="https://img.shields.io/github/actions/workflow/status/canopee-py/canopee/ci.yml?branch=main" alt="CI Status"></a>
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
**Canopee** is a production-ready configuration library that treats Python as the ultimate config DSL.
|
|
40
|
+
|
|
41
|
+
Built on top of Pydantic v2, it removes the brittleness of YAMLs, silent mutation footguns, and metaclass magic, giving you IDE autocomplete, instant validation, and elegant hyperparameter sweeping out of the box.
|
|
42
|
+
|
|
43
|
+
## 🌟 Why Canopee?
|
|
44
|
+
|
|
45
|
+
* **Always Valid**: Configs are validated precisely at construction. No runtime surprises.
|
|
46
|
+
* **Immutable**: `ConfigBase` objects are `frozen=True`. They can be hashed, cached, and safely passed across threads.
|
|
47
|
+
* **Type-Safe Evolution**: Evolve new variants purely with Python keywords via the `.evolve(**kwargs)` method.
|
|
48
|
+
* **First-Class Sweeps**: Define hyperparameter search spaces directly over your types, using strategies like *grid*, *random*, or *optuna*.
|
|
49
|
+
* **Symmetric I/O**: Naturally save and load instances via `.toml`, `.yaml`, or `.json` extensions natively, or inject CLI/Env overrides securely.
|
|
50
|
+
|
|
51
|
+
## 🚀 Quickstart
|
|
52
|
+
|
|
53
|
+
### Installation
|
|
54
|
+
```bash
|
|
55
|
+
pip install canopee
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Basic Usage
|
|
59
|
+
|
|
60
|
+
Subclass `ConfigBase` as you would any Pydantic model.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from canopee import ConfigBase
|
|
64
|
+
from pydantic import computed_field
|
|
65
|
+
|
|
66
|
+
class TrainingConfig(ConfigBase):
|
|
67
|
+
learning_rate: float = 1e-3
|
|
68
|
+
epochs: int = 20
|
|
69
|
+
batch_size: int = 128
|
|
70
|
+
|
|
71
|
+
@computed_field
|
|
72
|
+
@property
|
|
73
|
+
def total_steps(self) -> int:
|
|
74
|
+
return self.epochs * (10_000 // self.batch_size)
|
|
75
|
+
|
|
76
|
+
# 1. Instantiate (validated instantly)
|
|
77
|
+
cfg = TrainingConfig()
|
|
78
|
+
|
|
79
|
+
# 2. Evolve (returns a new modified frozen instance, IDE autocomplete works perfectly!)
|
|
80
|
+
fast_cfg = cfg.evolve(epochs=5, learning_rate=5e-3)
|
|
81
|
+
|
|
82
|
+
# Computed fields naturally update based on the new instance values
|
|
83
|
+
print(fast_cfg.total_steps)
|
|
84
|
+
|
|
85
|
+
# 3. Save it to disk (JSON, TOML, YAML supported out-of-the-box)
|
|
86
|
+
fast_cfg.save("experiment.toml")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Sweeps
|
|
90
|
+
|
|
91
|
+
Native support for generating massive, reproducible configuration variants.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from canopee.sweep import Sweep, log_uniform, choice
|
|
95
|
+
|
|
96
|
+
def train(cfg: TrainingConfig) -> float:
|
|
97
|
+
# return accuracy metric here
|
|
98
|
+
return 0.95
|
|
99
|
+
|
|
100
|
+
best_cfg = (
|
|
101
|
+
Sweep(TrainingConfig())
|
|
102
|
+
.vary("learning_rate", log_uniform(1e-5, 1e-1))
|
|
103
|
+
.vary("batch_size", choice(32, 64, 128))
|
|
104
|
+
.strategy("random", n_samples=20, seed=42)
|
|
105
|
+
.run(train)
|
|
106
|
+
.best(minimize=False)
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 📖 Documentation
|
|
111
|
+
|
|
112
|
+
The full documentation—including Guides on advanced `ConfigStore` registries and `cli/env` Source merging—can be generated by running:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uv run zensical serve
|
|
116
|
+
```
|
canopee-0.0.2/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1>🌲 Canopee</h1>
|
|
3
|
+
<p><strong>A type-safe, fluent configuration library for Python 3.11+.</strong></p>
|
|
4
|
+
<p>
|
|
5
|
+
<a href="https://pypi.org/project/canopee/"><img src="https://img.shields.io/pypi/v/canopee.svg" alt="PyPI version"></a>
|
|
6
|
+
<a href="https://pypi.org/project/canopee/"><img src="https://img.shields.io/pypi/pyversions/canopee.svg" alt="Python versions"></a>
|
|
7
|
+
<a href="https://github.com/canopee-py/canopee/actions"><img src="https://img.shields.io/github/actions/workflow/status/canopee-py/canopee/ci.yml?branch=main" alt="CI Status"></a>
|
|
8
|
+
</p>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
**Canopee** is a production-ready configuration library that treats Python as the ultimate config DSL.
|
|
14
|
+
|
|
15
|
+
Built on top of Pydantic v2, it removes the brittleness of YAMLs, silent mutation footguns, and metaclass magic, giving you IDE autocomplete, instant validation, and elegant hyperparameter sweeping out of the box.
|
|
16
|
+
|
|
17
|
+
## 🌟 Why Canopee?
|
|
18
|
+
|
|
19
|
+
* **Always Valid**: Configs are validated precisely at construction. No runtime surprises.
|
|
20
|
+
* **Immutable**: `ConfigBase` objects are `frozen=True`. They can be hashed, cached, and safely passed across threads.
|
|
21
|
+
* **Type-Safe Evolution**: Evolve new variants purely with Python keywords via the `.evolve(**kwargs)` method.
|
|
22
|
+
* **First-Class Sweeps**: Define hyperparameter search spaces directly over your types, using strategies like *grid*, *random*, or *optuna*.
|
|
23
|
+
* **Symmetric I/O**: Naturally save and load instances via `.toml`, `.yaml`, or `.json` extensions natively, or inject CLI/Env overrides securely.
|
|
24
|
+
|
|
25
|
+
## 🚀 Quickstart
|
|
26
|
+
|
|
27
|
+
### Installation
|
|
28
|
+
```bash
|
|
29
|
+
pip install canopee
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Basic Usage
|
|
33
|
+
|
|
34
|
+
Subclass `ConfigBase` as you would any Pydantic model.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from canopee import ConfigBase
|
|
38
|
+
from pydantic import computed_field
|
|
39
|
+
|
|
40
|
+
class TrainingConfig(ConfigBase):
|
|
41
|
+
learning_rate: float = 1e-3
|
|
42
|
+
epochs: int = 20
|
|
43
|
+
batch_size: int = 128
|
|
44
|
+
|
|
45
|
+
@computed_field
|
|
46
|
+
@property
|
|
47
|
+
def total_steps(self) -> int:
|
|
48
|
+
return self.epochs * (10_000 // self.batch_size)
|
|
49
|
+
|
|
50
|
+
# 1. Instantiate (validated instantly)
|
|
51
|
+
cfg = TrainingConfig()
|
|
52
|
+
|
|
53
|
+
# 2. Evolve (returns a new modified frozen instance, IDE autocomplete works perfectly!)
|
|
54
|
+
fast_cfg = cfg.evolve(epochs=5, learning_rate=5e-3)
|
|
55
|
+
|
|
56
|
+
# Computed fields naturally update based on the new instance values
|
|
57
|
+
print(fast_cfg.total_steps)
|
|
58
|
+
|
|
59
|
+
# 3. Save it to disk (JSON, TOML, YAML supported out-of-the-box)
|
|
60
|
+
fast_cfg.save("experiment.toml")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Sweeps
|
|
64
|
+
|
|
65
|
+
Native support for generating massive, reproducible configuration variants.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from canopee.sweep import Sweep, log_uniform, choice
|
|
69
|
+
|
|
70
|
+
def train(cfg: TrainingConfig) -> float:
|
|
71
|
+
# return accuracy metric here
|
|
72
|
+
return 0.95
|
|
73
|
+
|
|
74
|
+
best_cfg = (
|
|
75
|
+
Sweep(TrainingConfig())
|
|
76
|
+
.vary("learning_rate", log_uniform(1e-5, 1e-1))
|
|
77
|
+
.vary("batch_size", choice(32, 64, 128))
|
|
78
|
+
.strategy("random", n_samples=20, seed=42)
|
|
79
|
+
.run(train)
|
|
80
|
+
.best(minimize=False)
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 📖 Documentation
|
|
85
|
+
|
|
86
|
+
The full documentation—including Guides on advanced `ConfigStore` registries and `cli/env` Source merging—can be generated by running:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv run zensical serve
|
|
90
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["uv_build>=0.10.8,<0.11.0"]
|
|
3
|
+
build-backend = "uv_build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "canopee"
|
|
7
|
+
version = "0.0.2"
|
|
8
|
+
description = "A type-safe python configuration library"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Alexandre Mayerowitz", email = "alexandre.mayerowitz@gmail.com" },
|
|
12
|
+
]
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
dependencies = ["pydantic>=2.12.5", "tomli-w>=1.2.0"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
25
|
+
"Topic :: Software Development :: Testing",
|
|
26
|
+
"Topic :: Software Development :: Libraries",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Repository = "https://github.com/mayeroa/canopee"
|
|
31
|
+
Homepage = "https://mayeroa.github.io/canopee/"
|
|
32
|
+
Documentation = "https://mayeroa.github.io/canopee/"
|
|
33
|
+
Issues = "https://github.com/mayeroa/canopee/issues"
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
click = ["click>=8.3.1"]
|
|
37
|
+
dev = [
|
|
38
|
+
"mkdocs-material>=9.7.4",
|
|
39
|
+
"pytest>=9.0.2",
|
|
40
|
+
"pytest-cov>=7.0.0",
|
|
41
|
+
"ruff>=0.15.4",
|
|
42
|
+
"zensical>=0.0.24",
|
|
43
|
+
]
|
|
44
|
+
ml = ["lightning>=2.6.1", "torch>=2.10.0", "torchvision>=0.25.0"]
|
|
45
|
+
typer = ["typer>=0.24.1"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint]
|
|
48
|
+
extend-select = [
|
|
49
|
+
"F", # Pyflakes rules
|
|
50
|
+
"W", # PyCodeStyle warnings
|
|
51
|
+
"E", # PyCodeStyle errors
|
|
52
|
+
"I", # Sort imports properly
|
|
53
|
+
"UP", # Warn if certain things can changed due to newer Python versions
|
|
54
|
+
"C4", # Catch incorrect use of comprehensions, dict, list, etc
|
|
55
|
+
"FA", # Enforce from __future__ import annotations
|
|
56
|
+
"ISC", # Good use of string concatenation
|
|
57
|
+
"ICN", # Use common import conventions
|
|
58
|
+
"RET", # Good return practices
|
|
59
|
+
"SIM", # Common simplification rules
|
|
60
|
+
"TID", # Some good import practices
|
|
61
|
+
"TC", # Enforce importing certain types in a TYPE_CHECKING block
|
|
62
|
+
"PTH", # Use pathlib instead of os.path
|
|
63
|
+
"TD", # Be diligent with TODO comments
|
|
64
|
+
"NPY", # Some numpy-specific things
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
[tool.pytest.ini_options]
|
|
69
|
+
addopts = "--maxfail=1 --cov=canopee"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
canopee
|
|
3
|
+
~~~~~~~
|
|
4
|
+
|
|
5
|
+
A type-safe, Pydantic-native configuration library with elegant
|
|
6
|
+
composition, immutable configs, and a powerful Sweep engine.
|
|
7
|
+
|
|
8
|
+
Quick start::
|
|
9
|
+
|
|
10
|
+
from canopee import ConfigBase
|
|
11
|
+
from pydantic import Field, computed_field
|
|
12
|
+
|
|
13
|
+
class TrainingConfig(ConfigBase):
|
|
14
|
+
lr: float = Field(default=1e-3, ge=0.0, le=1.0)
|
|
15
|
+
epochs: int = 10
|
|
16
|
+
|
|
17
|
+
@computed_field
|
|
18
|
+
@property
|
|
19
|
+
def warmup_steps(self) -> int:
|
|
20
|
+
return self.epochs * 100
|
|
21
|
+
|
|
22
|
+
cfg = TrainingConfig()
|
|
23
|
+
|
|
24
|
+
# Dict / dot-path override:
|
|
25
|
+
fast = cfg | {"lr": 1e-2, "epochs": 3}
|
|
26
|
+
|
|
27
|
+
# Typed keyword override:
|
|
28
|
+
fast = cfg.evolve(lr=1e-2, epochs=3)
|
|
29
|
+
|
|
30
|
+
# Save / load:
|
|
31
|
+
save(cfg, "run.toml")
|
|
32
|
+
cfg2 = load(TrainingConfig, "run.toml")
|
|
33
|
+
|
|
34
|
+
# String serialization:
|
|
35
|
+
text = dumps(cfg, "yaml")
|
|
36
|
+
cfg3 = loads(TrainingConfig, "yaml", text)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from canopee import sweep as sweep
|
|
40
|
+
from canopee.cli import clify, ArgparseBackend, ClickBackend, TyperBackend
|
|
41
|
+
from canopee.core import ConfigBase, diff, evolve, to_flat
|
|
42
|
+
from canopee.sources import (
|
|
43
|
+
CLISource,
|
|
44
|
+
DictSource,
|
|
45
|
+
EnvSource,
|
|
46
|
+
FileSource,
|
|
47
|
+
Source,
|
|
48
|
+
merge_sources,
|
|
49
|
+
)
|
|
50
|
+
from canopee.serialization import dumps, load, loads, save
|
|
51
|
+
from canopee.store import ConfigStore, global_store
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
"ConfigBase",
|
|
55
|
+
"ConfigStore",
|
|
56
|
+
"global_store",
|
|
57
|
+
"Source",
|
|
58
|
+
"EnvSource",
|
|
59
|
+
"CLISource",
|
|
60
|
+
"FileSource",
|
|
61
|
+
"DictSource",
|
|
62
|
+
"merge_sources",
|
|
63
|
+
"sweep",
|
|
64
|
+
"clify",
|
|
65
|
+
"ArgparseBackend",
|
|
66
|
+
"ClickBackend",
|
|
67
|
+
"TyperBackend",
|
|
68
|
+
"evolve",
|
|
69
|
+
"diff",
|
|
70
|
+
"to_flat",
|
|
71
|
+
"save",
|
|
72
|
+
"load",
|
|
73
|
+
"dumps",
|
|
74
|
+
"loads",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
__version__ = "0.1.0"
|