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..34a3dbf 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,27 +1,30 @@
Metadata-Version: 2.1
Name: mypy
-Version: 0.910
+Version: 1.5.1
Summary: Optional static typing for Python
-Home-page: http://www.mypy-lang.org/
+Home-page: https://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: News, https://mypy-lang.org/news.html
+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.8
Provides-Extra: dmypy
Provides-Extra: python2
+Provides-Extra: reports
+Provides-Extra: install-types
License-File: LICENSE
Mypy -- Optional Static Typing for Python
@@ -33,5 +36,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..8b1ebbc 100644
--- a/README.md
+++ b/README.md
@@ -1,280 +1,193 @@
-
+
-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)
+[![Linting: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
+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:
-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.
+- 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)
-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:
+
+```python
+number = input("What is your favourite number?")
+print("It is", number + 1) # error: Unsupported operand types for + ("str" and "int")
+```
-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.
+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.
-In Ubuntu, Mint and Debian you can install Python 3 like this:
+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.
- $ sudo apt-get install python3 python3-pip
+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.
-For other Linux flavors, macOS and Windows, packages are available at
+See [the documentation](https://mypy.readthedocs.io/en/stable/index.html) for
+more examples and information.
- https://www.python.org/getit/
+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
-
-If you want to run the latest version of the code, you can install from git:
+```bash
+python3 -m pip install -U mypy
+```
- $ python3 -m pip install -U git+git://github.com/python/mypy.git
+If you want to run the latest version of the code, you can install from the
+repo directly:
+```bash
+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, 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:
+Now you can type-check the [statically typed parts] of a program like this:
- $ mypy PROGRAM
+```bash
+mypy PROGRAM
+```
-You can always use a Python interpreter to run your statically typed
-programs, even if they have type errors:
+You can always use the Python interpreter to run your statically typed
+programs, even if mypy reports type errors:
- $ python3 PROGRAM
+```bash
+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:
-[statically typed parts]: https://mypy.readthedocs.io/en/latest/getting_started.html#function-signatures-and-dynamic-vs-static-typing
+```bash
+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:
-* Vim:
- * Using [Syntastic](https://github.com/vim-syntastic/syntastic): in `~/.vimrc` add
+- Vim:
+ - Using [Syntastic](https://github.com/vim-syntastic/syntastic): in `~/.vimrc` add
`let g:syntastic_python_checkers=['mypy']`
- * Using [ALE](https://github.com/dense-analysis/ale): should be enabled by default when `mypy` is installed,
+ - 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)
-* 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))
-* 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
+- 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](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.
+- 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:
-
- http://www.mypy-lang.org/
-
-Or you can jump straight to the documentation:
-
- https://mypy.readthedocs.io/
-
-
-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`:
+Additional information is available at the web site:
- /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):
+Jump straight to the documentation:
- C:\>\Python34\python \Python34\Scripts\mypy PROGRAM
+
-### Working with `virtualenv`
+Follow along our changelog at:
-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
-
-
-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/
-
-
-Issue tracker
--------------
+Contributing
+------------
-Please report any bugs and enhancement ideas using the mypy issue
-tracker: https://github.com/python/mypy/issues
+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 have any questions about using mypy or types, please ask
-in the typing gitter instead: https://gitter.im/python/typing
+To get started with developing mypy, see [CONTRIBUTING.md](CONTRIBUTING.md).
+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
-
-If you wish to test out the compiled version of a development
-version of mypy, you can 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).
-
+```bash
+python3 -m pip install --no-binary mypy -U mypy
+```
-License
--------
+To use a compiled version of a development
+version of mypy, directly install a binary from
+.
-Mypy is licensed under the terms of the MIT License (see the file
-LICENSE).
+To contribute to the mypyc project, check out
diff --git a/build-requirements.txt b/build-requirements.txt
index eee2f9d..aac1b95 100644
--- a/build-requirements.txt
+++ b/build-requirements.txt
@@ -1,4 +1,4 @@
+# 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
diff --git a/conftest.py b/conftest.py
index 83a6689..4454b02 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):
@@ -12,7 +12,8 @@ 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
+# https://doc.pytest.org/en/latest/how-to/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..8b409aa 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,223 @@
+mypy (1.5.1-2) unstable; urgency=medium
+
+ * Demote armel/armhf to "-O2".
+
+ -- Michael R. Crusoe Fri, 18 Aug 2023 15:04:32 +0200
+
+mypy (1.5.1-1) unstable; urgency=medium
+
+ * New upstream version
+ * Build-Depends: s/dh-python/dh-sequence-python3/ (routine-update)
+ * d/source/lintian-overrides: update to match changes in upstream
+ * d/rules: skip the PEP561Suite tests which require internet access
+
+ -- Michael R. Crusoe Wed, 16 Aug 2023 19:44:24 +0200
+
+mypy (1.5.0-1) unstable; urgency=medium
+
+ * Team upload.
+ * New upstream release 1.5.0 (Closes: #1042039)
+ - Refresh patches
+ - Build-Depend on python3-attr
+
+ -- Nicolas Dandrimont Fri, 11 Aug 2023 13:05:43 +0200
+
+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..87cf7e1 100644
--- a/debian/control
+++ b/debian/control
@@ -1,37 +1,41 @@
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,
+ dh-sequence-python3,
+ python3-setuptools,
+ pybuild-plugin-pyproject,
+ python3-wheel,
flake8,
help2man,
python3-all,
python3-lxml,
+ python3-attr ,
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 +43,8 @@ Architecture: all
Depends: ${misc:Depends},
${python3:Depends},
python3-mypy (>= ${binary:Version})
-Suggests: mypy-doc
-Breaks: python3-mypy (= 0.740-1)
-Replaces: python3-mypy (= 0.740-1)
Recommends: python3-typeshed
+Suggests: mypy-doc
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 +56,7 @@ Description: optional static typing for Python
Package: mypy-doc
Architecture: all
+Multi-Arch: foreign
Section: doc
Depends: ${misc:Depends},
${sphinxdoc:Depends}
@@ -79,12 +82,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..fa923f2 100644
--- a/debian/patches/intersphinx
+++ b/debian/patches/intersphinx
@@ -1,23 +1,40 @@
-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
---- mypy.orig/docs/source/conf.py
-+++ mypy/docs/source/conf.py
-@@ -271,12 +271,12 @@
- rst_prolog = '.. |...| unicode:: U+2026 .. ellipsis\n'
+---
+ docs/source/conf.py | 19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/docs/source/conf.py b/docs/source/conf.py
+index 683b2a6..f4016c6 100644
+--- a/docs/source/conf.py
++++ b/docs/source/conf.py
+@@ -265,12 +265,21 @@ texinfo_documents = [
+ 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": ("https://www.attrs.org/en/stable/", None),
+- "cython": ("https://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": (
++ "https://www.attrs.org/en/stable",
++ "/usr/share/doc/python-attr-doc/html/objects.inv",
++ ),
++ "cython": ("https://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..b5e7fba
--- /dev/null
+++ b/debian/patches/python3.10.3
@@ -0,0 +1,35 @@
+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(+)
+
+diff --git a/test-data/unit/cmdline.test b/test-data/unit/cmdline.test
+index 6e9fdf6..38bc274 100644
+--- a/test-data/unit/cmdline.test
++++ b/test-data/unit/cmdline.test
+@@ -1289,6 +1289,10 @@ Found 1 error in 1 file (errors prevented further checking)
+ 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..b855693 100644
--- a/debian/patches/verbose
+++ b/debian/patches/verbose
@@ -1,13 +1,21 @@
-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
---- mypy.orig/setup.py
-+++ mypy/setup.py
-@@ -151,6 +151,7 @@
+---
+ setup.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/setup.py b/setup.py
+index bbb655e..eb6d57b 100644
+--- a/setup.py
++++ b/setup.py
+@@ -173,6 +173,7 @@ if USE_MYPYC:
# 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:
- ext_modules = []
+ assert is_list_of_setuptools_extension(ext_modules), "Expected mypycify to use setuptools"
+
diff --git a/debian/rules b/debian/rules
index a436480..1467219 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
@@ -8,13 +6,13 @@ PY3VERS=$(shell py3versions -vr)
include /usr/share/dpkg/pkg-info.mk
ifeq (,$(filter nodoc,$(DEB_BUILD_PROFILES)))
- WITH += ,sphinxdoc
+ WITH += --with sphinxdoc
endif
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
include /usr/share/dpkg/default.mk
-ifneq (,$(filter $(DEB_BUILD_ARCH),hppa))
+ifneq (,$(filter $(DEB_BUILD_ARCH),hppa armel armhf))
export MYPYC_OPT_LEVEL=2
else ifeq ($(DEB_HOST_ARCH_BITS), 32)
export DEB_CFLAGS_MAINT_APPEND += -g1
@@ -23,7 +21,7 @@ endif
%:
- dh $@ --with python3$(WITH) --buildsystem=pybuild
+ dh $@ $(WITH) --buildsystem=pybuild
ifeq (,$(filter nodoc,$(DEB_BUILD_PROFILES)))
manpages: debian/sphinx/mypy_options.rst debian/sphinx/stubgen_options.rst debian/dmypy.1 debian/mypy.1 debian/stubgen.1
@@ -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 or PEP561Suite)' \
+ -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..e1be2a5
--- /dev/null
+++ b/debian/source/lintian-overrides
@@ -0,0 +1,3 @@
+#uses-python-distutils [mypyc/build.py:*]
+uses-python-distutils [mypyc/lib-rt/setup.py:*]
+#uses-python-distutils [test-data/packages/typedpkg_ns_b-stubs/setup.py:*]
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/Makefile b/docs/Makefile
index be69e9d..c87c4c1 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -9,7 +9,7 @@ BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
-$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://www.sphinx-doc.org/)
endif
# Internal variables.
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/make.bat b/docs/make.bat
index 1e3d843..3664bed 100755
--- a/docs/make.bat
+++ b/docs/make.bat
@@ -56,7 +56,7 @@ if errorlevel 9009 (
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
- echo.http://sphinx-doc.org/
+ echo.https://www.sphinx-doc.org/
exit /b 1
)
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..5dd1364 100644
--- a/docs/source/additional_features.rst
+++ b/docs/source/additional_features.rst
@@ -9,10 +9,9 @@ of the previous sections.
Dataclasses
***********
-In Python 3.7, a new :py:mod:`dataclasses` module has been added to the standard library.
-This module allows defining and customizing simple boilerplate-free classes.
-They can be defined using the :py:func:`@dataclasses.dataclass
-` decorator:
+The :py:mod:`dataclasses` module allows defining and customizing simple
+boilerplate-free classes. They can be defined using the
+:py:func:`@dataclasses.dataclass ` decorator:
.. code-block:: python
@@ -21,10 +20,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:
@@ -121,55 +120,54 @@ Type annotations can be added as follows:
import attr
- @attr.s
+ @attrs.define
class A:
- one: int = attr.ib() # Variable annotation (Python 3.6+)
- two = attr.ib() # type: int # Type comment
- three = attr.ib(type=int) # type= argument
+ one: int
+ two: int = 7
+ three: int = attrs.field(8)
-If you're using ``auto_attribs=True`` you must use variable annotations.
+If you're using ``auto_attribs=False`` you must use ``attrs.field``:
.. code-block:: python
- import attr
+ import attrs
- @attr.s(auto_attribs=True)
+ @attrs.define
class A:
- one: int
- two: int = 7
- three: int = attr.ib(8)
+ one: int = attrs.field() # Variable annotation (Python 3.6+)
+ two = attrs.field() # type: int # Type comment
+ three = attrs.field(type=int) # type= argument
Typeshed has a couple of "white lie" annotations to make type checking
-easier. :py:func:`attr.ib` and :py:class:`attr.Factory` actually return objects, but the
+easier. :py:func:`attrs.field` and :py:class:`attrs.Factory` actually return objects, but the
annotation says these return the types that they expect to be assigned to.
That enables this to work:
.. code-block:: python
- import attr
- from typing import Dict
+ import attrs
- @attr.s(auto_attribs=True)
+ @attrs.define
class A:
- one: int = attr.ib(8)
- two: Dict[str, str] = attr.Factory(dict)
- bad: str = attr.ib(16) # Error: can't assign int to str
+ one: int = attrs.field(8)
+ two: dict[str, str] = attrs.Factory(dict)
+ bad: str = attrs.field(16) # Error: can't assign int to str
Caveats/Known Issues
====================
* The detection of attr classes and attributes works by function name only.
This means that if you have your own helper functions that, for example,
- ``return attr.ib()`` mypy will not see them.
+ ``return attrs.field()`` mypy will not see them.
* All boolean arguments that mypy cares about must be literal ``True`` or ``False``.
e.g the following will not work:
.. code-block:: python
- import attr
+ import attrs
YES = True
- @attr.s(init=YES)
+ @attrs.define(init=YES)
class A:
...
@@ -177,8 +175,8 @@ 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 `
- and `default decorators `_
+* :ref:`Validator decorators `
+ and `default decorators `_
are not type-checked against the attribute they are setting/validating.
* Method definitions added by mypy currently overwrite any existing method
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..297427e 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 can be useful in conditional branches
child: bool
if age < 18:
child = True
@@ -40,62 +29,66 @@ 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 in the annotation
+ # 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()
- # Mypy understands a value can't be None in an if-statement
+ 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
if x is not None:
+ # Mypy understands x won't be None here because of the if-statement
print(x.upper())
- # If a value can never be None due to some invariants, use an assert
+ # If you know a value can never be None due to some logic that mypy doesn't
+ # understand, use an assert
assert x is not None
print(x.upper())
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 +98,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]
+
+ 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: ...
+ 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
- a.foo = 42 # Works
- a.bar = 'Ex-parrot' # Fails type checking
+In some cases type annotations can cause issues at runtime, see
+:ref:`runtime_troubles` for dealing with this.
+See :ref:`silencing-type-errors` for details on how to silence errors.
Standard "duck types"
*********************
@@ -209,99 +271,35 @@ 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())
f({3: 'yes', 4: 'no'})
-
-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
-**********************
-
-See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.
-
-.. code-block:: python
-
- import asyncio
-
- # 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))
- await asyncio.sleep(0.1)
- count -= 1
- return "Blastoff!"
-
-
-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
+ # Use IO[str] or IO[bytes] for functions that should accept or return
+ # objects that come from an open() call (note that IO does not
# distinguish between reading, writing or other modes)
def get_sys_IO(mode: str = 'w') -> IO[str]:
if mode == 'w':
@@ -311,19 +309,38 @@ Miscellaneous
else:
return sys.stdout
- # Forward references are useful if you want to reference a class before
- # it is defined
- def f(foo: A) -> int: # This will fail
+
+You can even make your own duck types using :ref:`protocol-types`.
+
+Forward references
+******************
+
+.. code-block:: python
+
+ # You may want to reference a class before it is defined.
+ # This is known as a "forward reference".
+ def f(foo: A) -> int: # This will fail at runtime with 'A' is not defined
...
- class A:
+ # However, if you add the following special import:
+ from __future__ import annotations
+ # It will work at runtime and type checking will succeed as long as there
+ # is a class of that name later on in the file
+ def f(foo: A) -> int: # Ok
...
- # If you use the string literal 'A', it will pass as long as there is a
- # class of that name later on in the file
- def f(foo: 'A') -> int: # Ok
+ # Another option is to just put the type in quotes
+ def f(foo: 'A') -> int: # Also ok
...
+ class A:
+ # This can also come up if you need to reference a class in a type
+ # annotation inside the definition of that class
+ @classmethod
+ def create(cls) -> A:
+ ...
+
+See :ref:`forward-references` for more details.
Decorators
**********
@@ -342,3 +359,20 @@ Decorator functions can be expressed via generics. See
def decorator_args(url: str) -> Callable[[F], F]:
...
+
+Coroutines and asyncio
+**********************
+
+See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.
+
+.. code-block:: python
+
+ import asyncio
+
+ # A coroutine is typed like a normal function
+ async def countdown(tag: str, count: int) -> str:
+ while count > 0:
+ print(f'T-minus {count} ({tag})')
+ await asyncio.sleep(0.1)
+ count -= 1
+ return "Blastoff!"
diff --git a/docs/source/class_basics.rst b/docs/source/class_basics.rst
index 330d980..73f95f1 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,9 +205,41 @@ 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.
+In order to ensure that your code remains correct when renaming methods,
+it can be helpful to explicitly mark a method as overriding a base
+method. This can be done with the ``@override`` decorator. ``@override``
+can be imported from ``typing`` starting with Python 3.12 or from
+``typing_extensions`` for use with older Python versions. If the base
+method is then renamed while the overriding method is not, mypy will
+show an error:
+
+.. code-block:: python
+
+ from typing import override
+
+ class Base:
+ def f(self, x: int) -> None:
+ ...
+ def g_renamed(self, y: str) -> None:
+ ...
+
+ class Derived1(Base):
+ @override
+ def f(self, x: int) -> None: # OK
+ ...
+
+ @override
+ def g(self, y: str) -> None: # Error: no corresponding base method found
+ ...
+
+.. note::
+
+ Use :ref:`--enable-error-code explicit-override ` to require
+ that method overrides use the ``@override`` decorator. Emit an error if it is missing.
+
You can also override a statically typed method with a dynamically
typed one. This allows dynamically typed code to override methods
defined in library classes without worrying about their type
@@ -261,11 +292,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 +340,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 +367,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..d9de5cd 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
@@ -339,12 +353,17 @@ definitions or calls.
.. option:: --disallow-untyped-defs
This flag reports an error whenever it encounters a function definition
- without type annotations.
+ without type annotations or with incomplete type annotations.
+ (a superset of :option:`--disallow-incomplete-defs`).
+
+ For example, it would report an error for :code:`def f(a, b)` and :code:`def f(a: int, b)`.
.. option:: --disallow-incomplete-defs
This flag reports an error whenever it encounters a partly annotated
- function definition.
+ function definition, while still allowing entirely unannotated definitions.
+
+ For example, it would report an error for :code:`def f(a: int, b)` but not :code:`def f(a, b)`.
.. option:: --check-untyped-defs
@@ -370,29 +389,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 +424,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 +453,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 +527,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 +555,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 +580,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 +600,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!
...
@@ -584,6 +612,34 @@ of the above sections.
assert text is not None # OK, check against None is allowed as a special case.
+.. option:: --extra-checks
+
+ This flag enables additional checks that are technically correct but may be
+ impractical in real code. In particular, it prohibits partial overlap in
+ ``TypedDict`` updates, and makes arguments prepended via ``Concatenate``
+ positional-only. For example:
+
+ .. code-block:: python
+
+ from typing import TypedDict
+
+ class Foo(TypedDict):
+ a: int
+
+ class Bar(TypedDict):
+ a: int
+ b: int
+
+ def test(foo: Foo, bar: Bar) -> None:
+ # This is technically unsafe since foo can have a subtype of Foo at
+ # runtime, where type of key "b" is incompatible with int, see below
+ bar.update(foo)
+
+ class Bad(Foo):
+ b: str
+ bad: Bad = {"a": 0, "b": "no"}
+ test(bad, bar)
+
.. option:: --strict
This flag mode enables all optional error checking flags. You can see the
@@ -595,6 +651,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 +659,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 +717,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 +852,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 +908,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 +940,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..e6570b7 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. Example: ``# mypy: disable-error-code="truthy-bool, ignore-without-code"``
+* 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..683b2a6 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", "docs.source.html_builder"]
# 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": ("https://www.attrs.org/en/stable/", None),
+ "cython": ("https://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..9e79ff9 100644
--- a/docs/source/config_file.rst
+++ b/docs/source/config_file.rst
@@ -3,17 +3,22 @@
The mypy configuration file
===========================
-Mypy supports reading configuration settings from a file. By default
-it uses the file ``mypy.ini`` with a fallback to ``.mypy.ini``, then ``pyproject.toml``,
-then ``setup.cfg`` in the current directory, then ``$XDG_CONFIG_HOME/mypy/config``, then
-``~/.config/mypy/config``, and finally ``.mypy.ini`` in the user home directory
-if none of them are found; the :option:`--config-file ` command-line flag can be used
-to read a different file instead (see :ref:`config-file-flag`).
+Mypy supports reading configuration settings from a file with the following precedence order:
+
+ 1. ``./mypy.ini``
+ 2. ``./.mypy.ini``
+ 3. ``./pyproject.toml``
+ 4. ``./setup.cfg``
+ 5. ``$XDG_CONFIG_HOME/mypy/config``
+ 6. ``~/.config/mypy/config``
+ 7. ``~/.mypy.ini``
It is important to understand that there is no merging of configuration
-files, as it would lead to ambiguity. The :option:`--config-file ` flag
-has the highest precedence and must be correct; otherwise mypy will report
-an error and exit. Without command line option, mypy will look for configuration files in the above mentioned order.
+files, as it would lead to ambiguity. The :option:`--config-file `
+command-line flag has the highest precedence and
+must be correct; otherwise mypy will report an error and exit. Without the
+command line option, mypy will look for configuration files in the
+precedence order above.
Most flags correspond closely to :ref:`command-line flags
` but there are some differences in flag names and some
@@ -103,8 +108,8 @@ their name or by (when applicable) swapping their prefix from
``disallow`` to ``allow`` (and vice versa).
-Examples
-********
+Example ``mypy.ini``
+********************
Here is an example of a ``mypy.ini`` file. To use this config file, place it at the root
of your repo and run mypy.
@@ -114,7 +119,6 @@ of your repo and run mypy.
# Global options:
[mypy]
- python_version = 2.7
warn_return_any = True
warn_unused_configs = True
@@ -129,16 +133,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 +196,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 +297,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 +326,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.
@@ -290,7 +366,7 @@ section of the command line docs.
.. confval:: no_site_packages
- :type: bool
+ :type: boolean
:default: False
Disables using type information in installed packages (see :pep:`561`).
@@ -319,7 +395,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.
@@ -422,14 +498,19 @@ section of the command line docs.
:default: False
Disallows defining functions without type annotations or with incomplete type
- annotations.
+ annotations (a superset of :confval:`disallow_incomplete_defs`).
+
+ For example, it would report an error for :code:`def f(a, b)` and :code:`def f(a: int, b)`.
.. confval:: disallow_incomplete_defs
:type: boolean
:default: False
- Disallows defining functions with incomplete type annotations.
+ Disallows defining functions with incomplete type annotations, while still
+ allowing entirely unannotated definitions.
+
+ For example, it would report an error for :code:`def f(a: int, b)` but not :code:`def f(a, b)`.
.. confval:: check_untyped_defs
@@ -455,13 +536,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 +609,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 +638,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 +671,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 +699,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 +714,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 +749,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 +885,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 +911,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 +930,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 +940,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 +972,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 +982,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 +1025,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 +1067,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 +1085,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..f935e02 100644
--- a/docs/source/error_code_list.rst
+++ b/docs/source/error_code_list.rst
@@ -8,6 +8,8 @@ with default options. See :ref:`error-codes` for general documentation
about error codes. :ref:`error-codes-optional` documents additional
error codes that you can enable.
+.. _code-attr-defined:
+
Check that attribute exists [attr-defined]
------------------------------------------
@@ -43,6 +45,8 @@ A reference to a missing attribute is given the ``Any`` type. In the
above example, the type of ``non_existent`` will be ``Any``, which can
be important if you silence the error.
+.. _code-union-attr:
+
Check that attribute exists in each union item [union-attr]
-----------------------------------------------------------
@@ -75,6 +79,8 @@ You can often work around these errors by using ``assert isinstance(obj, ClassNa
or ``assert obj is not None`` to tell mypy that you know that the type is more specific
than what mypy thinks.
+.. _code-name-defined:
+
Check that name is defined [name-defined]
-----------------------------------------
@@ -89,6 +95,25 @@ This example accidentally calls ``sort()`` instead of :py:func:`sorted`:
x = sort([3, 2, 4]) # Error: Name "sort" is not defined [name-defined]
+.. _code-used-before-def:
+
+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
+
+.. _code-call-arg:
+
Check arguments in calls [call-arg]
-----------------------------------
@@ -107,6 +132,8 @@ Example:
greet('jack') # OK
greet('jill', 'jack') # Error: Too many arguments for "greet" [call-arg]
+.. _code-arg-type:
+
Check argument types [arg-type]
-------------------------------
@@ -117,15 +144,17 @@ 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))
+
+.. _code-call-overload:
Check calls to overloaded functions [call-overload]
---------------------------------------------------
@@ -158,6 +187,8 @@ Example:
# Error: No overload variant of "inc_maybe" matches argument type "float" [call-overload]
inc_maybe(1.2)
+.. _code-valid-type:
+
Check validity of types [valid-type]
------------------------------------
@@ -171,26 +202,26 @@ 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)
+
+.. _code-var-annotated:
Require annotation if variable type is unclear [var-annotated]
--------------------------------------------------------------
@@ -206,26 +237,26 @@ 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]
+.. _code-override:
+
Check validity of overrides [override]
--------------------------------------
@@ -262,6 +293,8 @@ Example:
arg: bool) -> int:
...
+.. _code-return:
+
Check that function returns a value [return]
--------------------------------------------
@@ -290,6 +323,40 @@ Example:
else:
raise ValueError('not defined for zero')
+.. _code-empty-body:
+
+Check that functions don't have empty bodies outside stubs [empty-body]
+-----------------------------------------------------------------------
+
+This error code is similar to the ``[return]`` code but is emitted specifically
+for functions and methods with empty bodies (if they are annotated with
+non-trivial return type). Such a distinction exists because in some contexts
+an empty body can be valid, for example for an abstract method or in a stub
+file. Also old versions of mypy used to unconditionally allow functions with
+empty bodies, so having a dedicated error code simplifies cross-version
+compatibility.
+
+Note that empty bodies are allowed for methods in *protocols*, and such methods
+are considered implicitly abstract:
+
+.. code-block:: python
+
+ from abc import abstractmethod
+ from typing import Protocol
+
+ class RegularABC:
+ @abstractmethod
+ def foo(self) -> int:
+ pass # OK
+ def bar(self) -> int:
+ pass # Error: Missing return statement [empty-body]
+
+ class Proto(Protocol):
+ def bar(self) -> int:
+ pass # OK
+
+.. _code-return-value:
+
Check that return value is compatible [return-value]
----------------------------------------------------
@@ -304,6 +371,8 @@ Example:
# Error: Incompatible return value type (got "int", expected "str") [return-value]
return x + 1
+.. _code-assignment:
+
Check types in assignment statement [assignment]
------------------------------------------------
@@ -326,6 +395,39 @@ Example:
# variable has type "str") [assignment]
r.name = 5
+.. _code-method-assign:
+
+Check that assignment target is not a method [method-assign]
+------------------------------------------------------------
+
+In general, assigning to a method on class object or instance (a.k.a.
+monkey-patching) is ambiguous in terms of types, since Python's static type
+system cannot express the difference between bound and unbound callable types.
+Consider this example:
+
+.. code-block:: python
+
+ class A:
+ def f(self) -> None: pass
+ def g(self) -> None: pass
+
+ def h(self: A) -> None: pass
+
+ A.f = h # Type of h is Callable[[A], None]
+ A().f() # This works
+ A.f = A().g # Type of A().g is Callable[[], None]
+ A().f() # ...but this also works at runtime
+
+To prevent the ambiguity, mypy will flag both assignments by default. If this
+error code is disabled, mypy will treat the assigned value in all method assignments as unbound,
+so only the second assignment will still generate an error.
+
+.. note::
+
+ This error code is a subcode of the more general ``[assignment]`` code.
+
+.. _code-type-var:
+
Check type variable values [type-var]
-------------------------------------
@@ -348,6 +450,8 @@ Example:
# Error: Value of type variable "T1" of "add" cannot be "str" [type-var]
add('x', 'y')
+.. _code-operator:
+
Check uses of various operators [operator]
------------------------------------------
@@ -362,6 +466,8 @@ Example:
# Error: Unsupported operand types for + ("int" and "str") [operator]
1 + 'x'
+.. _code-index:
+
Check indexing operations [index]
---------------------------------
@@ -377,12 +483,14 @@ 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
+.. _code-list-item:
+
Check list items [list-item]
----------------------------
@@ -394,10 +502,10 @@ 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]
+
+.. _code-dict-item:
Check dict items [dict-item]
----------------------------
@@ -410,19 +518,19 @@ 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'}
+
+.. _code-typeddict-item:
Check TypedDict items [typeddict-item]
--------------------------------------
-When constructing a ``TypedDict`` object, mypy checks that each key and value is compatible
-with the ``TypedDict`` type that is inferred from the surrounding context.
+When constructing a TypedDict object, mypy checks that each key and value is compatible
+with the TypedDict type that is inferred from the surrounding context.
-When getting a ``TypedDict`` item, mypy checks that the key
-exists. When assigning to a ``TypedDict``, mypy checks that both the
+When getting a TypedDict item, mypy checks that the key
+exists. When assigning to a TypedDict, mypy checks that both the
key and the value are valid.
Example:
@@ -439,6 +547,66 @@ Example:
# TypedDict item "x" has type "int") [typeddict-item]
p: Point = {'x': 1.2, 'y': 4}
+.. _code-typeddict-unknown-key:
+
+Check TypedDict Keys [typeddict-unknown-key]
+--------------------------------------------
+
+When constructing a TypedDict object, mypy checks whether the
+definition contains unknown keys, to catch invalid keys and
+misspellings. On the other hand, mypy will not generate an error when
+a previously constructed TypedDict value with extra keys is passed
+to a function as an argument, since TypedDict values support
+structural subtyping ("static duck typing") and the keys are assumed
+to have been validated at the point of construction. Example:
+
+.. code-block:: python
+
+ from typing_extensions import TypedDict
+
+ class Point(TypedDict):
+ x: int
+ y: int
+
+ class Point3D(Point):
+ z: int
+
+ def add_x_coordinates(a: Point, b: Point) -> int:
+ return a["x"] + b["x"]
+
+ a: Point = {"x": 1, "y": 4}
+ b: Point3D = {"x": 2, "y": 5, "z": 6}
+
+ add_x_coordinates(a, b) # OK
+
+ # Error: Extra key "z" for TypedDict "Point" [typeddict-unknown-key]
+ add_x_coordinates(a, {"x": 1, "y": 4, "z": 5})
+
+Setting a TypedDict item using an unknown key will also generate this
+error, since it could be a misspelling:
+
+.. code-block:: python
+
+ a: Point = {"x": 1, "y": 2}
+ # Error: Extra key "z" for TypedDict "Point" [typeddict-unknown-key]
+ a["z"] = 3
+
+Reading an unknown key will generate the more general (and serious)
+``typeddict-item`` error, which is likely to result in an exception at
+runtime:
+
+.. code-block:: python
+
+ a: Point = {"x": 1, "y": 2}
+ # Error: TypedDict "Point" has no key "z" [typeddict-item]
+ _ = a["z"]
+
+.. note::
+
+ This error code is a subcode of the wider ``[typeddict-item]`` code.
+
+.. _code-has-type:
+
Check that type of target is known [has-type]
---------------------------------------------
@@ -478,6 +646,8 @@ the issue:
def set_y(self) -> None:
self.y: int = self.x # Added annotation here
+.. _code-import:
+
Check that import target can be found [import]
----------------------------------------------
@@ -493,6 +663,8 @@ Example:
See :ref:`ignore-missing-imports` for how to work around these errors.
+.. _code-no-redef:
+
Check that each name is defined once [no-redef]
-----------------------------------------------
@@ -519,6 +691,8 @@ Example:
# (the first definition wins!)
A('x')
+.. _code-func-returns-value:
+
Check that called function returns a value [func-returns-value]
---------------------------------------------------------------
@@ -541,11 +715,13 @@ returns ``None``:
if f():
print("not false")
+.. _code-abstract:
+
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 +748,60 @@ Example:
# Error: Cannot instantiate abstract class "Thing" with abstract attribute "save" [abstract]
t = Thing()
+.. _code-type-abstract:
+
+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)
+
+.. _code-safe-super:
+
+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.
+
+.. _code-valid-newtype:
+
Check the target of NewType [valid-newtype]
-------------------------------------------
@@ -596,6 +826,8 @@ To work around the issue, you can either give mypy access to the sources
for ``acme`` or create a stub file for the module. See :ref:`ignore-missing-imports`
for more information.
+.. _code-exit-return:
+
Check the return type of __exit__ [exit-return]
-----------------------------------------------
@@ -652,6 +884,8 @@ You can also use ``None``:
def __exit__(self, exc, value, tb) -> None: # Also OK
print('exit')
+.. _code-name-match:
+
Check that naming is consistent [name-match]
--------------------------------------------
@@ -665,6 +899,204 @@ 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)])
+.. _code-literal-required:
+
+Check that literal is used where expected [literal-required]
+------------------------------------------------------------
+
+There are some places where only a (string) literal value is expected for
+the purposes of static type checking, for example a ``TypedDict`` key, or
+a ``__match_args__`` item. Providing a ``str``-valued variable in such contexts
+will result in an error. Note that in many cases you can also use ``Final``
+or ``Literal`` variables. Example:
+
+.. code-block:: python
+
+ from typing import Final, Literal, TypedDict
+
+ class Point(TypedDict):
+ x: int
+ y: int
+
+ def test(p: Point) -> None:
+ X: Final = "x"
+ p[X] # OK
+
+ Y: Literal["y"] = "y"
+ p[Y] # OK
+
+ key = "x" # Inferred type of key is `str`
+ # Error: TypedDict key must be a string literal;
+ # expected one of ("x", "y") [literal-required]
+ p[key]
+
+.. _code-no-overload-impl:
+
+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
+
+.. _code-unused-coroutine:
+
+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
+
+.. _code-top-level-await:
+
+Warn about top level await expressions [top-level-await]
+--------------------------------------------------------
+
+This error code is separate from the general ``[syntax]`` errors, because in
+some environments (e.g. IPython) a top level ``await`` is allowed. In such
+environments a user may want to use ``--disable-error-code=top-level-await``,
+that allows to still have errors for other improper uses of ``await``, for
+example:
+
+.. code-block:: python
+
+ async def f() -> None:
+ ...
+
+ top = await f() # Error: "await" outside function [top-level-await]
+
+ def g() -> None:
+ # This is a blocker error and cannot be silenced.
+ await f() # Error: "await" outside coroutine ("async def")
+
+.. _code-assert-type:
+
+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
+
+.. _code-truthy-function:
+
+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
+
+.. _code-str-format:
+
+Check that string formatting/interpolation is type-safe [str-format]
+--------------------------------------------------------------------
+
+Mypy will check that f-strings, ``str.format()`` calls, and ``%`` interpolations
+are valid (when corresponding template is a literal string). This includes
+checking number and types of replacements, for example:
+
+.. code-block:: python
+
+ # Error: Cannot find replacement for positional format specifier 1 [str-format]
+ "{} and {}".format("spam")
+ "{} and {}".format("spam", "eggs") # OK
+ # Error: Not all arguments converted during string formatting [str-format]
+ "{} and {}".format("spam", "eggs", "cheese")
+
+ # Error: Incompatible types in string interpolation
+ # (expression has type "float", placeholder has type "int") [str-format]
+ "{:d}".format(3.14)
+
+.. _code-str-bytes-safe:
+
+Check for implicit bytes coercions [str-bytes-safe]
+-------------------------------------------------------------------
+
+Warn about cases where a bytes object may be converted to a string in an unexpected manner.
+
+.. code-block:: python
+
+ b = b"abc"
+
+ # Error: If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc".
+ # If this is desired behavior, use f"{x!r}" or "{!r}".format(x).
+ # Otherwise, decode the bytes [str-bytes-safe]
+ print(f"The alphabet starts with {b}")
+
+ # Okay
+ print(f"The alphabet starts with {b!r}") # The alphabet starts with b'abc'
+ print(f"The alphabet starts with {b.decode('utf-8')}") # The alphabet starts with abc
+
+.. _code-annotation-unchecked:
+
+Notify about an annotation in an unchecked function [annotation-unchecked]
+--------------------------------------------------------------------------
+
+Sometimes a user may accidentally omit an annotation for a function, and mypy
+will not check the body of this function (unless one uses
+:option:`--check-untyped-defs ` or
+:option:`--disallow-untyped-defs `). To avoid
+such situations go unnoticed, mypy will show a note, if there are any type
+annotations in an unchecked function:
+
+.. code-block:: python
+
+ def test_assignment(): # "-> None" return annotation is missing
+ # Note: By default the bodies of untyped functions are not checked,
+ # consider using --check-untyped-defs [annotation-unchecked]
+ x: int = "no way"
+
+Note that mypy will still exit with return code ``0``, since such behaviour is
+specified by :pep:`484`.
+
+.. _code-syntax:
+
Report syntax errors [syntax]
-----------------------------
@@ -672,6 +1104,8 @@ If the code being checked is not syntactically valid, mypy issues a
syntax error. Most, but not all, syntax errors are *blocking errors*:
they can't be ignored with a ``# type: ignore`` comment.
+.. _code-misc:
+
Miscellaneous checks [misc]
---------------------------
diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst
index d88525f..30fad07 100644
--- a/docs/source/error_code_list2.rst
+++ b/docs/source/error_code_list2.rst
@@ -15,14 +15,16 @@ error codes that are enabled by default.
options by using a :ref:`configuration file ` or
:ref:`command-line options `.
+.. _code-type-arg:
+
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,12 +32,12 @@ 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:
...
+.. _code-no-untyped-def:
+
Check that every function has an annotation [no-untyped-def]
------------------------------------------------------------
@@ -64,6 +66,8 @@ Example:
def __init__(self) -> None:
self.value = 0
+.. _code-redundant-cast:
+
Check that cast is not redundant [redundant-cast]
-------------------------------------------------
@@ -84,6 +88,32 @@ Example:
# Error: Redundant cast to "int" [redundant-cast]
return cast(int, x)
+.. _code-redundant-self:
+
+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)()
+
+.. _code-comparison-overlap:
+
Check that comparisons are overlapping [comparison-overlap]
-----------------------------------------------------------
@@ -115,6 +145,8 @@ literal:
def is_magic(x: bytes) -> bool:
return x == b'magic' # OK
+.. _code-no-untyped-call:
+
Check that no untyped functions are called [no-untyped-call]
------------------------------------------------------------
@@ -134,6 +166,7 @@ Example:
def bad():
...
+.. _code-no-any-return:
Check that function does not return Any value [no-any-return]
-------------------------------------------------------------
@@ -155,6 +188,8 @@ Example:
# Error: Returning Any from function declared to return "str" [no-any-return]
return fields(x)[0]
+.. _code-no-any-unimported:
+
Check that types have no Any components due to missing imports [no-any-unimported]
----------------------------------------------------------------------------------
@@ -175,6 +210,8 @@ that ``Cat`` falls back to ``Any`` in a type annotation:
def feed(cat: Cat) -> None:
...
+.. _code-unreachable:
+
Check that statement or expression is unreachable [unreachable]
---------------------------------------------------------------
@@ -194,6 +231,8 @@ incorrect control flow or conditional checks that are accidentally always true o
# Error: Statement is unreachable [unreachable]
print('unreachable')
+.. _code-redundant-expr:
+
Check that expression is redundant [redundant-expr]
---------------------------------------------------
@@ -202,7 +241,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 +253,231 @@ 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)]
+
+
+.. _code-possibly-undefined:
+
+Warn about variables that are defined only in some execution paths [possibly-undefined]
+---------------------------------------------------------------------------------------
+
+If you use :option:`--enable-error-code possibly-undefined `,
+mypy generates an error if it cannot verify that a variable will be defined in
+all execution paths. This includes situations when a variable definition
+appears in a loop, in a conditional branch, in an except handler, etc. For
+example:
+
+.. code-block:: python
+
+ # Use "mypy --enable-error-code possibly-undefined ..."
+
+ from typing import Iterable
+
+ def test(values: Iterable[int], flag: bool) -> None:
+ if flag:
+ a = 1
+ z = a + 1 # Error: Name "a" may be undefined [possibly-undefined]
+
+ for v in values:
+ b = v
+ z = b + 1 # Error: Name "b" may be undefined [possibly-undefined]
+
+.. _code-truthy-bool:
+
+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:
+ ...
+
+.. _code-truthy-iterable:
+
+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]``.
+
+.. _code-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]
+
+.. _code-unused-awaitable:
+
+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
+
+.. _code-unused-ignore:
+
+Check that ``# type: ignore`` comment is used [unused-ignore]
+-------------------------------------------------------------
+
+If you use :option:`--enable-error-code unused-ignore `,
+or :option:`--warn-unused-ignores `
+mypy generates an error if you don't use a ``# type: ignore`` comment, i.e. if
+there is a comment, but there would be no error generated by mypy on this line
+anyway.
+
+Example:
+
+.. code-block:: python
+
+ # Use "mypy --warn-unused-ignores ..."
+
+ def add(a: int, b: int) -> int:
+ # Error: unused "type: ignore" comment
+ return a + b # type: ignore
+
+Note that due to a specific nature of this comment, the only way to selectively
+silence it, is to include the error code explicitly. Also note that this error is
+not shown if the ``# type: ignore`` is not used due to code being statically
+unreachable (e.g. due to platform or version checks).
+
+Example:
+
+.. code-block:: python
+
+ # Use "mypy --warn-unused-ignores ..."
+
+ import sys
+
+ try:
+ # The "[unused-ignore]" is needed to get a clean mypy run
+ # on both Python 3.8, and 3.9 where this module was added
+ import graphlib # type: ignore[import,unused-ignore]
+ except ImportError:
+ pass
+
+ if sys.version_info >= (3, 9):
+ # The following will not generate an error on either
+ # Python 3.8, or Python 3.9
+ 42 + "testing..." # type: ignore
+
+.. _code-explicit-override:
+
+Check that ``@override`` is used when overriding a base class method [explicit-override]
+----------------------------------------------------------------------------------------
+
+If you use :option:`--enable-error-code explicit-override `
+mypy generates an error if you override a base class method without using the
+``@override`` decorator. An error will not be emitted for overrides of ``__init__``
+or ``__new__``. See `PEP 698 `_.
+
+.. note::
+
+ Starting with Python 3.12, the ``@override`` decorator can be imported from ``typing``.
+ To use it with older Python versions, import it from ``typing_extensions`` instead.
+
+Example:
+
+.. code-block:: python
+
+ # Use "mypy --enable-error-code explicit-override ..."
+
+ from typing import override
+
+ class Parent:
+ def f(self, x: int) -> None:
+ pass
+
+ def g(self, y: int) -> None:
+ pass
+
+
+ class Child(Parent):
+ def f(self, x: int) -> None: # Error: Missing @override decorator
+ pass
+
+ @override
+ def g(self, y: int) -> None:
+ pass
diff --git a/docs/source/error_codes.rst b/docs/source/error_codes.rst
index 8a65457..65ae0e5 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,70 @@ 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.
+
+Subcodes of error codes
+-----------------------
+
+In some cases, mostly for backwards compatibility reasons, an error
+code may be covered also by another, wider error code. For example, an error with
+code ``[method-assign]`` can be ignored by ``# type: ignore[assignment]``.
+Similar logic works for disabling error codes globally. If a given error code
+is a subcode of another one, it will be mentioned in the documentation for the narrower
+code. This hierarchy is not nested: there cannot be subcodes of other
+subcodes.
diff --git a/docs/source/existing_code.rst b/docs/source/existing_code.rst
index 66259e5..c66008f 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,68 @@ 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 1.0):
+
+.. code-block:: text
+
+ # Start off with these
+ warn_unused_configs = True
+ warn_redundant_casts = True
+ warn_unused_ignores = 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..506f548 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,25 +155,11 @@ 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:
+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.
-.. 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()
-
-**get_function_signature_hook** is used to adjust the signature of a function.
+**get_function_signature_hook()** is used to adjust the signature of a function.
**get_method_hook()** is the same as ``get_function_hook()`` but for methods
instead of module level functions.
@@ -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..1958053 100644
--- a/docs/source/faq.rst
+++ b/docs/source/faq.rst
@@ -36,7 +36,7 @@ Here are some potential benefits of mypy-style static typing:
grows, you can adapt tricky application logic to static typing to
help maintenance.
-See also the `front page `_ of the mypy web
+See also the `front page `_ of the mypy web
site.
Would my project benefit from static typing?
@@ -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).
@@ -209,7 +202,7 @@ Mypy is a cool project. Can I help?
***********************************
Any help is much appreciated! `Contact
-`_ the developers if you would
+`_ the developers if you would
like to contribute. Any help related to development, design,
publicity, documentation, testing, web site maintenance, financing,
etc. can be helpful. You can learn a lot by contributing, and anybody
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..463c73b 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.8 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 `template_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/html_builder.py b/docs/source/html_builder.py
new file mode 100644
index 0000000..3064833
--- /dev/null
+++ b/docs/source/html_builder.py
@@ -0,0 +1,62 @@
+from __future__ import annotations
+
+import json
+import os
+import textwrap
+from pathlib import Path
+from typing import Any
+
+from sphinx.addnodes import document
+from sphinx.application import Sphinx
+from sphinx.builders.html import StandaloneHTMLBuilder
+
+
+class MypyHTMLBuilder(StandaloneHTMLBuilder):
+ def __init__(self, app: Sphinx) -> None:
+ super().__init__(app)
+ self._ref_to_doc = {}
+
+ def write_doc(self, docname: str, doctree: document) -> None:
+ super().write_doc(docname, doctree)
+ self._ref_to_doc.update({_id: docname for _id in doctree.ids})
+
+ def _verify_error_codes(self) -> None:
+ from mypy.errorcodes import error_codes
+
+ missing_error_codes = {c for c in error_codes if f"code-{c}" not in self._ref_to_doc}
+ if missing_error_codes:
+ raise ValueError(
+ f"Some error codes are not documented: {', '.join(sorted(missing_error_codes))}"
+ )
+
+ def _write_ref_redirector(self) -> None:
+ if os.getenv("VERIFY_MYPY_ERROR_CODES"):
+ self._verify_error_codes()
+ p = Path(self.outdir) / "_refs.html"
+ data = f"""
+
+
+
+
+
+ """
+ p.write_text(textwrap.dedent(data))
+
+ def finish(self) -> None:
+ super().finish()
+ self._write_ref_redirector()
+
+
+def setup(app: Sphinx) -> dict[str, Any]:
+ app.add_builder(MypyHTMLBuilder, override=True)
+
+ return {"version": "0.1", "parallel_read_safe": True, "parallel_write_safe": True}
diff --git a/docs/source/index.rst b/docs/source/index.rst
index c9ee1ce..c9dc6bc 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..fa4fae1 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.
@@ -102,7 +119,7 @@ The ``setup.py`` file could look like this:
.. code-block:: python
- from distutils.core import setup
+ from setuptools import setup
setup(
name="SuperPackageA",
@@ -112,11 +129,6 @@ The ``setup.py`` file could look like this:
packages=["package_a"]
)
-.. note::
-
- If you use :doc:`setuptools `, you must pass the option ``zip_safe=False`` to
- ``setup()``, or mypy will not be able to find the installed package.
-
Some packages have a mix of stub files and runtime files. These packages also
require a ``py.typed`` file. An example can be seen below:
@@ -133,7 +145,7 @@ The ``setup.py`` file might look like this:
.. code-block:: python
- from distutils.core import setup
+ from setuptools import setup
setup(
name="SuperPackageB",
@@ -163,7 +175,7 @@ The ``setup.py`` might look like this:
.. code-block:: python
- from distutils.core import setup
+ from setuptools import setup
setup(
name="SuperPackageC",
@@ -173,7 +185,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..c318085 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,11 +195,33 @@ 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.
+Callables can also be used against type objects, matching their
+``__init__`` or ``__new__`` signature:
+
+.. code-block:: python
+
+ from typing import Callable
+
+ class C:
+ def __init__(self, app: str) -> None:
+ pass
+
+ CallableType = Callable[[str], C]
+
+ def class_or_callable(arg: CallableType) -> None:
+ inst = arg("my_app")
+ reveal_type(inst) # Revealed type is "C"
+
+This is useful if you want ``arg`` to be either a ``Callable`` returning an
+instance of ``C`` or the type of ``C`` itself. This also works with
+:ref:`callback protocols `.
+
+
.. _union-types:
Union types
@@ -346,27 +369,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:
-
-.. 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:
+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: 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 +403,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 +425,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 +470,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 +487,7 @@ enabled:
def greeting(name: Optional[str]) -> str:
if name:
- return 'Hello, {}'.format(name)
+ return f'Hello, {name}'
else:
return 'Hello, stranger'
@@ -505,7 +506,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 +514,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 +527,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 +586,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 +620,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 +655,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 +671,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 +691,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 +713,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 +749,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..542ff1c 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"
@@ -704,11 +824,11 @@ classes are generic, self-type allows giving them precise signatures:
Typing async/await
******************
-Mypy supports the ability to type coroutines that use the ``async/await``
-syntax introduced in Python 3.5. For more information regarding coroutines and
-this new syntax, see :pep:`492`.
+Mypy lets you type coroutines that use the ``async/await`` syntax.
+For more information regarding coroutines, see :pep:`492` and the
+`asyncio documentation `_.
-Functions defined using ``async def`` are typed just like normal functions.
+Functions defined using ``async def`` are typed similar to normal functions.
The return type annotation should be the same as the type of the value you
expect to get back when ``await``-ing the coroutine.
@@ -717,129 +837,42 @@ 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:
+ async def countdown(tag: str, count: int) -> str:
while count > 0:
- my_str = await format_string(tag, count) # has type 'str'
+ my_str = await format_string(tag, count) # type is inferred to be str
print(my_str)
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
- loop = asyncio.get_event_loop()
- loop.run_until_complete(countdown_1("Millennium Falcon", 5))
- loop.close()
+ asyncio.run(countdown("Millennium Falcon", 5))
-The result of calling an ``async def`` function *without awaiting* will be a
-value of type :py:class:`Coroutine[Any, Any, T] `, which is a subtype of
+The result of calling an ``async def`` function *without awaiting* will
+automatically be inferred to be a value of type
+:py:class:`Coroutine[Any, Any, T] `, which is a subtype of
:py:class:`Awaitable[T] `:
.. code-block:: python
- my_coroutine = countdown_1("Millennium Falcon", 5)
- reveal_type(my_coroutine) # has type 'Coroutine[Any, Any, str]'
+ my_coroutine = countdown("Millennium Falcon", 5)
+ reveal_type(my_coroutine) # Revealed type is "typing.Coroutine[Any, Any, builtins.str]"
-.. note::
-
- :ref:`reveal_type() ` displays the inferred static type of
- an expression.
+.. _async-iterators:
-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.
+Asynchronous iterators
+----------------------
-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
-
- from typing import Any, Awaitable, Generator
- import asyncio
-
- class MyAwaitable(Awaitable[str]):
- def __init__(self, tag: str, count: int) -> None:
- self.tag = tag
- self.count = count
-
- def __await__(self) -> Generator[Any, None, str]:
- for i in range(n, 0, -1):
- print('T-minus {} ({})'.format(i, tag))
- yield from asyncio.sleep(0.1)
- return "Blastoff!"
-
- def countdown_3(tag: str, count: int) -> Awaitable[str]:
- return MyAwaitable(tag, count)
-
- loop = asyncio.get_event_loop()
- loop.run_until_complete(countdown_3("Heart of Gold", 5))
- loop.close()
-
-To create an iterable coroutine, subclass :py:class:`~typing.AsyncIterator`:
+If you have an asynchronous iterator, you can use the
+:py:class:`~typing.AsyncIterator` type in your annotations:
.. code-block:: python
from typing import Optional, AsyncIterator
import asyncio
- class arange(AsyncIterator[int]):
+ class arange:
def __init__(self, start: int, stop: int, step: int) -> None:
self.start = start
self.stop = stop
@@ -856,279 +889,92 @@ To create an iterable coroutine, subclass :py:class:`~typing.AsyncIterator`:
else:
return self.count
- async def countdown_4(tag: str, n: int) -> str:
- async for i in arange(n, 0, -1):
- print('T-minus {} ({})'.format(i, tag))
+ async def run_countdown(tag: str, countdown: AsyncIterator[int]) -> str:
+ async for i in countdown:
+ print(f'T-minus {i} ({tag})')
await asyncio.sleep(0.1)
return "Blastoff!"
- loop = asyncio.get_event_loop()
- 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:
-
-.. 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
+ asyncio.run(run_countdown("Serenity", arange(5, 0, -1)))
-Mypy will detect an invalid key as an error:
+Async generators (introduced in :pep:`525`) are an easy way to create
+async iterators:
.. 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::
+ from typing import AsyncGenerator, Optional
+ import asyncio
- :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.
+ # Could also type this as returning AsyncIterator[int]
+ async def arange(start: int, stop: int, step: int) -> AsyncGenerator[int, None]:
+ current = start
+ while (step > 0 and current < stop) or (step < 0 and current > stop):
+ yield current
+ current += step
-Class-based syntax
-------------------
+ asyncio.run(run_countdown("Battlestar Galactica", arange(5, 0, -1)))
-An alternative, class-based syntax to define a ``TypedDict`` is supported
-in Python 3.6 and later:
+One common confusion is that the presence of a ``yield`` statement in an
+``async def`` function has an effect on the type of the function:
.. code-block:: python
- from typing_extensions import TypedDict
-
- class Movie(TypedDict):
- name: str
- year: int
+ from typing import AsyncIterator
-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:
+ async def arange(stop: int) -> AsyncIterator[int]:
+ # When called, arange gives you an async iterator
+ # Equivalent to Callable[[int], AsyncIterator[int]]
+ i = 0
+ while i < stop:
+ yield i
+ i += 1
-.. code-block:: python
-
- class Movie(TypedDict):
- name: str
- year: int
-
- class BookBasedMovie(Movie):
- based_on: str
+ async def coroutine(stop: int) -> AsyncIterator[int]:
+ # When called, coroutine gives you something you can await to get an async iterator
+ # Equivalent to Callable[[int], Coroutine[Any, Any, AsyncIterator[int]]]
+ return arange(stop)
-Now ``BookBasedMovie`` has keys ``name``, ``year`` and ``based_on``.
+ async def main() -> None:
+ reveal_type(arange(5)) # Revealed type is "typing.AsyncIterator[builtins.int]"
+ reveal_type(coroutine(5)) # Revealed type is "typing.Coroutine[Any, Any, typing.AsyncIterator[builtins.int]]"
-Mixing required and non-required items
---------------------------------------
+ await arange(5) # Error: Incompatible types in "await" (actual type "AsyncIterator[int]", expected type "Awaitable[Any]")
+ reveal_type(await coroutine(5)) # Revealed type is "typing.AsyncIterator[builtins.int]"
-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:
+This can sometimes come up when trying to define base classes, Protocols or overloads:
.. code-block:: python
- class MovieBase(TypedDict):
- name: str
- year: int
+ from typing import AsyncIterator, Protocol, overload
- class Movie(MovieBase, total=False):
- based_on: str
+ class LauncherIncorrect(Protocol):
+ # Because launch does not have yield, this has type
+ # Callable[[], Coroutine[Any, Any, AsyncIterator[int]]]
+ # instead of
+ # Callable[[], AsyncIterator[int]]
+ async def launch(self) -> AsyncIterator[int]:
+ raise NotImplementedError
-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``.
+ class LauncherCorrect(Protocol):
+ def launch(self) -> AsyncIterator[int]:
+ raise NotImplementedError
-Unions of TypedDicts
---------------------
+ class LauncherAlsoCorrect(Protocol):
+ async def launch(self) -> AsyncIterator[int]:
+ raise NotImplementedError
+ if False:
+ yield 0
-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.
+ # The type of the overloads is independent of the implementation.
+ # In particular, their type is not affected by whether or not the
+ # implementation contains a `yield`.
+ # Use of `def`` makes it clear the type is Callable[..., AsyncIterator[int]],
+ # whereas with `async def` it would be Callable[..., Coroutine[Any, Any, AsyncIterator[int]]]
+ @overload
+ def launch(*, count: int = ...) -> AsyncIterator[int]: ...
+ @overload
+ def launch(*, time: float = ...) -> AsyncIterator[int]: ...
-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.
+ async def launch(*, count: int = 0, time: float = 0) -> AsyncIterator[int]:
+ # The implementation of launch is an async generator and contains a yield
+ yield 0
diff --git a/docs/source/mypy_daemon.rst b/docs/source/mypy_daemon.rst
index 29b554d..7586026 100644
--- a/docs/source/mypy_daemon.rst
+++ b/docs/source/mypy_daemon.rst
@@ -59,6 +59,11 @@ you have a large codebase.)
back to the stable functionality. See :ref:`follow-imports` for
details on how these work.
+.. note::
+
+ The mypy daemon automatically enables ``--local-partial-types`` by default.
+
+
Daemon client commands
**********************
@@ -152,6 +157,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 +182,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 +233,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 +249,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 @@
+
+