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

Datetime underflow causes validation to fail #1223

Closed
hamilton-earthscope opened this issue Mar 12, 2024 · 1 comment
Closed

Datetime underflow causes validation to fail #1223

hamilton-earthscope opened this issue Mar 12, 2024 · 1 comment

Comments

@hamilton-earthscope
Copy link

Hi Pydantic team, thanks for the great library!!

I'm reporting a bug that looks to me like an underflow issue when validating datetimes are greater than a given datetime.

Here's a reproducible example. I'm using Pydantic v2.6.4. Which is the latest at the time of writing.

import datetime as dt

from annotated_types import Ge, Lt
from pydantic import AwareDatetime, BaseModel, ValidationError

MyDatetime = Annotated[
    AwareDatetime,
    Ge(dt.datetime(1900, 1, 1, tzinfo=dt.timezone.utc)),
]

class TestModel(BaseModel):
    t: MyDatetime


@pytest.mark.parametrize(
    "t, exp_throws",
    [
        ("1500-01-01T00:00:00+00:00", True), # doesn't throw!!!
        ("1600-01-01T00:00:00+00:00", True),
        ("1899-12-31T23:59:59.999999+00:00", True),
        ("1900-01-01T00:00:00+00:00", False),
        ("2024-12-31T00:00:00+00:00", False),
    ],
)
def test_time_constraints(t: str, exp_throws: bool):
    if exp_throws:
        with pytest.raises(ValidationError) as e:
            TestModel(t=t)
        assert "greater than or equal" in str(e)
    else:
        m = TestModel(t=t)
        assert m.t.isoformat() == t

The reason I think it's an underflow issue is that if I change my model to

MyDatetime = Annotated[
    AwareDatetime,
    Ge(dt.datetime(1900, 1, 1, tzinfo=dt.timezone.utc)),
    Lt(dt.datetime(2030, 1, 1, tzinfo=dt.timezone.utc)),
]

Then I get a validation error for 1500-01-01T00:00:00Z that it should be less than 2030-01-01T00:00:00Z.

I reproduced the same thing by constructing the schema directly.

class MyDatetime:
    """A datetime that requires timezone info and a sane year."""

    @classmethod
    def __get_pydantic_core_schema__(
        cls, source: type[Any], handler: GetCoreSchemaHandler
    ) -> core_schema.CoreSchema:
        schema_args = {
            "tz_constraint": "aware",
            "ge": dt.datetime(1900, 1, 1, tzinfo=dt.timezone.utc),
            "lt": dt.datetime(2030, 1, 1, tzinfo=dt.timezone.utc),
        }
        if cls is source:
            return core_schema.datetime_schema(**schema_args)
        else:
            schema = handler(source)
            schema.update(schema_args)
            return schema

    def __repr__(self) -> str:
        return "MyDatetime"

I can work around this by using an AfterValidator and performing the Ge/Lt validation in python-land.

Cheers.

@davidhewitt
Copy link
Contributor

Agreed, I think a duplicate of pydantic/pydantic#8570, which has a proposed fix by erroring in pydantic/speedate#55 but that got stuck after I suggested instead fixing the underflow. I see you also agree with my assessment that fixing the underflow is the right solution 😂

@davidhewitt davidhewitt closed this as not planned Won't fix, can't repro, duplicate, stale Mar 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants