Wednesday 27 April 2022

Mypy 0.950 Released

We’ve just uploaded mypy 0.950 to the Python Package Index (PyPI). Mypy is a static type checker for Python. This release includes new features and bug fixes. You can install it as follows:

    python3 -m pip install -U mypy

You can read the full documentation for this release on Read the Docs.

Pinning Third-Party Library Stub Versions

Recent third-party library stubs available via types-* packages (e.g. types-requests) are actively using recent typing features that may not be supported by older mypy releases. We recommend that if you pin mypy to a specific version, you should also pin any stub packages to a version no more recent than the mypy release. Otherwise the mypy version you use may silently fall back to Any types if it encounters annotation syntax that it can’t process. It’s fine to continue using older versions of stubs when you upgrade mypy.

Note also that recent versions of many third-party stub packages don’t support Python 2 any more. If you are using mypy to type check Python 2 code, it’s important to pin all stub packages to versions that still support Python 2. Generally stub package versions released in Feb 2022 or earlier still support Python 2 (assuming that they supported Python 2 at all).

New Features: Concatenate and Literals with ParamSpec

It’s now possible to precisely annotate decorators that add/remove arguments, using ParamSpec together with typing.Concatenate (Python 3.10 or later) or typing_extensions.Concatenate. The decorator in this example provides an implicit Request argument to the decorated function:

    from typing import ParamSpec, TypeVar, Callable, Concatenate

    P = ParamSpec("P")
    T = TypeVar(T")

    def my_decorator(f: Callable[Concatenate[Request, P], T]
                    ) -> Callable[P, T]:
        def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
            r = current_request()
            return f(r, *args, **kwargs)
        return wrapper

    @my_decorator
    def my_func(request: Request, x: int) -> str:
        # do something ...
        return ...

    def func2() -> str:
        return my_func(x=2)  # OK, the request argument is implicit

You can provide the value of a ParamSpec explicitly using the [T1, …, Tn] syntax. This example illustrates the use case:

    from typing import ParamSpec, TypeVar, Generic, Callable

    P = ParamSpec("P")
    T = TypeVar("T")

    class CallCounter(Generic[P, T]):
        def __init__(self, fn: Callable[P, T]):
            self.fn = fn
            self.count = 0

        def invoke(self, *args: P.args, **kwargs: P.kwargs) -> T:
            self.count += 1
            return self.fn(*args, **kwargs)

    # The [str] below specifies the value of P (one positional 
    # argument of type str)
    def ensure_n_calls(cc: CallCounter[[str], None], 
                       n: int, arg: str) -> None:
        while cc.count < n:
            cc.invoke(arg)

This experimental support for ParamSpec Concatenate and literals was contributed by EXPLOSION (PR 11847).

New Feature: Detect Unused Coroutines and Awaitables

Now mypy will give an error if you forget to await a coroutine:

    async def log(message: str) -> None:
        ...

    async def do_stuff() -> None:
        # Error: Value of type "Coroutine[Any, Any, None]" 
        #        must be used
        log("doing stuff")  # Oops, no "await"
        ...

If you enable the unused-awaitable error code, mypy will also complain about any unused value that supports __await__. This is not enabled by default, since this can cause false positives.

This feature was contributed by Jared Hance (PR 12279).

New Feature: assert_type

You can now use typing_extensions.assert_type to ask mypy to validate that an expression has a specific static type. Mypy will report an error if the inferred type is not as expected:

    from typing_extensions import assert_type

    assert_type([1], list[int])  # OK

    # Error: Expression is of type "List[int]", not "List[str]"
    assert_type([1], list[str])

This can be used to validate that the expected type is inferred by mypy when calling a complex overloaded function, for example. At runtime assert_type just returns the first argument and doesn’t perform a runtime type check.

This was contributed by Jelle Zijlstra (PR 12612, PR 12584).

Mypyc Fixes and Improvements

  • Fix overflow in id built-in (Ekin Dursun, PR 12332)
  • Simplify generated code for native attribute get (Jukka Lehtosalo, PR 11978)
  • Implement close method for generators (Max Shvets, PR 12042)
  • Use more accurate flags with msvc (KotlinIsland, PR 12468)
  • Fix potential memory leak with setdefault() (Jukka Lehtosalo, PR 12514)
  • Make boxed integer constants/literals faster (Jukka Lehtosalo, PR 12507)

Performance Improvements

Mypy now type checks somewhat faster, in particular when dealing with enums and unions with many items.

  • Speed up union types (Jukka Lehtosalo, PR 12541, PR 12519)
  • Speed up subtype checks (Jukka Lehtosalo, PR 12540, PR 12538, PR 12536, PR 12539)
  • Speed up type checking enums (Hugues, PR 12032)
  • Speed up union types further (Hugues, PR 12630)

Documentation Improvements

  • Use Furo theme for documentation (97littleleaf11, PR 12348)
  • Add missing enable_error_code to config documentation (Mathieu Kniewallner, PR 12346)
  • Correct example in “Annotation issues at runtime” (Alex Waygood, PR 12356)
  • Fix inaccuracy: NoneType is exposed in the types module on Python 3.10+ (Alex Waygood, PR 12515)

Stubgen Improvements

  • Fix handling of Protocol (citruz, PR 12129)
  • Use _typeshed.Incomplete instead of typing.Any (Sebastian Rittau, PR 12449)
  • Do not consider nested generators (Štěpán Horáček, PR 12463)
  • Fix behavior for instance variables in C extensions (Shubham SInghal, PR 12524)

Stubtest Improvements

  • Generate error for read-only property at runtime, but not in stub (Alex Waygood, PR 12291)
  • Enable verification of __match_args__ attributes (Alex Waygood, PR 12465)

Other Notable Fixes and Improvements

  • Use tomllib on Python 3.11 (Shantanu, PR 12305)
  • Print compilation status with --version (Shantanu, PR 12318)
  • Fix __annotations__ being undefined (Niklas Gustafsson, PR 10969)
  • Add success message for notes-only output (97littleleaf11, PR 12306)
  • dmypy: Warn instead of failing if report generation is configured (Nate McMaster, PR 10181)
  • Fix caching of PEP 561 namespace packages with missing submodules (Shantanu, PR 12250)
  • Fix empty reveal_locals output (Cibin Mathew, PR 12400)
  • Check that async for/with is inside an async function (Štěpán Horáček, PR 12418)
  • Recognize Hashable as a real protocol (Nikita Sobolev, PR 11802)
  • Remove the * for inferred types from reveal_type output (Stanislav K, PR 12459)
  • Unify a codepath in typevarlike semanal (Jared Hance, PR 12480)
  • Recognise both attrs and attr package names (Spencer Brown, PR 12469)
  • Fix Callable attributes in frozen dataclasses (Jordan Speicher, PR 12383)
  • Improve checking of __slots__ (Jukka Lehtosalo, PR 12531)
  • Avoid conflicts between type variables defined in different classes (Jukka Lehtosalo, PR 12590)
  • Fix __slots__ and __deletable__ in incremental mode (Jukka Lehtosalo, PR 12645)
  • Fix issue with ParamSpec serialization (Jukka Lehtosalo, PR 12654)
  • Fix types of inherited attributes in generic dataclasses (Jukka Lehtosalo, PR 12656)

Typeshed Updates

Typeshed is now modular and distributed as separate PyPI packages for everything except the standard library stubs. Please see git log for full list of typeshed changes.

Acknowledgements

Thanks to all mypy contributors who contributed to this release:

  • 97littleleaf11
  • Akuli
  • Alex Waygood
  • Chris Rose
  • Cibin Mathew
  • citruz
  • EXPLOSION
  • Ekin Dursun
  • Géry Ogam
  • gresm
  • Hugues
  • Ikko Ashimine
  • Jared Hance
  • Jelle Zijlstra
  • Jordan Speicher
  • Kevin Mai-Husan Chia
  • KotlinIsland
  • luzpaz
  • Marc Mueller
  • Mathieu Kniewallner
  • Max Shvets
  • mixed-source
  • Nate McMaster
  • Nikita Sobolev
  • Niklas Gustafsson
  • Petter Friberg
  • Sebastian Rittau
  • Shantanu
  • Shubham SInghal
  • Spencer Brown
  • Stanislav K
  • Stanislav Levin
  • Štěpán Horáček

I’d also like to thank my employer, Dropbox, for funding the mypy core team.