Friday 10 April 2015

Mypy at PyCon 2015 in Montreal

I'm currently at PyCon 2015 in Montreal (and enjoying myself!). I'm happy to chat about anything related to mypy, PEP 484 (type hinting / typing), static typing or static analysis. Say hi if you see me, or meet me at the Dropbox booth or send me an email -- it can be quite difficult to find me among the crowds. There's probably also going to be an open space session that I will attend, maybe on Saturday. I'm going to be around until Wednesday morning.

Sunday 5 April 2015

Mypy 0.2 Released

I just uploaded mypy 0.2 to PyPI! This release focuses on PEP 484 compatibility, but it also contains many general improvements. The changes are too numerous to enumerate them all. Instead, I'll focus here on the most visible and useful ones.

Install mypy using pip:

$ pip install mypy-lang

Mypy 0.2 breaks backward compatibility. You will probably have to modify your code to be PEP 484 draft compatible. As before, mypy is experimental and still has bugs. Backward compatibility won't be preserved until mypy hits 1.0. However, mypy is committed to becoming compatible with PEP 484.

PEP 484 Syntax Changes

Several changes improve PEP 484 compatibility. Mypy still doesn't implement all of PEP 484, but we've made a lot of progress.

'typevar' Replaced With 'TypeVar'

To define a type variable, use typing.TypeVar instead of typing.typevar. For example:

  from typing import TypeVar, Sequence

  T = TypeVar('T')

  def first(a: Sequence[T]) -> T:
      return a[0]

Function[...] Replaced With Callable[...]

Replace types like Function[...] with Callable[...]. Other than the name change, the types are identical.

No More Type Application Syntax

You can't write code like this any more:

  from typing import List

  names = List[str]()  # ERROR

Use a type comment instead:

  from typing import List

  names = []  # type: List[str]

Types such as List[str] are no longer ordinary classes. Previously, List[int] evaluated to just list at runtime, making it possible to support the idiom in the first example. List[str] now actually creates a new type object that preserves information about the str type argument. This is useful and allows using type information at runtime in a variety of ways. The tradeoff is that constructing instances using generic type objects is no longer possible. As a side benefit, there is usually a single obvious way to declare the type of a container object. Previously there were just too many ways of defining the types of variables and objects.

Any(x) Not Valid As a Cast

Use cast(Any, e) instead of Any(e); the prior is equivalent to the latter, and the latter syntax is no longer supported.

Overloading In Stubs Only

The @overload decorator is only supported in stubs. You can replace many uses of overloading using union types.

Silencing Mypy Errors Locally

You can use a "# type: ignore" comment to silence mypy errors on a particular line. For example, to make mypy not complain about a missing function in a stub:

  import acme

  # Don't complain about missing do_stuff
  acme.do_stuff()  # type: ignore

This is very useful if mypy gets confused about some particular behavior in your code. Instead of trying to refactor your code to pass type checking, you can just locally ignore individual errors.

Better Python Support

Mypy supports additional Python syntax. The mypy parser now can parse most of Python 3.2 standard library, and there's also support for a bunch of features introduced in later 3.x releases.

More Library Modules Supported

Additional stubs for standard library modules are included, and we've started adding support for 3rd party modules such as requests.

This mypy release also makes it easier to work with arbitrary library modules that aren't directly supported my mypy. You can silence errors due to missing library stubs using # type: ignore. For example, if you want to use frobnicate that has no stubs:

  from frobnicate import do_stuff  # type: ignore

  do_stuff(...)  # Okay!

Type Aliases

Mypy supports type aliases that make it easier to use more powerful types such as union types and callable types, and can be used to have more descriptive names for types. Example:

  from typing import Dict, List, Tuple

  DependencyMap = Dict[str, List[str]]
  Location = Tuple[str, str]

  def get_dependencies(base: Location) -> DependencyMap: ...

Miscellania

  • Mypy supports named tuples (both collections.namedtuple and typing.NamedTuple).
  • Mypy supports __call__ and __getattr__ (thanks Sander Kersten!).
  • There's an alternative stub file name extension .pyi. This means that you can have stubs and normal .py files in the same directory. This can also be used to override the default stubs for standard library modules that ship with mypy with local modified variants.
  • Optional[t] allows documenting whether None is a valid value for a type.
  • Better runtime introspection of types (for example, the type parameter int of List[int] is preserved; previously the type parameters were stripped at runtime).
  • The ABCs in typing are compatible with collections.abc. For example, now there's both Sequence and MutableSequence.
  • As always, many bugs were squashed, though there are still remaining open bugs.
  • The @ducktype class decorator was removed. Some built-in types have special handling in the type checker so that int is compatible with float, as it was before.
  • There is no longer typing.AbstractGeneric -- always use typing.Generic when defining generic classes.

There are also some interesting work-in-progress features such as a new automatic stub generator.

Acknowledgements

Many people contributed to this release. Thanks to everybody who helped! Here is a partial list:

  • Guido van Rossum, Łukasz Langa and others at typehinting (PEP 484)
  • Sander Kersten (continued with strong contributions, including several new Python features and a bunch of code cleanup)
  • Igor Vuk
  • Brodie Rao
  • Anders Schuller
  • Ryan Gonzalez
  • Marek Sapota

An up-to-date list of code contributions is available at the GitHub contributors page.