diff --git a/README.md b/README.md index e0a782f..b72f8f6 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Logo -

parasite v0.1

+

parasite v0.1.9

zod inspired library for Python 3.11+ @@ -116,19 +116,20 @@ Name Stmts Miss Cover ---------------------------------------------- src/parasite/__init__.py 22 0 100% src/parasite/_const.py 17 0 100% +src/parasite/_utils.py 7 0 100% src/parasite/any.py 27 0 100% src/parasite/array.py 70 0 100% src/parasite/boolean.py 72 0 100% src/parasite/errors.py 1 0 100% src/parasite/never.py 18 0 100% src/parasite/null.py 29 0 100% -src/parasite/number.py 105 0 100% +src/parasite/number.py 106 0 100% src/parasite/object.py 93 0 100% src/parasite/string.py 207 0 100% src/parasite/type.py 29 0 100% src/parasite/variant.py 61 0 100% ---------------------------------------------- -TOTAL 751 0 100% +TOTAL 759 0 100% ``` diff --git a/pyproject.toml b/pyproject.toml index 27a834d..6505c0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -134,3 +134,4 @@ select = [ # flake8-simplify "SIM", ] +ignore = ["UP007", "UP035"] diff --git a/src/parasite/_utils.py b/src/parasite/_utils.py new file mode 100644 index 0000000..f3d7216 --- /dev/null +++ b/src/parasite/_utils.py @@ -0,0 +1,21 @@ +from typing import Optional, TypeVar, Callable + +T = TypeVar("T") +U = TypeVar("U") + + +def map_optional(func: Callable[[T], U], value: Optional[T]) -> Optional[U]: + """ + Calls the mapping function on the value, if it is not None. + + Args: + func (callable[[T], U]): mapping function + value (Optional[T]): value to map + + Returns: + Optional[U]: mapped value + """ + if value is None: + return value + + return func(value) diff --git a/src/parasite/number.py b/src/parasite/number.py index b1e6d07..7d30a06 100644 --- a/src/parasite/number.py +++ b/src/parasite/number.py @@ -11,6 +11,7 @@ # -- Package Imports -- from parasite.errors import ValidationError from parasite.type import ParasiteType, _NotFound +from parasite._utils import map_optional K = TypeVar("K") """Template type for the key in a dictionary.""" @@ -254,21 +255,24 @@ def _parse(self, obj: Numerical) -> Numerical: """ # cast to integer, if required if self._f_integer: - self._m_ll = int(self._m_ll) if self._m_ll is not None else None - self._m_ul = int(self._m_ul) if self._m_ul is not None else None + self._m_ll = map_optional(int, self._m_ll) + self._m_ul = map_optional(int, self._m_ul) + # validate upper limit values and guard clauses if self._f_lt and obj >= self._m_ul: raise ValidationError(f"object has to be < '{self._m_ul}', but is {obj!r}") elif self._f_lte and obj > self._m_ul: raise ValidationError(f"object has to be =<'{self._m_ul}', but is {obj!r}") + # validate lower limit values and guard clauses if self._f_gt and obj <= self._m_ll: raise ValidationError(f"object has to be > '{self._m_ll}', but is {obj!r}") elif self._f_gte and obj < self._m_ll: raise ValidationError(f"object has to be >='{self._m_ll}', but is {obj!r}") + # return the parsed value return obj def parse(self, obj: Any) -> Numerical: diff --git a/tests/test_00_parasite/test_04_number.py b/tests/test_00_parasite/test_04_number.py index 13ab833..09739c6 100644 --- a/tests/test_00_parasite/test_04_number.py +++ b/tests/test_00_parasite/test_04_number.py @@ -62,12 +62,20 @@ def test_number_gt() -> None: assert p.number().gt(1).parse_safe(1).is_err() assert p.number().gt(1).parse_safe(0).is_err() + assert p.number().integer().gt(1).parse_safe(2) == Ok(2) + assert p.number().integer().gt(1).parse_safe(1).is_err() + assert p.number().integer().gt(1).parse_safe(0).is_err() + def test_number_gte() -> None: assert p.number().gte(1).parse_safe(2) == Ok(2) assert p.number().gte(1).parse_safe(1) == Ok(1) assert p.number().gte(1).parse_safe(0).is_err() + assert p.number().integer().gte(1).parse_safe(2) == Ok(2) + assert p.number().integer().gte(1).parse_safe(1) == Ok(1) + assert p.number().integer().gte(1).parse_safe(0).is_err() + def test_number_positive() -> None: assert p.number().positive().parse_safe(1) == Ok(1) @@ -92,12 +100,20 @@ def test_number_lt() -> None: assert p.number().lt(1).parse_safe(1).is_err() assert p.number().lt(1).parse_safe(2).is_err() + assert p.number().integer().lt(1).parse_safe(0) == Ok(0) + assert p.number().integer().lt(1).parse_safe(1).is_err() + assert p.number().integer().lt(1).parse_safe(2).is_err() + def test_number_lte() -> None: assert p.number().lte(1).parse_safe(0) == Ok(0) assert p.number().lte(1).parse_safe(1) == Ok(1) assert p.number().lte(1).parse_safe(2).is_err() + assert p.number().integer().lte(1).parse_safe(0) == Ok(0) + assert p.number().integer().lte(1).parse_safe(1) == Ok(1) + assert p.number().integer().lte(1).parse_safe(2).is_err() + def test_number_negative() -> None: assert p.number().negative().parse_safe(-1) == Ok(-1)