Загрузить файлы в «venv/Lib/site-packages/pydantic/v1»
This commit is contained in:
161
venv/Lib/site-packages/pydantic/v1/error_wrappers.py
Normal file
161
venv/Lib/site-packages/pydantic/v1/error_wrappers.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import json
|
||||
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Sequence, Tuple, Type, Union
|
||||
|
||||
from pydantic.v1.json import pydantic_encoder
|
||||
from pydantic.v1.utils import Representation
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from pydantic.v1.config import BaseConfig
|
||||
from pydantic.v1.types import ModelOrDc
|
||||
from pydantic.v1.typing import ReprArgs
|
||||
|
||||
Loc = Tuple[Union[int, str], ...]
|
||||
|
||||
class _ErrorDictRequired(TypedDict):
|
||||
loc: Loc
|
||||
msg: str
|
||||
type: str
|
||||
|
||||
class ErrorDict(_ErrorDictRequired, total=False):
|
||||
ctx: Dict[str, Any]
|
||||
|
||||
|
||||
__all__ = 'ErrorWrapper', 'ValidationError'
|
||||
|
||||
|
||||
class ErrorWrapper(Representation):
|
||||
__slots__ = 'exc', '_loc'
|
||||
|
||||
def __init__(self, exc: Exception, loc: Union[str, 'Loc']) -> None:
|
||||
self.exc = exc
|
||||
self._loc = loc
|
||||
|
||||
def loc_tuple(self) -> 'Loc':
|
||||
if isinstance(self._loc, tuple):
|
||||
return self._loc
|
||||
else:
|
||||
return (self._loc,)
|
||||
|
||||
def __repr_args__(self) -> 'ReprArgs':
|
||||
return [('exc', self.exc), ('loc', self.loc_tuple())]
|
||||
|
||||
|
||||
# ErrorList is something like Union[List[Union[List[ErrorWrapper], ErrorWrapper]], ErrorWrapper]
|
||||
# but recursive, therefore just use:
|
||||
ErrorList = Union[Sequence[Any], ErrorWrapper]
|
||||
|
||||
|
||||
class ValidationError(Representation, ValueError):
|
||||
__slots__ = 'raw_errors', 'model', '_error_cache'
|
||||
|
||||
def __init__(self, errors: Sequence[ErrorList], model: 'ModelOrDc') -> None:
|
||||
self.raw_errors = errors
|
||||
self.model = model
|
||||
self._error_cache: Optional[List['ErrorDict']] = None
|
||||
|
||||
def errors(self) -> List['ErrorDict']:
|
||||
if self._error_cache is None:
|
||||
try:
|
||||
config = self.model.__config__ # type: ignore
|
||||
except AttributeError:
|
||||
config = self.model.__pydantic_model__.__config__ # type: ignore
|
||||
self._error_cache = list(flatten_errors(self.raw_errors, config))
|
||||
return self._error_cache
|
||||
|
||||
def json(self, *, indent: Union[None, int, str] = 2) -> str:
|
||||
return json.dumps(self.errors(), indent=indent, default=pydantic_encoder)
|
||||
|
||||
def __str__(self) -> str:
|
||||
errors = self.errors()
|
||||
no_errors = len(errors)
|
||||
return (
|
||||
f'{no_errors} validation error{"" if no_errors == 1 else "s"} for {self.model.__name__}\n'
|
||||
f'{display_errors(errors)}'
|
||||
)
|
||||
|
||||
def __repr_args__(self) -> 'ReprArgs':
|
||||
return [('model', self.model.__name__), ('errors', self.errors())]
|
||||
|
||||
|
||||
def display_errors(errors: List['ErrorDict']) -> str:
|
||||
return '\n'.join(f'{_display_error_loc(e)}\n {e["msg"]} ({_display_error_type_and_ctx(e)})' for e in errors)
|
||||
|
||||
|
||||
def _display_error_loc(error: 'ErrorDict') -> str:
|
||||
return ' -> '.join(str(e) for e in error['loc'])
|
||||
|
||||
|
||||
def _display_error_type_and_ctx(error: 'ErrorDict') -> str:
|
||||
t = 'type=' + error['type']
|
||||
ctx = error.get('ctx')
|
||||
if ctx:
|
||||
return t + ''.join(f'; {k}={v}' for k, v in ctx.items())
|
||||
else:
|
||||
return t
|
||||
|
||||
|
||||
def flatten_errors(
|
||||
errors: Sequence[Any], config: Type['BaseConfig'], loc: Optional['Loc'] = None
|
||||
) -> Generator['ErrorDict', None, None]:
|
||||
for error in errors:
|
||||
if isinstance(error, ErrorWrapper):
|
||||
if loc:
|
||||
error_loc = loc + error.loc_tuple()
|
||||
else:
|
||||
error_loc = error.loc_tuple()
|
||||
|
||||
if isinstance(error.exc, ValidationError):
|
||||
yield from flatten_errors(error.exc.raw_errors, config, error_loc)
|
||||
else:
|
||||
yield error_dict(error.exc, config, error_loc)
|
||||
elif isinstance(error, list):
|
||||
yield from flatten_errors(error, config, loc=loc)
|
||||
else:
|
||||
raise RuntimeError(f'Unknown error object: {error}')
|
||||
|
||||
|
||||
def error_dict(exc: Exception, config: Type['BaseConfig'], loc: 'Loc') -> 'ErrorDict':
|
||||
type_ = get_exc_type(exc.__class__)
|
||||
msg_template = config.error_msg_templates.get(type_) or getattr(exc, 'msg_template', None)
|
||||
ctx = exc.__dict__
|
||||
if msg_template:
|
||||
msg = msg_template.format(**ctx)
|
||||
else:
|
||||
msg = str(exc)
|
||||
|
||||
d: 'ErrorDict' = {'loc': loc, 'msg': msg, 'type': type_}
|
||||
|
||||
if ctx:
|
||||
d['ctx'] = ctx
|
||||
|
||||
return d
|
||||
|
||||
|
||||
_EXC_TYPE_CACHE: Dict[Type[Exception], str] = {}
|
||||
|
||||
|
||||
def get_exc_type(cls: Type[Exception]) -> str:
|
||||
# slightly more efficient than using lru_cache since we don't need to worry about the cache filling up
|
||||
try:
|
||||
return _EXC_TYPE_CACHE[cls]
|
||||
except KeyError:
|
||||
r = _get_exc_type(cls)
|
||||
_EXC_TYPE_CACHE[cls] = r
|
||||
return r
|
||||
|
||||
|
||||
def _get_exc_type(cls: Type[Exception]) -> str:
|
||||
if issubclass(cls, AssertionError):
|
||||
return 'assertion_error'
|
||||
|
||||
base_name = 'type_error' if issubclass(cls, TypeError) else 'value_error'
|
||||
if cls in (TypeError, ValueError):
|
||||
# just TypeError or ValueError, no extra code
|
||||
return base_name
|
||||
|
||||
# if it's not a TypeError or ValueError, we just take the lowercase of the exception name
|
||||
# no chaining or snake case logic, use "code" for more complex error types.
|
||||
code = getattr(cls, 'code', None) or cls.__name__.replace('Error', '').lower()
|
||||
return base_name + '.' + code
|
||||
646
venv/Lib/site-packages/pydantic/v1/errors.py
Normal file
646
venv/Lib/site-packages/pydantic/v1/errors.py
Normal file
@@ -0,0 +1,646 @@
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Callable, Sequence, Set, Tuple, Type, Union
|
||||
|
||||
from pydantic.v1.typing import display_as_type
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pydantic.v1.typing import DictStrAny
|
||||
|
||||
# explicitly state exports to avoid "from pydantic.v1.errors import *" also importing Decimal, Path etc.
|
||||
__all__ = (
|
||||
'PydanticTypeError',
|
||||
'PydanticValueError',
|
||||
'ConfigError',
|
||||
'MissingError',
|
||||
'ExtraError',
|
||||
'NoneIsNotAllowedError',
|
||||
'NoneIsAllowedError',
|
||||
'WrongConstantError',
|
||||
'NotNoneError',
|
||||
'BoolError',
|
||||
'BytesError',
|
||||
'DictError',
|
||||
'EmailError',
|
||||
'UrlError',
|
||||
'UrlSchemeError',
|
||||
'UrlSchemePermittedError',
|
||||
'UrlUserInfoError',
|
||||
'UrlHostError',
|
||||
'UrlHostTldError',
|
||||
'UrlPortError',
|
||||
'UrlExtraError',
|
||||
'EnumError',
|
||||
'IntEnumError',
|
||||
'EnumMemberError',
|
||||
'IntegerError',
|
||||
'FloatError',
|
||||
'PathError',
|
||||
'PathNotExistsError',
|
||||
'PathNotAFileError',
|
||||
'PathNotADirectoryError',
|
||||
'PyObjectError',
|
||||
'SequenceError',
|
||||
'ListError',
|
||||
'SetError',
|
||||
'FrozenSetError',
|
||||
'TupleError',
|
||||
'TupleLengthError',
|
||||
'ListMinLengthError',
|
||||
'ListMaxLengthError',
|
||||
'ListUniqueItemsError',
|
||||
'SetMinLengthError',
|
||||
'SetMaxLengthError',
|
||||
'FrozenSetMinLengthError',
|
||||
'FrozenSetMaxLengthError',
|
||||
'AnyStrMinLengthError',
|
||||
'AnyStrMaxLengthError',
|
||||
'StrError',
|
||||
'StrRegexError',
|
||||
'NumberNotGtError',
|
||||
'NumberNotGeError',
|
||||
'NumberNotLtError',
|
||||
'NumberNotLeError',
|
||||
'NumberNotMultipleError',
|
||||
'DecimalError',
|
||||
'DecimalIsNotFiniteError',
|
||||
'DecimalMaxDigitsError',
|
||||
'DecimalMaxPlacesError',
|
||||
'DecimalWholeDigitsError',
|
||||
'DateTimeError',
|
||||
'DateError',
|
||||
'DateNotInThePastError',
|
||||
'DateNotInTheFutureError',
|
||||
'TimeError',
|
||||
'DurationError',
|
||||
'HashableError',
|
||||
'UUIDError',
|
||||
'UUIDVersionError',
|
||||
'ArbitraryTypeError',
|
||||
'ClassError',
|
||||
'SubclassError',
|
||||
'JsonError',
|
||||
'JsonTypeError',
|
||||
'PatternError',
|
||||
'DataclassTypeError',
|
||||
'CallableError',
|
||||
'IPvAnyAddressError',
|
||||
'IPvAnyInterfaceError',
|
||||
'IPvAnyNetworkError',
|
||||
'IPv4AddressError',
|
||||
'IPv6AddressError',
|
||||
'IPv4NetworkError',
|
||||
'IPv6NetworkError',
|
||||
'IPv4InterfaceError',
|
||||
'IPv6InterfaceError',
|
||||
'ColorError',
|
||||
'StrictBoolError',
|
||||
'NotDigitError',
|
||||
'LuhnValidationError',
|
||||
'InvalidLengthForBrand',
|
||||
'InvalidByteSize',
|
||||
'InvalidByteSizeUnit',
|
||||
'MissingDiscriminator',
|
||||
'InvalidDiscriminator',
|
||||
)
|
||||
|
||||
|
||||
def cls_kwargs(cls: Type['PydanticErrorMixin'], ctx: 'DictStrAny') -> 'PydanticErrorMixin':
|
||||
"""
|
||||
For built-in exceptions like ValueError or TypeError, we need to implement
|
||||
__reduce__ to override the default behaviour (instead of __getstate__/__setstate__)
|
||||
By default pickle protocol 2 calls `cls.__new__(cls, *args)`.
|
||||
Since we only use kwargs, we need a little constructor to change that.
|
||||
Note: the callable can't be a lambda as pickle looks in the namespace to find it
|
||||
"""
|
||||
return cls(**ctx)
|
||||
|
||||
|
||||
class PydanticErrorMixin:
|
||||
code: str
|
||||
msg_template: str
|
||||
|
||||
def __init__(self, **ctx: Any) -> None:
|
||||
self.__dict__ = ctx
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.msg_template.format(**self.__dict__)
|
||||
|
||||
def __reduce__(self) -> Tuple[Callable[..., 'PydanticErrorMixin'], Tuple[Type['PydanticErrorMixin'], 'DictStrAny']]:
|
||||
return cls_kwargs, (self.__class__, self.__dict__)
|
||||
|
||||
|
||||
class PydanticTypeError(PydanticErrorMixin, TypeError):
|
||||
pass
|
||||
|
||||
|
||||
class PydanticValueError(PydanticErrorMixin, ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class ConfigError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class MissingError(PydanticValueError):
|
||||
msg_template = 'field required'
|
||||
|
||||
|
||||
class ExtraError(PydanticValueError):
|
||||
msg_template = 'extra fields not permitted'
|
||||
|
||||
|
||||
class NoneIsNotAllowedError(PydanticTypeError):
|
||||
code = 'none.not_allowed'
|
||||
msg_template = 'none is not an allowed value'
|
||||
|
||||
|
||||
class NoneIsAllowedError(PydanticTypeError):
|
||||
code = 'none.allowed'
|
||||
msg_template = 'value is not none'
|
||||
|
||||
|
||||
class WrongConstantError(PydanticValueError):
|
||||
code = 'const'
|
||||
|
||||
def __str__(self) -> str:
|
||||
permitted = ', '.join(repr(v) for v in self.permitted) # type: ignore
|
||||
return f'unexpected value; permitted: {permitted}'
|
||||
|
||||
|
||||
class NotNoneError(PydanticTypeError):
|
||||
code = 'not_none'
|
||||
msg_template = 'value is not None'
|
||||
|
||||
|
||||
class BoolError(PydanticTypeError):
|
||||
msg_template = 'value could not be parsed to a boolean'
|
||||
|
||||
|
||||
class BytesError(PydanticTypeError):
|
||||
msg_template = 'byte type expected'
|
||||
|
||||
|
||||
class DictError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid dict'
|
||||
|
||||
|
||||
class EmailError(PydanticValueError):
|
||||
msg_template = 'value is not a valid email address'
|
||||
|
||||
|
||||
class UrlError(PydanticValueError):
|
||||
code = 'url'
|
||||
|
||||
|
||||
class UrlSchemeError(UrlError):
|
||||
code = 'url.scheme'
|
||||
msg_template = 'invalid or missing URL scheme'
|
||||
|
||||
|
||||
class UrlSchemePermittedError(UrlError):
|
||||
code = 'url.scheme'
|
||||
msg_template = 'URL scheme not permitted'
|
||||
|
||||
def __init__(self, allowed_schemes: Set[str]):
|
||||
super().__init__(allowed_schemes=allowed_schemes)
|
||||
|
||||
|
||||
class UrlUserInfoError(UrlError):
|
||||
code = 'url.userinfo'
|
||||
msg_template = 'userinfo required in URL but missing'
|
||||
|
||||
|
||||
class UrlHostError(UrlError):
|
||||
code = 'url.host'
|
||||
msg_template = 'URL host invalid'
|
||||
|
||||
|
||||
class UrlHostTldError(UrlError):
|
||||
code = 'url.host'
|
||||
msg_template = 'URL host invalid, top level domain required'
|
||||
|
||||
|
||||
class UrlPortError(UrlError):
|
||||
code = 'url.port'
|
||||
msg_template = 'URL port invalid, port cannot exceed 65535'
|
||||
|
||||
|
||||
class UrlExtraError(UrlError):
|
||||
code = 'url.extra'
|
||||
msg_template = 'URL invalid, extra characters found after valid URL: {extra!r}'
|
||||
|
||||
|
||||
class EnumMemberError(PydanticTypeError):
|
||||
code = 'enum'
|
||||
|
||||
def __str__(self) -> str:
|
||||
permitted = ', '.join(repr(v.value) for v in self.enum_values) # type: ignore
|
||||
return f'value is not a valid enumeration member; permitted: {permitted}'
|
||||
|
||||
|
||||
class IntegerError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid integer'
|
||||
|
||||
|
||||
class FloatError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid float'
|
||||
|
||||
|
||||
class PathError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid path'
|
||||
|
||||
|
||||
class _PathValueError(PydanticValueError):
|
||||
def __init__(self, *, path: Path) -> None:
|
||||
super().__init__(path=str(path))
|
||||
|
||||
|
||||
class PathNotExistsError(_PathValueError):
|
||||
code = 'path.not_exists'
|
||||
msg_template = 'file or directory at path "{path}" does not exist'
|
||||
|
||||
|
||||
class PathNotAFileError(_PathValueError):
|
||||
code = 'path.not_a_file'
|
||||
msg_template = 'path "{path}" does not point to a file'
|
||||
|
||||
|
||||
class PathNotADirectoryError(_PathValueError):
|
||||
code = 'path.not_a_directory'
|
||||
msg_template = 'path "{path}" does not point to a directory'
|
||||
|
||||
|
||||
class PyObjectError(PydanticTypeError):
|
||||
msg_template = 'ensure this value contains valid import path or valid callable: {error_message}'
|
||||
|
||||
|
||||
class SequenceError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid sequence'
|
||||
|
||||
|
||||
class IterableError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid iterable'
|
||||
|
||||
|
||||
class ListError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid list'
|
||||
|
||||
|
||||
class SetError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid set'
|
||||
|
||||
|
||||
class FrozenSetError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid frozenset'
|
||||
|
||||
|
||||
class DequeError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid deque'
|
||||
|
||||
|
||||
class TupleError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid tuple'
|
||||
|
||||
|
||||
class TupleLengthError(PydanticValueError):
|
||||
code = 'tuple.length'
|
||||
msg_template = 'wrong tuple length {actual_length}, expected {expected_length}'
|
||||
|
||||
def __init__(self, *, actual_length: int, expected_length: int) -> None:
|
||||
super().__init__(actual_length=actual_length, expected_length=expected_length)
|
||||
|
||||
|
||||
class ListMinLengthError(PydanticValueError):
|
||||
code = 'list.min_items'
|
||||
msg_template = 'ensure this value has at least {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class ListMaxLengthError(PydanticValueError):
|
||||
code = 'list.max_items'
|
||||
msg_template = 'ensure this value has at most {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class ListUniqueItemsError(PydanticValueError):
|
||||
code = 'list.unique_items'
|
||||
msg_template = 'the list has duplicated items'
|
||||
|
||||
|
||||
class SetMinLengthError(PydanticValueError):
|
||||
code = 'set.min_items'
|
||||
msg_template = 'ensure this value has at least {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class SetMaxLengthError(PydanticValueError):
|
||||
code = 'set.max_items'
|
||||
msg_template = 'ensure this value has at most {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class FrozenSetMinLengthError(PydanticValueError):
|
||||
code = 'frozenset.min_items'
|
||||
msg_template = 'ensure this value has at least {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class FrozenSetMaxLengthError(PydanticValueError):
|
||||
code = 'frozenset.max_items'
|
||||
msg_template = 'ensure this value has at most {limit_value} items'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class AnyStrMinLengthError(PydanticValueError):
|
||||
code = 'any_str.min_length'
|
||||
msg_template = 'ensure this value has at least {limit_value} characters'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class AnyStrMaxLengthError(PydanticValueError):
|
||||
code = 'any_str.max_length'
|
||||
msg_template = 'ensure this value has at most {limit_value} characters'
|
||||
|
||||
def __init__(self, *, limit_value: int) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class StrError(PydanticTypeError):
|
||||
msg_template = 'str type expected'
|
||||
|
||||
|
||||
class StrRegexError(PydanticValueError):
|
||||
code = 'str.regex'
|
||||
msg_template = 'string does not match regex "{pattern}"'
|
||||
|
||||
def __init__(self, *, pattern: str) -> None:
|
||||
super().__init__(pattern=pattern)
|
||||
|
||||
|
||||
class _NumberBoundError(PydanticValueError):
|
||||
def __init__(self, *, limit_value: Union[int, float, Decimal]) -> None:
|
||||
super().__init__(limit_value=limit_value)
|
||||
|
||||
|
||||
class NumberNotGtError(_NumberBoundError):
|
||||
code = 'number.not_gt'
|
||||
msg_template = 'ensure this value is greater than {limit_value}'
|
||||
|
||||
|
||||
class NumberNotGeError(_NumberBoundError):
|
||||
code = 'number.not_ge'
|
||||
msg_template = 'ensure this value is greater than or equal to {limit_value}'
|
||||
|
||||
|
||||
class NumberNotLtError(_NumberBoundError):
|
||||
code = 'number.not_lt'
|
||||
msg_template = 'ensure this value is less than {limit_value}'
|
||||
|
||||
|
||||
class NumberNotLeError(_NumberBoundError):
|
||||
code = 'number.not_le'
|
||||
msg_template = 'ensure this value is less than or equal to {limit_value}'
|
||||
|
||||
|
||||
class NumberNotFiniteError(PydanticValueError):
|
||||
code = 'number.not_finite_number'
|
||||
msg_template = 'ensure this value is a finite number'
|
||||
|
||||
|
||||
class NumberNotMultipleError(PydanticValueError):
|
||||
code = 'number.not_multiple'
|
||||
msg_template = 'ensure this value is a multiple of {multiple_of}'
|
||||
|
||||
def __init__(self, *, multiple_of: Union[int, float, Decimal]) -> None:
|
||||
super().__init__(multiple_of=multiple_of)
|
||||
|
||||
|
||||
class DecimalError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid decimal'
|
||||
|
||||
|
||||
class DecimalIsNotFiniteError(PydanticValueError):
|
||||
code = 'decimal.not_finite'
|
||||
msg_template = 'value is not a valid decimal'
|
||||
|
||||
|
||||
class DecimalMaxDigitsError(PydanticValueError):
|
||||
code = 'decimal.max_digits'
|
||||
msg_template = 'ensure that there are no more than {max_digits} digits in total'
|
||||
|
||||
def __init__(self, *, max_digits: int) -> None:
|
||||
super().__init__(max_digits=max_digits)
|
||||
|
||||
|
||||
class DecimalMaxPlacesError(PydanticValueError):
|
||||
code = 'decimal.max_places'
|
||||
msg_template = 'ensure that there are no more than {decimal_places} decimal places'
|
||||
|
||||
def __init__(self, *, decimal_places: int) -> None:
|
||||
super().__init__(decimal_places=decimal_places)
|
||||
|
||||
|
||||
class DecimalWholeDigitsError(PydanticValueError):
|
||||
code = 'decimal.whole_digits'
|
||||
msg_template = 'ensure that there are no more than {whole_digits} digits before the decimal point'
|
||||
|
||||
def __init__(self, *, whole_digits: int) -> None:
|
||||
super().__init__(whole_digits=whole_digits)
|
||||
|
||||
|
||||
class DateTimeError(PydanticValueError):
|
||||
msg_template = 'invalid datetime format'
|
||||
|
||||
|
||||
class DateError(PydanticValueError):
|
||||
msg_template = 'invalid date format'
|
||||
|
||||
|
||||
class DateNotInThePastError(PydanticValueError):
|
||||
code = 'date.not_in_the_past'
|
||||
msg_template = 'date is not in the past'
|
||||
|
||||
|
||||
class DateNotInTheFutureError(PydanticValueError):
|
||||
code = 'date.not_in_the_future'
|
||||
msg_template = 'date is not in the future'
|
||||
|
||||
|
||||
class TimeError(PydanticValueError):
|
||||
msg_template = 'invalid time format'
|
||||
|
||||
|
||||
class DurationError(PydanticValueError):
|
||||
msg_template = 'invalid duration format'
|
||||
|
||||
|
||||
class HashableError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid hashable'
|
||||
|
||||
|
||||
class UUIDError(PydanticTypeError):
|
||||
msg_template = 'value is not a valid uuid'
|
||||
|
||||
|
||||
class UUIDVersionError(PydanticValueError):
|
||||
code = 'uuid.version'
|
||||
msg_template = 'uuid version {required_version} expected'
|
||||
|
||||
def __init__(self, *, required_version: int) -> None:
|
||||
super().__init__(required_version=required_version)
|
||||
|
||||
|
||||
class ArbitraryTypeError(PydanticTypeError):
|
||||
code = 'arbitrary_type'
|
||||
msg_template = 'instance of {expected_arbitrary_type} expected'
|
||||
|
||||
def __init__(self, *, expected_arbitrary_type: Type[Any]) -> None:
|
||||
super().__init__(expected_arbitrary_type=display_as_type(expected_arbitrary_type))
|
||||
|
||||
|
||||
class ClassError(PydanticTypeError):
|
||||
code = 'class'
|
||||
msg_template = 'a class is expected'
|
||||
|
||||
|
||||
class SubclassError(PydanticTypeError):
|
||||
code = 'subclass'
|
||||
msg_template = 'subclass of {expected_class} expected'
|
||||
|
||||
def __init__(self, *, expected_class: Type[Any]) -> None:
|
||||
super().__init__(expected_class=display_as_type(expected_class))
|
||||
|
||||
|
||||
class JsonError(PydanticValueError):
|
||||
msg_template = 'Invalid JSON'
|
||||
|
||||
|
||||
class JsonTypeError(PydanticTypeError):
|
||||
code = 'json'
|
||||
msg_template = 'JSON object must be str, bytes or bytearray'
|
||||
|
||||
|
||||
class PatternError(PydanticValueError):
|
||||
code = 'regex_pattern'
|
||||
msg_template = 'Invalid regular expression'
|
||||
|
||||
|
||||
class DataclassTypeError(PydanticTypeError):
|
||||
code = 'dataclass'
|
||||
msg_template = 'instance of {class_name}, tuple or dict expected'
|
||||
|
||||
|
||||
class CallableError(PydanticTypeError):
|
||||
msg_template = '{value} is not callable'
|
||||
|
||||
|
||||
class EnumError(PydanticTypeError):
|
||||
code = 'enum_instance'
|
||||
msg_template = '{value} is not a valid Enum instance'
|
||||
|
||||
|
||||
class IntEnumError(PydanticTypeError):
|
||||
code = 'int_enum_instance'
|
||||
msg_template = '{value} is not a valid IntEnum instance'
|
||||
|
||||
|
||||
class IPvAnyAddressError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 or IPv6 address'
|
||||
|
||||
|
||||
class IPvAnyInterfaceError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 or IPv6 interface'
|
||||
|
||||
|
||||
class IPvAnyNetworkError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 or IPv6 network'
|
||||
|
||||
|
||||
class IPv4AddressError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 address'
|
||||
|
||||
|
||||
class IPv6AddressError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv6 address'
|
||||
|
||||
|
||||
class IPv4NetworkError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 network'
|
||||
|
||||
|
||||
class IPv6NetworkError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv6 network'
|
||||
|
||||
|
||||
class IPv4InterfaceError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv4 interface'
|
||||
|
||||
|
||||
class IPv6InterfaceError(PydanticValueError):
|
||||
msg_template = 'value is not a valid IPv6 interface'
|
||||
|
||||
|
||||
class ColorError(PydanticValueError):
|
||||
msg_template = 'value is not a valid color: {reason}'
|
||||
|
||||
|
||||
class StrictBoolError(PydanticValueError):
|
||||
msg_template = 'value is not a valid boolean'
|
||||
|
||||
|
||||
class NotDigitError(PydanticValueError):
|
||||
code = 'payment_card_number.digits'
|
||||
msg_template = 'card number is not all digits'
|
||||
|
||||
|
||||
class LuhnValidationError(PydanticValueError):
|
||||
code = 'payment_card_number.luhn_check'
|
||||
msg_template = 'card number is not luhn valid'
|
||||
|
||||
|
||||
class InvalidLengthForBrand(PydanticValueError):
|
||||
code = 'payment_card_number.invalid_length_for_brand'
|
||||
msg_template = 'Length for a {brand} card must be {required_length}'
|
||||
|
||||
|
||||
class InvalidByteSize(PydanticValueError):
|
||||
msg_template = 'could not parse value and unit from byte string'
|
||||
|
||||
|
||||
class InvalidByteSizeUnit(PydanticValueError):
|
||||
msg_template = 'could not interpret byte unit: {unit}'
|
||||
|
||||
|
||||
class MissingDiscriminator(PydanticValueError):
|
||||
code = 'discriminated_union.missing_discriminator'
|
||||
msg_template = 'Discriminator {discriminator_key!r} is missing in value'
|
||||
|
||||
|
||||
class InvalidDiscriminator(PydanticValueError):
|
||||
code = 'discriminated_union.invalid_discriminator'
|
||||
msg_template = (
|
||||
'No match for discriminator {discriminator_key!r} and value {discriminator_value!r} '
|
||||
'(allowed values: {allowed_values})'
|
||||
)
|
||||
|
||||
def __init__(self, *, discriminator_key: str, discriminator_value: Any, allowed_values: Sequence[Any]) -> None:
|
||||
super().__init__(
|
||||
discriminator_key=discriminator_key,
|
||||
discriminator_value=discriminator_value,
|
||||
allowed_values=', '.join(map(repr, allowed_values)),
|
||||
)
|
||||
1253
venv/Lib/site-packages/pydantic/v1/fields.py
Normal file
1253
venv/Lib/site-packages/pydantic/v1/fields.py
Normal file
File diff suppressed because it is too large
Load Diff
400
venv/Lib/site-packages/pydantic/v1/generics.py
Normal file
400
venv/Lib/site-packages/pydantic/v1/generics.py
Normal file
@@ -0,0 +1,400 @@
|
||||
import functools
|
||||
import operator
|
||||
import sys
|
||||
import types
|
||||
import typing
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
ClassVar,
|
||||
Dict,
|
||||
ForwardRef,
|
||||
Generic,
|
||||
Iterator,
|
||||
List,
|
||||
Mapping,
|
||||
Optional,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
from weakref import WeakKeyDictionary, WeakValueDictionary
|
||||
|
||||
from typing_extensions import Annotated, Literal as ExtLiteral
|
||||
|
||||
from pydantic.v1.class_validators import gather_all_validators
|
||||
from pydantic.v1.fields import DeferredType
|
||||
from pydantic.v1.main import BaseModel, create_model
|
||||
from pydantic.v1.types import JsonWrapper
|
||||
from pydantic.v1.typing import display_as_type, get_all_type_hints, get_args, get_origin, typing_base
|
||||
from pydantic.v1.utils import all_identical, lenient_issubclass
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
|
||||
GenericModelT = TypeVar('GenericModelT', bound='GenericModel')
|
||||
TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type
|
||||
|
||||
CacheKey = Tuple[Type[Any], Any, Tuple[Any, ...]]
|
||||
Parametrization = Mapping[TypeVarType, Type[Any]]
|
||||
|
||||
# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected
|
||||
# once they are no longer referenced by the caller.
|
||||
if sys.version_info >= (3, 9): # Typing for weak dictionaries available at 3.9
|
||||
GenericTypesCache = WeakValueDictionary[CacheKey, Type[BaseModel]]
|
||||
AssignedParameters = WeakKeyDictionary[Type[BaseModel], Parametrization]
|
||||
else:
|
||||
GenericTypesCache = WeakValueDictionary
|
||||
AssignedParameters = WeakKeyDictionary
|
||||
|
||||
# _generic_types_cache is a Mapping from __class_getitem__ arguments to the parametrized version of generic models.
|
||||
# This ensures multiple calls of e.g. A[B] return always the same class.
|
||||
_generic_types_cache = GenericTypesCache()
|
||||
|
||||
# _assigned_parameters is a Mapping from parametrized version of generic models to assigned types of parametrizations
|
||||
# as captured during construction of the class (not instances).
|
||||
# E.g., for generic model `Model[A, B]`, when parametrized model `Model[int, str]` is created,
|
||||
# `Model[int, str]`: {A: int, B: str}` will be stored in `_assigned_parameters`.
|
||||
# (This information is only otherwise available after creation from the class name string).
|
||||
_assigned_parameters = AssignedParameters()
|
||||
|
||||
|
||||
class GenericModel(BaseModel):
|
||||
__slots__ = ()
|
||||
__concrete__: ClassVar[bool] = False
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with
|
||||
# `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of
|
||||
# `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below.
|
||||
__parameters__: ClassVar[Tuple[TypeVarType, ...]]
|
||||
|
||||
# Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings
|
||||
def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]:
|
||||
"""Instantiates a new class from a generic class `cls` and type variables `params`.
|
||||
|
||||
:param params: Tuple of types the class . Given a generic class
|
||||
`Model` with 2 type variables and a concrete model `Model[str, int]`,
|
||||
the value `(str, int)` would be passed to `params`.
|
||||
:return: New model class inheriting from `cls` with instantiated
|
||||
types described by `params`. If no parameters are given, `cls` is
|
||||
returned as is.
|
||||
|
||||
"""
|
||||
|
||||
def _cache_key(_params: Any) -> CacheKey:
|
||||
args = get_args(_params)
|
||||
# python returns a list for Callables, which is not hashable
|
||||
if len(args) == 2 and isinstance(args[0], list):
|
||||
args = (tuple(args[0]), args[1])
|
||||
return cls, _params, args
|
||||
|
||||
cached = _generic_types_cache.get(_cache_key(params))
|
||||
if cached is not None:
|
||||
return cached
|
||||
if cls.__concrete__ and Generic not in cls.__bases__:
|
||||
raise TypeError('Cannot parameterize a concrete instantiation of a generic model')
|
||||
if not isinstance(params, tuple):
|
||||
params = (params,)
|
||||
if cls is GenericModel and any(isinstance(param, TypeVar) for param in params):
|
||||
raise TypeError('Type parameters should be placed on typing.Generic, not GenericModel')
|
||||
if not hasattr(cls, '__parameters__'):
|
||||
raise TypeError(f'Type {cls.__name__} must inherit from typing.Generic before being parameterized')
|
||||
|
||||
check_parameters_count(cls, params)
|
||||
# Build map from generic typevars to passed params
|
||||
typevars_map: Dict[TypeVarType, Type[Any]] = dict(zip(cls.__parameters__, params))
|
||||
if all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map:
|
||||
return cls # if arguments are equal to parameters it's the same object
|
||||
|
||||
# Create new model with original model as parent inserting fields with DeferredType.
|
||||
model_name = cls.__concrete_name__(params)
|
||||
validators = gather_all_validators(cls)
|
||||
|
||||
type_hints = get_all_type_hints(cls).items()
|
||||
instance_type_hints = {k: v for k, v in type_hints if get_origin(v) is not ClassVar}
|
||||
|
||||
fields = {k: (DeferredType(), cls.__fields__[k].field_info) for k in instance_type_hints if k in cls.__fields__}
|
||||
|
||||
model_module, called_globally = get_caller_frame_info()
|
||||
created_model = cast(
|
||||
Type[GenericModel], # casting ensures mypy is aware of the __concrete__ and __parameters__ attributes
|
||||
create_model(
|
||||
model_name,
|
||||
__module__=model_module or cls.__module__,
|
||||
__base__=(cls,) + tuple(cls.__parameterized_bases__(typevars_map)),
|
||||
__config__=None,
|
||||
__validators__=validators,
|
||||
__cls_kwargs__=None,
|
||||
**fields,
|
||||
),
|
||||
)
|
||||
|
||||
_assigned_parameters[created_model] = typevars_map
|
||||
|
||||
if called_globally: # create global reference and therefore allow pickling
|
||||
object_by_reference = None
|
||||
reference_name = model_name
|
||||
reference_module_globals = sys.modules[created_model.__module__].__dict__
|
||||
while object_by_reference is not created_model:
|
||||
object_by_reference = reference_module_globals.setdefault(reference_name, created_model)
|
||||
reference_name += '_'
|
||||
|
||||
created_model.Config = cls.Config
|
||||
|
||||
# Find any typevars that are still present in the model.
|
||||
# If none are left, the model is fully "concrete", otherwise the new
|
||||
# class is a generic class as well taking the found typevars as
|
||||
# parameters.
|
||||
new_params = tuple(
|
||||
{param: None for param in iter_contained_typevars(typevars_map.values())}
|
||||
) # use dict as ordered set
|
||||
created_model.__concrete__ = not new_params
|
||||
if new_params:
|
||||
created_model.__parameters__ = new_params
|
||||
|
||||
# Save created model in cache so we don't end up creating duplicate
|
||||
# models that should be identical.
|
||||
_generic_types_cache[_cache_key(params)] = created_model
|
||||
if len(params) == 1:
|
||||
_generic_types_cache[_cache_key(params[0])] = created_model
|
||||
|
||||
# Recursively walk class type hints and replace generic typevars
|
||||
# with concrete types that were passed.
|
||||
_prepare_model_fields(created_model, fields, instance_type_hints, typevars_map)
|
||||
|
||||
return created_model
|
||||
|
||||
@classmethod
|
||||
def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str:
|
||||
"""Compute class name for child classes.
|
||||
|
||||
:param params: Tuple of types the class . Given a generic class
|
||||
`Model` with 2 type variables and a concrete model `Model[str, int]`,
|
||||
the value `(str, int)` would be passed to `params`.
|
||||
:return: String representing a the new class where `params` are
|
||||
passed to `cls` as type variables.
|
||||
|
||||
This method can be overridden to achieve a custom naming scheme for GenericModels.
|
||||
"""
|
||||
param_names = [display_as_type(param) for param in params]
|
||||
params_component = ', '.join(param_names)
|
||||
return f'{cls.__name__}[{params_component}]'
|
||||
|
||||
@classmethod
|
||||
def __parameterized_bases__(cls, typevars_map: Parametrization) -> Iterator[Type[Any]]:
|
||||
"""
|
||||
Returns unbound bases of cls parameterised to given type variables
|
||||
|
||||
:param typevars_map: Dictionary of type applications for binding subclasses.
|
||||
Given a generic class `Model` with 2 type variables [S, T]
|
||||
and a concrete model `Model[str, int]`,
|
||||
the value `{S: str, T: int}` would be passed to `typevars_map`.
|
||||
:return: an iterator of generic sub classes, parameterised by `typevars_map`
|
||||
and other assigned parameters of `cls`
|
||||
|
||||
e.g.:
|
||||
```
|
||||
class A(GenericModel, Generic[T]):
|
||||
...
|
||||
|
||||
class B(A[V], Generic[V]):
|
||||
...
|
||||
|
||||
assert A[int] in B.__parameterized_bases__({V: int})
|
||||
```
|
||||
"""
|
||||
|
||||
def build_base_model(
|
||||
base_model: Type[GenericModel], mapped_types: Parametrization
|
||||
) -> Iterator[Type[GenericModel]]:
|
||||
base_parameters = tuple(mapped_types[param] for param in base_model.__parameters__)
|
||||
parameterized_base = base_model.__class_getitem__(base_parameters)
|
||||
if parameterized_base is base_model or parameterized_base is cls:
|
||||
# Avoid duplication in MRO
|
||||
return
|
||||
yield parameterized_base
|
||||
|
||||
for base_model in cls.__bases__:
|
||||
if not issubclass(base_model, GenericModel):
|
||||
# not a class that can be meaningfully parameterized
|
||||
continue
|
||||
elif not getattr(base_model, '__parameters__', None):
|
||||
# base_model is "GenericModel" (and has no __parameters__)
|
||||
# or
|
||||
# base_model is already concrete, and will be included transitively via cls.
|
||||
continue
|
||||
elif cls in _assigned_parameters:
|
||||
if base_model in _assigned_parameters:
|
||||
# cls is partially parameterised but not from base_model
|
||||
# e.g. cls = B[S], base_model = A[S]
|
||||
# B[S][int] should subclass A[int], (and will be transitively via B[int])
|
||||
# but it's not viable to consistently subclass types with arbitrary construction
|
||||
# So don't attempt to include A[S][int]
|
||||
continue
|
||||
else: # base_model not in _assigned_parameters:
|
||||
# cls is partially parameterized, base_model is original generic
|
||||
# e.g. cls = B[str, T], base_model = B[S, T]
|
||||
# Need to determine the mapping for the base_model parameters
|
||||
mapped_types: Parametrization = {
|
||||
key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items()
|
||||
}
|
||||
yield from build_base_model(base_model, mapped_types)
|
||||
else:
|
||||
# cls is base generic, so base_class has a distinct base
|
||||
# can construct the Parameterised base model using typevars_map directly
|
||||
yield from build_base_model(base_model, typevars_map)
|
||||
|
||||
|
||||
def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any:
|
||||
"""Return type with all occurrences of `type_map` keys recursively replaced with their values.
|
||||
|
||||
:param type_: Any type, class or generic alias
|
||||
:param type_map: Mapping from `TypeVar` instance to concrete types.
|
||||
:return: New type representing the basic structure of `type_` with all
|
||||
`typevar_map` keys recursively replaced.
|
||||
|
||||
>>> replace_types(Tuple[str, Union[List[str], float]], {str: int})
|
||||
Tuple[int, Union[List[int], float]]
|
||||
|
||||
"""
|
||||
if not type_map:
|
||||
return type_
|
||||
|
||||
type_args = get_args(type_)
|
||||
origin_type = get_origin(type_)
|
||||
|
||||
if origin_type is Annotated:
|
||||
annotated_type, *annotations = type_args
|
||||
return Annotated[replace_types(annotated_type, type_map), tuple(annotations)]
|
||||
|
||||
if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal):
|
||||
return type_map.get(type_, type_)
|
||||
# Having type args is a good indicator that this is a typing module
|
||||
# class instantiation or a generic alias of some sort.
|
||||
if type_args:
|
||||
resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args)
|
||||
if all_identical(type_args, resolved_type_args):
|
||||
# If all arguments are the same, there is no need to modify the
|
||||
# type or create a new object at all
|
||||
return type_
|
||||
if (
|
||||
origin_type is not None
|
||||
and isinstance(type_, typing_base)
|
||||
and not isinstance(origin_type, typing_base)
|
||||
and getattr(type_, '_name', None) is not None
|
||||
):
|
||||
# In python < 3.9 generic aliases don't exist so any of these like `list`,
|
||||
# `type` or `collections.abc.Callable` need to be translated.
|
||||
# See: https://www.python.org/dev/peps/pep-0585
|
||||
origin_type = getattr(typing, type_._name)
|
||||
assert origin_type is not None
|
||||
# PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__.
|
||||
# We also cannot use isinstance() since we have to compare types.
|
||||
if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721
|
||||
return functools.reduce(operator.or_, resolved_type_args)
|
||||
return origin_type[resolved_type_args]
|
||||
|
||||
# We handle pydantic generic models separately as they don't have the same
|
||||
# semantics as "typing" classes or generic aliases
|
||||
if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__:
|
||||
type_args = type_.__parameters__
|
||||
resolved_type_args = tuple(replace_types(t, type_map) for t in type_args)
|
||||
if all_identical(type_args, resolved_type_args):
|
||||
return type_
|
||||
return type_[resolved_type_args]
|
||||
|
||||
# Handle special case for typehints that can have lists as arguments.
|
||||
# `typing.Callable[[int, str], int]` is an example for this.
|
||||
if isinstance(type_, (List, list)):
|
||||
resolved_list = list(replace_types(element, type_map) for element in type_)
|
||||
if all_identical(type_, resolved_list):
|
||||
return type_
|
||||
return resolved_list
|
||||
|
||||
# For JsonWrapperValue, need to handle its inner type to allow correct parsing
|
||||
# of generic Json arguments like Json[T]
|
||||
if not origin_type and lenient_issubclass(type_, JsonWrapper):
|
||||
type_.inner_type = replace_types(type_.inner_type, type_map)
|
||||
return type_
|
||||
|
||||
# If all else fails, we try to resolve the type directly and otherwise just
|
||||
# return the input with no modifications.
|
||||
new_type = type_map.get(type_, type_)
|
||||
# Convert string to ForwardRef
|
||||
if isinstance(new_type, str):
|
||||
return ForwardRef(new_type)
|
||||
else:
|
||||
return new_type
|
||||
|
||||
|
||||
def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None:
|
||||
actual = len(parameters)
|
||||
expected = len(cls.__parameters__)
|
||||
if actual != expected:
|
||||
description = 'many' if actual > expected else 'few'
|
||||
raise TypeError(f'Too {description} parameters for {cls.__name__}; actual {actual}, expected {expected}')
|
||||
|
||||
|
||||
DictValues: Type[Any] = {}.values().__class__
|
||||
|
||||
|
||||
def iter_contained_typevars(v: Any) -> Iterator[TypeVarType]:
|
||||
"""Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found."""
|
||||
if isinstance(v, TypeVar):
|
||||
yield v
|
||||
elif hasattr(v, '__parameters__') and not get_origin(v) and lenient_issubclass(v, GenericModel):
|
||||
yield from v.__parameters__
|
||||
elif isinstance(v, (DictValues, list)):
|
||||
for var in v:
|
||||
yield from iter_contained_typevars(var)
|
||||
else:
|
||||
args = get_args(v)
|
||||
for arg in args:
|
||||
yield from iter_contained_typevars(arg)
|
||||
|
||||
|
||||
def get_caller_frame_info() -> Tuple[Optional[str], bool]:
|
||||
"""
|
||||
Used inside a function to check whether it was called globally
|
||||
|
||||
Will only work against non-compiled code, therefore used only in pydantic.generics
|
||||
|
||||
:returns Tuple[module_name, called_globally]
|
||||
"""
|
||||
try:
|
||||
previous_caller_frame = sys._getframe(2)
|
||||
except ValueError as e:
|
||||
raise RuntimeError('This function must be used inside another function') from e
|
||||
except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it
|
||||
return None, False
|
||||
frame_globals = previous_caller_frame.f_globals
|
||||
return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals
|
||||
|
||||
|
||||
def _prepare_model_fields(
|
||||
created_model: Type[GenericModel],
|
||||
fields: Mapping[str, Any],
|
||||
instance_type_hints: Mapping[str, type],
|
||||
typevars_map: Mapping[Any, type],
|
||||
) -> None:
|
||||
"""
|
||||
Replace DeferredType fields with concrete type hints and prepare them.
|
||||
"""
|
||||
|
||||
for key, field in created_model.__fields__.items():
|
||||
if key not in fields:
|
||||
assert field.type_.__class__ is not DeferredType
|
||||
# https://github.com/nedbat/coveragepy/issues/198
|
||||
continue # pragma: no cover
|
||||
|
||||
assert field.type_.__class__ is DeferredType, field.type_.__class__
|
||||
|
||||
field_type_hint = instance_type_hints[key]
|
||||
concrete_type = replace_types(field_type_hint, typevars_map)
|
||||
field.type_ = concrete_type
|
||||
field.outer_type_ = concrete_type
|
||||
field.prepare()
|
||||
created_model.__annotations__[key] = concrete_type
|
||||
112
venv/Lib/site-packages/pydantic/v1/json.py
Normal file
112
venv/Lib/site-packages/pydantic/v1/json.py
Normal file
@@ -0,0 +1,112 @@
|
||||
import datetime
|
||||
from collections import deque
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network
|
||||
from pathlib import Path
|
||||
from re import Pattern
|
||||
from types import GeneratorType
|
||||
from typing import Any, Callable, Dict, Type, Union
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic.v1.color import Color
|
||||
from pydantic.v1.networks import NameEmail
|
||||
from pydantic.v1.types import SecretBytes, SecretStr
|
||||
|
||||
__all__ = 'pydantic_encoder', 'custom_pydantic_encoder', 'timedelta_isoformat'
|
||||
|
||||
|
||||
def isoformat(o: Union[datetime.date, datetime.time]) -> str:
|
||||
return o.isoformat()
|
||||
|
||||
|
||||
def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
|
||||
"""
|
||||
Encodes a Decimal as int of there's no exponent, otherwise float
|
||||
|
||||
This is useful when we use ConstrainedDecimal to represent Numeric(x,0)
|
||||
where a integer (but not int typed) is used. Encoding this as a float
|
||||
results in failed round-tripping between encode and parse.
|
||||
Our Id type is a prime example of this.
|
||||
|
||||
>>> decimal_encoder(Decimal("1.0"))
|
||||
1.0
|
||||
|
||||
>>> decimal_encoder(Decimal("1"))
|
||||
1
|
||||
"""
|
||||
if dec_value.as_tuple().exponent >= 0:
|
||||
return int(dec_value)
|
||||
else:
|
||||
return float(dec_value)
|
||||
|
||||
|
||||
ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
|
||||
bytes: lambda o: o.decode(),
|
||||
Color: str,
|
||||
datetime.date: isoformat,
|
||||
datetime.datetime: isoformat,
|
||||
datetime.time: isoformat,
|
||||
datetime.timedelta: lambda td: td.total_seconds(),
|
||||
Decimal: decimal_encoder,
|
||||
Enum: lambda o: o.value,
|
||||
frozenset: list,
|
||||
deque: list,
|
||||
GeneratorType: list,
|
||||
IPv4Address: str,
|
||||
IPv4Interface: str,
|
||||
IPv4Network: str,
|
||||
IPv6Address: str,
|
||||
IPv6Interface: str,
|
||||
IPv6Network: str,
|
||||
NameEmail: str,
|
||||
Path: str,
|
||||
Pattern: lambda o: o.pattern,
|
||||
SecretBytes: str,
|
||||
SecretStr: str,
|
||||
set: list,
|
||||
UUID: str,
|
||||
}
|
||||
|
||||
|
||||
def pydantic_encoder(obj: Any) -> Any:
|
||||
from dataclasses import asdict, is_dataclass
|
||||
|
||||
from pydantic.v1.main import BaseModel
|
||||
|
||||
if isinstance(obj, BaseModel):
|
||||
return obj.dict()
|
||||
elif is_dataclass(obj):
|
||||
return asdict(obj)
|
||||
|
||||
# Check the class type and its superclasses for a matching encoder
|
||||
for base in obj.__class__.__mro__[:-1]:
|
||||
try:
|
||||
encoder = ENCODERS_BY_TYPE[base]
|
||||
except KeyError:
|
||||
continue
|
||||
return encoder(obj)
|
||||
else: # We have exited the for loop without finding a suitable encoder
|
||||
raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable")
|
||||
|
||||
|
||||
def custom_pydantic_encoder(type_encoders: Dict[Any, Callable[[Type[Any]], Any]], obj: Any) -> Any:
|
||||
# Check the class type and its superclasses for a matching encoder
|
||||
for base in obj.__class__.__mro__[:-1]:
|
||||
try:
|
||||
encoder = type_encoders[base]
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
return encoder(obj)
|
||||
else: # We have exited the for loop without finding a suitable encoder
|
||||
return pydantic_encoder(obj)
|
||||
|
||||
|
||||
def timedelta_isoformat(td: datetime.timedelta) -> str:
|
||||
"""
|
||||
ISO 8601 encoding for Python timedelta object.
|
||||
"""
|
||||
minutes, seconds = divmod(td.seconds, 60)
|
||||
hours, minutes = divmod(minutes, 60)
|
||||
return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S'
|
||||
Reference in New Issue
Block a user