pythondeprecatedpyright

Pylance doesn't catch all deprecated functions or classes


I recently upgraded our app's Python version from 3.8 to 3.12, which necessitated upgrading several libraries that were not compatible with the new Python version. Since then, I've encountered issues with some functions and classes being deprecated.

I'm using Pylance in Visual Studio Code, and while it does catch some deprecated objects, such as: pylance deprecated warning

it fails to catch other deprecated classes that I only discover at runtime, like flask.json.JSONEncoder:

flask.json.JSONEncoder

Both deprecations are indicated in their implementations:

Datetime.datetime.utcnow:

@classmethod
def utcnow(cls):
    "Construct a UTC datetime from time.time()."
    import warnings
    warnings.warn("datetime.datetime.utcnow() is deprecated and scheduled for "
                  "removal in a future version. Use timezone-aware "
                  "objects to represent datetimes in UTC: "
                  "datetime.datetime.now(datetime.UTC).",
                  DeprecationWarning,
                  stacklevel=2)
    t = _time.time()
    return cls._fromtimestamp(t, True, None)

flask.json.JSONEncoder:

    def __init__(self, **kwargs) -> None:
        import warnings

        warnings.warn(
            "'JSONEncoder' is deprecated and will be removed in"
            " Flask 2.3. Use 'Flask.json' to provide an alternate"
            " JSON implementation instead.",
            DeprecationWarning,
            stacklevel=3,
        )
        super().__init__(**kwargs)


Why does Pylance catch some deprecated objects but not others, leaving some to be revealed only at runtime?

And are there any tools that can catch those deprecations statically?


Solution

  • Pyright/Pylance caught utcnow() because it was explicitly marked as deprecated in typeshed, which is the standard library's source of static typing:

    class timezone(tzinfo):
        ...
        @deprecated("Use timezone-aware objects to represent datetimes in UTC; e.g. by calling .now(datetime.UTC)")
        def utcnow(cls) -> Self: ...
    

    On the other hand, flask.json.JSONEncoder was not.

    @deprecated, which will be introduced to Python 3.13's warnings via PEP 702, can already be imported from typing_extensions. The two implementations are exactly the same and thus have the same runtime effects of raising DeprecationWarnings.