Marshmallow: Incompatible `AwareDateTime` with pytz

Created on 9 Apr 2020  Â·  7Comments  Â·  Source: marshmallow-code/marshmallow

Hello!

As I was trying to introduce strict typing to my project I ran into an issue when integrating pytz with marshmallow. It seems that marshmallow might be requesting too strict of types. The request for only datetime timezones prevents me from using pytz with the project (even though they are compatible). The mypy maintainer suggested that marshmallow needs to integrate protocol types to be able to solve this problem, though I'll admit I'm not too sure what that means in this case. For a rundown of the issue please see:

https://github.com/python/mypy/issues/8632

question

All 7 comments

The base class is tzinfo.

Would it make any difference if we specified tzinfo rather than datetime in the typing info?

>>> issubclass(dt.timezone, dt.tzinfo)
True
>>> isinstance(pytz.timezone('Europe/Paris'), dt.tzinfo)
True
>>> isinstance(pytz.timezone('Europe/Paris'), dt.timezone)
False

@lafrech I think what needs to be specified is some subclass of dt.tzinfo, not sure how you would go about that.

Hmmm... I think the argument is a tzinfo instance, so no need for this.

Would you like to try? Install marshmallow locally, change the typing info to specify tzinfo and see how it goes with mypy in your project.

A cast or a # type: ignore are the ways to go, or you can implement a helper
function that does the (no-op) type conversion. There is no supported way to
say that two types should be treated as equivalent.

😕 The point of casting is to declare that "two types should be treated as equivalent".

This returns the value unchanged. To the type checker this signals that the return value has the designated type, but at runtime we intentionally don’t check anything

https://docs.python.org/3/library/typing.html#typing.cast

If you can guarantee that pytz.UTC provides a superset of the interface provided by timezone, then you can cast it.

from marshmallow import Schema, fields
from typing import cast
from datetime import timezone
import pytz

UTC = cast(timezone, pytz.UTC)

class ExampleSchema(Schema):
   schema_date = fields.AwareDateTime(default_timezone=UTC)

# Success: no issues found in 1 source file

The mypy maintainer suggested that marshmallow needs to integrate protocol types to be able to solve this problem

maybe marshmallow should use protocol types to define timezone types?

I think it is reasonable to expect libraries to inherit from the builtin type they are extending. Structural interfaces are slower to type check, and I don't think libraries should maintain a mirror of builtin interfaces.

My point was that perhaps we should specify datetime.tzinfo as argument type rather than datetime.timezone.

    def __init__(
        self, format: str = None, *, default_timezone: dt.tzinfo = None, **kwargs
    ):

What we actually expect is a tzinfo, not specifically a dt.timezone.

dt.timezone is a convenience class provided by Python core to implement basic timezones. pytz timezones also inherit from tzinfo, which is the right thing to do, not dt.timezone.

The change above should fix the issue IIUC.

I would mark this issue as a bug @deckar01 I'll try to implement @lafrech patch and submit a PR when I get a chance

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zohuchneg picture zohuchneg  Â·  3Comments

vke-code picture vke-code  Â·  4Comments

manoadamro picture manoadamro  Â·  3Comments

tadams42 picture tadams42  Â·  3Comments

nickretallack picture nickretallack  Â·  4Comments