Friday, 5 May 2017

Mypy 0.510 Released

We’ve just uploaded mypy 0.510 to PyPI. This release adds new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install --upgrade mypy

Note: Remember that the package name is now mypy (no longer mypy-lang).

Update (10 May): Released mypy 0.511 that fixes two crash bugs but is otherwise identical to 0.510.

Overloads in Source Files

Previously the @overload decorator was only supported in stub files. Now you can use it in regular source files as well. First write some @overload declarations that define the different signatures your function supports. These should have empty bodies and are only used by mypy. Put the actual runtime definition of the function after these declarations, without a decorator. Here’s an example from the mypy documentation:

    from typing import overload, Sequence, TypeVar, Union
    T = TypeVar('T')

    class MyList(Sequence[T]):

        # The @overload definitions are just for the type checker,
        # and overwritten by the real implementation below.
        @overload
        def __getitem__(self, index: int) -> T:
            pass  # Don't put code here

        # All overloads and the implementation must be adjacent
        # in the source file, and overload order may matter:
        # when two overloads may overlap, the more specific one
        # should come first.
        @overload
        def __getitem__(self, index: slice) -> Sequence[T]:
            pass  # Don't put code here

        # The implementation goes last, without @overload.
        # It may or may not have type hints; if it does,
        # these are checked against the overload definitions
        # as well as against the implementation body.
        def __getitem__(self, index):
            # This is exactly the same as before.
            if isinstance(index, int):
                ...  # Return a T here
            elif isinstance(index, slice):
                ...  # Return a sequence of Ts here
            else:
                raise TypeError(...)

This was contributed by Naomi Seyfer.

Extended Callable Types

As an experimental mypy extension, you can specify Callable types that support keyword arguments, optional arguments, and more. Where you specify the arguments of a Callable, you can choose to supply just the type of a nameless positional argument, or an "argument specifier" representing a more complicated form of argument, using helpers such as Arg and DefaultArg that are defined in the mypy_extensions module. This allows one to more closely emulate the full range of possibilities given by Python’s def statement.

As an example, here's a complicated function definition and the corresponding Callable:

    from typing import Callable
    from mypy_extensions import (Arg, DefaultArg, NamedArg,
                                 DefaultNamedArg, VarArg, KwArg)

    def func(__a: int, # This convention is for nameless arguments
             b: int,
             c: int = 0,
             *args: int,
             d: int,
             e: int = 0,
             **kwargs: int) -> int:
        ...

    F = Callable[[int,            # Or Arg(int); an argument without a name
                  Arg(int, 'b'),  # Argument with name and type
                  DefaultArg(int, 'c'),  # Argument that may be omitted
                  VarArg(int),    # *args argument
                  NamedArg(int, 'd'),  # Must be passed as a keyword argument
                  DefaultNamedArg(int, 'e'),  # Like above, but may be omitted
                  KwArg(int)],    # **kwargs argument
                 int]  # Return type

    f: F = func

To use this, you need to install mypy_extensions:

    python3 -m pip install --upgrade mypy_extensions

This was contributed by Naomi Seyfer.

ClassVar

You can mark names intended to be used as class variables with ClassVar. In a pinch you can also use ClassVar in # type comments. This is supported by the typing module that ships with Python 3.6 (it is part of PEP 526). Example:

    from typing import ClassVar

    class C:
        x: int # instance variable
        y: ClassVar[int] # class variable
        z = None # type: ClassVar[int]

        def foo(self) -> None:
            self.x = 0  # OK
            self.y = 0  # Error: Cannot assign to class variable "y" via instance

    C.y = 0 # This is OK

This was contributed by Dominik Miedziński.

Quick Mode

Run mypy with the --quick-and-dirty (or just --quick) option to try a new experimental, unsafe variant of incremental mode. Quick mode is faster than regular incremental mode, because it only re-checks modules that were modified since their cache file was last written; regular incremental mode also re-checks all modules that depend on one or more modules that were re-checked.

Quick mode is unsafe because it may miss problems caused by a change in a dependency, so you should not use it in a continuous integration build, and you should perhaps run mypy without quick mode before landing commits. Quick mode updates the cache, but regular incremental mode ignores cache files written by quick mode.

Functional API for Enum

Mypy now also supports the functional API for defining an Enum. Previously you had to define a class deriving from Enum. Example (other forms are also supported):

    Color = Enum('Color', 'red blue green')

    Color.red    # Ok
    Color.black  # "Color" has no attribute "black"

Improvements to None Handling

Mypy now treats the None type more consistently between the default checking mode and the strict optional checking mode. Unlike previously, None is largely treated as a regular type, and things like List[None] mean what you’d expect: a list containing None values. Additionally, this idiom no longer generates an error:

    def f() -> None: ...

    def g() -> None:
        return f()  # Okay

Generators and Async Comprehensions (PEP 525 and PEP 530)

Python 3.6 allows coroutines defined with async def to be generators — they may contain yield statements and expressions. It also introduces a syntax for asynchronous comprehensions. Mypy now supports these features. Here’s an example from the mypy documentation:

    from typing import AsyncIterator

    async def gen() -> AsyncIterator[bytes]:
        lst = [b async for b in gen()]  # Inferred type is "List[bytes]"
        yield 'no way'  # Error: Incompatible types (got "str", expected "bytes")

This was contributed by Jelle Zijlstra.

Functions Returning Generic Functions

Mypy now understands that a function may return a generic function. A typical use case is a function that returns a decorator:

    from typing import TypeVar, Callable, Any, cast

    T = TypeVar('T', bound=Callable[..., Any])

    def logged(description: str) -> Callable[[T], T]:
        def decorator(f: T) -> T:
            def wrapper(*args, **kwargs):
                print('entering:', description)
                value = f(*args, **kwargs)
                print('leaving:', description)
            return cast(T, wrapper)
        return decorator

    @logged('system initialization')
    def init() -> None:
        print('do something')

    init(1)  # Too many arguments (signature is correctly preserved)

This was contributed by Naomi Seyfer.

Don’t Simplify Unions Containing Any

Unions containing Any, such as Union[int, Any], are now handled consistently. Previously in some cases mypy would simplify these into just Any, which is not equivalent. This could result in mypy failing to generate errors for buggy code. All operations performed on a union-typed value much be valid for every union item. For example, adding a string to a Union[int, Any] value is an error, since you can’t add a string and an integer. If the union was simplified to Any, mypy would not detect this error, since anything can be added to Any.

Prohibit Parametrizing Built-in Types

You no longer can write list[int] (with lower case l) in type annotations, as this doesn’t work at runtime. The also applies to dict and other types that have capitalized aliases in typing. Use List, Dict and so on (defined in typing) in type annotations. Note that this may require many changes to existing type annotations.

This was contributed by Ivan Levkivskyi.

More New Features

  • Support arbitrary member access on Type[Any] so that it’s possible to access class methods and attributes. (Daniel F Moisset)
  • Allow keyword arguments in __call__. (Ivan Levkivskyi)
  • Infer types from issubclass() calls, similar to isinstance(). (Max Moroz)
  • Always write the cache for incremental checking (unless cache_dir is /dev/null).
  • Use types.ModuleType instead of module, since the latter doesn’t exist at runtime. (Max Moroz)
  • Make it an error to use a class-attribute type variable outside a type. (Naomi Seyfer)
  • Allow importing NoReturn from typing. (Ivan Levkivskyi)
  • Reject TypeVar with only one constraint, since these never make sense. (Michael Lee)
  • Allow instantiation of Type[A], if A is abstract. (Ivan Levkivskyi)
  • Allow unions and nested tuples in except handlers. (Jelle Zijlstra)
  • Treat type as equivalent to Type[Any]. (Ivan Levkivskyi)
  • Make Type[T] compatible with Callable[..., T]. (Dominik Miedziński)
  • Always use the default Python 3 version to parse stub files, so that Python 3.6 features can be used in stub files.
  • Support default values for items in NamedTuple class definitions. (Jelle Zijlstra)
  • Reject generic types as the second argument to isinstance or issubclass, since they don’t work at runtime. (Max Moroz)
  • Allow variable as a type in isinstance. (Max Moroz)
  • Support Type[x] and type with isinstance. (Max Moroz)
  • Allow isinstance/issubclass with nested tuples. (Max Moroz)
  • Improve type inference of containers containing callables or overloads. (Ivan Levkivskyi)
  • Add support for type aliases typing.ChainMap, typing.Counter, typing.DefaultDict and typing.Deque. (Jelle Zijlstra)
  • Improvements to TypedDict (this feature is still incomplete and undocumented). (Roy Williams, Max Moroz and Ivan Levkivskyi)

Removed or Deprecated Features

  • The old parser that was available through --no-fast-parser is no longer supported.
  • Deprecate --strict-boolean and don’t enable it with --strict. (Max Moroz)
  • Drop Python 3.2 as a type checking target, since it has reached its end of life.
  • The stubs for sqlalchemy were dropped since they were incomplete and caused problems with common idioms. The stubs now live in a separate repository.

Notable Bugs Fixed

  • Fixes to various crashes. (Ivan Levkivskyi, Max Moroz and Jelle Zijlstra)
  • Fixes to incremental mode.
  • Fix bugs related to narrowing down unions using runtime checks.
  • Fix unions containing both bool and float.
  • Make union simplification be independent of the order of union items.
  • Fixes to confusing error messages due to dict displays. (Daniel F Moisset)
  • Fix subtyping for type variables whose upper bound is a union. (Max Moroz)
  • Fix invalid complaints about f-string expressions. (Ingmar Steen)
  • Fix isinstance check with nested unions. (Ivan Levkivskyi)
  • Work around random failures on writing cache files on Windows.
  • Fixes to % formatting. (Jelle Zijlstra)
  • Fixes to nested classes. (Elazar Gershuni)
  • Disallow generic Enums as they don’t work. (Jelle Zijlstra)

Other Changes

  • Require version 1.0.3 of typed-ast to run mypy.
  • Mypy developers on Windows must run certain git commands as Administrator. This only affects the mypy and typeshed git repositories.
  • Add stubtest, a tool for comparing a stub file against the implementation. (Jared Garst)
  • Speed up incremental mode. (Max Moroz)
  • Many updates to the library stubs in typeshed. A few highlights (there are too many contributors to list them all here; see below for a full contributor list):
    • Many new stubs.
    • Many stubs that had separate Python 2 and Python 3 variants were merged into shared Python 2+3 stubs to improve consistency and to simplify maintenance.

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • Ben Kuhn
  • Daniel F Moisset
  • Dominik Miedziński
  • Elazar Gershuni
  • Ethan
  • Garrett
  • Ingmar Steen
  • Ivan Levkivskyi
  • Jared Garst
  • Jelle Zijlstra
  • Łukasz Langa
  • Max Moroz
  • Michael Lee
  • Naomi Seyfer
  • Ryan Gonzalez
  • Tobin Yehle

Additional thanks to all contributors to typeshed. In particular, I’d like to single out Jelle Zijlstra and David Euresti who have done a huge amount work on improving typeshed. Here’s a list of all typeshed contributors who contributed to this release:

  • Alvaro Caceres
  • Andrey Vlasovskikh
  • Antoine Reversat
  • Ashwini Chaudhary
  • Bertrand Bonnefoy-Claudet
  • Carl Meyer
  • Cooper Lees
  • David Euresti
  • David Wetterau
  • Dominik Miedziński
  • Eddie Antonio Santos
  • Ethan
  • George King
  • Günther Noack
  • Hong Minhee
  • Ivan Levkivskyi
  • James Saryerwinnie
  • Jan Hermann
  • Jelle Zijlstra
  • Jeremy Apthorp
  • jkleint
  • John Reese
  • Josiah Boning
  • Luka Sterbic
  • Łukasz Langa
  • Manuel Krebber
  • Marcin Kurczewski
  • Martijn Pieters
  • Matthias Kramm
  • Max Moroz
  • Michael Walter
  • Michał Masłowski
  • Naomi Seyfer
  • Nathan Henrie
  • Nikhil Marathe
  • nimin98
  • rchen152
  • Richard Hansen
  • Roy Williams
  • Sam Dunster
  • Samuel Colvin
  • Sebastian Meßmer
  • Semyon Proshev
  • Shengpei Zhang
  • Stefan Urbanek
  • Tadeu Manoel
  • Teddy Sudol
  • Thomas Ballinger
  • Tim Abbott

— Jukka (on behalf of the rest of the mypy team: Guido, David and Greg)