vtypes (original) (raw)
vtypes
- validating types¶
Validating types for python - use isinstance()
to validate both type and value.
vtypes
is a small library to define "validating types". These types can be used to add value validation on top of type checking anywhere where you usually rely on isinstance()
. This can in particular be used to make validation schemas simpler and more readable, for example used in pyfields.
Installing¶
Usage¶
a - basics¶
A VType
is a combination of :
- a type name, for example
'PositiveInt'
- one or several base types: for example
int
. When several are provided, they all should match ("and" combination). - one or several validators: for example
lambda x: x >= 0
A VType
is constructed using vtype(name, type, validators, ...)
. For example we can create a positive int:
from vtypes import vtype PositiveInt = vtype('PositiveInt', int, {'should be positive': lambda x: x >= 0})
A VType
's main purpose is to behave like a type (therefore to be compliant with isinstance
) and to validate both type and values at the same time when isinstance
is called:
assert isinstance(1, PositiveInt) assert not isinstance(-1, PositiveInt) # an int, but not >= 0
An alternate way to define a VType
is to define a python class inheriting from VType
.
- base types can be either provided as superclass, or in the
__type__
class attribute, - validators can be provided in the
__validators__
class attribute.
So the following two classes are equivalent to our previous PositiveInt
example:
`from vtypes import VType
type is provided in the ancestors
class PositiveInt(int, VType): validators = {'should be positive': lambda x: x >= 0}
type is provided in type
class PositiveInt2(VType): type = int validators = {'should be positive': lambda x: x >= 0} `
b - goodies¶
In addition to this primary feature, a VType
provides a few handy methods:
- detailed error messages with
validate
(note: a variable name should be provided, for example'size'
).
`>>> PositiveInt.validate('size', -1)
ValidationError[ValueError]: Error validating [size=-1]. InvalidValue: should be positive. Function [] returned [False] for value -1. `
- partial checkers:
has_valid_type
for type-only, andhas_valid_value
for value-only:
assert PositiveInt.has_valid_type(-1) # -1 is an int assert not PositiveInt.has_valid_value(-1) # -1 < 0
Finally, you may wish to use is_vtype
to check if anything is a VType
:
`from vtypes import is_vtype
assert is_vtype(PositiveInt) assert not is_vtype(int) assert not is_vtype(1) `
c - validators syntax¶
There are many ways to declare validators:
- a single callable
- a single tuple
(<callable>, <error_msg>)
,(<callable>, <failure_type>)
or(<callable>, <error_msg>, <failure_type>)
- a list of such callables and tuples
- a dictionary where keys are
<callable>
,<error_msg>
, or<failure_type>
and values are one or two (tuple) of such elements. This is at least for the author, the most intuitive and readable style:
ConstrainedInt = vtype('ConstrainedInt', int, {'should be positive': lambda x: x >= 0, 'should be a multiple of 3': lambda x: x % 3})
Note that this syntax is valid8 simple syntax.
If you wish to create even more compact callables, you may wish to look at mini_lambda.
d - composition¶
You can combine types, for example a nonempty string can be obtained by mixing NonEmpty
and str
.
- with the compact style: simply put the classes to combine in a tuple in the second
vtype
argument:
`NonEmpty = vtype('NonEmpty', (), {'should be non empty': lambda x: len(x) > 0}) """A VType describing non-empty containers, with strictly positive length."""
NonEmptyStr = vtype('NonEmptyStr', (NonEmpty, str), ()) """A VType for non-empty strings""" `
- with the class style: either use inheritance, or fill the
__type__
class attribute with a tuple
`class NonEmpty(VType): """A VType describing non-empty containers, with strictly positive length.""" validators = {'should be non empty': lambda x: len(x) > 0}
class NonEmptyStr(NonEmpty, str): """A VType for non-empty strings"""
class NonEmptyStr2(VType): """A VType for non-empty strings - alternate style""" type = NonEmpty, str `
All these behave as expected:
assert isinstance('hoho', NonEmptyStr) assert not isinstance('', NonEmptyStr) assert not isinstance(1, NonEmptyStr)
Main features¶
- Validate both type and value with
isinstance
, thanks to easy-to-write "validating types" has_valid_type
andhas_valid_value
methods provided for easy auditing, as well asis_vtype
- Validation syntax fully compliant with
valid8
. Compliant error message available through avalidate()
method - v-types are composable so that creating a library of reusable elements is straightforward (note: should we provide one in this library based on
valid8
library ?) - Two styles:
vtype(...)
constructor method, as well as an alternateclass ...(VType)
style to perform composition using inheritance, and write docstrings more easily.
See Also¶
- checktypes, that was a great source of inspiration. The only reason I ended up recreating something new a couple years after discovering it, was that I really wanted to leverage the
valid8
syntax for validators (as well as its standardized exceptions).
Do you like this library ? You might also like my other python libraries
Want to contribute ?¶
Details on the github page: https://github.com/smarie/python-vtypes