Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update pydantic-core to 2.4.0 #6831

Merged
merged 3 commits into from Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 61 additions & 0 deletions docs/errors/validation_errors.md
Expand Up @@ -1892,6 +1892,67 @@ except ValidationError as exc:
#> 'url_type'
```

## `uuid_parsing`

This error is raised when the input value's type is not valid for a UUID field:

```py
from uuid import UUID

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
u: UUID


try:
Model(u='12345678-124-1234-1234-567812345678')
except ValidationError as exc:
print(repr(exc.errors()[0]['type']))
#> 'uuid_parsing'
```

## `uuid_type`

This error is raised when the input value's type is not valid instance for a UUID field (str, bytes or UUID):

```py
from uuid import UUID

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
u: UUID


try:
Model(u=1234567812412341234567812345678)
except ValidationError as exc:
print(repr(exc.errors()[0]['type']))
#> 'uuid_type'
```

## `uuid_version`

This error is raised when the input value's type is not match UUID version:

```py
from pydantic import UUID5, BaseModel, ValidationError


class Model(BaseModel):
u: UUID5


try:
Model(u='a6cc5730-2261-11ee-9c43-2eb5a363657c')
except ValidationError as exc:
print(repr(exc.errors()[0]['type']))
#> 'uuid_version'
```

## `value_error`

This error is raised when a `ValueError` is raised during validation:
Expand Down
206 changes: 103 additions & 103 deletions pdm.lock

Large diffs are not rendered by default.

37 changes: 3 additions & 34 deletions pydantic/_internal/_std_types_schema.py
Expand Up @@ -373,40 +373,9 @@ def uuid_prepare_pydantic_annotations(
if source_type is not UUID:
return None

def uuid_validator(input_value: str | bytes | UUID) -> UUID:
if isinstance(input_value, UUID):
return input_value
try:
if isinstance(input_value, str):
return UUID(input_value)
else:
try:
return UUID(input_value.decode())
except ValueError:
# 16 bytes in big-endian order as the bytes argument fail
# the above check
return UUID(bytes=input_value)
except ValueError:
raise PydanticCustomError('uuid_parsing', 'Input should be a valid UUID, unable to parse string as an UUID')

from_primitive_type_schema = core_schema.no_info_after_validator_function(
uuid_validator, core_schema.union_schema([core_schema.str_schema(), core_schema.bytes_schema()])
)
lax = core_schema.json_or_python_schema(
json_schema=from_primitive_type_schema,
python_schema=core_schema.union_schema(
[core_schema.is_instance_schema(UUID), from_primitive_type_schema],
),
)

strict = core_schema.json_or_python_schema(
json_schema=from_primitive_type_schema,
python_schema=core_schema.is_instance_schema(UUID),
)

schema = core_schema.lax_or_strict_schema(
lax_schema=lax,
strict_schema=strict,
schema = core_schema.uuid_schema(
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we use the InnerSchemaValidator here?

Copy link
Member

Choose a reason for hiding this comment

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

I think this is fine.

# TODO: this shouldn't be necessary, but avoids a UserWarning emitted
# when serializing a string
serialization=core_schema.to_string_ser_schema(),
)

Expand Down
11 changes: 11 additions & 0 deletions pydantic/json_schema.py
Expand Up @@ -1657,6 +1657,17 @@ def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonS
self.update_with_validations(json_schema, schema, self.ValidationsMapping.string)
return json_schema

def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue:
"""Generates a JSON schema that matches a UUID.

Args:
schema: The core schema.

Returns:
The generated JSON schema.
"""
return {'type': 'string', 'format': 'uuid'}

def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue:
"""Generates a JSON schema that matches a schema that defines a JSON object with definitions.

Expand Down
11 changes: 1 addition & 10 deletions pydantic/types.py
Expand Up @@ -542,16 +542,7 @@ def __get_pydantic_json_schema__(
def __get_pydantic_core_schema__(
self, source: Any, handler: _annotated_handlers.GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.general_after_validator_function(
cast(core_schema.GeneralValidatorFunction, self.validate), handler(source)
)

def validate(self, value: UUID, _: core_schema.ValidationInfo) -> UUID:
if value.version != self.uuid_version:
raise PydanticCustomError(
'uuid_version', 'uuid version {required_version} expected', {'required_version': self.uuid_version}
)
return value
return core_schema.uuid_schema(version=self.uuid_version)

def __hash__(self) -> int:
return hash(type(self.uuid_version))
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -61,7 +61,7 @@ requires-python = '>=3.7'
dependencies = [
'typing-extensions>=4.6.1',
'annotated-types>=0.4.0',
"pydantic-core==2.3.1",
"pydantic-core==2.4.0",
]
dynamic = ['version', 'readme']

Expand Down
52 changes: 17 additions & 35 deletions tests/test_types.py
Expand Up @@ -109,6 +109,7 @@
except ImportError:
email_validator = None


# TODO add back tests for Iterator


Expand Down Expand Up @@ -2671,18 +2672,12 @@ def test_uuid_error():
# insert_assert(exc_info.value.errors(include_url=False))
assert exc_info.value.errors(include_url=False) == [
{
'type': 'is_instance_of',
'loc': ('is-instance[UUID]',),
'msg': 'Input should be an instance of UUID',
'loc': (),
'msg': 'Input should be a valid UUID, invalid group length in group 4: expected 12, found 5',
'input': 'ebcdab58-6eb8-46fb-a190-d07a3',
'ctx': {'class': 'UUID'},
},
{
'ctx': {'error': 'invalid group length in group 4: expected 12, found 5'},
'type': 'uuid_parsing',
'loc': ('function-after[uuid_validator(), union[str,bytes]]',),
'msg': 'Input should be a valid UUID, unable to parse string as an UUID',
'input': 'ebcdab58-6eb8-46fb-a190-d07a3',
},
}
]

not_a_valid_input_type = object()
Expand All @@ -2691,23 +2686,10 @@ def test_uuid_error():
# insert_assert(exc_info.value.errors(include_url=False))
assert exc_info.value.errors(include_url=False) == [
{
'type': 'is_instance_of',
'loc': ('is-instance[UUID]',),
'msg': 'Input should be an instance of UUID',
'input': not_a_valid_input_type,
'ctx': {'class': 'UUID'},
},
{
'type': 'string_type',
'loc': ('function-after[uuid_validator(), union[str,bytes]]', 'str'),
'msg': 'Input should be a valid string',
'input': not_a_valid_input_type,
},
{
'type': 'bytes_type',
'loc': ('function-after[uuid_validator(), union[str,bytes]]', 'bytes'),
'msg': 'Input should be a valid bytes',
'input': not_a_valid_input_type,
'loc': (),
'msg': 'UUID input should be a string, bytes or UUID object',
'type': 'uuid_type',
},
]

Expand Down Expand Up @@ -2760,30 +2742,30 @@ class UUIDModel(BaseModel):
{
'type': 'uuid_version',
'loc': ('a',),
'msg': 'uuid version 1 expected',
'msg': 'UUID version 1 expected',
'input': d,
'ctx': {'required_version': 1},
'ctx': {'expected_version': 1},
},
{
'type': 'uuid_version',
'loc': ('b',),
'msg': 'uuid version 3 expected',
'msg': 'UUID version 3 expected',
'input': c,
'ctx': {'required_version': 3},
'ctx': {'expected_version': 3},
},
{
'type': 'uuid_version',
'loc': ('c',),
'msg': 'uuid version 4 expected',
'msg': 'UUID version 4 expected',
'input': b,
'ctx': {'required_version': 4},
'ctx': {'expected_version': 4},
},
{
'type': 'uuid_version',
'loc': ('d',),
'msg': 'uuid version 5 expected',
'msg': 'UUID version 5 expected',
'input': a,
'ctx': {'required_version': 5},
'ctx': {'expected_version': 5},
},
]

Expand Down Expand Up @@ -4730,7 +4712,7 @@ class Model(BaseModel):
x: Union[int, Annotated[str, Field(max_length=max_length)]]

v = Model(x=MyStr('1')).x
assert type(v) is MyStr
assert type(v) is str
assert v == '1'


Expand Down