No project description provided
Project description
pynsure
[!TIP] [pin-sure] (like insure 😄)
Predicate-based runtime constraint validator for Python
Check it out
Just use type hints and a decorator to verify parameter constraints at runtime.
from pynsure import validate, Unsigned
@validate()
def add_two(a: Unsigned, b: int) -> int:
return a + b
add_two(3, 4) # OK
add_two(-2, 4) # BAD
Make your own types using typing.Annotated
!
from pynsure import validate
from typing import Annotated
Odd = Annotated[int, (lambda _v: _v & 1 == 1, "{} must be odd but its value is {{}}")]
@validate()
def add_two(a: Odd, b: Odd):
return a + b
add_two(3, 5) # OK
add_two(4, 5) # BAD
[!Note]
{}
is replaced with the parameter name and{{}}
is replaced by the parameter value automatically when aValidationError
is raised.
You can even specify multiple predicates for your Annotated types:
from pynsure import validate
from typing import Annotated
PositiveAndOdd = Annotated[
int,
(lambda _v: _v & 1 == 1, "{} must be odd but its value is {{}}"),
(lambda _v: _v > 0, "{} must be greater than 0 but its value is {{}}"),
]
@validate()
def add_two(a: PositiveAndOdd, b: PositiveAndOdd) -> int:
return a + b
add_two(7, 9) # OK
add_two(-7, 9) # BAD
add_two(7, 8) # BAD
Only Annotated types following this form are validated:
MyType = Annotated[<base_type>, (<predicate>, <message>), <...>]
where ...
can be more predicate + message tuples
"Why not use asserts?"
Valid point.
Basically, pynsure
makes it easier for users of your functions to understand
the exact constraints surrounding a parameter (or return value). You can make
and document your constraints and have them runtime-validated in just a few
easy steps.
If my function expects four positive numbers, it's a whole lot easier to annotate like this:
@validate()
def add_four(a: Unsigned, b: Unsigned, c: Unsigned, d: Unsigned) -> Unsigned:
return a + b + c + d
...than it is to do this:
def add_four(a, b, c, d):
assert isinstance(a, int) and a >= 0, "a should be greater than or equal to 0"
assert isinstance(b, int) and b >= 0, "b should be greater than or equal to 0"
assert isinstance(c, int) and c >= 0, "c should be greater than or equal to 0"
assert isinstance(d, int) and d >= 0, "d should be greater than or equal to 0"
return
...plus pynsure
will validate return types and return value constraints at
runtime too! if add_four()
doesn't return an integer greater than or equal to
0, a ValidationError
will be raised.
"Why not use pydantic"
Great point.
pydantic
is awesome (and battle-tested) but is a bit clunky if you want to do
basic constraints and don't necessarily need giant serializable objects that
you can convert from json to a dict and a whole bunch of other fancy stuff.
You have a function that expects non-empty strings? pynsure
makes this a
breeze. Let's compare:
Using pynsure
from pynsure import validate
from typing import Annotated
NonEmptyStr = Annotated[str, (lambda _s: len(_s) > 0, "{} shouldn't be empty")]
@validate()
def format_name(first_name: NonEmptyStr, last_name: NonEmptyStr) -> NonEmptyStr:
return f"{last_name}, {first_name}"
format_name(first_name="Bob", last_name="Smith")
Using pydantic
from pydantic import BaseModel, constr
class NonEmptyStr(BaseModel):
string: constr(min_length=1)
def format_name(first_name: NonEmptyStr, last_name: NonEmptyStr) -> str:
return f"{last_name}, {first_name}"
format_name(first_name=NonEmptyStr(string="Bob"), last_name=NonEmptyStr(string="Smith"))
This is fine but a bit clunky having to fiddle around with BaseModels.
Conclusion
Ultimately, use whatever you want, this isn't some new standard and you'll
probably get better mileage from pydantic
(as far as runtime validation is
concerned). But, if you want to set some quick and easy constraints on your
methods, give pynsure
a shot.
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 pynsure-0.1.0.tar.gz
.
File metadata
- Download URL: pynsure-0.1.0.tar.gz
- Upload date:
- Size: 3.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.8 Linux/6.2.0-1016-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ffb82f89bbc98a25bcaeaf7e4af24bba6b6b2fa4bfbde6d9a596a8ea9c0ce115 |
|
MD5 | 501780f7acb4db942e63eff699f10eaf |
|
BLAKE2b-256 | 80f0b39310cef863641dbafd92f98cca347f506cc07070096e34ce44249269eb |
File details
Details for the file pynsure-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: pynsure-0.1.0-py3-none-any.whl
- Upload date:
- Size: 3.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.8 Linux/6.2.0-1016-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2ee0c328472945236b3162b543616b07044a6556266208249cc72bfbec8a7f82 |
|
MD5 | 16fc638a9e847f88511524d07f962748 |
|
BLAKE2b-256 | 6c4c3ef95303fc49016a8c39eb2c8db8bd4129213516f04b1cc5c492ff6f40ff |