Skip to content

code in "Combining Pydantic and semver" doc contains bug on serialization to json. #429

@apiwat-chantawibul

Description

@apiwat-chantawibul

Situation

The code defining ManifestVersion in "Combining Pydantic and semver" documentation

from typing import Annotated, Any, Callable
from pydantic import GetJsonSchemaHandler
from pydantic_core import core_schema
from pydantic.json_schema import JsonSchemaValue
from semver import Version
class _VersionPydanticAnnotation:
@classmethod
def __get_pydantic_core_schema__(
cls,
_source_type: Any,
_handler: Callable[[Any], core_schema.CoreSchema],
) -> core_schema.CoreSchema:
def validate_from_str(value: str) -> Version:
return Version.parse(value)
from_str_schema = core_schema.chain_schema(
[
core_schema.str_schema(),
core_schema.no_info_plain_validator_function(validate_from_str),
]
)
return core_schema.json_or_python_schema(
json_schema=from_str_schema,
python_schema=core_schema.union_schema(
[
core_schema.is_instance_schema(Version),
from_str_schema,
]
),
serialization=core_schema.plain_serializer_function_ser_schema(
lambda instance: instance.x
),
)
@classmethod
def __get_pydantic_json_schema__(
cls, _core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler
) -> JsonSchemaValue:
return handler(core_schema.str_schema())
ManifestVersion = Annotated[Version, _VersionPydanticAnnotation]

has a bug when ManifestVersion is used for serialization to JSON, resulting in the following raised exception:

pydantic_core._pydantic_core.PydanticSerializationError: Error calling function `<lambda>`: AttributeError: 'Version' object has no attribute 'x'

To Reproduce

from pydantic import TypeAdapter
from semver import Version

version = Version.parse('1.2.3')
json_version = TypeAdapter(ManifestVersion).dump_json(version)

Expected Behavior

is described in the following pytest module.
(with the ManifestVersion defined in __init__.py.)

import json
import pytest
from pydantic import TypeAdapter
from semver import Version

from . import ManifestVersion


@pytest.mark.parametrize(
    'version',
    [
        '0.0.1',
        '1.9.8',
        '2.3.4-rc+generic',
        '11.12.13-0.1.2',
    ],
)
def test_serialize(version):
    expected_json = json.dumps(version).encode()
    expected_python = version = Version.parse(version)

    result_python = TypeAdapter(ManifestVersion).dump_python(version)
    result_json = TypeAdapter(ManifestVersion).dump_json(version)

    assert result_python == expected_python
    assert result_json == expected_json

Solution

Change

serialization=core_schema.plain_serializer_function_ser_schema(
lambda instance: instance.x
),

to

serialization = core_schema.to_string_ser_schema(),

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions