Validators
Collection of functions to specifies wich validations you want
require_params()
Signature
def require_params(*expected_params: str | tuple[str, *tuple[type, ...]]) -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function has the required parameters. Take parameter names as strings or tuples composed of the parameter names and the expected types. Type requirement is done by parsing the type hint, so it's not type-safe.
Parameters
*expected_params: Parameter names as strings or tuples composed of the parameter names and the expected types
Raises
TypeErrorif arguments are not str or not (str, type, ..., type)DecoratorUsageValidationErrorif the decorated decorator is not used correctly.
Example use
@validate_decorated(require_params("x", "y"))
def my_decorator(func): return func
@my_decorator
def correct_usage(x, y): pass
@my_decorator
def bad_usage(x): pass # Will raise an DecoratorUsageValidationError
###
@validate_decorated(require_params(("x", int, float), ("y", str)))
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(x: int | float, y: str, z: float): pass # Has all of the required params
@deco_factory("test")
def bad_usage(x: int, y: str, z: float): pass # Will raise an DecoratorUsageValidationError
require_at_least_n_params()
Signature
def require_at_least_n_params(n: int, *expected_params: str | tuple[str, *tuple[type, ...]]) -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function has at least n required parameters. Take parameter names as strings or tuples composed of the parameter names and the expected types. Type requirement is done by parsing the type hint, so it's not type-safe.
Parameters
n: Minimum number of required parameters that must be present*expected_params: Parameter names as strings or tuples composed of the parameter names and the expected types
Raises
TypeErrorifnis not a positive integer or if arguments are not str or not (str, type, ..., type)DecoratorUsageValidationErrorif the decorated decorator is not used correctly.
Example use
@validate_decorated(require_at_least_n_params(2, "x", "y", "z"))
def my_decorator(func): return func
@my_decorator
def correct_usage(x, y): pass # Has 2 of the required params
@my_decorator
def also_correct(x, y, z): pass # Has all 3 params
@my_decorator
def bad_usage(x): pass # Will raise an DecoratorUsageValidationError (only 1 param)
###
@validate_decorated(require_at_least_n_params(1, ("x", int, float), ("y", str), ("z", bool)))
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(x: int | float, w: str): pass # Has x (int) which satisfies the requirement
@deco_factory("test")
def bad_usage(w: str): pass # Will raise an DecoratorUsageValidationError (no matching params)
no_params()
Signature
def no_params() -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function takes no parameters (except self for methods).
This validator checks that the function signature has no required or optional parameters.
The self parameter is automatically ignored to allow usage with methods.
Raises
DecoratorUsageValidationErrorif the decorated function has any parameters (other thanself).
Example use
@validate_decorated(no_params())
def my_decorator(func): return func
@my_decorator
def correct_usage(): pass # No parameters - OK
@my_decorator
def method(self): pass # Only 'self' parameter - OK for methods
@my_decorator
def bad_usage(x): pass # Will raise a DecoratorUsageValidationError
###
@validate_decorated(no_params())
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(): pass # No parameters - OK
@deco_factory("test")
def bad_usage(x, y): pass # Will raise a DecoratorUsageValidationError
no_optional_params()
Signature
def no_optional_params() -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function has no optional parameters (except self for methods).
This validator checks that all function parameters are required (no default values).
The self parameter is automatically ignored to allow usage with methods.
Raises
DecoratorUsageValidationErrorif the decorated function has any optional parameters (parameters with default values).
Example use
@validate_decorated(no_optional_params())
def my_decorator(func): return func
@my_decorator
def correct_usage(x, y): pass # All parameters are required - OK
@my_decorator
def method(self, x, y): pass # Only 'self' parameter - OK for methods
@my_decorator
def also_correct(): pass # No parameters at all - OK
@my_decorator
def bad_usage(x, y=10): pass # Will raise a DecoratorUsageValidationError
###
@validate_decorated(no_optional_params())
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(x, y, z): pass # All parameters are required - OK
@deco_factory("test")
def bad_usage(x, y=10, z="hello"): pass # Will raise a DecoratorUsageValidationError
has_return()
Signature
def has_return() -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function has a return type annotation and contains at least one return statement that is not 'return None'. This validator checks that the function signature includes a return type annotation and that the function body contains meaningful return statements.
Raises
DecoratorUsageValidationErrorif the decorated function does not have a return type annotation or does not contain at least one meaningful return statement (not 'return None' or empty return).
Example use
@validate_decorated(has_return())
def my_decorator(func): return func
@my_decorator
def correct_usage() -> int: return 42 # Has return annotation - OK
@my_decorator
def bad_usage(): # Will raise a DecoratorUsageValidationError
return "no annotation"
@my_decorator
def also_bad() -> int: # Will raise a DecoratorUsageValidationError
return None
@my_decorator
def another_bad() -> str: # Will raise a DecoratorUsageValidationError
if True:
return # Empty return
else:
return None
###
@validate_decorated(has_return())
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage() -> str: return "hello" # Has return annotation - OK
@deco_factory("test")
def bad_usage(): # Will raise a DecoratorUsageValidationError
pass
@deco_factory("test")
def also_bad() -> int: # Will raise a DecoratorUsageValidationError
return None
no_return()
Signature
def no_return() -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Ensure that the decorated function has no return type annotation and contains no meaningful return statements. This validator checks that the function signature has no return type annotation and that the function body contains no meaningful return statements.
Raises
DecoratorUsageValidationErrorif the decorated function has a return type annotation or contains at least one meaningful return statement.
Example use
@validate_decorated(no_return())
def my_decorator(func): return func
@my_decorator
def correct_usage(): pass # No return annotation - OK
@my_decorator
def also_correct(): # OK - returns None
return None
@my_decorator
def another_correct(): # OK - empty return
if True:
return
print("hello")
@my_decorator
def bad_usage() -> int: # Will raise a DecoratorUsageValidationError
pass
@my_decorator
def also_bad(): # Will raise a DecoratorUsageValidationError
return 42
###
@validate_decorated(no_return())
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(): pass # No return annotation - OK
@deco_factory("test")
def bad_usage() -> str: # Will raise a DecoratorUsageValidationError
return "hello"
@deco_factory("test")
def also_bad(): # Will raise a DecoratorUsageValidationError
return 42
custom_validator()
Signature
def custom_validator(validation_func: Callable[[Callable[..., Any]], bool], error_message: str = "does not meet custom validation requirements") -> Callable[[Callable[..., Any], Any], Callable[..., Any]]
Description
Allow users to define their own validation logic using a custom function. The validation function should take the decorated function as input and return True if valid, False otherwise.
Parameters
validation_func: A function that takes the decorated function and returns True if valid, False if invaliderror_message: Custom error message to display when validation fails (optional)
Raises
TypeErrorifvalidation_funcis not callable orerror_messageis not a stringDecoratorUsageValidationErrorif the custom validation fails or if the validation function raises an exception
Example use
def check_name_starts_with_test(func):
return func.__name__.startswith("test_")
@validate_decorated(custom_validator(check_name_starts_with_test))
def my_decorator(func): return func
@my_decorator
def test_correct_usage(): pass # OK - name starts with 'test_'
@my_decorator
def bad_usage(): pass # Will raise a DecoratorUsageValidationError
###
def check_has_docstring(func):
return func.__doc__ is not None
@validate_decorated(custom_validator(check_has_docstring, "function must have a docstring"))
def my_decorator(func): return func
@my_decorator
def correct_usage():
"""This function has a docstring"""
pass
@my_decorator
def bad_usage(): pass # Will raise: "function must have a docstring"
###
def check_param_count_at_least(min_count):
def validator_func(func):
from inspect import signature
return len(signature(func).parameters) >= min_count
return validator_func
@validate_decorated(custom_validator(check_param_count_at_least(2), "function must have at least 2 parameters"))
def deco_factory(param):
def inner(f):
return f
return inner
@deco_factory("test")
def correct_usage(x, y): pass # OK - has 2 parameters
@deco_factory("test")
def bad_usage(x): pass # Will raise a DecoratorUsageValidationError