Custom Constraint Design
Principles of Custom Constraint Creation
Custom constraints allow developers to implement complex, domain-specific validation rules beyond standard type and range checks.
1. Function-Based Constraint Validators
def create_custom_validator(validation_func, error_message):
def validator(value):
if not validation_func(value):
raise ValueError(error_message)
return value
return validator
## Email validation example
def validate_email(email):
return '@' in email and '.' in email
email_validator = create_custom_validator(
validate_email,
"Invalid email format"
)
## Usage
try:
valid_email = email_validator("[email protected]")
print(f"Valid email: {valid_email}")
except ValueError as e:
print(e)
2. Constraint Composition
class ConstraintManager:
@staticmethod
def combine_constraints(*constraints):
def composed_validator(value):
for constraint in constraints:
constraint(value)
return value
return composed_validator
## Complex validation example
def length_constraint(min_length, max_length):
def validator(value):
if len(value) < min_length or len(value) > max_length:
raise ValueError(f"Length must be between {min_length} and {max_length}")
return value
return validator
def contains_digit(value):
if not any(char.isdigit() for char in value):
raise ValueError("Must contain at least one digit")
return value
## Composite password validator
password_validator = ConstraintManager.combine_constraints(
length_constraint(8, 20),
contains_digit
)
## Usage
try:
valid_password = password_validator("SecurePass123")
print("Password is valid")
except ValueError as e:
print(e)
3. Decorator-Based Custom Constraints
def custom_constraint(validation_func, error_message=None):
def decorator(func):
def wrapper(*args, **kwargs):
## Validate input arguments
for arg in args:
if not validation_func(arg):
raise ValueError(error_message or f"Constraint violated for {arg}")
return func(*args, **kwargs)
return wrapper
return decorator
## Example usage
def is_positive(x):
return x > 0
@custom_constraint(is_positive, "Only positive numbers allowed")
def calculate_area(radius):
return 3.14 * radius ** 2
## Demonstration
try:
print(calculate_area(5)) ## Valid
print(calculate_area(-2)) ## Raises error
except ValueError as e:
print(e)
Constraint Design Workflow
flowchart TD
A[Define Constraint Logic] --> B[Create Validation Function]
B --> C{Validate Input}
C --> |Pass| D[Execute Function]
C --> |Fail| E[Raise Specific Error]
Custom Constraint Strategies
Strategy |
Use Case |
Complexity |
Flexibility |
Function Validators |
Simple checks |
Low |
Medium |
Decorator Constraints |
Method-level validation |
Medium |
High |
Composition Approach |
Complex, multi-step validation |
High |
Very High |
Advanced Constraint Techniques
Context-Aware Validation
class BusinessRuleValidator:
@staticmethod
def validate_transaction(amount, account_balance):
if amount > account_balance:
raise ValueError("Insufficient funds")
if amount < 0:
raise ValueError("Negative transaction not allowed")
return True
## Usage
try:
BusinessRuleValidator.validate_transaction(100, 500)
print("Transaction approved")
except ValueError as e:
print(e)
LabEx Validation Insights
At LabEx, we emphasize creating flexible, reusable constraint designs that can adapt to complex validation requirements while maintaining clean, readable code.