@@ -7,46 +7,94 @@ This section explains how to get started using mypy with an existing,
7
7
significant codebase that has little or no type annotations. If you are
8
8
a beginner, you can skip this section.
9
9
10
- These steps will get you started with mypy on an existing codebase:
10
+ Start small
11
+ -----------
11
12
12
- 1. Start small -- get a clean mypy build for some files, with few
13
- annotations
13
+ If your codebase is large, pick a subset of your codebase (say, 5,000 to 50,000
14
+ lines) and get mypy to run successfully only on this subset at first, *before
15
+ adding annotations *. This should be doable in a day or two. The sooner you get
16
+ some form of mypy passing on your codebase, the sooner you benefit.
14
17
15
- 2. Write a mypy runner script to ensure consistent results
18
+ You'll likely need to fix some mypy errors, either by inserting
19
+ annotations requested by mypy or by adding ``# type: ignore ``
20
+ comments to silence errors you don't want to fix now.
16
21
17
- 3. Run mypy in Continuous Integration to prevent type errors
22
+ We'll mention some tips for getting mypy passing on your codebase in various
23
+ sections below.
18
24
19
- 4. Gradually annotate commonly imported modules
25
+ Run mypy consistently and prevent regressions
26
+ ---------------------------------------------
20
27
21
- 5. Write annotations as you modify existing code and write new code
28
+ Make sure all developers on your codebase run mypy the same way.
29
+ One way to ensure this is adding a small script with your mypy
30
+ invocation to your codebase, or adding your mypy invocation to
31
+ existing tools you use to run tests, like ``tox ``.
22
32
23
- 6. Use :doc: `monkeytype:index ` or `PyAnnotate `_ to automatically annotate legacy code
33
+ * Make sure everyone runs mypy with the same options. Checking a mypy
34
+ :ref: `configuration file <config-file >` into your codebase can help
35
+ with this.
24
36
25
- We discuss all of these points in some detail below, and a few optional
26
- follow-up steps .
37
+ * Make sure everyone type checks the same set of files. See
38
+ :ref: ` specifying-code-to-be-checked ` for details .
27
39
28
- Start small
29
- -----------
40
+ * Make sure everyone runs mypy with the same version of mypy, for instance
41
+ by pinning mypy with the rest of your dev requirements.
30
42
31
- If your codebase is large, pick a subset of your codebase (say, 5,000
32
- to 50,000 lines) and run mypy only on this subset at first,
33
- *without any annotations *. This shouldn't take more than a day or two
34
- to implement, so you start enjoying benefits soon.
43
+ In particular, you'll want to make sure to run mypy as part of your
44
+ Continuous Integration (CI) system as soon as possible. This will
45
+ prevent new type errors from being introduced into your codebase.
35
46
36
- You'll likely need to fix some mypy errors, either by inserting
37
- annotations requested by mypy or by adding ``# type: ignore ``
38
- comments to silence errors you don't want to fix now.
47
+ A simple CI script could look something like this:
48
+
49
+ .. code-block :: text
50
+
51
+ python3 -m pip install mypy==0.971
52
+ # Run your standardised mypy invocation, e.g.
53
+ mypy my_project
54
+ # This could also look like `scripts/run_mypy.sh`, `tox -e mypy`, `make mypy`, etc
55
+
56
+ Ignoring errors from certain modules
57
+ ------------------------------------
39
58
40
- In particular, mypy often generates errors about modules that it can't
41
- find or that don't have stub files:
59
+ By default mypy will follow imports in your code and try to check everything.
60
+ This means even if you only pass in a few files to mypy, it may still process a
61
+ large number of imported files. This could potentially result in lots of errors
62
+ you don't want to deal with at the moment.
63
+
64
+ One way to deal with this is to ignore errors in modules you aren't yet ready to
65
+ type check. The :confval: `ignore_errors ` option is useful for this, for instance,
66
+ if you aren't yet ready to deal with errors from ``package_to_fix_later ``:
67
+
68
+ .. code-block :: text
69
+
70
+ [mypy-package_to_fix_later.*]
71
+ ignore_errors = True
72
+
73
+ You could even invert this, by setting ``ignore_errors = True `` in your global
74
+ config section and only enabling error reporting with ``ignore_errors = False ``
75
+ for the set of modules you are ready to type check.
76
+
77
+ Fixing errors related to imports
78
+ --------------------------------
79
+
80
+ A common class of error you will encounter is errors from mypy about modules
81
+ that it can't find, that don't have types, or don't have stub files:
42
82
43
83
.. code-block :: text
44
84
45
85
core/config.py:7: error: Cannot find implementation or library stub for module named 'frobnicate'
46
86
core/model.py:9: error: Cannot find implementation or library stub for module named 'acme'
47
87
...
48
88
49
- This is normal, and you can easily ignore these errors. For example,
89
+ Sometimes these can be fixed by installing the relevant packages or
90
+ stub libraries in the environment you're running ``mypy `` in.
91
+
92
+ See :ref: `ignore-missing-imports ` for a complete reference on these errors
93
+ and the ways in which you can fix them.
94
+
95
+ You'll likely find that you want to suppress all errors from importing
96
+ a given module that doesn't have types. If you only import that module
97
+ in one or two places, you can use ``# type: ignore `` comments. For example,
50
98
here we ignore an error about a third-party module ``frobnicate `` that
51
99
doesn't have stubs using ``# type: ignore ``:
52
100
@@ -56,9 +104,9 @@ doesn't have stubs using ``# type: ignore``:
56
104
...
57
105
frobnicate.initialize() # OK (but not checked)
58
106
59
- You can also use a mypy configuration file, which is convenient if
60
- there are a large number of errors to ignore . For example, to disable
61
- errors about importing ``frobnicate `` and ``acme `` everywhere in your
107
+ But if you import the module in many places, this becomes unwieldy. In this
108
+ case, we recommend using a :ref: ` configuration file < config-file >` . For example,
109
+ to disable errors about importing ``frobnicate `` and ``acme `` everywhere in your
62
110
codebase, use a config like this:
63
111
64
112
.. code-block :: text
@@ -69,69 +117,33 @@ codebase, use a config like this:
69
117
[mypy-acme.*]
70
118
ignore_missing_imports = True
71
119
72
- You can add multiple sections for different modules that should be
73
- ignored.
74
-
75
- If your config file is named ``mypy.ini ``, this is how you run mypy:
76
-
77
- .. code-block :: text
78
-
79
- mypy --config-file mypy.ini mycode/
80
-
81
120
If you get a large number of errors, you may want to ignore all errors
82
- about missing imports. This can easily cause problems later on and
83
- hide real errors, and it's only recommended as a last resort.
84
- For more details, look :ref: ` here < follow-imports >` .
121
+ about missing imports, for instance by setting :confval: ` ignore_missing_imports `
122
+ to true globally. This can hide errors later on, so we recommend avoiding this
123
+ if possible .
85
124
86
- Mypy follows imports by default. This can result in a few files passed
87
- on the command line causing mypy to process a large number of imported
88
- files, resulting in lots of errors you don't want to deal with at the
89
- moment. There is a config file option to disable this behavior, but
90
- since this can hide errors, it's not recommended for most users.
125
+ Finally, mypy allows fine-grained control over specific import following
126
+ behaviour. It's very easy to silently shoot yourself in the foot when playing
127
+ around with these, so it's mostly recommended as a last resort. For more
128
+ details, look :ref: `here <follow-imports >`.
91
129
92
- Mypy runner script
93
- ------------------
94
-
95
- Introduce a mypy runner script that runs mypy, so that every developer
96
- will use mypy consistently. Here are some things you may want to do in
97
- the script:
98
-
99
- * Ensure that the correct version of mypy is installed.
100
-
101
- * Specify mypy config file or command-line options.
102
-
103
- * Provide set of files to type check. You may want to implement
104
- inclusion and exclusion filters for full control of the file
105
- list.
106
-
107
- Continuous Integration
108
- ----------------------
109
-
110
- Once you have a clean mypy run and a runner script for a part
111
- of your codebase, set up your Continuous Integration (CI) system to
112
- run mypy to ensure that developers won't introduce bad annotations.
113
- A simple CI script could look something like this:
114
-
115
- .. code-block :: text
116
-
117
- python3 -m pip install mypy==0.790 # Pinned version avoids surprises
118
- scripts/mypy # Run the mypy runner script you set up
119
-
120
- Annotate widely imported modules
121
- --------------------------------
130
+ Prioritise annotating widely imported modules
131
+ ---------------------------------------------
122
132
123
133
Most projects have some widely imported modules, such as utilities or
124
134
model classes. It's a good idea to annotate these pretty early on,
125
135
since this allows code using these modules to be type checked more
126
- effectively. Since mypy supports gradual typing, it's okay to leave
127
- some of these modules unannotated. The more you annotate, the more
128
- useful mypy will be, but even a little annotation coverage is useful.
136
+ effectively.
137
+
138
+ Mypy is designed to support gradual typing, i.e. letting you add annotations at
139
+ your own pace, so it's okay to leave some of these modules unannotated. The more
140
+ you annotate, the more useful mypy will be, but even a little annotation
141
+ coverage is useful.
129
142
130
143
Write annotations as you go
131
144
---------------------------
132
145
133
- Now you are ready to include type annotations in your development
134
- workflows. Consider adding something like these in your code style
146
+ Consider adding something like these in your code style
135
147
conventions:
136
148
137
149
1. Developers should add annotations for any new code.
@@ -143,9 +155,9 @@ codebase without much effort.
143
155
Automate annotation of legacy code
144
156
----------------------------------
145
157
146
- There are tools for automatically adding draft annotations
147
- based on type profiles collected at runtime. Tools include
148
- :doc: `monkeytype:index ` (Python 3) and `PyAnnotate `_.
158
+ There are tools for automatically adding draft annotations based on simple
159
+ static analysis or on type profiles collected at runtime. Tools include
160
+ :doc: `monkeytype:index `, ` autotyping `_ and `PyAnnotate `_.
149
161
150
162
A simple approach is to collect types from test runs. This may work
151
163
well if your test coverage is good (and if your tests aren't very
@@ -156,6 +168,68 @@ fraction of production network requests. This clearly requires more
156
168
care, as type collection could impact the reliability or the
157
169
performance of your service.
158
170
171
+ Introduce stricter options
172
+ --------------------------
173
+
174
+ Mypy is very configurable. Once you get started with static typing, you may want
175
+ to explore the various strictness options mypy provides to catch more bugs. For
176
+ example, you can ask mypy to require annotations for all functions in certain
177
+ modules to avoid accidentally introducing code that won't be type checked using
178
+ :confval: `disallow_untyped_defs `. Refer to :ref: `config-file ` for the details.
179
+
180
+ An excellent goal to aim for is to have your codebase pass when run against ``mypy --strict ``.
181
+ This basically ensures that you will never have a type related error without an explicit
182
+ circumvention somewhere (such as a ``# type: ignore `` comment).
183
+
184
+ The following config is equivalent to ``--strict ``:
185
+
186
+ .. code-block :: text
187
+
188
+ # Start off with these
189
+ warn_unused_configs = True
190
+ warn_redundant_casts = True
191
+ warn_unused_ignores = True
192
+ no_implicit_optional = True
193
+
194
+ # Getting these passing should be easy
195
+ strict_equality = True
196
+ strict_concatenate = True
197
+
198
+ # Strongly recommend enabling this one as soon as you can
199
+ check_untyped_defs = True
200
+
201
+ # These shouldn't be too much additional work, but may be tricky to
202
+ # get passing if you use a lot of untyped libraries
203
+ disallow_subclassing_any = True
204
+ disallow_untyped_decorators = True
205
+ disallow_any_generics = True
206
+
207
+ # These next few are various gradations of forcing use of type annotations
208
+ disallow_untyped_calls = True
209
+ disallow_incomplete_defs = True
210
+ disallow_untyped_defs = True
211
+
212
+ # This one isn't too hard to get passing, but return on investment is lower
213
+ no_implicit_reexport = True
214
+
215
+ # This one can be tricky to get passing if you use a lot of untyped libraries
216
+ warn_return_any = True
217
+
218
+ Note that you can also start with ``--strict `` and subtract, for instance:
219
+
220
+ .. code-block :: text
221
+
222
+ strict = True
223
+ warn_return_any = False
224
+
225
+ Remember that many of these options can be enabled on a per-module basis. For instance,
226
+ you may want to enable ``disallow_untyped_defs `` for modules which you've completed
227
+ annotations for, in order to prevent new code from being added without annotations.
228
+
229
+ And if you want, it doesn't stop at ``--strict ``. Mypy has additional checks
230
+ that are not part of ``--strict `` that can be useful. See the complete
231
+ :ref: `command-line ` reference and :ref: `error-codes-optional `.
232
+
159
233
Speed up mypy runs
160
234
------------------
161
235
@@ -165,14 +239,5 @@ this will be. If your project has at least 100,000 lines of code or
165
239
so, you may also want to set up :ref: `remote caching <remote-cache >`
166
240
for further speedups.
167
241
168
- Introduce stricter options
169
- --------------------------
170
-
171
- Mypy is very configurable. Once you get started with static typing, you may want
172
- to explore the various strictness options mypy provides to catch more bugs. For
173
- example, you can ask mypy to require annotations for all functions in certain
174
- modules to avoid accidentally introducing code that won't be type checked using
175
- :confval: `disallow_untyped_defs `, or type check code without annotations as well
176
- with :confval: `check_untyped_defs `. Refer to :ref: `config-file ` for the details.
177
-
178
242
.. _PyAnnotate : https://github.com/dropbox/pyannotate
243
+ .. _autotyping : https://github.com/JelleZijlstra/autotyping
0 commit comments