diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 224e7f0..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.pc/
diff --git a/LICENSE b/LICENSE
index 2e64b70..991496c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -4,7 +4,8 @@ Mypy (and mypyc) are licensed under the terms of the MIT license, reproduced bel
The MIT License
-Copyright (c) 2015-2021 Jukka Lehtosalo and contributors
+Copyright (c) 2012-2022 Jukka Lehtosalo and contributors
+Copyright (c) 2015-2022 Dropbox, Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -26,8 +27,8 @@ DEALINGS IN THE SOFTWARE.
= = = = =
-Portions of mypy and mypyc are licensed under different licenses. The
-files under stdlib-samples as well as the files
+Portions of mypy and mypyc are licensed under different licenses.
+The files
mypyc/lib-rt/pythonsupport.h, mypyc/lib-rt/getargs.c and
mypyc/lib-rt/getargsfast.c are licensed under the PSF 2 License, reproduced
below.
diff --git a/MANIFEST.in b/MANIFEST.in
index dd65e11..1c26ae1 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -41,7 +41,8 @@ include runtests.py
include pytest.ini
include LICENSE mypyc/README.md
-exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini
+exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini action.yml .editorconfig
+exclude .git-blame-ignore-revs .pre-commit-config.yaml
global-exclude *.py[cod]
global-exclude .DS_Store
diff --git a/PKG-INFO b/PKG-INFO
index b784d05..e400ed9 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,27 +1,31 @@
Metadata-Version: 2.1
Name: mypy
-Version: 0.910
+Version: 1.0.1
Summary: Optional static typing for Python
Home-page: http://www.mypy-lang.org/
Author: Jukka Lehtosalo
Author-email: jukka.lehtosalo@iki.fi
License: MIT License
Project-URL: News, http://mypy-lang.org/news.html
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
+Project-URL: Documentation, https://mypy.readthedocs.io/en/stable/index.html
+Project-URL: Repository, https://github.com/python/mypy
+Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development
-Requires-Python: >=3.5
+Classifier: Typing :: Typed
+Requires-Python: >=3.7
Provides-Extra: dmypy
Provides-Extra: python2
+Provides-Extra: reports
+Provides-Extra: install-types
License-File: LICENSE
Mypy -- Optional Static Typing for Python
@@ -33,5 +37,3 @@ can catch many programming errors by analyzing your program, without
actually having to run it. Mypy has a powerful type system with
features such as type inference, gradual typing, generics and union
types.
-
-
diff --git a/README.md b/README.md
index 3c7a1e7..9d9618e 100644
--- a/README.md
+++ b/README.md
@@ -1,112 +1,126 @@
-
+
-Mypy: Optional Static Typing for Python
+Mypy: Static Typing for Python
=======================================
-[![Build Status](https://api.travis-ci.com/python/mypy.svg?branch=master)](https://travis-ci.com/python/mypy)
+[![Stable Version](https://img.shields.io/pypi/v/mypy?color=blue)](https://pypi.org/project/mypy/)
+[![Downloads](https://img.shields.io/pypi/dm/mypy)](https://pypistats.org/packages/mypy)
+[![Build Status](https://github.com/python/mypy/actions/workflows/test.yml/badge.svg)](https://github.com/python/mypy/actions)
+[![Documentation Status](https://readthedocs.org/projects/mypy/badge/?version=latest)](https://mypy.readthedocs.io/en/latest/?badge=latest)
[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
+[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
+[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
+[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
+Got a question?
+---------------
-Got a question? Join us on Gitter!
-----------------------------------
+We are always happy to answer questions! Here are some good places to ask them:
-We don't have a mailing list; but we are always happy to answer
-questions on [gitter chat](https://gitter.im/python/typing). If you are
-sure you've found a bug please search our issue trackers for a
-duplicate before filing a new issue:
+- for anything you're curious about, try [gitter chat](https://gitter.im/python/typing)
+- for general questions about Python typing, try [typing discussions](https://github.com/python/typing/discussions)
-- [mypy tracker](https://github.com/python/mypy/issues)
- for mypy issues
-- [typeshed tracker](https://github.com/python/typeshed/issues)
- for issues with specific modules
-- [typing tracker](https://github.com/python/typing/issues)
- for discussion of new type system features (PEP 484 changes) and
- runtime bugs in the typing module
+If you're just getting started,
+[the documentation](https://mypy.readthedocs.io/en/stable/index.html)
+and [type hints cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)
+can also help answer questions.
-What is mypy?
--------------
+If you think you've found a bug:
-Mypy is an optional static type checker for Python. You can add type
-hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/)) to your
-Python programs, and use mypy to type check them statically.
-Find bugs in your programs without even running them!
+- check our [common issues page](https://mypy.readthedocs.io/en/stable/common_issues.html)
+- search our [issue tracker](https://github.com/python/mypy/issues) to see if
+ it's already been reported
+- consider asking on [gitter chat](https://gitter.im/python/typing)
-You can mix dynamic and static typing in your programs. You can always
-fall back to dynamic typing when static typing is not convenient, such
-as for legacy code.
+To report a bug or request an enhancement:
-Here is a small example to whet your appetite (Python 3):
+- report at [our issue tracker](https://github.com/python/mypy/issues)
+- if the issue is with a specific library or function, consider reporting it at
+ [typeshed tracker](https://github.com/python/typeshed/issues) or the issue
+ tracker for that library
-```python
-from typing import Iterator
+To discuss a new type system feature:
+- discuss at [typing-sig mailing list](https://mail.python.org/archives/list/typing-sig@python.org/)
+- there is also some historical discussion [here](https://github.com/python/typing/issues)
-def fib(n: int) -> Iterator[int]:
- a, b = 0, 1
- while a < n:
- yield a
- a, b = b, a + b
-```
-See [the documentation](https://mypy.readthedocs.io/en/stable/introduction.html) for more examples.
-For Python 2.7, the standard annotations are written as comments:
-```python
-def is_palindrome(s):
- # type: (str) -> bool
- return s == s[::-1]
-```
+What is mypy?
+-------------
-See [the documentation for Python 2 support](https://mypy.readthedocs.io/en/latest/python2.html).
+Mypy is a static type checker for Python.
-Mypy is in development; some features are missing and there are bugs.
-See 'Development status' below.
+Type checkers help ensure that you're using variables and functions in your code
+correctly. With mypy, add type hints ([PEP 484](https://www.python.org/dev/peps/pep-0484/))
+to your Python programs, and mypy will warn you when you use those types
+incorrectly.
-Requirements
-------------
+Python is a dynamic language, so usually you'll only see errors in your code
+when you attempt to run it. Mypy is a *static* checker, so it finds bugs
+in your programs without even running them!
+
+Here is a small example to whet your appetite:
-You need Python 3.5 or later to run mypy. You can have multiple Python
-versions (2.x and 3.x) installed on the same system without problems.
+```python
+number = input("What is your favourite number?")
+print("It is", number + 1) # error: Unsupported operand types for + ("str" and "int")
+```
-In Ubuntu, Mint and Debian you can install Python 3 like this:
+Adding type hints for mypy does not interfere with the way your program would
+otherwise run. Think of type hints as similar to comments! You can always use
+the Python interpreter to run your code, even if mypy reports errors.
- $ sudo apt-get install python3 python3-pip
+Mypy is designed with gradual typing in mind. This means you can add type
+hints to your code base slowly and that you can always fall back to dynamic
+typing when static typing is not convenient.
-For other Linux flavors, macOS and Windows, packages are available at
+Mypy has a powerful and easy-to-use type system, supporting features such as
+type inference, generics, callable types, tuple types, union types,
+structural subtyping and more. Using mypy will make your programs easier to
+understand, debug, and maintain.
- https://www.python.org/getit/
+See [the documentation](https://mypy.readthedocs.io/en/stable/index.html) for
+more examples and information.
+In particular, see:
+- [type hints cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)
+- [getting started](https://mypy.readthedocs.io/en/stable/getting_started.html)
+- [list of error codes](https://mypy.readthedocs.io/en/stable/error_code_list.html)
Quick start
-----------
Mypy can be installed using pip:
- $ python3 -m pip install -U mypy
+ python3 -m pip install -U mypy
-If you want to run the latest version of the code, you can install from git:
+If you want to run the latest version of the code, you can install from the
+repo directly:
- $ python3 -m pip install -U git+git://github.com/python/mypy.git
+ python3 -m pip install -U git+https://github.com/python/mypy.git
+ # or if you don't have 'git' installed
+ python3 -m pip install -U https://github.com/python/mypy/zipball/master
+Now you can type-check the [statically typed parts] of a program like this:
-Now, if Python on your system is configured properly (else see
-"Troubleshooting" below), you can type-check the [statically typed parts] of a
-program like this:
+ mypy PROGRAM
- $ mypy PROGRAM
+You can always use the Python interpreter to run your statically typed
+programs, even if mypy reports type errors:
-You can always use a Python interpreter to run your statically typed
-programs, even if they have type errors:
-
- $ python3 PROGRAM
+ python3 PROGRAM
You can also try mypy in an [online playground](https://mypy-play.net/) (developed by
-Yusuke Miyazaki).
+Yusuke Miyazaki). If you are working with large code bases, you can run mypy in
+[daemon mode], that will give much faster (often sub-second) incremental updates:
+
+ dmypy run -- PROGRAM
[statically typed parts]: https://mypy.readthedocs.io/en/latest/getting_started.html#function-signatures-and-dynamic-vs-static-typing
+[daemon-mode]: https://mypy.readthedocs.io/en/stable/mypy_daemon.html
-IDE, Linter Integrations, and Pre-commit
-----------------------------------------
+Integrations
+------------
Mypy can be integrated into popular IDEs:
@@ -115,166 +129,55 @@ Mypy can be integrated into popular IDEs:
`let g:syntastic_python_checkers=['mypy']`
* Using [ALE](https://github.com/dense-analysis/ale): should be enabled by default when `mypy` is installed,
or can be explicitly enabled by adding `let b:ale_linters = ['mypy']` in `~/vim/ftplugin/python.vim`
-* Emacs: using [Flycheck](https://github.com/flycheck/) and [Flycheck-mypy](https://github.com/lbolla/emacs-flycheck-mypy)
+* Emacs: using [Flycheck](https://github.com/flycheck/)
* Sublime Text: [SublimeLinter-contrib-mypy](https://github.com/fredcallaway/SublimeLinter-contrib-mypy)
* Atom: [linter-mypy](https://atom.io/packages/linter-mypy)
* PyCharm: [mypy plugin](https://github.com/dropbox/mypy-PyCharm-plugin) (PyCharm integrates
- [its own implementation of PEP 484](https://www.jetbrains.com/help/pycharm/type-hinting-in-product.html))
+ [its own implementation](https://www.jetbrains.com/help/pycharm/type-hinting-in-product.html) of [PEP 484](https://peps.python.org/pep-0484/))
* VS Code: provides [basic integration](https://code.visualstudio.com/docs/python/linting#_mypy) with mypy.
-
-Mypy can also be set up as a pre-commit hook using [pre-commit mirrors-mypy].
-
-[pre-commit mirrors-mypy]: https://github.com/pre-commit/mirrors-mypy
+* pre-commit: use [pre-commit mirrors-mypy](https://github.com/pre-commit/mirrors-mypy).
Web site and documentation
--------------------------
-Documentation and additional information is available at the web site:
+Additional information is available at the web site:
http://www.mypy-lang.org/
-Or you can jump straight to the documentation:
+Jump straight to the documentation:
https://mypy.readthedocs.io/
+Follow along our changelog at:
-Troubleshooting
----------------
-
-Depending on your configuration, you may have to run `pip` like
-this:
-
- $ python3 -m pip install -U mypy
-
-This should automatically install the appropriate version of
-mypy's parser, typed-ast. If for some reason it does not, you
-can install it manually:
-
- $ python3 -m pip install -U typed-ast
-
-If the `mypy` command isn't found after installation: After
-`python3 -m pip install`, the `mypy` script and
-dependencies, including the `typing` module, will be installed to
-system-dependent locations. Sometimes the script directory will not
-be in `PATH`, and you have to add the target directory to `PATH`
-manually or create a symbolic link to the script. In particular, on
-macOS, the script may be installed under `/Library/Frameworks`:
-
- /Library/Frameworks/Python.framework/Versions//bin
-
-In Windows, the script is generally installed in
-`\PythonNN\Scripts`. So, type check a program like this (replace
-`\Python34` with your Python installation path):
-
- C:\>\Python34\python \Python34\Scripts\mypy PROGRAM
-
-### Working with `virtualenv`
-
-If you are using [`virtualenv`](https://virtualenv.pypa.io/en/stable/),
-make sure you are running a python3 environment. Installing via `pip3`
-in a v2 environment will not configure the environment to run installed
-modules from the command line.
-
- $ python3 -m pip install -U virtualenv
- $ python3 -m virtualenv env
-
+ https://mypy-lang.blogspot.com/
-Quick start for contributing to mypy
-------------------------------------
-
-If you want to contribute, first clone the mypy git repository:
-
- $ git clone https://github.com/python/mypy.git
-
-From the mypy directory, use pip to install mypy:
-
- $ cd mypy
- $ python3 -m pip install -U .
-
-Replace `python3` with your Python 3 interpreter. You may have to do
-the above as root. For example, in Ubuntu:
-
- $ sudo python3 -m pip install -U .
-
-Now you can use the `mypy` program just as above. In case of trouble
-see "Troubleshooting" above.
-
-> NOTE: Installing with sudo can be a security risk. Please try with the `--user` flag first.
- $ python3 -m pip install --user -U .
-
-
-Tests
------
-
-The basic way to run tests:
-
- $ pip3 install -r test-requirements.txt
- $ python2 -m pip install -U typing
- $ ./runtests.py
-
-For more on the tests, such as how to write tests and how to control
-which tests to run, see [Test README.md](test-data/unit/README.md).
-
-
-Development status
-------------------
-
-Mypy is beta software, but it has already been used in production
-for several years at Dropbox and in many other organizations, and
-it has an extensive test suite.
-
-See [the roadmap](ROADMAP.md) if you are interested in plans for the
-future.
-
-
-Changelog
----------
-
-Follow mypy's updates on the blog: https://mypy-lang.blogspot.com/
+Contributing
+------------
-Issue tracker
--------------
+Help in testing, development, documentation and other tasks is
+highly appreciated and useful to the project. There are tasks for
+contributors of all experience levels.
-Please report any bugs and enhancement ideas using the mypy issue
-tracker: https://github.com/python/mypy/issues
+To get started with developing mypy, see [CONTRIBUTING.md](CONTRIBUTING.md).
-If you have any questions about using mypy or types, please ask
-in the typing gitter instead: https://gitter.im/python/typing
+If you need help getting started, don't hesitate to ask on [gitter](https://gitter.im/python/typing).
-Compiled version of mypy
-------------------------
+Mypyc and compiled version of mypy
+----------------------------------
-We have built a compiled version of mypy using the [mypyc
-compiler](https://github.com/python/mypy/tree/master/mypyc) for
-mypy-annotated Python code. It is approximately 4 times faster than
-interpreted mypy and is available (and the default) for 64-bit
-Windows, macOS, and Linux.
+[Mypyc](https://github.com/mypyc/mypyc) uses Python type hints to compile Python
+modules to faster C extensions. Mypy is itself compiled using mypyc: this makes
+mypy approximately 4 times faster than if interpreted!
To install an interpreted mypy instead, use:
- $ python3 -m pip install --no-binary mypy -U mypy
+ python3 -m pip install --no-binary mypy -U mypy
-If you wish to test out the compiled version of a development
-version of mypy, you can directly install a binary from
+To use a compiled version of a development
+version of mypy, directly install a binary from
https://github.com/mypyc/mypy_mypyc-wheels/releases/latest.
-
-Help wanted
------------
-
-Any help in testing, development, documentation and other tasks is
-highly appreciated and useful to the project. There are tasks for
-contributors of all experience levels. If you're just getting started,
-ask on the [gitter chat](https://gitter.im/python/typing) for ideas of good
-beginner issues.
-
-For more details, see the file [CONTRIBUTING.md](CONTRIBUTING.md).
-
-
-License
--------
-
-Mypy is licensed under the terms of the MIT License (see the file
-LICENSE).
+To contribute to the mypyc project, check out https://github.com/mypyc/mypyc
diff --git a/build-requirements.txt b/build-requirements.txt
index eee2f9d..52c518d 100644
--- a/build-requirements.txt
+++ b/build-requirements.txt
@@ -1,4 +1,5 @@
+# NOTE: this needs to be kept in sync with the "requires" list in pyproject.toml
-r mypy-requirements.txt
-types-typed-ast>=1.4.0,<1.5.0
-types-toml>=0.0
-types-enum34>=0.0; python_version == '3.5'
+types-psutil
+types-setuptools
+types-typed-ast>=1.5.8,<1.6.0
diff --git a/conftest.py b/conftest.py
index 83a6689..0bd7b6a 100644
--- a/conftest.py
+++ b/conftest.py
@@ -1,8 +1,8 @@
+from __future__ import annotations
+
import os.path
-pytest_plugins = [
- 'mypy.test.data',
-]
+pytest_plugins = ["mypy.test.data"]
def pytest_configure(config):
@@ -14,5 +14,6 @@ def pytest_configure(config):
# This function name is special to pytest. See
# http://doc.pytest.org/en/latest/writing_plugins.html#initialization-command-line-and-configuration-hooks
def pytest_addoption(parser) -> None:
- parser.addoption('--bench', action='store_true', default=False,
- help='Enable the benchmark test runs')
+ parser.addoption(
+ "--bench", action="store_true", default=False, help="Enable the benchmark test runs"
+ )
diff --git a/debian/changelog b/debian/changelog
index 6c121c1..802ce31 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,199 @@
+mypy (1.0.1-1) unstable; urgency=medium
+
+ * New upstream version
+ * Remove trailing whitespace in debian/changelog (routine-update)
+ * Drop the cherry-picked 32-bits.patch, it is part of the new release.
+
+ -- Michael R. Crusoe Fri, 24 Feb 2023 12:56:47 +0100
+
+mypy (1.0.0-1) unstable; urgency=medium
+
+ * Add patch to fix test for 32-bit systems, cherry-picked from upstream.
+
+ -- Michael R. Crusoe Tue, 14 Feb 2023 00:24:00 +0100
+
+mypy (0.991-3) unstable; urgency=medium
+
+ * Team upload.
+ * Add a Depends on python3-tomli for the autopkgtest, so it can run on
+ Python 3.11, and test all branches.
+
+ -- Stefano Rivera Mon, 13 Feb 2023 08:05:19 -0400
+
+mypy (1.0.0-1~0exp1) experimental; urgency=medium
+
+ * Revert: Try the same level of optimization on all archs.
+
+ -- Michael R. Crusoe Mon, 13 Feb 2023 13:22:02 +0100
+
+mypy (1.0.0-1~0exp) experimental; urgency=medium
+
+ * New upstream release.
+ * Standards-Version: 4.6.2 (routine-update)
+ * Use secure URI in Homepage field.
+ * d/control: Build-Depend on the generic python3-venv.
+ * Try the same level of optimization on all archs.
+ * d/control: remove unused dependency on distutils.
+ * d/source/lintian-overrides: ignore false positives about distutils.
+ * d/control: build-dep on furo; drop patch to use the standard sphinx
+ theme.
+ * d/tests/control: tests need python3-tomli
+
+ -- Michael R. Crusoe Thu, 09 Feb 2023 18:55:44 +0100
+
+mypy (0.991-2) unstable; urgency=medium
+
+ * Team upload.
+ * Drop dependency on python3.10-venv
+
+ -- Jochen Sprickerhof Sun, 05 Feb 2023 16:19:50 +0100
+
+mypy (0.991-1) unstable; urgency=medium
+
+ * New upstream version
+ * Also need python3.11-venv
+
+ -- Michael R. Crusoe Wed, 16 Nov 2022 14:05:35 +0100
+
+mypy (0.990-1) unstable; urgency=medium
+
+ * New upstream version
+ * Remove debian/patches/psutils-in-typeshed as it is no longer needed.
+ All other patches refreshed.
+ * d/control: Need newer typeshed for the selftests.
+
+ -- Michael R. Crusoe Tue, 08 Nov 2022 15:33:50 +0100
+
+mypy (0.982-2) unstable; urgency=medium
+
+ * Team upload
+
+ [ Jochen Sprickerhof ]
+ * d/control: Drop unused dependency on python3-typed-ast
+ This dependency is only required for Python < 3.8.
+
+ -- Sebastian Ramacher Thu, 13 Oct 2022 23:39:29 +0200
+
+mypy (0.982-1) unstable; urgency=medium
+
+ * New upstream version
+
+ -- Michael R. Crusoe Tue, 04 Oct 2022 10:29:51 +0200
+
+mypy (0.981-2) unstable; urgency=medium
+
+ * d/control: this release breaks older releases of the dataclasses-
+ json Python package.
+
+ -- Michael R. Crusoe Sun, 02 Oct 2022 12:53:41 +0200
+
+mypy (0.981-1) unstable; urgency=medium
+
+ * New upstream version
+ * removed 4 patches applied upstream; refreshed the rest.
+ * python3.10-venv is now needed for the tests
+ * debian/rules: skip testCustomTypeshedDirWithRelativePathDoesNotCrash
+
+ -- Michael R. Crusoe Thu, 29 Sep 2022 11:52:42 +0200
+
+mypy (0.971-4) unstable; urgency=medium
+
+ * Team upload.
+ * Patch: sleep() in mypyc test suite to avoid races and fix FTBFS on s390x.
+
+ -- Stefano Rivera Mon, 26 Sep 2022 17:18:20 +0200
+
+mypy (0.971-3) unstable; urgency=medium
+
+ [ Michael R. Crusoe ]
+ * Stop skipping tests.
+
+ [ Stefano Rivera ]
+ * Team upload.
+ * Depend on python3-setuptools for autopkgtest, no longer a dependency of
+ python3-virtualenv.
+ * Recommend python3-setuptools, required by mypyc.
+ * Refresh PQ patches.
+ * Patch: Python 3.10.7 support.
+
+ -- Stefano Rivera Mon, 26 Sep 2022 12:36:51 +0200
+
+mypy (0.971-2) unstable; urgency=medium
+
+ * debian/rules: Only run the tests for arch-dependent builds
+ * debian/patches/intersphinx: update patch for "six" links
+
+ -- Michael R. Crusoe Wed, 17 Aug 2022 15:14:24 +0200
+
+mypy (0.971-1) unstable; urgency=medium
+
+ * New upstream version
+ * debian/clean: add additional directories & files
+ * debian/patches/walrus.patch: cherry-pick patch from upstream to fix the
+ walrus tests. Closes: #1017145, #1017312
+
+ -- Michael R. Crusoe Mon, 15 Aug 2022 14:41:00 +0200
+
+mypy (0.961-1) unstable; urgency=medium
+
+ * New upstream version
+
+ -- Michael R. Crusoe Mon, 06 Jun 2022 21:29:13 +0200
+
+mypy (0.960-1) unstable; urgency=medium
+
+ * New upstream version
+ * Standards-Version: 4.6.1 (routine-update)
+ * Refresh patches
+ * Skip the furo docs theme; it is no packaged yet for Debian.
+ * debian/copyright: remove unused entries
+
+ -- Michael R. Crusoe Thu, 02 Jun 2022 15:10:28 +0200
+
+mypy (0.942-1) unstable; urgency=medium
+
+ [ Stefano Rivera ]
+ * Team upload.
+ * New upstream version
+ * Patch: Python 3.10.3 support. Closes: #1008259
+
+ [ Michael R. Crusoe ]
+ * Drop the python 3.10.1 patch, no longer needed
+
+ -- Stefano Rivera Sat, 02 Apr 2022 22:07:43 -0400
+
+mypy (0.931-1) unstable; urgency=medium
+
+ * New upstream version
+ * Remove mypc_fix, was incorporated upstream.
+ * Skip some tests due to 64-bit assumptions. Closes: #1002909
+
+ -- Michael R. Crusoe Mon, 10 Jan 2022 10:42:31 +0100
+
+mypy (0.930-1) unstable; urgency=medium
+
+ [ Andreas Tille ]
+ * Move package to Debian Python Team
+
+ [ Michael R. Crusoe ]
+ * New upstream version
+ * Refresh patches
+ * debian/patches/mypyc_fix: new patch as per upstream suggestion
+ * debian/{rules,tests/run-unit-test}: skip fewer tests
+
+ -- Michael R. Crusoe Mon, 27 Dec 2021 10:16:35 +0100
+
+mypy (0.921-1) unstable; urgency=medium
+
+ * New upstream version
+ * debian/rules: skip testErrorOutput for now
+ * debian/patches/python3.10.1{,_part2}: cherry-pick patches from upstream
+ for Python 3.10.1 compat.
+ * debian/control: add tomli build-dep
+ * debian/patches: small refresh
+
+ -- Michael R. Crusoe Tue, 21 Dec 2021 21:04:13 +0100
+
mypy (0.910-4) unstable; urgency=medium
[ Antonio Terceiro ]
diff --git a/debian/clean b/debian/clean
index e7fe5c3..a33e783 100644
--- a/debian/clean
+++ b/debian/clean
@@ -3,6 +3,10 @@ extensions/mypy_extensions.egg-info/
.pytest_cache/
docs/build/
mypy/__pycache__/
+mypyc/lib-rt/build/
+mypyc/external/googletest/make/*.o
+mypyc/external/googletest/make/*.a
+mypyc/lib-rt/*.so
test-data/packages/typedpkg/build/
test-data/packages/typedpkg/dist/
test-data/packages/typedpkg/typedpkg.egg-info/
diff --git a/debian/control b/debian/control
index 64910fb..936f69e 100644
--- a/debian/control
+++ b/debian/control
@@ -1,37 +1,40 @@
Source: mypy
-Maintainer: Debian Med Packaging Team
+Maintainer: Debian Python Team
Uploaders: Michael R. Crusoe
Section: utils
Testsuite: autopkgtest-pkg-python
Priority: optional
Build-Depends: debhelper-compat (= 13),
dh-python,
+ python3-setuptools,
+ pybuild-plugin-pyproject,
+ python3-wheel,
flake8,
help2man,
python3-all,
python3-lxml,
python3-pytest-xdist ,
python3-pytest-cov ,
- python3-setuptools,
python3-sphinx ,
- python3-sphinx-rtd-theme ,
- python3-typed-ast,
- python3-typed-ast (<< 1.5.0),
+ furo ,
python3-typeshed,
python3-psutil,
python3-mypy-extensions,
python3-typing-extensions,
python3-virtualenv ,
+ python3-typeshed ,
python3-all-dev,
+ python3-tomli,
+ python3-venv ,
python3-doc ,
cython-doc ,
python-six-doc ,
python-setuptools-doc ,
python-attr-doc
-Standards-Version: 4.6.0
-Vcs-Browser: https://salsa.debian.org/med-team/mypy
-Vcs-Git: https://salsa.debian.org/med-team/mypy.git
-Homepage: http://www.mypy-lang.org/
+Standards-Version: 4.6.2
+Vcs-Browser: https://salsa.debian.org/python-team/packages/mypy
+Vcs-Git: https://salsa.debian.org/python-team/packages/mypy.git
+Homepage: https://www.mypy-lang.org/
Rules-Requires-Root: no
Package: mypy
@@ -39,10 +42,10 @@ Architecture: all
Depends: ${misc:Depends},
${python3:Depends},
python3-mypy (>= ${binary:Version})
+Recommends: python3-typeshed
Suggests: mypy-doc
Breaks: python3-mypy (= 0.740-1)
Replaces: python3-mypy (= 0.740-1)
-Recommends: python3-typeshed
Description: optional static typing for Python
Add type annotations to your Python programs, and use mypy to type check them.
Mypy is essentially a Python linter on steroids, and it can catch many
@@ -54,6 +57,7 @@ Description: optional static typing for Python
Package: mypy-doc
Architecture: all
+Multi-Arch: foreign
Section: doc
Depends: ${misc:Depends},
${sphinxdoc:Depends}
@@ -79,12 +83,11 @@ Section: python
Depends: ${misc:Depends},
${python3:Depends},
${shlibs:Depends},
- python3-typed-ast,
python3-mypy-extensions,
python3-psutil,
- python3-distutils,
python3-pkg-resources
-Recommends: python3-lxml
+Recommends: python3-lxml,
+ python3-setuptools
Description: public modules for mypy (Python 3)
Add type annotations to your Python programs, and use mypy to type check them.
Mypy is essentially a Python linter on steroids, and it can catch many
diff --git a/debian/copyright b/debian/copyright
index 46e590e..221f573 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -7,22 +7,9 @@ Copyright: © 2015-2016 Jukka Lehtosalo and contributors
License: Expat
Files: debian/*
-Copyright: © 2016-2020 Michael R. Crusoe
+Copyright: © 2016-2022 Michael R. Crusoe
License: Expat
-Files: test-data/stdlib-samples/3.2/test/test_getopt.py
-Copyright: 2010 David Goodger
-License: Python-2.0
-
-Files: test-data/stdlib-samples/3.2/test/test_shutil.py
-Copyright: 2003 Python Software Foundation
-License: Python-2.0
-
-Files: test-data/stdlib-samples/3.2/textwrap.py
-Copyright: 2003 Python Software Foundation
- 1999-2001 Gregory P. Ward
-License: Python-2.0
-
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@@ -41,197 +28,3 @@ License: Expat
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-
-License: Python-2.0
- PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
- --------------------------------------------
- .
- 1. This LICENSE AGREEMENT is between the Python Software Foundation
- ("PSF"), and the Individual or Organization ("Licensee") accessing and
- otherwise using this software ("Python") in source or binary form and
- its associated documentation.
- .
- 2. Subject to the terms and conditions of this License Agreement, PSF
- hereby grants Licensee a nonexclusive, royalty-free, world-wide
- license to reproduce, analyze, test, perform and/or display publicly,
- prepare derivative works, distribute, and otherwise use Python
- alone or in any derivative version, provided, however, that PSF's
- License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
- 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights
- Reserved" are retained in Python alone or in any derivative version
- prepared by Licensee.
- .
- 3. In the event Licensee prepares a derivative work that is based on
- or incorporates Python or any part thereof, and wants to make
- the derivative work available to others as provided herein, then
- Licensee hereby agrees to include in any such work a brief summary of
- the changes made to Python.
- .
- 4. PSF is making Python available to Licensee on an "AS IS"
- basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
- IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
- DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
- FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
- INFRINGE ANY THIRD PARTY RIGHTS.
- .
- 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
- FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
- A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
- OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
- .
- 6. This License Agreement will automatically terminate upon a material
- breach of its terms and conditions.
- .
- 7. Nothing in this License Agreement shall be deemed to create any
- relationship of agency, partnership, or joint venture between PSF and
- Licensee. This License Agreement does not grant permission to use PSF
- trademarks or trade name in a trademark sense to endorse or promote
- products or services of Licensee, or any third party.
- .
- 8. By copying, installing or otherwise using Python, Licensee
- agrees to be bound by the terms and conditions of this License
- Agreement.
- .
- BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
- -------------------------------------------
- .
- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
- .
- 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
- office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
- Individual or Organization ("Licensee") accessing and otherwise using
- this software in source or binary form and its associated
- documentation ("the Software").
- .
- 2. Subject to the terms and conditions of this BeOpen Python License
- Agreement, BeOpen hereby grants Licensee a non-exclusive,
- royalty-free, world-wide license to reproduce, analyze, test, perform
- and/or display publicly, prepare derivative works, distribute, and
- otherwise use the Software alone or in any derivative version,
- provided, however, that the BeOpen Python License is retained in the
- Software, alone or in any derivative version prepared by Licensee.
- .
- 3. BeOpen is making the Software available to Licensee on an "AS IS"
- basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
- IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
- DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
- FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
- INFRINGE ANY THIRD PARTY RIGHTS.
- .
- 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
- SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
- AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
- DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
- .
- 5. This License Agreement will automatically terminate upon a material
- breach of its terms and conditions.
- .
- 6. This License Agreement shall be governed by and interpreted in all
- respects by the law of the State of California, excluding conflict of
- law provisions. Nothing in this License Agreement shall be deemed to
- create any relationship of agency, partnership, or joint venture
- between BeOpen and Licensee. This License Agreement does not grant
- permission to use BeOpen trademarks or trade names in a trademark
- sense to endorse or promote products or services of Licensee, or any
- third party. As an exception, the "BeOpen Python" logos available at
- http://www.pythonlabs.com/logos.html may be used according to the
- permissions granted on that web page.
- .
- 7. By copying, installing or otherwise using the software, Licensee
- agrees to be bound by the terms and conditions of this License
- Agreement.
- .
- CNRI OPEN SOURCE LICENSE AGREEMENT (for Python 1.6b1)
- --------------------------------------------------
- .
- IMPORTANT: PLEASE READ THE FOLLOWING AGREEMENT CAREFULLY.
- .
- BY CLICKING ON "ACCEPT" WHERE INDICATED BELOW, OR BY COPYING,
- INSTALLING OR OTHERWISE USING PYTHON 1.6, beta 1 SOFTWARE, YOU ARE
- DEEMED TO HAVE AGREED TO THE TERMS AND CONDITIONS OF THIS LICENSE
- AGREEMENT.
- .
- 1. This LICENSE AGREEMENT is between the Corporation for National
- Research Initiatives, having an office at 1895 Preston White Drive,
- Reston, VA 20191 ("CNRI"), and the Individual or Organization
- ("Licensee") accessing and otherwise using Python 1.6, beta 1
- software in source or binary form and its associated documentation,
- as released at the www.python.org Internet site on August 4, 2000
- ("Python 1.6b1").
- .
- 2. Subject to the terms and conditions of this License Agreement, CNRI
- hereby grants Licensee a non-exclusive, royalty-free, world-wide
- license to reproduce, analyze, test, perform and/or display
- publicly, prepare derivative works, distribute, and otherwise use
- Python 1.6b1 alone or in any derivative version, provided, however,
- that CNRIs License Agreement is retained in Python 1.6b1, alone or
- in any derivative version prepared by Licensee.
- .
- Alternately, in lieu of CNRIs License Agreement, Licensee may
- substitute the following text (omitting the quotes): "Python 1.6,
- beta 1, is made available subject to the terms and conditions in
- CNRIs License Agreement. This Agreement may be located on the
- Internet using the following unique, persistent identifier (known
- as a handle): 1895.22/1011. This Agreement may also be obtained
- from a proxy server on the Internet using the
- URL:http://hdl.handle.net/1895.22/1011".
- .
- 3. In the event Licensee prepares a derivative work that is based on
- or incorporates Python 1.6b1 or any part thereof, and wants to make
- the derivative work available to the public as provided herein,
- then Licensee hereby agrees to indicate in any such work the nature
- of the modifications made to Python 1.6b1.
- .
- 4. CNRI is making Python 1.6b1 available to Licensee on an "AS IS"
- basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
- IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
- DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR
- FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6b1
- WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
- .
- 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
- SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR
- LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING PYTHON 1.6b1,
- OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY
- THEREOF.
- .
- 6. This License Agreement will automatically terminate upon a material
- breach of its terms and conditions.
- .
- 7. This License Agreement shall be governed by and interpreted in all
- respects by the law of the State of Virginia, excluding conflict of
- law provisions. Nothing in this License Agreement shall be deemed
- to create any relationship of agency, partnership, or joint venture
- between CNRI and Licensee. This License Agreement does not grant
- permission to use CNRI trademarks or trade name in a trademark
- sense to endorse or promote products or services of Licensee, or
- any third party.
- .
- 8. By clicking on the "ACCEPT" button where indicated, or by copying,
- installing or otherwise using Python 1.6b1, Licensee agrees to be
- bound by the terms and conditions of this License Agreement.
- .
- ACCEPT
- .
- CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
- --------------------------------------------------
- .
- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
- The Netherlands. All rights reserved.
- .
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Stichting Mathematisch
- Centrum or CWI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior
- permission.
- .
- STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
- THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
- FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/debian/patches/intersphinx b/debian/patches/intersphinx
index 0f777b3..d3e8971 100644
--- a/debian/patches/intersphinx
+++ b/debian/patches/intersphinx
@@ -1,23 +1,29 @@
-Author: Michael R. Crusoe
-Description: link to local documenatin
+From: "Michael R. Crusoe"
+Date: Sat, 2 Apr 2022 17:49:43 -0400
+Subject: link to local documenatin
+
Forwarded: not-needed
+---
+ docs/source/conf.py | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
--- mypy.orig/docs/source/conf.py
+++ mypy/docs/source/conf.py
-@@ -271,12 +271,12 @@
- rst_prolog = '.. |...| unicode:: U+2026 .. ellipsis\n'
+@@ -265,12 +265,12 @@
+ rst_prolog = ".. |...| unicode:: U+2026 .. ellipsis\n"
intersphinx_mapping = {
-- 'python': ('https://docs.python.org/3', None),
-- 'six': ('https://six.readthedocs.io', None),
-- 'attrs': ('http://www.attrs.org/en/stable', None),
-- 'cython': ('http://docs.cython.org/en/latest', None),
-+ 'python': ('https://docs.python.org/3', f'/usr/share/doc/python{sys.version_info.major}.{sys.version_info.minor}/html/objects.inv'),
-+ 'six': ('https://six.readthedocs.io', '/usr/share/doc/python-six/html/objects.inv'),
-+ 'attrs': ('http://www.attrs.org/en/stable', '/usr/share/doc/python-attr-doc/html/objects.inv'),
-+ 'cython': ('http://docs.cython.org/en/latest', '/usr/share/doc/cython-doc/html/objects.inv'),
- 'monkeytype': ('https://monkeytype.readthedocs.io/en/latest', None),
-- 'setuptools': ('https://setuptools.readthedocs.io/en/latest', None),
-+ 'setuptools': ('https://setuptools.readthedocs.io/en/latest', '/usr/share/doc/python-setuptools-doc/html/objects.inv'),
+- "python": ("https://docs.python.org/3", None),
+- "six": ("https://six.readthedocs.io", None),
+- "attrs": ("http://www.attrs.org/en/stable", None),
+- "cython": ("http://docs.cython.org/en/latest", None),
++ "python": ("https://docs.python.org/3", f'/usr/share/doc/python{sys.version_info.major}.{sys.version_info.minor}/html/objects.inv'),
++ "six": ("https://six.readthedocs.io", '/usr/share/doc/python-six-doc/html/objects.inv'),
++ "attrs": ("http://www.attrs.org/en/stable", '/usr/share/doc/python-attr-doc/html/objects.inv'),
++ "cython": ("http://docs.cython.org/en/latest", '/usr/share/doc/cython-doc/html/objects.inv'),
+ "monkeytype": ("https://monkeytype.readthedocs.io/en/latest", None),
+- "setuptools": ("https://setuptools.readthedocs.io/en/latest", None),
++ "setuptools": ("https://setuptools.readthedocs.io/en/latest", '/usr/share/doc/python-setuptools-doc/html/objects.inv'),
}
diff --git a/debian/patches/psutils-in-typeshed b/debian/patches/psutils-in-typeshed
deleted file mode 100644
index 5923cfc..0000000
--- a/debian/patches/psutils-in-typeshed
+++ /dev/null
@@ -1,14 +0,0 @@
-Author: Antonio Terceiro
-Description: drop typing ignore for psutil (now provided by python3-typeshed)
-Forwarded: not-needed
---- a/mypy/dmypy_server.py
-+++ b/mypy/dmypy_server.py
-@@ -874,7 +874,7 @@ MiB = 2**20 # type: Final
- def get_meminfo() -> Dict[str, Any]:
- res = {} # type: Dict[str, Any]
- try:
-- import psutil # type: ignore # It's not in typeshed yet
-+ import psutil
- except ImportError:
- res['memory_psutil_missing'] = (
- 'psutil not found, run pip install mypy[dmypy] '
diff --git a/debian/patches/python3.10.3 b/debian/patches/python3.10.3
new file mode 100644
index 0000000..dcdea39
--- /dev/null
+++ b/debian/patches/python3.10.3
@@ -0,0 +1,33 @@
+From: Stanislav Levin
+Date: Fri, 25 Mar 2022 18:54:03 +0300
+Subject: testcmdline: Sync assumption about error message for Python 3.10.3
+ (#12452)
+
+Python 3.10.3 is more correct about syntax error for
+`mypy` test case `testBlocker`.
+
+See https://bugs.python.org/issue46240 for details.
+
+Closes #12451
+
+Signed-off-by: Stanislav Levin
+Bug-Upstream: https://github.com/python/mypy/issues/12451
+Bug-Debian: https://bugs.debian.org/1008259
+Origin: upstream, https://github.com/python/mypy/commit/6b0e8485ac20a15fb7ad8762e14315c9e9bdc349
+---
+ test-data/unit/cmdline.test | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- mypy.orig/test-data/unit/cmdline.test
++++ mypy/test-data/unit/cmdline.test
+@@ -1310,6 +1310,10 @@
+ pkg/x.py:1: error: invalid syntax
+ Found 1 error in 1 file (errors prevented further checking)
+ == Return code: 2
++[out version>=3.10.3]
++pkg/x.py:1: error: invalid syntax
++Found 1 error in 1 file (errors prevented further checking)
++== Return code: 2
+
+ [case testCmdlinePackageAndFile]
+ # cmd: mypy -p pkg file
diff --git a/debian/patches/series b/debian/patches/series
index 67116b9..4c835e7 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,3 @@
verbose
intersphinx
-psutils-in-typeshed
+python3.10.3
diff --git a/debian/patches/verbose b/debian/patches/verbose
index 8f9492a..25a53b8 100644
--- a/debian/patches/verbose
+++ b/debian/patches/verbose
@@ -1,12 +1,18 @@
-Author: Michael R. Crusoe
-Description: make the build more verbose
+From: "Michael R. Crusoe"
+Date: Sat, 2 Apr 2022 17:49:43 -0400
+Subject: make the build more verbose
+
Forwarded: not-needed
+---
+ setup.py | 1 +
+ 1 file changed, 1 insertion(+)
+
--- mypy.orig/setup.py
+++ mypy/setup.py
-@@ -151,6 +151,7 @@
+@@ -165,6 +165,7 @@
# Use multi-file compilation mode on windows because without it
# our Appveyor builds run out of memory sometimes.
- multi_file=sys.platform == 'win32' or force_multifile,
+ multi_file=sys.platform == "win32" or force_multifile,
+ verbose=True,
)
else:
diff --git a/debian/rules b/debian/rules
index a436480..b477832 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,4 @@
#!/usr/bin/make -f
-SHELL=bash # needed for the <(echo …) process subsitution temporary file
- # tricks with help2man
export DH_VERBOSE=1
export PYBUILD_DESTDIR_python3=debian/python3-mypy
export PYBUILD_NAME=mypy
@@ -45,13 +43,14 @@ debian/sphinx/stubgen_options.rst: docs/source/stubgen.rst
sed -n -e '/stubgen --help/,$$ {/stubgen --help/d; p}' $< > $@
override_dh_auto_build-arch:
-ifneq (,$(filter $(DEB_BUILD_ARCH),mips64el mipsel alpha ia64 m68k powerpc riscv64 sh4 sparc64))
+ifneq (,$(filter $(DEB_BUILD_ARCH), mips64el mipsel alpha ia64 m68k powerpc riscv64 sh4 sparc64))
MYPY_USE_MYPYC=0 dh_auto_build
else
MYPY_USE_MYPYC=1 dh_auto_build
endif
override_dh_auto_build-indep: manpages
+ MYPY_USE_MYPYC=0 dh_auto_build
ifeq (,$(filter nodoc,$(DEB_BUILD_PROFILES)))
PYTHONPATH=$(CURDIR) $(MAKE) -C docs html
endif
@@ -72,7 +71,7 @@ override_dh_auto_install:
dh_movefiles --package=mypy --sourcedir=debian/python3-mypy usr/bin
rm -Rf debian/python3-mypy/usr/bin
-override_dh_auto_test:
+override_dh_auto_test-arch:
ifeq (,$(filter nocheck,$(DEB_BUILD_PROFILES)))
export TEST_MYPYC=1
PYBUILD_SYSTEM=custom \
@@ -80,11 +79,13 @@ ifeq (,$(filter nocheck,$(DEB_BUILD_PROFILES)))
--config-file {dir}/mypy_self_check.ini -p mypy" dh_auto_test
dh_auto_install
set -e; for v in $(PY3VERS); do \
- PATH=$$PATH:$(CURDIR)/debian/mypy/usr/bin/ python$$v -m pytest -n auto \
- -o testpaths="mypy/test mypyc/test" -o python_files=test*.py \
- -k "not (StubtestMiscUnit or StubtestUnit or testSubclassSpecialize1 or testSubclassSpecialize2 or testMultiModuleSpecialize or testMultiModuleSpecialize_multi or testMultiModuleSpecialize_separate)" \
- -o python_classes= -o python_functions=; \
+ PYTHONPATH=$$(pybuild --print build_dir --pyver $$v | awk '{ print $$3 }') PATH=$$PATH:$(CURDIR)/debian/python3-mypy/usr/bin/ python$$v -m pytest -n auto \
+ -o testpaths="mypy/test mypyc/test" -o python_files=test*.py -k 'not testCustomTypeshedDirWithRelativePathDoesNotCrash' \
+ -o python_classes= -o python_functions= ; \
done
endif
+override_dh_auto_test-indep:
+ echo No tests to run for the "mypy" package, only for "python3-mypy"
+
.PHONY: manpages
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
new file mode 100644
index 0000000..3559148
--- /dev/null
+++ b/debian/source/lintian-overrides
@@ -0,0 +1,3 @@
+uses-python-distutils [mypyc/build.py:53]
+uses-python-distutils [mypyc/lib-rt/setup.py:9]
+uses-python-distutils [test-data/packages/typedpkg_ns_b-stubs/setup.py:5]
diff --git a/debian/tests/control b/debian/tests/control
index 9687171..65eb079 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -1,3 +1,11 @@
Tests: run-unit-test
-Depends: mypy, python3-typeshed, python3-pytest-xdist, python3-virtualenv, python3-lxml
+Depends: gcc,
+ @,
+ python3-dev,
+ python3-lxml,
+ python3-pytest-xdist,
+ python3-setuptools,
+ python3-tomli,
+ python3-typeshed (>= 0.0~git20221107.4f381af),
+ python3-virtualenv
Restrictions: allow-stderr
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
index 5acabc8..16bb59c 100755
--- a/debian/tests/run-unit-test
+++ b/debian/tests/run-unit-test
@@ -12,13 +12,19 @@ fi
cd "$AUTOPKGTEST_TMP"
+mypy --help
+mypyc --help
+stubgen --help
+stubtest --help
+
export TEST_MYPYC=1
-MYPY_TEST_PREFIX=${START} pytest-3 -n auto -v -o testpaths="mypy/test mypyc/test" \
- -o python_files=test*.py -o python_classes= \
- -o python_functions= -k 'not (StubtestMiscUnit or StubtestUnit or testSubclassSpecialize1 or testSubclassSpecialize2 or testMultiModuleSpecialize or testMultiModuleSpecialize_multi or testMultiModuleSpecialize_separate)' \
- --pyargs mypy
+rm -Rf mypy mypyc
cp -r /usr/lib/python3/dist-packages/mypy ./
+cp -r /usr/lib/python3/dist-packages/mypyc ./
+
+MYPY_TEST_PREFIX=${START} pytest-3 -v --pyargs mypy
+
rm -Rf mypy/typeshed
-#/usr/bin/mypy --config-file ${START}/mypy_self_check.ini mypy
+/usr/bin/mypy --config-file ${START}/mypy_self_check.ini mypy
diff --git a/docs/README.md b/docs/README.md
index 2122eef..0d574c9 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -6,7 +6,7 @@ What's this?
This directory contains the source code for Mypy documentation (under `source/`)
and build scripts. The documentation uses Sphinx and reStructuredText. We use
-`sphinx-rtd-theme` as the documentation theme.
+`furo` as the documentation theme.
Building the documentation
--------------------------
diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt
index d20641e..395964a 100644
--- a/docs/requirements-docs.txt
+++ b/docs/requirements-docs.txt
@@ -1,2 +1,2 @@
-Sphinx >= 1.4.4
-sphinx-rtd-theme >= 0.1.9
+sphinx>=4.2.0,<5.0.0
+furo>=2022.3.4
diff --git a/docs/source/additional_features.rst b/docs/source/additional_features.rst
index fc15159..ef5bf9e 100644
--- a/docs/source/additional_features.rst
+++ b/docs/source/additional_features.rst
@@ -21,10 +21,10 @@ They can be defined using the :py:func:`@dataclasses.dataclass
@dataclass
class Application:
name: str
- plugins: List[str] = field(default_factory=list)
+ plugins: list[str] = field(default_factory=list)
test = Application("Testing...") # OK
- bad = Application("Testing...", "with plugin") # Error: List[str] expected
+ bad = Application("Testing...", "with plugin") # Error: list[str] expected
Mypy will detect special methods (such as :py:meth:`__lt__ `) depending on the flags used to
define dataclasses. For example:
@@ -177,7 +177,7 @@ Caveats/Known Issues
will complain about not understanding the argument and the type annotation in
:py:meth:`__init__ ` will be replaced by ``Any``.
-* :ref:`Validator decorators `
+* :ref:`Validator decorators `
and `default decorators `_
are not type-checked against the attribute they are setting/validating.
diff --git a/docs/source/builtin_types.rst b/docs/source/builtin_types.rst
index 6abd525..37b5616 100644
--- a/docs/source/builtin_types.rst
+++ b/docs/source/builtin_types.rst
@@ -15,8 +15,8 @@ Type Description
``int`` integer
``float`` floating point number
``bool`` boolean value (subclass of ``int``)
-``str`` string (unicode in Python 3)
-``bytes`` 8-bit string
+``str`` text, sequence of unicode codepoints
+``bytes`` 8-bit string, sequence of byte values
``object`` an arbitrary object (``object`` is the common base class)
====================== ===============================
@@ -53,6 +53,7 @@ Type Description
``Iterable[int]`` iterable object containing ints
``Sequence[bool]`` sequence of booleans (read-only)
``Mapping[str, int]`` mapping from ``str`` keys to ``int`` values (read-only)
+``type[C]`` type object of ``C`` (``C`` is a class/type variable/union of types)
====================== ===============================
The type ``dict`` is a *generic* class, signified by type arguments within
@@ -82,6 +83,7 @@ Type Description
``Iterable[int]`` iterable object containing ints
``Sequence[bool]`` sequence of booleans (read-only)
``Mapping[str, int]`` mapping from ``str`` keys to ``int`` values (read-only)
+``Type[C]`` type object of ``C`` (``C`` is a class/type variable/union of types)
====================== ===============================
``List`` is an alias for the built-in type ``list`` that supports
diff --git a/docs/source/casts.rst b/docs/source/casts.rst
deleted file mode 100644
index 61eeb30..0000000
--- a/docs/source/casts.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-.. _casts:
-
-Casts and type assertions
-=========================
-
-Mypy supports type casts that are usually used to coerce a statically
-typed value to a subtype. Unlike languages such as Java or C#,
-however, mypy casts are only used as hints for the type checker, and they
-don't perform a runtime type check. Use the function :py:func:`~typing.cast` to perform a
-cast:
-
-.. code-block:: python
-
- from typing import cast, List
-
- o: object = [1]
- x = cast(List[int], o) # OK
- y = cast(List[str], o) # OK (cast performs no actual runtime check)
-
-To support runtime checking of casts such as the above, we'd have to check
-the types of all list items, which would be very inefficient for large lists.
-Casts are used to silence spurious
-type checker warnings and give the type checker a little help when it can't
-quite understand what is going on.
-
-.. note::
-
- You can use an assertion if you want to perform an actual runtime check:
-
- .. code-block:: python
-
- def foo(o: object) -> None:
- print(o + 5) # Error: can't add 'object' and 'int'
- assert isinstance(o, int)
- print(o + 5) # OK: type of 'o' is 'int' here
-
-You don't need a cast for expressions with type ``Any``, or when
-assigning to a variable with type ``Any``, as was explained earlier.
-You can also use ``Any`` as the cast target type -- this lets you perform
-any operations on the result. For example:
-
-.. code-block:: python
-
- from typing import cast, Any
-
- x = 1
- x.whatever() # Type check error
- y = cast(Any, x)
- y.whatever() # Type check OK (runtime error)
diff --git a/docs/source/cheat_sheet.rst b/docs/source/cheat_sheet.rst
deleted file mode 100644
index 64a2d52..0000000
--- a/docs/source/cheat_sheet.rst
+++ /dev/null
@@ -1,282 +0,0 @@
-.. _cheat-sheet-py2:
-
-Type hints cheat sheet (Python 2)
-=================================
-
-This document is a quick cheat sheet showing how the :pep:`484` type
-language represents various common types in Python 2.
-
-.. note::
-
- Technically many of the type annotations shown below are redundant,
- because mypy can derive them from the type of the expression. So
- many of the examples have a dual purpose: show how to write the
- annotation, and show the inferred types.
-
-.. note::
-
- To check Python 2 code with mypy, you'll need to install mypy with
- ``pip install 'mypy[python2]'``.
-
-
-
-Built-in types
-**************
-
-.. code-block:: python
-
- from typing import List, Set, Dict, Tuple, Text, Optional
-
- # For simple built-in types, just use the name of the type
- x = 1 # type: int
- x = 1.0 # type: float
- x = True # type: bool
- x = "test" # type: str
- x = u"test" # type: unicode
-
- # For collections, the name of the type is capitalized, and the
- # name of the type inside the collection is in brackets
- x = [1] # type: List[int]
- x = {6, 7} # type: Set[int]
-
- # For mappings, we need the types of both keys and values
- x = {'field': 2.0} # type: Dict[str, float]
-
- # For tuples, we specify the types of all the elements
- x = (3, "yes", 7.5) # type: Tuple[int, str, float]
-
- # For textual data, use Text
- # ("Text" means "unicode" in Python 2 and "str" in Python 3)
- x = [u"one", u"two"] # type: List[Text]
-
- # Use Optional[] for values that could be None
- x = some_function() # type: Optional[str]
- # Mypy understands a value can't be None in an if-statement
- if x is not None:
- print x.upper()
- # If a value can never be None due to some invariants, use an assert
- assert x is not None
- print x.upper()
-
-Functions
-*********
-
-.. code-block:: python
-
- from typing import Callable, Iterator, Union, Optional, List
-
- # This is how you annotate a function definition
- def stringify(num):
- # type: (int) -> str
- """Your function docstring goes here after the type definition."""
- return str(num)
-
- # This function has no parameters and also returns nothing. Annotations
- # can also be placed on the same line as their function headers.
- def greet_world(): # type: () -> None
- print "Hello, world!"
-
- # And here's how you specify multiple arguments
- def plus(num1, num2):
- # type: (int, int) -> int
- return num1 + num2
-
- # Add type annotations for arguments with default values as though they
- # had no defaults
- def f(num1, my_float=3.5):
- # type: (int, float) -> float
- return num1 + my_float
-
- # An argument can be declared positional-only by giving it a name
- # starting with two underscores
- def quux(__x):
- # type: (int) -> None
- pass
-
- quux(3) # Fine
- quux(__x=3) # Error
-
- # This is how you annotate a callable (function) value
- x = f # type: Callable[[int, float], float]
-
- # A generator function that yields ints is secretly just a function that
- # returns an iterator of ints, so that's how we annotate it
- def g(n):
- # type: (int) -> Iterator[int]
- i = 0
- while i < n:
- yield i
- i += 1
-
- # There's an alternative syntax for functions with many arguments
- def send_email(address, # type: Union[str, List[str]]
- sender, # type: str
- cc, # type: Optional[List[str]]
- bcc, # type: Optional[List[str]]
- subject='',
- body=None # type: List[str]
- ):
- # type: (...) -> bool
- ...
-
-When you're puzzled or when things are complicated
-**************************************************
-
-.. code-block:: python
-
- from typing import Union, Any, List, Optional, cast
-
- # To find out what type mypy infers for an expression anywhere in
- # your program, wrap it in reveal_type(). Mypy will print an error
- # message with the type; remove it again before running the code.
- reveal_type(1) # -> Revealed type is "builtins.int"
-
- # Use Union when something could be one of a few types
- x = [3, 5, "test", "fun"] # type: List[Union[int, str]]
-
- # Use Any if you don't know the type of something or it's too
- # dynamic to write a type for
- x = mystery_function() # type: Any
-
- # If you initialize a variable with an empty container or "None"
- # you may have to help mypy a bit by providing a type annotation
- x = [] # type: List[str]
- x = None # type: Optional[str]
-
- # This makes each positional arg and each keyword arg a "str"
- def call(self, *args, **kwargs):
- # type: (*str, **str) -> str
- request = make_request(*args, **kwargs)
- return self.do_api_query(request)
-
- # Use a "type: ignore" comment to suppress errors on a given line,
- # when your code confuses mypy or runs into an outright bug in mypy.
- # Good practice is to comment every "ignore" with a bug link
- # (in mypy, typeshed, or your own code) or an explanation of the issue.
- x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
-
- # "cast" is a helper function that lets you override the inferred
- # type of an expression. It's only for mypy -- there's no runtime check.
- a = [4]
- b = cast(List[int], a) # Passes fine
- c = cast(List[str], a) # Passes fine (no runtime check)
- reveal_type(c) # -> Revealed type is "builtins.list[builtins.str]"
- print c # -> [4]; the object is not cast
-
- # If you want dynamic attributes on your class, have it override "__setattr__"
- # or "__getattr__" in a stub or in your source code.
- #
- # "__setattr__" allows for dynamic assignment to names
- # "__getattr__" allows for dynamic access to names
- class A:
- # This will allow assignment to any A.x, if x is the same type as "value"
- # (use "value: Any" to allow arbitrary types)
- def __setattr__(self, name, value):
- # type: (str, int) -> None
- ...
-
- a.foo = 42 # Works
- a.bar = 'Ex-parrot' # Fails type checking
-
-
-Standard "duck types"
-*********************
-
-In typical Python code, many functions that can take a list or a dict
-as an argument only need their argument to be somehow "list-like" or
-"dict-like". A specific meaning of "list-like" or "dict-like" (or
-something-else-like) is called a "duck type", and several duck types
-that are common in idiomatic Python are standardized.
-
-.. code-block:: python
-
- from typing import Mapping, MutableMapping, Sequence, Iterable
-
- # Use Iterable for generic iterables (anything usable in "for"),
- # and Sequence where a sequence (supporting "len" and "__getitem__") is
- # required
- def f(iterable_of_ints):
- # type: (Iterable[int]) -> List[str]
- return [str(x) for x in iterator_of_ints]
-
- f(range(1, 3))
-
- # Mapping describes a dict-like object (with "__getitem__") that we won't
- # mutate, and MutableMapping one (with "__setitem__") that we might
- def f(my_dict):
- # type: (Mapping[int, str]) -> List[int]
- return list(my_dict.keys())
-
- f({3: 'yes', 4: 'no'})
-
- def f(my_mapping):
- # type: (MutableMapping[int, str]) -> Set[str]
- my_mapping[5] = 'maybe'
- return set(my_mapping.values())
-
- f({3: 'yes', 4: 'no'})
-
-
-Classes
-*******
-
-.. code-block:: python
-
- class MyClass(object):
- # For instance methods, omit type for "self"
- def my_method(self, num, str1):
- # type: (int, str) -> str
- return num * str1
-
- # The "__init__" method doesn't return anything, so it gets return
- # type "None" just like any other method that doesn't return anything
- def __init__(self):
- # type: () -> None
- pass
-
- # User-defined classes are valid as types in annotations
- x = MyClass() # type: MyClass
-
-
-Miscellaneous
-*************
-
-.. code-block:: python
-
- import sys
- import re
- from typing import Match, AnyStr, IO
-
- # "typing.Match" describes regex matches from the re module
- x = re.match(r'[0-9]+', "15") # type: Match[str]
-
- # Use IO[] for functions that should accept or return any
- # object that comes from an open() call (IO[] does not
- # distinguish between reading, writing or other modes)
- def get_sys_IO(mode='w'):
- # type: (str) -> IO[str]
- if mode == 'w':
- return sys.stdout
- elif mode == 'r':
- return sys.stdin
- else:
- return sys.stdout
-
-
-Decorators
-**********
-
-Decorator functions can be expressed via generics. See
-:ref:`declaring-decorators` for the more details.
-
-.. code-block:: python
-
- from typing import Any, Callable, TypeVar
-
- F = TypeVar('F', bound=Callable[..., Any])
-
- def bare_decorator(func): # type: (F) -> F
- ...
-
- def decorator_args(url): # type: (str) -> Callable[[F], F]
- ...
diff --git a/docs/source/cheat_sheet_py3.rst b/docs/source/cheat_sheet_py3.rst
index 35c60f5..5aa1770 100644
--- a/docs/source/cheat_sheet_py3.rst
+++ b/docs/source/cheat_sheet_py3.rst
@@ -1,38 +1,27 @@
.. _cheat-sheet-py3:
-Type hints cheat sheet (Python 3)
-=================================
-
-This document is a quick cheat sheet showing how the :pep:`484` type
-annotation notation represents various common types in Python 3.
-
-.. note::
-
- Technically many of the type annotations shown below are redundant,
- because mypy can derive them from the type of the expression. So
- many of the examples have a dual purpose: show how to write the
- annotation, and show the inferred types.
+Type hints cheat sheet
+======================
+This document is a quick cheat sheet showing how to use type
+annotations for various common types in Python.
Variables
*********
-Python 3.6 introduced a syntax for annotating variables in :pep:`526`
-and we use it in most examples.
+Technically many of the type annotations shown below are redundant,
+since mypy can usually infer the type of a variable from its value.
+See :ref:`type-inference-and-annotations` for more details.
.. code-block:: python
- # This is how you declare the type of a variable type in Python 3.6
+ # This is how you declare the type of a variable
age: int = 1
- # In Python 3.5 and earlier you can use a type comment instead
- # (equivalent to the previous definition)
- age = 1 # type: int
-
# You don't need to initialize a variable to annotate it
a: int # Ok (no value at runtime until assigned)
- # The latter is useful in conditional branches
+ # Doing so is useful in conditional branches
child: bool
if age < 18:
child = True
@@ -40,47 +29,52 @@ and we use it in most examples.
child = False
-Built-in types
-**************
+Useful built-in types
+*********************
.. code-block:: python
- from typing import List, Set, Dict, Tuple, Optional
-
- # For simple built-in types, just use the name of the type
+ # For most types, just use the name of the type.
+ # Note that mypy can usually infer the type of a variable from its value,
+ # so technically these annotations are redundant
x: int = 1
x: float = 1.0
x: bool = True
x: str = "test"
x: bytes = b"test"
- # For collections, the type of the collection item is in brackets
- # (Python 3.9+)
+ # For collections on Python 3.9+, the type of the collection item is in brackets
x: list[int] = [1]
x: set[int] = {6, 7}
- # In Python 3.8 and earlier, the name of the collection type is
- # capitalized, and the type is imported from 'typing'
- x: List[int] = [1]
- x: Set[int] = {6, 7}
-
- # Same as above, but with type comment syntax (Python 3.5 and earlier)
- x = [1] # type: List[int]
-
# For mappings, we need the types of both keys and values
- x: dict[str, float] = {'field': 2.0} # Python 3.9+
- x: Dict[str, float] = {'field': 2.0}
+ x: dict[str, float] = {"field": 2.0} # Python 3.9+
# For tuples of fixed size, we specify the types of all the elements
x: tuple[int, str, float] = (3, "yes", 7.5) # Python 3.9+
- x: Tuple[int, str, float] = (3, "yes", 7.5)
# For tuples of variable size, we use one type and ellipsis
x: tuple[int, ...] = (1, 2, 3) # Python 3.9+
+
+ # On Python 3.8 and earlier, the name of the collection type is
+ # capitalized, and the type is imported from the 'typing' module
+ from typing import List, Set, Dict, Tuple
+ x: List[int] = [1]
+ x: Set[int] = {6, 7}
+ x: Dict[str, float] = {"field": 2.0}
+ x: Tuple[int, str, float] = (3, "yes", 7.5)
x: Tuple[int, ...] = (1, 2, 3)
- # Use Optional[] for values that could be None
- x: Optional[str] = some_function()
+ from typing import Union, Optional
+
+ # On Python 3.10+, use the | operator when something could be one of a few types
+ x: list[int | str] = [3, 5, "test", "fun"] # Python 3.10+
+ # On earlier versions, use Union
+ x: list[Union[int, str]] = [3, 5, "test", "fun"]
+
+ # Use Optional[X] for a value that could be None
+ # Optional[X] is the same as X | None or Union[X, None]
+ x: Optional[str] = "something" if some_condition() else None
# Mypy understands a value can't be None in an if-statement
if x is not None:
print(x.upper())
@@ -91,11 +85,9 @@ Built-in types
Functions
*********
-Python 3 supports an annotation syntax for function declarations.
-
.. code-block:: python
- from typing import Callable, Iterator, Union, Optional, List
+ from typing import Callable, Iterator, Union, Optional
# This is how you annotate a function definition
def stringify(num: int) -> str:
@@ -105,98 +97,167 @@ Python 3 supports an annotation syntax for function declarations.
def plus(num1: int, num2: int) -> int:
return num1 + num2
- # Add default value for an argument after the type annotation
- def f(num1: int, my_float: float = 3.5) -> float:
- return num1 + my_float
+ # If a function does not return a value, use None as the return type
+ # Default value for an argument goes after the type annotation
+ def show(value: str, excitement: int = 10) -> None:
+ print(value + "!" * excitement)
+
+ # Note that arguments without a type are dynamically typed (treated as Any)
+ # and that functions without any annotations not checked
+ def untyped(x):
+ x.anything() + 1 + "string" # no errors
# This is how you annotate a callable (function) value
x: Callable[[int, float], float] = f
+ def register(callback: Callable[[str], int]) -> None: ...
# A generator function that yields ints is secretly just a function that
# returns an iterator of ints, so that's how we annotate it
- def g(n: int) -> Iterator[int]:
+ def gen(n: int) -> Iterator[int]:
i = 0
while i < n:
yield i
i += 1
# You can of course split a function annotation over multiple lines
- def send_email(address: Union[str, List[str]],
+ def send_email(address: Union[str, list[str]],
sender: str,
- cc: Optional[List[str]],
- bcc: Optional[List[str]],
- subject='',
- body: Optional[List[str]] = None
+ cc: Optional[list[str]],
+ bcc: Optional[list[str]],
+ subject: str = '',
+ body: Optional[list[str]] = None
) -> bool:
...
- # An argument can be declared positional-only by giving it a name
- # starting with two underscores:
- def quux(__x: int) -> None:
+ # Mypy understands positional-only and keyword-only arguments
+ # Positional-only arguments can also be marked by using a name starting with
+ # two underscores
+ def quux(x: int, / *, y: int) -> None:
pass
- quux(3) # Fine
- quux(__x=3) # Error
+ quux(3, y=5) # Ok
+ quux(3, 5) # error: Too many positional arguments for "quux"
+ quux(x=3, y=5) # error: Unexpected keyword argument "x" for "quux"
+
+ # This says each positional arg and each keyword arg is a "str"
+ def call(self, *args: str, **kwargs: str) -> str:
+ reveal_type(args) # Revealed type is "tuple[str, ...]"
+ reveal_type(kwargs) # Revealed type is "dict[str, str]"
+ request = make_request(*args, **kwargs)
+ return self.do_api_query(request)
+
+Classes
+*******
+
+.. code-block:: python
+
+ class BankAccount:
+ # The "__init__" method doesn't return anything, so it gets return
+ # type "None" just like any other method that doesn't return anything
+ def __init__(self, account_name: str, initial_balance: int = 0) -> None:
+ # mypy will infer the correct types for these instance variables
+ # based on the types of the parameters.
+ self.account_name = account_name
+ self.balance = initial_balance
+
+ # For instance methods, omit type for "self"
+ def deposit(self, amount: int) -> None:
+ self.balance += amount
+
+ def withdraw(self, amount: int) -> None:
+ self.balance -= amount
+
+ # User-defined classes are valid as types in annotations
+ account: BankAccount = BankAccount("Alice", 400)
+ def transfer(src: BankAccount, dst: BankAccount, amount: int) -> None:
+ src.withdraw(amount)
+ dst.deposit(amount)
+
+ # Functions that accept BankAccount also accept any subclass of BankAccount!
+ class AuditedBankAccount(BankAccount):
+ # You can optionally declare instance variables in the class body
+ audit_log: list[str]
+ # This is an instance variable with a default value
+ auditor_name: str = "The Spanish Inquisition"
+
+ def __init__(self, account_name: str, initial_balance: int = 0) -> None:
+ super().__init__(account_name, initial_balance)
+ self.audit_log: list[str] = []
+
+ def deposit(self, amount: int) -> None:
+ self.audit_log.append(f"Deposited {amount}")
+ self.balance += amount
+
+ def withdraw(self, amount: int) -> None:
+ self.audit_log.append(f"Withdrew {amount}")
+ self.balance -= amount
+
+ audited = AuditedBankAccount("Bob", 300)
+ transfer(audited, account, 100) # type checks!
+
+ # You can use the ClassVar annotation to declare a class variable
+ class Car:
+ seats: ClassVar[int] = 4
+ passengers: ClassVar[list[str]]
+
+ # If you want dynamic attributes on your class, have it
+ # override "__setattr__" or "__getattr__"
+ class A:
+ # This will allow assignment to any A.x, if x is the same type as "value"
+ # (use "value: Any" to allow arbitrary types)
+ def __setattr__(self, name: str, value: int) -> None: ...
+
+ # This will allow access to any A.x, if x is compatible with the return type
+ def __getattr__(self, name: str) -> int: ...
+
+ a.foo = 42 # Works
+ a.bar = 'Ex-parrot' # Fails type checking
When you're puzzled or when things are complicated
**************************************************
.. code-block:: python
- from typing import Union, Any, List, Optional, cast
+ from typing import Union, Any, Optional, TYPE_CHECKING, cast
# To find out what type mypy infers for an expression anywhere in
# your program, wrap it in reveal_type(). Mypy will print an error
# message with the type; remove it again before running the code.
- reveal_type(1) # -> Revealed type is "builtins.int"
+ reveal_type(1) # Revealed type is "builtins.int"
- # Use Union when something could be one of a few types
- x: List[Union[int, str]] = [3, 5, "test", "fun"]
+ # If you initialize a variable with an empty container or "None"
+ # you may have to help mypy a bit by providing an explicit type annotation
+ x: list[str] = []
+ x: Optional[str] = None
# Use Any if you don't know the type of something or it's too
# dynamic to write a type for
x: Any = mystery_function()
-
- # If you initialize a variable with an empty container or "None"
- # you may have to help mypy a bit by providing a type annotation
- x: List[str] = []
- x: Optional[str] = None
-
- # This makes each positional arg and each keyword arg a "str"
- def call(self, *args: str, **kwargs: str) -> str:
- request = make_request(*args, **kwargs)
- return self.do_api_query(request)
+ # Mypy will let you do anything with x!
+ x.whatever() * x["you"] + x("want") - any(x) and all(x) is super # no errors
# Use a "type: ignore" comment to suppress errors on a given line,
# when your code confuses mypy or runs into an outright bug in mypy.
- # Good practice is to comment every "ignore" with a bug link
- # (in mypy, typeshed, or your own code) or an explanation of the issue.
- x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
+ # Good practice is to add a comment explaining the issue.
+ x = confusing_function() # type: ignore # confusing_function won't return None here because ...
# "cast" is a helper function that lets you override the inferred
# type of an expression. It's only for mypy -- there's no runtime check.
a = [4]
- b = cast(List[int], a) # Passes fine
- c = cast(List[str], a) # Passes fine (no runtime check)
- reveal_type(c) # -> Revealed type is "builtins.list[builtins.str]"
- print(c) # -> [4]; the object is not cast
-
- # If you want dynamic attributes on your class, have it override "__setattr__"
- # or "__getattr__" in a stub or in your source code.
- #
- # "__setattr__" allows for dynamic assignment to names
- # "__getattr__" allows for dynamic access to names
- class A:
- # This will allow assignment to any A.x, if x is the same type as "value"
- # (use "value: Any" to allow arbitrary types)
- def __setattr__(self, name: str, value: int) -> None: ...
-
- # This will allow access to any A.x, if x is compatible with the return type
- def __getattr__(self, name: str) -> int: ...
-
- a.foo = 42 # Works
- a.bar = 'Ex-parrot' # Fails type checking
+ b = cast(list[int], a) # Passes fine
+ c = cast(list[str], a) # Passes fine despite being a lie (no runtime check)
+ reveal_type(c) # Revealed type is "builtins.list[builtins.str]"
+ print(c) # Still prints [4] ... the object is not changed or casted at runtime
+
+ # Use "TYPE_CHECKING" if you want to have code that mypy can see but will not
+ # be executed at runtime (or to have code that mypy can't see)
+ if TYPE_CHECKING:
+ import json
+ else:
+ import orjson as json # mypy is unaware of this
+In some cases type annotations can cause issues at runtime, see
+:ref:`runtime_troubles` for dealing with this.
Standard "duck types"
*********************
@@ -209,25 +270,25 @@ that are common in idiomatic Python are standardized.
.. code-block:: python
- from typing import Mapping, MutableMapping, Sequence, Iterable, List, Set
+ from typing import Mapping, MutableMapping, Sequence, Iterable
# Use Iterable for generic iterables (anything usable in "for"),
# and Sequence where a sequence (supporting "len" and "__getitem__") is
# required
- def f(ints: Iterable[int]) -> List[str]:
+ def f(ints: Iterable[int]) -> list[str]:
return [str(x) for x in ints]
f(range(1, 3))
# Mapping describes a dict-like object (with "__getitem__") that we won't
# mutate, and MutableMapping one (with "__setitem__") that we might
- def f(my_mapping: Mapping[int, str]) -> List[int]:
- my_mapping[5] = 'maybe' # if we try this, mypy will throw an error...
+ def f(my_mapping: Mapping[int, str]) -> list[int]:
+ my_mapping[5] = 'maybe' # mypy will complain about this line...
return list(my_mapping.keys())
f({3: 'yes', 4: 'no'})
- def f(my_mapping: MutableMapping[int, str]) -> Set[str]:
+ def f(my_mapping: MutableMapping[int, str]) -> set[str]:
my_mapping[5] = 'maybe' # ...but mypy is OK with this.
return set(my_mapping.values())
@@ -236,40 +297,6 @@ that are common in idiomatic Python are standardized.
You can even make your own duck types using :ref:`protocol-types`.
-Classes
-*******
-
-.. code-block:: python
-
- class MyClass:
- # You can optionally declare instance variables in the class body
- attr: int
- # This is an instance variable with a default value
- charge_percent: int = 100
-
- # The "__init__" method doesn't return anything, so it gets return
- # type "None" just like any other method that doesn't return anything
- def __init__(self) -> None:
- ...
-
- # For instance methods, omit type for "self"
- def my_method(self, num: int, str1: str) -> str:
- return num * str1
-
- # User-defined classes are valid as types in annotations
- x: MyClass = MyClass()
-
- # You can use the ClassVar annotation to declare a class variable
- class Car:
- seats: ClassVar[int] = 4
- passengers: ClassVar[List[str]]
-
- # You can also declare the type of an attribute in "__init__"
- class Box:
- def __init__(self) -> None:
- self.items: List[str] = []
-
-
Coroutines and asyncio
**********************
@@ -282,7 +309,7 @@ See :ref:`async-and-await` for the full detail on typing coroutines and asynchro
# A coroutine is typed like a normal function
async def countdown35(tag: str, count: int) -> str:
while count > 0:
- print('T-minus {} ({})'.format(count, tag))
+ print(f'T-minus {count} ({tag})')
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
@@ -294,11 +321,7 @@ Miscellaneous
.. code-block:: python
import sys
- import re
- from typing import Match, AnyStr, IO
-
- # "typing.Match" describes regex matches from the re module
- x: Match[str] = re.match(r'[0-9]+', "15")
+ from typing import IO
# Use IO[] for functions that should accept or return any
# object that comes from an open() call (IO[] does not
@@ -313,7 +336,7 @@ Miscellaneous
# Forward references are useful if you want to reference a class before
# it is defined
- def f(foo: A) -> int: # This will fail
+ def f(foo: A) -> int: # This will fail at runtime with 'A' is not defined
...
class A:
diff --git a/docs/source/class_basics.rst b/docs/source/class_basics.rst
index 330d980..1d41641 100644
--- a/docs/source/class_basics.rst
+++ b/docs/source/class_basics.rst
@@ -1,3 +1,5 @@
+.. _class-basics:
+
Class basics
============
@@ -33,7 +35,7 @@ a type annotation:
.. code-block:: python
class A:
- x: List[int] # Declare attribute 'x' of type List[int]
+ x: list[int] # Declare attribute 'x' of type list[int]
a = A()
a.x = [1] # OK
@@ -42,19 +44,6 @@ As in Python generally, a variable defined in the class body can be used
as a class or an instance variable. (As discussed in the next section, you
can override this with a :py:data:`~typing.ClassVar` annotation.)
-Type comments work as well, if you need to support Python versions earlier
-than 3.6:
-
-.. code-block:: python
-
- class A:
- x = None # type: List[int] # Declare attribute 'x' of type List[int]
-
-Note that attribute definitions in the class body that use a type comment
-are special: a ``None`` value is valid as the initializer, even though
-the declared type is not optional. This should be used sparingly, as this can
-result in ``None``-related runtime errors that mypy can't detect.
-
Similarly, you can give explicit types to instance variables defined
in a method:
@@ -62,7 +51,7 @@ in a method:
class A:
def __init__(self) -> None:
- self.x: List[int] = []
+ self.x: list[int] = []
def f(self) -> None:
self.y: Any = 0
@@ -127,12 +116,6 @@ particular attribute should not be set on instances:
a.x = 1 # Error: Cannot assign to class variable "x" via instance
print(a.x) # OK -- can be read through an instance
-.. note::
-
- If you need to support Python 3 versions 3.5.2 or earlier, you have
- to import ``ClassVar`` from ``typing_extensions`` instead (available on
- PyPI). If you use Python 2.7, you can import it from ``typing``.
-
It's not necessary to annotate all class variables using
:py:data:`~typing.ClassVar`. An attribute without the :py:data:`~typing.ClassVar` annotation can
still be used as a class variable. However, mypy won't prevent it from
@@ -164,9 +147,25 @@ a :py:data:`~typing.ClassVar` annotation, but this might not do what you'd expec
In this case the type of the attribute will be implicitly ``Any``.
This behavior will change in the future, since it's surprising.
+An explicit :py:data:`~typing.ClassVar` may be particularly handy to distinguish
+between class and instance variables with callable types. For example:
+
+.. code-block:: python
+
+ from typing import Callable, ClassVar
+
+ class A:
+ foo: Callable[[int], None]
+ bar: ClassVar[Callable[[A, int], None]]
+ bad: Callable[[A], None]
+
+ A().foo(42) # OK
+ A().bar(42) # OK
+ A().bad() # Error: Too few arguments
+
.. note::
A :py:data:`~typing.ClassVar` type parameter cannot include type variables:
- ``ClassVar[T]`` and ``ClassVar[List[T]]``
+ ``ClassVar[T]`` and ``ClassVar[list[T]]``
are both invalid if ``T`` is a type variable (see :ref:`generic-classes`
for more about type variables).
@@ -206,7 +205,7 @@ override has a compatible signature:
You can also vary return types **covariantly** in overriding. For
example, you could override the return type ``Iterable[int]`` with a
- subtype such as ``List[int]``. Similarly, you can vary argument types
+ subtype such as ``list[int]``. Similarly, you can vary argument types
**contravariantly** -- subclasses can have more general argument types.
You can also override a statically typed method with a dynamically
@@ -261,11 +260,6 @@ function decorator. Example:
x = Animal() # Error: 'Animal' is abstract due to 'eat' and 'can_walk'
y = Cat() # OK
-.. note::
-
- In Python 2.7 you have to use :py:func:`@abc.abstractproperty ` to define
- an abstract property.
-
Note that mypy performs checking for unimplemented abstract methods
even if you omit the :py:class:`~abc.ABCMeta` metaclass. This can be useful if the
metaclass would cause runtime metaclass conflicts.
@@ -314,6 +308,26 @@ however:
in this case, but any attempt to construct an instance will be
flagged as an error.
+Mypy allows you to omit the body for an abstract method, but if you do so,
+it is unsafe to call such method via ``super()``. For example:
+
+.. code-block:: python
+
+ from abc import abstractmethod
+ class Base:
+ @abstractmethod
+ def foo(self) -> int: pass
+ @abstractmethod
+ def bar(self) -> int:
+ return 0
+ class Sub(Base):
+ def foo(self) -> int:
+ return super().foo() + 1 # error: Call to abstract method "foo" of "Base"
+ # with trivial body via super() is unsafe
+ @abstractmethod
+ def bar(self) -> int:
+ return super().bar() + 1 # This is OK however.
+
A class can inherit any number of classes, both abstract and
concrete. As with normal overrides, a dynamically typed method can
override or implement a statically typed method defined in any base
@@ -321,3 +335,35 @@ class, including an abstract method defined in an abstract base class.
You can implement an abstract property using either a normal
property or an instance variable.
+
+Slots
+*****
+
+When a class has explicitly defined
+`__slots__ `_,
+mypy will check that all attributes assigned to are members of ``__slots__``:
+
+.. code-block:: python
+
+ class Album:
+ __slots__ = ('name', 'year')
+
+ def __init__(self, name: str, year: int) -> None:
+ self.name = name
+ self.year = year
+ # Error: Trying to assign name "released" that is not in "__slots__" of type "Album"
+ self.released = True
+
+ my_album = Album('Songs about Python', 2021)
+
+Mypy will only check attribute assignments against ``__slots__`` when
+the following conditions hold:
+
+1. All base classes (except builtin ones) must have explicit
+ ``__slots__`` defined (this mirrors Python semantics).
+
+2. ``__slots__`` does not include ``__dict__``. If ``__slots__``
+ includes ``__dict__``, arbitrary attributes can be set, similar to
+ when ``__slots__`` is not defined (this mirrors Python semantics).
+
+3. All values in ``__slots__`` must be string literals.
diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst
index 2d82d2b..31d23db 100644
--- a/docs/source/command_line.rst
+++ b/docs/source/command_line.rst
@@ -58,12 +58,20 @@ for full details, see :ref:`running-mypy`.
For instance, to avoid discovering any files named `setup.py` you could
pass ``--exclude '/setup\.py$'``. Similarly, you can ignore discovering
directories with a given name by e.g. ``--exclude /build/`` or
- those matching a subpath with ``--exclude /project/vendor/``.
+ those matching a subpath with ``--exclude /project/vendor/``. To ignore
+ multiple files / directories / paths, you can provide the --exclude
+ flag more than once, e.g ``--exclude '/setup\.py$' --exclude '/build/'``.
- Note that this flag only affects recursive discovery, that is, when mypy is
- discovering files within a directory tree or submodules of a package to
- check. If you pass a file or module explicitly it will still be checked. For
- instance, ``mypy --exclude '/setup.py$' but_still_check/setup.py``.
+ Note that this flag only affects recursive directory tree discovery, that
+ is, when mypy is discovering files within a directory tree or submodules of
+ a package to check. If you pass a file or module explicitly it will still be
+ checked. For instance, ``mypy --exclude '/setup.py$'
+ but_still_check/setup.py``.
+
+ In particular, ``--exclude`` does not affect mypy's :ref:`import following
+ `. You can use a per-module :confval:`follow_imports` config
+ option to additionally avoid mypy from following imports and checking code
+ you do not wish to be checked.
Note that mypy will never recursively discover files and directories named
"site-packages", "node_modules" or "__pycache__", or those whose name starts
@@ -121,30 +129,12 @@ Import discovery
The following flags customize how exactly mypy discovers and follows
imports.
-.. option:: --namespace-packages
-
- This flag enables import discovery to use namespace packages (see
- :pep:`420`). In particular, this allows discovery of imported
- packages that don't have an ``__init__.py`` (or ``__init__.pyi``)
- file.
-
- Namespace packages are found (using the PEP 420 rules, which
- prefers "classic" packages over namespace packages) along the
- module search path -- this is primarily set from the source files
- passed on the command line, the ``MYPYPATH`` environment variable,
- and the :confval:`mypy_path` config option.
-
- This flag affects how mypy finds modules and packages explicitly passed on
- the command line. It also affects how mypy determines fully qualified module
- names for files passed on the command line. See :ref:`Mapping file paths to
- modules ` for details.
-
.. option:: --explicit-package-bases
This flag tells mypy that top-level packages will be based in either the
current directory, or a member of the ``MYPYPATH`` environment variable or
:confval:`mypy_path` config option. This option is only useful in
- conjunction with :option:`--namespace-packages`. See :ref:`Mapping file
+ in the absence of `__init__.py`. See :ref:`Mapping file
paths to modules ` for details.
.. option:: --ignore-missing-imports
@@ -204,6 +194,41 @@ imports.
By default, mypy will suppress any error messages generated within :pep:`561`
compliant packages. Adding this flag will disable this behavior.
+.. option:: --fast-module-lookup
+
+ The default logic used to scan through search paths to resolve imports has a
+ quadratic worse-case behavior in some cases, which is for instance triggered
+ by a large number of folders sharing a top-level namespace as in::
+
+ foo/
+ company/
+ foo/
+ a.py
+ bar/
+ company/
+ bar/
+ b.py
+ baz/
+ company/
+ baz/
+ c.py
+ ...
+
+ If you are in this situation, you can enable an experimental fast path by
+ setting the :option:`--fast-module-lookup` option.
+
+
+.. option:: --no-namespace-packages
+
+ This flag disables import discovery of namespace packages (see :pep:`420`).
+ In particular, this prevents discovery of packages that don't have an
+ ``__init__.py`` (or ``__init__.pyi``) file.
+
+ This flag affects how mypy finds modules and packages explicitly passed on
+ the command line. It also affects how mypy determines fully qualified module
+ names for files passed on the command line. See :ref:`Mapping file paths to
+ modules ` for details.
+
.. _platform-configuration:
@@ -220,23 +245,13 @@ For more information on how to use these flags, see :ref:`version_and_platform_c
This flag will make mypy type check your code as if it were
run under Python version X.Y. Without this option, mypy will default to using
- whatever version of Python is running mypy. Note that the :option:`-2` and
- :option:`--py2` flags are aliases for :option:`--python-version 2.7 <--python-version>`.
+ whatever version of Python is running mypy.
This flag will attempt to find a Python executable of the corresponding
version to search for :pep:`561` compliant packages. If you'd like to
disable this, use the :option:`--no-site-packages` flag (see
:ref:`import-discovery` for more details).
-.. option:: -2, --py2
-
- Equivalent to running :option:`--python-version 2.7 <--python-version>`.
-
- .. note::
-
- To check Python 2 code with mypy, you'll need to install mypy with
- ``pip install 'mypy[python2]'``.
-
.. option:: --platform PLATFORM
This flag will make mypy type check your code as if it were
@@ -266,7 +281,7 @@ For more information on how to use these flags, see :ref:`version_and_platform_c
Disallow dynamic typing
***********************
-The ``Any`` type is used represent a value that has a :ref:`dynamic type `.
+The ``Any`` type is used to represent a value that has a :ref:`dynamic type `.
The ``--disallow-any`` family of flags will disallow various uses of the ``Any`` type in
a module -- this lets us strategically disallow the use of dynamic typing in a controlled way.
@@ -304,9 +319,8 @@ The following options are available:
.. option:: --disallow-any-generics
This flag disallows usage of generic types that do not specify explicit
- type parameters. Moreover, built-in collections (such as :py:class:`list` and
- :py:class:`dict`) become disallowed as you should use their aliases from the :py:mod:`typing`
- module (such as :py:class:`List[int] ` and :py:class:`Dict[str, str] `).
+ type parameters. For example, you can't use a bare ``x: list``. Instead, you
+ must always write something like ``x: list[int]``.
.. option:: --disallow-subclassing-any
@@ -370,29 +384,23 @@ None and Optional handling
The following flags adjust how mypy handles values of type ``None``.
For more details, see :ref:`no_strict_optional`.
-.. _no-implicit-optional:
+.. _implicit-optional:
-.. option:: --no-implicit-optional
+.. option:: --implicit-optional
- This flag causes mypy to stop treating arguments with a ``None``
+ This flag causes mypy to treat arguments with a ``None``
default value as having an implicit :py:data:`~typing.Optional` type.
- For example, by default mypy will assume that the ``x`` parameter
- is of type ``Optional[int]`` in the code snippet below since
- the default parameter is ``None``:
+ For example, if this flag is set, mypy would assume that the ``x``
+ parameter is actually of type ``Optional[int]`` in the code snippet below
+ since the default parameter is ``None``:
.. code-block:: python
def foo(x: int = None) -> None:
print(x)
- If this flag is set, the above snippet will no longer type check:
- we must now explicitly indicate that the type is ``Optional[int]``:
-
- .. code-block:: python
-
- def foo(x: Optional[int] = None) -> None:
- print(x)
+ **Note:** This was disabled by default starting in mypy 0.980.
.. option:: --no-strict-optional
@@ -411,7 +419,7 @@ For more details, see :ref:`no_strict_optional`.
Configuring warnings
********************
-The follow flags enable warnings for code that is sound but is
+The following flags enable warnings for code that is sound but is
potentially problematic or redundant in some way.
.. option:: --warn-redundant-casts
@@ -440,9 +448,10 @@ potentially problematic or redundant in some way.
are when:
- The function has a ``None`` or ``Any`` return type
- - The function has an empty body or a body that is just
- ellipsis (``...``). Empty functions are often used for
- abstract methods.
+ - The function has an empty body and is marked as an abstract method,
+ is in a protocol class, or is in a stub file
+ - The execution path can never return; for example, if an exception
+ is always raised
Passing in :option:`--no-warn-no-return` will disable these error
messages in all cases.
@@ -513,11 +522,20 @@ of the above sections.
.. code-block:: python
- def process(items: List[str]) -> None:
- # 'items' has type List[str]
+ def process(items: list[str]) -> None:
+ # 'items' has type list[str]
items = [item.split() for item in items]
- # 'items' now has type List[List[str]]
- ...
+ # 'items' now has type list[list[str]]
+
+ The variable must be used before it can be redefined:
+
+ .. code-block:: python
+
+ def process(items: list[str]) -> None:
+ items = "mypy" # invalid redefinition to str because the variable hasn't been used yet
+ print(items)
+ items = "100" # valid, items now has type str
+ items = int(items) # valid, items now has type int
.. option:: --local-partial-types
@@ -532,11 +550,11 @@ of the above sections.
from typing import Optional
a = None # Need type annotation here if using --local-partial-types
- b = None # type: Optional[int]
+ b: Optional[int] = None
class Foo:
bar = None # Need type annotation here if using --local-partial-types
- baz = None # type: Optional[int]
+ baz: Optional[int] = None
def __init__(self) -> None:
self.bar = 1
@@ -557,8 +575,13 @@ of the above sections.
# This won't re-export the value
from foo import bar
+
+ # Neither will this
+ from foo import bar as bang
+
# This will re-export it as bar and allow other modules to import it
from foo import bar as bar
+
# This will also re-export bar
from foo import bar
__all__ = ['bar']
@@ -572,9 +595,9 @@ of the above sections.
.. code-block:: python
- from typing import List, Text
+ from typing import Text
- items: List[int]
+ items: list[int]
if 'some string' in items: # Error: non-overlapping container check!
...
@@ -595,6 +618,7 @@ of the above sections.
.. option:: --disable-error-code
This flag allows disabling one or multiple error codes globally.
+ See :ref:`error-codes` for more information.
.. code-block:: python
@@ -602,20 +626,21 @@ of the above sections.
x = 'a string'
x.trim() # error: "str" has no attribute "trim" [attr-defined]
- # --disable-error-code attr-defined
+ # When using --disable-error-code attr-defined
x = 'a string'
x.trim()
.. option:: --enable-error-code
This flag allows enabling one or multiple error codes globally.
+ See :ref:`error-codes` for more information.
- Note: This flag will override disabled error codes from the --disable-error-code
- flag
+ Note: This flag will override disabled error codes from the
+ :option:`--disable-error-code ` flag.
.. code-block:: python
- # --disable-error-code attr-defined
+ # When using --disable-error-code attr-defined
x = 'a string'
x.trim()
@@ -659,9 +684,17 @@ in error messages.
main.py:12:9: error: Unsupported operand types for / ("int" and "str")
-.. option:: --show-error-codes
+.. option:: --show-error-end
+
+ This flag will make mypy show not just that start position where
+ an error was detected, but also the end position of the relevant expression.
+ This way various tools can easily highlight the whole error span. The format is
+ ``file:line:column:end_line:end_column``. This option implies
+ ``--show-column-numbers``.
+
+.. option:: --hide-error-codes
- This flag will add an error code ``[]`` to error messages. The error
+ This flag will hide the error code ``[]`` from error messages. By default, the error
code is shown after each error message::
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
@@ -786,7 +819,8 @@ in developing or debugging mypy internals.
submitting them upstream, but also allows you to use a forked version of
typeshed.
- Note that this doesn't affect third-party library stubs.
+ Note that this doesn't affect third-party library stubs. To test third-party stubs,
+ for example try ``MYPYPATH=stubs/six mypy ...``.
.. _warn-incomplete-stub:
@@ -841,13 +875,17 @@ format into the specified directory.
Causes mypy to generate a Cobertura XML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. option:: --html-report / --xslt-html-report DIR
Causes mypy to generate an HTML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. option:: --linecount-report DIR
@@ -869,13 +907,17 @@ format into the specified directory.
Causes mypy to generate a text file type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. option:: --xml-report DIR
Causes mypy to generate an XML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
Miscellaneous
*************
diff --git a/docs/source/common_issues.rst b/docs/source/common_issues.rst
index 0a513ef..afb8e7d 100644
--- a/docs/source/common_issues.rst
+++ b/docs/source/common_issues.rst
@@ -9,15 +9,6 @@ doesn't work as expected. Statically typed code is often identical to
normal Python code (except for type annotations), but sometimes you need
to do things slightly differently.
-Can't install mypy using pip
-----------------------------
-
-If installation fails, you've probably hit one of these issues:
-
-* Mypy needs Python 3.5 or later to run.
-* You may have to run pip like this:
- ``python3 -m pip install mypy``.
-
.. _annotations_needed:
No errors reported for obviously wrong code
@@ -26,102 +17,109 @@ No errors reported for obviously wrong code
There are several common reasons why obviously wrong code is not
flagged as an error.
-- **The function containing the error is not annotated.** Functions that
- do not have any annotations (neither for any argument nor for the
- return type) are not type-checked, and even the most blatant type
- errors (e.g. ``2 + 'a'``) pass silently. The solution is to add
- annotations. Where that isn't possible, functions without annotations
- can be checked using :option:`--check-untyped-defs `.
+**The function containing the error is not annotated.**
- Example:
+Functions that
+do not have any annotations (neither for any argument nor for the
+return type) are not type-checked, and even the most blatant type
+errors (e.g. ``2 + 'a'``) pass silently. The solution is to add
+annotations. Where that isn't possible, functions without annotations
+can be checked using :option:`--check-untyped-defs `.
- .. code-block:: python
+Example:
+
+.. code-block:: python
- def foo(a):
- return '(' + a.split() + ')' # No error!
+ def foo(a):
+ return '(' + a.split() + ')' # No error!
- This gives no error even though ``a.split()`` is "obviously" a list
- (the author probably meant ``a.strip()``). The error is reported
- once you add annotations:
+This gives no error even though ``a.split()`` is "obviously" a list
+(the author probably meant ``a.strip()``). The error is reported
+once you add annotations:
- .. code-block:: python
+.. code-block:: python
- def foo(a: str) -> str:
- return '(' + a.split() + ')'
- # error: Unsupported operand types for + ("str" and List[str])
+ def foo(a: str) -> str:
+ return '(' + a.split() + ')'
+ # error: Unsupported operand types for + ("str" and List[str])
- If you don't know what types to add, you can use ``Any``, but beware:
+If you don't know what types to add, you can use ``Any``, but beware:
-- **One of the values involved has type 'Any'.** Extending the above
- example, if we were to leave out the annotation for ``a``, we'd get
- no error:
+**One of the values involved has type 'Any'.**
- .. code-block:: python
+Extending the above
+example, if we were to leave out the annotation for ``a``, we'd get
+no error:
- def foo(a) -> str:
- return '(' + a.split() + ')' # No error!
+.. code-block:: python
- The reason is that if the type of ``a`` is unknown, the type of
- ``a.split()`` is also unknown, so it is inferred as having type
- ``Any``, and it is no error to add a string to an ``Any``.
+ def foo(a) -> str:
+ return '(' + a.split() + ')' # No error!
- If you're having trouble debugging such situations,
- :ref:`reveal_type() ` might come in handy.
+The reason is that if the type of ``a`` is unknown, the type of
+``a.split()`` is also unknown, so it is inferred as having type
+``Any``, and it is no error to add a string to an ``Any``.
- Note that sometimes library stubs have imprecise type information,
- e.g. the :py:func:`pow` builtin returns ``Any`` (see `typeshed issue 285
- `_ for the reason).
+If you're having trouble debugging such situations,
+:ref:`reveal_type() ` might come in handy.
-- :py:meth:`__init__ ` **method has no annotated
- arguments or return type annotation.** :py:meth:`__init__ `
- is considered fully-annotated **if at least one argument is annotated**,
- while mypy will infer the return type as ``None``.
- The implication is that, for a :py:meth:`__init__ ` method
- that has no argument, you'll have to explicitly annotate the return type
- as ``None`` to type-check this :py:meth:`__init__ ` method:
+Note that sometimes library stubs with imprecise type information
+can be a source of ``Any`` values.
- .. code-block:: python
+:py:meth:`__init__ ` **method has no annotated
+arguments and no return type annotation.**
- def foo(s: str) -> str:
- return s
-
- class A():
- def __init__(self, value: str): # Return type inferred as None, considered as typed method
- self.value = value
- foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
-
- class B():
- def __init__(self): # No argument is annotated, considered as untyped method
- foo(1) # No error!
-
- class C():
- def __init__(self) -> None: # Must specify return type to type-check
- foo(1) # error: Argument 1 to "foo" has incompatible type "int"; expected "str"
-
-- **Some imports may be silently ignored**. Another source of
- unexpected ``Any`` values are the :option:`--ignore-missing-imports
- ` and :option:`--follow-imports=skip
- ` flags. When you use :option:`--ignore-missing-imports `,
- any imported module that cannot be found is silently replaced with
- ``Any``. When using :option:`--follow-imports=skip ` the same is true for
- modules for which a ``.py`` file is found but that are not specified
- on the command line. (If a ``.pyi`` stub is found it is always
- processed normally, regardless of the value of
- :option:`--follow-imports `.) To help debug the former situation (no
- module found at all) leave out :option:`--ignore-missing-imports `; to get
- clarity about the latter use :option:`--follow-imports=error `. You can
- read up about these and other useful flags in :ref:`command-line`.
-
-- **A function annotated as returning a non-optional type returns 'None'
- and mypy doesn't complain**.
+This is basically a combination of the two cases above, in that ``__init__``
+without annotations can cause ``Any`` types leak into instance variables:
- .. code-block:: python
+.. code-block:: python
+
+ class Bad:
+ def __init__(self):
+ self.value = "asdf"
+ 1 + "asdf" # No error!
+
+ bad = Bad()
+ bad.value + 1 # No error!
+ reveal_type(bad) # Revealed type is "__main__.Bad"
+ reveal_type(bad.value) # Revealed type is "Any"
- def foo() -> str:
- return None # No error!
+ class Good:
+ def __init__(self) -> None: # Explicitly return None
+ self.value = value
- You may have disabled strict optional checking (see
- :ref:`no_strict_optional` for more).
+
+**Some imports may be silently ignored**.
+
+A common source of unexpected ``Any`` values is the
+:option:`--ignore-missing-imports ` flag.
+
+When you use :option:`--ignore-missing-imports `,
+any imported module that cannot be found is silently replaced with ``Any``.
+
+To help debug this, simply leave out
+:option:`--ignore-missing-imports `.
+As mentioned in :ref:`fix-missing-imports`, setting ``ignore_missing_imports=True``
+on a per-module basis will make bad surprises less likely and is highly encouraged.
+
+Use of the :option:`--follow-imports=skip ` flags can also
+cause problems. Use of these flags is strongly discouraged and only required in
+relatively niche situations. See :ref:`follow-imports` for more information.
+
+**mypy considers some of your code unreachable**.
+
+See :ref:`unreachable` for more information.
+
+**A function annotated as returning a non-optional type returns 'None'
+and mypy doesn't complain**.
+
+.. code-block:: python
+
+ def foo() -> str:
+ return None # No error!
+
+You may have disabled strict optional checking (see
+:ref:`no_strict_optional` for more).
.. _silencing_checker:
@@ -186,29 +184,16 @@ over ``.py`` files.
Ignoring a whole file
---------------------
-A ``# type: ignore`` comment at the top of a module (before any statements,
-including imports or docstrings) has the effect of ignoring the *entire* module.
-
-.. code-block:: python
-
- # type: ignore
+* To only ignore errors, use a top-level ``# mypy: ignore-errors`` comment instead.
+* To only ignore errors with a specific error code, use a top-level
+ ``# mypy: disable-error-code=...`` comment.
+* To replace the contents of a module with ``Any``, use a per-module ``follow_imports = skip``.
+ See :ref:`Following imports ` for details.
- import foo
-
- foo.bar()
-
-Unexpected errors about 'None' and/or 'Optional' types
-------------------------------------------------------
-
-Starting from mypy 0.600, mypy uses
-:ref:`strict optional checking ` by default,
-and the ``None`` value is not compatible with non-optional types.
-It's easy to switch back to the older behavior where ``None`` was
-compatible with arbitrary types (see :ref:`no_strict_optional`).
-You can also fall back to this behavior if strict optional
-checking would require a large number of ``assert foo is not None``
-checks to be inserted, and you want to minimize the number
-of code changes required to get a clean mypy run.
+Note that a ``# type: ignore`` comment at the top of a module (before any statements,
+including imports or docstrings) has the effect of ignoring the entire contents of the module.
+This behaviour can be surprising and result in
+"Module ... has no attribute ... [attr-defined]" errors.
Issues with code at runtime
---------------------------
@@ -267,20 +252,20 @@ Redefinitions with incompatible types
Each name within a function only has a single 'declared' type. You can
reuse for loop indices etc., but if you want to use a variable with
-multiple types within a single function, you may need to declare it
-with the ``Any`` type.
+multiple types within a single function, you may need to instead use
+multiple variables (or maybe declare the variable with an ``Any`` type).
.. code-block:: python
def f() -> None:
n = 1
...
- n = 'x' # Type error: n has type int
+ n = 'x' # error: Incompatible types in assignment (expression has type "str", variable has type "int")
.. note::
- This limitation could be lifted in a future mypy
- release.
+ Using the :option:`--allow-redefinition `
+ flag can suppress this error in several cases.
Note that you can redefine a variable with a more *precise* or a more
concrete type. For example, you can redefine a sequence (which does
@@ -294,6 +279,8 @@ not support ``sort()``) as a list and sort it in-place:
# Type of x is List[int] here.
x.sort() # Okay!
+See :ref:`type-narrowing` for more information.
+
.. _variance:
Invariance vs covariance
@@ -345,41 +332,60 @@ Declaring a supertype as variable type
Sometimes the inferred type is a subtype (subclass) of the desired
type. The type inference uses the first assignment to infer the type
-of a name (assume here that ``Shape`` is the base class of both
-``Circle`` and ``Triangle``):
+of a name:
.. code-block:: python
- shape = Circle() # Infer shape to be Circle
- ...
- shape = Triangle() # Type error: Triangle is not a Circle
+ class Shape: ...
+ class Circle(Shape): ...
+ class Triangle(Shape): ...
+
+ shape = Circle() # mypy infers the type of shape to be Circle
+ shape = Triangle() # error: Incompatible types in assignment (expression has type "Triangle", variable has type "Circle")
You can just give an explicit type for the variable in cases such the
above example:
.. code-block:: python
- shape = Circle() # type: Shape # The variable s can be any Shape,
- # not just Circle
- ...
- shape = Triangle() # OK
+ shape: Shape = Circle() # The variable s can be any Shape, not just Circle
+ shape = Triangle() # OK
Complex type tests
------------------
-Mypy can usually infer the types correctly when using :py:func:`isinstance `
-type tests, but for other kinds of checks you may need to add an
+Mypy can usually infer the types correctly when using :py:func:`isinstance `,
+:py:func:`issubclass `,
+or ``type(obj) is some_class`` type tests,
+and even :ref:`user-defined type guards `,
+but for other kinds of checks you may need to add an
explicit type cast:
.. code-block:: python
- def f(o: object) -> None:
- if type(o) is int:
- o = cast(int, o)
- g(o + 1) # This would be an error without the cast
- ...
- else:
- ...
+ from typing import Sequence, cast
+
+ def find_first_str(a: Sequence[object]) -> str:
+ index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
+ if index < 0:
+ raise ValueError('No str found')
+
+ found = a[index] # Has type "object", despite the fact that we know it is "str"
+ return cast(str, found) # We need an explicit cast to make mypy happy
+
+Alternatively, you can use an ``assert`` statement together with some
+of the supported type inference techniques:
+
+.. code-block:: python
+
+ def find_first_str(a: Sequence[object]) -> str:
+ index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
+ if index < 0:
+ raise ValueError('No str found')
+
+ found = a[index] # Has type "object", despite the fact that we know it is "str"
+ assert isinstance(found, str) # Now, "found" will be narrowed to "str"
+ return found # No need for the explicit "cast()" anymore
.. note::
@@ -390,19 +396,11 @@ explicit type cast:
runtime. The cast above would have been unnecessary if the type of
``o`` was ``Any``.
-Mypy can't infer the type of ``o`` after the :py:class:`type() ` check
-because it only knows about :py:func:`isinstance` (and the latter is better
-style anyway). We can write the above code without a cast by using
-:py:func:`isinstance`:
-
-.. code-block:: python
+.. note::
- def f(o: object) -> None:
- if isinstance(o, int): # Mypy understands isinstance checks
- g(o + 1) # Okay; type of o is inferred as int here
- ...
+ You can read more about type narrowing techniques :ref:`here `.
-Type inference in mypy is designed to work well in common cases, to be
+Type inference in Mypy is designed to work well in common cases, to be
predictable and to let the type checker give useful error
messages. More powerful type inference strategies often have complex
and difficult-to-predict failure modes and could result in very
@@ -428,12 +426,10 @@ More specifically, mypy will understand the use of :py:data:`sys.version_info` a
import sys
# Distinguishing between different versions of Python:
- if sys.version_info >= (3, 5):
- # Python 3.5+ specific definitions and imports
- elif sys.version_info[0] >= 3:
- # Python 3 specific definitions and imports
+ if sys.version_info >= (3, 8):
+ # Python 3.8+ specific definitions and imports
else:
- # Python 2 specific definitions and imports
+ # Other definitions and imports
# Distinguishing between different operating systems:
if sys.platform.startswith("linux"):
@@ -473,9 +469,9 @@ operating system as default values for :py:data:`sys.version_info` and
:py:data:`sys.platform`.
To target a different Python version, use the :option:`--python-version X.Y ` flag.
-For example, to verify your code typechecks if were run using Python 2, pass
-in :option:`--python-version 2.7 ` from the command line. Note that you do not need
-to have Python 2.7 installed to perform this check.
+For example, to verify your code typechecks if were run using Python 3.8, pass
+in :option:`--python-version 3.8 ` from the command line. Note that you do not need
+to have Python 3.8 installed to perform this check.
To target a different operating system, use the :option:`--platform PLATFORM ` flag.
For example, to verify your code typechecks if it were run in Windows, pass
@@ -596,7 +592,7 @@ method signature. E.g.:
The third line elicits an error because mypy sees the argument type
``bytes`` as a reference to the method by that name. Other than
-renaming the method, a work-around is to use an alias:
+renaming the method, a workaround is to use an alias:
.. code-block:: python
@@ -618,51 +614,73 @@ You can install the latest development version of mypy from source. Clone the
git clone https://github.com/python/mypy.git
cd mypy
- sudo python3 -m pip install --upgrade .
+ python3 -m pip install --upgrade .
+
+To install a development version of mypy that is mypyc-compiled, see the
+instructions at the `mypyc wheels repo `_.
Variables vs type aliases
------------------------------------
+-------------------------
-Mypy has both type aliases and variables with types like ``Type[...]`` and it is important to know their difference.
+Mypy has both *type aliases* and variables with types like ``Type[...]``. These are
+subtly different, and it's important to understand how they differ to avoid pitfalls.
-1. Variables with type ``Type[...]`` should be created by assignments with an explicit type annotations:
+1. A variable with type ``Type[...]`` is defined using an assignment with an
+ explicit type annotation:
-.. code-block:: python
+ .. code-block:: python
- class A: ...
- tp: Type[A] = A
+ class A: ...
+ tp: Type[A] = A
-2. Aliases are created by assignments without an explicit type:
+2. You can define a type alias using an assignment without an explicit type annotation
+ at the top level of a module:
-.. code-block:: python
+ .. code-block:: python
- class A: ...
- Alias = A
+ class A: ...
+ Alias = A
-3. The difference is that aliases are completely known statically and can be used in type context (annotations):
+ You can also use ``TypeAlias`` (:pep:`613`) to define an *explicit type alias*:
-.. code-block:: python
+ .. code-block:: python
+
+ from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier
- class A: ...
- class B: ...
+ class A: ...
+ Alias: TypeAlias = A
- if random() > 0.5:
- Alias = A
- else:
- Alias = B # error: Cannot assign multiple types to name "Alias" without an explicit "Type[...]" annotation \
- # error: Incompatible types in assignment (expression has type "Type[B]", variable has type "Type[A]")
+ You should always use ``TypeAlias`` to define a type alias in a class body or
+ inside a function.
- tp: Type[object] # tp is a type variable
- if random() > 0.5:
- tp = A
- else:
- tp = B # This is OK
+The main difference is that the target of an alias is precisely known statically, and this
+means that they can be used in type annotations and other *type contexts*. Type aliases
+can't be defined conditionally (unless using
+:ref:`supported Python version and platform checks `):
- def fun1(x: Alias) -> None: ... # This is OK
- def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type
+ .. code-block:: python
+
+ class A: ...
+ class B: ...
+
+ if random() > 0.5:
+ Alias = A
+ else:
+ # error: Cannot assign multiple types to name "Alias" without an
+ # explicit "Type[...]" annotation
+ Alias = B
+
+ tp: Type[object] # "tp" is a variable with a type object value
+ if random() > 0.5:
+ tp = A
+ else:
+ tp = B # This is OK
+
+ def fun1(x: Alias) -> None: ... # OK
+ def fun2(x: tp) -> None: ... # Error: "tp" is not valid as a type
Incompatible overrides
-------------------------------
+----------------------
It's unsafe to override a method with a more specific argument type,
as it violates the `Liskov substitution principle
@@ -718,6 +736,8 @@ not necessary:
def test(self, t: List[int]) -> Sequence[str]: # type: ignore[override]
...
+.. _unreachable:
+
Unreachable code
----------------
@@ -773,7 +793,6 @@ False:
If you use the :option:`--warn-unreachable ` flag, mypy will generate
an error about each unreachable code block.
-
Narrowing and inner functions
-----------------------------
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 9f1ab88..5faefdc 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -12,8 +12,10 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys
+from __future__ import annotations
+
import os
+import sys
from sphinx.application import Sphinx
from sphinx.util.docfields import Field
@@ -21,54 +23,54 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath("../.."))
from mypy.version import __version__ as mypy_version
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['sphinx.ext.intersphinx']
+extensions = ["sphinx.ext.intersphinx"]
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
# The suffix of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
-master_doc = 'index'
+master_doc = "index"
# General information about the project.
-project = u'Mypy'
-copyright = u'2016, Jukka Lehtosalo'
+project = "mypy"
+copyright = "2012-2022 Jukka Lehtosalo and mypy contributors"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = mypy_version.split('-')[0]
+version = mypy_version.split("-")[0]
# The full version, including alpha/beta/rc tags.
release = mypy_version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@@ -76,173 +78,159 @@
# The reST default role (used for this markup: `text`) to use for all
# documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
-#keep_warnings = False
+# keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-try:
- import sphinx_rtd_theme
-except:
- html_theme = 'default'
-else:
- html_theme = 'sphinx_rtd_theme'
- html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+html_theme = "furo"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+html_logo = "mypy_light.svg"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
+# html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
-#html_extra_path = []
+# html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
-htmlhelp_basename = 'Mypydoc'
+htmlhelp_basename = "mypydoc"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+ # The paper size ('letterpaper' or 'a4paper').
+ #'papersize': 'letterpaper',
+ # The font size ('10pt', '11pt' or '12pt').
+ #'pointsize': '10pt',
+ # Additional stuff for the LaTeX preamble.
+ #'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
-latex_documents = [
- ('index', 'Mypy.tex', u'Mypy Documentation',
- u'Jukka', 'manual'),
-]
+latex_documents = [("index", "Mypy.tex", "Mypy Documentation", "Jukka", "manual")]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'mypy', u'Mypy Documentation',
- [u'Jukka Lehtosalo'], 1)
-]
+man_pages = [("index", "mypy", "Mypy Documentation", ["Jukka Lehtosalo"], 1)]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
@@ -251,43 +239,49 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'Mypy', u'Mypy Documentation',
- u'Jukka', 'Mypy', 'One line description of project.',
- 'Miscellaneous'),
+ (
+ "index",
+ "Mypy",
+ "Mypy Documentation",
+ "Jukka",
+ "Mypy",
+ "One line description of project.",
+ "Miscellaneous",
+ )
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
-#texinfo_no_detailmenu = False
+# texinfo_no_detailmenu = False
-rst_prolog = '.. |...| unicode:: U+2026 .. ellipsis\n'
+rst_prolog = ".. |...| unicode:: U+2026 .. ellipsis\n"
intersphinx_mapping = {
- 'python': ('https://docs.python.org/3', None),
- 'six': ('https://six.readthedocs.io', None),
- 'attrs': ('http://www.attrs.org/en/stable', None),
- 'cython': ('http://docs.cython.org/en/latest', None),
- 'monkeytype': ('https://monkeytype.readthedocs.io/en/latest', None),
- 'setuptools': ('https://setuptools.readthedocs.io/en/latest', None),
+ "python": ("https://docs.python.org/3", None),
+ "six": ("https://six.readthedocs.io", None),
+ "attrs": ("http://www.attrs.org/en/stable", None),
+ "cython": ("http://docs.cython.org/en/latest", None),
+ "monkeytype": ("https://monkeytype.readthedocs.io/en/latest", None),
+ "setuptools": ("https://setuptools.readthedocs.io/en/latest", None),
}
def setup(app: Sphinx) -> None:
app.add_object_type(
- 'confval',
- 'confval',
- objname='configuration value',
- indextemplate='pair: %s; configuration value',
+ "confval",
+ "confval",
+ objname="configuration value",
+ indextemplate="pair: %s; configuration value",
doc_field_types=[
- Field('type', label='Type', has_arg=False, names=('type',)),
- Field('default', label='Default', has_arg=False, names=('default',)),
- ]
+ Field("type", label="Type", has_arg=False, names=("type",)),
+ Field("default", label="Default", has_arg=False, names=("default",)),
+ ],
)
diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst
index cc3a0bc..3b96e6b 100644
--- a/docs/source/config_file.rst
+++ b/docs/source/config_file.rst
@@ -114,7 +114,6 @@ of your repo and run mypy.
# Global options:
[mypy]
- python_version = 2.7
warn_return_any = True
warn_unused_configs = True
@@ -129,16 +128,13 @@ of your repo and run mypy.
[mypy-somelibrary]
ignore_missing_imports = True
-This config file specifies three global options in the ``[mypy]`` section. These three
+This config file specifies two global options in the ``[mypy]`` section. These two
options will:
-1. Type-check your entire project assuming it will be run using Python 2.7.
- (This is equivalent to using the :option:`--python-version 2.7 ` or :option:`-2 ` flag).
-
-2. Report an error whenever a function returns a value that is inferred
+1. Report an error whenever a function returns a value that is inferred
to have type ``Any``.
-3. Report any config options that are unused by mypy. (This will help us catch typos
+2. Report any config options that are unused by mypy. (This will help us catch typos
when making changes to our config file).
Next, this module specifies three per-module options. The first two options change how mypy
@@ -195,25 +191,96 @@ section of the command line docs.
This option may only be set in the global section (``[mypy]``).
+.. confval:: modules
+
+ :type: comma-separated list of strings
+
+ A comma-separated list of packages which should be checked by mypy if none are given on the command
+ line. Mypy *will not* recursively type check any submodules of the provided
+ module.
+
+ This option may only be set in the global section (``[mypy]``).
+
+
+.. confval:: packages
+
+ :type: comma-separated list of strings
+
+ A comma-separated list of packages which should be checked by mypy if none are given on the command
+ line. Mypy *will* recursively type check any submodules of the provided
+ package. This flag is identical to :confval:`modules` apart from this
+ behavior.
+
+ This option may only be set in the global section (``[mypy]``).
+
.. confval:: exclude
:type: regular expression
A regular expression that matches file names, directory names and paths
which mypy should ignore while recursively discovering files to check.
- Use forward slashes on all platforms.
+ Use forward slashes (``/``) as directory separators on all platforms.
+
+ .. code-block:: ini
+
+ [mypy]
+ exclude = (?x)(
+ ^one\.py$ # files named "one.py"
+ | two\.pyi$ # or files ending with "two.pyi"
+ | ^three\. # or files starting with "three."
+ )
+
+ Crafting a single regular expression that excludes multiple files while remaining
+ human-readable can be a challenge. The above example demonstrates one approach.
+ ``(?x)`` enables the ``VERBOSE`` flag for the subsequent regular expression, which
+ `ignores most whitespace and supports comments`__. The above is equivalent to:
+ ``(^one\.py$|two\.pyi$|^three\.)``.
+
+ .. __: https://docs.python.org/3/library/re.html#re.X
For more details, see :option:`--exclude `.
This option may only be set in the global section (``[mypy]``).
+ .. note::
+
+ Note that the TOML equivalent differs slightly. It can be either a single string
+ (including a multi-line string) -- which is treated as a single regular
+ expression -- or an array of such strings. The following TOML examples are
+ equivalent to the above INI example.
+
+ Array of strings:
+
+ .. code-block:: toml
+
+ [tool.mypy]
+ exclude = [
+ "^one\\.py$", # TOML's double-quoted strings require escaping backslashes
+ 'two\.pyi$', # but TOML's single-quoted strings do not
+ '^three\.',
+ ]
+
+ A single, multi-line string:
+
+ .. code-block:: toml
+
+ [tool.mypy]
+ exclude = '''(?x)(
+ ^one\.py$ # files named "one.py"
+ | two\.pyi$ # or files ending with "two.pyi"
+ | ^three\. # or files starting with "three."
+ )''' # TOML's single-quoted strings do not require escaping backslashes
+
+ See :ref:`using-a-pyproject-toml`.
+
.. confval:: namespace_packages
:type: boolean
- :default: False
+ :default: True
Enables :pep:`420` style namespace packages. See the
- corresponding flag :option:`--namespace-packages ` for more information.
+ corresponding flag :option:`--no-namespace-packages `
+ for more information.
This option may only be set in the global section (``[mypy]``).
@@ -225,7 +292,7 @@ section of the command line docs.
This flag tells mypy that top-level packages will be based in either the
current directory, or a member of the ``MYPYPATH`` environment variable or
:confval:`mypy_path` config option. This option is only useful in
- conjunction with :confval:`namespace_packages`. See :ref:`Mapping file
+ the absence of `__init__.py`. See :ref:`Mapping file
paths to modules ` for details.
This option may only be set in the global section (``[mypy]``).
@@ -254,6 +321,10 @@ section of the command line docs.
``error``. For explanations see the discussion for the
:option:`--follow-imports ` command line flag.
+ Using this option in a per-module section (potentially with a wildcard,
+ as described at the top of this page) is a good way to prevent mypy from
+ checking portions of your code.
+
If this option is used in a per-module section, the module name should
match the name of the *imported* module, not the module containing the
import statement.
@@ -319,7 +390,7 @@ Platform configuration
:type: string
Specifies the Python version used to parse and check the target
- program. The string should be in the format ``DIGIT.DIGIT`` --
+ program. The string should be in the format ``MAJOR.MINOR`` --
for example ``2.7``. The default is the version of the Python
interpreter used to run mypy.
@@ -455,13 +526,15 @@ None and Optional handling
For more information, see the :ref:`None and Optional handling `
section of the command line docs.
-.. confval:: no_implicit_optional
+.. confval:: implicit_optional
:type: boolean
:default: False
- Changes the treatment of arguments with a default value of ``None`` by not implicitly
- making their type :py:data:`~typing.Optional`.
+ Causes mypy to treat arguments with a ``None``
+ default value as having an implicit :py:data:`~typing.Optional` type.
+
+ **Note:** This was True by default in mypy versions 0.980 and earlier.
.. confval:: strict_optional
@@ -526,14 +599,6 @@ Suppressing errors
Note: these configuration options are available in the config file only. There is
no analog available via the command line options.
-.. confval:: show_none_errors
-
- :type: boolean
- :default: True
-
- Shows errors related to strict ``None`` checking, if the global :confval:`strict_optional`
- flag is enabled.
-
.. confval:: ignore_errors
:type: boolean
@@ -563,6 +628,24 @@ section of the command line docs.
Allows variables to be redefined with an arbitrary type, as long as the redefinition
is in the same block and nesting level as the original definition.
+ Example where this can be useful:
+
+ .. code-block:: python
+
+ def process(items: list[str]) -> None:
+ # 'items' has type list[str]
+ items = [item.split() for item in items]
+ # 'items' now has type list[list[str]]
+
+ The variable must be used before it can be redefined:
+
+ .. code-block:: python
+
+ def process(items: list[str]) -> None:
+ items = "mypy" # invalid redefinition to str because the variable hasn't been used yet
+ print(items)
+ items = "100" # valid, items now has type str
+ items = int(items) # valid, items now has type int
.. confval:: local_partial_types
@@ -578,6 +661,14 @@ section of the command line docs.
Allows disabling one or multiple error codes globally.
+.. confval:: enable_error_code
+
+ :type: comma-separated list of strings
+
+ Allows enabling one or multiple error codes globally.
+
+ Note: This option will override disabled error codes from the disable_error_code option.
+
.. confval:: implicit_reexport
:type: boolean
@@ -598,6 +689,13 @@ section of the command line docs.
from foo import bar
__all__ = ['bar']
+.. confval:: strict_concatenate
+
+ :type: boolean
+ :default: False
+
+ Make arguments prepended via ``Concatenate`` be truly positional-only.
+
.. confval:: strict_equality
:type: boolean
@@ -606,6 +704,18 @@ section of the command line docs.
Prohibit equality checks, identity checks, and container checks between
non-overlapping types.
+.. confval:: strict
+
+ :type: boolean
+ :default: False
+
+ Enable all optional error checking flags. You can see the list of
+ flags enabled by strict mode in the full :option:`mypy --help`
+ output.
+
+ Note: the exact list of flags enabled by :confval:`strict` may
+ change over time.
+
Configuring error messages
**************************
@@ -629,12 +739,12 @@ These options may only be set in the global section (``[mypy]``).
Shows column numbers in error messages.
-.. confval:: show_error_codes
+.. confval:: hide_error_codes
:type: boolean
:default: False
- Shows error codes in error messages. See :ref:`error-codes` for more information.
+ Hides error codes in error messages. See :ref:`error-codes` for more information.
.. confval:: pretty
@@ -765,9 +875,16 @@ These options may only be set in the global section (``[mypy]``).
:type: string
- Specifies an alternative directory to look for stubs instead of the
- default ``typeshed`` directory. User home directory and environment
- variables will be expanded.
+ This specifies the directory where mypy looks for standard library typeshed
+ stubs, instead of the typeshed that ships with mypy. This is
+ primarily intended to make it easier to test typeshed changes before
+ submitting them upstream, but also allows you to use a forked version of
+ typeshed.
+
+ User home directory and environment variables will be expanded.
+
+ Note that this doesn't affect third-party library stubs. To test third-party stubs,
+ for example try ``MYPYPATH=stubs/six mypy ...``.
.. confval:: warn_incomplete_stub
@@ -784,6 +901,12 @@ Report generation
If these options are set, mypy will generate a report in the specified
format into the specified directory.
+.. warning::
+
+ Generating reports disables incremental mode and can significantly slow down
+ your workflow. It is recommended to enable reporting only for specific runs
+ (e.g. in CI).
+
.. confval:: any_exprs_report
:type: string
@@ -797,7 +920,9 @@ format into the specified directory.
Causes mypy to generate a Cobertura XML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. confval:: html_report / xslt_html_report
@@ -805,7 +930,9 @@ format into the specified directory.
Causes mypy to generate an HTML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. confval:: linecount_report
@@ -835,7 +962,9 @@ format into the specified directory.
Causes mypy to generate a text file type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
.. confval:: xml_report
@@ -843,7 +972,9 @@ format into the specified directory.
Causes mypy to generate an XML type checking coverage report.
- You must install the `lxml`_ library to generate this report.
+ To generate this report, you must either manually install the `lxml`_
+ library or specify mypy installation with the setuptools extra
+ ``mypy[reports]``.
Miscellaneous
@@ -884,6 +1015,8 @@ These options may only be set in the global section (``[mypy]``).
Controls how much debug output will be generated. Higher numbers are more verbose.
+.. _using-a-pyproject-toml:
+
Using a pyproject.toml file
***************************
@@ -924,10 +1057,10 @@ Instead of using a ``mypy.ini`` file, a ``pyproject.toml`` file (as specified by
* Boolean values should be all lower case
-Please see the `TOML Documentation`_ for more details and information on
+Please see the `TOML Documentation`_ for more details and information on
what is allowed in a ``toml`` file. See `PEP 518`_ for more information on the layout
and structure of the ``pyproject.toml`` file.
-
+
Example ``pyproject.toml``
**************************
@@ -942,6 +1075,10 @@ of your repo (or append it to the end of an existing ``pyproject.toml`` file) an
python_version = "2.7"
warn_return_any = true
warn_unused_configs = true
+ exclude = [
+ '^file1\.py$', # TOML literal string (single-quotes, no escaping necessary)
+ "^file2\\.py$", # TOML basic string (double-quotes, backslash and other characters need escaping)
+ ]
# mypy per-module options:
diff --git a/docs/source/duck_type_compatibility.rst b/docs/source/duck_type_compatibility.rst
index 45dcfc4..e801f92 100644
--- a/docs/source/duck_type_compatibility.rst
+++ b/docs/source/duck_type_compatibility.rst
@@ -9,7 +9,6 @@ supported for a small set of built-in types:
* ``int`` is duck type compatible with ``float`` and ``complex``.
* ``float`` is duck type compatible with ``complex``.
* ``bytearray`` and ``memoryview`` are duck type compatible with ``bytes``.
-* In Python 2, ``str`` is duck type compatible with ``unicode``.
For example, mypy considers an ``int`` object to be valid whenever a
``float`` object is expected. Thus code like this is nice and clean
@@ -30,16 +29,3 @@ a more principled and extensible fashion. Protocols don't apply to
cases like ``int`` being compatible with ``float``, since ``float`` is not
a protocol class but a regular, concrete class, and many standard library
functions expect concrete instances of ``float`` (or ``int``).
-
-.. note::
-
- Note that in Python 2 a ``str`` object with non-ASCII characters is
- often *not valid* when a unicode string is expected. The mypy type
- system does not consider a string with non-ASCII values as a
- separate type so some programs with this kind of error will
- silently pass type checking. In Python 3 ``str`` and ``bytes`` are
- separate, unrelated types and this kind of error is easy to
- detect. This a good reason for preferring Python 3 over Python 2!
-
- See :ref:`text-and-anystr` for details on how to enforce that a
- value must be a unicode string in a cross-compatible way.
diff --git a/docs/source/dynamic_typing.rst b/docs/source/dynamic_typing.rst
index cea5248..d3476de 100644
--- a/docs/source/dynamic_typing.rst
+++ b/docs/source/dynamic_typing.rst
@@ -4,27 +4,39 @@
Dynamically typed code
======================
-As mentioned earlier, bodies of functions that don't have any explicit
-types in their function annotation are dynamically typed (operations
-are checked at runtime). Code outside functions is statically typed by
-default, and types of variables are inferred. This does usually the
-right thing, but you can also make any variable dynamically typed by
-defining it explicitly with the type ``Any``:
+In :ref:`getting-started-dynamic-vs-static`, we discussed how bodies of functions
+that don't have any explicit type annotations in their function are "dynamically typed"
+and that mypy will not check them. In this section, we'll talk a little bit more
+about what that means and how you can enable dynamic typing on a more fine grained basis.
+
+In cases where your code is too magical for mypy to understand, you can make a
+variable or parameter dynamically typed by explicitly giving it the type
+``Any``. Mypy will let you do basically anything with a value of type ``Any``,
+including assigning a value of type ``Any`` to a variable of any type (or vice
+versa).
.. code-block:: python
from typing import Any
- s = 1 # Statically typed (type int)
- d: Any = 1 # Dynamically typed (type Any)
- s = 'x' # Type check error
- d = 'x' # OK
+ num = 1 # Statically typed (inferred to be int)
+ num = 'x' # error: Incompatible types in assignment (expression has type "str", variable has type "int")
+
+ dyn: Any = 1 # Dynamically typed (type Any)
+ dyn = 'x' # OK
+
+ num = dyn # No error, mypy will let you assign a value of type Any to any variable
+ num += 1 # Oops, mypy still thinks num is an int
+
+You can think of ``Any`` as a way to locally disable type checking.
+See :ref:`silencing-type-errors` for other ways you can shut up
+the type checker.
Operations on Any values
------------------------
-You can do anything using a value with type ``Any``, and type checker
-does not complain:
+You can do anything using a value with type ``Any``, and the type checker
+will not complain:
.. code-block:: python
@@ -37,7 +49,7 @@ does not complain:
open(x).read()
return x
-Values derived from an ``Any`` value also often have the type ``Any``
+Values derived from an ``Any`` value also usually have the type ``Any``
implicitly, as mypy can't infer a more precise result type. For
example, if you get the attribute of an ``Any`` value or call a
``Any`` value the result is ``Any``:
@@ -45,12 +57,45 @@ example, if you get the attribute of an ``Any`` value or call a
.. code-block:: python
def f(x: Any) -> None:
- y = x.foo() # y has type Any
- y.bar() # Okay as well!
+ y = x.foo()
+ reveal_type(y) # Revealed type is "Any"
+ z = y.bar("mypy will let you do anything to y")
+ reveal_type(z) # Revealed type is "Any"
``Any`` types may propagate through your program, making type checking
less effective, unless you are careful.
+Function parameters without annotations are also implicitly ``Any``:
+
+.. code-block:: python
+
+ def f(x) -> None:
+ reveal_type(x) # Revealed type is "Any"
+ x.can.do["anything", x]("wants", 2)
+
+You can make mypy warn you about untyped function parameters using the
+:option:`--disallow-untyped-defs ` flag.
+
+Generic types missing type parameters will have those parameters implicitly
+treated as ``Any``:
+
+.. code-block:: python
+
+ from typing import List
+
+ def f(x: List) -> None:
+ reveal_type(x) # Revealed type is "builtins.list[Any]"
+ reveal_type(x[0]) # Revealed type is "Any"
+ x[0].anything_goes() # OK
+
+You can make mypy warn you about untyped function parameters using the
+:option:`--disallow-any-generics ` flag.
+
+Finally, another major source of ``Any`` types leaking into your program is from
+third party libraries that mypy does not know about. This is particularly the case
+when using the :option:`--ignore-missing-imports `
+flag. See :ref:`fix-missing-imports` for more information about this.
+
Any vs. object
--------------
@@ -77,10 +122,15 @@ operations:
o.foo() # Error!
o + 2 # Error!
open(o) # Error!
- n = 1 # type: int
+ n: int = 1
n = o # Error!
-You can use :py:func:`~typing.cast` (see chapter :ref:`casts`) or :py:func:`isinstance` to
-go from a general type such as :py:class:`object` to a more specific
-type (subtype) such as ``int``. :py:func:`~typing.cast` is not needed with
+
+If you're not sure whether you need to use :py:class:`object` or ``Any``, use
+:py:class:`object` -- only switch to using ``Any`` if you get a type checker
+complaint.
+
+You can use different :ref:`type narrowing `
+techniques to narrow :py:class:`object` to a more specific
+type (subtype) such as ``int``. Type narrowing is not needed with
dynamically typed values (values with type ``Any``).
diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst
index 3afde02..efafb4d 100644
--- a/docs/source/error_code_list.rst
+++ b/docs/source/error_code_list.rst
@@ -89,6 +89,23 @@ This example accidentally calls ``sort()`` instead of :py:func:`sorted`:
x = sort([3, 2, 4]) # Error: Name "sort" is not defined [name-defined]
+
+Check that a variable is not used before it's defined [used-before-def]
+-----------------------------------------------------------------------
+
+Mypy will generate an error if a name is used before it's defined.
+While the name-defined check will catch issues with names that are undefined,
+it will not flag if a variable is used and then defined later in the scope.
+used-before-def check will catch such cases.
+
+Example:
+
+.. code-block:: python
+
+ print(x) # Error: Name "x" is used before definition [used-before-def]
+ x = 123
+
+
Check arguments in calls [call-arg]
-----------------------------------
@@ -117,15 +134,15 @@ Example:
.. code-block:: python
- from typing import List, Optional
+ from typing import Optional
- def first(x: List[int]) -> Optional[int]:
+ def first(x: list[int]) -> Optional[int]:
return x[0] if x else 0
- t = (5, 4)
- # Error: Argument 1 to "first" has incompatible type "Tuple[int, int]";
- # expected "List[int]" [arg-type]
- print(first(t))
+ t = (5, 4)
+ # Error: Argument 1 to "first" has incompatible type "tuple[int, int]";
+ # expected "list[int]" [arg-type]
+ print(first(t))
Check calls to overloaded functions [call-overload]
---------------------------------------------------
@@ -171,26 +188,24 @@ This example incorrectly uses the function ``log`` as a type:
.. code-block:: python
- from typing import List
+ def log(x: object) -> None:
+ print('log:', repr(x))
- def log(x: object) -> None:
- print('log:', repr(x))
-
- # Error: Function "t.log" is not valid as a type [valid-type]
- def log_all(objs: List[object], f: log) -> None:
- for x in objs:
- f(x)
+ # Error: Function "t.log" is not valid as a type [valid-type]
+ def log_all(objs: list[object], f: log) -> None:
+ for x in objs:
+ f(x)
You can use :py:data:`~typing.Callable` as the type for callable objects:
.. code-block:: python
- from typing import List, Callable
+ from typing import Callable
- # OK
- def log_all(objs: List[object], f: Callable[[object], None]) -> None:
- for x in objs:
- f(x)
+ # OK
+ def log_all(objs: list[object], f: Callable[[object], None]) -> None:
+ for x in objs:
+ f(x)
Require annotation if variable type is unclear [var-annotated]
--------------------------------------------------------------
@@ -206,23 +221,21 @@ Example with an error:
.. code-block:: python
- class Bundle:
- def __init__(self) -> None:
- # Error: Need type annotation for "items"
- # (hint: "items: List[] = ...") [var-annotated]
- self.items = []
+ class Bundle:
+ def __init__(self) -> None:
+ # Error: Need type annotation for "items"
+ # (hint: "items: list[] = ...") [var-annotated]
+ self.items = []
- reveal_type(Bundle().items) # list[Any]
+ reveal_type(Bundle().items) # list[Any]
To address this, we add an explicit annotation:
.. code-block:: python
- from typing import List
-
- class Bundle:
- def __init__(self) -> None:
- self.items: List[str] = [] # OK
+ class Bundle:
+ def __init__(self) -> None:
+ self.items: list[str] = [] # OK
reveal_type(Bundle().items) # list[str]
@@ -377,10 +390,10 @@ Example:
a['x'] # OK
- # Error: Invalid index type "int" for "Dict[str, int]"; expected type "str" [index]
+ # Error: Invalid index type "int" for "dict[str, int]"; expected type "str" [index]
print(a[1])
- # Error: Invalid index type "bytes" for "Dict[str, int]"; expected type "str" [index]
+ # Error: Invalid index type "bytes" for "dict[str, int]"; expected type "str" [index]
a[b'x'] = 4
Check list items [list-item]
@@ -394,10 +407,8 @@ Example:
.. code-block:: python
- from typing import List
-
# Error: List item 0 has incompatible type "int"; expected "str" [list-item]
- a: List[str] = [0]
+ a: list[str] = [0]
Check dict items [dict-item]
----------------------------
@@ -410,10 +421,8 @@ Example:
.. code-block:: python
- from typing import Dict
-
# Error: Dict entry 0 has incompatible type "str": "str"; expected "str": "int" [dict-item]
- d: Dict[str, int] = {'key': 'value'}
+ d: dict[str, int] = {'key': 'value'}
Check TypedDict items [typeddict-item]
--------------------------------------
@@ -545,7 +554,7 @@ Check instantiation of abstract classes [abstract]
--------------------------------------------------
Mypy generates an error if you try to instantiate an abstract base
-class (ABC). An abtract base class is a class with at least one
+class (ABC). An abstract base class is a class with at least one
abstract method or attribute. (See also :py:mod:`abc` module documentation)
Sometimes a class is made accidentally abstract, often due to an
@@ -572,6 +581,54 @@ Example:
# Error: Cannot instantiate abstract class "Thing" with abstract attribute "save" [abstract]
t = Thing()
+Safe handling of abstract type object types [type-abstract]
+-----------------------------------------------------------
+
+Mypy always allows instantiating (calling) type objects typed as ``Type[t]``,
+even if it is not known that ``t`` is non-abstract, since it is a common
+pattern to create functions that act as object factories (custom constructors).
+Therefore, to prevent issues described in the above section, when an abstract
+type object is passed where ``Type[t]`` is expected, mypy will give an error.
+Example:
+
+.. code-block:: python
+
+ from abc import ABCMeta, abstractmethod
+ from typing import List, Type, TypeVar
+
+ class Config(metaclass=ABCMeta):
+ @abstractmethod
+ def get_value(self, attr: str) -> str: ...
+
+ T = TypeVar("T")
+ def make_many(typ: Type[T], n: int) -> List[T]:
+ return [typ() for _ in range(n)] # This will raise if typ is abstract
+
+ # Error: Only concrete class can be given where "Type[Config]" is expected [type-abstract]
+ make_many(Config, 5)
+
+Check that call to an abstract method via super is valid [safe-super]
+---------------------------------------------------------------------
+
+Abstract methods often don't have any default implementation, i.e. their
+bodies are just empty. Calling such methods in subclasses via ``super()``
+will cause runtime errors, so mypy prevents you from doing so:
+
+.. code-block:: python
+
+ from abc import abstractmethod
+ class Base:
+ @abstractmethod
+ def foo(self) -> int: ...
+ class Sub(Base):
+ def foo(self) -> int:
+ return super().foo() + 1 # error: Call to abstract method "foo" of "Base" with
+ # trivial body via super() is unsafe [safe-super]
+ Sub().foo() # This will crash at runtime.
+
+Mypy considers the following as trivial bodies: a ``pass`` statement, a literal
+ellipsis ``...``, a docstring, and a ``raise NotImplementedError`` statement.
+
Check the target of NewType [valid-newtype]
-------------------------------------------
@@ -665,6 +722,78 @@ consistently when using the call-based syntax. Example:
# Error: First argument to namedtuple() should be "Point2D", not "Point"
Point2D = NamedTuple("Point", [("x", int), ("y", int)])
+Check that overloaded functions have an implementation [no-overload-impl]
+-------------------------------------------------------------------------
+
+Overloaded functions outside of stub files must be followed by a non overloaded
+implementation.
+
+.. code-block:: python
+
+ from typing import overload
+
+ @overload
+ def func(value: int) -> int:
+ ...
+
+ @overload
+ def func(value: str) -> str:
+ ...
+
+ # presence of required function below is checked
+ def func(value):
+ pass # actual implementation
+
+Check that coroutine return value is used [unused-coroutine]
+------------------------------------------------------------
+
+Mypy ensures that return values of async def functions are not
+ignored, as this is usually a programming error, as the coroutine
+won't be executed at the call site.
+
+.. code-block:: python
+
+ async def f() -> None:
+ ...
+
+ async def g() -> None:
+ f() # Error: missing await
+ await f() # OK
+
+You can work around this error by assigning the result to a temporary,
+otherwise unused variable:
+
+.. code-block:: python
+
+ _ = f() # No error
+
+Check types in assert_type [assert-type]
+----------------------------------------
+
+The inferred type for an expression passed to ``assert_type`` must match
+the provided type.
+
+.. code-block:: python
+
+ from typing_extensions import assert_type
+
+ assert_type([1], list[int]) # OK
+
+ assert_type([1], list[str]) # Error
+
+Check that function isn't used in boolean context [truthy-function]
+-------------------------------------------------------------------
+
+Functions will always evaluate to true in boolean contexts.
+
+.. code-block:: python
+
+ def f():
+ ...
+
+ if f: # Error: Function "Callable[[], Any]" could always be true in boolean context [truthy-function]
+ pass
+
Report syntax errors [syntax]
-----------------------------
diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst
index d88525f..f160515 100644
--- a/docs/source/error_code_list2.rst
+++ b/docs/source/error_code_list2.rst
@@ -19,10 +19,10 @@ Check that type arguments exist [type-arg]
------------------------------------------
If you use :option:`--disallow-any-generics `, mypy requires that each generic
-type has values for each type argument. For example, the types ``List`` or
-``dict`` would be rejected. You should instead use types like ``List[int]`` or
-``Dict[str, int]``. Any omitted generic type arguments get implicit ``Any``
-values. The type ``List`` is equivalent to ``List[Any]``, and so on.
+type has values for each type argument. For example, the types ``list`` or
+``dict`` would be rejected. You should instead use types like ``list[int]`` or
+``dict[str, int]``. Any omitted generic type arguments get implicit ``Any``
+values. The type ``list`` is equivalent to ``list[Any]``, and so on.
Example:
@@ -30,10 +30,8 @@ Example:
# mypy: disallow-any-generics
- from typing import List
-
- # Error: Missing type parameters for generic type "List" [type-arg]
- def remove_dups(items: List) -> List:
+ # Error: Missing type parameters for generic type "list" [type-arg]
+ def remove_dups(items: list) -> list:
...
Check that every function has an annotation [no-untyped-def]
@@ -84,6 +82,28 @@ Example:
# Error: Redundant cast to "int" [redundant-cast]
return cast(int, x)
+Check that methods do not have redundant Self annotations [redundant-self]
+--------------------------------------------------------------------------
+
+If a method uses the ``Self`` type in the return type or the type of a
+non-self argument, there is no need to annotate the ``self`` argument
+explicitly. Such annotations are allowed by :pep:`673` but are
+redundant. If you enable this error code, mypy will generate an error if
+there is a redundant ``Self`` type.
+
+Example:
+
+.. code-block:: python
+
+ # mypy: enable-error-code="redundant-self"
+
+ from typing import Self
+
+ class C:
+ # Error: Redundant "Self" annotation for the first method argument
+ def copy(self: Self) -> Self:
+ return type(self)()
+
Check that comparisons are overlapping [comparison-overlap]
-----------------------------------------------------------
@@ -202,7 +222,7 @@ mypy generates an error if it thinks that an expression is redundant.
.. code-block:: python
- # mypy: enable-error-code redundant-expr
+ # Use "mypy --enable-error-code redundant-expr ..."
def example(x: int) -> None:
# Error: Left operand of "and" is always true [redundant-expr]
@@ -214,3 +234,116 @@ mypy generates an error if it thinks that an expression is redundant.
# Error: If condition in comprehension is always true [redundant-expr]
[i for i in range(x) if isinstance(i, int)]
+
+
+Check that expression is not implicitly true in boolean context [truthy-bool]
+-----------------------------------------------------------------------------
+
+Warn when the type of an expression in a boolean context does not
+implement ``__bool__`` or ``__len__``. Unless one of these is
+implemented by a subtype, the expression will always be considered
+true, and there may be a bug in the condition.
+
+As an exception, the ``object`` type is allowed in a boolean context.
+Using an iterable value in a boolean context has a separate error code
+(see below).
+
+.. code-block:: python
+
+ # Use "mypy --enable-error-code truthy-bool ..."
+
+ class Foo:
+ pass
+ foo = Foo()
+ # Error: "foo" has type "Foo" which does not implement __bool__ or __len__ so it could always be true in boolean context
+ if foo:
+ ...
+
+
+Check that iterable is not implicitly true in boolean context [truthy-iterable]
+-------------------------------------------------------------------------------
+
+Generate an error if a value of type ``Iterable`` is used as a boolean
+condition, since ``Iterable`` does not implement ``__len__`` or ``__bool__``.
+
+Example:
+
+.. code-block:: python
+
+ from typing import Iterable
+
+ def transform(items: Iterable[int]) -> list[int]:
+ # Error: "items" has type "Iterable[int]" which can always be true in boolean context. Consider using "Collection[int]" instead. [truthy-iterable]
+ if not items:
+ return [42]
+ return [x + 1 for x in items]
+
+If ``transform`` is called with a ``Generator`` argument, such as
+``int(x) for x in []``, this function would not return ``[42]`` unlike
+what might be intended. Of course, it's possible that ``transform`` is
+only called with ``list`` or other container objects, and the ``if not
+items`` check is actually valid. If that is the case, it is
+recommended to annotate ``items`` as ``Collection[int]`` instead of
+``Iterable[int]``.
+
+
+.. _ignore-without-code:
+
+Check that ``# type: ignore`` include an error code [ignore-without-code]
+-------------------------------------------------------------------------
+
+Warn when a ``# type: ignore`` comment does not specify any error codes.
+This clarifies the intent of the ignore and ensures that only the
+expected errors are silenced.
+
+Example:
+
+.. code-block:: python
+
+ # Use "mypy --enable-error-code ignore-without-code ..."
+
+ class Foo:
+ def __init__(self, name: str) -> None:
+ self.name = name
+
+ f = Foo('foo')
+
+ # This line has a typo that mypy can't help with as both:
+ # - the expected error 'assignment', and
+ # - the unexpected error 'attr-defined'
+ # are silenced.
+ # Error: "type: ignore" comment without error code (consider "type: ignore[attr-defined]" instead)
+ f.nme = 42 # type: ignore
+
+ # This line warns correctly about the typo in the attribute name
+ # Error: "Foo" has no attribute "nme"; maybe "name"?
+ f.nme = 42 # type: ignore[assignment]
+
+Check that awaitable return value is used [unused-awaitable]
+------------------------------------------------------------
+
+If you use :option:`--enable-error-code unused-awaitable `,
+mypy generates an error if you don't use a returned value that defines ``__await__``.
+
+Example:
+
+.. code-block:: python
+
+ # Use "mypy --enable-error-code unused-awaitable ..."
+
+ import asyncio
+
+ async def f() -> int: ...
+
+ async def g() -> None:
+ # Error: Value of type "Task[int]" must be used
+ # Are you missing an await?
+ asyncio.create_task(f())
+
+You can assign the value to a temporary, otherwise unused to variable to
+silence the error:
+
+.. code-block:: python
+
+ async def g() -> None:
+ _ = asyncio.create_task(f()) # No error
diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst
index 8a65457..aabedf8 100644
--- a/docs/source/error_codes.rst
+++ b/docs/source/error_codes.rst
@@ -23,14 +23,20 @@ Error codes may change in future mypy releases.
Displaying error codes
----------------------
-Error codes are not displayed by default. Use :option:`--show-error-codes `
-or config `show_error_codes = True` to display error codes. Error codes are shown inside square brackets:
+Error codes are displayed by default. Use :option:`--hide-error-codes `
+or config ``hide_error_codes = True`` to hide error codes. Error codes are shown inside square brackets:
.. code-block:: text
- $ mypy --show-error-codes prog.py
+ $ mypy prog.py
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
+It's also possible to require error codes for ``type: ignore`` comments.
+See :ref:`ignore-without-code` for more information.
+
+
+.. _silence-error-codes:
+
Silencing errors based on error codes
-------------------------------------
@@ -40,11 +46,8 @@ line. This can be used even if you have not configured mypy to show
error codes. Currently it's only possible to disable arbitrary error
codes on individual lines using this comment.
-.. note::
-
- There are command-line flags and config file settings for enabling
- certain optional error codes, such as :option:`--disallow-untyped-defs `,
- which enables the ``no-untyped-def`` error code.
+You can also use :option:`--disable-error-code `
+to disable specific error codes globally.
This example shows how to ignore an error about an imported name mypy
thinks is undefined:
@@ -54,3 +57,59 @@ thinks is undefined:
# 'foo' is defined in 'foolib', even though mypy can't see the
# definition.
from foolib import foo # type: ignore[attr-defined]
+
+
+Enabling specific error codes
+-----------------------------
+
+There are command-line flags and config file settings for enabling
+certain optional error codes, such as :option:`--disallow-untyped-defs `,
+which enables the ``no-untyped-def`` error code.
+
+You can use :option:`--enable-error-code ` to
+enable specific error codes that don't have a dedicated command-line
+flag or config file setting.
+
+Per-module enabling/disabling error codes
+-----------------------------------------
+
+You can use :ref:`configuration file ` sections to enable or
+disable specific error codes only in some modules. For example, this ``mypy.ini``
+config will enable non-annotated empty containers in tests, while keeping
+other parts of code checked in strict mode:
+
+.. code-block:: ini
+
+ [mypy]
+ strict = True
+
+ [mypy-tests.*]
+ allow_untyped_defs = True
+ allow_untyped_calls = True
+ disable_error_code = var-annotated, has-type
+
+Note that per-module enabling/disabling acts as override over the global
+options. So that you don't need to repeat the error code lists for each
+module if you have them in global config section. For example:
+
+.. code-block:: ini
+
+ [mypy]
+ enable_error_code = truthy-bool, ignore-without-code, unused-awaitable
+
+ [mypy-extensions.*]
+ disable_error_code = unused-awaitable
+
+The above config will allow unused awaitables in extension modules, but will
+still keep the other two error codes enabled. The overall logic is following:
+
+* Command line and/or config main section set global error codes
+
+* Individual config sections *adjust* them per glob/module
+
+* Inline ``# mypy: ...`` comments can further *adjust* them for a specific
+ module
+
+So one can e.g. enable some code globally, disable it for all tests in
+the corresponding config section, and then re-enable it with an inline
+comment in some specific test.
diff --git a/docs/source/existing_code.rst b/docs/source/existing_code.rst
index 66259e5..410d7af 100644
--- a/docs/source/existing_code.rst
+++ b/docs/source/existing_code.rst
@@ -7,38 +7,78 @@ This section explains how to get started using mypy with an existing,
significant codebase that has little or no type annotations. If you are
a beginner, you can skip this section.
-These steps will get you started with mypy on an existing codebase:
+Start small
+-----------
-1. Start small -- get a clean mypy build for some files, with few
- annotations
+If your codebase is large, pick a subset of your codebase (say, 5,000 to 50,000
+lines) and get mypy to run successfully only on this subset at first, *before
+adding annotations*. This should be doable in a day or two. The sooner you get
+some form of mypy passing on your codebase, the sooner you benefit.
-2. Write a mypy runner script to ensure consistent results
+You'll likely need to fix some mypy errors, either by inserting
+annotations requested by mypy or by adding ``# type: ignore``
+comments to silence errors you don't want to fix now.
-3. Run mypy in Continuous Integration to prevent type errors
+We'll mention some tips for getting mypy passing on your codebase in various
+sections below.
-4. Gradually annotate commonly imported modules
+Run mypy consistently and prevent regressions
+---------------------------------------------
-5. Write annotations as you modify existing code and write new code
+Make sure all developers on your codebase run mypy the same way.
+One way to ensure this is adding a small script with your mypy
+invocation to your codebase, or adding your mypy invocation to
+existing tools you use to run tests, like ``tox``.
-6. Use :doc:`monkeytype:index` or `PyAnnotate`_ to automatically annotate legacy code
+* Make sure everyone runs mypy with the same options. Checking a mypy
+ :ref:`configuration file ` into your codebase can help
+ with this.
-We discuss all of these points in some detail below, and a few optional
-follow-up steps.
+* Make sure everyone type checks the same set of files. See
+ :ref:`specifying-code-to-be-checked` for details.
-Start small
------------
+* Make sure everyone runs mypy with the same version of mypy, for instance
+ by pinning mypy with the rest of your dev requirements.
-If your codebase is large, pick a subset of your codebase (say, 5,000
-to 50,000 lines) and run mypy only on this subset at first,
-*without any annotations*. This shouldn't take more than a day or two
-to implement, so you start enjoying benefits soon.
+In particular, you'll want to make sure to run mypy as part of your
+Continuous Integration (CI) system as soon as possible. This will
+prevent new type errors from being introduced into your codebase.
-You'll likely need to fix some mypy errors, either by inserting
-annotations requested by mypy or by adding ``# type: ignore``
-comments to silence errors you don't want to fix now.
+A simple CI script could look something like this:
+
+.. code-block:: text
+
+ python3 -m pip install mypy==0.971
+ # Run your standardised mypy invocation, e.g.
+ mypy my_project
+ # This could also look like `scripts/run_mypy.sh`, `tox run -e mypy`, `make mypy`, etc
+
+Ignoring errors from certain modules
+------------------------------------
-In particular, mypy often generates errors about modules that it can't
-find or that don't have stub files:
+By default mypy will follow imports in your code and try to check everything.
+This means even if you only pass in a few files to mypy, it may still process a
+large number of imported files. This could potentially result in lots of errors
+you don't want to deal with at the moment.
+
+One way to deal with this is to ignore errors in modules you aren't yet ready to
+type check. The :confval:`ignore_errors` option is useful for this, for instance,
+if you aren't yet ready to deal with errors from ``package_to_fix_later``:
+
+.. code-block:: text
+
+ [mypy-package_to_fix_later.*]
+ ignore_errors = True
+
+You could even invert this, by setting ``ignore_errors = True`` in your global
+config section and only enabling error reporting with ``ignore_errors = False``
+for the set of modules you are ready to type check.
+
+Fixing errors related to imports
+--------------------------------
+
+A common class of error you will encounter is errors from mypy about modules
+that it can't find, that don't have types, or don't have stub files:
.. code-block:: text
@@ -46,7 +86,15 @@ find or that don't have stub files:
core/model.py:9: error: Cannot find implementation or library stub for module named 'acme'
...
-This is normal, and you can easily ignore these errors. For example,
+Sometimes these can be fixed by installing the relevant packages or
+stub libraries in the environment you're running ``mypy`` in.
+
+See :ref:`ignore-missing-imports` for a complete reference on these errors
+and the ways in which you can fix them.
+
+You'll likely find that you want to suppress all errors from importing
+a given module that doesn't have types. If you only import that module
+in one or two places, you can use ``# type: ignore`` comments. For example,
here we ignore an error about a third-party module ``frobnicate`` that
doesn't have stubs using ``# type: ignore``:
@@ -56,9 +104,9 @@ doesn't have stubs using ``# type: ignore``:
...
frobnicate.initialize() # OK (but not checked)
-You can also use a mypy configuration file, which is convenient if
-there are a large number of errors to ignore. For example, to disable
-errors about importing ``frobnicate`` and ``acme`` everywhere in your
+But if you import the module in many places, this becomes unwieldy. In this
+case, we recommend using a :ref:`configuration file `. For example,
+to disable errors about importing ``frobnicate`` and ``acme`` everywhere in your
codebase, use a config like this:
.. code-block:: text
@@ -69,69 +117,33 @@ codebase, use a config like this:
[mypy-acme.*]
ignore_missing_imports = True
-You can add multiple sections for different modules that should be
-ignored.
-
-If your config file is named ``mypy.ini``, this is how you run mypy:
-
-.. code-block:: text
-
- mypy --config-file mypy.ini mycode/
-
If you get a large number of errors, you may want to ignore all errors
-about missing imports. This can easily cause problems later on and
-hide real errors, and it's only recommended as a last resort.
-For more details, look :ref:`here `.
-
-Mypy follows imports by default. This can result in a few files passed
-on the command line causing mypy to process a large number of imported
-files, resulting in lots of errors you don't want to deal with at the
-moment. There is a config file option to disable this behavior, but
-since this can hide errors, it's not recommended for most users.
-
-Mypy runner script
-------------------
-
-Introduce a mypy runner script that runs mypy, so that every developer
-will use mypy consistently. Here are some things you may want to do in
-the script:
-
-* Ensure that the correct version of mypy is installed.
-
-* Specify mypy config file or command-line options.
-
-* Provide set of files to type check. You may want to implement
- inclusion and exclusion filters for full control of the file
- list.
-
-Continuous Integration
-----------------------
-
-Once you have a clean mypy run and a runner script for a part
-of your codebase, set up your Continuous Integration (CI) system to
-run mypy to ensure that developers won't introduce bad annotations.
-A simple CI script could look something like this:
+about missing imports, for instance by setting :confval:`ignore_missing_imports`
+to true globally. This can hide errors later on, so we recommend avoiding this
+if possible.
-.. code-block:: text
+Finally, mypy allows fine-grained control over specific import following
+behaviour. It's very easy to silently shoot yourself in the foot when playing
+around with these, so it's mostly recommended as a last resort. For more
+details, look :ref:`here `.
- python3 -m pip install mypy==0.790 # Pinned version avoids surprises
- scripts/mypy # Run the mypy runner script you set up
-
-Annotate widely imported modules
---------------------------------
+Prioritise annotating widely imported modules
+---------------------------------------------
Most projects have some widely imported modules, such as utilities or
model classes. It's a good idea to annotate these pretty early on,
since this allows code using these modules to be type checked more
-effectively. Since mypy supports gradual typing, it's okay to leave
-some of these modules unannotated. The more you annotate, the more
-useful mypy will be, but even a little annotation coverage is useful.
+effectively.
+
+Mypy is designed to support gradual typing, i.e. letting you add annotations at
+your own pace, so it's okay to leave some of these modules unannotated. The more
+you annotate, the more useful mypy will be, but even a little annotation
+coverage is useful.
Write annotations as you go
---------------------------
-Now you are ready to include type annotations in your development
-workflows. Consider adding something like these in your code style
+Consider adding something like these in your code style
conventions:
1. Developers should add annotations for any new code.
@@ -143,9 +155,9 @@ codebase without much effort.
Automate annotation of legacy code
----------------------------------
-There are tools for automatically adding draft annotations
-based on type profiles collected at runtime. Tools include
-:doc:`monkeytype:index` (Python 3) and `PyAnnotate`_.
+There are tools for automatically adding draft annotations based on simple
+static analysis or on type profiles collected at runtime. Tools include
+:doc:`monkeytype:index`, `autotyping`_ and `PyAnnotate`_.
A simple approach is to collect types from test runs. This may work
well if your test coverage is good (and if your tests aren't very
@@ -156,14 +168,7 @@ fraction of production network requests. This clearly requires more
care, as type collection could impact the reliability or the
performance of your service.
-Speed up mypy runs
-------------------
-
-You can use :ref:`mypy daemon ` to get much faster
-incremental mypy runs. The larger your project is, the more useful
-this will be. If your project has at least 100,000 lines of code or
-so, you may also want to set up :ref:`remote caching `
-for further speedups.
+.. _getting-to-strict:
Introduce stricter options
--------------------------
@@ -172,7 +177,69 @@ Mypy is very configurable. Once you get started with static typing, you may want
to explore the various strictness options mypy provides to catch more bugs. For
example, you can ask mypy to require annotations for all functions in certain
modules to avoid accidentally introducing code that won't be type checked using
-:confval:`disallow_untyped_defs`, or type check code without annotations as well
-with :confval:`check_untyped_defs`. Refer to :ref:`config-file` for the details.
+:confval:`disallow_untyped_defs`. Refer to :ref:`config-file` for the details.
+
+An excellent goal to aim for is to have your codebase pass when run against ``mypy --strict``.
+This basically ensures that you will never have a type related error without an explicit
+circumvention somewhere (such as a ``# type: ignore`` comment).
+
+The following config is equivalent to ``--strict`` (as of mypy 0.990):
+
+.. code-block:: text
+
+ # Start off with these
+ warn_unused_configs = True
+ warn_redundant_casts = True
+ warn_unused_ignores = True
+ no_implicit_optional = True
+
+ # Getting these passing should be easy
+ strict_equality = True
+ strict_concatenate = True
+
+ # Strongly recommend enabling this one as soon as you can
+ check_untyped_defs = True
+
+ # These shouldn't be too much additional work, but may be tricky to
+ # get passing if you use a lot of untyped libraries
+ disallow_subclassing_any = True
+ disallow_untyped_decorators = True
+ disallow_any_generics = True
+
+ # These next few are various gradations of forcing use of type annotations
+ disallow_untyped_calls = True
+ disallow_incomplete_defs = True
+ disallow_untyped_defs = True
+
+ # This one isn't too hard to get passing, but return on investment is lower
+ no_implicit_reexport = True
+
+ # This one can be tricky to get passing if you use a lot of untyped libraries
+ warn_return_any = True
+
+Note that you can also start with ``--strict`` and subtract, for instance:
+
+.. code-block:: text
+
+ strict = True
+ warn_return_any = False
+
+Remember that many of these options can be enabled on a per-module basis. For instance,
+you may want to enable ``disallow_untyped_defs`` for modules which you've completed
+annotations for, in order to prevent new code from being added without annotations.
+
+And if you want, it doesn't stop at ``--strict``. Mypy has additional checks
+that are not part of ``--strict`` that can be useful. See the complete
+:ref:`command-line` reference and :ref:`error-codes-optional`.
+
+Speed up mypy runs
+------------------
+
+You can use :ref:`mypy daemon ` to get much faster
+incremental mypy runs. The larger your project is, the more useful
+this will be. If your project has at least 100,000 lines of code or
+so, you may also want to set up :ref:`remote caching `
+for further speedups.
.. _PyAnnotate: https://github.com/dropbox/pyannotate
+.. _autotyping: https://github.com/JelleZijlstra/autotyping
diff --git a/docs/source/extending_mypy.rst b/docs/source/extending_mypy.rst
index 90e5f2f..daf8636 100644
--- a/docs/source/extending_mypy.rst
+++ b/docs/source/extending_mypy.rst
@@ -9,10 +9,10 @@ Integrating mypy into another Python application
************************************************
It is possible to integrate mypy into another Python 3 application by
-importing ``mypy.api`` and calling the ``run`` function with a parameter of type ``List[str]``, containing
+importing ``mypy.api`` and calling the ``run`` function with a parameter of type ``list[str]``, containing
what normally would have been the command line arguments to mypy.
-Function ``run`` returns a ``Tuple[str, str, int]``, namely
+Function ``run`` returns a ``tuple[str, str, int]``, namely
``(, , )``, in which ````
is what mypy normally writes to :py:data:`sys.stdout`, ```` is what mypy
normally writes to :py:data:`sys.stderr` and ``exit_status`` is the exit status mypy normally
@@ -155,23 +155,9 @@ When analyzing this code, mypy will call ``get_type_analyze_hook("lib.Vector")``
so the plugin can return some valid type for each variable.
**get_function_hook()** is used to adjust the return type of a function call.
-This is a good choice if the return type of some function depends on *values*
-of some arguments that can't be expressed using literal types (for example
-a function may return an ``int`` for positive arguments and a ``float`` for
-negative arguments). This hook will be also called for instantiation of classes.
-For example:
-
-.. code-block:: python
-
- from contextlib import contextmanager
- from typing import TypeVar, Callable
-
- T = TypeVar('T')
-
- @contextmanager # built-in plugin can infer a precise type here
- def stopwatch(timer: Callable[[], T]) -> Iterator[T]:
- ...
- yield timer()
+This hook will be also called for instantiation of classes.
+This is a good choice if the return type is too complex
+to be expressed by regular python typing.
**get_function_signature_hook** is used to adjust the signature of a function.
@@ -198,6 +184,10 @@ fields which already exist on the class. *Exception:* if :py:meth:`__getattr__ <
:py:meth:`__getattribute__ ` is a method on the class, the hook is called for all
fields which do not refer to methods.
+**get_class_attribute_hook()** is similar to above, but for attributes on classes rather than instances.
+Unlike above, this does not have special casing for :py:meth:`__getattr__ ` or
+:py:meth:`__getattribute__ `.
+
**get_class_decorator_hook()** can be used to update class definition for
given class decorators. For example, you can add some attributes to the class
to match runtime behaviour:
@@ -246,32 +236,4 @@ when the configuration for a module changes, we want to invalidate
mypy's cache for that module so that it can be rechecked. This hook
should be used to report to mypy any relevant configuration data,
so that mypy knows to recheck the module if the configuration changes.
-The hooks hould return data encodable as JSON.
-
-Notes about the semantic analyzer
-*********************************
-
-Mypy 0.710 introduced a new semantic analyzer, and the old semantic
-analyzer was removed in mypy 0.730. Support for the new semantic analyzer
-required some changes to existing plugins. Here is a short summary of the
-most important changes:
-
-* The order of processing AST nodes is different. Code outside
- functions is processed first, and functions and methods are
- processed afterwards.
-
-* Each AST node can be processed multiple times to resolve forward
- references. The same plugin hook may be called multiple times, so
- they need to be idempotent.
-
-* The ``anal_type()`` API method returns ``None`` if some part of
- the type is not available yet due to forward references, for example.
-
-* When looking up symbols, you may encounter *placeholder nodes* that
- are used for names that haven't been fully processed yet. You'll
- generally want to request another semantic analysis iteration by
- *deferring* in that case.
-
-See the docstring at the top of
-`mypy/plugin.py `_
-for more details.
+The hooks should return data encodable as JSON.
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
index 43ba3d0..d97929c 100644
--- a/docs/source/faq.rst
+++ b/docs/source/faq.rst
@@ -85,14 +85,6 @@ could be other tools that can compile statically typed mypy code to C
modules or to efficient JVM bytecode, for example, but this is outside
the scope of the mypy project.
-How do I type check my Python 2 code?
-*************************************
-
-You can use a :pep:`comment-based function annotation syntax
-<484#suggested-syntax-for-python-2-7-and-straddling-code>`
-and use the :option:`--py2 ` command-line option to type check your Python 2 code.
-You'll also need to install ``typing`` for Python 2 via ``pip install typing``.
-
Is mypy free?
*************
@@ -197,11 +189,12 @@ the following aspects, among others:
defined in terms of translating them to C or C++. Mypy just uses
Python semantics, and mypy does not deal with accessing C library
functionality.
-
+
Does it run on PyPy?
*********************
-No. MyPy relies on `typed-ast
+Somewhat. With PyPy 3.8, mypy is at least able to type check itself.
+With older versions of PyPy, mypy relies on `typed-ast
`_, which uses several APIs that
PyPy does not support (including some internal CPython APIs).
diff --git a/docs/source/final_attrs.rst b/docs/source/final_attrs.rst
index 8c42ae9..297b97e 100644
--- a/docs/source/final_attrs.rst
+++ b/docs/source/final_attrs.rst
@@ -17,7 +17,7 @@ There is no runtime enforcement by the Python runtime.
The examples in this page import ``Final`` and ``final`` from the
``typing`` module. These types were added to ``typing`` in Python 3.8,
- but are also available for use in Python 2.7 and 3.4 - 3.7 via the
+ but are also available for use in Python 3.4 - 3.7 via the
``typing_extensions`` package.
Final names
@@ -33,7 +33,7 @@ further assignments to final names in type-checked code:
from typing import Final
- RATE: Final = 3000
+ RATE: Final = 3_000
class Base:
DEFAULT_ID: Final = 0
@@ -119,9 +119,9 @@ annotations. Using it in any other position is an error. In particular,
.. code-block:: python
- x: List[Final[int]] = [] # Error!
+ x: list[Final[int]] = [] # Error!
- def fun(x: Final[List[int]]) -> None: # Error!
+ def fun(x: Final[list[int]]) -> None: # Error!
...
``Final`` and :py:data:`~typing.ClassVar` should not be used together. Mypy will infer
diff --git a/docs/source/generics.rst b/docs/source/generics.rst
index 817466d..9ac79f9 100644
--- a/docs/source/generics.rst
+++ b/docs/source/generics.rst
@@ -2,7 +2,7 @@ Generics
========
This section explains how you can define your own generic classes that take
-one or more type parameters, similar to built-in types such as ``List[X]``.
+one or more type parameters, similar to built-in types such as ``list[X]``.
User-defined generics are a moderately advanced feature and you can get far
without ever using them -- feel free to skip this section and come back later.
@@ -13,8 +13,8 @@ Defining generic classes
The built-in collection classes are generic classes. Generic types
have one or more type parameters, which can be arbitrary types. For
-example, ``Dict[int, str]`` has the type parameters ``int`` and
-``str``, and ``List[int]`` has a type parameter ``int``.
+example, ``dict[int, str]`` has the type parameters ``int`` and
+``str``, and ``list[int]`` has a type parameter ``int``.
Programs can also define new generic classes. Here is a very simple
generic class that represents a stack:
@@ -28,7 +28,7 @@ generic class that represents a stack:
class Stack(Generic[T]):
def __init__(self) -> None:
# Create an empty list with items of type T
- self.items: List[T] = []
+ self.items: list[T] = []
def push(self, item: T) -> None:
self.items.append(item)
@@ -40,7 +40,7 @@ generic class that represents a stack:
return not self.items
The ``Stack`` class can be used to represent a stack of any type:
-``Stack[int]``, ``Stack[Tuple[int, str]]``, etc.
+``Stack[int]``, ``Stack[tuple[int, str]]``, etc.
Using ``Stack`` is similar to built-in container types:
@@ -50,17 +50,9 @@ Using ``Stack`` is similar to built-in container types:
stack = Stack[int]()
stack.push(2)
stack.pop()
- stack.push('x') # Type error
+ stack.push('x') # error: Argument 1 to "push" of "Stack" has incompatible type "str"; expected "int"
-Type inference works for user-defined generic types as well:
-
-.. code-block:: python
-
- def process(stack: Stack[int]) -> None: ...
-
- process(Stack()) # Argument has inferred type Stack[int]
-
-Construction of instances of generic types is also type checked:
+Construction of instances of generic types is type checked:
.. code-block:: python
@@ -68,87 +60,48 @@ Construction of instances of generic types is also type checked:
def __init__(self, content: T) -> None:
self.content = content
- Box(1) # OK, inferred type is Box[int]
+ Box(1) # OK, inferred type is Box[int]
Box[int](1) # Also OK
- s = 'some string'
- Box[int](s) # Type error
-
-Generic class internals
-***********************
-
-You may wonder what happens at runtime when you index
-``Stack``. Actually, indexing ``Stack`` returns essentially a copy
-of ``Stack`` that returns instances of the original class on
-instantiation:
-
-.. code-block:: python
-
- >>> print(Stack)
- __main__.Stack
- >>> print(Stack[int])
- __main__.Stack[int]
- >>> print(Stack[int]().__class__)
- __main__.Stack
-
-Note that built-in types :py:class:`list`, :py:class:`dict` and so on do not support
-indexing in Python. This is why we have the aliases :py:class:`~typing.List`, :py:class:`~typing.Dict`
-and so on in the :py:mod:`typing` module. Indexing these aliases gives
-you a class that directly inherits from the target class in Python:
-
-.. code-block:: python
-
- >>> from typing import List
- >>> List[int]
- typing.List[int]
- >>> List[int].__bases__
- (, typing.MutableSequence)
-
-Generic types could be instantiated or subclassed as usual classes,
-but the above examples illustrate that type variables are erased at
-runtime. Generic ``Stack`` instances are just ordinary
-Python objects, and they have no extra runtime overhead or magic due
-to being generic, other than a metaclass that overloads the indexing
-operator.
+ Box[int]('some string') # error: Argument 1 to "Box" has incompatible type "str"; expected "int"
.. _generic-subclasses:
-Defining sub-classes of generic classes
-***************************************
+Defining subclasses of generic classes
+**************************************
User-defined generic classes and generic classes defined in :py:mod:`typing`
-can be used as base classes for another classes, both generic and
-non-generic. For example:
+can be used as a base class for another class (generic or non-generic). For example:
.. code-block:: python
- from typing import Generic, TypeVar, Mapping, Iterator, Dict
+ from typing import Generic, TypeVar, Mapping, Iterator
KT = TypeVar('KT')
VT = TypeVar('VT')
- class MyMap(Mapping[KT, VT]): # This is a generic subclass of Mapping
- def __getitem__(self, k: KT) -> VT:
- ... # Implementations omitted
- def __iter__(self) -> Iterator[KT]:
- ...
- def __len__(self) -> int:
- ...
+ # This is a generic subclass of Mapping
+ class MyMap(Mapping[KT, VT]):
+ def __getitem__(self, k: KT) -> VT: ...
+ def __iter__(self) -> Iterator[KT]: ...
+ def __len__(self) -> int: ...
- items: MyMap[str, int] # Okay
+ items: MyMap[str, int] # OK
- class StrDict(Dict[str, str]): # This is a non-generic subclass of Dict
+ # This is a non-generic subclass of dict
+ class StrDict(dict[str, str]):
def __str__(self) -> str:
- return 'StrDict({})'.format(super().__str__())
+ return f'StrDict({super().__str__()})'
+
data: StrDict[int, int] # Error! StrDict is not generic
data2: StrDict # OK
+ # This is a user-defined generic class
class Receiver(Generic[T]):
- def accept(self, value: T) -> None:
- ...
+ def accept(self, value: T) -> None: ...
- class AdvancedReceiver(Receiver[T]):
- ...
+ # This is a generic subclass of Receiver
+ class AdvancedReceiver(Receiver[T]): ...
.. note::
@@ -194,15 +147,16 @@ For example:
Generic functions
*****************
-Generic type variables can also be used to define generic functions:
+Type variables can be used to define generic functions:
.. code-block:: python
from typing import TypeVar, Sequence
- T = TypeVar('T') # Declare type variable
+ T = TypeVar('T')
- def first(seq: Sequence[T]) -> T: # Generic function
+ # A generic function!
+ def first(seq: Sequence[T]) -> T:
return seq[0]
As with generic classes, the type variable can be replaced with any
@@ -211,10 +165,8 @@ return type is derived from the sequence item type. For example:
.. code-block:: python
- # Assume first defined as above.
-
- s = first('foo') # s has type str.
- n = first([1, 2, 3]) # n has type int.
+ reveal_type(first([1, 2, 3])) # Revealed type is "builtins.int"
+ reveal_type(first(['a', 'b'])) # Revealed type is "builtins.str"
Note also that a single definition of a type variable (such as ``T``
above) can be used in multiple generic functions or classes. In this
@@ -241,17 +193,11 @@ Generic methods and generic self
********************************
You can also define generic methods — just use a type variable in the
-method signature that is different from class type variables. In particular,
-``self`` may also be generic, allowing a method to return the most precise
-type known at the point of access.
-
-.. note::
-
- This feature is experimental. Checking code with type annotations for self
- arguments is still not fully implemented. Mypy may disallow valid code or
- allow unsafe code.
-
-In this way, for example, you can typecheck chaining of setter methods:
+method signature that is different from class type variables. In
+particular, the ``self`` argument may also be generic, allowing a
+method to return the most precise type known at the point of access.
+In this way, for example, you can type check a chain of setter
+methods:
.. code-block:: python
@@ -274,25 +220,27 @@ In this way, for example, you can typecheck chaining of setter methods:
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
+ circle: Circle = Circle().set_scale(0.5).set_radius(2.7)
+ square: Square = Square().set_scale(0.5).set_width(3.2)
-Without using generic ``self``, the last two lines could not be type-checked properly.
+Without using generic ``self``, the last two lines could not be type
+checked properly, since the return type of ``set_scale`` would be
+``Shape``, which doesn't define ``set_radius`` or ``set_width``.
Other uses are factory methods, such as copy and deserialization.
For class methods, you can also define generic ``cls``, using :py:class:`Type[T] `:
.. code-block:: python
- from typing import TypeVar, Tuple, Type
+ from typing import TypeVar, Type
T = TypeVar('T', bound='Friend')
class Friend:
- other = None # type: Friend
+ other: "Friend" = None
@classmethod
- def make_pair(cls: Type[T]) -> Tuple[T, T]:
+ def make_pair(cls: Type[T]) -> tuple[T, T]:
a, b = cls(), cls()
a.other = b
b.other = a
@@ -310,9 +258,74 @@ In the latter case, you must implement this method in all future subclasses.
Note also that mypy cannot always verify that the implementation of a copy
or a deserialization method returns the actual type of self. Therefore
you may need to silence mypy inside these methods (but not at the call site),
-possibly by making use of the ``Any`` type.
+possibly by making use of the ``Any`` type or a ``# type: ignore`` comment.
+
+Note that mypy lets you use generic self types in certain unsafe ways
+in order to support common idioms. For example, using a generic
+self type in an argument type is accepted even though it's unsafe:
+
+.. code-block:: python
+
+ from typing import TypeVar
+
+ T = TypeVar("T")
-For some advanced uses of self-types see :ref:`additional examples `.
+ class Base:
+ def compare(self: T, other: T) -> bool:
+ return False
+
+ class Sub(Base):
+ def __init__(self, x: int) -> None:
+ self.x = x
+
+ # This is unsafe (see below) but allowed because it's
+ # a common pattern and rarely causes issues in practice.
+ def compare(self, other: Sub) -> bool:
+ return self.x > other.x
+
+ b: Base = Sub(42)
+ b.compare(Base()) # Runtime error here: 'Base' object has no attribute 'x'
+
+For some advanced uses of self types, see :ref:`additional examples `.
+
+Automatic self types using typing.Self
+**************************************
+
+Since the patterns described above are quite common, mypy supports a
+simpler syntax, introduced in :pep:`673`, to make them easier to use.
+Instead of defining a type variable and using an explicit annotation
+for ``self``, you can import the special type ``typing.Self`` that is
+automatically transformed into a type variable with the current class
+as the upper bound, and you don't need an annotation for ``self`` (or
+``cls`` in class methods). The example from the previous section can
+be made simpler by using ``Self``:
+
+.. code-block:: python
+
+ from typing import Self
+
+ class Friend:
+ other: Self | None = None
+
+ @classmethod
+ def make_pair(cls) -> tuple[Self, Self]:
+ a, b = cls(), cls()
+ a.other = b
+ b.other = a
+ return a, b
+
+ class SuperFriend(Friend):
+ pass
+
+ a, b = SuperFriend.make_pair()
+
+This is more compact than using explicit type variables. Also, you can
+use ``Self`` in attribute annotations in addition to methods.
+
+.. note::
+
+ To use this feature on Python versions earlier than 3.11, you will need to
+ import ``Self`` from ``typing_extensions`` (version 4.0 or newer).
.. _variance-of-generics:
@@ -324,51 +337,84 @@ relations between them: invariant, covariant, and contravariant.
Assuming that we have a pair of types ``A`` and ``B``, and ``B`` is
a subtype of ``A``, these are defined as follows:
-* A generic class ``MyCovGen[T, ...]`` is called covariant in type variable
- ``T`` if ``MyCovGen[B, ...]`` is always a subtype of ``MyCovGen[A, ...]``.
-* A generic class ``MyContraGen[T, ...]`` is called contravariant in type
- variable ``T`` if ``MyContraGen[A, ...]`` is always a subtype of
- ``MyContraGen[B, ...]``.
-* A generic class ``MyInvGen[T, ...]`` is called invariant in ``T`` if neither
+* A generic class ``MyCovGen[T]`` is called covariant in type variable
+ ``T`` if ``MyCovGen[B]`` is always a subtype of ``MyCovGen[A]``.
+* A generic class ``MyContraGen[T]`` is called contravariant in type
+ variable ``T`` if ``MyContraGen[A]`` is always a subtype of
+ ``MyContraGen[B]``.
+* A generic class ``MyInvGen[T]`` is called invariant in ``T`` if neither
of the above is true.
Let us illustrate this by few simple examples:
-* :py:data:`~typing.Union` is covariant in all variables: ``Union[Cat, int]`` is a subtype
- of ``Union[Animal, int]``,
- ``Union[Dog, int]`` is also a subtype of ``Union[Animal, int]``, etc.
- Most immutable containers such as :py:class:`~typing.Sequence` and :py:class:`~typing.FrozenSet` are also
- covariant.
-* :py:data:`~typing.Callable` is an example of type that behaves contravariant in types of
- arguments, namely ``Callable[[Employee], int]`` is a subtype of
- ``Callable[[Manager], int]``. To understand this, consider a function:
+.. code-block:: python
+
+ # We'll use these classes in the examples below
+ class Shape: ...
+ class Triangle(Shape): ...
+ class Square(Shape): ...
+
+* Most immutable containers, such as :py:class:`~typing.Sequence` and
+ :py:class:`~typing.FrozenSet` are covariant. :py:data:`~typing.Union` is
+ also covariant in all variables: ``Union[Triangle, int]`` is
+ a subtype of ``Union[Shape, int]``.
.. code-block:: python
- def salaries(staff: List[Manager],
- accountant: Callable[[Manager], int]) -> List[int]: ...
+ def count_lines(shapes: Sequence[Shape]) -> int:
+ return sum(shape.num_sides for shape in shapes)
- This function needs a callable that can calculate a salary for managers, and
- if we give it a callable that can calculate a salary for an arbitrary
- employee, it's still safe.
-* :py:class:`~typing.List` is an invariant generic type. Naively, one would think
- that it is covariant, but let us consider this code:
+ triangles: Sequence[Triangle]
+ count_lines(triangles) # OK
+
+ def foo(triangle: Triangle, num: int):
+ shape_or_number: Union[Shape, int]
+ # a Triangle is a Shape, and a Shape is a valid Union[Shape, int]
+ shape_or_number = triangle
+
+ Covariance should feel relatively intuitive, but contravariance and invariance
+ can be harder to reason about.
+
+* :py:data:`~typing.Callable` is an example of type that behaves contravariant
+ in types of arguments. That is, ``Callable[[Shape], int]`` is a subtype of
+ ``Callable[[Triangle], int]``, despite ``Shape`` being a supertype of
+ ``Triangle``. To understand this, consider:
.. code-block:: python
- class Shape:
- pass
+ def cost_of_paint_required(
+ triangle: Triangle,
+ area_calculator: Callable[[Triangle], float]
+ ) -> float:
+ return area_calculator(triangle) * DOLLAR_PER_SQ_FT
+
+ # This straightforwardly works
+ def area_of_triangle(triangle: Triangle) -> float: ...
+ cost_of_paint_required(triangle, area_of_triangle) # OK
+
+ # But this works as well!
+ def area_of_any_shape(shape: Shape) -> float: ...
+ cost_of_paint_required(triangle, area_of_any_shape) # OK
+
+ ``cost_of_paint_required`` needs a callable that can calculate the area of a
+ triangle. If we give it a callable that can calculate the area of an
+ arbitrary shape (not just triangles), everything still works.
+
+* :py:class:`~typing.List` is an invariant generic type. Naively, one would think
+ that it is covariant, like :py:class:`~typing.Sequence` above, but consider this code:
+
+ .. code-block:: python
class Circle(Shape):
- def rotate(self):
- ...
+ # The rotate method is only defined on Circle, not on Shape
+ def rotate(self): ...
- def add_one(things: List[Shape]) -> None:
+ def add_one(things: list[Shape]) -> None:
things.append(Shape())
- my_things: List[Circle] = []
- add_one(my_things) # This may appear safe, but...
- my_things[0].rotate() # ...this will fail
+ my_circles: list[Circle] = []
+ add_one(my_circles) # This may appear safe, but...
+ my_circles[-1].rotate() # ...this will fail, since my_circles[0] is now a Shape, not a Circle
Another example of invariant type is :py:class:`~typing.Dict`. Most mutable containers
are invariant.
@@ -396,6 +442,45 @@ type variables defined with special keyword arguments ``covariant`` or
my_box = Box(Cat())
look_into(my_box) # OK, but mypy would complain here for an invariant type
+.. _type-variable-upper-bound:
+
+Type variables with upper bounds
+********************************
+
+A type variable can also be restricted to having values that are
+subtypes of a specific type. This type is called the upper bound of
+the type variable, and is specified with the ``bound=...`` keyword
+argument to :py:class:`~typing.TypeVar`.
+
+.. code-block:: python
+
+ from typing import TypeVar, SupportsAbs
+
+ T = TypeVar('T', bound=SupportsAbs[float])
+
+In the definition of a generic function that uses such a type variable
+``T``, the type represented by ``T`` is assumed to be a subtype of
+its upper bound, so the function can use methods of the upper bound on
+values of type ``T``.
+
+.. code-block:: python
+
+ def largest_in_absolute_value(*xs: T) -> T:
+ return max(xs, key=abs) # Okay, because T is a subtype of SupportsAbs[float].
+
+In a call to such a function, the type ``T`` must be replaced by a
+type that is a subtype of its upper bound. Continuing the example
+above:
+
+.. code-block:: python
+
+ largest_in_absolute_value(-3.5, 2) # Okay, has type float.
+ largest_in_absolute_value(5+6j, 7) # Okay, has type complex.
+ largest_in_absolute_value('a', 'b') # Error: 'str' is not a subtype of SupportsAbs[float].
+
+Type parameters of generic classes may also have upper bounds, which
+restrict the valid values for the type parameter in the same way.
+
.. _type-variable-value-restriction:
Type variables with value restriction
@@ -430,7 +515,7 @@ argument types:
concat(b'a', b'b') # Okay
concat(1, 2) # Error!
-Note that this is different from a union type, since combinations
+Importantly, this is different from a union type, since combinations
of ``str`` and ``bytes`` are not accepted:
.. code-block:: python
@@ -438,8 +523,8 @@ of ``str`` and ``bytes`` are not accepted:
concat('string', b'bytes') # Error!
In this case, this is exactly what we want, since it's not possible
-to concatenate a string and a bytes object! The type checker
-will reject this function:
+to concatenate a string and a bytes object! If we tried to use
+``Union``, the type checker would complain about this possibility:
.. code-block:: python
@@ -454,10 +539,13 @@ subtype of ``str``:
class S(str): pass
ss = concat(S('foo'), S('bar'))
+ reveal_type(ss) # Revealed type is "builtins.str"
You may expect that the type of ``ss`` is ``S``, but the type is
actually ``str``: a subtype gets promoted to one of the valid values
-for the type variable, which in this case is ``str``. This is thus
+for the type variable, which in this case is ``str``.
+
+This is thus
subtly different from *bounded quantification* in languages such as
Java, where the return type would be ``S``. The way mypy implements
this is correct for ``concat``, since ``concat`` actually returns a
@@ -473,96 +561,151 @@ values when defining a generic class. For example, mypy uses the type
:py:class:`Pattern[AnyStr] ` for the return value of :py:func:`re.compile`,
since regular expressions can be based on a string or a bytes pattern.
-.. _type-variable-upper-bound:
-
-Type variables with upper bounds
-********************************
-
-A type variable can also be restricted to having values that are
-subtypes of a specific type. This type is called the upper bound of
-the type variable, and is specified with the ``bound=...`` keyword
-argument to :py:class:`~typing.TypeVar`.
+A type variable may not have both a value restriction (see
+:ref:`type-variable-upper-bound`) and an upper bound.
-.. code-block:: python
+.. _declaring-decorators:
- from typing import TypeVar, SupportsAbs
+Declaring decorators
+********************
- T = TypeVar('T', bound=SupportsAbs[float])
+Decorators are typically functions that take a function as an argument and
+return another function. Describing this behaviour in terms of types can
+be a little tricky; we'll show how you can use ``TypeVar`` and a special
+kind of type variable called a *parameter specification* to do so.
-In the definition of a generic function that uses such a type variable
-``T``, the type represented by ``T`` is assumed to be a subtype of
-its upper bound, so the function can use methods of the upper bound on
-values of type ``T``.
+Suppose we have the following decorator, not type annotated yet,
+that preserves the original function's signature and merely prints the decorated function's name:
.. code-block:: python
- def largest_in_absolute_value(*xs: T) -> T:
- return max(xs, key=abs) # Okay, because T is a subtype of SupportsAbs[float].
+ def printing_decorator(func):
+ def wrapper(*args, **kwds):
+ print("Calling", func)
+ return func(*args, **kwds)
+ return wrapper
-In a call to such a function, the type ``T`` must be replaced by a
-type that is a subtype of its upper bound. Continuing the example
-above,
+and we use it to decorate function ``add_forty_two``:
.. code-block:: python
- largest_in_absolute_value(-3.5, 2) # Okay, has type float.
- largest_in_absolute_value(5+6j, 7) # Okay, has type complex.
- largest_in_absolute_value('a', 'b') # Error: 'str' is not a subtype of SupportsAbs[float].
+ # A decorated function.
+ @printing_decorator
+ def add_forty_two(value: int) -> int:
+ return value + 42
-Type parameters of generic classes may also have upper bounds, which
-restrict the valid values for the type parameter in the same way.
+ a = add_forty_two(3)
-A type variable may not have both a value restriction (see
-:ref:`type-variable-value-restriction`) and an upper bound.
+Since ``printing_decorator`` is not type-annotated, the following won't get type checked:
-.. _declaring-decorators:
+.. code-block:: python
-Declaring decorators
-********************
+ reveal_type(a) # Revealed type is "Any"
+ add_forty_two('foo') # No type checker error :(
-One common application of type variable upper bounds is in declaring a
-decorator that preserves the signature of the function it decorates,
-regardless of that signature.
+This is a sorry state of affairs! If you run with ``--strict``, mypy will
+even alert you to this fact:
+``Untyped decorator makes function "add_forty_two" untyped``
Note that class decorators are handled differently than function decorators in
mypy: decorating a class does not erase its type, even if the decorator has
incomplete type annotations.
-Here's a complete example of a function decorator:
+Here's how one could annotate the decorator:
.. code-block:: python
- from typing import Any, Callable, TypeVar, Tuple, cast
+ from typing import Any, Callable, TypeVar, cast
F = TypeVar('F', bound=Callable[..., Any])
# A decorator that preserves the signature.
- def my_decorator(func: F) -> F:
+ def printing_decorator(func: F) -> F:
def wrapper(*args, **kwds):
print("Calling", func)
return func(*args, **kwds)
return cast(F, wrapper)
- # A decorated function.
- @my_decorator
- def foo(a: int) -> str:
- return str(a)
-
- a = foo(12)
- reveal_type(a) # str
- foo('x') # Type check error: incompatible type "str"; expected "int"
+ @printing_decorator
+ def add_forty_two(value: int) -> int:
+ return value + 42
-From the final block we see that the signatures of the decorated
-functions ``foo()`` and ``bar()`` are the same as those of the original
-functions (before the decorator is applied).
+ a = add_forty_two(3)
+ reveal_type(a) # Revealed type is "builtins.int"
+ add_forty_two('x') # Argument 1 to "add_forty_two" has incompatible type "str"; expected "int"
-The bound on ``F`` is used so that calling the decorator on a
-non-function (e.g. ``my_decorator(1)``) will be rejected.
+This still has some shortcomings. First, we need to use the unsafe
+:py:func:`~typing.cast` to convince mypy that ``wrapper()`` has the same
+signature as ``func``. See :ref:`casts `.
-Also note that the ``wrapper()`` function is not type-checked. Wrapper
-functions are typically small enough that this is not a big
+Second, the ``wrapper()`` function is not tightly type checked, although
+wrapper functions are typically small enough that this is not a big
problem. This is also the reason for the :py:func:`~typing.cast` call in the
-``return`` statement in ``my_decorator()``. See :ref:`casts`.
+``return`` statement in ``printing_decorator()``.
+
+However, we can use a parameter specification (:py:class:`~typing.ParamSpec`),
+for a more faithful type annotation:
+
+.. code-block:: python
+
+ from typing import Callable, TypeVar
+ from typing_extensions import ParamSpec
+
+ P = ParamSpec('P')
+ T = TypeVar('T')
+
+ def printing_decorator(func: Callable[P, T]) -> Callable[P, T]:
+ def wrapper(*args: P.args, **kwds: P.kwargs) -> T:
+ print("Calling", func)
+ return func(*args, **kwds)
+ return wrapper
+
+Parameter specifications also allow you to describe decorators that
+alter the signature of the input function:
+
+.. code-block:: python
+
+ from typing import Callable, TypeVar
+ from typing_extensions import ParamSpec
+
+ P = ParamSpec('P')
+ T = TypeVar('T')
+
+ # We reuse 'P' in the return type, but replace 'T' with 'str'
+ def stringify(func: Callable[P, T]) -> Callable[P, str]:
+ def wrapper(*args: P.args, **kwds: P.kwargs) -> str:
+ return str(func(*args, **kwds))
+ return wrapper
+
+ @stringify
+ def add_forty_two(value: int) -> int:
+ return value + 42
+
+ a = add_forty_two(3)
+ reveal_type(a) # Revealed type is "builtins.str"
+ add_forty_two('x') # error: Argument 1 to "add_forty_two" has incompatible type "str"; expected "int"
+
+Or insert an argument:
+
+.. code-block:: python
+
+ from typing import Callable, TypeVar
+ from typing_extensions import Concatenate, ParamSpec
+
+ P = ParamSpec('P')
+ T = TypeVar('T')
+
+ def printing_decorator(func: Callable[P, T]) -> Callable[Concatenate[str, P], T]:
+ def wrapper(msg: str, /, *args: P.args, **kwds: P.kwargs) -> T:
+ print("Calling", func, "with", msg)
+ return func(*args, **kwds)
+ return wrapper
+
+ @printing_decorator
+ def add_forty_two(value: int) -> int:
+ return value + 42
+
+ a = add_forty_two('three', 3)
.. _decorator-factories:
@@ -590,7 +733,7 @@ achieved by combining with :py:func:`@overload `:
.. code-block:: python
- from typing import Any, Callable, TypeVar, overload
+ from typing import Any, Callable, Optional, TypeVar, overload
F = TypeVar('F', bound=Callable[..., Any])
@@ -602,7 +745,7 @@ achieved by combining with :py:func:`@overload `:
def atomic(*, savepoint: bool = True) -> Callable[[F], F]: ...
# Implementation
- def atomic(__func: Callable[..., Any] = None, *, savepoint: bool = True):
+ def atomic(__func: Optional[Callable[..., Any]] = None, *, savepoint: bool = True):
def decorator(func: Callable[..., Any]):
... # Code goes here
if __func is not None:
@@ -652,6 +795,9 @@ protocols mostly follow the normal rules for generic classes. Example:
y: Box[int] = ...
x = y # Error -- Box is invariant
+Note that ``class ClassName(Protocol[T])`` is allowed as a shorthand for
+``class ClassName(Protocol, Generic[T])``, as per :pep:`PEP 544: Generic protocols <544#generic-protocols>`,
+
The main difference between generic protocols and ordinary generic
classes is that mypy checks that the declared variances of generic
type variables in a protocol match how they are used in the protocol
@@ -661,20 +807,18 @@ variable is invariant:
.. code-block:: python
- from typing import TypeVar
- from typing_extensions import Protocol
+ from typing import Protocol, TypeVar
T = TypeVar('T')
- class ReadOnlyBox(Protocol[T]): # Error: covariant type variable expected
+ class ReadOnlyBox(Protocol[T]): # error: Invariant type variable "T" used in protocol where covariant one is expected
def content(self) -> T: ...
This example correctly uses a covariant type variable:
.. code-block:: python
- from typing import TypeVar
- from typing_extensions import Protocol
+ from typing import Protocol, TypeVar
T_co = TypeVar('T_co', covariant=True)
@@ -699,16 +843,12 @@ Generic protocols can also be recursive. Example:
class L:
val: int
+ def next(self) -> 'L': ...
- ... # details omitted
-
- def next(self) -> 'L':
- ... # details omitted
-
- def last(seq: Linked[T]) -> T:
- ... # implementation omitted
+ def last(seq: Linked[T]) -> T: ...
- result = last(L()) # Inferred type of 'result' is 'int'
+ result = last(L())
+ reveal_type(result) # Revealed type is "builtins.int"
.. _generic-type-aliases:
@@ -724,11 +864,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases
.. code-block:: python
- from typing import TypeVar, Iterable, Tuple, Union, Callable
+ from typing import TypeVar, Iterable, Union, Callable
S = TypeVar('S')
- TInt = Tuple[int, S]
+ TInt = tuple[int, S]
UInt = Union[S, int]
CBack = Callable[..., S]
@@ -736,11 +876,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases
...
def activate(cb: CBack[S]) -> S: # Same as Callable[..., S]
...
- table_entry: TInt # Same as Tuple[int, Any]
+ table_entry: TInt # Same as tuple[int, Any]
T = TypeVar('T', int, float, complex)
- Vec = Iterable[Tuple[T, T]]
+ Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T:
return sum(x*y for x, y in v)
@@ -748,8 +888,8 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases
def dilate(v: Vec[T], scale: T) -> Vec[T]:
return ((x * scale, y * scale) for x, y in v)
- v1: Vec[int] = [] # Same as Iterable[Tuple[int, int]]
- v2: Vec = [] # Same as Iterable[Tuple[Any, Any]]
+ v1: Vec[int] = [] # Same as Iterable[tuple[int, int]]
+ v2: Vec = [] # Same as Iterable[tuple[Any, Any]]
v3: Vec[int, int] = [] # Error: Invalid alias, too many type arguments!
Type aliases can be imported from modules just like other names. An
@@ -778,9 +918,60 @@ defeating the purpose of using aliases. Example:
OIntVec = Optional[Vec[int]]
-.. note::
+Using type variable bounds or values in generic aliases has the same effect
+as in generic classes/functions.
+
+
+Generic class internals
+***********************
+
+You may wonder what happens at runtime when you index a generic class.
+Indexing returns a *generic alias* to the original class that returns instances
+of the original class on instantiation:
+
+.. code-block:: python
- A type alias does not define a new type. For generic type aliases
- this means that variance of type variables used for alias definition does not
- apply to aliases. A parameterized generic alias is treated simply as an original
- type with the corresponding type variables substituted.
+ >>> from typing import TypeVar, Generic
+ >>> T = TypeVar('T')
+ >>> class Stack(Generic[T]): ...
+ >>> Stack
+ __main__.Stack
+ >>> Stack[int]
+ __main__.Stack[int]
+ >>> instance = Stack[int]()
+ >>> instance.__class__
+ __main__.Stack
+
+Generic aliases can be instantiated or subclassed, similar to real
+classes, but the above examples illustrate that type variables are
+erased at runtime. Generic ``Stack`` instances are just ordinary
+Python objects, and they have no extra runtime overhead or magic due
+to being generic, other than a metaclass that overloads the indexing
+operator.
+
+Note that in Python 3.8 and lower, the built-in types
+:py:class:`list`, :py:class:`dict` and others do not support indexing.
+This is why we have the aliases :py:class:`~typing.List`,
+:py:class:`~typing.Dict` and so on in the :py:mod:`typing`
+module. Indexing these aliases gives you a generic alias that
+resembles generic aliases constructed by directly indexing the target
+class in more recent versions of Python:
+
+.. code-block:: python
+
+ >>> # Only relevant for Python 3.8 and below
+ >>> # For Python 3.9 onwards, prefer `list[int]` syntax
+ >>> from typing import List
+ >>> List[int]
+ typing.List[int]
+
+Note that the generic aliases in ``typing`` don't support constructing
+instances:
+
+.. code-block:: python
+
+ >>> from typing import List
+ >>> List[int]()
+ Traceback (most recent call last):
+ ...
+ TypeError: Type List cannot be instantiated; use list() instead
diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst
index 12c05c0..9b92709 100644
--- a/docs/source/getting_started.rst
+++ b/docs/source/getting_started.rst
@@ -4,17 +4,19 @@ Getting started
===============
This chapter introduces some core concepts of mypy, including function
-annotations, the :py:mod:`typing` module, library stubs, and more.
+annotations, the :py:mod:`typing` module, stub files, and more.
-Be sure to read this chapter carefully, as the rest of the documentation
+If you're looking for a quick intro, see the
+:ref:`mypy cheatsheet `.
+
+If you're unfamiliar with the concepts of static and dynamic type checking,
+be sure to read this chapter carefully, as the rest of the documentation
may not make much sense otherwise.
Installing and running mypy
***************************
-Mypy requires Python 3.5 or later to run. Once you've
-`installed Python 3 `_,
-install mypy using pip:
+Mypy requires Python 3.7 or later to run. You can install mypy using pip:
.. code-block:: shell
@@ -31,26 +33,21 @@ out any errors it finds. Mypy will type check your code *statically*: this
means that it will check for errors without ever running your code, just
like a linter.
-This means that you are always free to ignore the errors mypy reports and
-treat them as just warnings, if you so wish: mypy runs independently from
-Python itself.
+This also means that you are always free to ignore the errors mypy reports,
+if you so wish. You can always use the Python interpreter to run your code,
+even if mypy reports errors.
However, if you try directly running mypy on your existing Python code, it
-will most likely report little to no errors: you must add *type annotations*
-to your code to take full advantage of mypy. See the section below for details.
-
-.. note::
-
- Although you must install Python 3 to run mypy, mypy is fully capable of
- type checking Python 2 code as well: just pass in the :option:`--py2 ` flag. See
- :ref:`python2` for more details.
+will most likely report little to no errors. This is a feature! It makes it
+easy to adopt mypy incrementally.
- .. code-block:: shell
+In order to get useful diagnostics from mypy, you must add *type annotations*
+to your code. See the section below for details.
- $ mypy --py2 program.py
+.. _getting-started-dynamic-vs-static:
-Function signatures and dynamic vs static typing
-************************************************
+Dynamic vs static typing
+************************
A function without type annotations is considered to be *dynamically typed* by mypy:
@@ -62,22 +59,32 @@ A function without type annotations is considered to be *dynamically typed* by m
By default, mypy will **not** type check dynamically typed functions. This means
that with a few exceptions, mypy will not report any errors with regular unannotated Python.
-This is the case even if you misuse the function: for example, mypy would currently
-not report any errors if you tried running ``greeting(3)`` or ``greeting(b"Alice")``
-even though those function calls would result in errors at runtime.
+This is the case even if you misuse the function!
+
+.. code-block:: python
+
+ def greeting(name):
+ return 'Hello ' + name
-You can teach mypy to detect these kinds of bugs by adding *type annotations* (also
-known as *type hints*). For example, you can teach mypy that ``greeting`` both accepts
+ # These calls will fail when the program run, but mypy does not report an error
+ # because "greeting" does not have type annotations.
+ greeting(123)
+ greeting(b"Alice")
+
+We can get mypy to detect these kinds of bugs by adding *type annotations* (also
+known as *type hints*). For example, you can tell mypy that ``greeting`` both accepts
and returns a string like so:
.. code-block:: python
+ # The "name: str" annotation says that the "name" argument should be a string
+ # The "-> str" annotation says that "greeting" will return a string
def greeting(name: str) -> str:
return 'Hello ' + name
-This function is now *statically typed*: mypy can use the provided type hints to detect
-incorrect usages of the ``greeting`` function. For example, it will reject the following
-calls since the arguments have invalid types:
+This function is now *statically typed*: mypy will use the provided type hints
+to detect incorrect use of the ``greeting`` function and incorrect use of
+variables within the ``greeting`` function. For example:
.. code-block:: python
@@ -86,13 +93,10 @@ calls since the arguments have invalid types:
greeting(3) # Argument 1 to "greeting" has incompatible type "int"; expected "str"
greeting(b'Alice') # Argument 1 to "greeting" has incompatible type "bytes"; expected "str"
+ greeting("World!") # No error
-Note that this is all still valid Python 3 code! The function annotation syntax
-shown above was added to Python :pep:`as a part of Python 3.0 <3107>`.
-
-If you are trying to type check Python 2 code, you can add type hints
-using a comment-based syntax instead of the Python 3 annotation syntax.
-See our section on :ref:`typing Python 2 code ` for more details.
+ def bad_greeting(name: str) -> str:
+ return 'Hello ' * name # Unsupported operand types for * ("str" and "str")
Being able to pick whether you want a function to be dynamically or statically
typed can be very helpful. For example, if you are migrating an existing
@@ -103,65 +107,35 @@ the code using dynamic typing and only add type hints later once the code is mor
Once you are finished migrating or prototyping your code, you can make mypy warn you
if you add a dynamic function by mistake by using the :option:`--disallow-untyped-defs `
-flag. See :ref:`command-line` for more information on configuring mypy.
+flag. You can also get mypy to provide some limited checking of dynamically typed
+functions by using the :option:`--check-untyped-defs ` flag.
+See :ref:`command-line` for more information on configuring mypy.
-.. note::
-
- The earlier stages of analysis performed by mypy may report errors
- even for dynamically typed functions. However, you should not rely
- on this, as this may change in the future.
+Strict mode and configuration
+*****************************
-More function signatures
-************************
+Mypy has a *strict mode* that enables a number of additional checks,
+like :option:`--disallow-untyped-defs `.
-Here are a few more examples of adding type hints to function signatures.
+If you run mypy with the :option:`--strict ` flag, you
+will basically never get a type related error at runtime without a corresponding
+mypy error, unless you explicitly circumvent mypy somehow.
-If a function does not explicitly return a value, give it a return
-type of ``None``. Using a ``None`` result in a statically typed
-context results in a type check error:
+However, this flag will probably be too aggressive if you are trying
+to add static types to a large, existing codebase. See :ref:`existing-code`
+for suggestions on how to handle that case.
-.. code-block:: python
+Mypy is very configurable, so you can start with using ``--strict``
+and toggle off individual checks. For instance, if you use many third
+party libraries that do not have types,
+:option:`--ignore-missing-imports `
+may be useful. See :ref:`getting-to-strict` for how to build up to ``--strict``.
- def p() -> None:
- print('hello')
+See :ref:`command-line` and :ref:`config-file` for a complete reference on
+configuration options.
- a = p() # Error: "p" does not return a value
-
-Make sure to remember to include ``None``: if you don't, the function
-will be dynamically typed. For example:
-
-.. code-block:: python
-
- def f():
- 1 + 'x' # No static type error (dynamically typed)
-
- def g() -> None:
- 1 + 'x' # Type check error (statically typed)
-
-Arguments with default values can be annotated like so:
-
-.. code-block:: python
-
- def greeting(name: str, excited: bool = False) -> str:
- message = 'Hello, {}'.format(name)
- if excited:
- message += '!!!'
- return message
-
-``*args`` and ``**kwargs`` arguments can be annotated like so:
-
-.. code-block:: python
-
- def stars(*args: int, **kwargs: float) -> None:
- # 'args' has type 'Tuple[int, ...]' (a tuple of ints)
- # 'kwargs' has type 'Dict[str, float]' (a dict of strs to floats)
- for arg in args:
- print(arg)
- for key, value in kwargs:
- print(key, value)
-
-Additional types, and the typing module
-***************************************
+More complex types
+******************
So far, we've added type hints that use only basic concrete types like
``str`` and ``float``. What if we want to express more complex types,
@@ -182,34 +156,16 @@ strings, use the ``list[str]`` type (Python 3.9 and later):
greet_all(names) # Ok!
greet_all(ages) # Error due to incompatible types
-The ``list`` type is an example of something called a *generic type*: it can
-accept one or more *type parameters*. In this case, we *parameterized* ``list``
+The :py:class:`list` type is an example of something called a *generic type*: it can
+accept one or more *type parameters*. In this case, we *parameterized* :py:class:`list`
by writing ``list[str]``. This lets mypy know that ``greet_all`` accepts specifically
lists containing strings, and not lists containing ints or any other type.
-In Python 3.8 and earlier, you can instead import the
-:py:class:`~typing.List` type from the :py:mod:`typing` module:
-
-.. code-block:: python
-
- from typing import List # Python 3.8 and earlier
-
- def greet_all(names: List[str]) -> None:
- for name in names:
- print('Hello ' + name)
-
- ...
-
-You can find many of these more complex static types in the :py:mod:`typing` module.
-
In the above examples, the type signature is perhaps a little too rigid.
After all, there's no reason why this function must accept *specifically* a list --
it would run just fine if you were to pass in a tuple, a set, or any other custom iterable.
-You can express this idea using the
-:py:class:`collections.abc.Iterable` type instead of
-:py:class:`~typing.List` (or :py:class:`typing.Iterable` in Python
-3.8 and earlier):
+You can express this idea using :py:class:`collections.abc.Iterable`:
.. code-block:: python
@@ -219,8 +175,19 @@ You can express this idea using the
for name in names:
print('Hello ' + name)
+This behavior is actually a fundamental aspect of the PEP 484 type system: when
+we annotate some variable with a type ``T``, we are actually telling mypy that
+variable can be assigned an instance of ``T``, or an instance of a *subtype* of ``T``.
+That is, ``list[str]`` is a subtype of ``Iterable[str]``.
+
+This also applies to inheritance, so if you have a class ``Child`` that inherits from
+``Parent``, then a value of type ``Child`` can be assigned to a variable of type ``Parent``.
+For example, a ``RuntimeError`` instance can be passed to a function that is annotated
+as taking an ``Exception``.
+
As another example, suppose you want to write a function that can accept *either*
-ints or strings, but no other types. You can express this using the :py:data:`~typing.Union` type:
+ints or strings, but no other types. You can express this using the
+:py:data:`~typing.Union` type. For example, ``int`` is a subtype of ``Union[int, str]``:
.. code-block:: python
@@ -228,30 +195,16 @@ ints or strings, but no other types. You can express this using the :py:data:`~t
def normalize_id(user_id: Union[int, str]) -> str:
if isinstance(user_id, int):
- return 'user-{}'.format(100000 + user_id)
+ return f'user-{100_000 + user_id}'
else:
return user_id
-Similarly, suppose that you want the function to accept only strings or ``None``. You can
-again use :py:data:`~typing.Union` and use ``Union[str, None]`` -- or alternatively, use the type
-``Optional[str]``. These two types are identical and interchangeable: ``Optional[str]``
-is just a shorthand or *alias* for ``Union[str, None]``. It exists mostly as a convenience
-to help function signatures look a little cleaner:
-
-.. code-block:: python
-
- from typing import Optional
+The :py:mod:`typing` module contains many other useful types.
- def greeting(name: Optional[str] = None) -> str:
- # Optional[str] means the same thing as Union[str, None]
- if name is None:
- name = 'stranger'
- return 'Hello, ' + name
+For a quick overview, look through the :ref:`mypy cheatsheet `.
-The :py:mod:`typing` module contains many other useful types. You can find a
-quick overview by looking through the :ref:`mypy cheatsheets `
-and a more detailed overview (including information on how to make your own
-generic types or your own type aliases) by looking through the
+For a detailed overview (including information on how to make your own
+generic types or your own type aliases), look through the
:ref:`type system reference `.
.. note::
@@ -268,7 +221,7 @@ generic types or your own type aliases) by looking through the
In some examples we use capitalized variants of types, such as
``List``, and sometimes we use plain ``list``. They are equivalent,
- but the prior variant is needed if you are not using a recent Python.
+ but the prior variant is needed if you are using Python 3.8 or earlier.
Local type inference
********************
@@ -279,14 +232,11 @@ mypy will try and *infer* as many details as possible.
We saw an example of this in the ``normalize_id`` function above -- mypy understands
basic :py:func:`isinstance ` checks and so can infer that the ``user_id`` variable was of
-type ``int`` in the if-branch and of type ``str`` in the else-branch. Similarly, mypy
-was able to understand that ``name`` could not possibly be ``None`` in the ``greeting``
-function above, based both on the ``name is None`` check and the variable assignment
-in that if statement.
+type ``int`` in the if-branch and of type ``str`` in the else-branch.
As another example, consider the following function. Mypy can type check this function
without a problem: it will use the available context and deduce that ``output`` must be
-of type ``List[float]`` and that ``num`` must be of type ``float``:
+of type ``list[float]`` and that ``num`` must be of type ``float``:
.. code-block:: python
@@ -297,110 +247,60 @@ of type ``List[float]`` and that ``num`` must be of type ``float``:
output.append(num)
return output
-Mypy will warn you if it is unable to determine the type of some variable --
-for example, when assigning an empty dictionary to some global value:
-
-.. code-block:: python
-
- my_global_dict = {} # Error: Need type annotation for "my_global_dict"
+For more details, see :ref:`type-inference-and-annotations`.
-You can teach mypy what type ``my_global_dict`` is meant to have by giving it
-a type hint. For example, if you knew this variable is supposed to be a dict
-of ints to floats, you could annotate it using either variable annotations
-(introduced in Python 3.6 by :pep:`526`) or using a comment-based
-syntax like so:
-
-.. code-block:: python
-
- # If you're using Python 3.9+
- my_global_dict: dict[int, float] = {}
-
- # If you're using Python 3.6+
- my_global_dict: Dict[int, float] = {}
-
- # If you want compatibility with even older versions of Python
- my_global_dict = {} # type: Dict[int, float]
-
-.. _stubs-intro:
-
-Library stubs and typeshed
-**************************
+Types from libraries
+********************
-Mypy uses library *stubs* to type check code interacting with library
-modules, including the Python standard library. A library stub defines
-a skeleton of the public interface of the library, including classes,
-variables and functions, and their types. Mypy ships with stubs for
-the standard library from the `typeshed
-`_ project, which contains library
-stubs for the Python builtins, the standard library, and selected
-third-party packages.
+Mypy can also understand how to work with types from libraries that you use.
-For example, consider this code:
+For instance, mypy comes out of the box with an intimate knowledge of the
+Python standard library. For example, here is a function which uses the
+``Path`` object from the
+`pathlib standard library module `_:
.. code-block:: python
- x = chr(4)
+ from pathlib import Path
-Without a library stub, mypy would have no way of inferring the type of ``x``
-and checking that the argument to :py:func:`chr` has a valid type.
+ def load_template(template_path: Path, name: str) -> str:
+ # Mypy knows that `file_path` has a `read_text` method that returns a str
+ template = template_path.read_text()
+ # ...so it understands this line type checks
+ return template.replace('USERNAME', name)
-Mypy complains if it can't find a stub (or a real module) for a
-library module that you import. Some modules ship with stubs or inline
-annotations that mypy can automatically find, or you can install
-additional stubs using pip (see :ref:`fix-missing-imports` and
-:ref:`installed-packages` for the details). For example, you can install
-the stubs for the ``requests`` package like this:
+If a third party library you use :ref:`declares support for type checking `,
+mypy will type check your use of that library based on the type hints
+it contains.
-.. code-block::
-
- python3 -m pip install types-requests
-
-The stubs are usually packaged in a distribution named
-``types-``. Note that the distribution name may be
-different from the name of the package that you import. For example,
-``types-PyYAML`` contains stubs for the ``yaml`` package. Mypy can
-often suggest the name of the stub distribution:
+However, if the third party library does not have type hints, mypy will
+complain about missing type information.
.. code-block:: text
- prog.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8)
+ prog.py:1: error: Library stubs not installed for "yaml"
prog.py:1: note: Hint: "python3 -m pip install types-PyYAML"
+ prog.py:2: error: Library stubs not installed for "requests"
+ prog.py:2: note: Hint: "python3 -m pip install types-requests"
...
-.. note::
-
- Starting in mypy 0.900, most third-party package stubs must be
- installed explicitly. This decouples mypy and stub versioning,
- allowing stubs to updated without updating mypy. This also allows
- stubs not originally included with mypy to be installed. Earlier
- mypy versions included a fixed set of stubs for third-party
- packages.
+In this case, you can provide mypy a different source of type information,
+by installing a *stub* package. A stub package is a package that contains
+type hints for another library, but no actual code.
-You can also :ref:`create
-stubs ` easily. We discuss ways of silencing complaints
-about missing stubs in :ref:`ignore-missing-imports`.
-
-Configuring mypy
-****************
+.. code-block:: shell
-Mypy supports many command line options that you can use to tweak how
-mypy behaves: see :ref:`command-line` for more details.
+ $ python3 -m pip install types-PyYAML types-requests
-For example, suppose you want to make sure *all* functions within your
-codebase are using static typing and make mypy report an error if you
-add a dynamically-typed function by mistake. You can make mypy do this
-by running mypy with the :option:`--disallow-untyped-defs ` flag.
+Stubs packages for a distribution are often named ``types-``.
+Note that a distribution name may be different from the name of the package that
+you import. For example, ``types-PyYAML`` contains stubs for the ``yaml``
+package.
-Another potentially useful flag is :option:`--strict `, which enables many
-(though not all) of the available strictness options -- including
-:option:`--disallow-untyped-defs `.
+For more discussion on strategies for handling errors about libraries without
+type information, refer to :ref:`fix-missing-imports`.
-This flag is mostly useful if you're starting a new project from scratch
-and want to maintain a high degree of type safety from day one. However,
-this flag will probably be too aggressive if you either plan on using
-many untyped third party libraries or are trying to add static types to
-a large, existing codebase. See :ref:`existing-code` for more suggestions
-on how to handle the latter case.
+For more information about stubs, see :ref:`stub-files`.
Next steps
**********
@@ -409,8 +309,7 @@ If you are in a hurry and don't want to read lots of documentation
before getting started, here are some pointers to quick learning
resources:
-* Read the :ref:`mypy cheatsheet ` (also for
- :ref:`Python 2 `).
+* Read the :ref:`mypy cheatsheet `.
* Read :ref:`existing-code` if you have a significant existing
codebase without many type annotations.
@@ -436,5 +335,8 @@ resources:
`mypy issue tracker `_ and
typing `Gitter chat `_.
+* For general questions about Python typing, try posting at
+ `typing discussions `_.
+
You can also continue reading this document and skip sections that
aren't relevant for you. You don't need to read sections in order.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index c9ee1ce..7ab3ede 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -6,24 +6,54 @@
Welcome to mypy documentation!
==============================
-Mypy is a static type checker for Python 3 and Python 2.7.
+Mypy is a static type checker for Python.
-.. toctree::
- :maxdepth: 2
- :caption: First steps
+Type checkers help ensure that you're using variables and functions in your code
+correctly. With mypy, add type hints (:pep:`484`)
+to your Python programs, and mypy will warn you when you use those types
+incorrectly.
- introduction
- getting_started
- existing_code
+Python is a dynamic language, so usually you'll only see errors in your code
+when you attempt to run it. Mypy is a *static* checker, so it finds bugs
+in your programs without even running them!
+
+Here is a small example to whet your appetite:
+
+.. code-block:: python
+
+ number = input("What is your favourite number?")
+ print("It is", number + 1) # error: Unsupported operand types for + ("str" and "int")
+
+Adding type hints for mypy does not interfere with the way your program would
+otherwise run. Think of type hints as similar to comments! You can always use
+the Python interpreter to run your code, even if mypy reports errors.
+
+Mypy is designed with gradual typing in mind. This means you can add type
+hints to your code base slowly and that you can always fall back to dynamic
+typing when static typing is not convenient.
-.. _overview-cheat-sheets:
+Mypy has a powerful and easy-to-use type system, supporting features such as
+type inference, generics, callable types, tuple types, union types,
+structural subtyping and more. Using mypy will make your programs easier to
+understand, debug, and maintain.
+
+.. note::
+
+ Although mypy is production ready, there may be occasional changes
+ that break backward compatibility. The mypy development team tries to
+ minimize the impact of changes to user code. In case of a major breaking
+ change, mypy's major version will be bumped.
+
+Contents
+--------
.. toctree::
:maxdepth: 2
- :caption: Cheat sheets
+ :caption: First steps
+ getting_started
cheat_sheet_py3
- cheat_sheet
+ existing_code
.. _overview-type-system-reference:
@@ -38,13 +68,13 @@ Mypy is a static type checker for Python 3 and Python 2.7.
runtime_troubles
protocols
dynamic_typing
- python2
- casts
+ type_narrowing
duck_type_compatibility
stubs
generics
more_types
literal_types
+ typed_dict
final_attrs
metaclasses
@@ -60,6 +90,7 @@ Mypy is a static type checker for Python 3 and Python 2.7.
installed_packages
extending_mypy
stubgen
+ stubtest
.. toctree::
:maxdepth: 2
@@ -73,6 +104,13 @@ Mypy is a static type checker for Python 3 and Python 2.7.
additional_features
faq
+.. toctree::
+ :hidden:
+ :caption: Project Links
+
+ GitHub
+ Website
+
Indices and tables
==================
diff --git a/docs/source/installed_packages.rst b/docs/source/installed_packages.rst
index d640f5d..b9a3b89 100644
--- a/docs/source/installed_packages.rst
+++ b/docs/source/installed_packages.rst
@@ -25,6 +25,23 @@ you can create such packages.
:pep:`561` specifies how a package can declare that it supports
type checking.
+.. note::
+
+ New versions of stub packages often use type system features not
+ supported by older, and even fairly recent mypy versions. If you
+ pin to an older version of mypy (using ``requirements.txt``, for
+ example), it is recommended that you also pin the versions of all
+ your stub package dependencies.
+
+.. note::
+
+ Starting in mypy 0.900, most third-party package stubs must be
+ installed explicitly. This decouples mypy and stub versioning,
+ allowing stubs to updated without updating mypy. This also allows
+ stubs not originally included with mypy to be installed. Earlier
+ mypy versions included a fixed set of stubs for third-party
+ packages.
+
Using installed packages with mypy (PEP 561)
********************************************
@@ -40,10 +57,10 @@ stubs.)
If you have installed typed packages in another Python installation or
environment, mypy won't automatically find them. One option is to
install another copy of those packages in the environment in which you
-use to run mypy. Alternatively, you can use the
+installed mypy. Alternatively, you can use the
:option:`--python-executable ` flag to point
-to the target Python executable, and mypy will find packages installed
-for that Python executable.
+to the Python executable for another environment, and mypy will find
+packages installed for that Python executable.
Note that mypy does not support some more advanced import features,
such as zip imports and custom import hooks.
@@ -173,7 +190,12 @@ The ``setup.py`` might look like this:
packages=["package_c-stubs"]
)
-If you have separate stubs for Python 2 and Python 3, you can place
-the Python 2 stubs in a directory with the suffix ``-python2-stubs``.
-We recommend that Python 2 and Python 3 stubs are bundled together for
-simplicity, instead of distributing them separately.
+The instructions above are enough to ensure that the built wheels
+contain the appropriate files. However, to ensure inclusion inside the
+``sdist`` (``.tar.gz`` archive), you may also need to modify the
+inclusion rules in your ``MANIFEST.in``:
+
+.. code-block:: text
+
+ global-include *.pyi
+ global-include *.typed
diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst
deleted file mode 100644
index 16ed5a3..0000000
--- a/docs/source/introduction.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-Introduction
-============
-
-Mypy is a static type checker for Python 3 and Python 2.7. If you sprinkle
-your code with type annotations, mypy can type check your code and find common
-bugs. As mypy is a static analyzer, or a lint-like tool, the type
-annotations are just hints for mypy and don't interfere when running your program.
-You run your program with a standard Python interpreter, and the annotations
-are treated effectively as comments.
-
-Using the Python 3 annotation syntax (using :pep:`484` and :pep:`526` notation)
-or a comment-based annotation syntax for Python 2 code, you will be able to
-efficiently annotate your code and use mypy to check the code for common errors.
-Mypy has a powerful and easy-to-use type system with modern features such as
-type inference, generics, callable types, tuple types, union types, and
-structural subtyping.
-
-As a developer, you decide how to use mypy in your workflow. You can always
-escape to dynamic typing as mypy's approach to static typing doesn't restrict
-what you can do in your programs. Using mypy will make your programs easier to
-understand, debug, and maintain.
-
-This documentation provides a short introduction to mypy. It will help you
-get started writing statically typed code. Knowledge of Python and a
-statically typed object-oriented language, such as Java, are assumed.
-
-.. note::
-
- Mypy is used in production by many companies and projects, but mypy is
- officially beta software. There will be occasional changes
- that break backward compatibility. The mypy development team tries to
- minimize the impact of changes to user code.
diff --git a/docs/source/kinds_of_types.rst b/docs/source/kinds_of_types.rst
index 1efc2b3..b575a6e 100644
--- a/docs/source/kinds_of_types.rst
+++ b/docs/source/kinds_of_types.rst
@@ -108,23 +108,24 @@ The ``Any`` type is discussed in more detail in section :ref:`dynamic-typing`.
Tuple types
***********
-The type ``Tuple[T1, ..., Tn]`` represents a tuple with the item types ``T1``, ..., ``Tn``:
+The type ``tuple[T1, ..., Tn]`` represents a tuple with the item types ``T1``, ..., ``Tn``:
.. code-block:: python
- def f(t: Tuple[int, str]) -> None:
+ # Use `typing.Tuple` in Python 3.8 and earlier
+ def f(t: tuple[int, str]) -> None:
t = 1, 'foo' # OK
t = 'foo', 1 # Type check error
A tuple type of this kind has exactly a specific number of items (2 in
the above example). Tuples can also be used as immutable,
-varying-length sequences. You can use the type ``Tuple[T, ...]`` (with
+varying-length sequences. You can use the type ``tuple[T, ...]`` (with
a literal ``...`` -- it's part of the syntax) for this
purpose. Example:
.. code-block:: python
- def print_squared(t: Tuple[int, ...]) -> None:
+ def print_squared(t: tuple[int, ...]) -> None:
for n in t:
print(n, n ** 2)
@@ -134,12 +135,12 @@ purpose. Example:
.. note::
- Usually it's a better idea to use ``Sequence[T]`` instead of ``Tuple[T, ...]``, as
+ Usually it's a better idea to use ``Sequence[T]`` instead of ``tuple[T, ...]``, as
:py:class:`~typing.Sequence` is also compatible with lists and other non-tuple sequences.
.. note::
- ``Tuple[...]`` is valid as a base class in Python 3.6 and later, and
+ ``tuple[...]`` is valid as a base class in Python 3.6 and later, and
always in stub files. In earlier Python versions you can sometimes work around this
limitation by using a named tuple as a base class (see section :ref:`named-tuples`).
@@ -194,7 +195,7 @@ using bidirectional type inference:
.. code-block:: python
- l = map(lambda x: x + 1, [1, 2, 3]) # Infer x as int and l as List[int]
+ l = map(lambda x: x + 1, [1, 2, 3]) # Infer x as int and l as list[int]
If you want to give the argument or return value types explicitly, use
an ordinary, perhaps nested function definition.
@@ -346,27 +347,13 @@ This also works for attributes defined within methods:
def __init__(self) -> None:
self.count: Optional[int] = None
-As a special case, you can use a non-optional type when initializing an
-attribute to ``None`` inside a class body *and* using a type comment,
-since when using a type comment, an initializer is syntactically required,
-and ``None`` is used as a dummy, placeholder initializer:
+This is not a problem when using variable annotations, since no initial
+value is needed:
.. code-block:: python
- from typing import List
-
- class Container:
- items = None # type: List[str] # OK (only with type comment)
-
-This is not a problem when using variable annotations, since no initializer
-is needed:
-
-.. code-block:: python
-
- from typing import List
-
class Container:
- items: List[str] # No initializer
+ items: list[str] # No initial value
Mypy generally uses the first assignment to a variable to
infer the type of the variable. However, if you assign both a ``None``
@@ -394,18 +381,15 @@ case you should add an explicit ``Optional[...]`` annotation (or type comment).
The Python interpreter internally uses the name ``NoneType`` for
the type of ``None``, but ``None`` is always used in type
- annotations. The latter is shorter and reads better. (Besides,
- ``NoneType`` is not even defined in the standard library.)
+ annotations. The latter is shorter and reads better. (``NoneType``
+ is available as :py:data:`types.NoneType` on Python 3.10+, but is
+ not exposed at all on earlier versions of Python.)
.. note::
``Optional[...]`` *does not* mean a function argument with a default value.
- However, if the default value of an argument is ``None``, you can use
- an optional type for the argument, but it's not enforced by default.
- You can use the :option:`--no-implicit-optional ` command-line option to stop
- treating arguments with a ``None`` default value as having an implicit
- ``Optional[...]`` type. It's possible that this will become the default
- behavior in the future.
+ It simply means that ``None`` is a valid value for the argument. This is
+ a common confusion because ``None`` is a common default value for arguments.
.. _alternative_union_syntax:
@@ -419,15 +403,10 @@ the runtime with some limitations (see :ref:`runtime_troubles`).
.. code-block:: python
- from typing import List
-
t1: int | str # equivalent to Union[int, str]
t2: int | None # equivalent to Optional[int]
- # Usable in type comments
- t3 = 42 # type: int | str
-
.. _no_strict_optional:
Disabling strict optional checking
@@ -469,7 +448,7 @@ but it's not obvious from its signature:
def greeting(name: str) -> str:
if name:
- return 'Hello, {}'.format(name)
+ return f'Hello, {name}'
else:
return 'Hello, stranger'
@@ -486,7 +465,7 @@ enabled:
def greeting(name: Optional[str]) -> str:
if name:
- return 'Hello, {}'.format(name)
+ return f'Hello, {name}'
else:
return 'Hello, stranger'
@@ -505,7 +484,7 @@ In certain situations, type names may end up being long and painful to type:
.. code-block:: python
- def f() -> Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]:
+ def f() -> Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]]:
...
When cases like this arise, you can define a type alias by simply
@@ -513,7 +492,7 @@ assigning the type to a variable:
.. code-block:: python
- AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
+ AliasType = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]]
# Now we can use AliasType in place of the full name:
@@ -526,6 +505,25 @@ assigning the type to a variable:
another type -- it's equivalent to the target type except for
:ref:`generic aliases `.
+Since Mypy 0.930 you can also use *explicit type aliases*, which were
+introduced in :pep:`613`.
+
+There can be confusion about exactly when an assignment defines an implicit type alias --
+for example, when the alias contains forward references, invalid types, or violates some other
+restrictions on type alias declarations. Because the
+distinction between an unannotated variable and a type alias is implicit,
+ambiguous or incorrect type alias declarations default to defining
+a normal variable instead of a type alias.
+
+Explicit type aliases are unambiguous and can also improve readability by
+making the intent clear:
+
+.. code-block:: python
+
+ from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier
+
+ AliasType: TypeAlias = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]]
+
.. _named-tuples:
Named tuples
@@ -566,6 +564,31 @@ Python 3.6 introduced an alternative, class-based syntax for named tuples with t
p = Point(x=1, y='x') # Argument has incompatible type "str"; expected "int"
+.. note::
+
+ You can use the raw ``NamedTuple`` "pseudo-class" in type annotations
+ if any ``NamedTuple`` object is valid.
+
+ For example, it can be useful for deserialization:
+
+ .. code-block:: python
+
+ def deserialize_named_tuple(arg: NamedTuple) -> Dict[str, Any]:
+ return arg._asdict()
+
+ Point = namedtuple('Point', ['x', 'y'])
+ Person = NamedTuple('Person', [('name', str), ('age', int)])
+
+ deserialize_named_tuple(Point(x=1, y=2)) # ok
+ deserialize_named_tuple(Person(name='Nikita', age=18)) # ok
+
+ # Error: Argument 1 to "deserialize_named_tuple" has incompatible type
+ # "Tuple[int, int]"; expected "NamedTuple"
+ deserialize_named_tuple((1, 2))
+
+ Note that this behavior is highly experimental, non-standard,
+ and may not be supported by other type checkers and IDEs.
+
.. _type-of-class:
The type of class objects
@@ -575,10 +598,11 @@ The type of class objects
<484#the-type-of-class-objects>`.)
Sometimes you want to talk about class objects that inherit from a
-given class. This can be spelled as :py:class:`Type[C] ` where ``C`` is a
+given class. This can be spelled as ``type[C]`` (or, on Python 3.8 and lower,
+:py:class:`typing.Type[C] `) where ``C`` is a
class. In other words, when ``C`` is the name of a class, using ``C``
to annotate an argument declares that the argument is an instance of
-``C`` (or of a subclass of ``C``), but using :py:class:`Type[C] ` as an
+``C`` (or of a subclass of ``C``), but using ``type[C]`` as an
argument annotation declares that the argument is a class object
deriving from ``C`` (or ``C`` itself).
@@ -609,7 +633,7 @@ you pass it the right class object:
# (Here we could write the user object to a database)
return user
-How would we annotate this function? Without :py:class:`~typing.Type` the best we
+How would we annotate this function? Without the ability to parameterize ``type``, the best we
could do would be:
.. code-block:: python
@@ -625,14 +649,14 @@ doesn't see that the ``buyer`` variable has type ``ProUser``:
buyer = new_user(ProUser)
buyer.pay() # Rejected, not a method on User
-However, using :py:class:`~typing.Type` and a type variable with an upper bound (see
+However, using the ``type[C]`` syntax and a type variable with an upper bound (see
:ref:`type-variable-upper-bound`) we can do better:
.. code-block:: python
U = TypeVar('U', bound=User)
- def new_user(user_class: Type[U]) -> U:
+ def new_user(user_class: type[U]) -> U:
# Same implementation as before
Now mypy will infer the correct type of the result when we call
@@ -645,64 +669,20 @@ Now mypy will infer the correct type of the result when we call
.. note::
- The value corresponding to :py:class:`Type[C] ` must be an actual class
+ The value corresponding to ``type[C]`` must be an actual class
object that's a subtype of ``C``. Its constructor must be
compatible with the constructor of ``C``. If ``C`` is a type
variable, its upper bound must be a class object.
-For more details about ``Type[]`` see :pep:`PEP 484: The type of
+For more details about ``type[]`` and :py:class:`typing.Type[] `, see :pep:`PEP 484: The type of
class objects <484#the-type-of-class-objects>`.
-.. _text-and-anystr:
-
-Text and AnyStr
-***************
-
-Sometimes you may want to write a function which will accept only unicode
-strings. This can be challenging to do in a codebase intended to run in
-both Python 2 and Python 3 since ``str`` means something different in both
-versions and ``unicode`` is not a keyword in Python 3.
-
-To help solve this issue, use :py:class:`~typing.Text` which is aliased to
-``unicode`` in Python 2 and to ``str`` in Python 3. This allows you to
-indicate that a function should accept only unicode strings in a
-cross-compatible way:
-
-.. code-block:: python
-
- from typing import Text
-
- def unicode_only(s: Text) -> Text:
- return s + u'\u2713'
-
-In other cases, you may want to write a function that will work with any
-kind of string but will not let you mix two different string types. To do
-so use :py:data:`~typing.AnyStr`:
-
-.. code-block:: python
-
- from typing import AnyStr
-
- def concat(x: AnyStr, y: AnyStr) -> AnyStr:
- return x + y
-
- concat('foo', 'foo') # Okay
- concat(b'foo', b'foo') # Okay
- concat('foo', b'foo') # Error: cannot mix bytes and unicode
-
-For more details, see :ref:`type-variable-value-restriction`.
-
-.. note::
-
- How ``bytes``, ``str``, and ``unicode`` are handled between Python 2 and
- Python 3 may change in future versions of mypy.
-
.. _generators:
Generators
**********
-A basic generator that only yields values can be annotated as having a return
+A basic generator that only yields values can be succinctly annotated as having a return
type of either :py:class:`Iterator[YieldType] ` or :py:class:`Iterable[YieldType] `. For example:
.. code-block:: python
@@ -711,9 +691,20 @@ type of either :py:class:`Iterator[YieldType] ` or :py:class:`I
for i in range(n):
yield i * i
+A good rule of thumb is to annotate functions with the most specific return
+type possible. However, you should also take care to avoid leaking implementation
+details into a function's public API. In keeping with these two principles, prefer
+:py:class:`Iterator[YieldType] ` over
+:py:class:`Iterable[YieldType] ` as the return-type annotation for a
+generator function, as it lets mypy know that users are able to call :py:func:`next` on
+the object returned by the function. Nonetheless, bear in mind that ``Iterable`` may
+sometimes be the better option, if you consider it an implementation detail that
+``next()`` can be called on the object returned by your function.
+
If you want your generator to accept values via the :py:meth:`~generator.send` method or return
-a value, you should use the
-:py:class:`Generator[YieldType, SendType, ReturnType] ` generic type instead. For example:
+a value, on the other hand, you should use the
+:py:class:`Generator[YieldType, SendType, ReturnType] ` generic type instead of
+either ``Iterator`` or ``Iterable``. For example:
.. code-block:: python
@@ -736,7 +727,7 @@ annotated the first example as the following:
for i in range(n):
yield i * i
-This is slightly different from using ``Iterable[int]`` or ``Iterator[int]``,
+This is slightly different from using ``Iterator[int]`` or ``Iterable[int]``,
since generators have :py:meth:`~generator.close`, :py:meth:`~generator.send`, and :py:meth:`~generator.throw` methods that
-generic iterables don't. If you will call these methods on the returned
-generator, use the :py:class:`~typing.Generator` type instead of :py:class:`~typing.Iterable` or :py:class:`~typing.Iterator`.
+generic iterators and iterables don't. If you plan to call these methods on the returned
+generator, use the :py:class:`~typing.Generator` type instead of :py:class:`~typing.Iterator` or :py:class:`~typing.Iterable`.
diff --git a/docs/source/literal_types.rst b/docs/source/literal_types.rst
index a223011..a66d300 100644
--- a/docs/source/literal_types.rst
+++ b/docs/source/literal_types.rst
@@ -1,7 +1,10 @@
+Literal types and Enums
+=======================
+
.. _literal_types:
Literal types
-=============
+-------------
Literal types let you indicate that an expression is equal to some specific
primitive value. For example, if we annotate a variable with type ``Literal["foo"]``,
@@ -49,8 +52,8 @@ precise type signature for this function using ``Literal[...]`` and overloads:
The examples in this page import ``Literal`` as well as ``Final`` and
``TypedDict`` from the ``typing`` module. These types were added to
- ``typing`` in Python 3.8, but are also available for use in Python 2.7
- and 3.4 - 3.7 via the ``typing_extensions`` package.
+ ``typing`` in Python 3.8, but are also available for use in Python
+ 3.4 - 3.7 via the ``typing_extensions`` package.
Parameterizing Literals
***********************
@@ -142,7 +145,7 @@ as adding an explicit ``Literal[...]`` annotation, it often leads to the same ef
in practice.
The main cases where the behavior of context-sensitive vs true literal types differ are
-when you try using those types in places that are not explicitly expecting a ``Literal[...]``.
+when you try using those types in places that are not explicitly expecting a ``Literal[...]``.
For example, compare and contrast what happens when you try appending these types to a list:
.. code-block:: python
@@ -152,16 +155,16 @@ For example, compare and contrast what happens when you try appending these type
a: Final = 19
b: Literal[19] = 19
- # Mypy will chose to infer List[int] here.
+ # Mypy will choose to infer list[int] here.
list_of_ints = []
list_of_ints.append(a)
- reveal_type(list_of_ints) # Revealed type is "List[int]"
+ reveal_type(list_of_ints) # Revealed type is "list[int]"
# But if the variable you're appending is an explicit Literal, mypy
- # will infer List[Literal[19]].
+ # will infer list[Literal[19]].
list_of_lits = []
list_of_lits.append(b)
- reveal_type(list_of_lits) # Revealed type is "List[Literal[19]]"
+ reveal_type(list_of_lits) # Revealed type is "list[Literal[19]]"
Intelligent indexing
@@ -186,13 +189,13 @@ corresponding to some particular index, we can use Literal types like so:
# But what if we want the index to be a variable? Normally mypy won't
# know exactly what the index is and so will return a less precise type:
- int_index = 1
+ int_index = 0
reveal_type(tup[int_index]) # Revealed type is "Union[str, float]"
# But if we use either Literal types or a Final int, we can gain back
# the precision we originally had:
- lit_index: Literal[1] = 1
- fin_index: Final = 1
+ lit_index: Literal[0] = 0
+ fin_index: Final = 0
reveal_type(tup[lit_index]) # Revealed type is "str"
reveal_type(tup[fin_index]) # Revealed type is "str"
@@ -208,7 +211,7 @@ corresponding to some particular index, we can use Literal types like so:
# You can also index using unions of literals
id_key: Literal["main_id", "backup_id"]
- reveal_type(d[id_key]) # Revealed type is "int"
+ reveal_type(d[id_key]) # Revealed type is "int"
.. _tagged_unions:
@@ -248,7 +251,7 @@ type. Then, you can discriminate between each kind of TypedDict by checking the
# Literal["new-job", "cancel-job"], but the check below will narrow
# the type to either Literal["new-job"] or Literal["cancel-job"].
#
- # This in turns narrows the type of 'event' to either NewJobEvent
+ # This in turns narrows the type of 'event' to either NewJobEvent
# or CancelJobEvent.
if event["tag"] == "new-job":
print(event["job_name"])
@@ -289,6 +292,102 @@ using ``isinstance()``:
This feature is sometimes called "sum types" or "discriminated union types"
in other programming languages.
+Exhaustiveness checking
+***********************
+
+You may want to check that some code covers all possible
+``Literal`` or ``Enum`` cases. Example:
+
+.. code-block:: python
+
+ from typing import Literal
+
+ PossibleValues = Literal['one', 'two']
+
+ def validate(x: PossibleValues) -> bool:
+ if x == 'one':
+ return True
+ elif x == 'two':
+ return False
+ raise ValueError(f'Invalid value: {x}')
+
+ assert validate('one') is True
+ assert validate('two') is False
+
+In the code above, it's easy to make a mistake. You can
+add a new literal value to ``PossibleValues`` but forget
+to handle it in the ``validate`` function:
+
+.. code-block:: python
+
+ PossibleValues = Literal['one', 'two', 'three']
+
+Mypy won't catch that ``'three'`` is not covered. If you want mypy to
+perform an exhaustiveness check, you need to update your code to use an
+``assert_never()`` check:
+
+.. code-block:: python
+
+ from typing import Literal, NoReturn
+
+ PossibleValues = Literal['one', 'two']
+
+ def assert_never(value: NoReturn) -> NoReturn:
+ # This also works at runtime as well
+ assert False, f'This code should never be reached, got: {value}'
+
+ def validate(x: PossibleValues) -> bool:
+ if x == 'one':
+ return True
+ elif x == 'two':
+ return False
+ assert_never(x)
+
+Now if you add a new value to ``PossibleValues`` but don't update ``validate``,
+mypy will spot the error:
+
+.. code-block:: python
+
+ PossibleValues = Literal['one', 'two', 'three']
+
+ def validate(x: PossibleValues) -> bool:
+ if x == 'one':
+ return True
+ elif x == 'two':
+ return False
+ # Error: Argument 1 to "assert_never" has incompatible type "Literal['three']";
+ # expected "NoReturn"
+ assert_never(x)
+
+If runtime checking against unexpected values is not needed, you can
+leave out the ``assert_never`` call in the above example, and mypy
+will still generate an error about function ``validate`` returning
+without a value:
+
+.. code-block:: python
+
+ PossibleValues = Literal['one', 'two', 'three']
+
+ # Error: Missing return statement
+ def validate(x: PossibleValues) -> bool:
+ if x == 'one':
+ return True
+ elif x == 'two':
+ return False
+
+Exhaustiveness checking is also supported for match statements (Python 3.10 and later):
+
+.. code-block:: python
+
+ def validate(x: PossibleValues) -> bool:
+ match x:
+ case 'one':
+ return True
+ case 'two':
+ return False
+ assert_never(x)
+
+
Limitations
***********
@@ -302,3 +401,131 @@ whatever type the parameter has. For example, ``Literal[3]`` is treated as a
subtype of ``int`` and so will inherit all of ``int``'s methods directly. This
means that ``Literal[3].__add__`` accepts the same arguments and has the same
return type as ``int.__add__``.
+
+
+Enums
+-----
+
+Mypy has special support for :py:class:`enum.Enum` and its subclasses:
+:py:class:`enum.IntEnum`, :py:class:`enum.Flag`, :py:class:`enum.IntFlag`,
+and :py:class:`enum.StrEnum`.
+
+.. code-block:: python
+
+ from enum import Enum
+
+ class Direction(Enum):
+ up = 'up'
+ down = 'down'
+
+ reveal_type(Direction.up) # Revealed type is "Literal[Direction.up]?"
+ reveal_type(Direction.down) # Revealed type is "Literal[Direction.down]?"
+
+You can use enums to annotate types as you would expect:
+
+.. code-block:: python
+
+ class Movement:
+ def __init__(self, direction: Direction, speed: float) -> None:
+ self.direction = direction
+ self.speed = speed
+
+ Movement(Direction.up, 5.0) # ok
+ Movement('up', 5.0) # E: Argument 1 to "Movement" has incompatible type "str"; expected "Direction"
+
+Exhaustiveness checking
+***********************
+
+Similar to ``Literal`` types, ``Enum`` supports exhaustiveness checking.
+Let's start with a definition:
+
+.. code-block:: python
+
+ from enum import Enum
+ from typing import NoReturn
+
+ def assert_never(value: NoReturn) -> NoReturn:
+ # This also works in runtime as well:
+ assert False, f'This code should never be reached, got: {value}'
+
+ class Direction(Enum):
+ up = 'up'
+ down = 'down'
+
+Now, let's use an exhaustiveness check:
+
+.. code-block:: python
+
+ def choose_direction(direction: Direction) -> None:
+ if direction is Direction.up:
+ reveal_type(direction) # N: Revealed type is "Literal[Direction.up]"
+ print('Going up!')
+ return
+ elif direction is Direction.down:
+ print('Down')
+ return
+ # This line is never reached
+ assert_never(direction)
+
+If we forget to handle one of the cases, mypy will generate an error:
+
+.. code-block:: python
+
+ def choose_direction(direction: Direction) -> None:
+ if direction == Direction.up:
+ print('Going up!')
+ return
+ assert_never(direction) # E: Argument 1 to "assert_never" has incompatible type "Direction"; expected "NoReturn"
+
+Exhaustiveness checking is also supported for match statements (Python 3.10 and later).
+
+Extra Enum checks
+*****************
+
+Mypy also tries to support special features of ``Enum``
+the same way Python's runtime does:
+
+- Any ``Enum`` class with values is implicitly :ref:`final `.
+ This is what happens in CPython:
+
+ .. code-block:: python
+
+ >>> class AllDirection(Direction):
+ ... left = 'left'
+ ... right = 'right'
+ Traceback (most recent call last):
+ ...
+ TypeError: AllDirection: cannot extend enumeration 'Direction'
+
+ Mypy also catches this error:
+
+ .. code-block:: python
+
+ class AllDirection(Direction): # E: Cannot inherit from final class "Direction"
+ left = 'left'
+ right = 'right'
+
+- All ``Enum`` fields are implicitly ``final`` as well.
+
+ .. code-block:: python
+
+ Direction.up = '^' # E: Cannot assign to final attribute "up"
+
+- All field names are checked to be unique.
+
+ .. code-block:: python
+
+ class Some(Enum):
+ x = 1
+ x = 2 # E: Attempted to reuse member name "x" in Enum definition "Some"
+
+- Base classes have no conflicts and mixin types are correct.
+
+ .. code-block:: python
+
+ class WrongEnum(str, int, enum.Enum):
+ # E: Only a single data type mixin is allowed for Enum subtypes, found extra "int"
+ ...
+
+ class MixinAfterEnum(enum.Enum, Mixin): # E: No base classes are allowed after "enum.Enum"
+ ...
diff --git a/docs/source/metaclasses.rst b/docs/source/metaclasses.rst
index 750b938..396d7db 100644
--- a/docs/source/metaclasses.rst
+++ b/docs/source/metaclasses.rst
@@ -25,27 +25,6 @@ Defining a metaclass
class A(metaclass=M):
pass
-In Python 2, the syntax for defining a metaclass is different:
-
-.. code-block:: python
-
- class A(object):
- __metaclass__ = M
-
-Mypy also supports using :py:func:`six.with_metaclass` and :py:func:`@six.add_metaclass `
-to define metaclass in a portable way:
-
-.. code-block:: python
-
- import six
-
- class A(six.with_metaclass(M)):
- pass
-
- @six.add_metaclass(M)
- class C(object):
- pass
-
.. _examples:
Metaclass usage example
@@ -93,12 +72,15 @@ so it's better not to combine metaclasses and class hierarchies:
class A1(metaclass=M1): pass
class A2(metaclass=M2): pass
- class B1(A1, metaclass=M2): pass # Mypy Error: Inconsistent metaclass structure for "B1"
+ class B1(A1, metaclass=M2): pass # Mypy Error: metaclass conflict
# At runtime the above definition raises an exception
# TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
- # Same runtime error as in B1, but mypy does not catch it yet
- class B12(A1, A2): pass
+ class B12(A1, A2): pass # Mypy Error: metaclass conflict
+
+ # This can be solved via a common metaclass subtype:
+ class CorrectMeta(M1, M2): pass
+ class B2(A1, A2, metaclass=CorrectMeta): pass # OK, runtime is also OK
* Mypy does not understand dynamically-computed metaclasses,
such as ``class A(metaclass=f()): ...``
diff --git a/docs/source/more_types.rst b/docs/source/more_types.rst
index 16ec058..ff5e8d3 100644
--- a/docs/source/more_types.rst
+++ b/docs/source/more_types.rst
@@ -2,7 +2,7 @@ More types
==========
This section introduces a few additional kinds of types, including :py:data:`~typing.NoReturn`,
-:py:func:`NewType `, ``TypedDict``, and types for async code. It also discusses
+:py:func:`NewType `, and types for async code. It also discusses
how to give functions more precise types using overloads. All of these are only
situationally useful, so feel free to skip this section and come back when you
have a need for some of them.
@@ -20,9 +20,6 @@ Here's a quick summary of what's covered here:
signatures. This is useful if you need to encode a relationship between the
arguments and the return type that would be difficult to express normally.
-* ``TypedDict`` lets you give precise types for dictionaries that represent
- objects with a fixed schema, such as ``{'id': 1, 'items': ['x']}``.
-
* Async types let you type check programs using ``async`` and ``await``.
.. _noreturn:
@@ -60,12 +57,6 @@ pip to use :py:data:`~typing.NoReturn` in your code. Python 3 command line:
python3 -m pip install --upgrade typing-extensions
-This works for Python 2:
-
-.. code-block:: text
-
- pip install --upgrade typing-extensions
-
.. _newtypes:
NewTypes
@@ -84,7 +75,7 @@ certain values from base class instances. Example:
...
However, this approach introduces some runtime overhead. To avoid this, the typing
-module provides a helper function :py:func:`NewType ` that creates simple unique types with
+module provides a helper object :py:func:`NewType ` that creates simple unique types with
almost zero runtime overhead. Mypy will treat the statement
``Derived = NewType('Derived', Base)`` as being roughly equivalent to the following
definition:
@@ -95,7 +86,7 @@ definition:
def __init__(self, _x: Base) -> None:
...
-However, at runtime, ``NewType('Derived', Base)`` will return a dummy function that
+However, at runtime, ``NewType('Derived', Base)`` will return a dummy callable that
simply returns its argument:
.. code-block:: python
@@ -120,14 +111,14 @@ implicitly casting from ``UserId`` where ``int`` is expected. Examples:
name_by_id(42) # Fails type check
name_by_id(UserId(42)) # OK
- num = UserId(5) + 1 # type: int
+ num: int = UserId(5) + 1
:py:func:`NewType ` accepts exactly two arguments. The first argument must be a string literal
containing the name of the new type and must equal the name of the variable to which the new
type is assigned. The second argument must be a properly subclassable class, i.e.,
not a type construct like :py:data:`~typing.Union`, etc.
-The function returned by :py:func:`NewType ` accepts only one argument; this is equivalent to
+The callable returned by :py:func:`NewType ` accepts only one argument; this is equivalent to
supporting only one constructor accepting an instance of the base class (see above).
Example:
@@ -148,8 +139,7 @@ Example:
tcp_packet = TcpPacketId(127, 0) # Fails in type checker and at runtime
You cannot use :py:func:`isinstance` or :py:func:`issubclass` on the object returned by
-:py:func:`~typing.NewType`, because function objects don't support these operations. You cannot
-create subclasses of these objects either.
+:py:func:`~typing.NewType`, nor can you subclass an object returned by :py:func:`~typing.NewType`.
.. note::
@@ -295,6 +285,25 @@ return type by using overloads like so:
subtypes, you can use a :ref:`value restriction
`.
+The default values of a function's arguments don't affect its signature -- only
+the absence or presence of a default value does. So in order to reduce
+redundancy, it's possible to replace default values in overload definitions with
+``...`` as a placeholder:
+
+.. code-block:: python
+
+ from typing import overload
+
+ class M: ...
+
+ @overload
+ def get_model(model_or_pk: M, flag: bool = ...) -> M: ...
+ @overload
+ def get_model(model_or_pk: int, flag: bool = ...) -> M | None: ...
+
+ def get_model(model_or_pk: int | M, flag: bool = True) -> M | None:
+ ...
+
Runtime behavior
----------------
@@ -336,13 +345,15 @@ program:
.. code-block:: python
- from typing import List, overload
+ # For Python 3.8 and below you must use `typing.List` instead of `list`. e.g.
+ # from typing import List
+ from typing import overload
@overload
- def summarize(data: List[int]) -> float: ...
+ def summarize(data: list[int]) -> float: ...
@overload
- def summarize(data: List[str]) -> str: ...
+ def summarize(data: list[str]) -> str: ...
def summarize(data):
if not data:
@@ -356,7 +367,7 @@ program:
output = summarize([])
The ``summarize([])`` call matches both variants: an empty list could
-be either a ``List[int]`` or a ``List[str]``. In this case, mypy
+be either a ``list[int]`` or a ``list[str]``. In this case, mypy
will break the tie by picking the first matching variant: ``output``
will have an inferred type of ``float``. The implementor is responsible
for making sure ``summarize`` breaks ties in the same way at runtime.
@@ -378,7 +389,7 @@ matching variant returns:
.. code-block:: python
- some_list: Union[List[int], List[str]]
+ some_list: Union[list[int], list[str]]
# output3 is of type 'Union[float, str]'
output3 = summarize(some_list)
@@ -505,7 +516,7 @@ suppose we modify the above snippet so it calls ``summarize`` instead of
.. code-block:: python
- some_list: List[str] = []
+ some_list: list[str] = []
summarize(some_list) + "danger danger" # Type safe, yet crashes at runtime!
We run into a similar issue here. This program type checks if we look just at the
@@ -552,7 +563,7 @@ with ``Union[int, slice]`` and ``Union[T, Sequence]``.
Previously, mypy used to perform type erasure on all overload variants. For
example, the ``summarize`` example from the previous section used to be
- illegal because ``List[str]`` and ``List[int]`` both erased to just ``List[Any]``.
+ illegal because ``list[str]`` and ``list[int]`` both erased to just ``list[Any]``.
This restriction was removed in mypy 0.620.
Mypy also previously used to select the best matching variant using a different
@@ -561,6 +572,115 @@ with ``Union[int, slice]`` and ``Union[T, Sequence]``.
to returning ``Any`` only if the input arguments also contain ``Any``.
+Conditional overloads
+---------------------
+
+Sometimes it is useful to define overloads conditionally.
+Common use cases include types that are unavailable at runtime or that
+only exist in a certain Python version. All existing overload rules still apply.
+For example, there must be at least two overloads.
+
+.. note::
+
+ Mypy can only infer a limited number of conditions.
+ Supported ones currently include :py:data:`~typing.TYPE_CHECKING`, ``MYPY``,
+ :ref:`version_and_platform_checks`, :option:`--always-true `,
+ and :option:`--always-false ` values.
+
+.. code-block:: python
+
+ from typing import TYPE_CHECKING, Any, overload
+
+ if TYPE_CHECKING:
+ class A: ...
+ class B: ...
+
+
+ if TYPE_CHECKING:
+ @overload
+ def func(var: A) -> A: ...
+
+ @overload
+ def func(var: B) -> B: ...
+
+ def func(var: Any) -> Any:
+ return var
+
+
+ reveal_type(func(A())) # Revealed type is "A"
+
+.. code-block:: python
+
+ # flags: --python-version 3.10
+ import sys
+ from typing import Any, overload
+
+ class A: ...
+ class B: ...
+ class C: ...
+ class D: ...
+
+
+ if sys.version_info < (3, 7):
+ @overload
+ def func(var: A) -> A: ...
+
+ elif sys.version_info >= (3, 10):
+ @overload
+ def func(var: B) -> B: ...
+
+ else:
+ @overload
+ def func(var: C) -> C: ...
+
+ @overload
+ def func(var: D) -> D: ...
+
+ def func(var: Any) -> Any:
+ return var
+
+
+ reveal_type(func(B())) # Revealed type is "B"
+ reveal_type(func(C())) # No overload variant of "func" matches argument type "C"
+ # Possible overload variants:
+ # def func(var: B) -> B
+ # def func(var: D) -> D
+ # Revealed type is "Any"
+
+
+.. note::
+
+ In the last example, mypy is executed with
+ :option:`--python-version 3.10 `.
+ Therefore, the condition ``sys.version_info >= (3, 10)`` will match and
+ the overload for ``B`` will be added.
+ The overloads for ``A`` and ``C`` are ignored!
+ The overload for ``D`` is not defined conditionally and thus is also added.
+
+When mypy cannot infer a condition to be always ``True`` or always ``False``,
+an error is emitted.
+
+.. code-block:: python
+
+ from typing import Any, overload
+
+ class A: ...
+ class B: ...
+
+
+ def g(bool_var: bool) -> None:
+ if bool_var: # Condition can't be inferred, unable to merge overloads
+ @overload
+ def func(var: A) -> A: ...
+
+ @overload
+ def func(var: B) -> B: ...
+
+ def func(var: Any) -> Any: ...
+
+ reveal_type(func(A())) # Revealed type is "Any"
+
+
.. _advanced_self:
Advanced uses of self-types
@@ -595,7 +715,7 @@ argument is itself generic:
.. code-block:: python
- T = TypeVar('T')
+ T = TypeVar('T', covariant=True)
S = TypeVar('S')
class Storage(Generic[T]):
@@ -604,7 +724,7 @@ argument is itself generic:
def first_chunk(self: Storage[Sequence[S]]) -> S:
return self.content[0]
- page: Storage[List[str]]
+ page: Storage[list[str]]
page.first_chunk() # OK, type is "str"
Storage(0).first_chunk() # Error: Invalid self argument "Storage[int]" to attribute function
@@ -689,13 +809,13 @@ classes are generic, self-type allows giving them precise signatures:
self.item = item
@classmethod
- def make_pair(cls: Type[Q], item: T) -> Tuple[Q, Q]:
+ def make_pair(cls: Type[Q], item: T) -> tuple[Q, Q]:
return cls(item), cls(item)
class Sub(Base[T]):
...
- pair = Sub.make_pair('yes') # Type is "Tuple[Sub[str], Sub[str]]"
+ pair = Sub.make_pair('yes') # Type is "tuple[Sub[str], Sub[str]]"
bad = Sub[int].make_pair('no') # Error: Argument 1 to "make_pair" of "Base"
# has incompatible type "str"; expected "int"
@@ -717,7 +837,7 @@ expect to get back when ``await``-ing the coroutine.
import asyncio
async def format_string(tag: str, count: int) -> str:
- return 'T-minus {} ({})'.format(count, tag)
+ return f'T-minus {count} ({tag})'
async def countdown_1(tag: str, count: int) -> str:
while count > 0:
@@ -745,68 +865,6 @@ value of type :py:class:`Coroutine[Any, Any, T] `, which is a
:ref:`reveal_type() ` displays the inferred static type of
an expression.
-If you want to use coroutines in Python 3.4, which does not support
-the ``async def`` syntax, you can instead use the :py:func:`@asyncio.coroutine `
-decorator to convert a generator into a coroutine.
-
-Note that we set the ``YieldType`` of the generator to be ``Any`` in the
-following example. This is because the exact yield type is an implementation
-detail of the coroutine runner (e.g. the :py:mod:`asyncio` event loop) and your
-coroutine shouldn't have to know or care about what precisely that type is.
-
-.. code-block:: python
-
- from typing import Any, Generator
- import asyncio
-
- @asyncio.coroutine
- def countdown_2(tag: str, count: int) -> Generator[Any, None, str]:
- while count > 0:
- print('T-minus {} ({})'.format(count, tag))
- yield from asyncio.sleep(0.1)
- count -= 1
- return "Blastoff!"
-
- loop = asyncio.get_event_loop()
- loop.run_until_complete(countdown_2("USS Enterprise", 5))
- loop.close()
-
-As before, the result of calling a generator decorated with :py:func:`@asyncio.coroutine `
-will be a value of type :py:class:`Awaitable[T] `.
-
-.. note::
-
- At runtime, you are allowed to add the :py:func:`@asyncio.coroutine ` decorator to
- both functions and generators. This is useful when you want to mark a
- work-in-progress function as a coroutine, but have not yet added ``yield`` or
- ``yield from`` statements:
-
- .. code-block:: python
-
- import asyncio
-
- @asyncio.coroutine
- def serialize(obj: object) -> str:
- # todo: add yield/yield from to turn this into a generator
- return "placeholder"
-
- However, mypy currently does not support converting functions into
- coroutines. Support for this feature will be added in a future version, but
- for now, you can manually force the function to be a generator by doing
- something like this:
-
- .. code-block:: python
-
- from typing import Generator
- import asyncio
-
- @asyncio.coroutine
- def serialize(obj: object) -> Generator[None, None, str]:
- # todo: add yield/yield from to turn this into a generator
- if False:
- yield
- return "placeholder"
-
You may also choose to create a subclass of :py:class:`~typing.Awaitable` instead:
.. code-block:: python
@@ -821,7 +879,7 @@ You may also choose to create a subclass of :py:class:`~typing.Awaitable` instea
def __await__(self) -> Generator[Any, None, str]:
for i in range(n, 0, -1):
- print('T-minus {} ({})'.format(i, tag))
+ print(f'T-minus {i} ({tag})')
yield from asyncio.sleep(0.1)
return "Blastoff!"
@@ -858,7 +916,7 @@ To create an iterable coroutine, subclass :py:class:`~typing.AsyncIterator`:
async def countdown_4(tag: str, n: int) -> str:
async for i in arange(n, 0, -1):
- print('T-minus {} ({})'.format(i, tag))
+ print(f'T-minus {i} ({tag})')
await asyncio.sleep(0.1)
return "Blastoff!"
@@ -866,269 +924,25 @@ To create an iterable coroutine, subclass :py:class:`~typing.AsyncIterator`:
loop.run_until_complete(countdown_4("Serenity", 5))
loop.close()
-For a more concrete example, the mypy repo has a toy webcrawler that
-demonstrates how to work with coroutines. One version
-`uses async/await `_
-and one
-`uses yield from `_.
-
-.. _typeddict:
-
-TypedDict
-*********
-
-Python programs often use dictionaries with string keys to represent objects.
-Here is a typical example:
+If you use coroutines in legacy code that was originally written for
+Python 3.4, which did not support the ``async def`` syntax, you would
+instead use the :py:func:`@asyncio.coroutine `
+decorator to convert a generator into a coroutine, and use a
+generator type as the return type:
.. code-block:: python
- movie = {'name': 'Blade Runner', 'year': 1982}
-
-Only a fixed set of string keys is expected (``'name'`` and
-``'year'`` above), and each key has an independent value type (``str``
-for ``'name'`` and ``int`` for ``'year'`` above). We've previously
-seen the ``Dict[K, V]`` type, which lets you declare uniform
-dictionary types, where every value has the same type, and arbitrary keys
-are supported. This is clearly not a good fit for
-``movie`` above. Instead, you can use a ``TypedDict`` to give a precise
-type for objects like ``movie``, where the type of each
-dictionary value depends on the key:
-
-.. code-block:: python
-
- from typing_extensions import TypedDict
-
- Movie = TypedDict('Movie', {'name': str, 'year': int})
-
- movie = {'name': 'Blade Runner', 'year': 1982} # type: Movie
-
-``Movie`` is a ``TypedDict`` type with two items: ``'name'`` (with type ``str``)
-and ``'year'`` (with type ``int``). Note that we used an explicit type
-annotation for the ``movie`` variable. This type annotation is
-important -- without it, mypy will try to infer a regular, uniform
-:py:class:`~typing.Dict` type for ``movie``, which is not what we want here.
-
-.. note::
-
- If you pass a ``TypedDict`` object as an argument to a function, no
- type annotation is usually necessary since mypy can infer the
- desired type based on the declared argument type. Also, if an
- assignment target has been previously defined, and it has a
- ``TypedDict`` type, mypy will treat the assigned value as a ``TypedDict``,
- not :py:class:`~typing.Dict`.
-
-Now mypy will recognize these as valid:
-
-.. code-block:: python
-
- name = movie['name'] # Okay; type of name is str
- year = movie['year'] # Okay; type of year is int
-
-Mypy will detect an invalid key as an error:
-
-.. code-block:: python
-
- director = movie['director'] # Error: 'director' is not a valid key
-
-Mypy will also reject a runtime-computed expression as a key, as
-it can't verify that it's a valid key. You can only use string
-literals as ``TypedDict`` keys.
-
-The ``TypedDict`` type object can also act as a constructor. It
-returns a normal :py:class:`dict` object at runtime -- a ``TypedDict`` does
-not define a new runtime type:
-
-.. code-block:: python
-
- toy_story = Movie(name='Toy Story', year=1995)
-
-This is equivalent to just constructing a dictionary directly using
-``{ ... }`` or ``dict(key=value, ...)``. The constructor form is
-sometimes convenient, since it can be used without a type annotation,
-and it also makes the type of the object explicit.
-
-Like all types, ``TypedDict``\s can be used as components to build
-arbitrarily complex types. For example, you can define nested
-``TypedDict``\s and containers with ``TypedDict`` items.
-Unlike most other types, mypy uses structural compatibility checking
-(or structural subtyping) with ``TypedDict``\s. A ``TypedDict`` object with
-extra items is a compatible with (a subtype of) a narrower
-``TypedDict``, assuming item types are compatible (*totality* also affects
-subtyping, as discussed below).
-
-A ``TypedDict`` object is not a subtype of the regular ``Dict[...]``
-type (and vice versa), since :py:class:`~typing.Dict` allows arbitrary keys to be
-added and removed, unlike ``TypedDict``. However, any ``TypedDict`` object is
-a subtype of (that is, compatible with) ``Mapping[str, object]``, since
-:py:class:`~typing.Mapping` only provides read-only access to the dictionary items:
-
-.. code-block:: python
-
- def print_typed_dict(obj: Mapping[str, object]) -> None:
- for key, value in obj.items():
- print('{}: {}'.format(key, value))
-
- print_typed_dict(Movie(name='Toy Story', year=1995)) # OK
-
-.. note::
-
- Unless you are on Python 3.8 or newer (where ``TypedDict`` is available in
- standard library :py:mod:`typing` module) you need to install ``typing_extensions``
- using pip to use ``TypedDict``:
-
- .. code-block:: text
-
- python3 -m pip install --upgrade typing-extensions
-
- Or, if you are using Python 2:
-
- .. code-block:: text
-
- pip install --upgrade typing-extensions
-
-Totality
---------
-
-By default mypy ensures that a ``TypedDict`` object has all the specified
-keys. This will be flagged as an error:
-
-.. code-block:: python
-
- # Error: 'year' missing
- toy_story = {'name': 'Toy Story'} # type: Movie
-
-Sometimes you want to allow keys to be left out when creating a
-``TypedDict`` object. You can provide the ``total=False`` argument to
-``TypedDict(...)`` to achieve this:
-
-.. code-block:: python
-
- GuiOptions = TypedDict(
- 'GuiOptions', {'language': str, 'color': str}, total=False)
- options = {} # type: GuiOptions # Okay
- options['language'] = 'en'
-
-You may need to use :py:meth:`~dict.get` to access items of a partial (non-total)
-``TypedDict``, since indexing using ``[]`` could fail at runtime.
-However, mypy still lets use ``[]`` with a partial ``TypedDict`` -- you
-just need to be careful with it, as it could result in a :py:exc:`KeyError`.
-Requiring :py:meth:`~dict.get` everywhere would be too cumbersome. (Note that you
-are free to use :py:meth:`~dict.get` with total ``TypedDict``\s as well.)
-
-Keys that aren't required are shown with a ``?`` in error messages:
-
-.. code-block:: python
-
- # Revealed type is "TypedDict('GuiOptions', {'language'?: builtins.str,
- # 'color'?: builtins.str})"
- reveal_type(options)
-
-Totality also affects structural compatibility. You can't use a partial
-``TypedDict`` when a total one is expected. Also, a total ``TypedDict`` is not
-valid when a partial one is expected.
-
-Supported operations
---------------------
-
-``TypedDict`` objects support a subset of dictionary operations and methods.
-You must use string literals as keys when calling most of the methods,
-as otherwise mypy won't be able to check that the key is valid. List
-of supported operations:
-
-* Anything included in :py:class:`~typing.Mapping`:
-
- * ``d[key]``
- * ``key in d``
- * ``len(d)``
- * ``for key in d`` (iteration)
- * :py:meth:`d.get(key[, default]) `
- * :py:meth:`d.keys() `
- * :py:meth:`d.values() `
- * :py:meth:`d.items() `
-
-* :py:meth:`d.copy() `
-* :py:meth:`d.setdefault(key, default) `
-* :py:meth:`d1.update(d2) `
-* :py:meth:`d.pop(key[, default]) ` (partial ``TypedDict``\s only)
-* ``del d[key]`` (partial ``TypedDict``\s only)
-
-In Python 2 code, these methods are also supported:
-
-* ``has_key(key)``
-* ``viewitems()``
-* ``viewkeys()``
-* ``viewvalues()``
-
-.. note::
-
- :py:meth:`~dict.clear` and :py:meth:`~dict.popitem` are not supported since they are unsafe
- -- they could delete required ``TypedDict`` items that are not visible to
- mypy because of structural subtyping.
-
-Class-based syntax
-------------------
-
-An alternative, class-based syntax to define a ``TypedDict`` is supported
-in Python 3.6 and later:
-
-.. code-block:: python
-
- from typing_extensions import TypedDict
-
- class Movie(TypedDict):
- name: str
- year: int
-
-The above definition is equivalent to the original ``Movie``
-definition. It doesn't actually define a real class. This syntax also
-supports a form of inheritance -- subclasses can define additional
-items. However, this is primarily a notational shortcut. Since mypy
-uses structural compatibility with ``TypedDict``\s, inheritance is not
-required for compatibility. Here is an example of inheritance:
-
-.. code-block:: python
-
- class Movie(TypedDict):
- name: str
- year: int
-
- class BookBasedMovie(Movie):
- based_on: str
-
-Now ``BookBasedMovie`` has keys ``name``, ``year`` and ``based_on``.
-
-Mixing required and non-required items
---------------------------------------
-
-In addition to allowing reuse across ``TypedDict`` types, inheritance also allows
-you to mix required and non-required (using ``total=False``) items
-in a single ``TypedDict``. Example:
-
-.. code-block:: python
-
- class MovieBase(TypedDict):
- name: str
- year: int
-
- class Movie(MovieBase, total=False):
- based_on: str
-
-Now ``Movie`` has required keys ``name`` and ``year``, while ``based_on``
-can be left out when constructing an object. A ``TypedDict`` with a mix of required
-and non-required keys, such as ``Movie`` above, will only be compatible with
-another ``TypedDict`` if all required keys in the other ``TypedDict`` are required keys in the
-first ``TypedDict``, and all non-required keys of the other ``TypedDict`` are also non-required keys
-in the first ``TypedDict``.
-
-Unions of TypedDicts
---------------------
+ from typing import Any, Generator
+ import asyncio
-Since TypedDicts are really just regular dicts at runtime, it is not possible to
-use ``isinstance`` checks to distinguish between different variants of a Union of
-TypedDict in the same way you can with regular objects.
+ @asyncio.coroutine
+ def countdown_2(tag: str, count: int) -> Generator[Any, None, str]:
+ while count > 0:
+ print(f'T-minus {count} ({tag})')
+ yield from asyncio.sleep(0.1)
+ count -= 1
+ return "Blastoff!"
-Instead, you can use the :ref:`tagged union pattern `. The referenced
-section of the docs has a full description with an example, but in short, you will
-need to give each TypedDict the same key where each value has a unique
-unique :ref:`Literal type `. Then, check that key to distinguish
-between your TypedDicts.
+ loop = asyncio.get_event_loop()
+ loop.run_until_complete(countdown_2("USS Enterprise", 5))
+ loop.close()
diff --git a/docs/source/mypy_daemon.rst b/docs/source/mypy_daemon.rst
index 29b554d..ec12283 100644
--- a/docs/source/mypy_daemon.rst
+++ b/docs/source/mypy_daemon.rst
@@ -152,6 +152,12 @@ Additional daemon flags
Write performance profiling information to ``FILE``. This is only available
for the ``check``, ``recheck``, and ``run`` commands.
+.. option:: --export-types
+
+ Store all expression types in memory for future use. This is useful to speed
+ up future calls to ``dmypy inspect`` (but uses more memory). Only valid for
+ ``check``, ``recheck``, and ``run`` command.
+
Static inference of annotations
*******************************
@@ -171,7 +177,7 @@ In this example, the function ``format_id()`` has no annotation:
.. code-block:: python
def format_id(user):
- return "User: {}".format(user)
+ return f"User: {user}"
root = format_id(0)
@@ -222,11 +228,6 @@ command.
Only allow some fraction of types in the suggested signature to be ``Any`` types.
The fraction ranges from ``0`` (same as ``--no-any``) to ``1``.
-.. option:: --try-text
-
- Try also using ``unicode`` wherever ``str`` is inferred. This flag may be useful
- for annotating Python 2/3 straddling code.
-
.. option:: --callsites
Only find call sites for a given function instead of suggesting a type.
@@ -243,8 +244,129 @@ command.
Set the maximum number of types to try for a function (default: ``64``).
-.. TODO: Add similar sections about go to definition, find usages, and
- reveal type when added, and then move this to a separate file.
+Statically inspect expressions
+******************************
+
+The daemon allows to get declared or inferred type of an expression (or other
+information about an expression, such as known attributes or definition location)
+using ``dmypy inspect LOCATION`` command. The location of the expression should be
+specified in the format ``path/to/file.py:line:column[:end_line:end_column]``.
+Both line and column are 1-based. Both start and end position are inclusive.
+These rules match how mypy prints the error location in error messages.
+
+If a span is given (i.e. all 4 numbers), then only an exactly matching expression
+is inspected. If only a position is given (i.e. 2 numbers, line and column), mypy
+will inspect all *expressions*, that include this position, starting from the
+innermost one.
+
+Consider this Python code snippet:
+
+.. code-block:: python
+
+ def foo(x: int, longer_name: str) -> None:
+ x
+ longer_name
+
+Here to find the type of ``x`` one needs to call ``dmypy inspect src.py:2:5:2:5``
+or ``dmypy inspect src.py:2:5``. While for ``longer_name`` one needs to call
+``dmypy inspect src.py:3:5:3:15`` or, for example, ``dmypy inspect src.py:3:10``.
+Please note that this command is only valid after daemon had a successful type
+check (without parse errors), so that types are populated, e.g. using
+``dmypy check``. In case where multiple expressions match the provided location,
+their types are returned separated by a newline.
+
+Important note: it is recommended to check files with :option:`--export-types`
+since otherwise most inspections will not work without :option:`--force-reload`.
+
+.. option:: --show INSPECTION
+
+ What kind of inspection to run for expression(s) found. Currently the supported
+ inspections are:
+
+ * ``type`` (default): Show the best known type of a given expression.
+ * ``attrs``: Show which attributes are valid for an expression (e.g. for
+ auto-completion). Format is ``{"Base1": ["name_1", "name_2", ...]; "Base2": ...}``.
+ Names are sorted by method resolution order. If expression refers to a module,
+ then module attributes will be under key like ``""``.
+ * ``definition`` (experimental): Show the definition location for a name
+ expression or member expression. Format is ``path/to/file.py:line:column:Symbol``.
+ If multiple definitions are found (e.g. for a Union attribute), they are
+ separated by comma.
+
+.. option:: --verbose
+
+ Increase verbosity of types string representation (can be repeated).
+ For example, this will print fully qualified names of instance types (like
+ ``"builtins.str"``), instead of just a short name (like ``"str"``).
+
+.. option:: --limit NUM
+
+ If the location is given as ``line:column``, this will cause daemon to
+ return only at most ``NUM`` inspections of innermost expressions.
+ Value of 0 means no limit (this is the default). For example, if one calls
+ ``dmypy inspect src.py:4:10 --limit=1`` with this code
+
+ .. code-block:: python
+
+ def foo(x: int) -> str: ..
+ def bar(x: str) -> None: ...
+ baz: int
+ bar(foo(baz))
+
+ This will output just one type ``"int"`` (for ``baz`` name expression).
+ While without the limit option, it would output all three types: ``"int"``,
+ ``"str"``, and ``"None"``.
+
+.. option:: --include-span
+
+ With this option on, the daemon will prepend each inspection result with
+ the full span of corresponding expression, formatted as ``1:2:1:4 -> "int"``.
+ This may be useful in case multiple expressions match a location.
+
+.. option:: --include-kind
+
+ With this option on, the daemon will prepend each inspection result with
+ the kind of corresponding expression, formatted as ``NameExpr -> "int"``.
+ If both this option and :option:`--include-span` are on, the kind will
+ appear first, for example ``NameExpr:1:2:1:4 -> "int"``.
+
+.. option:: --include-object-attrs
+
+ This will make the daemon include attributes of ``object`` (excluded by
+ default) in case of an ``atts`` inspection.
+
+.. option:: --union-attrs
+
+ Include attributes valid for some of possible expression types (by default
+ an intersection is returned). This is useful for union types of type variables
+ with values. For example, with this code:
+
+ .. code-block:: python
+
+ from typing import Union
+
+ class A:
+ x: int
+ z: int
+ class B:
+ y: int
+ z: int
+ var: Union[A, B]
+ var
+
+ The command ``dmypy inspect --show attrs src.py:10:1`` will return
+ ``{"A": ["z"], "B": ["z"]}``, while with ``--union-attrs`` it will return
+ ``{"A": ["x", "z"], "B": ["y", "z"]}``.
+
+.. option:: --force-reload
+
+ Force re-parsing and re-type-checking file before inspection. By default
+ this is done only when needed (for example file was not loaded from cache
+ or daemon was initially run without ``--export-types`` mypy option),
+ since reloading may be slow (up to few seconds for very large files).
+
+.. TODO: Add similar section about find usages when added, and then move
+ this to a separate file.
.. _watchman: https://facebook.github.io/watchman/
diff --git a/docs/source/mypy_light.svg b/docs/source/mypy_light.svg
new file mode 100644
index 0000000..4eaf65d
--- /dev/null
+++ b/docs/source/mypy_light.svg
@@ -0,0 +1,99 @@
+
+
diff --git a/docs/source/protocols.rst b/docs/source/protocols.rst
index 38d1ee9..cb51809 100644
--- a/docs/source/protocols.rst
+++ b/docs/source/protocols.rst
@@ -4,14 +4,17 @@ Protocols and structural subtyping
==================================
Mypy supports two ways of deciding whether two classes are compatible
-as types: nominal subtyping and structural subtyping. *Nominal*
-subtyping is strictly based on the class hierarchy. If class ``D``
+as types: nominal subtyping and structural subtyping.
+
+*Nominal* subtyping is strictly based on the class hierarchy. If class ``D``
inherits class ``C``, it's also a subtype of ``C``, and instances of
``D`` can be used when ``C`` instances are expected. This form of
subtyping is used by default in mypy, since it's easy to understand
and produces clear and concise error messages, and since it matches
how the native :py:func:`isinstance ` check works -- based on class
-hierarchy. *Structural* subtyping can also be useful. Class ``D`` is
+hierarchy.
+
+*Structural* subtyping is based on the operations that can be performed with an object. Class ``D`` is
a structural subtype of class ``C`` if the former has all attributes
and methods of the latter, and with compatible types.
@@ -55,11 +58,292 @@ For example, ``IntList`` below is iterable, over ``int`` values:
print_numbered(x) # OK
print_numbered([4, 5]) # Also OK
-The subsections below introduce all built-in protocols defined in
+:ref:`predefined_protocols_reference` lists all protocols defined in
:py:mod:`typing` and the signatures of the corresponding methods you need to define
to implement each protocol (the signatures can be left out, as always, but mypy
won't type check unannotated methods).
+Simple user-defined protocols
+*****************************
+
+You can define your own protocol class by inheriting the special ``Protocol``
+class:
+
+.. code-block:: python
+
+ from typing import Iterable
+ from typing_extensions import Protocol
+
+ class SupportsClose(Protocol):
+ # Empty method body (explicit '...')
+ def close(self) -> None: ...
+
+ class Resource: # No SupportsClose base class!
+
+ def close(self) -> None:
+ self.resource.release()
+
+ # ... other methods ...
+
+ def close_all(items: Iterable[SupportsClose]) -> None:
+ for item in items:
+ item.close()
+
+ close_all([Resource(), open('some/file')]) # Okay!
+
+``Resource`` is a subtype of the ``SupportsClose`` protocol since it defines
+a compatible ``close`` method. Regular file objects returned by :py:func:`open` are
+similarly compatible with the protocol, as they support ``close()``.
+
+.. note::
+
+ The ``Protocol`` base class is provided in the ``typing_extensions``
+ package for Python 3.4-3.7. Starting with Python 3.8, ``Protocol``
+ is included in the ``typing`` module.
+
+Defining subprotocols and subclassing protocols
+***********************************************
+
+You can also define subprotocols. Existing protocols can be extended
+and merged using multiple inheritance. Example:
+
+.. code-block:: python
+
+ # ... continuing from the previous example
+
+ class SupportsRead(Protocol):
+ def read(self, amount: int) -> bytes: ...
+
+ class TaggedReadableResource(SupportsClose, SupportsRead, Protocol):
+ label: str
+
+ class AdvancedResource(Resource):
+ def __init__(self, label: str) -> None:
+ self.label = label
+
+ def read(self, amount: int) -> bytes:
+ # some implementation
+ ...
+
+ resource: TaggedReadableResource
+ resource = AdvancedResource('handle with care') # OK
+
+Note that inheriting from an existing protocol does not automatically
+turn the subclass into a protocol -- it just creates a regular
+(non-protocol) class or ABC that implements the given protocol (or
+protocols). The ``Protocol`` base class must always be explicitly
+present if you are defining a protocol:
+
+.. code-block:: python
+
+ class NotAProtocol(SupportsClose): # This is NOT a protocol
+ new_attr: int
+
+ class Concrete:
+ new_attr: int = 0
+
+ def close(self) -> None:
+ ...
+
+ # Error: nominal subtyping used by default
+ x: NotAProtocol = Concrete() # Error!
+
+You can also include default implementations of methods in
+protocols. If you explicitly subclass these protocols you can inherit
+these default implementations.
+
+Explicitly including a protocol as a
+base class is also a way of documenting that your class implements a
+particular protocol, and it forces mypy to verify that your class
+implementation is actually compatible with the protocol. In particular,
+omitting a value for an attribute or a method body will make it implicitly
+abstract:
+
+.. code-block:: python
+
+ class SomeProto(Protocol):
+ attr: int # Note, no right hand side
+ def method(self) -> str: ... # Literally just ... here
+
+ class ExplicitSubclass(SomeProto):
+ pass
+
+ ExplicitSubclass() # error: Cannot instantiate abstract class 'ExplicitSubclass'
+ # with abstract attributes 'attr' and 'method'
+
+Invariance of protocol attributes
+*********************************
+
+A common issue with protocols is that protocol attributes are invariant.
+For example:
+
+.. code-block:: python
+
+ class Box(Protocol):
+ content: object
+
+ class IntBox:
+ content: int
+
+ def takes_box(box: Box) -> None: ...
+
+ takes_box(IntBox()) # error: Argument 1 to "takes_box" has incompatible type "IntBox"; expected "Box"
+ # note: Following member(s) of "IntBox" have conflicts:
+ # note: content: expected "object", got "int"
+
+This is because ``Box`` defines ``content`` as a mutable attribute.
+Here's why this is problematic:
+
+.. code-block:: python
+
+ def takes_box_evil(box: Box) -> None:
+ box.content = "asdf" # This is bad, since box.content is supposed to be an object
+
+ my_int_box = IntBox()
+ takes_box_evil(my_int_box)
+ my_int_box.content + 1 # Oops, TypeError!
+
+This can be fixed by declaring ``content`` to be read-only in the ``Box``
+protocol using ``@property``:
+
+.. code-block:: python
+
+ class Box(Protocol):
+ @property
+ def content(self) -> object: ...
+
+ class IntBox:
+ content: int
+
+ def takes_box(box: Box) -> None: ...
+
+ takes_box(IntBox(42)) # OK
+
+Recursive protocols
+*******************
+
+Protocols can be recursive (self-referential) and mutually
+recursive. This is useful for declaring abstract recursive collections
+such as trees and linked lists:
+
+.. code-block:: python
+
+ from typing import TypeVar, Optional
+ from typing_extensions import Protocol
+
+ class TreeLike(Protocol):
+ value: int
+
+ @property
+ def left(self) -> Optional['TreeLike']: ...
+
+ @property
+ def right(self) -> Optional['TreeLike']: ...
+
+ class SimpleTree:
+ def __init__(self, value: int) -> None:
+ self.value = value
+ self.left: Optional['SimpleTree'] = None
+ self.right: Optional['SimpleTree'] = None
+
+ root: TreeLike = SimpleTree(0) # OK
+
+Using isinstance() with protocols
+*********************************
+
+You can use a protocol class with :py:func:`isinstance` if you decorate it
+with the ``@runtime_checkable`` class decorator. The decorator adds
+rudimentary support for runtime structural checks:
+
+.. code-block:: python
+
+ from typing_extensions import Protocol, runtime_checkable
+
+ @runtime_checkable
+ class Portable(Protocol):
+ handles: int
+
+ class Mug:
+ def __init__(self) -> None:
+ self.handles = 1
+
+ def use(handles: int) -> None: ...
+
+ mug = Mug()
+ if isinstance(mug, Portable): # Works at runtime!
+ use(mug.handles)
+
+:py:func:`isinstance` also works with the :ref:`predefined protocols `
+in :py:mod:`typing` such as :py:class:`~typing.Iterable`.
+
+.. warning::
+ :py:func:`isinstance` with protocols is not completely safe at runtime.
+ For example, signatures of methods are not checked. The runtime
+ implementation only checks that all protocol members exist,
+ not that they have the correct type. :py:func:`issubclass` with protocols
+ will only check for the existence of methods.
+
+.. note::
+ :py:func:`isinstance` with protocols can also be surprisingly slow.
+ In many cases, you're better served by using :py:func:`hasattr` to
+ check for the presence of attributes.
+
+.. _callback_protocols:
+
+Callback protocols
+******************
+
+Protocols can be used to define flexible callback types that are hard
+(or even impossible) to express using the :py:data:`Callable[...] ` syntax, such as variadic,
+overloaded, and complex generic callbacks. They are defined with a special :py:meth:`__call__ `
+member:
+
+.. code-block:: python
+
+ from typing import Optional, Iterable
+ from typing_extensions import Protocol
+
+ class Combiner(Protocol):
+ def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ...
+
+ def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
+ for item in data:
+ ...
+
+ def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> list[bytes]:
+ ...
+ def bad_cb(*vals: bytes, maxitems: Optional[int]) -> list[bytes]:
+ ...
+
+ batch_proc([], good_cb) # OK
+ batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of
+ # different name and kind in the callback
+
+Callback protocols and :py:data:`~typing.Callable` types can be used interchangeably.
+Argument names in :py:meth:`__call__ ` methods must be identical, unless
+a double underscore prefix is used. For example:
+
+.. code-block:: python
+
+ from typing import Callable, TypeVar
+ from typing_extensions import Protocol
+
+ T = TypeVar('T')
+
+ class Copy(Protocol):
+ def __call__(self, __origin: T) -> T: ...
+
+ copy_a: Callable[[T], T]
+ copy_b: Copy
+
+ copy_a = copy_b # OK
+ copy_b = copy_a # Also OK
+
+.. _predefined_protocols_reference:
+
+Predefined protocol reference
+*****************************
+
Iteration protocols
...................
@@ -283,213 +567,3 @@ AsyncContextManager[T]
traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]]
See also :py:class:`~typing.AsyncContextManager`.
-
-Simple user-defined protocols
-*****************************
-
-You can define your own protocol class by inheriting the special ``Protocol``
-class:
-
-.. code-block:: python
-
- from typing import Iterable
- from typing_extensions import Protocol
-
- class SupportsClose(Protocol):
- def close(self) -> None:
- ... # Empty method body (explicit '...')
-
- class Resource: # No SupportsClose base class!
- # ... some methods ...
-
- def close(self) -> None:
- self.resource.release()
-
- def close_all(items: Iterable[SupportsClose]) -> None:
- for item in items:
- item.close()
-
- close_all([Resource(), open('some/file')]) # Okay!
-
-``Resource`` is a subtype of the ``SupportsClose`` protocol since it defines
-a compatible ``close`` method. Regular file objects returned by :py:func:`open` are
-similarly compatible with the protocol, as they support ``close()``.
-
-.. note::
-
- The ``Protocol`` base class is provided in the ``typing_extensions``
- package for Python 2.7 and 3.4-3.7. Starting with Python 3.8, ``Protocol``
- is included in the ``typing`` module.
-
-Defining subprotocols and subclassing protocols
-***********************************************
-
-You can also define subprotocols. Existing protocols can be extended
-and merged using multiple inheritance. Example:
-
-.. code-block:: python
-
- # ... continuing from the previous example
-
- class SupportsRead(Protocol):
- def read(self, amount: int) -> bytes: ...
-
- class TaggedReadableResource(SupportsClose, SupportsRead, Protocol):
- label: str
-
- class AdvancedResource(Resource):
- def __init__(self, label: str) -> None:
- self.label = label
-
- def read(self, amount: int) -> bytes:
- # some implementation
- ...
-
- resource: TaggedReadableResource
- resource = AdvancedResource('handle with care') # OK
-
-Note that inheriting from an existing protocol does not automatically
-turn the subclass into a protocol -- it just creates a regular
-(non-protocol) class or ABC that implements the given protocol (or
-protocols). The ``Protocol`` base class must always be explicitly
-present if you are defining a protocol:
-
-.. code-block:: python
-
- class NotAProtocol(SupportsClose): # This is NOT a protocol
- new_attr: int
-
- class Concrete:
- new_attr: int = 0
-
- def close(self) -> None:
- ...
-
- # Error: nominal subtyping used by default
- x: NotAProtocol = Concrete() # Error!
-
-You can also include default implementations of methods in
-protocols. If you explicitly subclass these protocols you can inherit
-these default implementations. Explicitly including a protocol as a
-base class is also a way of documenting that your class implements a
-particular protocol, and it forces mypy to verify that your class
-implementation is actually compatible with the protocol.
-
-.. note::
-
- You can use Python 3.6 variable annotations (:pep:`526`)
- to declare protocol attributes. On Python 2.7 and earlier Python 3
- versions you can use type comments and properties.
-
-Recursive protocols
-*******************
-
-Protocols can be recursive (self-referential) and mutually
-recursive. This is useful for declaring abstract recursive collections
-such as trees and linked lists:
-
-.. code-block:: python
-
- from typing import TypeVar, Optional
- from typing_extensions import Protocol
-
- class TreeLike(Protocol):
- value: int
-
- @property
- def left(self) -> Optional['TreeLike']: ...
-
- @property
- def right(self) -> Optional['TreeLike']: ...
-
- class SimpleTree:
- def __init__(self, value: int) -> None:
- self.value = value
- self.left: Optional['SimpleTree'] = None
- self.right: Optional['SimpleTree'] = None
-
- root: TreeLike = SimpleTree(0) # OK
-
-Using isinstance() with protocols
-*********************************
-
-You can use a protocol class with :py:func:`isinstance` if you decorate it
-with the ``@runtime_checkable`` class decorator. The decorator adds
-support for basic runtime structural checks:
-
-.. code-block:: python
-
- from typing_extensions import Protocol, runtime_checkable
-
- @runtime_checkable
- class Portable(Protocol):
- handles: int
-
- class Mug:
- def __init__(self) -> None:
- self.handles = 1
-
- def use(handles: int) -> None: ...
-
- mug = Mug()
- if isinstance(mug, Portable):
- use(mug.handles) # Works statically and at runtime
-
-:py:func:`isinstance` also works with the :ref:`predefined protocols `
-in :py:mod:`typing` such as :py:class:`~typing.Iterable`.
-
-.. note::
- :py:func:`isinstance` with protocols is not completely safe at runtime.
- For example, signatures of methods are not checked. The runtime
- implementation only checks that all protocol members are defined.
-
-.. _callback_protocols:
-
-Callback protocols
-******************
-
-Protocols can be used to define flexible callback types that are hard
-(or even impossible) to express using the :py:data:`Callable[...] ` syntax, such as variadic,
-overloaded, and complex generic callbacks. They are defined with a special :py:meth:`__call__ `
-member:
-
-.. code-block:: python
-
- from typing import Optional, Iterable, List
- from typing_extensions import Protocol
-
- class Combiner(Protocol):
- def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> List[bytes]: ...
-
- def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes:
- for item in data:
- ...
-
- def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> List[bytes]:
- ...
- def bad_cb(*vals: bytes, maxitems: Optional[int]) -> List[bytes]:
- ...
-
- batch_proc([], good_cb) # OK
- batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of
- # different name and kind in the callback
-
-Callback protocols and :py:data:`~typing.Callable` types can be used interchangeably.
-Keyword argument names in :py:meth:`__call__ ` methods must be identical, unless
-a double underscore prefix is used. For example:
-
-.. code-block:: python
-
- from typing import Callable, TypeVar
- from typing_extensions import Protocol
-
- T = TypeVar('T')
-
- class Copy(Protocol):
- def __call__(self, __origin: T) -> T: ...
-
- copy_a: Callable[[T], T]
- copy_b: Copy
-
- copy_a = copy_b # OK
- copy_b = copy_a # Also OK
diff --git a/docs/source/python2.rst b/docs/source/python2.rst
deleted file mode 100644
index 67ea4f8..0000000
--- a/docs/source/python2.rst
+++ /dev/null
@@ -1,134 +0,0 @@
-.. _python2:
-
-Type checking Python 2 code
-===========================
-
-For code that needs to be Python 2.7 compatible, function type
-annotations are given in comments, since the function annotation
-syntax was introduced in Python 3. The comment-based syntax is
-specified in :pep:`484`.
-
-Mypy requires typed-ast in order to check Python 2 code. You can install it
-using ``pip install 'mypy[python2]'``.
-
-Run mypy in Python 2 mode by using the :option:`--py2 ` option::
-
- $ mypy --py2 program.py
-
-To run your program, you must have the ``typing`` module in your
-Python 2 module search path. Use ``pip install typing`` to install the
-module. This also works for Python 3 versions prior to 3.5 that don't
-include :py:mod:`typing` in the standard library.
-
-The example below illustrates the Python 2 function type annotation
-syntax. This syntax is also valid in Python 3 mode:
-
-.. code-block:: python
-
- from typing import List
-
- def hello(): # type: () -> None
- print 'hello'
-
- class Example:
- def method(self, lst, opt=0, *args, **kwargs):
- # type: (List[str], int, *str, **bool) -> int
- """Docstring comes after type comment."""
- ...
-
-It's worth going through these details carefully to avoid surprises:
-
-- You don't provide an annotation for the ``self`` / ``cls`` variable of
- methods.
-
-- Docstring always comes *after* the type comment.
-
-- For ``*args`` and ``**kwargs`` the type should be prefixed with
- ``*`` or ``**``, respectively (except when using the multi-line
- annotation syntax described below). Again, the above example
- illustrates this.
-
-- Things like ``Any`` must be imported from ``typing``, even if they
- are only used in comments.
-
-- In Python 2 mode ``str`` is implicitly promoted to ``unicode``, similar
- to how ``int`` is compatible with ``float``. This is unlike ``bytes`` and
- ``str`` in Python 3, which are incompatible. ``bytes`` in Python 2 is
- equivalent to ``str``. (This might change in the future.)
-
-.. _multi_line_annotation:
-
-Multi-line Python 2 function annotations
-----------------------------------------
-
-Mypy also supports a multi-line comment annotation syntax. You
-can provide a separate annotation for each argument using the variable
-annotation syntax. When using the single-line annotation syntax
-described above, functions with long argument lists tend to result in
-overly long type comments and it's often tricky to see which argument
-type corresponds to which argument. The alternative, multi-line
-annotation syntax makes long annotations easier to read and write.
-
-Here is an example (from :pep:`484`):
-
-.. code-block:: python
-
- def send_email(address, # type: Union[str, List[str]]
- sender, # type: str
- cc, # type: Optional[List[str]]
- bcc, # type: Optional[List[str]]
- subject='',
- body=None # type: List[str]
- ):
- # type: (...) -> bool
- """Send an email message. Return True if successful."""
-
-
-You write a separate annotation for each function argument on the same
-line as the argument. Each annotation must be on a separate line. If
-you leave out an annotation for an argument, it defaults to
-``Any``. You provide a return type annotation in the body of the
-function using the form ``# type: (...) -> rt``, where ``rt`` is the
-return type. Note that the return type annotation contains literal
-three dots.
-
-When using multi-line comments, you do not need to prefix the
-types of your ``*arg`` and ``**kwarg`` parameters with ``*`` or ``**``.
-For example, here is how you would annotate the first example using
-multi-line comments:
-
-.. code-block:: python
-
- from typing import List
-
- class Example:
- def method(self,
- lst, # type: List[str]
- opt=0, # type: int
- *args, # type: str
- **kwargs # type: bool
- ):
- # type: (...) -> int
- """Docstring comes after type comment."""
- ...
-
-
-Additional notes
-----------------
-
-- You should include types for arguments with default values in the
- annotation. The ``opt`` argument of ``method`` in the example at the
- beginning of this section is an example of this.
-
-- The annotation can be on the same line as the function header or on
- the following line.
-
-- Variables use a comment-based type syntax (explained in
- :ref:`explicit-var-types`).
-
-- You don't need to use string literal escapes for forward references
- within comments (string literal escapes are explained later).
-
-- Mypy uses a separate set of library stub files in `typeshed
- `_ for Python 2. Library support
- may vary between Python 2 and Python 3.
diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst
index d4061fc..b0cefec 100644
--- a/docs/source/running_mypy.rst
+++ b/docs/source/running_mypy.rst
@@ -26,10 +26,6 @@ Specifying code to be checked
Mypy lets you specify what files it should type check in several different ways.
-Note that if you use namespace packages (in particular, packages without
-``__init__.py``), you'll need to specify :option:`--namespace-packages `.
-
1. First, you can pass in paths to Python files and directories you
want to type check. For example::
@@ -81,7 +77,10 @@ Note that if you use namespace packages (in particular, packages without
$ mypy -c 'x = [1, 2]; print(x())'
...will type check the above string as a mini-program (and in this case,
- will report that ``List[int]`` is not callable).
+ will report that ``list[int]`` is not callable).
+
+You can also use the :confval:`files` option in your :file:`mypy.ini` file to specify which
+files to check, in which case you can simply run ``mypy`` with no arguments.
Reading a list of files from a file
@@ -104,6 +103,82 @@ flags, the recommended approach is to use a
:ref:`configuration file ` instead.
+.. _mapping-paths-to-modules:
+
+Mapping file paths to modules
+*****************************
+
+One of the main ways you can tell mypy what to type check
+is by providing mypy a list of paths. For example::
+
+ $ mypy file_1.py foo/file_2.py file_3.pyi some/directory
+
+This section describes how exactly mypy maps the provided paths
+to modules to type check.
+
+- Mypy will check all paths provided that correspond to files.
+
+- Mypy will recursively discover and check all files ending in ``.py`` or
+ ``.pyi`` in directory paths provided, after accounting for
+ :option:`--exclude `.
+
+- For each file to be checked, mypy will attempt to associate the file (e.g.
+ ``project/foo/bar/baz.py``) with a fully qualified module name (e.g.
+ ``foo.bar.baz``). The directory the package is in (``project``) is then
+ added to mypy's module search paths.
+
+How mypy determines fully qualified module names depends on if the options
+:option:`--no-namespace-packages ` and
+:option:`--explicit-package-bases ` are set.
+
+1. If :option:`--no-namespace-packages ` is set,
+ mypy will rely solely upon the presence of ``__init__.py[i]`` files to
+ determine the fully qualified module name. That is, mypy will crawl up the
+ directory tree for as long as it continues to find ``__init__.py`` (or
+ ``__init__.pyi``) files.
+
+ For example, if your directory tree consists of ``pkg/subpkg/mod.py``, mypy
+ would require ``pkg/__init__.py`` and ``pkg/subpkg/__init__.py`` to exist in
+ order correctly associate ``mod.py`` with ``pkg.subpkg.mod``
+
+2. The default case. If :option:`--namespace-packages ` is on, but :option:`--explicit-package-bases ` is off, mypy will allow for the possibility that
+ directories without ``__init__.py[i]`` are packages. Specifically, mypy will
+ look at all parent directories of the file and use the location of the
+ highest ``__init__.py[i]`` in the directory tree to determine the top-level
+ package.
+
+ For example, say your directory tree consists solely of ``pkg/__init__.py``
+ and ``pkg/a/b/c/d/mod.py``. When determining ``mod.py``'s fully qualified
+ module name, mypy will look at ``pkg/__init__.py`` and conclude that the
+ associated module name is ``pkg.a.b.c.d.mod``.
+
+3. You'll notice that the above case still relies on ``__init__.py``. If
+ you can't put an ``__init__.py`` in your top-level package, but still wish to
+ pass paths (as opposed to packages or modules using the ``-p`` or ``-m``
+ flags), :option:`--explicit-package-bases `
+ provides a solution.
+
+ With :option:`--explicit-package-bases `, mypy
+ will locate the nearest parent directory that is a member of the ``MYPYPATH``
+ environment variable, the :confval:`mypy_path` config or is the current
+ working directory. Mypy will then use the relative path to determine the
+ fully qualified module name.
+
+ For example, say your directory tree consists solely of
+ ``src/namespace_pkg/mod.py``. If you run the following command, mypy
+ will correctly associate ``mod.py`` with ``namespace_pkg.mod``::
+
+ $ MYPYPATH=src mypy --namespace-packages --explicit-package-bases .
+
+If you pass a file not ending in ``.py[i]``, the module name assumed is
+``__main__`` (matching the behavior of the Python interpreter), unless
+:option:`--scripts-are-modules ` is passed.
+
+Passing :option:`-v ` will show you the files and associated module
+names that mypy will check.
+
How mypy handles imports
************************
@@ -133,14 +208,12 @@ Missing imports
***************
When you import a module, mypy may report that it is unable to follow
-the import.
-
-This can cause errors that look like the following:
+the import. This can cause errors that look like the following:
.. code-block:: text
- main.py:1: error: Library stubs not installed for "requests" (or incompatible with Python 3.8)
- main.py:2: error: Skipping analyzing 'django': found module but no type hints or library stubs
+ main.py:1: error: Skipping analyzing 'django': module is installed, but missing library stubs or py.typed marker
+ main.py:2: error: Library stubs not installed for "requests"
main.py:3: error: Cannot find implementation or library stub for module named "this_module_does_not_exist"
If you get any of these errors on an import, mypy will assume the type of that
@@ -155,55 +228,19 @@ attribute of the module will automatically succeed:
# But this type checks, and x will have type 'Any'
x = does_not_exist.foobar()
-The next sections describe what each error means and recommended next steps.
-
-Library stubs not installed
----------------------------
-
-If mypy can't find stubs for a third-party library, and it knows that stubs exist for
-the library, you will get a message like this:
-
-.. code-block:: text
-
- main.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8)
- main.py:1: note: Hint: "python3 -m pip install types-PyYAML"
- main.py:1: note: (or run "mypy --install-types" to install all missing stub packages)
-
-You can resolve the issue by running the suggested pip command or
-commands. Alternatively, you can use :option:`--install-types ` to install all known missing stubs:
-
-.. code-block:: text
-
- mypy --install-types
-
-This installs any stub packages that were suggested in the previous
-mypy run. You can also use your normal mypy command line with the
-extra :option:`--install-types ` option to
-install missing stubs at the end of the run (if any were found).
-
-Use :option:`--install-types ` with
-:option:`--non-interactive ` to install all suggested
-stub packages without asking for confirmation, *and* type check your
-code, in a single command:
+This can result in mypy failing to warn you about errors in your code. Since
+operations on ``Any`` result in ``Any``, these dynamic types can propagate
+through your code, making type checking less effective. See
+:ref:`dynamic-typing` for more information.
-.. code-block:: text
-
- mypy --install-types --non-interactive src/
+The next sections describe what each of these errors means and recommended next steps; scroll to
+the section that matches your error.
-This can be useful in Continuous Integration jobs if you'd prefer not
-to manage stub packages manually. This is somewhat slower than
-explicitly installing stubs before running mypy, since it may type
-check your code twice -- the first time to find the missing stubs, and
-the second time to type check your code properly after mypy has
-installed the stubs.
-
-.. _missing-type-hints-for-third-party-library:
-Missing type hints for third party library
-------------------------------------------
+Missing library stubs or py.typed marker
+----------------------------------------
-If you are getting a "Skipping analyzing X: found module but no type hints or library stubs",
+If you are getting a ``Skipping analyzing X: module is installed, but missing library stubs or py.typed marker``,
error, this means mypy was able to find the module you were importing, but no
corresponding type hints.
@@ -213,12 +250,12 @@ unless they either have declared themselves to be
themselves on `typeshed `_, the repository
of types for the standard library and some 3rd party libraries.
-If you are getting this error, try:
+If you are getting this error, try to obtain type hints for the library you're using:
1. Upgrading the version of the library you're using, in case a newer version
has started to include type hints.
-2. Searching to see if there is a :ref:`PEP 561 compliant stub package `.
+2. Searching to see if there is a :ref:`PEP 561 compliant stub package `
corresponding to your third party library. Stub packages let you install
type hints independently from the library itself.
@@ -232,7 +269,7 @@ If you are getting this error, try:
adding the location to the ``MYPYPATH`` environment variable.
These stub files do not need to be complete! A good strategy is to use
- stubgen, a program that comes bundled with mypy, to generate a first
+ :ref:`stubgen `, a program that comes bundled with mypy, to generate a first
rough draft of the stubs. You can then iterate on just the parts of the
library you need.
@@ -241,16 +278,19 @@ If you are getting this error, try:
:ref:`PEP 561 compliant packages `.
If you are unable to find any existing type hints nor have time to write your
-own, you can instead *suppress* the errors. All this will do is make mypy stop
-reporting an error on the line containing the import: the imported module
-will continue to be of type ``Any``.
+own, you can instead *suppress* the errors.
+
+All this will do is make mypy stop reporting an error on the line containing the
+import: the imported module will continue to be of type ``Any``, and mypy may
+not catch errors in its use.
1. To suppress a *single* missing import error, add a ``# type: ignore`` at the end of the
line containing the import.
-2. To suppress *all* missing import imports errors from a single library, add
- a section to your :ref:`mypy config file ` for that library setting
- :confval:`ignore_missing_imports` to True. For example, suppose your codebase
+2. To suppress *all* missing import errors from a single library, add
+ a per-module section to your :ref:`mypy config file