Friday, 23 March 2018

Mypy 0.580 released

We’ve just uploaded mypy 0.580 to the Python Package Index (PyPI). This release includes new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install -U mypy

You can read the documentation for this release on ReadTheDocs.

New Features

  • Add support for multiple packages on the command line alongside modules (Eric Wieser, PR 4733). Now you can run mypy with several packages on the command line, for example:
    mypy --package p.a --package p.b --module c
  • Set python_version to default to sys.version_info (Ethan Smith, PR 4686). This makes the implementation match docs and makes it easier to implement PEP 561.

Notable Bugs Fixed

  • Fix issues related to indirect imports in import cycles (PR 4695)
  • Fix frozen subclass and callable issues in attrs plugin (David Euresti, PR 4755)
  • stubgenc: Generate PEP 526 style variable annotations (gclinch, PR 4716)
  • Fix XML report generation (PR 4745)

Improved Error Messages

  • Helpful error message when strict is found in configuration file, which is unsupported (gclinch, PR 4706)

Other Changes

  • Refuse to run under Python 3.5.0 or anything before Python 3.4 (PR 4721). This is caused by the fact that the version of typing module shipped with Python 3.5.0 has several bugs and incompatible/old API.

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • David Euresti
  • Eric Wieser
  • Ethan Smith
  • gclinch
  • Jelle Zijlstra

Additional thanks to all contributors to typeshed:

  • Dan Sully
  • David Euresti
  • Ethan Smith
  • Josh Holland
  • Kenny Do
  • Martin DeMello
  • Matthias Kramm
  • Miguel Gaiowski
  • Nipunn Koorapati
  • rchen152
  • Rob Day
  • Roy Williams
  • Salvo 'LtWorf' Tomaselli
  • Sebastian Rittau
  • Sergey Passichenko
  • Svyatoslav Ilinskiy
  • Takuya Akiba
  • yed podtrzitko

— Ivan Levkivskyi, on behalf of the mypy team

Friday, 2 March 2018

Mypy 0.570 Released

We’ve just uploaded mypy 0.570 to the Python Package Index (PyPI). This release includes new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install -U mypy

You can read the documentation for this release on ReadTheDocs.

We're also happy to welcome long-time mypy core dev Ivan Levkivskyi to the mypy team at Dropbox.

New Features

  • Type check class decorators (David Euresti, PR 4544)
  • Plugin for typechecking classes generated by attrs (Documentation) (David Euresti)
  • Hooks into the semantic analyzer for plugins (PR 4328, PR 4397) (David Euresti)

Notable Bugs Fixed

  • Allow calling instances of tuple subclasses that define __call__ (PR 4367)
  • Improve handling of callable() (PR 4343)
  • Fix crashes due to improper handling of type variables (PR 4384)
  • Various stubgen bugs fixed (PR 4407, PR 4467, PR 4518) (hoefling)
  • Allow subtypes to define more overloads than their supertype (Ryan Gonzalez, PR 3263)
  • Fix typing of assignment to list (e.g. [a, b] = foo()) (Elazar Gershuni, PR 4340)
  • Don’t generate --warn-return-any warnings from binary magic methods that raise NotImplementedError (Vlad Starostin, PR 4545)
  • Fix false negatives in incremental mode due to missing dependencies on parent classes (PR 4566)
  • Fix type of forward reference to a decorated class method (PR 4486)
  • Have divmod() properly dispatch to __[r]divmod__ methods (David Euresti, PR 4585)
  • Fix setup.py breakage (yed podtrzitko, PR 4570)
  • Fix platforms in setup.py (Thomas Grainger, PR 3765)
  • Make psutil an optional dependency (Dominik Miedziński, PR 4634)

Improved Error Messages

  • Give faster feedback by streaming error messages incrementally during type checking (PR 4396)
  • Add variable name to "Need type annotation for variable" error (Elliott Beach, PR 4496)
  • Report columns as 1-based, not 0-based (Elliott Beach, PR 4482)
  • Display argument name, not number, for functions called with keyword arguments (Elliott Beach, PR 4504)

Other Changes

  • Document Generator/Iterator distinction (Carl Meyer, PR 4424)
  • Consistently exit with code 2 on blocking errors (PR 4449)
  • Allow unrecognized flags beginning with x_ in mypy.ini, for use in configuring linters and other tools that work with mypy (PR 4521)
  • Refactor and clean up test discovery (Elazar Gershuni, PR 3973)
  • Remove the home-rolled myunit testing framework (Elazar Gershuni, PR 4369)
  • Test cases for enum iteration (Nick Gaya, PR 4400)

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • a4ff7810
  • Amit D
  • Ashwini Chaudhary
  • Carl Meyer
  • David Euresti
  • Dominik Miedziński
  • Elazar Gershuni
  • Elliott Beach
  • Ethan Smith
  • Germano Gabbianelli
  • Guilherme Caminha
  • hoefling
  • Jelle Zijlstra
  • Nick Gaya
  • Ryan Gonzalez
  • Thomas Grainger
  • Vlad Starostin
  • yed podtrzitko

Additional thanks to all contributors to typeshed:

  • Alan Du
  • Alex Dehnert
  • Anthony Sottile
  • Ashwini Chaudhary
  • Asim Goheer
  • Can Berk Güder
  • Carl Meyer
  • Chad Dombrova
  • Daniel Bowman
  • Daniel Bowtell
  • Daniel Li
  • David Euresti
  • David Zbarsky
  • Elazar Gershuni
  • Elliott Beach
  • Erwin Janssen
  • Ethan Smith
  • Garrett
  • George King
  • gossrock
  • Han Song
  • Ilya Kulakov
  • James M. Allen
  • Jason Fried
  • Jelle Zijlstra
  • Karl Ramm
  • Łukasz Langa
  • Mark Amery
  • Martin DeMello
  • Marti Raudsepp
  • Matt Bogosian
  • Matthias Kramm
  • Michael Lee
  • Michel Albert
  • Nathan Henrie
  • Neil Conway
  • Nick Gaya
  • NODA, Kai
  • PeterJCLaw
  • Pradyun Gedam
  • rchen152
  • Rhys Parry
  • Rick Kilgore
  • Roy Williams
  • Salvo 'LtWorf' Tomaselli
  • Sebastian Rittau
  • Semyon Proshev
  • shahin
  • Thomas Broadley
  • Yuri Khan

--Michael J. Sullivan, on behalf of the mypy team

Monday, 5 February 2018

Dropbox releases mypy-protobuf

At Dropbox we use Google’s Protocol Buffers a lot. So much, in fact, that we sorely needed a way to generate mypy stub files (.pyi files) that match the generated .py files. And out of sheer enthusiasm we implemented the stub file generation code twice! Once in Go, once in Python. Go figure. :-)

We’ve now open-sourced both versions, so if you’re a Python shop, you can use the Python version, while if you’re a Go shop that occasionally uses Python, or you want a faster stub generator, you can use the Go version.

Ready to give it a try? Here’s the repo: https://github.com/dropbox/mypy-protobuf; instructions for both versions are in the top-level README.md. If you’re going for the Python version there’s no need to clone the repo: just pip install mypy-protobuf and pass --mypy_out=<somewhere> to your protoc invocation.

Friday, 15 December 2017

Mypy 0.560 Released

We’ve just uploaded mypy 0.560 to the Python Package Index (PyPI). This release includes new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install -U mypy

You can read the documentation for this release on ReadTheDocs.

I'm also happy to welcome our newest mypy team member at Dropbox, Michael Sullivan.

Iterable and Friends Are Now Protocols

Various ABCs in typing such as Iterable, Iterator and Sized are now protocols instead of regular ABCs. This means that they support structural subtyping and you no longer need to explicitly subclass from typing.Iterable if you want your class to be treated as an Iterable, for example. You only need to define an __iter__ method:

    from typing import Iterator
    
    class MyCollection:  # Note: no base classes
        ...
        def __iter__(self) -> Iterator[str]: ...
    
    def dump(c: MyCollection) -> None:
        for item in sorted(c):  # Okay, sorted() takes any Iterable    
            print(item)

Previously you had to explicitly subclass MyCollection from Iterator[str] to make mypy accept it as an argument for sorted() (and in other contexts where an iterable object is expected), even though it’d work at runtime without subclassing:

    from typing import Iterable, Iterator
    
    class MyCollection(Iterable[str]):  # Base class is now optional
        ...

The new behavior matches how duck typing works in Python, and it also avoids potential metaclass conflicts that you may encounter if you inherit from one of the typing ABCs.

Read the documentation for more details, including a full list of protocols in typing. With this change, protocols are no longer considered an experimental feature.

This was contributed by Ivan Levkivskyi.

Other New Features

  • Widen type of x to Any when isinstance(x, Any) is asserted (Dominik Miedziński, PR 3751)
  • Add checks for overlapping tuple types in overloads (Elazar Gershuni, PR 4238)

Notable Bugs Fixed

  • Fix spurious abstract attribute errors with Any base class (PR 4230)
  • Fix crash caused by lambda that is deferred, i.e. it refers to a variable whose inferred type is not available yet for mypy (PR 4232)
  • Check the right operand of is expressions (Ethan Smith, PR 4243)
  • When disallow_untyped_defs is enabled, correctly warn about missing return types in async def (Jelle Zijlstra, PR 4218)
  • Check signatures of reverse operator methods (Ethan Smith, PR 4249)
  • Fix type inference problem with tuple types (Ivan Levkivskyi, PR 4087)
  • Report additional errors in lambda bodies that were previously omitted (Ethan Smith, PR 4257)
  • Fix crash related to relative imports (Ivan Levkivskyi, PR 4259)
  • Fix spurious errors about returning Any when --warn-return-any is used (Elazar Gershuni, PR 4295)
  • Issue a blocking error early if builtins can't be found, instead of crashing or generating confusing errors (PR 4327)

Improved Error Messages

  • Fix missing line number in covariance error (PR 4275)
  • Improve error message for an invalid callable type (Daniel Li, PR 4213)
  • Produce better error on invalid types like List(int) (Michael J. Sullivan, PR 4323)
  • Give better error message for omitted parentheses in function type comment (Michael J. Sullivan, PR 4329)
  • Suggest spurious trailing commas as a cause for invalid tuple types (Michael J. Sullivan, PR 4336)

Other Changes

  • Speed improvements in incremental mode (PR 4294, PR 4308, PR 4331)
  • Document empty tuple syntax: Tuple[()] (Ethan Smith, PR 4313)
  • Document how to silence invalid errors from linters (Ethan Smith, PR 4314)
  • Document how to ignore imports in specific modules only (Ethan Smith, PR 4316)

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • Daniel Li
  • Dominik Miedziński
  • Elazar Gershuni
  • Ethan Smith
  • Ivan Levkivskyi
  • Jelle Zijlstra
  • Nehal J Wani

Additional thanks to all contributors to typeshed:

  • Alex Willmer
  • Ben Leslie
  • Brandon W Maister
  • Daniel Axtens
  • Elazar Gershuni
  • Ethan Smith
  • FichteFoll
  • gossrock
  • Grzegorz Śliwiński
  • Henri Bai
  • Ivan Levkivskyi
  • Jelle Zijlstra
  • Josh Staiger
  • Kenny Do
  • Luka Sterbic
  • Masayuki Yamamoto
  • Nathan Henrie
  • Neil Pilgrim
  • Patrick Valsecchi
  • rchen152
  • Sebastian Rittau
  • Sebastian Steenbuck
  • Semyon Proshev
  • Tim Abbott

Wednesday, 15 November 2017

Dropbox releases PyAnnotate -- auto-generate type annotations for mypy

For statically checking Python code, mypy is great, but it only works after you have added type annotations to your codebase. When you have a large codebase, this can be painful. At Dropbox we’ve annotated over 1.2 million lines of code (about 20% of our total Python codebase), so we know how much work this can be. It’s worth it though: the payoff is fantastic.

To easy the pain of adding type annotations to existing code, we’ve developed a tool, PyAnnotate, that observes what types are actually used at runtime, and inserts annotations into your source code based on those observations. We’ve now open-sourced the tool.

Here’s how it works. To start, you run your code with a special profiling hook enabled. This observes all call arguments and return values and records the observed types in memory. At the end of a run the data is dumped to a file in JSON format. A separate command-line utility can then read this JSON file and use it to add inline annotations to your source code.

Once the automatic annotations have been added you should run mypy on the updated files to verify that the generated annotations make sense, and most likely you will have to tweak some annotations by hand. But once you get the hang of it, PyAnnotate can save you a lot of work when adding annotations to a large codebase, and that’s nothing to sneeze at.

PyAnnotate is intended to ease the work of adding type annotations to existing (may we say “legacy”) code. For new code we recommend adding annotations as you write the code — type annotations should reflect the intention of the author, and there’s no better time to capture those intentions than when initially writing the code.

Example

Here’s a little program that defines a gcd() function and calls it a few times:

# gcd.py
def main():
    print(gcd(15, 10))
    print(gcd(45, 12))

def gcd(a, b):
    while b:
        a, b = b, a%b
    return a

We also need a driver script:

# driver.py
from gcd import main
from pyannotate_runtime import collect_types

if __name__ == '__main__':
    collect_types.init_types_collection()
    with collect_types.collect():
        main()
    collect_types.dump_stats('type_info.json')

Now let’s install PyAnnotate and run the driver script. The standard output is just what the main()  function prints:

$ pip install pyannotate
$ python driver.py
5
3
$ 

At this point, if you’re curious, you can look in type_info.json to see what types were recorded:

[
    {
        "path": "gcd.py",
        "line": 1,
        "func_name": "main",
        "type_comments": [
            "() -> None"
        ],
        "samples": 1
    },
    {
        "path": "gcd.py",
        "line": 5,
        "func_name": "gcd",
        "type_comments": [
            "(int, int) -> int"
        ],
        "samples": 2
    }
]

Let’s go ahead and annotate the gcd.py file (the -w flag means “go ahead, update the file”):

$ pyannotate -w gcd.py
Refactored gcd.py
--- gcd.py        (original)
+++ gcd.py        (refactored)
@@ -1,8 +1,10 @@
 def main():
+    # type: () -> None
     print(gcd(15, 10))
     print(gcd(45, 12))
 def gcd(a, b):
+    # type: (int, int) -> int
     while b:
         a, b = b, a%b
     return a
Files that were modified:
gcd.py
$ mypy gcd.py
$ 

Since the original file was so small, the unified diff printed by PyAnnotate happens to show the entire file. Note that the final command shows that mypy is happy with the results! If you’d rather not see the diff output, use the -q flag.

Where to get PyAnnotate

The full source code for PyAnnotate is on GitHub: https://github.com/dropbox/pyannotate
If you’d rather just install and use it, a source distribution and a universal “wheel” file exist on PyPI: https://pypi.python.org/pypi/pyannotate

Caveats

PyAnnotate doesn’t actually inspect every call — the profiling hooks have a lot of overhead and a test scenario for a large application would run too slowly. For details on the “downsampling” it performs see the source code. For the same reasons it also doesn’t inspect every item of a list or dictionary — in fact it only inspects the first four. And if a function is called with many different argument types, it will only preserve the first eight that differ significantly.

The generated annotations are only as good as the test scenario you’re using. If you have a function that is written to take either an integer or a string, but your test scenario only calls it with integers, the annotations will say arg: int. If your function may return None or a dictionary, but in your test scenario it always returns None, the annotation will say -> None.

Annotations for functions with *args or **kwds in their signature will likely require manual cleanup.

PyAnnotate currently doesn’t generate Abstract Base Classes (ABCs) such as Iterable or Mapping. If you’re a fan of these you will have to do some manual tweaking to the output.

Since NewType and TypedDict are invisible at runtime, PyAnnotate won’t generate those.

Because of a limitation of the profiling hook, the runtime collection code cannot tell the difference between raising an exception and returning None.

Code in __main__ is currently ignored, because the module name doesn’t correspond to the filename.

The current version of PyAnnotate has been designed to work with either Python 2 or Python 3, but we’ve only used it for Python 2 code ourselves (since that’s what we have) and the tool currently generates type comments that are compatible with Python 2. We’re happy to accept a pull request adding the capability to generate Python 3 style annotations though.

Surely there are some bugs left in our code. We’re happy to accept bug reports in our tracker and bug fixes as pull requests. Note that all code contributions require filling out the Dropbox Contributor License Agreement (CLA).

We consider the current release a prototype, and we don’t promise that future versions will be backwards compatible. In fact, we hope to find the time to make significant changes. We just didn’t feel we would do anyone a favor by sitting on the code longer than we already have.

Friday, 10 November 2017

Mypy 0.550 released

We’ve just uploaded mypy 0.550 to the Python Package Index (PyPI). This release includes new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install -U mypy

You can read the documentation for this release on ReadTheDocs.

Notable Changes

  • The --old-html-report flag was removed (PR 4204)
  • Replace --disallow-any flags with separate boolean flags (PR 4178)
  • Running mypy on Python 3.3 is no longer supported. However Python 3.3 is still valid for the target of the analysis (i.e. the --python-version flag) (PR 4152)

Notable Bugs Fixed

  • Fix classmethod access for Tuple subclasses (PR 4164)
  • Ignore failure to remove temporary files (PR 4163)
  • Make stubgen return status 0 on --help (PR 4160)
  • Fix broken installation on Windows in virtualenv (PR 4149)
  • Fix recent crashes in forward refs (PR 4120)
  • The source of mypy itself is now fully strict-optional compatible (PR 4078)
  • Check code after inferred UninhabitedType (PR 4059)

Notable Typeshed Changes

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • Aleksander Gondek
  • Elazar Gershuni
  • Gareth T
  • Gregory Werbin
  • Hugo vk
  • Ivan Levkivskyi
  • Jelle Zijlstra
  • Rahiel Kasim
  • Svyatoslav Ilinskiy

Additional thanks to all contributors to typeshed:

  • Alan Du
  • Carl Meyer
  • Ethan Smith
  • Grzegorz Śliwiński
  • Ilya Konstantinov
  • Jelle Zijlstra
  • Josh Staiger
  • Martin DeMello
  • Matthew Wright
  • Matěj Cepl
  • Patrick Valsecchi
  • Roy Williams
  • Sally
  • Sebastian Rittau
  • Sebastian Steenbuck
  • Wilfred Hughes
  • Zac Hatfield Dodds
  • anentropic
  • hashstat
  • marienz
  • rchen152

Friday, 20 October 2017

Mypy 0.540 Released

We’ve just uploaded mypy 0.540 to the Python Package Index (PyPI). This release includes new features, bug fixes and library stub (typeshed) updates. You can install it as follows:

    python3 -m pip install -U mypy

You can read the documentation for this release on ReadTheDocs.

Switch to More Rapid Releases

Going forward, we are going to release a new mypy version roughly every 2-4 weeks. The motivation is to make the release process lighter-weight and more predictable, and to reduce the need for bug fix releases — the next normal release will be a short time away, so we’d only need bug fix releases for critical bugs. As a bonus, users will get new features and bug fixes sooner, and contributors will have their PRs released faster!

New Features

  • Allow assignments to multiple targets from union types (Ivan Levkivskyi, PR 4067)
  • Allow definitions of subscripted type aliases such as Item = Tuple[int, str] within functions (Ivan Levkivskyi, PR 4000)
  • Narrow type of optional left operand of in operator if the collection items aren’t optional (Ivan Levkivskyi, PR 4072)
  • Generate an error if <unknown> type would be inferred for a variable (PR 4112)

Notable Bugs Fixed

  • Fix errors not being reported for some modules with incremental mode by deleting cache file for a module if errors are found (Ivan Levkivskyi, PR 4045)
  • Fix incremental mode crash related to Type[...] types (Ivan Levkivskyi, PR 4038)
  • Fix crash related to tuple types (Ivan Levkivskyi, PR 4051)
  • Fix incorrect errors about __getattr__ methods (Ivan Levkivskyi, PR 4073)
  • Fixes to non-method attributes with callable types (Elazar Gershuni, PR 4016)
  • Fix function overloading based on Type[...] types (Ivan Levkivskyi, PR 4037)
  • Fix processing invalid overloaded function definitions (Elazar Gershuni, PR 4064)
  • Fix handling of disallow_any/disallow_untyped_defs combination in mypy config file (Jelle Zijlstra, PR 4076)

Acknowledgments

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

Thanks to all mypy contributors who contributed to this release:

  • Carl Meyer
  • Edward Betts
  • Elazar Gershuni
  • Ethan Smith
  • Ivan Levkivskyi
  • Jelle Zijlstra

Additional thanks to all contributors to typeshed:

  • Ashwini Chaudhary
  • FichteFoll
  • Gábor Bernát
  • Jelle Zijlstra
  • Lloyd
  • Max Rozentsveyg
  • Michael Lee
  • Naman Bharadwaj
  • Semyon Proshev
  • Suren Nihalani
  • Travis Parker
  • hashstat
  • rymdhund