8000 Is upcasting of builtins really necessary? · Issue #1013 · pydantic/pydantic-core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Is upcasting of builtins really necessary? #1013
Closed
@moser

Description

@moser

Hi,

when we upgraded to V2 recently, we were surprised to find that pydantic now upcasts e.g. instances of a subclass of str to str. I searched recent issues about it and only found one (Issue 7201: Incorrect parsing of bson.Int64) about the upcasting topic in general. A comment on the fixing PR (#914) from @davidhewitt said

Personally I think we want to go the other way and not upcast in both, I already can't remember why we wanted the upcast in lax mode.

So, my question is: Is the upcast really necessary (in lax mode)?

I see two problems with it:

  1. The behavior is different for builtins (or their subclasses) and regular classes (e.g. datetime or user-defined classes).
  2. Some valid use cases of subclasses of builtins are obstructed.

Our use case for subclasses of e.g. str is pretty straightforward. We often compare pydantic objects in our tests, but most of the time we are only interested in matching a subset of the fields. Thus, we came up with "matcher" classes that work like this:

from datetime import datetime
import pydantic

# Production code
class StrModel(pydantic.BaseModel):
    string: str


class DateModel(pydantic.BaseModel):
    date: datetime


# Test code
class AnyStr(str):
    def __eq__(self, other):
        return isinstance(other, str)


# Failing test
def test_any_str_matches():
    assert StrModel(string=AnyStr()) == StrModel(string="baz")
    assert StrModel(string="baz") == StrModel(string=AnyStr())


class AnyDatetime(datetime):
    def __new__(cls):
        obj = datetime.__new__(cls, 2000, 1, 1, 0, 0, 0)
        return obj

    def __eq__(self, other):
        return isinstance(other, datetime)


# Working test
def test_any_datetime_matches():
    assert DateModel(date=AnyDatetime()) == DateModel(date=datetime.now())
    assert DateModel(date=datetime.now()) == DateModel(date=AnyDatetime())

As our use case is "test-only", we do not want to litter the production code with special annotations/validators that might enable the use of the builtin subclasses.

Cheers,
Martin

Metadata

Metadata

Assignees

Labels

V3Suggested changes for pydantic and pydantic-core V3unconfirmed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0