1Additional features
2-------------------
3
4This section discusses various features that did not fit in naturally in one
5of the previous sections.
6
7.. _dataclasses_support:
8
9Dataclasses
10***********
11
12In Python 3.7, a new :py:mod:`dataclasses` module has been added to the standard library.
13This module allows defining and customizing simple boilerplate-free classes.
14They can be defined using the :py:func:`@dataclasses.dataclass
15<python:dataclasses.dataclass>` decorator:
16
17.. code-block:: python
18
19    from dataclasses import dataclass, field
20
21    @dataclass
22    class Application:
23        name: str
24        plugins: List[str] = field(default_factory=list)
25
26    test = Application("Testing...")  # OK
27    bad = Application("Testing...", "with plugin")  # Error: List[str] expected
28
29Mypy will detect special methods (such as :py:meth:`__lt__ <object.__lt__>`) depending on the flags used to
30define dataclasses. For example:
31
32.. code-block:: python
33
34    from dataclasses import dataclass
35
36    @dataclass(order=True)
37    class OrderedPoint:
38        x: int
39        y: int
40
41    @dataclass(order=False)
42    class UnorderedPoint:
43        x: int
44        y: int
45
46    OrderedPoint(1, 2) < OrderedPoint(3, 4)  # OK
47    UnorderedPoint(1, 2) < UnorderedPoint(3, 4)  # Error: Unsupported operand types
48
49Dataclasses can be generic and can be used in any other way a normal
50class can be used:
51
52.. code-block:: python
53
54    from dataclasses import dataclass
55    from typing import Generic, TypeVar
56
57    T = TypeVar('T')
58
59    @dataclass
60    class BoxedData(Generic[T]):
61        data: T
62        label: str
63
64    def unbox(bd: BoxedData[T]) -> T:
65        ...
66
67    val = unbox(BoxedData(42, "<important>"))  # OK, inferred type is int
68
69For more information see :doc:`official docs <python:library/dataclasses>`
70and :pep:`557`.
71
72Caveats/Known Issues
73====================
74
75Some functions in the :py:mod:`dataclasses` module, such as :py:func:`~dataclasses.replace` and :py:func:`~dataclasses.asdict`,
76have imprecise (too permissive) types. This will be fixed in future releases.
77
78Mypy does not yet recognize aliases of :py:func:`dataclasses.dataclass <dataclasses.dataclass>`, and will
79probably never recognize dynamically computed decorators. The following examples
80do **not** work:
81
82.. code-block:: python
83
84    from dataclasses import dataclass
85
86    dataclass_alias = dataclass
87    def dataclass_wrapper(cls):
88      return dataclass(cls)
89
90    @dataclass_alias
91    class AliasDecorated:
92      """
93      Mypy doesn't recognize this as a dataclass because it is decorated by an
94      alias of `dataclass` rather than by `dataclass` itself.
95      """
96      attribute: int
97
98    @dataclass_wrapper
99    class DynamicallyDecorated:
100      """
101      Mypy doesn't recognize this as a dataclass because it is decorated by a
102      function returning `dataclass` rather than by `dataclass` itself.
103      """
104      attribute: int
105
106    AliasDecorated(attribute=1) # error: Unexpected keyword argument
107    DynamicallyDecorated(attribute=1) # error: Unexpected keyword argument
108
109.. _attrs_package:
110
111The attrs package
112*****************
113
114:doc:`attrs <attrs:index>` is a package that lets you define
115classes without writing boilerplate code. Mypy can detect uses of the
116package and will generate the necessary method definitions for decorated
117classes using the type annotations it finds.
118Type annotations can be added as follows:
119
120.. code-block:: python
121
122    import attr
123
124    @attr.s
125    class A:
126        one: int = attr.ib()          # Variable annotation (Python 3.6+)
127        two = attr.ib()  # type: int  # Type comment
128        three = attr.ib(type=int)     # type= argument
129
130If you're using ``auto_attribs=True`` you must use variable annotations.
131
132.. code-block:: python
133
134    import attr
135
136    @attr.s(auto_attribs=True)
137    class A:
138        one: int
139        two: int = 7
140        three: int = attr.ib(8)
141
142Typeshed has a couple of "white lie" annotations to make type checking
143easier. :py:func:`attr.ib` and :py:class:`attr.Factory` actually return objects, but the
144annotation says these return the types that they expect to be assigned to.
145That enables this to work:
146
147.. code-block:: python
148
149    import attr
150    from typing import Dict
151
152    @attr.s(auto_attribs=True)
153    class A:
154        one: int = attr.ib(8)
155        two: Dict[str, str] = attr.Factory(dict)
156        bad: str = attr.ib(16)   # Error: can't assign int to str
157
158Caveats/Known Issues
159====================
160
161* The detection of attr classes and attributes works by function name only.
162  This means that if you have your own helper functions that, for example,
163  ``return attr.ib()`` mypy will not see them.
164
165* All boolean arguments that mypy cares about must be literal ``True`` or ``False``.
166  e.g the following will not work:
167
168  .. code-block:: python
169
170      import attr
171      YES = True
172      @attr.s(init=YES)
173      class A:
174          ...
175
176* Currently, ``converter`` only supports named functions.  If mypy finds something else it
177  will complain about not understanding the argument and the type annotation in
178  :py:meth:`__init__ <object.__init__>` will be replaced by ``Any``.
179
180* :ref:`Validator decorators <attrs:examples_validators>`
181  and `default decorators <http://www.attrs.org/en/stable/examples.html#defaults>`_
182  are not type-checked against the attribute they are setting/validating.
183
184* Method definitions added by mypy currently overwrite any existing method
185  definitions.
186
187.. _remote-cache:
188
189Using a remote cache to speed up mypy runs
190******************************************
191
192Mypy performs type checking *incrementally*, reusing results from
193previous runs to speed up successive runs. If you are type checking a
194large codebase, mypy can still be sometimes slower than desirable. For
195example, if you create a new branch based on a much more recent commit
196than the target of the previous mypy run, mypy may have to
197process almost every file, as a large fraction of source files may
198have changed. This can also happen after you've rebased a local
199branch.
200
201Mypy supports using a *remote cache* to improve performance in cases
202such as the above.  In a large codebase, remote caching can sometimes
203speed up mypy runs by a factor of 10, or more.
204
205Mypy doesn't include all components needed to set
206this up -- generally you will have to perform some simple integration
207with your Continuous Integration (CI) or build system to configure
208mypy to use a remote cache. This discussion assumes you have a CI
209system set up for the mypy build you want to speed up, and that you
210are using a central git repository. Generalizing to different
211environments should not be difficult.
212
213Here are the main components needed:
214
215* A shared repository for storing mypy cache files for all landed commits.
216
217* CI build that uploads mypy incremental cache files to the shared repository for
218  each commit for which the CI build runs.
219
220* A wrapper script around mypy that developers use to run mypy with remote
221  caching enabled.
222
223Below we discuss each of these components in some detail.
224
225Shared repository for cache files
226=================================
227
228You need a repository that allows you to upload mypy cache files from
229your CI build and make the cache files available for download based on
230a commit id.  A simple approach would be to produce an archive of the
231``.mypy_cache`` directory (which contains the mypy cache data) as a
232downloadable *build artifact* from your CI build (depending on the
233capabilities of your CI system).  Alternatively, you could upload the
234data to a web server or to S3, for example.
235
236Continuous Integration build
237============================
238
239The CI build would run a regular mypy build and create an archive containing
240the ``.mypy_cache`` directory produced by the build. Finally, it will produce
241the cache as a build artifact or upload it to a repository where it is
242accessible by the mypy wrapper script.
243
244Your CI script might work like this:
245
246* Run mypy normally. This will generate cache data under the
247  ``.mypy_cache`` directory.
248
249* Create a tarball from the ``.mypy_cache`` directory.
250
251* Determine the current git master branch commit id (say, using
252  ``git rev-parse HEAD``).
253
254* Upload the tarball to the shared repository with a name derived from the
255  commit id.
256
257Mypy wrapper script
258===================
259
260The wrapper script is used by developers to run mypy locally during
261development instead of invoking mypy directly.  The wrapper first
262populates the local ``.mypy_cache`` directory from the shared
263repository and then runs a normal incremental build.
264
265The wrapper script needs some logic to determine the most recent
266central repository commit (by convention, the ``origin/master`` branch
267for git) the local development branch is based on. In a typical git
268setup you can do it like this:
269
270.. code::
271
272    git merge-base HEAD origin/master
273
274The next step is to download the cache data (contents of the
275``.mypy_cache`` directory) from the shared repository based on the
276commit id of the merge base produced by the git command above. The
277script will decompress the data so that mypy will start with a fresh
278``.mypy_cache``. Finally, the script runs mypy normally. And that's all!
279
280Caching with mypy daemon
281========================
282
283You can also use remote caching with the :ref:`mypy daemon <mypy_daemon>`.
284The remote cache will significantly speed up the first ``dmypy check``
285run after starting or restarting the daemon.
286
287The mypy daemon requires extra fine-grained dependency data in
288the cache files which aren't included by default. To use caching with
289the mypy daemon, use the :option:`--cache-fine-grained <mypy --cache-fine-grained>` option in your CI
290build::
291
292    $ mypy --cache-fine-grained <args...>
293
294This flag adds extra information for the daemon to the cache. In
295order to use this extra information, you will also need to use the
296``--use-fine-grained-cache`` option with ``dmypy start`` or
297``dmypy restart``. Example::
298
299    $ dmypy start -- --use-fine-grained-cache <options...>
300
301Now your first ``dmypy check`` run should be much faster, as it can use
302cache information to avoid processing the whole program.
303
304Refinements
305===========
306
307There are several optional refinements that may improve things further,
308at least if your codebase is hundreds of thousands of lines or more:
309
310* If the wrapper script determines that the merge base hasn't changed
311  from a previous run, there's no need to download the cache data and
312  it's better to instead reuse the existing local cache data.
313
314* If you use the mypy daemon, you may want to restart the daemon each time
315  after the merge base or local branch has changed to avoid processing a
316  potentially large number of changes in an incremental build, as this can
317  be much slower than downloading cache data and restarting the daemon.
318
319* If the current local branch is based on a very recent master commit,
320  the remote cache data may not yet be available for that commit, as
321  there will necessarily be some latency to build the cache files. It
322  may be a good idea to look for cache data for, say, the 5 latest
323  master commits and use the most recent data that is available.
324
325* If the remote cache is not accessible for some reason (say, from a public
326  network), the script can still fall back to a normal incremental build.
327
328* You can have multiple local cache directories for different local branches
329  using the :option:`--cache-dir <mypy --cache-dir>` option. If the user switches to an existing
330  branch where downloaded cache data is already available, you can continue
331  to use the existing cache data instead of redownloading the data.
332
333* You can set up your CI build to use a remote cache to speed up the
334  CI build. This would be particularly useful if each CI build starts
335  from a fresh state without access to cache files from previous
336  builds. It's still recommended to run a full, non-incremental
337  mypy build to create the cache data, as repeatedly updating cache
338  data incrementally could result in drift over a long time period (due
339  to a mypy caching issue, perhaps).
340
341.. _extended_callable:
342
343Extended Callable types
344***********************
345
346.. note::
347
348   This feature is deprecated.  You can use
349   :ref:`callback protocols <callback_protocols>` as a replacement.
350
351As an experimental mypy extension, you can specify :py:data:`~typing.Callable` types
352that support keyword arguments, optional arguments, and more.  When
353you specify the arguments of a :py:data:`~typing.Callable`, you can choose to supply just
354the type of a nameless positional argument, or an "argument specifier"
355representing a more complicated form of argument.  This allows one to
356more closely emulate the full range of possibilities given by the
357``def`` statement in Python.
358
359As an example, here's a complicated function definition and the
360corresponding :py:data:`~typing.Callable`:
361
362.. code-block:: python
363
364   from typing import Callable
365   from mypy_extensions import (Arg, DefaultArg, NamedArg,
366                                DefaultNamedArg, VarArg, KwArg)
367
368   def func(__a: int,  # This convention is for nameless arguments
369            b: int,
370            c: int = 0,
371            *args: int,
372            d: int,
373            e: int = 0,
374            **kwargs: int) -> int:
375       ...
376
377   F = Callable[[int,  # Or Arg(int)
378                 Arg(int, 'b'),
379                 DefaultArg(int, 'c'),
380                 VarArg(int),
381                 NamedArg(int, 'd'),
382                 DefaultNamedArg(int, 'e'),
383                 KwArg(int)],
384                int]
385
386   f: F = func
387
388Argument specifiers are special function calls that can specify the
389following aspects of an argument:
390
391- its type (the only thing that the basic format supports)
392
393- its name (if it has one)
394
395- whether it may be omitted
396
397- whether it may or must be passed using a keyword
398
399- whether it is a ``*args`` argument (representing the remaining
400  positional arguments)
401
402- whether it is a ``**kwargs`` argument (representing the remaining
403  keyword arguments)
404
405The following functions are available in ``mypy_extensions`` for this
406purpose:
407
408.. code-block:: python
409
410   def Arg(type=Any, name=None):
411       # A normal, mandatory, positional argument.
412       # If the name is specified it may be passed as a keyword.
413
414   def DefaultArg(type=Any, name=None):
415       # An optional positional argument (i.e. with a default value).
416       # If the name is specified it may be passed as a keyword.
417
418   def NamedArg(type=Any, name=None):
419       # A mandatory keyword-only argument.
420
421   def DefaultNamedArg(type=Any, name=None):
422       # An optional keyword-only argument (i.e. with a default value).
423
424   def VarArg(type=Any):
425       # A *args-style variadic positional argument.
426       # A single VarArg() specifier represents all remaining
427       # positional arguments.
428
429   def KwArg(type=Any):
430       # A **kwargs-style variadic keyword argument.
431       # A single KwArg() specifier represents all remaining
432       # keyword arguments.
433
434In all cases, the ``type`` argument defaults to ``Any``, and if the
435``name`` argument is omitted the argument has no name (the name is
436required for ``NamedArg`` and ``DefaultNamedArg``).  A basic
437:py:data:`~typing.Callable` such as
438
439.. code-block:: python
440
441   MyFunc = Callable[[int, str, int], float]
442
443is equivalent to the following:
444
445.. code-block:: python
446
447   MyFunc = Callable[[Arg(int), Arg(str), Arg(int)], float]
448
449A :py:data:`~typing.Callable` with unspecified argument types, such as
450
451.. code-block:: python
452
453   MyOtherFunc = Callable[..., int]
454
455is (roughly) equivalent to
456
457.. code-block:: python
458
459   MyOtherFunc = Callable[[VarArg(), KwArg()], int]
460
461.. note::
462
463   Each of the functions above currently just returns its ``type``
464   argument at runtime, so the information contained in the argument
465   specifiers is not available at runtime.  This limitation is
466   necessary for backwards compatibility with the existing
467   ``typing.py`` module as present in the Python 3.5+ standard library
468   and distributed via PyPI.
469