Skip to content

Json[SomeType] does not deserialize value if SomeType is a TypeVar #2860

@anatoly-scherbakov

Description

@anatoly-scherbakov

Checks

  • I added a descriptive title to this issue
  • I have searched (google, github) for similar issues and couldn't find anything
  • I have read and followed the docs and still think this is a bug

Bug

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.8.2
            pydantic compiled: True
                 install path: /home/anatoly/projects/customer-types-distributor/venv/lib/python3.8/site-packages/pydantic
               python version: 3.8.6 (default, Dec 28 2020, 18:55:09)  [GCC 9.3.0]
                     platform: Linux-5.4.0-73-generic-x86_64-with-glibc2.29
     optional deps. installed: ['typing-extensions']

Context. Working with Amazon Web Services, I am trying to create a Pydantic helper to deserialize incoming data a Lambda function receives from SQS queue. I am using generic models so as to make this definition reusable. I also use Json type because part of the information is represented as JSON string.

Attempted solution.

import json
from typing import Generic, TypeVar, List

from pydantic import Json, BaseModel
from pydantic.generics import GenericModel

RecordType = TypeVar('RecordType')


class SQSRecord(GenericModel, Generic[RecordType]):
    """Individual SQS event record."""

    json_body: Json[RecordType]
    list_body: List[RecordType]


class Cat(BaseModel):
    """Cat description."""

    name: str
    color: str


class SQSCatRecord(SQSRecord[Cat]):
    """Cat descriptions from SQS queue."""


def test_sqs_cat_record():
    raw_record = {
        'json_body': json.dumps({
            'name': 'Spike',
            'color': 'black',
        }),
        'list_body': [{
            'name': 'Spike',
            'color': 'black',
        }],
    }

    record = SQSCatRecord(**raw_record)

    # This works, because List[RecordType] decodes the data
    assert isinstance(record.list_body[0], Cat)

    # This fails, because Json[RecordType] does not
    assert isinstance(record.json_body, Cat), (
        f'{record.json_body} is not a Cat instance.'
    )


if __name__ == '__main__':
    test_sqs_cat_record()

Its output:

AssertionError: {'Name': 'Spike', 'color': 'black'} is not a Cat instance.

It seems that Json with a type argument that is a TypeVar expects a dict, instead of trying to deserialize using the provided Cat model.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug V1Bug related to Pydantic V1.X

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions