Description
This code (only the first part is relevant to the bug, the second part with MyTzInfo
shows why this happens):
import datetime
import pydantic_core
# Mypy complains:
# Too many arguments for "TzInfo" [call-arg]
# But running the code works and prints "UTC".
print(pydantic_core.TzInfo(0))
# Mypy is happy with this, but running the code results in:
# TypeError: TzInfo.__new__() missing 1 required positional argument: 'seconds'
try:
print(pydantic_core.TzInfo())
except TypeError as exc:
print(f"Got error as expected: {exc}")
else:
raise AssertionError("Expected TypeError")
class MyTzInfo(datetime.tzinfo):
def tzname(self, dt: datetime.datetime | None) -> str:
return "Fake timezone"
def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta:
return datetime.timedelta(seconds=42)
def dst(self, dt: datetime.datetime | None) -> datetime.timedelta:
return datetime.timedelta(seconds=0)
def __repr__(self) -> str:
return f"MyTzInfo: {self.tzname(None)}"
# Mypy compains with this as well, but running the code works as `datetime.tzinfo` ignores its
# arguments.
print(MyTzInfo())
print(MyTzInfo(0))
print(MyTzInfo(0, "foo", 42))
Produces this output:
UTC
Got error as expected: TzInfo.__new__() missing 1 required positional argument: 'seconds'
MyTzInfo: Fake timezone
MyTzInfo: Fake timezone
MyTzInfo: Fake timezone
The problem is that datetime.tzinfo
ignores any argument passed to it, but it's annotated in typeshed as not accepting any argument.
In pydantic_core, the interface for TzInfo
is defined as a final class TzInfo(datetime.tzinfo)
which doesn't have an __init__
, so mypy assumes it doesn't accept arguments. On the other hand, the implementation requires the number of seconds.
I'm using the most recent version of pydantic and mypy from PyPi:
$ pip show mypy
Name: mypy
Version: 1.14.1
Summary: Optional static typing for Python
Home-page:
Author:
Author-email: Jukka Lehtosalo <jukka.lehtosalo@iki.fi>
License: MIT
Location: /Users/bari/.pyenv/versions/3.10.1/envs/tmp3.10/lib/python3.10/site-packages
Requires: typing_extensions, mypy_extensions, tomli
Required-by:
$ pip show pydantic_core
Name: pydantic_core
Version: 2.27.2
Summary: Core functionality for Pydantic validation and serialization
Home-page: https://github.com/pydantic/pydantic-core
Author:
Author-email: Samuel Colvin <s@muelcolvin.com>
License: MIT
Location: /Users/bari/.pyenv/versions/3.10.1/envs/tmp3.10/lib/python3.10/site-packages
Requires: typing-extensions
Required-by: pydantic
Note that, in practice, I don't need to use pydantic.TzInfo
in my production code. I'm only using it in some unit tests as my code previously tripped up when dealing with pydantic converting Python's native datetime.timezone.utc
.