Generic validation decorators.
Project description
Generic Validation For Python
Checking the input arguments of a function is a common task. It allows the software designer to stop the flow of execution if an error occured and to display information detailing the error.
Python provides decorators that can be used to add extra
functionality to a function. The package gvalidate
provides the function validate
that
can be used to easily create argument validating decorators
while avoiding most of the
required boilerplate.
Installation
To install the package gvalidate
use the command:
$ pip install gvalidate
Usage
This section demonstrates how to use the function validate
to define validation decorators.
1. Generic Validation Decorators
The example below shows how to define a decorator that will validate
the arguments of the decorated function and
raise an exception of type ValueError
if any argument does not pass validation.
The most important ingredient is the function provided as validator
.
This function must accept one argument (the one
being validated) and return a boolean.
If it returns False
validation fails.
The function validate
is generic in the sense that we
can pass any function with the required signature as a validator.
In the example shown below all arguments of the function box_dimensions
are validated using a lambda function.
from gvalidate.generic_validators import validate
@validate(validator = lambda x: x > 0,
message='Dimensions must be positive.' # Optional, default: ''
error_type=ValueError, # Optional, default: ValueError
enable_warnings=True, # Optional, default: True
)
def box_dimensions(length, height, width):
pass
To validate only certain
function arguments these must
be passed as a tuple via the parameter argument_names
.
In the example below only the arguments length
and height
are
validated.
from gvalidate.generic_validators import validate
@validate(validator = lambda x: x > 0,
argument_names = ('length', 'height'),
message='Dimensions must be positive.' # Optional, default: ''
error_type=ValueError, # Optional, default: ValueError
enable_warnings=True, # Optional, default: True
)
def box_dimensions_2(length, height, width):
pass
Note: To validate a single argument one a string containing the argument name may
specified via the parameter argument_names
.
Calling the function box_dimensions
with negative arguments
causes an exception to be raised:
box_dimensions(-1, 10, 20)
# ... stack trace will be printed here
ValueError: ('Invalid argument in function box_dimensions: length = -10.'
'Dimensions must be positive.')
The argument message
passed to the decorator is appended to the
message attached to the exception. In the example above message
was:
'Dimensions must be positive'.
2. Concrete Validation Decorators
In the example above, we defined a validating decorator on the spot
using the generic method validate
.
To reuse a validating decorator one may define a separate function.
In the example below the decorator validate_callable
checks if the
specified arguments are callable.
def validate_callable(argument_names: tuple = (), enable_warnings=True):
'''
Raises an exception if any argument in `argument_names` is not callable.
'''
return validate(
validator=lambda input: callable(input),
argument_names = (),
message='Must be callable.',
enable_warnings=enable_warnings,
)
# Using the decorator defined above.
@validate_callable('callback')
def function_with_a_callback(id: int, callback: callable):
pass
Ready made validation decorators can be found in the modules:
function_validators
numerical_validators
string_validators
3. Disabling Warnings
Any invalid argument name listed in the tuple argument_names
will be silently ignored if enable_warnings
is explicitly set to False
.
Consider the function below:
from gvalidate.generic_validators import validate
@validate(argument_names = ('aeg',),
validator = lambda x: x > 0,
message='Age must be positive.',
enable_warnings=False
)
def person_data(age, name):
pass
Calling the function with the arguments: person_data(age = -10, name = 'Anna')
will pass validation since the argument name aeg
specified
in the decorator does not exist.
Nested Validators
Several decorators performing validation may be applied to the same function. In that case, validation starts with the top-most decorator. Stacking decorators allows fine grained validation.
In the example below, we check that length
is positive and callback
is callable:
@gv.validate_positive('length')
@gv.validate_callable('callback')
def g(length, callback):
'''
Used to test nested validation decorators.
'''
pass
Note: Stacked decorators are in fact nested decorators. To allow
access to the signature of the decorated
function from within nested decorators
functools.wraps
was used. For more details check out the implementation of validate
.
Testing
To run the tests clone the project source code available at
gvalidate
using the command:
$ git clone https://github.com/simphotonics/gvalidate.git
The command above will create a directory called gvalidate
.
It is recommended to create a separate environment before proceeding.
Then navigate to the directory gvalidate
and use the commands:
$ make init
$ make test
The first command will install pytest
and the local package
gvalidate
. The second command
will run the unit tests located in the directory tests
.
Contributing
Contributions are welcome. To add validators that are useful to you or other users please create a pull request or request to be added as a collaborator.
The following steps should be considered when creating a pull request:
-
Add validators to existing modules for example
string_validators
or alternatively create a new module. -
Document the added functions. Add a doc entry to the top of the module. Add a doc entry to
__init__.py
if a new module was added. Consider adding documentation toREADME.md
. -
Add tests to unit test the added functions.
Features and bugs
Please file feature requests and bugs at the issue tracker.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file gvalidate-0.0.1.tar.gz
.
File metadata
- Download URL: gvalidate-0.0.1.tar.gz
- Upload date:
- Size: 9.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.0 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bf13306627952c2d99dec67a35fcf247fdbd3180d3d75dd76e9f2fb17be849cd |
|
MD5 | c8dc9d054bc4ca3abae9e0b81d193bba |
|
BLAKE2b-256 | 7ef0c2ba9b87a94af41950bc1a86e2a2d209295658535d7a965578fa4dc6ea37 |
File details
Details for the file gvalidate-0.0.1-py3-none-any.whl
.
File metadata
- Download URL: gvalidate-0.0.1-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.7.0 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1ddfcfae93fd819b3c9f8e3ac1d09b908891de47fef3cf4ef606947369b93a29 |
|
MD5 | 0caca2e534986e1710a9b46a4943d3e0 |
|
BLAKE2b-256 | 5df019c0432bc3b11efa5c515bf6f6756bc5aba8945936d50d80a66aae55ff65 |