Source code for typedpy.fields.numbers
from decimal import Decimal
from typedpy.structures import ImmutableField, Field
from typedpy.commons import wrap_val
[docs]class Number(Field):
"""
Base class for numerical fields. Based on Json schema draft4.
Accepts and int or float.
Arguments:
multipleOf(int): optional
The number must be a multiple of this number
minimum(int or float): optional
value cannot be lower than this number
maximum(int or float): optional
value cannot be higher than this number
exclusiveMaximum(bool): optional
marks the maximum threshold above as exclusive
"""
def __init__(
self,
*args,
multiplesOf=None,
minimum=None,
maximum=None,
exclusiveMaximum=None,
**kwargs,
):
self.multiplesOf = multiplesOf
self.minimum = minimum
self.maximum = maximum
self.exclusiveMaximum = exclusiveMaximum
super().__init__(*args, **kwargs)
def _validate_static(self, value):
def is_number(val):
return isinstance(val, (float, int, Decimal))
def err_prefix():
return f"{self._name}: Got {wrap_val(value)}; " if self._name else ""
if not is_number(value):
raise TypeError(f"{err_prefix()}Expected a number")
if (
isinstance(self.multiplesOf, float)
and int(value / self.multiplesOf) != value / self.multiplesOf
or isinstance(self.multiplesOf, int)
and value % self.multiplesOf
):
raise ValueError(
f"{err_prefix()}Expected a a multiple of {self.multiplesOf}"
)
if (is_number(self.minimum)) and self.minimum > value:
raise ValueError(f"{err_prefix()}Expected a minimum of {self.minimum}")
if is_number(self.maximum):
if self.exclusiveMaximum and self.maximum == value:
raise ValueError(
f"{err_prefix()}Expected a maximum of less than {self.maximum}"
)
if self.maximum < value:
raise ValueError(f"{err_prefix()}Expected a maximum of {self.maximum}")
def _validate(self, value):
Number._validate_static(self, value)
def __set__(self, instance, value):
if not getattr(instance, "_skip_validation", False) and not getattr(
instance, "_trust_supplied_values", False
):
self._validate(value)
super().__set__(instance, value)
[docs]class Positive(Number):
"""
An extension of :class:`Number`. Requires the number to be positive
"""
def __set__(self, instance, value):
if value <= 0:
raise ValueError(f"{self._name}: Got {value}; Expected a positive number")
super().__set__(instance, value)
[docs]class NonPositive(Number):
"""
An extension of :class:`Number`. Requires the number to be negative or 0
"""
def __set__(self, instance, value):
if value > 0:
raise ValueError(
f"{self._name}: Got {value}; Expected a negative number or 0"
)
super().__set__(instance, value)
[docs]class Negative(Number):
"""
An extension of :class:`Number`. Requires the number to be negative
"""
def __set__(self, instance, value):
if value >= 0:
raise ValueError(f"{self._name}: Got {value}; Expected a negative number")
super().__set__(instance, value)
[docs]class NonNegative(Number):
"""
An extension of :class:`Number`. Requires the number to be positive or 0
"""
def __set__(self, instance, value):
if value < 0:
raise ValueError(
f"{self._name}: Got {value}; Expected a positive number or 0"
)
super().__set__(instance, value)
[docs]class ImmutableNumber(ImmutableField, Number):
"""
An immutable version of :class:`Number`
"""
pass