We’ve just uploaded mypy 0.4.6 to PyPI.
This release adds many new
features, bug fixes and library stub updates. As always, you can
install it as follows, being careful to install mypy-lang, not mypy:
python3 -m pip install --upgrade mypy-lang
Generic Type Aliases
You can now define type aliases that are themselves generic types. For
example, consider this definition of Vector:
from typing import TypeVar, List
T = TypeVar('T')
Vector = Tuple[T, T, T]
Now Vector[float], for example, is equivalent to Tuple[float,
float, float]. Generic type aliases can make your type annotations
shorter and easier to read. The following example defines two
equivalent functions. The first one uses a generic type alias to
simplify the signature:
def negate1(vecs: List[Vector[float]]) -> List[Vector[float]]:
return [(-x, -y, -z) for x, y, z in vecs]
def negate2(vecs: List[Tuple[float, float, float]]
) -> List[Tuple[float, float, float]]:
return [(-x, -y, -z) for x, y, z in vecs]
Check out the
documentation
for more details.
This was contributed by Ivan Levkivskyi and he also implemented the
related changes to typing.
Detecting Missing Return Statements
Mypy now can generate an error if a function is missing a return
statement, unless the return type is None or Any.
Use the --warn-no-return command line option to enable this,
or the warn_no_return config file setting.
When the option is set, mypy warns about this function, since it doesn’t
return anything if the condition is false:
def f(n: int) -> int:
if n > 3:
return n + 1 # Missing return statement
Mypy currently doesn’t warn about empty function bodies or bodies
that only have an ellipsis (…), since these are sometimes used for
abstract methods and aren’t necessarily a problem.
The option can generate false positives if you rely on the implicit
None return value when execution falls off the end of a
function.
This was contributed by Reid Barton.
Improved Type Checking of Import Cycles
Previous versions of mypy were prone to giving errors like ‘Cannot
determine type of “foo”’ if your program had import cycles. Another
common problem was that innocent-looking changes inside import cycles
would cause mypy to emit a new set of unrelated errors.
This release has two changes that should resolve most of these
issues. They are a bit technical, and it’s not important to understand
how they work in order to enjoy the benefits. Anyway, the two
following subsections have a summary for those who are interested in
the nitty-gritty internal details. Feel free to skip them. For even more
details, have a look at these PRs:
#2264 and
#2167
Deferred Checking within Import Cycles
Previously mypy type-checked each module only once, a single module
at a time. This could be a problem with import cycles. For example,
module a could depend on inferred types in b, and b could depend
on types of a. No linear ordering of modules would produce clean
output, unless the program had type annotations for all the
problematic variables — this was only a problem for things whose types
weren’t immediately obvious to mypy. Mypy now type-checks an import
cycle in two passes. If there is a reference to a variable in another
module that mypy hasn’t yet processed, mypy defers the type-checking
of the surrounding function, and finally runs another type-checking
pass for only deferred functions.
Programs without cycles aren’t affected, since mypy has
type-checked single modules in two passes for some time. We’ve now
generalized it to multiple modules in a cycle.
Stable Processing Order within Import Cycles
The erratic mypy behavior mentioned earlier was caused by changes
in the order of processing modules within a cycle. Mypy goes through
each module in a cycle in a linear order, and some errors are only
triggered for certain orderings. In previous versions of mypy a small
change in a program could trigger big changes in the module processing
order. Mypy now better approximates the runtime module initialization
order, which is usually pretty stable.
For example, if module a has a statement like from b import f,
module b likely will be initialized before module a at runtime,
and so mypy will type-check b before a. On the other hand, if an
import statement is within an if TYPE_CHECKING: block, mypy will not
use this heuristic, since typing.TYPE_CHECKING is false at runtime
and the import statement won’t affect runtime behavior.
Self Types (Experimental)
[This feature is experimental — the implementation still has
significant limitations or bugs, and the feature may change in future
mypy versions in incompatible ways.]
Sometimes you have a method that returns a value with exactly the
same type as self. Previously there was no way to do this. Now you
can annotate the self argument with a type variable to express
this. Here’s an example taken from the
documentation:
from typing import TypeVar
T = TypeVar('T', bound='Shape')
class Shape:
def set_scale(self: T, scale: float) -> T:
self.scale = scale
return self
class Circle(Shape):
def set_radius(self, r: float) -> 'Circle':
self.radius = r
return self
class Square(Shape):
def set_width(self, w: float) -> 'Square':
self.width = w
return self
circle = Circle().set_scale(0.5).set_radius(2.7) # type: Circle
square = Square().set_scale(0.5).set_width(3.2) # type: Square
By declaring self as a type variable, the set_scale can return
a Circle when called on a Circle object and a Square when called
on a Square, while only having a single method definition in the
Shape base class.
For a class method, you can also now use Type[T] in a similar way
as the annotation for the cls argument.
This feature was contributed by Elazar Gershuni.
Type Applications
Mypy now supports a type application syntax for user-defined
generic classes. For example, consider a generic Stack class:
from typing import TypeVar, Generic
T = TypeVar('T')
class Stack(Generic[T]):
...
When constructing a Stack instance, you can use the type
application syntax Stack[<type>] to specify the type arguments. This
constructs a Stack[int] instance using a type application:
stack = Stack[int]()
Previously you had to use a type annotation, which is more verbose:
stack = Stack() # type: Stack[int]
This is now practical since the latest typing implementation
caches the result of Stack[int], so it will be quick enough even for
a frequently called function. This was actually supported in early
mypy releases, but it has been unsupported for a while, primarily due
to performance concerns.
You still have to use the type annotation syntax for
standard-library classes such as list and Queue since these
classes don’t support the indexing operator.
This was contributed by Ivan Levkivskyi. He also implemented the
related changes to typing.
New NamedTuple Syntax (Python 3.6)
You can use a new syntax for named tuples with Python 3.6b1 or newer:
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(x=1, y=2)
Run mypy with --fast-parser --python-version 3.6 to use
this. You’ll need to install a recent version of typed_ast (pip3
install --upgrade typed_ast).
This was contributed by Ivan Levkivskyi.
Config File Changes
The filename patterns in the mypy configuration file were changed
to module name patterns. You’ll have to update your config files if
you use this feature.
Here’s an example mypy.ini file that rejects functions without a
type annotation in the frobnicate package but allows them elsewhere:
[mypy-frobnicate.*]
disallow_untyped_defs = True
You can configure additional module search path entries in the mypy
configuration file through the mypy_path configuration file
option. This can be useful with local stub files stored in a separate
directory, for example. Previously you had to use the MYPYPATH
environment variable. mypy_path was contributed by Filip Figiel.
New Command Line Options
- Add --cobertura-xml-report for outputting Cobertura XML reports
with type checking coverage information (Roy Williams).
- Add support for using a custom typeshed directory (--custom-typeshed-dir).
- Add --junit-xml=PATH option for generating JUnit XML files with type checking results.
- Add --find-occurrences that finds all references to a class member
using static type information (experimental).
- Stubgen now supports --fast-parser (Ivan Levkivskyi).
Other Changes in This Release
- Improvements to --strict-optional (please go ahead and
try it — it now works pretty well).
- Allow subclassing Tuple[...] outside stubs again (Ivan Levkivskyi).
- Show column number for reveal_type() expressions.
- Various updates to the bundled typing module.
- Support conditional import in functions/classes (Mark Laws).
- Support matrix multiplication operator @ (Elazar Gershuni).
- Several miscellaneous bug fixes.
- Several documentation improvements.
- Lots of updates to the library stubs in
typeshed.
Acknowledgements
Thanks to all mypy contributors who contributed to this release:
- Alex Jurkiewicz
- Byungwoo Jeon
- Calen Pennington
- Chris Lamb
- David Foster
- Elazar Gershuni
- Filip Figiel
- Herbert Ho
- Ivan Levkivskyi
- Kevin Yap
- Mark Laws
- Reid Barton
- Roy Williams
- Ryan Gonzalez
- Ulric Aleksandrov
Additional thanks to these contributors to
typeshed:
- Alvaro Caceres
- Calen Pennington
- David Percy
- Dima Gerasimov
- Eklavya Sharma
- Evan Hubinger
- Gerhard Hagerer
- Hong Minhee
- Jakub Stasiak
- Jon Dufresne
- Jordan Pittier
- Joshua Smock
- Kai Lautaportti
- Matthias Kramm
- Onno Kortmann
- Reiner Gerecke
- Ruud van Asseldonk
- Ryan C. Thompson
- Sebastian Meßmer
- TrueBrain
- Xavier Mehrenberger
- Yegor Roganov
- Joseph H Garvin
- nobuggy
- paavoap
— Jukka (on behalf of the rest of the mypy team: Guido, David and Greg)