clevis 0.3.2__tar.gz → 0.3.3__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.3.2 → clevis-0.3.3}/CHANGELOG.md +18 -0
- {clevis-0.3.2 → clevis-0.3.3}/PKG-INFO +1 -1
- {clevis-0.3.2 → clevis-0.3.3}/pyproject.toml +1 -1
- {clevis-0.3.2 → clevis-0.3.3}/src/clevis/__init__.py +27 -7
- clevis-0.3.3/tests/test_advanced_types.py +752 -0
- clevis-0.3.3/tests/test_yoker_schema.py +579 -0
- {clevis-0.3.2 → clevis-0.3.3}/uv.lock +1 -1
- {clevis-0.3.2 → clevis-0.3.3}/.claude/settings.local.json +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/.github/workflows/test.yml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/.gitignore +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/.python-version +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/.readthedocs.yaml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/HISTORY.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/LICENSE +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/Makefile +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/PACKAGE.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/README.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/REQUIREMENTS.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/TODO.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/2026-05-30-api-review-p1-003.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/2026-06-05-api-review-p2-001-factory-pattern.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/2026-06-05-api-review-subcommand-enhancements.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/P2-002-security-parameter.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/api-cli-optional.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/edge-case-analysis.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/functional.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/analysis/security-P2-002.md +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/docs/api.rst +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/docs/conf.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/docs/index.rst +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/docs/installation.rst +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/docs/usage.rst +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/example_config_param.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/app1.toml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/commands.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/factory.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/main.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/nested-commands.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/nested.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/nested.toml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/examples/project.toml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/nested-commands.toml +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/src/clevis/__init__.pyi +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/src/clevis/py.typed +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_bug_regression.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_clevis.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_config_key.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_edge_cases.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_parser.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_security.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_subcommand_config.py +0 -0
- {clevis-0.3.2 → clevis-0.3.3}/tests/test_toctou_fix.py +0 -0
|
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## 0.3.3 (2026-06-07)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Support for `Literal["A", "B", "C"]` types with validation
|
|
12
|
+
- Support for container types: `list[T]`, `dict[K, V]`, `set[T]`, `tuple[T, ...]`
|
|
13
|
+
- Automatic conversion of TOML arrays to `tuple` and `set` types
|
|
14
|
+
- Support for nested dataclasses as dict values: `dict[str, DataclassType]`
|
|
15
|
+
- Compatibility with `frozen=True` dataclasses
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Enhanced `unpack_type()` to properly handle container types and Literal types
|
|
19
|
+
- Updated `from_dict()` to use `Config(cast=[tuple, set])` for automatic type casting
|
|
20
|
+
- Improved type hints with `Union` and `get_origin` imports
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- `unpack_type()` now correctly returns container types as-is instead of treating them as unions
|
|
24
|
+
- `unpack_type()` now correctly returns Literal types as-is for dacite validation
|
|
25
|
+
|
|
8
26
|
## 0.3.2 (2026-06-07)
|
|
9
27
|
|
|
10
28
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clevis
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Configuration management for Python projects with dataclass-based schemas
|
|
5
5
|
Project-URL: Homepage, https://github.com/christophevg/clevis
|
|
6
6
|
Project-URL: Documentation, https://clevis.readthedocs.io
|
|
@@ -21,12 +21,12 @@ from collections.abc import Callable
|
|
|
21
21
|
from dataclasses import Field, dataclass, field, fields, is_dataclass
|
|
22
22
|
from enum import Enum
|
|
23
23
|
from pathlib import Path
|
|
24
|
-
from typing import Any, Protocol, TypedDict, TypeVar, get_args
|
|
24
|
+
from typing import Any, Literal, Protocol, TypedDict, TypeVar, Union, get_args, get_origin
|
|
25
25
|
|
|
26
|
-
from dacite import from_dict
|
|
26
|
+
from dacite import Config, from_dict
|
|
27
27
|
from dacite.exceptions import DaciteError, MissingValueError, WrongTypeError
|
|
28
28
|
|
|
29
|
-
__version__ = "0.3.
|
|
29
|
+
__version__ = "0.3.3"
|
|
30
30
|
|
|
31
31
|
logger = logging.getLogger(__name__)
|
|
32
32
|
|
|
@@ -629,6 +629,8 @@ def unpack_type(type_def: type) -> type:
|
|
|
629
629
|
Given a type, if a union type, return the not-None type (dataclass).
|
|
630
630
|
|
|
631
631
|
For Optional[T] or T | None, returns T.
|
|
632
|
+
For container types (list, dict, set, tuple), returns as-is.
|
|
633
|
+
For Literal types, returns as-is.
|
|
632
634
|
For non-union types, returns the type as-is.
|
|
633
635
|
|
|
634
636
|
Args:
|
|
@@ -640,13 +642,30 @@ def unpack_type(type_def: type) -> type:
|
|
|
640
642
|
Raises:
|
|
641
643
|
ValueError: If union has more than 2 types (not supported yet)
|
|
642
644
|
"""
|
|
643
|
-
types
|
|
644
|
-
|
|
645
|
-
|
|
645
|
+
from types import UnionType
|
|
646
|
+
|
|
647
|
+
origin = get_origin(type_def)
|
|
648
|
+
|
|
649
|
+
# Handle container types (list, dict, set, tuple) - return as-is
|
|
650
|
+
if origin in (list, dict, set, tuple):
|
|
651
|
+
return type_def
|
|
652
|
+
|
|
653
|
+
# Handle Literal types - return as-is (dacite validates)
|
|
654
|
+
if origin is Literal:
|
|
646
655
|
return type_def
|
|
656
|
+
|
|
657
|
+
# Handle Union types (Optional[T] / T | None)
|
|
658
|
+
# Not a union type - return as-is
|
|
659
|
+
if origin is not Union and origin is not UnionType:
|
|
660
|
+
return type_def
|
|
661
|
+
|
|
662
|
+
types = get_args(type_def)
|
|
647
663
|
# <type> | None is only supported combination
|
|
664
|
+
if len(types) == 0:
|
|
665
|
+
return type_def # Not a generic/union
|
|
648
666
|
if len(types) > 2:
|
|
649
667
|
raise ValueError("Complex unions not supported")
|
|
668
|
+
# T | None or None | T
|
|
650
669
|
return types[0] if types[1] is type(None) else types[1] # type: ignore[no-any-return]
|
|
651
670
|
|
|
652
671
|
|
|
@@ -807,8 +826,9 @@ def get_config(
|
|
|
807
826
|
apply_to_dict(get_factory(clz).get_args(args), cfg)
|
|
808
827
|
|
|
809
828
|
# Convert dict to dataclass
|
|
829
|
+
# Use cast=[tuple, set] to convert TOML lists to tuples and sets
|
|
810
830
|
try:
|
|
811
|
-
return from_dict(data_class=clz, data=cfg)
|
|
831
|
+
return from_dict(data_class=clz, data=cfg, config=Config(cast=[tuple, set]))
|
|
812
832
|
except MissingValueError as e:
|
|
813
833
|
# Extract field path from dacite error message
|
|
814
834
|
# Format: 'missing value for field "database.host"'
|