Base class to work with integer value.
"""
+ _orig_value: int
_value: int
+ def __init__(self, source_value: Any, object_path: str = "/") -> None:
+ super().__init__(source_value, object_path)
+ if isinstance(source_value, int) and not isinstance(source_value, bool):
+ self._orig_value = source_value
+ self._value = source_value
+ else:
+ raise ValueError(
+ f"Unexpected value for '{type(self)}'."
+ f" Expected integer, got '{source_value}' with type '{type(source_value)}'",
+ object_path,
+ )
+
def __int__(self) -> int:
return self._value
def __str__(self) -> str:
return str(self._value)
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
+
def __eq__(self, o: object) -> bool:
return isinstance(o, IntBase) and o._value == self._value
def serialize(self) -> Any:
- return self._value
+ return self._orig_value
@classmethod
def json_schema(cls: Type["IntBase"]) -> Dict[Any, Any]:
Base class to work with string value.
"""
+ _orig_value: str
_value: str
+ def __init__(self, source_value: Any, object_path: str = "/") -> None:
+ super().__init__(source_value, object_path)
+ if isinstance(source_value, (str, int)) and not isinstance(source_value, bool):
+ self._orig_value = str(source_value)
+ self._value = str(source_value)
+ else:
+ raise ValueError(
+ f"Unexpected value for '{type(self)}'."
+ f" Expected string, got '{source_value}' with type '{type(source_value)}'",
+ object_path,
+ )
+
def __int__(self) -> int:
raise ValueError("Can't convert string to an integer.")
def __str__(self) -> str:
return self._value
- def to_std(self) -> str:
- return self._value
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
def __hash__(self) -> int:
return hash(self._value)
return isinstance(o, StrBase) and o._value == self._value
def serialize(self) -> Any:
- return self._value
+ return self._orig_value
@classmethod
def json_schema(cls: Type["StrBase"]) -> Dict[Any, Any]:
_max: int
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, int) and not isinstance(source_value, bool):
- if hasattr(self, "_min") and (source_value < self._min):
- raise ValueError(f"value {source_value} is lower than the minimum {self._min}.")
- if hasattr(self, "_max") and (source_value > self._max):
- raise ValueError(f"value {source_value} is higher than the maximum {self._max}")
- self._value = source_value
- else:
- raise ValueError(
- f"expected integer, got '{type(source_value)}'",
- object_path,
- )
+ super().__init__(source_value, object_path)
+ if hasattr(self, "_min") and (self._value < self._min):
+ raise ValueError(f"value {self._value} is lower than the minimum {self._min}.", object_path)
+ if hasattr(self, "_max") and (self._value > self._max):
+ raise ValueError(f"value {self._value} is higher than the maximum {self._max}", object_path)
@classmethod
def json_schema(cls: Type["IntRangeBase"]) -> Dict[Any, Any]:
_re: Pattern[str]
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, str):
- if type(self)._re.match(source_value):
- self._value: str = source_value
- else:
- raise ValueError(f"'{source_value}' does not match '{self._re.pattern}' pattern")
- else:
- raise ValueError(
- f"expected string, got '{type(source_value)}'",
- object_path,
- )
+ super().__init__(source_value, object_path)
+ if not type(self)._re.match(self._value):
+ raise ValueError(f"'{self._value}' does not match '{self._re.pattern}' pattern", object_path)
@classmethod
def json_schema(cls: Type["PatternBase"]) -> Dict[Any, Any]:
return {"type": "string", "pattern": rf"{cls._re.pattern}"}
-class UnitBase(IntBase):
+class UnitBase(StrBase):
"""
Base class to work with string value that match regex pattern.
Just inherit the class and set '_units'.
_re: Pattern[str]
_units: Dict[str, int]
- _value_orig: str
+ _base_value: int
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
+ super().__init__(source_value, object_path)
+
type(self)._re = re.compile(rf"^(\d+)({r'|'.join(type(self)._units.keys())})$")
- if isinstance(source_value, str) and self._re.match(source_value):
- self._value_orig = source_value
- grouped = self._re.search(source_value)
- if grouped:
- val, unit = grouped.groups()
- if unit is None:
- raise ValueError(f"Missing units. Accepted units are {list(type(self)._units.keys())}")
- elif unit not in type(self)._units:
- raise ValueError(
- f"Used unexpected unit '{unit}' for {type(self).__name__}."
- f" Accepted units are {list(type(self)._units.keys())}",
- object_path,
- )
- self._value = int(val) * type(self)._units[unit]
- else:
- raise ValueError(f"{type(self._value)} Failed to convert: {self}")
- elif source_value in (0, "0"):
- self._value_orig = source_value
- self._value = int(source_value)
- elif isinstance(source_value, int):
- raise ValueError(
- f"number without units, please convert to string and add unit - {list(type(self)._units.keys())}",
- object_path,
- )
+ grouped = self._re.search(self._value)
+ if grouped:
+ val, unit = grouped.groups()
+ if unit is None:
+ raise ValueError(f"Missing units. Accepted units are {list(type(self)._units.keys())}", object_path)
+ elif unit not in type(self)._units:
+ raise ValueError(
+ f"Used unexpected unit '{unit}' for {type(self).__name__}."
+ f" Accepted units are {list(type(self)._units.keys())}",
+ object_path,
+ )
+ self._base_value = int(val) * type(self)._units[unit]
else:
raise ValueError(
- f"expected number with units in a string, got '{type(source_value)}'.",
+ f"Unexpected value for '{type(self)}'."
+ " Expected string that matches pattern " + rf"'{type(self)._re.pattern}'."
+ f" Positive integer and one of the units {list(type(self)._units.keys())}, got '{source_value}'.",
object_path,
)
- def __str__(self) -> str:
- """
- Used by Jinja2. Must return only a number.
- """
- return str(self._value_orig)
+ def __int__(self) -> int:
+ return self._base_value
def __repr__(self) -> str:
- return f"Unit[{type(self).__name__},{self._value_orig}]"
+ return f"Unit[{type(self).__name__},{self._value}]"
def __eq__(self, o: object) -> bool:
"""
return isinstance(o, UnitBase) and o._value == self._value
def serialize(self) -> Any:
- return self._value_orig
+ return self._orig_value
@classmethod
def json_schema(cls: Type["UnitBase"]) -> Dict[Any, Any]:
_units = {"B": 1, "K": 1024, "M": 1024**2, "G": 1024**3}
def bytes(self) -> int:
- return self._value
+ return self._base_value
def mbytes(self) -> int:
- return self._value // 1024**2
+ return self._base_value // 1024**2
class TimeUnit(UnitBase):
_units = {"us": 1, "ms": 10**3, "s": 10**6, "m": 60 * 10**6, "h": 3600 * 10**6, "d": 24 * 3600 * 10**6}
def seconds(self) -> int:
- return self._value // 1000**2
+ return self._base_value // 1000**2
def millis(self) -> int:
- return self._value // 1000
+ return self._base_value // 1000
def micros(self) -> int:
- return self._value
+ return self._base_value
class DomainName(StrBase):
)
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, str):
- try:
- punycode = source_value.encode("idna").decode("utf-8") if source_value != "." else "."
- except ValueError:
- raise ValueError(
- f"conversion of '{source_value}' to IDN punycode representation failed",
- object_path,
- )
-
- if type(self)._re.match(punycode):
- self._value = source_value
- self._punycode = punycode
- else:
- raise ValueError(
- f"'{source_value}' represented in punycode '{punycode}' does not match '{self._re.pattern}' pattern",
- object_path,
- )
+ super().__init__(source_value, object_path)
+ try:
+ punycode = self._value.encode("idna").decode("utf-8") if self._value != "." else "."
+ except ValueError:
+ raise ValueError(
+ f"conversion of '{self._value}' to IDN punycode representation failed",
+ object_path,
+ )
+
+ if type(self)._re.match(punycode):
+ self._punycode = punycode
else:
raise ValueError(
- "Unexpected value for '<domain-name>'."
- f" Expected string, got '{source_value}' with type '{type(source_value)}'",
+ f"'{source_value}' represented in punycode '{punycode}' does not match '{self._re.pattern}' pattern",
object_path,
)
class InterfaceName(PatternBase):
+ """
+ Network interface name.
+ """
+
_re = re.compile(r"^[a-zA-Z0-9]+(?:[-_][a-zA-Z0-9]+)*$")
port: PortNumber
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, str):
- parts = source_value.split("@")
- if len(parts) == 2:
+ super().__init__(source_value, object_path)
+
+ parts = self._value.split("@")
+ if len(parts) == 2:
+ try:
+ self.addr = ipaddress.ip_address(parts[0])
+ except ValueError as e1:
try:
- self.addr = ipaddress.ip_address(parts[0])
- except ValueError as e1:
- try:
- self.if_name = InterfaceName(parts[0])
- except ValueError as e2:
- raise ValueError(f"expected IP address or interface name, got '{parts[0]}'.") from e1 and e2
- self.port = PortNumber.from_str(parts[1], object_path)
- else:
- raise ValueError(f"expected '<ip-address|interface-name>@<port>', got '{source_value}'.")
- self._value = source_value
+ self.if_name = InterfaceName(parts[0])
+ except ValueError as e2:
+ raise ValueError(
+ f"expected IP address or interface name, got '{parts[0]}'.", object_path
+ ) from e1 and e2
+ self.port = PortNumber.from_str(parts[1], object_path)
else:
- raise ValueError(
- "Unexpected value for '<ip-address|interface-name>@<port>'."
- f" Expected string, got '{source_value}' with type '{type(source_value)}'",
- object_path,
- )
+ raise ValueError(f"expected '<ip-address|interface-name>@<port>', got '{source_value}'.", object_path)
class InterfaceOptionalPort(StrBase):
port: Optional[PortNumber] = None
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, str):
- parts = source_value.split("@")
- if 0 < len(parts) < 3:
+ super().__init__(source_value, object_path)
+
+ parts = self._value.split("@")
+ if 0 < len(parts) < 3:
+ try:
+ self.addr = ipaddress.ip_address(parts[0])
+ except ValueError as e1:
try:
- self.addr = ipaddress.ip_address(parts[0])
- except ValueError as e1:
- try:
- self.if_name = InterfaceName(parts[0])
- except ValueError as e2:
- raise ValueError(f"expected IP address or interface name, got '{parts[0]}'.") from e1 and e2
- if len(parts) == 2:
- self.port = PortNumber.from_str(parts[1], object_path)
- else:
- raise ValueError(f"expected '<ip-address|interface-name>[@<port>]', got '{parts}'.")
- self._value = source_value
+ self.if_name = InterfaceName(parts[0])
+ except ValueError as e2:
+ raise ValueError(
+ f"expected IP address or interface name, got '{parts[0]}'.", object_path
+ ) from e1 and e2
+ if len(parts) == 2:
+ self.port = PortNumber.from_str(parts[1], object_path)
else:
- raise ValueError(
- "Unexpected value for '<ip-address|interface-name>[@<port>]'."
- f" Expected string, got '{source_value}' with type '{type(source_value)}'",
- object_path,
- )
+ raise ValueError(f"expected '<ip-address|interface-name>[@<port>]', got '{parts}'.", object_path)
class IPAddressPort(StrBase):
port: PortNumber
def __init__(self, source_value: Any, object_path: str = "/") -> None:
- super().__init__(source_value)
- if isinstance(source_value, str):
- parts = source_value.split("@")
- if len(parts) == 2:
- self.port = PortNumber.from_str(parts[1], object_path)
- try:
- self.addr = ipaddress.ip_address(parts[0])
- except ValueError as e:
- raise ValueError(f"failed to parse IP address '{parts[0]}'.") from e
- else:
- raise ValueError(f"expected '<ip-address>@<port>', got '{source_value}'.")
- self._value = source_value
+ super().__init__(source_value, object_path)
+
+ parts = self._value.split("@")
+ if len(parts) == 2:
+ self.port = PortNumber.from_str(parts[1], object_path)
+ try:
+ self.addr = ipaddress.ip_address(parts[0])
+ except ValueError as e:
+ raise ValueError(f"failed to parse IP address '{parts[0]}'.", object_path) from e
else:
- raise ValueError(
- "Unexpected value for '<ip-address>@<port>'."
- f" Expected string, got '{source_value}' with type '{type(source_value)}'"
- )
+ raise ValueError(f"expected '<ip-address>@<port>', got '{source_value}'.", object_path)
class IPAddressOptionalPort(StrBase):
def __init__(self, source_value: Any, object_path: str = "/") -> None:
super().__init__(source_value)
- if isinstance(source_value, str):
- parts = source_value.split("@")
- if 0 < len(parts) < 3:
- try:
- self.addr = ipaddress.ip_address(parts[0])
- except ValueError as e:
- raise ValueError(f"failed to parse IP address '{parts[0]}'.") from e
- if len(parts) == 2:
- self.port = PortNumber.from_str(parts[1], object_path)
- else:
- raise ValueError(f"expected '<ip-address>[@<port>]', got '{parts}'.")
- self._value = source_value
+ parts = source_value.split("@")
+ if 0 < len(parts) < 3:
+ try:
+ self.addr = ipaddress.ip_address(parts[0])
+ except ValueError as e:
+ raise ValueError(f"failed to parse IP address '{parts[0]}'.", object_path) from e
+ if len(parts) == 2:
+ self.port = PortNumber.from_str(parts[1], object_path)
else:
- raise ValueError(
- "Unexpected value for a '<ip-address>[@<port>]'."
- f" Expected string, got '{source_value}' with type '{type(source_value)}'",
- object_path,
- )
+ raise ValueError(f"expected '<ip-address>[@<port>]', got '{parts}'.", object_path)
class IPv4Address(BaseValueType):
def __int__(self) -> int:
raise ValueError("Can't convert IPv4 address to an integer")
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
+
def __eq__(self, o: object) -> bool:
"""
Two instances of IPv4Address are equal when they represent same IPv4 address as string.
def __int__(self) -> int:
raise ValueError("Can't convert IPv6 address to an integer")
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
+
def __eq__(self, o: object) -> bool:
"""
Two instances of IPv6Address are equal when they represent same IPv6 address as string.
f" Expected string, got '{source_value}' with type '{type(source_value)}'"
)
- def to_std(self) -> Union[ipaddress.IPv4Network, ipaddress.IPv6Network]:
- return self._value
+ def __int__(self) -> int:
+ raise ValueError("Can't convert network prefix to an integer")
def __str__(self) -> str:
return self._value.with_prefixlen
- def __int__(self) -> int:
- raise ValueError("Can't convert network prefix to an integer")
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
+
+ def to_std(self) -> Union[ipaddress.IPv4Network, ipaddress.IPv6Network]:
+ return self._value
def serialize(self) -> Any:
return self._value.with_prefixlen
def __int__(self) -> int:
raise ValueError("Can't convert network prefix to an integer")
+ def __repr__(self) -> str:
+ return f'{type(self).__name__}("{self._value}")'
+
def __eq__(self, o: object) -> bool:
return isinstance(o, IPv6Network) and o._value == self._value