您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

192 行
6.4 KiB

  1. import json
  2. from enum import Enum
  3. from typing import TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Optional, Tuple, Type, Union
  4. from typing_extensions import Literal, Protocol
  5. from pydantic.v1.typing import AnyArgTCallable, AnyCallable
  6. from pydantic.v1.utils import GetterDict
  7. from pydantic.v1.version import compiled
  8. if TYPE_CHECKING:
  9. from typing import overload
  10. from pydantic.v1.fields import ModelField
  11. from pydantic.v1.main import BaseModel
  12. ConfigType = Type['BaseConfig']
  13. class SchemaExtraCallable(Protocol):
  14. @overload
  15. def __call__(self, schema: Dict[str, Any]) -> None:
  16. pass
  17. @overload
  18. def __call__(self, schema: Dict[str, Any], model_class: Type[BaseModel]) -> None:
  19. pass
  20. else:
  21. SchemaExtraCallable = Callable[..., None]
  22. __all__ = 'BaseConfig', 'ConfigDict', 'get_config', 'Extra', 'inherit_config', 'prepare_config'
  23. class Extra(str, Enum):
  24. allow = 'allow'
  25. ignore = 'ignore'
  26. forbid = 'forbid'
  27. # https://github.com/cython/cython/issues/4003
  28. # Fixed in Cython 3 and Pydantic v1 won't support Cython 3.
  29. # Pydantic v2 doesn't depend on Cython at all.
  30. if not compiled:
  31. from typing_extensions import TypedDict
  32. class ConfigDict(TypedDict, total=False):
  33. title: Optional[str]
  34. anystr_lower: bool
  35. anystr_strip_whitespace: bool
  36. min_anystr_length: int
  37. max_anystr_length: Optional[int]
  38. validate_all: bool
  39. extra: Extra
  40. allow_mutation: bool
  41. frozen: bool
  42. allow_population_by_field_name: bool
  43. use_enum_values: bool
  44. fields: Dict[str, Union[str, Dict[str, str]]]
  45. validate_assignment: bool
  46. error_msg_templates: Dict[str, str]
  47. arbitrary_types_allowed: bool
  48. orm_mode: bool
  49. getter_dict: Type[GetterDict]
  50. alias_generator: Optional[Callable[[str], str]]
  51. keep_untouched: Tuple[type, ...]
  52. schema_extra: Union[Dict[str, object], 'SchemaExtraCallable']
  53. json_loads: Callable[[str], object]
  54. json_dumps: AnyArgTCallable[str]
  55. json_encoders: Dict[Type[object], AnyCallable]
  56. underscore_attrs_are_private: bool
  57. allow_inf_nan: bool
  58. copy_on_model_validation: Literal['none', 'deep', 'shallow']
  59. # whether dataclass `__post_init__` should be run after validation
  60. post_init_call: Literal['before_validation', 'after_validation']
  61. else:
  62. ConfigDict = dict # type: ignore
  63. class BaseConfig:
  64. title: Optional[str] = None
  65. anystr_lower: bool = False
  66. anystr_upper: bool = False
  67. anystr_strip_whitespace: bool = False
  68. min_anystr_length: int = 0
  69. max_anystr_length: Optional[int] = None
  70. validate_all: bool = False
  71. extra: Extra = Extra.ignore
  72. allow_mutation: bool = True
  73. frozen: bool = False
  74. allow_population_by_field_name: bool = False
  75. use_enum_values: bool = False
  76. fields: Dict[str, Union[str, Dict[str, str]]] = {}
  77. validate_assignment: bool = False
  78. error_msg_templates: Dict[str, str] = {}
  79. arbitrary_types_allowed: bool = False
  80. orm_mode: bool = False
  81. getter_dict: Type[GetterDict] = GetterDict
  82. alias_generator: Optional[Callable[[str], str]] = None
  83. keep_untouched: Tuple[type, ...] = ()
  84. schema_extra: Union[Dict[str, Any], 'SchemaExtraCallable'] = {}
  85. json_loads: Callable[[str], Any] = json.loads
  86. json_dumps: Callable[..., str] = json.dumps
  87. json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable] = {}
  88. underscore_attrs_are_private: bool = False
  89. allow_inf_nan: bool = True
  90. # whether inherited models as fields should be reconstructed as base model,
  91. # and whether such a copy should be shallow or deep
  92. copy_on_model_validation: Literal['none', 'deep', 'shallow'] = 'shallow'
  93. # whether `Union` should check all allowed types before even trying to coerce
  94. smart_union: bool = False
  95. # whether dataclass `__post_init__` should be run before or after validation
  96. post_init_call: Literal['before_validation', 'after_validation'] = 'before_validation'
  97. @classmethod
  98. def get_field_info(cls, name: str) -> Dict[str, Any]:
  99. """
  100. Get properties of FieldInfo from the `fields` property of the config class.
  101. """
  102. fields_value = cls.fields.get(name)
  103. if isinstance(fields_value, str):
  104. field_info: Dict[str, Any] = {'alias': fields_value}
  105. elif isinstance(fields_value, dict):
  106. field_info = fields_value
  107. else:
  108. field_info = {}
  109. if 'alias' in field_info:
  110. field_info.setdefault('alias_priority', 2)
  111. if field_info.get('alias_priority', 0) <= 1 and cls.alias_generator:
  112. alias = cls.alias_generator(name)
  113. if not isinstance(alias, str):
  114. raise TypeError(f'Config.alias_generator must return str, not {alias.__class__}')
  115. field_info.update(alias=alias, alias_priority=1)
  116. return field_info
  117. @classmethod
  118. def prepare_field(cls, field: 'ModelField') -> None:
  119. """
  120. Optional hook to check or modify fields during model creation.
  121. """
  122. pass
  123. def get_config(config: Union[ConfigDict, Type[object], None]) -> Type[BaseConfig]:
  124. if config is None:
  125. return BaseConfig
  126. else:
  127. config_dict = (
  128. config
  129. if isinstance(config, dict)
  130. else {k: getattr(config, k) for k in dir(config) if not k.startswith('__')}
  131. )
  132. class Config(BaseConfig):
  133. ...
  134. for k, v in config_dict.items():
  135. setattr(Config, k, v)
  136. return Config
  137. def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType':
  138. if not self_config:
  139. base_classes: Tuple['ConfigType', ...] = (parent_config,)
  140. elif self_config == parent_config:
  141. base_classes = (self_config,)
  142. else:
  143. base_classes = self_config, parent_config
  144. namespace['json_encoders'] = {
  145. **getattr(parent_config, 'json_encoders', {}),
  146. **getattr(self_config, 'json_encoders', {}),
  147. **namespace.get('json_encoders', {}),
  148. }
  149. return type('Config', base_classes, namespace)
  150. def prepare_config(config: Type[BaseConfig], cls_name: str) -> None:
  151. if not isinstance(config.extra, Extra):
  152. try:
  153. config.extra = Extra(config.extra)
  154. except ValueError:
  155. raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"')