This commit is contained in:
Iliyan Angelov
2025-12-01 06:50:10 +02:00
parent 91f51bc6fe
commit 62c1fe5951
4682 changed files with 544807 additions and 31208 deletions

View File

@@ -1,13 +1,17 @@
"""Usage docs: https://docs.pydantic.dev/2.5/concepts/plugins#build-a-plugin
"""!!! abstract "Usage Documentation"
[Build a Plugin](../concepts/plugins.md#build-a-plugin)
Plugin interface for Pydantic plugins, and related types.
"""
from __future__ import annotations
from typing import Any, Callable, NamedTuple
from typing import Any, Callable, Literal, NamedTuple
from pydantic_core import CoreConfig, CoreSchema, ValidationError
from typing_extensions import Literal, Protocol, TypeAlias
from typing_extensions import Protocol, TypeAlias
from pydantic.config import ExtraValues
__all__ = (
'PydanticPluginProtocol',
@@ -111,21 +115,26 @@ class ValidatePythonHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
input: Any,
*,
strict: bool | None = None,
extra: ExtraValues | None = None,
from_attributes: bool | None = None,
context: dict[str, Any] | None = None,
context: Any | None = None,
self_instance: Any | None = None,
by_alias: bool | None = None,
by_name: bool | None = None,
) -> None:
"""Callback to be notified of validation start, and create an instance of the event handler.
Args:
input: The input to be validated.
strict: Whether to validate the object in strict mode.
extra: Whether to ignore, allow, or forbid extra data during model validation.
from_attributes: Whether to validate objects as inputs by extracting attributes.
context: The context to use for validation, this is passed to functional validators.
self_instance: An instance of a model to set attributes on from validation, this is used when running
validation from the `__init__` method of a model.
by_alias: Whether to use the field's alias to match the input data to an attribute.
by_name: Whether to use the field's name to match the input data to an attribute.
"""
pass
class ValidateJsonHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
@@ -136,19 +145,24 @@ class ValidateJsonHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
input: str | bytes | bytearray,
*,
strict: bool | None = None,
context: dict[str, Any] | None = None,
extra: ExtraValues | None = None,
context: Any | None = None,
self_instance: Any | None = None,
by_alias: bool | None = None,
by_name: bool | None = None,
) -> None:
"""Callback to be notified of validation start, and create an instance of the event handler.
Args:
input: The JSON data to be validated.
strict: Whether to validate the object in strict mode.
extra: Whether to ignore, allow, or forbid extra data during model validation.
context: The context to use for validation, this is passed to functional validators.
self_instance: An instance of a model to set attributes on from validation, this is used when running
validation from the `__init__` method of a model.
by_alias: Whether to use the field's alias to match the input data to an attribute.
by_name: Whether to use the field's name to match the input data to an attribute.
"""
pass
StringInput: TypeAlias = 'dict[str, StringInput]'
@@ -158,13 +172,22 @@ class ValidateStringsHandlerProtocol(BaseValidateHandlerProtocol, Protocol):
"""Event handler for `SchemaValidator.validate_strings`."""
def on_enter(
self, input: StringInput, *, strict: bool | None = None, context: dict[str, Any] | None = None
self,
input: StringInput,
*,
strict: bool | None = None,
extra: ExtraValues | None = None,
context: Any | None = None,
by_alias: bool | None = None,
by_name: bool | None = None,
) -> None:
"""Callback to be notified of validation start, and create an instance of the event handler.
Args:
input: The string data to be validated.
strict: Whether to validate the object in strict mode.
extra: Whether to ignore, allow, or forbid extra data during model validation.
context: The context to use for validation, this is passed to functional validators.
by_alias: Whether to use the field's alias to match the input data to an attribute.
by_name: Whether to use the field's name to match the input data to an attribute.
"""
pass

View File

@@ -1,16 +1,10 @@
from __future__ import annotations
import sys
import importlib.metadata as importlib_metadata
import os
import warnings
from typing import TYPE_CHECKING, Iterable
from typing_extensions import Final
if sys.version_info >= (3, 8):
import importlib.metadata as importlib_metadata
else:
import importlib_metadata
from collections.abc import Iterable
from typing import TYPE_CHECKING, Final
if TYPE_CHECKING:
from . import PydanticPluginProtocol
@@ -30,10 +24,13 @@ def get_plugins() -> Iterable[PydanticPluginProtocol]:
Inspired by: https://github.com/pytest-dev/pluggy/blob/1.3.0/src/pluggy/_manager.py#L376-L402
"""
disabled_plugins = os.getenv('PYDANTIC_DISABLE_PLUGINS')
global _plugins, _loading_plugins
if _loading_plugins:
# this happens when plugins themselves use pydantic, we return no plugins
return ()
elif disabled_plugins in ('__all__', '1', 'true'):
return ()
elif _plugins is None:
_plugins = {}
# set _loading_plugins so any plugins that use pydantic don't themselves use plugins
@@ -45,12 +42,15 @@ def get_plugins() -> Iterable[PydanticPluginProtocol]:
continue
if entry_point.value in _plugins:
continue
if disabled_plugins is not None and entry_point.name in disabled_plugins.split(','):
continue
try:
_plugins[entry_point.value] = entry_point.load()
except (ImportError, AttributeError) as e:
warnings.warn(
f'{e.__class__.__name__} while loading the `{entry_point.name}` Pydantic plugin, '
f'this plugin will not be installed.\n\n{e!r}'
f'this plugin will not be installed.\n\n{e!r}',
stacklevel=2,
)
finally:
_loading_plugins = False

View File

@@ -1,11 +1,13 @@
"""Pluggable schema validator for pydantic."""
from __future__ import annotations
import functools
from typing import TYPE_CHECKING, Any, Callable, Iterable, TypeVar
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar
from pydantic_core import CoreConfig, CoreSchema, SchemaValidator, ValidationError
from typing_extensions import Literal, ParamSpec
from typing_extensions import ParamSpec
if TYPE_CHECKING:
from . import BaseValidateHandlerProtocol, PydanticPluginProtocol, SchemaKind, SchemaTypePath
@@ -25,7 +27,7 @@ def create_schema_validator(
schema_kind: SchemaKind,
config: CoreConfig | None = None,
plugin_settings: dict[str, Any] | None = None,
) -> SchemaValidator:
) -> SchemaValidator | PluggableSchemaValidator:
"""Create a `SchemaValidator` or `PluggableSchemaValidator` if plugins are installed.
Returns:
@@ -44,7 +46,7 @@ def create_schema_validator(
config,
plugins,
plugin_settings or {},
) # type: ignore
)
else:
return SchemaValidator(schema, config)