Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions python/pydantic_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,35 @@

class ErrorDetails(_TypedDict):
type: str
"""
The type of error that occurred, this is an identifier designed for
programmatic use that will change rarely or never.

`type` is unique for each error message, and can hence be used as an identifier to build custom error messages.
"""
loc: tuple[int | str, ...]
"""Tuple of strings and ints identifying where in the schema the error occurred."""
msg: str
"""A human readable error message."""
input: _Any
"""The input data at this `loc` that caused the error."""
ctx: _NotRequired[dict[str, str | int | float]]
"""
Values which are required to render the error message, and could hence be useful in rendering custom error messages.
"""


class InitErrorDetails(_TypedDict):
type: str | PydanticCustomError
"""The type of error that occurred, this should a "slug" identifier that changes rarely or never."""
loc: _NotRequired[tuple[int | str, ...]]
"""Tuple of strings and ints identifying where in the schema the error occurred."""
input: _Any
"""The input data at this `loc` that caused the error."""
ctx: _NotRequired[dict[str, str | int | float]]
"""
Values which are required to render the error message, and could hence be useful in rendering custom error messages.
"""


class ErrorTypeInfo(_TypedDict):
Expand Down
215 changes: 200 additions & 15 deletions python/pydantic_core/_pydantic_core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,43 @@ _T = TypeVar('_T', default=Any, covariant=True)

@final
class Some(Generic[_T]):
"""
Similar to Rust's [`Option::Some`](https://doc.rust-lang.org/std/option/enum.Option.html) type, this
identifies a value as being present, and provides a way to access it.

Generally used in a union with `None` to different between "some value which could be None" and no value.
"""

__match_args__ = ('value',)

@property
def value(self) -> _T: ...
def value(self) -> _T:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type annotation is _T, maybe we should rename to T for nicer docs?

image

"""
Returns the value wrapped by `Some`.
"""
@classmethod
def __class_getitem__(cls, __item: Any) -> Type[Self]: ...

@final
class SchemaValidator:
def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None) -> Self: ...
"""
`SchemaValidator` is the Python wrapper for `pydantic-core`'s Rust validation logic, internally it owns one
`CombinedValidator` which may in turn own more `CombinedValidator`s which make up the full schema validator.
"""

def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None) -> Self:
"""
Create a new SchemaValidator.

Arguments:
schema: The [`CoreSchema`][pydantic_core.core_schema.CoreSchema] to use for validation.
config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to configure validation.
"""
Comment on lines +82 to +89
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like __new__ doesn't show in the docs. @Kludex also reported an issue with __new__ and __init__ mismatching arguments in some cases (e.g. for exceptions, __init__ comes from BaseException). I think this is probably a PyO3 bug, PyO3 sets __new__ but not __init__.

Maybe for now it's more practical to set both __new__ and __init__ here, document __init__, and I'll have a think about how to resolve this in PyO3?

@property
def title(self) -> str: ...
def title(self) -> str:
"""
The title of the schema, as used in the heading of [`ValidationError.__str__()`][pydantic_core.ValidationError].
"""
def validate_python(
self,
input: Any,
Expand All @@ -75,7 +100,28 @@ class SchemaValidator:
from_attributes: bool | None = None,
context: 'dict[str, Any] | None' = None,
self_instance: Any | None = None,
) -> Any: ...
) -> Any:
"""
Validate a Python object against the schema and return the validated object.

Arguments:
input: The Python object to validate.
strict: Whether to validate the object in strict mode.
If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used.
from_attributes: Whether to validate objects as inputs to models by extracting attributes.
If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used.
context: The context to use for validation, this is passed to functional validators as
[`info.context`][pydantic_core.core_schema.ValidationInfo.context].
self_instance: An instance of a model set attributes on from validation, this is used when running
validation from the `__init__` method of a model.

Raises:
ValidationError: If validation fails.
Exception: Other error types maybe raised if internal errors occur.

Returns:
The validated object.
"""
def isinstance_python(
self,
input: Any,
Expand All @@ -84,15 +130,48 @@ class SchemaValidator:
from_attributes: bool | None = None,
context: 'dict[str, Any] | None' = None,
self_instance: Any | None = None,
) -> bool: ...
) -> bool:
"""
Similar to [`validate_python()`][pydantic_core.SchemaValidator.validate_python] but returns a boolean.

Arguments match `validate_python()`. This method will not raise `ValidationError`s but will raise internal
errors.

Returns:
`True` if validation succeeds, `False` if validation fails.
"""
def validate_json(
self,
input: str | bytes | bytearray,
*,
strict: bool | None = None,
context: 'dict[str, Any] | None' = None,
self_instance: Any | None = None,
) -> Any: ...
) -> Any:
"""
Validate JSON data directly against the schema and return the validated Python object.

This method should be significantly faster than `validate_python(json.loads(json_data))` as it avoids the
need to create intermediate Python objects

It also handles constructing the correct Python type even in strict mode, where
`validate_python(json.loads(json_data))` would fail validation.

Arguments:
input: The JSON data to validate.
strict: Whether to validate the object in strict mode.
If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used.
context: The context to use for validation, this is passed to functional validators as
[`info.context`][pydantic_core.core_schema.ValidationInfo.context].
self_instance: An instance of a model set attributes on from validation.

Raises:
ValidationError: If validation fails or if the JSON data is invalid.
Exception: Other error types maybe raised if internal errors occur.

Returns:
The validated Python object.
"""
def validate_assignment(
self,
obj: Any,
Expand All @@ -104,15 +183,60 @@ class SchemaValidator:
context: 'dict[str, Any] | None' = None,
) -> dict[str, Any] | tuple[dict[str, Any], dict[str, Any] | None, set[str]]:
"""
ModelValidator and ModelFieldsValidator will return a tuple of (fields data, extra data, fields set)
Validate an assignment to a field on a model.

Arguments:
obj: The model instance being assigned to.
field_name: The name of the field to validate assignment for.
field_value: The value to assign to the field.
strict: Whether to validate the object in strict mode.
If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used.
from_attributes: Whether to validate objects as inputs to models by extracting attributes.
If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used.
context: The context to use for validation, this is passed to functional validators as
[`info.context`][pydantic_core.core_schema.ValidationInfo.context].

Raises:
ValidationError: If validation fails.
Exception: Other error types maybe raised if internal errors occur.

Returns:
Either the model dict or a tuple of `(model_data, model_extra, fields_set)`
"""
def get_default_value(self, *, strict: bool | None = None, context: Any = None) -> Some | None:
"""
Get the default value for the schema, including running default value validation.

Arguments:
strict: Whether to validate the default value in strict mode.
If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used.
context: The context to use for validation, this is passed to functional validators as
[`info.context`][pydantic_core.core_schema.ValidationInfo.context].

Raises:
ValidationError: If validation fails.
Exception: Other error types maybe raised if internal errors occur.

Returns:
`None` if the schema has no default value, otherwise a [`Some`][pydantic_core.Some] containing the default.
"""
def get_default_value(self, *, strict: bool | None = None, context: Any = None) -> Some | None: ...

_IncEx: TypeAlias = set[int] | set[str] | dict[int, _IncEx] | dict[str, _IncEx] | None

@final
class SchemaSerializer:
def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None) -> Self: ...
"""
`SchemaSerializer` is the Python wrapper for `pydantic-core`'s Rust serialization logic, internally it owns one
`CombinedSerializer` which may in turn own more `CombinedSerializer`s which make up the full schema serializer.
"""
def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None) -> Self:
"""
Create a new SchemaSerializer.

Arguments:
schema: The [`CoreSchema`][pydantic_core.core_schema.CoreSchema] to use for serialization.
config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to to configure serialization.
"""
def to_python(
self,
value: Any,
Expand All @@ -127,7 +251,32 @@ class SchemaSerializer:
round_trip: bool = False,
warnings: bool = True,
fallback: Callable[[Any], Any] | None = None,
) -> Any: ...
) -> Any:
"""
Serialize a Python object to a Python object including transforming and filtering data.

Arguments:
value: The Python object to serialize.
mode: The serialization mode to use, either `'python'` or `'json'`, defaults to `'python'`. In JSON mode,
all values are converted to JSON compatible types, e.g. `None`, `int`, `float`, `str`, `list`, `dict`.
include: A set of fields to include, if `None` all fields are included.
exclude: A set of fields to exclude, if `None` no fields are excluded.
Comment on lines +263 to +264
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The types of include and exclude are _IncEx - we may want to make that alias public and document it.

image

by_alias: Whether to use the alias names of fields.
exclude_unset: Whether to exclude fields that are not set,
e.g. are not included in `__pydantic_fields_set__`.
exclude_defaults: Whether to exclude fields that are equal to their default value.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
warnings: Whether to log warnings when invalid fields are encountered.
fallback: A function to call when an unknown value is encountered,
if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.

Raises:
PydanticSerializationError: If serialization fails and no `fallback` function is provided.

Returns:
The serialized Python object.
"""
def to_json(
self,
value: Any,
Expand All @@ -142,7 +291,31 @@ class SchemaSerializer:
round_trip: bool = False,
warnings: bool = True,
fallback: Callable[[Any], Any] | None = None,
) -> bytes: ...
) -> bytes:
"""
Serialize a Python object to JSON including transforming and filtering data.

Arguments:
value: The Python object to serialize.
indent: If `None`, the JSON will be compact, otherwise it will be pretty-printed with the indent provided.
include: A set of fields to include, if `None` all fields are included.
exclude: A set of fields to exclude, if `None` no fields are excluded.
by_alias: Whether to use the alias names of fields.
exclude_unset: Whether to exclude fields that are not set,
e.g. are not included in `__pydantic_fields_set__`.
exclude_defaults: Whether to exclude fields that are equal to their default value.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
warnings: Whether to log warnings when invalid fields are encountered.
fallback: A function to call when an unknown value is encountered,
if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised.

Raises:
PydanticSerializationError: If serialization fails and no `fallback` function is provided.

Returns:
JSON bytes.
"""

def to_json(
value: Any,
Expand Down Expand Up @@ -248,6 +421,11 @@ class SchemaError(Exception):

@final
class ValidationError(ValueError):
"""
`ValidationError` is the exception raised by `pydantic-core` when validation fails, it contains a list of errors
which detail why validation failed.
"""

@staticmethod
def from_exception_data(
title: str,
Expand All @@ -256,10 +434,17 @@ class ValidationError(ValueError):
hide_input: bool = False,
) -> ValidationError:
"""
Provisory constructor for a Validation Error.
This API will probably change and be deprecated in the the future; we will make it easier and more
powerful to construct and use ValidationErrors, but we cannot do that before our initial Pydantic V2 release.
So if you use this method please be aware that it may change or be removed before Pydantic V3.
Python constructor for a Validation Error.

The API for constructing validation errors will probably change in future,
hence the static method rather than `__init__`.

Arguments:
title: The title of the error, as used in the heading of `str(validation_error`
line_errors: A list of [`InitErrorDetails`][pydantic_core.InitErrorDetails] which contain information
about errors that occurred during validation.
error_mode: Whether the error is for a Python object or JSON.
hide_input: Whether to hide the input value in the error message.
"""
@property
def title(self) -> str: ...
Expand Down