1"""Plugin interface for Pydantic plugins, and related types."""
2
3from __future__ import annotations
4
5from collections.abc import Callable
6from typing import Any, Literal, NamedTuple, TypeAlias
7
8from pydantic_core import CoreConfig, CoreSchema, ValidationError
9from typing_extensions import Protocol
10
11from pydantic.config import ExtraValues
12
13__all__ = (
14 'PydanticPluginProtocol',
15 'BaseValidateHandlerProtocol',
16 'ValidatePythonHandlerProtocol',
17 'ValidateJsonHandlerProtocol',
18 'ValidateStringsHandlerProtocol',
19 'NewSchemaReturns',
20 'SchemaTypePath',
21 'SchemaKind',
22)
23
24NewSchemaReturns: TypeAlias = 'tuple[ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None]'
25
26
27class SchemaTypePath(NamedTuple):
28 """Path defining where `schema_type` was defined, or where `TypeAdapter` was called."""
29
30 module: str
31 name: str
32
33
34SchemaKind: TypeAlias = Literal['BaseModel', 'TypeAdapter', 'dataclass', 'create_model', 'validate_call']
35
36
37class PydanticPluginProtocol(Protocol):
38 """Protocol defining the interface for Pydantic plugins."""
39
40 def new_schema_validator(
41 self,
42 schema: CoreSchema,
43 schema_type: Any,
44 schema_type_path: SchemaTypePath,
45 schema_kind: SchemaKind,
46 config: CoreConfig | None,
47 plugin_settings: dict[str, object],
48 ) -> tuple[
49 ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None
50 ]:
51 """This method is called for each plugin every time a new [`SchemaValidator`][pydantic_core.SchemaValidator]
52 is created.
53
54 It should return an event handler for each of the three validation methods, or `None` if the plugin does not
55 implement that method.
56
57 Args:
58 schema: The schema to validate against.
59 schema_type: The original type which the schema was created from, e.g. the model class.
60 schema_type_path: Path defining where `schema_type` was defined, or where `TypeAdapter` was called.
61 schema_kind: The kind of schema to validate against.
62 config: The config to use for validation.
63 plugin_settings: Any plugin settings.
64
65 Returns:
66 A tuple of optional event handlers for each of the three validation methods -
67 `validate_python`, `validate_json`, `validate_strings`.
68 """
69 raise NotImplementedError('Pydantic plugins should implement `new_schema_validator`.')
70
71
72class BaseValidateHandlerProtocol(Protocol):
73 """Base class for plugin callbacks protocols.
74
75 You shouldn't implement this protocol directly, instead use one of the subclasses with adds the correctly
76 typed `on_error` method.
77 """
78
79 on_enter: Callable[..., None]
80 """`on_enter` is changed to be more specific on all subclasses"""
81
82 def on_success(self, result: Any) -> None:
83 """Callback to be notified of successful validation.
84
85 Args:
86 result: The result of the validation.
87 """
88 return
89
90 def on_error(self, error: ValidationError) -> None:
91 """Callback to be notified of validation errors.
92
93 Args:
94 error: The validation error.
95 """
96 return
97
98 def on_exception(self, exception: Exception) -> None:
99 """Callback to be notified of validation exceptions.
100
101 Args:
102 exception: The exception raised during validation.
103 """
104 return
105
106
107class ValidatePythonHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
108 """Event handler for `SchemaValidator.validate_python`."""
109
110 def on_enter(
111 self,
112 input: Any,
113 *,
114 strict: bool | None = None,
115 extra: ExtraValues | None = None,
116 from_attributes: bool | None = None,
117 context: Any | None = None,
118 self_instance: Any | None = None,
119 by_alias: bool | None = None,
120 by_name: bool | None = None,
121 ) -> None:
122 """Callback to be notified of validation start, and create an instance of the event handler.
123
124 Args:
125 input: The input to be validated.
126 strict: Whether to validate the object in strict mode.
127 extra: Whether to ignore, allow, or forbid extra data during model validation.
128 from_attributes: Whether to validate objects as inputs by extracting attributes.
129 context: The context to use for validation, this is passed to functional validators.
130 self_instance: An instance of a model to set attributes on from validation, this is used when running
131 validation from the `__init__` method of a model.
132 by_alias: Whether to use the field's alias to match the input data to an attribute.
133 by_name: Whether to use the field's name to match the input data to an attribute.
134 """
135
136
137class ValidateJsonHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
138 """Event handler for `SchemaValidator.validate_json`."""
139
140 def on_enter(
141 self,
142 input: str | bytes | bytearray,
143 *,
144 strict: bool | None = None,
145 extra: ExtraValues | None = None,
146 context: Any | None = None,
147 self_instance: Any | None = None,
148 by_alias: bool | None = None,
149 by_name: bool | None = None,
150 ) -> None:
151 """Callback to be notified of validation start, and create an instance of the event handler.
152
153 Args:
154 input: The JSON data to be validated.
155 strict: Whether to validate the object in strict mode.
156 extra: Whether to ignore, allow, or forbid extra data during model validation.
157 context: The context to use for validation, this is passed to functional validators.
158 self_instance: An instance of a model to set attributes on from validation, this is used when running
159 validation from the `__init__` method of a model.
160 by_alias: Whether to use the field's alias to match the input data to an attribute.
161 by_name: Whether to use the field's name to match the input data to an attribute.
162 """
163
164
165StringInput: TypeAlias = 'dict[str, StringInput]'
166
167
168class ValidateStringsHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
169 """Event handler for `SchemaValidator.validate_strings`."""
170
171 def on_enter(
172 self,
173 input: StringInput,
174 *,
175 strict: bool | None = None,
176 extra: ExtraValues | None = None,
177 context: Any | None = None,
178 by_alias: bool | None = None,
179 by_name: bool | None = None,
180 ) -> None:
181 """Callback to be notified of validation start, and create an instance of the event handler.
182
183 Args:
184 input: The string data to be validated.
185 strict: Whether to validate the object in strict mode.
186 extra: Whether to ignore, allow, or forbid extra data during model validation.
187 context: The context to use for validation, this is passed to functional validators.
188 by_alias: Whether to use the field's alias to match the input data to an attribute.
189 by_name: Whether to use the field's name to match the input data to an attribute.
190 """