Source code for baguette.converters

import abc
import math
import typing


class Converter(abc.ABC):
    @abc.abstractproperty
    def REGEX(self) -> str:
        ...

    @abc.abstractmethod
    def convert(self, string: str):
        ...


[docs]class StringConverter(Converter): """Converter for string URL parameters. Arguments --------- length : Optional :class:`int` Required length of the string. Default: ``None`` allow_slash : Optional :class:`bool` Allow slashes in the string. Default: ``False`` Attributes ---------- length : Optional :class:`int` Required length of the string. allow_slash : :class:`bool` Allow slashes in the string. REGEX : :class:`str` Regex for the route :meth:`~baguette.router.Route.build_regex`. """ REGEX = r"[^\/]+" def __init__( self, length: typing.Optional[int] = None, allow_slash: bool = False, ): self.length = length self.allow_slash = allow_slash if self.allow_slash: self.REGEX = r".+"
[docs] def convert(self, string: str): """Converts the string of the URL parameter and validates the value. Arguments --------- string : :class:`str` URL parameter to convert. Returns ------- :class:`str` Converted URL parameter. Raises ------ ValueError :attr:`length` is specified and the URL parameter has a different length than :attr:`length`. ValueError :attr:`allow_slash` is ``False`` and the URL parameter contains slashes. """ if self.length is not None and len(string) != self.length: raise ValueError( f"Expected string of length {self.length}. Got {len(string)}" ) if not self.allow_slash and "/" in string: raise ValueError(f"Expected string without '/'. Got {string!r}") return str(string)
[docs]class PathConverter(Converter): """Converter for string URL parameters. Arguments --------- allow_empty : Optional :class:`bool` Whether to allow empty paths. Default: ``False`` Attributes ---------- allow_empty : :class:`bool` Whether to allow empty paths. REGEX : :class:`str` Regex for the route :meth:`~baguette.router.Route.build_regex`. """ REGEX = r".+" def __init__(self, allow_empty: bool = False): self.allow_empty = allow_empty if self.allow_empty: self.REGEX = r".*"
[docs] def convert(self, string: str): """Converts the string of the URL parameter and validates the value. Arguments --------- string : :class:`str` URL parameter to convert. Returns ------- :class:`str` Converted URL parameter. Raises ------ ValueError :attr:`allow_empty` is ``True`` and the path is empty. """ if not self.allow_empty and string == "": raise ValueError("Path cannot be empty") return string.strip("/")
[docs]class IntegerConverter(Converter): """Converter for integer URL parameters. Arguments --------- signed : Optional :class:`bool` Whether to accept integers starting with ``+`` or ``-``. Default: ``False`` min : Optional :class:`int` Minimum value of the integer. Default: ``None`` max : Optional :class:`int` Maximum value of the integer. Default: ``None`` Attributes ---------- signed : :class:`bool` Whether to accept integers starting with ``+`` or ``-``. min : Optional :class:`int` Minimum value of the integer. max : Optional :class:`int` Maximum value of the integer. REGEX : :class:`str` Regex for the route :meth:`~baguette.router.Route.build_regex`. """ REGEX = r"[\+-]?\d+" def __init__( self, signed: bool = False, min: typing.Optional[int] = None, max: typing.Optional[int] = None, ): self.signed = signed self.min = min self.max = max
[docs] def convert(self, string: str): """Converts the string of the URL parameter and validates the value. Arguments --------- string : :class:`str` URL parameter to convert. Returns ------- :class:`int` Converted URL parameter. Raises ------ ValueError :attr:`signed` is ``False`` and the URL parameter starts with ``+`` or ``-``. ValueError Couldn't convert the URL parameter to an integer. ValueError :attr:`min` is specified and the URL parameter is lower then :attr:`min`. ValueError :attr:`max` is specified and the URL parameter is higher then :attr:`max`. """ if not self.signed and (string.strip()[0] in "+-"): raise ValueError( "Expected unsigned integer. Got integer starting with " + string.strip()[0] ) integer = int(string) if self.min is not None and integer < self.min: raise ValueError(f"Expected integer higher than {self.min}") if self.max is not None and integer > self.max: raise ValueError(f"Expected integer lower than {self.max}") return integer
[docs]class FloatConverter(Converter): """Converter for float URL parameters. Arguments --------- signed : Optional :class:`bool` Whether to accept floats starting with ``+`` or ``-``. Default: ``False`` min : Optional :class:`float` Minimum value of the float. Default: ``None`` max : Optional :class:`float` Maximum value of the float. Default: ``None`` allow_infinity : Optional :class:`bool` Whether to accept floats that are ``inf`` or ``-inf``. Default: ``False`` allow_nan : Optional :class:`bool` Whether to accept floats that are ``NaN``. Default: ``False`` Attributes ---------- signed : :class:`bool` Whether to accept floats starting with ``+`` or ``-``. min : Optional :class:`float` Minimum value of the float. max : Optional :class:`float` Maximum value of the float. allow_infinity : :class:`bool` Whether to accept floats that are ``inf`` or ``-inf``. allow_nan : :class:`bool` Whether to accept floats that are ``NaN``. REGEX : :class:`str` Regex for the route :meth:`~baguette.router.Route.build_regex`. """ REGEX = r"[\+-]?\d*\.?\d*" def __init__( self, signed: bool = False, min: typing.Optional[float] = None, max: typing.Optional[float] = None, allow_infinity: bool = False, allow_nan: bool = False, ): self.signed = signed self.min = min self.max = max self.allow_infinity = allow_infinity self.allow_nan = allow_nan
[docs] def convert(self, string: str): """Converts the string of the URL parameter and validates the value. Arguments --------- string : :class:`str` URL parameter to convert. Returns ------- :class:`float` Converted URL parameter. Raises ------ ValueError :attr:`signed` is ``False`` and the URL parameter starts with ``+`` or ``-``. ValueError Couldn't convert the URL parameter to an float. ValueError :attr:`min` is specified and the URL parameter is lower then :attr:`min`. ValueError :attr:`max` is specified and the URL parameter is higher then :attr:`max`. ValueError :attr:`allow_infinity` is ``False`` and the URL parameter is ``inf`` or ``-inf``. ValueError :attr:`allow_nan` is ``False`` and the URL parameter is ``nan``. """ if not self.signed and (string.strip()[0] in "+-"): raise ValueError( "Expected unsigned float. Got float starting with " + string.strip()[0] ) number = float(string) if self.min is not None and number < self.min: raise ValueError(f"Expected float higher than {self.min}") if self.max is not None and number > self.max: raise ValueError(f"Expected float lower than {self.max}") if not self.allow_infinity and math.isinf(number): raise ValueError(f"Expected a non-infinity value. Got {number}") if not self.allow_nan and math.isnan(number): raise ValueError(f"Expected a non-NaN value. Got {number}") return number