Ensure
Ensure is a Python library offering a set of simple, literate assertion helpers for validating conditions. It allows writing expressive, concise, and readable Pythonic code for validation, inspired by JavaScript assertion libraries. Beyond testing, 'ensure' can be used for production code validation as it doesn't rely on the 'assert' statement (which can be disabled with the -O flag). The current version is 1.0.4, and it is actively maintained.
Warnings
- gotcha When using `ensure_annotations` with multiprocessing, you might encounter `PicklingError` due to issues with pickling decorated functions. This is a known limitation when dealing with annotation enforcement across process boundaries.
- gotcha Unlike Python's built-in `assert` statement, `ensure` is designed to be production-safe and will not have its checks disabled when Python is run with the `-O` (optimization) flag. If you intend for checks to be removable in optimized builds, `ensure` is not the right tool for those specific checks.
- breaking Older versions (pre-0.8.1) of `ensure` had compatibility issues with the `collections.abc` module due to changes in Python's standard library, particularly impacting type checking for abstract base classes. This could lead to `ImportError` or unexpected behavior.
- gotcha Python 3.12 deprecated `unittest.TestCase.assertRaisesRegexp` in favor of `unittest.TestCase.assertRaisesRegex`. Although `ensure` updated its internal usage in v1.0.4, older versions of `ensure` might experience compatibility issues or warnings when run with Python 3.12, particularly in tests that internally rely on the `unittest` module's regex assertion methods.
Install
-
pip install ensure
Imports
- ensure
from ensure import ensure
- check
from ensure import check
- ensure_annotations
from ensure import ensure_annotations
Quickstart
from ensure import ensure, check
# Basic assertions
ensure(1).is_an(int)
ensure("hello").is_a(str).has_length(5)
ensure([1, 2, 3]).contains(1).and_also.does_not_contain(4)
# Chained assertions
ensure({"a": 1, "b": 2}).has_key("a").whose_value.is_an(int)
# Function call assertions
ensure(int).called_with("1100101", base=2).returns(101)
ensure(dict).called_with(1, 2).raises(TypeError)
# Using 'check' for custom exception handling
try:
check(1).is_a(float).or_raise(ValueError, "Value must be a float, got {value}")
except ValueError as e:
print(f"Caught expected error: {e}")
# Type annotation enforcement (Python 3)
from ensure import ensure_annotations, EnsureError
@ensure_annotations
def add_numbers(a: int, b: int) -> int:
return a + b
print(f"2 + 3 = {add_numbers(2, 3)}")
# This would typically raise an EnsureError
try:
add_numbers("2", 3)
except EnsureError as e:
print(f"Caught expected annotation error: {e}")