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.

Saturday 17 January 2015

Mypy and the PEP 484 (Type Hinting) Draft

Guido van Rossum just yesterday announced that the first draft of PEP 484 is available for review. This Python Enhancement Proposal defines a standard type annotation syntax, which is heavily inspired by mypy, for type hinting. The plan is to get it included in Python 3.5.

I've been contributing to the design and editing process and am very excited about the prospect of mypy supporting a standard annotation syntax. That's why (in addition to holidays) there hasn't been much activity in the mypy repo during the last month or so. Fear not -- there's a lot of things happening around mypy.

The PEP does not define a type checker or many of the details needed to implement a type system -- it gives a syntax and basic guidelines, around which various tools such as type checkers (including mypy), IDEs and maybe even optimizing (JIT) compilers can be implemented. There is still a lot of room for mypy to experiment and innovate around type checking Python code.

Why This Is Great

A standardized syntax could be boon for mypy. Here are just some benefits:

  • More people, projects and companies are likely to hear about and use a syntax that is standard. More users means more polish, more bugs fixed, and overall a better experience for everybody.
  • 3rd party libraries are likely to adopt type annotations when there is a standard. Mypy will catch more bugs when you use these static-typing-aware libraries in your programs.
  • Tools such as IDEs and documentation generators are likely to add support for standard type annotations.
  • There will be less fragmentation caused by multiple incompatible type syntax languages. This makes things less confusing and reduces duplicate work.

How Does This Affect Mypy Features?

The PEP will have some direct implicitations for mypy. As it's still a draft, we don't know what the final proposal will look like, but some aspects of mypy, mostly syntax, will likely change. Here are some of the most prominent differences (some of these are not yet reflected in the PEP draft):

  • The PEP uses Callable[...] instead of Function[...] for callable/function types.
  • Generic types are not valid in expressions. So code like
        x = List[int]()
        
    will be written like this (this has been supported by mypy since the early days):
        x = []  # type: List[int]
        
    Syntax for type annotations is still being discussed, and this is clearly one of the more controversial aspects of the proposal.
  • typevar is spelled TypeVar and has other syntactic changes.
  • Function overloading (@overload) is only available in library stubs. A future PEP may add runtime support for function overloading or multiple dispatch, but for now there's not going to be overloading for user code. This isn't really a major issue, since other mypy features such as union types (which are a recent addition and part of the PEP) make overloading rarely useful any more.
  • There's provisions for explicit type checking of None values. Currently mypy implicitly makes None compatible with every type, but this is likely going to change. For example, Optional[int] would be used for int or None (same as Union[int, None]).
  • There's a new type for variable length tuples: Tuple[int, ...] ('...' is part of the syntax).
  • Type arguments of generic types in function annotations will be available for introspection. Currently List[int] evaluates to just list which loses information at runtime.

I've added a bunch of issues that cover differences between the PEP and mypy.

Join the Discussion

Join the discussion of open PEP issues and suggest changes at https://github.com/ambv/typehinting!