https://github.com/oodesigns/constrained-values
A Python library for creating type-safe, self-validating value objects using a powerful transformation and validation pipeline.
https://github.com/oodesigns/constrained-values
constrained-enum constrained-range constrained-value constraint-programming python validated-enum validated-range validated-value validation validation-library validator value-object
Last synced: 22 days ago
JSON representation
A Python library for creating type-safe, self-validating value objects using a powerful transformation and validation pipeline.
- Host: GitHub
- URL: https://github.com/oodesigns/constrained-values
- Owner: OODesigns
- License: mit
- Created: 2025-09-15T06:47:16.000Z (7 months ago)
- Default Branch: master
- Last Pushed: 2025-10-29T08:18:30.000Z (5 months ago)
- Last Synced: 2025-11-28T15:46:30.804Z (4 months ago)
- Topics: constrained-enum, constrained-range, constrained-value, constraint-programming, python, validated-enum, validated-range, validated-value, validation, validation-library, validator, value-object
- Language: Python
- Homepage:
- Size: 181 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://OODesigns.github.io/constrained-values/constrained_values.html)
[](https://github.com/OODesigns/constrained-values/actions)
[](https://pypi.org/project/constrained-values/)

[](https://opensource.org/licenses/MIT)
## Constrained Values
A lightweight Python library for **creating type-safe, self-validating value objects** โ transforming primitive data into meaningful, domain-aware objects with rich validation and transformation pipelines.
---
## ๐งญ Philosophy: Beyond Primitive Types
In most codebases, we pass around raw values without context:
- Is `temperature = 25` Celsius or Fahrenheit?
- Is `spi_mode = 2` valid for this device?
- What does `-32768` mean again?
Primitive values lack **meaning**, **constraints**, and **domain intent**.
This is *Primitive Obsession* โ a subtle but pervasive design smell.
**Constrained Values** replaces primitives with expressive, validated objects that make **validity explicit**.
Each object carries its **status** (`OK` or `EXCEPTION`) and associated errors.
By default, invalid values can exist safely and report their state โ but if you want to enforce strict invariants, you can enable **exception mode** to raise immediately on invalid input.
๐ [**Full Documentation โ**](https://oodesigns.github.io/constrained-values/constrained_values.html#the-philosophy-beyond-primitive-types)
---
## โจ Features
- ๐งฉ **Rich Value Objects** โ Replace primitives with expressive, validated domain objects.
- ๐ **Composable Pipelines** โ Chain multiple validation and transformation strategies.
- ๐ง **Built-in Validators** โ Range checks, enums, type coercion, and more.
- โ๏ธ **Custom Logic** โ Easily extend with your own domain-specific rules.
- ๐ฆ **Clear Error Handling** โ Track validation status and descriptive messages.
- ๐งฏ **Strict/Exception Mode (optional)** โ By default, invalid values are reported non-destructively; enable strict mode to raise exceptions and enforce invariants at creation.
- ๐งพ **Type-Safety** โ Each value enforces its canonical type at runtime.
---
## ๐ Installation
```bash
pip install constrained-values
```
## ๐ก Quick Example
```python
from constrained_values import RangeValue
class Temperature(RangeValue):
"""Temperature constrained between 0 and 100ยฐC."""
def __init__(self, value):
super().__init__(value, low_value=0, high_value=100)
def main() -> None:
# โ
Valid temperature
t = Temperature(42)
print("Value:", t.value) # 42
print("Status:", t.status.name) # OK
print("Details:", t.details) # validation successful
# ๐ซ Invalid temperature
t_invalid = Temperature(120)
print("Value:", t_invalid.value) # None
print("Status:", t_invalid.status) # Status.EXCEPTION
print("Details:", t_invalid.details) # Value must be less than or equal to 100, got 120
if __name__ == "__main__":
main()
```
## ๐ฅ Strict version
If you want the behavior where invalid input throws immediately, use the StrictValue mixin:
```python
class StrictTemperature(RangeValue, StrictValue):
"""Same range constraint but raises if invalid."""
def __init__(self, value):
RangeValue.__init__(self, value, low_value=0, high_value=100)
def main() -> None:
t = StrictTemperature(42)
print("Value:", t.value) # 42
try:
StrictTemperature(120)
except ValueError as e:
print(e) # Failed Constraints for value - '120': Value must be less than or equal to 100, got 120
if __name__ == "__main__":
main()
```