mypy-0.942/ 0000755 0001751 0000171 00000000000 14217067353 013335 5 ustar runner docker 0000000 0000000 mypy-0.942/LICENSE 0000644 0001751 0000171 00000026100 14217067311 014333 0 ustar runner docker 0000000 0000000 Mypy (and mypyc) are licensed under the terms of the MIT license, reproduced below.
= = = = =
The MIT License
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"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
= = = = =
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.
= = = = =
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, 2007, 2008, 2009, 2010,
2011, 2012 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 LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------
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.1 software in
source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, CNRI
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 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee. Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement. This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013. This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 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 1.6.1.
4. CNRI is making Python 1.6.1 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.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
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 the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement. 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.6.1, 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.
mypy-0.942/MANIFEST.in 0000644 0001751 0000171 00000002031 14217067311 015061 0 ustar runner docker 0000000 0000000 # some of the prunes here are so that check-manifest doesn't complain about their exclusion
# as such, be judicious in your use of prune
# stubs
prune mypy/typeshed
include mypy/typeshed/LICENSE
include mypy/typeshed/stdlib/VERSIONS
recursive-include mypy/typeshed *.pyi
# mypy and mypyc
include mypy/py.typed
recursive-include mypy *.py
recursive-include mypyc *.py
# random
include mypy_bootstrap.ini
graft mypy/xml
graft scripts
# docs
graft docs
prune docs/build
prune docs/source/_build
# assorted mypyc requirements
graft mypyc/external
graft mypyc/lib-rt
graft mypyc/test-data
graft mypyc/doc
# files necessary for testing sdist
include mypy-requirements.txt
include build-requirements.txt
include test-requirements.txt
include mypy_self_check.ini
prune misc
include misc/proper_plugin.py
graft test-data
include conftest.py
include runtests.py
include pytest.ini
include LICENSE mypyc/README.md
exclude .gitmodules CONTRIBUTING.md CREDITS ROADMAP.md tox.ini action.yml .editorconfig
global-exclude *.py[cod]
global-exclude .DS_Store
mypy-0.942/PKG-INFO 0000644 0001751 0000171 00000002710 14217067353 014432 0 ustar runner docker 0000000 0000000 Metadata-Version: 2.1
Name: mypy
Version: 0.942
Summary: Optional static typing for Python
Home-page: http://www.mypy-lang.org/
Author: Jukka Lehtosalo
Author-email: jukka.lehtosalo@iki.fi
License: MIT License
Project-URL: News, http://mypy-lang.org/news.html
Project-URL: Documentation, https://mypy.readthedocs.io/en/stable/introduction.html
Project-URL: Repository, https://github.com/python/mypy
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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: Topic :: Software Development
Requires-Python: >=3.6
Provides-Extra: dmypy
Provides-Extra: python2
Provides-Extra: reports
License-File: LICENSE
Mypy -- 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 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.
mypy-0.942/README.md 0000644 0001751 0000171 00000014735 14217067311 014620 0 ustar runner docker 0000000 0000000
Mypy: Static Typing for Python
=======================================
[](https://travis-ci.com/python/mypy)
[](https://mypy.readthedocs.io/en/latest/?badge=latest)
[](https://gitter.im/python/typing?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](http://mypy-lang.org/)
Got a question?
---------------
We are always happy to answer questions! Here are some good places to ask them:
- 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)
If you're just getting started,
[the documentation](https://mypy.readthedocs.io/en/stable/introduction.html)
and [type hints cheat sheet](https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html)
can also help answer questions.
If you think you've found a bug:
- 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)
To report a bug or request an enhancement:
- 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
To discuss a new type system feature:
- discuss at [typing-sig mailing list](https://mail.python.org/archives/list/typing-sig@python.org/)
- there is also some historical discussion [here](https://github.com/python/typing/issues)
What is mypy?
-------------
Mypy is a static type checker for Python.
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.
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!
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.
Here is a small example to whet your appetite:
```python
number = input("What is your favourite number?")
print("Well, my favourite number is: ", number + 1) # error: Unsupported operand types for + ("str" and "int")
```
See [the documentation](https://mypy.readthedocs.io/en/stable/introduction.html) for more examples.
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)
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:
python3 -m pip install -U git+git://github.com/python/mypy.git
Now you can type-check the [statically typed parts] of a program like this:
mypy PROGRAM
You can always use the Python interpreter to run your statically typed
programs, even if mypy reports type errors:
python3 PROGRAM
You can also try mypy in an [online playground](https://mypy-play.net/) (developed by
Yusuke Miyazaki).
[statically typed parts]: https://mypy.readthedocs.io/en/latest/getting_started.html#function-signatures-and-dynamic-vs-static-typing
Integrations
------------
Mypy can be integrated into popular IDEs:
* 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,
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.
* pre-commit: use [pre-commit mirrors-mypy](https://github.com/pre-commit/mirrors-mypy).
Web site and documentation
--------------------------
Additional information is available at the web site:
http://www.mypy-lang.org/
Jump straight to the documentation:
https://mypy.readthedocs.io/
Follow along our changelog at:
https://mypy-lang.blogspot.com/
Contributing
------------
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.
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).
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.
mypyc and compiled version of mypy
----------------------------------
[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
To use a compiled version of a development
version of mypy, directly install a binary from
https://github.com/mypyc/mypy_mypyc-wheels/releases/latest.
To contribute to the mypyc project, check out https://github.com/mypyc/mypyc
mypy-0.942/build-requirements.txt 0000644 0001751 0000171 00000000067 14217067311 017713 0 ustar runner docker 0000000 0000000 -r mypy-requirements.txt
types-typed-ast>=1.4.0,<1.5.0
mypy-0.942/conftest.py 0000644 0001751 0000171 00000001053 14217067311 015525 0 ustar runner docker 0000000 0000000 import os.path
pytest_plugins = [
'mypy.test.data',
]
def pytest_configure(config):
mypy_source_root = os.path.dirname(os.path.abspath(__file__))
if os.getcwd() != mypy_source_root:
os.chdir(mypy_source_root)
# This function name is special to pytest. See
# http://doc.pytest.org/en/latest/writing_plugins.html#initialization-command-line-and-configuration-hooks
def pytest_addoption(parser) -> None:
parser.addoption('--bench', action='store_true', default=False,
help='Enable the benchmark test runs')
mypy-0.942/docs/ 0000755 0001751 0000171 00000000000 14217067353 014265 5 ustar runner docker 0000000 0000000 mypy-0.942/docs/Makefile 0000644 0001751 0000171 00000015153 14217067311 015724 0 ustar runner docker 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
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/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Mypy.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Mypy.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Mypy"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Mypy"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
mypy-0.942/docs/README.md 0000644 0001751 0000171 00000002071 14217067311 015536 0 ustar runner docker 0000000 0000000 Mypy Documentation
==================
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.
Building the documentation
--------------------------
Install Sphinx and other dependencies (i.e. theme) needed for the documentation.
From the `docs` directory, use `pip`:
```
$ pip install -r requirements-docs.txt
```
Build the documentation like this:
```
$ make html
```
The built documentation will be placed in the `docs/build` directory. Open
`docs/build/index.html` to view the documentation.
Helpful documentation build commands
------------------------------------
Clean the documentation build:
```
$ make clean
```
Test and check the links found in the documentation:
```
$ make linkcheck
```
Documentation on Read The Docs
------------------------------
The mypy documentation is hosted on Read The Docs, and the latest version
can be found at https://mypy.readthedocs.io/en/latest.
mypy-0.942/docs/make.bat 0000755 0001751 0000171 00000015062 14217067311 015673 0 ustar runner docker 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
set I18NSPHINXOPTS=%SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
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/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Mypy.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Mypy.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
mypy-0.942/docs/requirements-docs.txt 0000644 0001751 0000171 00000000064 14217067311 020471 0 ustar runner docker 0000000 0000000 sphinx>=4.2.0,<5.0.0
sphinx-rtd-theme>=1.0.0,<2.0.0
mypy-0.942/docs/source/ 0000755 0001751 0000171 00000000000 14217067353 015565 5 ustar runner docker 0000000 0000000 mypy-0.942/docs/source/additional_features.rst 0000644 0001751 0000171 00000037067 14217067311 022334 0 ustar runner docker 0000000 0000000 Additional features
-------------------
This section discusses various features that did not fit in naturally in one
of the previous sections.
.. _dataclasses_support:
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:
.. code-block:: python
from dataclasses import dataclass, field
@dataclass
class Application:
name: str
plugins: list[str] = field(default_factory=list)
test = Application("Testing...") # OK
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:
.. code-block:: python
from dataclasses import dataclass
@dataclass(order=True)
class OrderedPoint:
x: int
y: int
@dataclass(order=False)
class UnorderedPoint:
x: int
y: int
OrderedPoint(1, 2) < OrderedPoint(3, 4) # OK
UnorderedPoint(1, 2) < UnorderedPoint(3, 4) # Error: Unsupported operand types
Dataclasses can be generic and can be used in any other way a normal
class can be used:
.. code-block:: python
from dataclasses import dataclass
from typing import Generic, TypeVar
T = TypeVar('T')
@dataclass
class BoxedData(Generic[T]):
data: T
label: str
def unbox(bd: BoxedData[T]) -> T:
...
val = unbox(BoxedData(42, "")) # OK, inferred type is int
For more information see :doc:`official docs `
and :pep:`557`.
Caveats/Known Issues
====================
Some functions in the :py:mod:`dataclasses` module, such as :py:func:`~dataclasses.replace` and :py:func:`~dataclasses.asdict`,
have imprecise (too permissive) types. This will be fixed in future releases.
Mypy does not yet recognize aliases of :py:func:`dataclasses.dataclass `, and will
probably never recognize dynamically computed decorators. The following examples
do **not** work:
.. code-block:: python
from dataclasses import dataclass
dataclass_alias = dataclass
def dataclass_wrapper(cls):
return dataclass(cls)
@dataclass_alias
class AliasDecorated:
"""
Mypy doesn't recognize this as a dataclass because it is decorated by an
alias of `dataclass` rather than by `dataclass` itself.
"""
attribute: int
@dataclass_wrapper
class DynamicallyDecorated:
"""
Mypy doesn't recognize this as a dataclass because it is decorated by a
function returning `dataclass` rather than by `dataclass` itself.
"""
attribute: int
AliasDecorated(attribute=1) # error: Unexpected keyword argument
DynamicallyDecorated(attribute=1) # error: Unexpected keyword argument
.. _attrs_package:
The attrs package
*****************
:doc:`attrs ` is a package that lets you define
classes without writing boilerplate code. Mypy can detect uses of the
package and will generate the necessary method definitions for decorated
classes using the type annotations it finds.
Type annotations can be added as follows:
.. code-block:: python
import attr
@attr.s
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
If you're using ``auto_attribs=True`` you must use variable annotations.
.. code-block:: python
import attr
@attr.s(auto_attribs=True)
class A:
one: int
two: int = 7
three: int = attr.ib(8)
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
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
@attr.s(auto_attribs=True)
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
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.
* 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
YES = True
@attr.s(init=YES)
class A:
...
* Currently, ``converter`` only supports named functions. If mypy finds something else it
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 `_
are not type-checked against the attribute they are setting/validating.
* Method definitions added by mypy currently overwrite any existing method
definitions.
.. _remote-cache:
Using a remote cache to speed up mypy runs
******************************************
Mypy performs type checking *incrementally*, reusing results from
previous runs to speed up successive runs. If you are type checking a
large codebase, mypy can still be sometimes slower than desirable. For
example, if you create a new branch based on a much more recent commit
than the target of the previous mypy run, mypy may have to
process almost every file, as a large fraction of source files may
have changed. This can also happen after you've rebased a local
branch.
Mypy supports using a *remote cache* to improve performance in cases
such as the above. In a large codebase, remote caching can sometimes
speed up mypy runs by a factor of 10, or more.
Mypy doesn't include all components needed to set
this up -- generally you will have to perform some simple integration
with your Continuous Integration (CI) or build system to configure
mypy to use a remote cache. This discussion assumes you have a CI
system set up for the mypy build you want to speed up, and that you
are using a central git repository. Generalizing to different
environments should not be difficult.
Here are the main components needed:
* A shared repository for storing mypy cache files for all landed commits.
* CI build that uploads mypy incremental cache files to the shared repository for
each commit for which the CI build runs.
* A wrapper script around mypy that developers use to run mypy with remote
caching enabled.
Below we discuss each of these components in some detail.
Shared repository for cache files
=================================
You need a repository that allows you to upload mypy cache files from
your CI build and make the cache files available for download based on
a commit id. A simple approach would be to produce an archive of the
``.mypy_cache`` directory (which contains the mypy cache data) as a
downloadable *build artifact* from your CI build (depending on the
capabilities of your CI system). Alternatively, you could upload the
data to a web server or to S3, for example.
Continuous Integration build
============================
The CI build would run a regular mypy build and create an archive containing
the ``.mypy_cache`` directory produced by the build. Finally, it will produce
the cache as a build artifact or upload it to a repository where it is
accessible by the mypy wrapper script.
Your CI script might work like this:
* Run mypy normally. This will generate cache data under the
``.mypy_cache`` directory.
* Create a tarball from the ``.mypy_cache`` directory.
* Determine the current git master branch commit id (say, using
``git rev-parse HEAD``).
* Upload the tarball to the shared repository with a name derived from the
commit id.
Mypy wrapper script
===================
The wrapper script is used by developers to run mypy locally during
development instead of invoking mypy directly. The wrapper first
populates the local ``.mypy_cache`` directory from the shared
repository and then runs a normal incremental build.
The wrapper script needs some logic to determine the most recent
central repository commit (by convention, the ``origin/master`` branch
for git) the local development branch is based on. In a typical git
setup you can do it like this:
.. code::
git merge-base HEAD origin/master
The next step is to download the cache data (contents of the
``.mypy_cache`` directory) from the shared repository based on the
commit id of the merge base produced by the git command above. The
script will decompress the data so that mypy will start with a fresh
``.mypy_cache``. Finally, the script runs mypy normally. And that's all!
Caching with mypy daemon
========================
You can also use remote caching with the :ref:`mypy daemon `.
The remote cache will significantly speed up the first ``dmypy check``
run after starting or restarting the daemon.
The mypy daemon requires extra fine-grained dependency data in
the cache files which aren't included by default. To use caching with
the mypy daemon, use the :option:`--cache-fine-grained ` option in your CI
build::
$ mypy --cache-fine-grained
This flag adds extra information for the daemon to the cache. In
order to use this extra information, you will also need to use the
``--use-fine-grained-cache`` option with ``dmypy start`` or
``dmypy restart``. Example::
$ dmypy start -- --use-fine-grained-cache
Now your first ``dmypy check`` run should be much faster, as it can use
cache information to avoid processing the whole program.
Refinements
===========
There are several optional refinements that may improve things further,
at least if your codebase is hundreds of thousands of lines or more:
* If the wrapper script determines that the merge base hasn't changed
from a previous run, there's no need to download the cache data and
it's better to instead reuse the existing local cache data.
* If you use the mypy daemon, you may want to restart the daemon each time
after the merge base or local branch has changed to avoid processing a
potentially large number of changes in an incremental build, as this can
be much slower than downloading cache data and restarting the daemon.
* If the current local branch is based on a very recent master commit,
the remote cache data may not yet be available for that commit, as
there will necessarily be some latency to build the cache files. It
may be a good idea to look for cache data for, say, the 5 latest
master commits and use the most recent data that is available.
* If the remote cache is not accessible for some reason (say, from a public
network), the script can still fall back to a normal incremental build.
* You can have multiple local cache directories for different local branches
using the :option:`--cache-dir ` option. If the user switches to an existing
branch where downloaded cache data is already available, you can continue
to use the existing cache data instead of redownloading the data.
* You can set up your CI build to use a remote cache to speed up the
CI build. This would be particularly useful if each CI build starts
from a fresh state without access to cache files from previous
builds. It's still recommended to run a full, non-incremental
mypy build to create the cache data, as repeatedly updating cache
data incrementally could result in drift over a long time period (due
to a mypy caching issue, perhaps).
.. _extended_callable:
Extended Callable types
***********************
.. note::
This feature is deprecated. You can use
:ref:`callback protocols ` as a replacement.
As an experimental mypy extension, you can specify :py:data:`~typing.Callable` types
that support keyword arguments, optional arguments, and more. When
you specify the arguments of a :py:data:`~typing.Callable`, you can choose to supply just
the type of a nameless positional argument, or an "argument specifier"
representing a more complicated form of argument. This allows one to
more closely emulate the full range of possibilities given by the
``def`` statement in Python.
As an example, here's a complicated function definition and the
corresponding :py:data:`~typing.Callable`:
.. code-block:: python
from typing import Callable
from mypy_extensions import (Arg, DefaultArg, NamedArg,
DefaultNamedArg, VarArg, KwArg)
def func(__a: int, # This convention is for nameless arguments
b: int,
c: int = 0,
*args: int,
d: int,
e: int = 0,
**kwargs: int) -> int:
...
F = Callable[[int, # Or Arg(int)
Arg(int, 'b'),
DefaultArg(int, 'c'),
VarArg(int),
NamedArg(int, 'd'),
DefaultNamedArg(int, 'e'),
KwArg(int)],
int]
f: F = func
Argument specifiers are special function calls that can specify the
following aspects of an argument:
- its type (the only thing that the basic format supports)
- its name (if it has one)
- whether it may be omitted
- whether it may or must be passed using a keyword
- whether it is a ``*args`` argument (representing the remaining
positional arguments)
- whether it is a ``**kwargs`` argument (representing the remaining
keyword arguments)
The following functions are available in ``mypy_extensions`` for this
purpose:
.. code-block:: python
def Arg(type=Any, name=None):
# A normal, mandatory, positional argument.
# If the name is specified it may be passed as a keyword.
def DefaultArg(type=Any, name=None):
# An optional positional argument (i.e. with a default value).
# If the name is specified it may be passed as a keyword.
def NamedArg(type=Any, name=None):
# A mandatory keyword-only argument.
def DefaultNamedArg(type=Any, name=None):
# An optional keyword-only argument (i.e. with a default value).
def VarArg(type=Any):
# A *args-style variadic positional argument.
# A single VarArg() specifier represents all remaining
# positional arguments.
def KwArg(type=Any):
# A **kwargs-style variadic keyword argument.
# A single KwArg() specifier represents all remaining
# keyword arguments.
In all cases, the ``type`` argument defaults to ``Any``, and if the
``name`` argument is omitted the argument has no name (the name is
required for ``NamedArg`` and ``DefaultNamedArg``). A basic
:py:data:`~typing.Callable` such as
.. code-block:: python
MyFunc = Callable[[int, str, int], float]
is equivalent to the following:
.. code-block:: python
MyFunc = Callable[[Arg(int), Arg(str), Arg(int)], float]
A :py:data:`~typing.Callable` with unspecified argument types, such as
.. code-block:: python
MyOtherFunc = Callable[..., int]
is (roughly) equivalent to
.. code-block:: python
MyOtherFunc = Callable[[VarArg(), KwArg()], int]
.. note::
Each of the functions above currently just returns its ``type``
argument at runtime, so the information contained in the argument
specifiers is not available at runtime. This limitation is
necessary for backwards compatibility with the existing
``typing.py`` module as present in the Python 3.5+ standard library
and distributed via PyPI.
mypy-0.942/docs/source/builtin_types.rst 0000644 0001751 0000171 00000007514 14217067311 021212 0 ustar runner docker 0000000 0000000 Built-in types
==============
This chapter introduces some commonly used built-in types. We will
cover many other kinds of types later.
Simple types
............
Here are examples of some common built-in types:
====================== ===============================
Type Description
====================== ===============================
``int`` integer
``float`` floating point number
``bool`` boolean value (subclass of ``int``)
``str`` string (unicode in Python 3)
``bytes`` 8-bit string
``object`` an arbitrary object (``object`` is the common base class)
====================== ===============================
All built-in classes can be used as types.
Any type
........
If you can't find a good type for some value, you can always fall back
to ``Any``:
====================== ===============================
Type Description
====================== ===============================
``Any`` dynamically typed value with an arbitrary type
====================== ===============================
The type ``Any`` is defined in the :py:mod:`typing` module.
See :ref:`dynamic-typing` for more details.
Generic types
.............
In Python 3.9 and later, built-in collection type objects support
indexing:
====================== ===============================
Type Description
====================== ===============================
``list[str]`` list of ``str`` objects
``tuple[int, int]`` tuple of two ``int`` objects (``tuple[()]`` is the empty tuple)
``tuple[int, ...]`` tuple of an arbitrary number of ``int`` objects
``dict[str, int]`` dictionary from ``str`` keys to ``int`` values
``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)
====================== ===============================
The type ``dict`` is a *generic* class, signified by type arguments within
``[...]``. For example, ``dict[int, str]`` is a dictionary from integers to
strings and ``dict[Any, Any]`` is a dictionary of dynamically typed
(arbitrary) values and keys. ``list`` is another generic class.
``Iterable``, ``Sequence``, and ``Mapping`` are generic types that correspond to
Python protocols. For example, a ``str`` object or a ``list[str]`` object is
valid when ``Iterable[str]`` or ``Sequence[str]`` is expected.
You can import them from :py:mod:`collections.abc` instead of importing from
:py:mod:`typing` in Python 3.9.
See :ref:`generic-builtins` for more details, including how you can
use these in annotations also in Python 3.7 and 3.8.
These legacy types defined in :py:mod:`typing` are needed if you need to support
Python 3.8 and earlier:
====================== ===============================
Type Description
====================== ===============================
``List[str]`` list of ``str`` objects
``Tuple[int, int]`` tuple of two ``int`` objects (``Tuple[()]`` is the empty tuple)
``Tuple[int, ...]`` tuple of an arbitrary number of ``int`` objects
``Dict[str, int]`` dictionary from ``str`` keys to ``int`` values
``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)
====================== ===============================
``List`` is an alias for the built-in type ``list`` that supports
indexing (and similarly for ``dict``/``Dict`` and
``tuple``/``Tuple``).
Note that even though ``Iterable``, ``Sequence`` and ``Mapping`` look
similar to abstract base classes defined in :py:mod:`collections.abc`
(formerly ``collections``), they are not identical, since the latter
don't support indexing prior to Python 3.9.
mypy-0.942/docs/source/cheat_sheet.rst 0000644 0001751 0000171 00000021242 14217067311 020566 0 ustar runner docker 0000000 0000000 .. _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]
...
mypy-0.942/docs/source/cheat_sheet_py3.rst 0000644 0001751 0000171 00000024556 14217067311 021374 0 ustar runner docker 0000000 0000000 .. _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.
Variables
*********
Python 3.6 introduced a syntax for annotating variables in :pep:`526`
and we use it in most examples.
.. code-block:: python
# This is how you declare the type of a variable type in Python 3.6
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
child: bool
if age < 18:
child = True
else:
child = False
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
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+)
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 the 'typing' module
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}
# 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+
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
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
*********
Python 3 supports an annotation syntax for function declarations.
.. code-block:: python
from typing import Callable, Iterator, Union, Optional
# This is how you annotate a function definition
def stringify(num: int) -> str:
return str(num)
# And here's how you specify multiple arguments
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
# This is how you annotate a callable (function) value
x: Callable[[int, float], float] = f
# 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]:
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]],
sender: str,
cc: Optional[list[str]],
bcc: Optional[list[str]],
subject='',
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:
pass
quux(3) # Fine
quux(__x=3) # Error
When you're puzzled or when things are complicated
**************************************************
.. code-block:: python
from typing import Union, Any, 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: list[Union[int, str]] = [3, 5, "test", "fun"]
# 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)
# 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: 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
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(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...
return list(my_mapping.keys())
f({3: 'yes', 4: 'no'})
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")
# 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: str = 'w') -> IO[str]:
if mode == 'w':
return sys.stdout
elif mode == 'r':
return sys.stdin
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
...
class A:
...
# 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
...
Decorators
**********
Decorator functions can be expressed via generics. See
:ref:`declaring-decorators` for more details.
.. code-block:: python
from typing import Any, Callable, TypeVar
F = TypeVar('F', bound=Callable[..., Any])
def bare_decorator(func: F) -> F:
...
def decorator_args(url: str) -> Callable[[F], F]:
...
mypy-0.942/docs/source/class_basics.rst 0000644 0001751 0000171 00000025545 14217067311 020755 0 ustar runner docker 0000000 0000000 Class basics
============
This section will help get you started annotating your
classes. Built-in classes such as ``int`` also follow these same
rules.
Instance and class attributes
*****************************
The mypy type checker detects if you are trying to access a missing
attribute, which is a very common programming error. For this to work
correctly, instance and class attributes must be defined or
initialized within the class. Mypy infers the types of attributes:
.. code-block:: python
class A:
def __init__(self, x: int) -> None:
self.x = x # Aha, attribute 'x' of type 'int'
a = A(1)
a.x = 2 # OK!
a.y = 3 # Error: "A" has no attribute "y"
This is a bit like each class having an implicitly defined
:py:data:`__slots__ ` attribute. This is only enforced during type
checking and not when your program is running.
You can declare types of variables in the class body explicitly using
a type annotation:
.. code-block:: python
class A:
x: list[int] # Declare attribute 'x' of type list[int]
a = A()
a.x = [1] # OK
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:
.. code-block:: python
class A:
def __init__(self) -> None:
self.x: list[int] = []
def f(self) -> None:
self.y: Any = 0
You can only define an instance variable within a method if you assign
to it explicitly using ``self``:
.. code-block:: python
class A:
def __init__(self) -> None:
self.y = 1 # Define 'y'
a = self
a.x = 1 # Error: 'x' not defined
Annotating __init__ methods
***************************
The :py:meth:`__init__ ` method is somewhat special -- it doesn't return a
value. This is best expressed as ``-> None``. However, since many feel
this is redundant, it is allowed to omit the return type declaration
on :py:meth:`__init__ ` methods **if at least one argument is annotated**. For
example, in the following classes :py:meth:`__init__ ` is considered fully
annotated:
.. code-block:: python
class C1:
def __init__(self) -> None:
self.var = 42
class C2:
def __init__(self, arg: int):
self.var = arg
However, if :py:meth:`__init__ ` has no annotated arguments and no return type
annotation, it is considered an untyped method:
.. code-block:: python
class C3:
def __init__(self):
# This body is not type checked
self.var = 42 + 'abc'
Class attribute annotations
***************************
You can use a :py:data:`ClassVar[t] ` annotation to explicitly declare that a
particular attribute should not be set on instances:
.. code-block:: python
from typing import ClassVar
class A:
x: ClassVar[int] = 0 # Class variable only
A.x += 1 # OK
a = A()
a.x = 1 # Error: Cannot assign to class variable "x" via instance
print(a.x) # OK -- can be read through an instance
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
being used as an instance variable, as discussed previously:
.. code-block:: python
class A:
x = 0 # Can be used as a class or instance variable
A.x += 1 # OK
a = A()
a.x = 1 # Also OK
Note that :py:data:`~typing.ClassVar` is not a class, and you can't use it with
:py:func:`isinstance` or :py:func:`issubclass`. It does not change Python
runtime behavior -- it's only for type checkers such as mypy (and
also helpful for human readers).
You can also omit the square brackets and the variable type in
a :py:data:`~typing.ClassVar` annotation, but this might not do what you'd expect:
.. code-block:: python
class A:
y: ClassVar = 0 # Type implicitly Any!
In this case the type of the attribute will be implicitly ``Any``.
This behavior will change in the future, since it's surprising.
.. note::
A :py:data:`~typing.ClassVar` type parameter cannot include type variables:
``ClassVar[T]`` and ``ClassVar[list[T]]``
are both invalid if ``T`` is a type variable (see :ref:`generic-classes`
for more about type variables).
Overriding statically typed methods
***********************************
When overriding a statically typed method, mypy checks that the
override has a compatible signature:
.. code-block:: python
class Base:
def f(self, x: int) -> None:
...
class Derived1(Base):
def f(self, x: str) -> None: # Error: type of 'x' incompatible
...
class Derived2(Base):
def f(self, x: int, y: int) -> None: # Error: too many arguments
...
class Derived3(Base):
def f(self, x: int) -> None: # OK
...
class Derived4(Base):
def f(self, x: float) -> None: # OK: mypy treats int as a subtype of float
...
class Derived5(Base):
def f(self, x: int, y: int = 0) -> None: # OK: accepts more than the base
... # class method
.. note::
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
**contravariantly** -- subclasses can have more general argument types.
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
signatures.
As always, relying on dynamically typed code can be unsafe. There is no
runtime enforcement that the method override returns a value that is
compatible with the original return type, since annotations have no
effect at runtime:
.. code-block:: python
class Base:
def inc(self, x: int) -> int:
return x + 1
class Derived(Base):
def inc(self, x): # Override, dynamically typed
return 'hello' # Incompatible with 'Base', but no mypy error
Abstract base classes and multiple inheritance
**********************************************
Mypy supports Python :doc:`abstract base classes ` (ABCs). Abstract classes
have at least one abstract method or property that must be implemented
by any *concrete* (non-abstract) subclass. You can define abstract base
classes using the :py:class:`abc.ABCMeta` metaclass and the :py:func:`@abc.abstractmethod `
function decorator. Example:
.. code-block:: python
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def eat(self, food: str) -> None: pass
@property
@abstractmethod
def can_walk(self) -> bool: pass
class Cat(Animal):
def eat(self, food: str) -> None:
... # Body omitted
@property
def can_walk(self) -> bool:
return True
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.
Since you can't create instances of ABCs, they are most commonly used in
type annotations. For example, this method accepts arbitrary iterables
containing arbitrary animals (instances of concrete ``Animal``
subclasses):
.. code-block:: python
def feed_all(animals: Iterable[Animal], food: str) -> None:
for animal in animals:
animal.eat(food)
There is one important peculiarity about how ABCs work in Python --
whether a particular class is abstract or not is somewhat implicit.
In the example below, ``Derived`` is treated as an abstract base class
since ``Derived`` inherits an abstract ``f`` method from ``Base`` and
doesn't explicitly implement it. The definition of ``Derived``
generates no errors from mypy, since it's a valid ABC:
.. code-block:: python
from abc import ABCMeta, abstractmethod
class Base(metaclass=ABCMeta):
@abstractmethod
def f(self, x: int) -> None: pass
class Derived(Base): # No error -- Derived is implicitly abstract
def g(self) -> None:
...
Attempting to create an instance of ``Derived`` will be rejected,
however:
.. code-block:: python
d = Derived() # Error: 'Derived' is abstract
.. note::
It's a common error to forget to implement an abstract method.
As shown above, the class definition will not generate an error
in this case, but any attempt to construct an instance will be
flagged as an error.
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
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.
mypy-0.942/docs/source/command_line.rst 0000644 0001751 0000171 00000102764 14217067311 020750 0 ustar runner docker 0000000 0000000 .. _command-line:
.. program:: mypy
The mypy command line
=====================
This section documents mypy's command line interface. You can view
a quick summary of the available flags by running :option:`mypy --help`.
.. note::
Command line flags are liable to change between releases.
Specifying what to type check
*****************************
By default, you can specify what code you want mypy to type check
by passing in the paths to what you want to have type checked::
$ mypy foo.py bar.py some_directory
Note that directories are checked recursively.
Mypy also lets you specify what code to type check in several other
ways. A short summary of the relevant flags is included below:
for full details, see :ref:`running-mypy`.
.. option:: -m MODULE, --module MODULE
Asks mypy to type check the provided module. This flag may be
repeated multiple times.
Mypy *will not* recursively type check any submodules of the provided
module.
.. option:: -p PACKAGE, --package PACKAGE
Asks mypy to type check the provided package. This flag may be
repeated multiple times.
Mypy *will* recursively type check any submodules of the provided
package. This flag is identical to :option:`--module` apart from this
behavior.
.. option:: -c PROGRAM_TEXT, --command PROGRAM_TEXT
Asks mypy to type check the provided string as a program.
.. option:: --exclude
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.
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/``. 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 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
with a period, exactly as ``--exclude
'/(site-packages|node_modules|__pycache__|\..*)/$'`` would. Mypy will also
never recursively discover files with extensions other than ``.py`` or
``.pyi``.
Optional arguments
******************
.. option:: -h, --help
Show help message and exit.
.. option:: -v, --verbose
More verbose messages.
.. option:: -V, --version
Show program's version number and exit.
.. _config-file-flag:
Config file
***********
.. option:: --config-file CONFIG_FILE
This flag makes mypy read configuration settings from the given file.
By default settings are read from ``mypy.ini``, ``.mypy.ini``, ``pyproject.toml``, or ``setup.cfg``
in the current directory. Settings override mypy's built-in defaults and
command line flags can override settings.
Specifying :option:`--config-file= <--config-file>` (with no filename) will ignore *all*
config files.
See :ref:`config-file` for the syntax of configuration files.
.. option:: --warn-unused-configs
This flag makes mypy warn about unused ``[mypy-]`` config
file sections.
(This requires turning off incremental mode using :option:`--no-incremental`.)
.. _import-discovery:
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
paths to modules ` for details.
.. option:: --ignore-missing-imports
This flag makes mypy ignore all missing imports. It is equivalent
to adding ``# type: ignore`` comments to all unresolved imports
within your codebase.
Note that this flag does *not* suppress errors about missing names
in successfully resolved modules. For example, if one has the
following files::
package/__init__.py
package/mod.py
Then mypy will generate the following errors with :option:`--ignore-missing-imports`:
.. code-block:: python
import package.unknown # No error, ignored
x = package.unknown.func() # OK. 'func' is assumed to be of type 'Any'
from package import unknown # No error, ignored
from package.mod import NonExisting # Error: Module has no attribute 'NonExisting'
For more details, see :ref:`ignore-missing-imports`.
.. option:: --follow-imports {normal,silent,skip,error}
This flag adjusts how mypy follows imported modules that were not
explicitly passed in via the command line.
The default option is ``normal``: mypy will follow and type check
all modules. For more information on what the other options do,
see :ref:`Following imports `.
.. option:: --python-executable EXECUTABLE
This flag will have mypy collect type information from :pep:`561`
compliant packages installed for the Python executable ``EXECUTABLE``.
If not provided, mypy will use PEP 561 compliant packages installed for
the Python executable running mypy.
See :ref:`installed-packages` for more on making PEP 561 compliant packages.
.. option:: --no-site-packages
This flag will disable searching for :pep:`561` compliant packages. This
will also disable searching for a usable Python executable.
Use this flag if mypy cannot find a Python executable for the version of
Python being checked, and you don't need to use PEP 561 typed packages.
Otherwise, use :option:`--python-executable`.
.. option:: --no-silence-site-packages
By default, mypy will suppress any error messages generated within :pep:`561`
compliant packages. Adding this flag will disable this behavior.
.. _platform-configuration:
Platform configuration
**********************
By default, mypy will assume that you intend to run your code using the same
operating system and Python version you are using to run mypy itself. The
following flags let you modify this behavior.
For more information on how to use these flags, see :ref:`version_and_platform_checks`.
.. option:: --python-version X.Y
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>`.
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
run under the given operating system. Without this option, mypy will
default to using whatever operating system you are currently using.
The ``PLATFORM`` parameter may be any string supported by
:py:data:`sys.platform`.
.. _always-true:
.. option:: --always-true NAME
This flag will treat all variables named ``NAME`` as
compile-time constants that are always true. This flag may
be repeated.
.. option:: --always-false NAME
This flag will treat all variables named ``NAME`` as
compile-time constants that are always false. This flag may
be repeated.
.. _disallow-dynamic-typing:
Disallow dynamic typing
***********************
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.
The following options are available:
.. option:: --disallow-any-unimported
This flag disallows usage of types that come from unfollowed imports
(such types become aliases for ``Any``). Unfollowed imports occur either
when the imported module does not exist or when :option:`--follow-imports=skip <--follow-imports>`
is set.
.. option:: --disallow-any-expr
This flag disallows all expressions in the module that have type ``Any``.
If an expression of type ``Any`` appears anywhere in the module
mypy will output an error unless the expression is immediately
used as an argument to :py:func:`~typing.cast` or assigned to a variable with an
explicit type annotation.
In addition, declaring a variable of type ``Any``
or casting to type ``Any`` is not allowed. Note that calling functions
that take parameters of type ``Any`` is still allowed.
.. option:: --disallow-any-decorated
This flag disallows functions that have ``Any`` in their signature
after decorator transformation.
.. option:: --disallow-any-explicit
This flag disallows explicit ``Any`` in type positions such as type
annotations and generic type parameters.
.. option:: --disallow-any-generics
This flag disallows usage of generic types that do not specify explicit
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
This flag reports an error whenever a class subclasses a value of
type ``Any``. This may occur when the base class is imported from
a module that doesn't exist (when using
:option:`--ignore-missing-imports`) or is
ignored due to :option:`--follow-imports=skip <--follow-imports>` or a
``# type: ignore`` comment on the ``import`` statement.
Since the module is silenced, the imported class is given a type of ``Any``.
By default mypy will assume that the subclass correctly inherited
the base class even though that may not actually be the case. This
flag makes mypy raise an error instead.
.. _untyped-definitions-and-calls:
Untyped definitions and calls
*****************************
The following flags configure how mypy handles untyped function
definitions or calls.
.. option:: --disallow-untyped-calls
This flag reports an error whenever a function with type annotations
calls a function defined without annotations.
.. option:: --disallow-untyped-defs
This flag reports an error whenever it encounters a function definition
without type annotations.
.. option:: --disallow-incomplete-defs
This flag reports an error whenever it encounters a partly annotated
function definition.
.. option:: --check-untyped-defs
This flag is less severe than the previous two options -- it type checks
the body of every function, regardless of whether it has type annotations.
(By default the bodies of functions without annotations are not type
checked.)
It will assume all arguments have type ``Any`` and always infer ``Any``
as the return type.
.. option:: --disallow-untyped-decorators
This flag reports an error whenever a function with type annotations
is decorated with a decorator without annotations.
.. _none-and-optional-handling:
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:
.. option:: --no-implicit-optional
This flag causes mypy to stop treating 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``:
.. 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)
.. option:: --no-strict-optional
This flag disables strict checking of :py:data:`~typing.Optional`
types and ``None`` values. With this option, mypy doesn't
generally check the use of ``None`` values -- they are valid
everywhere. See :ref:`no_strict_optional` for more about this feature.
**Note:** Strict optional checking was enabled by default starting in
mypy 0.600, and in previous versions it had to be explicitly enabled
using ``--strict-optional`` (which is still accepted).
.. _configuring-warnings:
Configuring warnings
********************
The following flags enable warnings for code that is sound but is
potentially problematic or redundant in some way.
.. option:: --warn-redundant-casts
This flag will make mypy report an error whenever your code uses
an unnecessary cast that can safely be removed.
.. option:: --warn-unused-ignores
This flag will make mypy report an error whenever your code uses
a ``# type: ignore`` comment on a line that is not actually
generating an error message.
This flag, along with the :option:`--warn-redundant-casts` flag, are both
particularly useful when you are upgrading mypy. Previously,
you may have needed to add casts or ``# type: ignore`` annotations
to work around bugs in mypy or missing stubs for 3rd party libraries.
These two flags let you discover cases where either workarounds are
no longer necessary.
.. option:: --no-warn-no-return
By default, mypy will generate errors when a function is missing
return statements in some execution paths. The only exceptions
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.
Passing in :option:`--no-warn-no-return` will disable these error
messages in all cases.
.. option:: --warn-return-any
This flag causes mypy to generate a warning when returning a value
with type ``Any`` from a function declared with a non-``Any`` return type.
.. option:: --warn-unreachable
This flag will make mypy report an error whenever it encounters
code determined to be unreachable or redundant after performing type analysis.
This can be a helpful way of detecting certain kinds of bugs in your code.
For example, enabling this flag will make mypy report that the ``x > 7``
check is redundant and that the ``else`` block below is unreachable.
.. code-block:: python
def process(x: int) -> None:
# Error: Right operand of "or" is never evaluated
if isinstance(x, int) or x > 7:
# Error: Unsupported operand types for + ("int" and "str")
print(x + "bad")
else:
# Error: 'Statement is unreachable' error
print(x + "bad")
To help prevent mypy from generating spurious warnings, the "Statement is
unreachable" warning will be silenced in exactly two cases:
1. When the unreachable statement is a ``raise`` statement, is an
``assert False`` statement, or calls a function that has the :py:data:`~typing.NoReturn`
return type hint. In other words, when the unreachable statement
throws an error or terminates the program in some way.
2. When the unreachable statement was *intentionally* marked as unreachable
using :ref:`version_and_platform_checks`.
.. note::
Mypy currently cannot detect and report unreachable or redundant code
inside any functions using :ref:`type-variable-value-restriction`.
This limitation will be removed in future releases of mypy.
.. _miscellaneous-strictness-flags:
Miscellaneous strictness flags
******************************
This section documents any other flags that do not neatly fall under any
of the above sections.
.. option:: --allow-untyped-globals
This flag causes mypy to suppress errors caused by not being able to fully
infer the types of global and class variables.
.. option:: --allow-redefinition
By default, mypy won't allow a variable to be redefined with an
unrelated type. This flag enables redefinition of a variable with an
arbitrary type *in some contexts*: only redefinitions within the
same block and nesting depth as the original definition are allowed.
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
.. option:: --local-partial-types
In mypy, the most common cases for partial types are variables initialized using ``None``,
but without explicit ``Optional`` annotations. By default, mypy won't check partial types
spanning module top level or class top level. This flag changes the behavior to only allow
partial types at local level, therefore it disallows inferring variable type for ``None``
from two assignments in different scopes. For example:
.. code-block:: python
from typing import Optional
a = None # Need type annotation here if using --local-partial-types
b = None # type: Optional[int]
class Foo:
bar = None # Need type annotation here if using --local-partial-types
baz = None # type: Optional[int]
def __init__(self) -> None:
self.bar = 1
reveal_type(Foo().bar) # Union[int, None] without --local-partial-types
Note: this option is always implicitly enabled in mypy daemon and will become
enabled by default for mypy in a future release.
.. option:: --no-implicit-reexport
By default, imported values to a module are treated as exported and mypy allows
other modules to import them. This flag changes the behavior to not re-export unless
the item is imported using from-as or is included in ``__all__``. Note this is
always treated as enabled for stub files. For example:
.. code-block:: python
# 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']
.. option:: --strict-equality
By default, mypy allows always-false comparisons like ``42 == 'no'``.
Use this flag to prohibit such comparisons of non-overlapping types, and
similar identity and container checks:
.. code-block:: python
from typing import Text
items: list[int]
if 'some string' in items: # Error: non-overlapping container check!
...
text: Text
if text != b'other bytes': # Error: non-overlapping equality check!
...
assert text is not None # OK, check against None is allowed as a special case.
.. option:: --strict
This flag mode enables 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 running :option:`--strict` may change
over time.
.. option:: --disable-error-code
This flag allows disabling one or multiple error codes globally.
.. code-block:: python
# no flag
x = 'a string'
x.trim() # error: "str" has no attribute "trim" [attr-defined]
# --disable-error-code attr-defined
x = 'a string'
x.trim()
.. option:: --enable-error-code
This flag allows enabling one or multiple error codes globally.
Note: This flag will override disabled error codes from the --disable-error-code
flag
.. code-block:: python
# --disable-error-code attr-defined
x = 'a string'
x.trim()
# --disable-error-code attr-defined --enable-error-code attr-defined
x = 'a string'
x.trim() # error: "str" has no attribute "trim" [attr-defined]
.. _configuring-error-messages:
Configuring error messages
**************************
The following flags let you adjust how much detail mypy displays
in error messages.
.. option:: --show-error-context
This flag will precede all errors with "note" messages explaining the
context of the error. For example, consider the following program:
.. code-block:: python
class Test:
def foo(self, x: int) -> int:
return x + "bar"
Mypy normally displays an error message that looks like this::
main.py:3: error: Unsupported operand types for + ("int" and "str")
If we enable this flag, the error message now looks like this::
main.py: note: In member "foo" of class "Test":
main.py:3: error: Unsupported operand types for + ("int" and "str")
.. option:: --show-column-numbers
This flag will add column offsets to error messages.
For example, the following indicates an error in line 12, column 9
(note that column offsets are 0-based)::
main.py:12:9: error: Unsupported operand types for / ("int" and "str")
.. option:: --show-error-codes
This flag will add an error code ``[]`` to error messages. The error
code is shown after each error message::
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
See :ref:`error-codes` for more information.
.. option:: --pretty
Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.
.. option:: --no-color-output
This flag will disable color output in error messages, enabled by default.
.. option:: --no-error-summary
This flag will disable error summary. By default mypy shows a summary line
including total number of errors, number of files with errors, and number
of files checked.
.. option:: --show-absolute-path
Show absolute paths to files.
.. option:: --soft-error-limit N
This flag will adjust the limit after which mypy will (sometimes)
disable reporting most additional errors. The limit only applies
if it seems likely that most of the remaining errors will not be
useful or they may be overly noisy. If ``N`` is negative, there is
no limit. The default limit is 200.
.. _incremental:
Incremental mode
****************
By default, mypy will store type information into a cache. Mypy
will use this information to avoid unnecessary recomputation when
it type checks your code again. This can help speed up the type
checking process, especially when most parts of your program have
not changed since the previous mypy run.
If you want to speed up how long it takes to recheck your code
beyond what incremental mode can offer, try running mypy in
:ref:`daemon mode `.
.. option:: --no-incremental
This flag disables incremental mode: mypy will no longer reference
the cache when re-run.
Note that mypy will still write out to the cache even when
incremental mode is disabled: see the :option:`--cache-dir` flag below
for more details.
.. option:: --cache-dir DIR
By default, mypy stores all cache data inside of a folder named
``.mypy_cache`` in the current directory. This flag lets you
change this folder. This flag can also be useful for controlling
cache use when using :ref:`remote caching `.
This setting will override the ``MYPY_CACHE_DIR`` environment
variable if it is set.
Mypy will also always write to the cache even when incremental
mode is disabled so it can "warm up" the cache. To disable
writing to the cache, use ``--cache-dir=/dev/null`` (UNIX)
or ``--cache-dir=nul`` (Windows).
.. option:: --sqlite-cache
Use an `SQLite`_ database to store the cache.
.. option:: --cache-fine-grained
Include fine-grained dependency information in the cache for the mypy daemon.
.. option:: --skip-version-check
By default, mypy will ignore cache data generated by a different
version of mypy. This flag disables that behavior.
.. option:: --skip-cache-mtime-checks
Skip cache internal consistency checks based on mtime.
Advanced options
****************
The following flags are useful mostly for people who are interested
in developing or debugging mypy internals.
.. option:: --pdb
This flag will invoke the Python debugger when mypy encounters
a fatal error.
.. option:: --show-traceback, --tb
If set, this flag will display a full traceback when mypy
encounters a fatal error.
.. option:: --raise-exceptions
Raise exception on fatal error.
.. option:: --custom-typing-module MODULE
This flag lets you use a custom module as a substitute for the
:py:mod:`typing` module.
.. option:: --custom-typeshed-dir DIR
This flag 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.
Note that this doesn't affect third-party library stubs.
.. _warn-incomplete-stub:
.. option:: --warn-incomplete-stub
This flag modifies both the :option:`--disallow-untyped-defs` and
:option:`--disallow-incomplete-defs` flags so they also report errors
if stubs in typeshed are missing type annotations or has incomplete
annotations. If both flags are missing, :option:`--warn-incomplete-stub`
also does nothing.
This flag is mainly intended to be used by people who want contribute
to typeshed and would like a convenient way to find gaps and omissions.
If you want mypy to report an error when your codebase *uses* an untyped
function, whether that function is defined in typeshed or not, use the
:option:`--disallow-untyped-calls` flag. See :ref:`untyped-definitions-and-calls`
for more details.
.. _shadow-file:
.. option:: --shadow-file SOURCE_FILE SHADOW_FILE
When mypy is asked to type check ``SOURCE_FILE``, this flag makes mypy
read from and type check the contents of ``SHADOW_FILE`` instead. However,
diagnostics will continue to refer to ``SOURCE_FILE``.
Specifying this argument multiple times (``--shadow-file X1 Y1 --shadow-file X2 Y2``)
will allow mypy to perform multiple substitutions.
This allows tooling to create temporary files with helpful modifications
without having to change the source file in place. For example, suppose we
have a pipeline that adds ``reveal_type`` for certain variables.
This pipeline is run on ``original.py`` to produce ``temp.py``.
Running ``mypy --shadow-file original.py temp.py original.py`` will then
cause mypy to type check the contents of ``temp.py`` instead of ``original.py``,
but error messages will still reference ``original.py``.
Report generation
*****************
If these flags are set, mypy will generate a report in the specified
format into the specified directory.
.. option:: --any-exprs-report DIR
Causes mypy to generate a text file report documenting how many
expressions of type ``Any`` are present within your codebase.
.. option:: --cobertura-xml-report DIR
Causes mypy to generate a Cobertura XML type checking coverage 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.
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
Causes mypy to generate a text file report documenting the functions
and lines that are typed and untyped within your codebase.
.. option:: --linecoverage-report DIR
Causes mypy to generate a JSON file that maps each source file's
absolute filename to a list of line numbers that belong to typed
functions in that file.
.. option:: --lineprecision-report DIR
Causes mypy to generate a flat text file report with per-module
statistics of how many lines are typechecked etc.
.. option:: --txt-report / --xslt-txt-report DIR
Causes mypy to generate a text file type checking coverage 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.
To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.
Miscellaneous
*************
.. option:: --install-types
This flag causes mypy to install known missing stub packages for
third-party libraries using pip. It will display the pip command
that will be run, and expects a confirmation before installing
anything. For security reasons, these stubs are limited to only a
small subset of manually selected packages that have been
verified by the typeshed team. These packages include only stub
files and no executable code.
If you use this option without providing any files or modules to
type check, mypy will install stub packages suggested during the
previous mypy run. If there are files or modules to type check,
mypy first type checks those, and proposes to install missing
stubs at the end of the run, but only if any missing modules were
detected.
.. note::
This is new in mypy 0.900. Previous mypy versions included a
selection of third-party package stubs, instead of having
them installed separately.
.. option:: --non-interactive
When used together with :option:`--install-types `, this causes mypy to install all suggested stub
packages using pip without asking for confirmation, and then
continues to perform type checking using the installed stubs, if
some files or modules are provided to type check.
This is implemented as up to two mypy runs internally. The first run
is used to find missing stub packages, and output is shown from
this run only if no missing stub packages were found. If missing
stub packages were found, they are installed and then another run
is performed.
.. option:: --junit-xml JUNIT_XML
Causes mypy to generate a JUnit XML test result document with
type checking results. This can make it easier to integrate mypy
with continuous integration (CI) tools.
.. option:: --find-occurrences CLASS.MEMBER
This flag will make mypy print out all usages of a class member
based on static type information. This feature is experimental.
.. option:: --scripts-are-modules
This flag will give command line arguments that appear to be
scripts (i.e. files whose name does not end in ``.py``)
a module name derived from the script name rather than the fixed
name :py:mod:`__main__`.
This lets you check more than one script in a single mypy invocation.
(The default :py:mod:`__main__` is technically more correct, but if you
have many scripts that import a large package, the behavior enabled
by this flag is often more convenient.)
.. _lxml: https://pypi.org/project/lxml/
.. _SQLite: https://www.sqlite.org/
mypy-0.942/docs/source/common_issues.rst 0000644 0001751 0000171 00000065470 14217067311 021210 0 ustar runner docker 0000000 0000000 .. _common_issues:
Common issues and solutions
===========================
This section has examples of cases when you need to update your code
to use static typing, and ideas for working around issues if mypy
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.6 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
-------------------------------------------
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 `.
Example:
.. code-block:: python
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:
.. code-block:: python
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:
**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:
.. code-block:: python
def foo(a) -> str:
return '(' + a.split() + ')' # No error!
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``.
If you're having trouble debugging such situations,
:ref:`reveal_type() ` might come in handy.
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).
: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:
.. code-block:: python
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**.
.. 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:
Spurious errors and locally silencing the checker
-------------------------------------------------
You can use a ``# type: ignore`` comment to silence the type checker
on a particular line. For example, let's say our code is using
the C extension module ``frobnicate``, and there's no stub available.
Mypy will complain about this, as it has no information about the
module:
.. code-block:: python
import frobnicate # Error: No module "frobnicate"
frobnicate.start()
You can add a ``# type: ignore`` comment to tell mypy to ignore this
error:
.. code-block:: python
import frobnicate # type: ignore
frobnicate.start() # Okay!
The second line is now fine, since the ignore comment causes the name
``frobnicate`` to get an implicit ``Any`` type.
.. note::
You can use the form ``# type: ignore[]`` to only ignore
specific errors on the line. This way you are less likely to
silence unexpected errors that are not safe to ignore, and this
will also document what the purpose of the comment is. See
:ref:`error-codes` for more information.
.. note::
The ``# type: ignore`` comment will only assign the implicit ``Any``
type if mypy cannot find information about that particular module. So,
if we did have a stub available for ``frobnicate`` then mypy would
ignore the ``# type: ignore`` comment and typecheck the stub as usual.
Another option is to explicitly annotate values with type ``Any`` --
mypy will let you perform arbitrary operations on ``Any``
values. Sometimes there is no more precise type you can use for a
particular value, especially if you use dynamic Python features
such as :py:meth:`__getattr__ `:
.. code-block:: python
class Wrapper:
...
def __getattr__(self, a: str) -> Any:
return getattr(self._wrapped, a)
Finally, you can create a stub file (``.pyi``) for a file that
generates spurious errors. Mypy will only look at the stub file
and ignore the implementation, since stub files take precedence
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
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.
Issues with code at runtime
---------------------------
Idiomatic use of type annotations can sometimes run up against what a given
version of Python considers legal code. These can result in some of the
following errors when trying to run your code:
* ``ImportError`` from circular imports
* ``NameError: name "X" is not defined`` from forward references
* ``TypeError: 'type' object is not subscriptable`` from types that are not generic at runtime
* ``ImportError`` or ``ModuleNotFoundError`` from use of stub definitions not available at runtime
* ``TypeError: unsupported operand type(s) for |: 'type' and 'type'`` from use of new syntax
For dealing with these, see :ref:`runtime_troubles`.
Mypy runs are slow
------------------
If your mypy runs feel slow, you should probably use the :ref:`mypy
daemon `, which can speed up incremental mypy runtimes by
a factor of 10 or more. :ref:`Remote caching ` can
make cold mypy runs several times faster.
Types of empty collections
--------------------------
You often need to specify the type when you assign an empty list or
dict to a new variable, as mentioned earlier:
.. code-block:: python
a: List[int] = []
Without the annotation mypy can't always figure out the
precise type of ``a``.
You can use a simple empty list literal in a dynamically typed function (as the
type of ``a`` would be implicitly ``Any`` and need not be inferred), if type
of the variable has been declared or inferred before, or if you perform a simple
modification operation in the same scope (such as ``append`` for a list):
.. code-block:: python
a = [] # Okay because followed by append, inferred type List[int]
for i in range(n):
a.append(i * i)
However, in more complex cases an explicit type annotation can be
required (mypy will tell you this). Often the annotation can
make your code easier to understand, so it doesn't only help mypy but
everybody who is reading the code!
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.
.. code-block:: python
def f() -> None:
n = 1
...
n = 'x' # Type error: n has type int
.. note::
This limitation could be lifted in a future mypy
release.
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
not support ``sort()``) as a list and sort it in-place:
.. code-block:: python
def f(x: Sequence[int]) -> None:
# Type of x is Sequence[int] here; we don't know the concrete type.
x = list(x)
# Type of x is List[int] here.
x.sort() # Okay!
.. _variance:
Invariance vs covariance
------------------------
Most mutable generic collections are invariant, and mypy considers all
user-defined generic classes invariant by default
(see :ref:`variance-of-generics` for motivation). This could lead to some
unexpected errors when combined with type inference. For example:
.. code-block:: python
class A: ...
class B(A): ...
lst = [A(), A()] # Inferred type is List[A]
new_lst = [B(), B()] # inferred type is List[B]
lst = new_lst # mypy will complain about this, because List is invariant
Possible strategies in such situations are:
* Use an explicit type annotation:
.. code-block:: python
new_lst: List[A] = [B(), B()]
lst = new_lst # OK
* Make a copy of the right hand side:
.. code-block:: python
lst = list(new_lst) # Also OK
* Use immutable collections as annotations whenever possible:
.. code-block:: python
def f_bad(x: List[A]) -> A:
return x[0]
f_bad(new_lst) # Fails
def f_good(x: Sequence[A]) -> A:
return x[0]
f_good(new_lst) # OK
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``):
.. code-block:: python
shape = Circle() # Infer shape to be Circle
...
shape = Triangle() # Type error: Triangle is not a 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
Complex type tests
------------------
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
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::
Note that the :py:class:`object` type used in the above example is similar
to ``Object`` in Java: it only supports operations defined for *all*
objects, such as equality and :py:func:`isinstance`. The type ``Any``,
in contrast, supports all operations, even if they may fail at
runtime. The cast above would have been unnecessary if the type of
``o`` was ``Any``.
.. note::
You can read more about type narrowing techniques :ref:`here `.
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
confusing error messages. The tradeoff is that you as a programmer
sometimes have to give the type checker a little help.
.. _version_and_platform_checks:
Python version and system platform checks
-----------------------------------------
Mypy supports the ability to perform Python version checks and platform
checks (e.g. Windows vs Posix), ignoring code paths that won't be run on
the targeted Python version or platform. This allows you to more effectively
typecheck code that supports multiple versions of Python or multiple operating
systems.
More specifically, mypy will understand the use of :py:data:`sys.version_info` and
:py:data:`sys.platform` checks within ``if/elif/else`` statements. For example:
.. code-block:: python
import sys
# Distinguishing between different versions of Python:
if sys.version_info >= (3, 8):
# Python 3.8+ specific definitions and imports
elif sys.version_info[0] >= 3:
# Python 3 specific definitions and imports
else:
# Python 2 specific definitions and imports
# Distinguishing between different operating systems:
if sys.platform.startswith("linux"):
# Linux-specific code
elif sys.platform == "darwin":
# Mac-specific code
elif sys.platform == "win32":
# Windows-specific code
else:
# Other systems
As a special case, you can also use one of these checks in a top-level
(unindented) ``assert``; this makes mypy skip the rest of the file.
Example:
.. code-block:: python
import sys
assert sys.platform != 'win32'
# The rest of this file doesn't apply to Windows.
Some other expressions exhibit similar behavior; in particular,
:py:data:`~typing.TYPE_CHECKING`, variables named ``MYPY``, and any variable
whose name is passed to :option:`--always-true ` or :option:`--always-false `.
(However, ``True`` and ``False`` are not treated specially!)
.. note::
Mypy currently does not support more complex checks, and does not assign
any special meaning when assigning a :py:data:`sys.version_info` or :py:data:`sys.platform`
check to a variable. This may change in future versions of mypy.
By default, mypy will use your current version of Python and your current
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.
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
in :option:`--platform win32 `. See the documentation for :py:data:`sys.platform`
for examples of valid platform parameters.
.. _reveal-type:
Displaying the type of an expression
------------------------------------
You can use ``reveal_type(expr)`` to ask mypy to display the inferred
static type of an expression. This can be useful when you don't quite
understand how mypy handles a particular piece of code. Example:
.. code-block:: python
reveal_type((1, 'hello')) # Revealed type is "Tuple[builtins.int, builtins.str]"
You can also use ``reveal_locals()`` at any line in a file
to see the types of all local variables at once. Example:
.. code-block:: python
a = 1
b = 'one'
reveal_locals()
# Revealed local types are:
# a: builtins.int
# b: builtins.str
.. note::
``reveal_type`` and ``reveal_locals`` are only understood by mypy and
don't exist in Python. If you try to run your program, you'll have to
remove any ``reveal_type`` and ``reveal_locals`` calls before you can
run your code. Both are always available and you don't need to import
them.
.. _silencing-linters:
Silencing linters
-----------------
In some cases, linters will complain about unused imports or code. In
these cases, you can silence them with a comment after type comments, or on
the same line as the import:
.. code-block:: python
# to silence complaints about unused imports
from typing import List # noqa
a = None # type: List[int]
To silence the linter on the same line as a type comment
put the linter comment *after* the type comment:
.. code-block:: python
a = some_complex_thing() # type: ignore # noqa
Covariant subtyping of mutable protocol members is rejected
-----------------------------------------------------------
Mypy rejects this because this is potentially unsafe.
Consider this example:
.. code-block:: python
from typing_extensions import Protocol
class P(Protocol):
x: float
def fun(arg: P) -> None:
arg.x = 3.14
class C:
x = 42
c = C()
fun(c) # This is not safe
c.x << 5 # Since this will fail!
To work around this problem consider whether "mutating" is actually part
of a protocol. If not, then one can use a :py:class:`@property ` in
the protocol definition:
.. code-block:: python
from typing_extensions import Protocol
class P(Protocol):
@property
def x(self) -> float:
pass
def fun(arg: P) -> None:
...
class C:
x = 42
fun(C()) # OK
Dealing with conflicting names
------------------------------
Suppose you have a class with a method whose name is the same as an
imported (or built-in) type, and you want to use the type in another
method signature. E.g.:
.. code-block:: python
class Message:
def bytes(self):
...
def register(self, path: bytes): # error: Invalid type "mod.Message.bytes"
...
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:
.. code-block:: python
bytes_ = bytes
class Message:
def bytes(self):
...
def register(self, path: bytes_):
...
Using a development mypy build
------------------------------
You can install the latest development version of mypy from source. Clone the
`mypy repository on GitHub `_, and then run
``pip install`` locally:
.. code-block:: text
git clone https://github.com/python/mypy.git
cd mypy
sudo python3 -m pip install --upgrade .
Variables vs type aliases
-------------------------
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. A variable with type ``Type[...]`` is defined using an assignment with an
explicit type annotation:
.. code-block:: python
class A: ...
tp: Type[A] = A
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
class A: ...
Alias = A
You can also use ``TypeAlias`` (:pep:`613`) to define an *explicit type alias*:
.. code-block:: python
from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier
class A: ...
Alias: TypeAlias = A
You should always use ``TypeAlias`` to define a type alias in a class body or
inside a function.
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 `):
.. 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
`_.
For return types, it's unsafe to override a method with a more general
return type.
Other incompatible signature changes in method overrides, such as
adding an extra required parameter, or removing an optional parameter,
will also generate errors. The signature of a method in a subclass
should accept all valid calls to the base class method. Mypy
treats a subclass as a subtype of the base class. An instance of a
subclass is valid everywhere where an instance of the base class is
valid.
This example demonstrates both safe and unsafe overrides:
.. code-block:: python
from typing import Sequence, List, Iterable
class A:
def test(self, t: Sequence[int]) -> Sequence[str]:
...
class GeneralizedArgument(A):
# A more general argument type is okay
def test(self, t: Iterable[int]) -> Sequence[str]: # OK
...
class NarrowerArgument(A):
# A more specific argument type isn't accepted
def test(self, t: List[int]) -> Sequence[str]: # Error
...
class NarrowerReturn(A):
# A more specific return type is fine
def test(self, t: Sequence[int]) -> List[str]: # OK
...
class GeneralizedReturn(A):
# A more general return type is an error
def test(self, t: Sequence[int]) -> Iterable[str]: # Error
...
You can use ``# type: ignore[override]`` to silence the error. Add it
to the line that generates the error, if you decide that type safety is
not necessary:
.. code-block:: python
class NarrowerArgument(A):
def test(self, t: List[int]) -> Sequence[str]: # type: ignore[override]
...
.. _unreachable:
Unreachable code
----------------
Mypy may consider some code as *unreachable*, even if it might not be
immediately obvious why. It's important to note that mypy will *not*
type check such code. Consider this example:
.. code-block:: python
class Foo:
bar: str = ''
def bar() -> None:
foo: Foo = Foo()
return
x: int = 'abc' # Unreachable -- no error
It's easy to see that any statement after ``return`` is unreachable,
and hence mypy will not complain about the mis-typed code below
it. For a more subtle example, consider this code:
.. code-block:: python
class Foo:
bar: str = ''
def bar() -> None:
foo: Foo = Foo()
assert foo.bar is None
x: int = 'abc' # Unreachable -- no error
Again, mypy will not report any errors. The type of ``foo.bar`` is
``str``, and mypy reasons that it can never be ``None``. Hence the
``assert`` statement will always fail and the statement below will
never be executed. (Note that in Python, ``None`` is not an empty
reference but an object of type ``None``.)
In this example mypy will go on to check the last line and report an
error, since mypy thinks that the condition could be either True or
False:
.. code-block:: python
class Foo:
bar: str = ''
def bar() -> None:
foo: Foo = Foo()
if not foo.bar:
return
x: int = 'abc' # Reachable -- error
If you use the :option:`--warn-unreachable ` flag, mypy will generate
an error about each unreachable code block.
Narrowing and inner functions
-----------------------------
Because closures in Python are late-binding (https://docs.python-guide.org/writing/gotchas/#late-binding-closures),
mypy will not narrow the type of a captured variable in an inner function.
This is best understood via an example:
.. code-block:: python
def foo(x: Optional[int]) -> Callable[[], int]:
if x is None:
x = 5
print(x + 1) # mypy correctly deduces x must be an int here
def inner() -> int:
return x + 1 # but (correctly) complains about this line
x = None # because x could later be assigned None
return inner
inner = foo(5)
inner() # this will raise an error when called
To get this code to type check, you could assign ``y = x`` after ``x`` has been
narrowed, and use ``y`` in the inner function, or add an assert in the inner
function.
mypy-0.942/docs/source/conf.py 0000644 0001751 0000171 00000022060 14217067311 017056 0 ustar runner docker 0000000 0000000 # -*- coding: utf-8 -*-
#
# Mypy documentation build configuration file, created by
# sphinx-quickstart on Sun Sep 14 19:50:35 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
from sphinx.application import Sphinx
from sphinx.util.docfields import Field
# 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('../..'))
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'
# 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']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Mypy'
copyright = u'2016, Jukka Lehtosalo'
# 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]
# 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
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#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
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#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()]
# 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 = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#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
# 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
# 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']
# 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 = []
# 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'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is 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 = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
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': '',
}
# 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'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#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)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (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'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
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),
}
def setup(app: Sphinx) -> None:
app.add_object_type(
'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',)),
]
)
mypy-0.942/docs/source/config_file.rst 0000644 0001751 0000171 00000075232 14217067311 020566 0 ustar runner docker 0000000 0000000 .. _config-file:
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`).
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.
Most flags correspond closely to :ref:`command-line flags
` but there are some differences in flag names and some
flags may take a different value based on the module being processed.
Some flags support user home directory and environment variable expansion.
To refer to the user home directory, use ``~`` at the beginning of the path.
To expand environment variables use ``$VARNAME`` or ``${VARNAME}``.
Config file format
******************
The configuration file format is the usual
:doc:`ini file ` format. It should contain
section names in square brackets and flag settings of the form
`NAME = VALUE`. Comments start with ``#`` characters.
- A section named ``[mypy]`` must be present. This specifies
the global flags.
- Additional sections named ``[mypy-PATTERN1,PATTERN2,...]`` may be
present, where ``PATTERN1``, ``PATTERN2``, etc., are comma-separated
patterns of fully-qualified module names, with some components optionally
replaced by the '*' character (e.g. ``foo.bar``, ``foo.bar.*``, ``foo.*.baz``).
These sections specify additional flags that only apply to *modules*
whose name matches at least one of the patterns.
A pattern of the form ``qualified_module_name`` matches only the named module,
while ``dotted_module_name.*`` matches ``dotted_module_name`` and any
submodules (so ``foo.bar.*`` would match all of ``foo.bar``,
``foo.bar.baz``, and ``foo.bar.baz.quux``).
Patterns may also be "unstructured" wildcards, in which stars may
appear in the middle of a name (e.g
``site.*.migrations.*``). Stars match zero or more module
components (so ``site.*.migrations.*`` can match ``site.migrations``).
.. _config-precedence:
When options conflict, the precedence order for configuration is:
1. :ref:`Inline configuration ` in the source file
2. Sections with concrete module names (``foo.bar``)
3. Sections with "unstructured" wildcard patterns (``foo.*.baz``),
with sections later in the configuration file overriding
sections earlier.
4. Sections with "well-structured" wildcard patterns
(``foo.bar.*``), with more specific overriding more general.
5. Command line options.
6. Top-level configuration file options.
The difference in precedence order between "structured" patterns (by
specificity) and "unstructured" patterns (by order in the file) is
unfortunate, and is subject to change in future versions.
.. note::
The :confval:`warn_unused_configs` flag may be useful to debug misspelled
section names.
.. note::
Configuration flags are liable to change between releases.
Per-module and global options
*****************************
Some of the config options may be set either globally (in the ``[mypy]`` section)
or on a per-module basis (in sections like ``[mypy-foo.bar]``).
If you set an option both globally and for a specific module, the module configuration
options take precedence. This lets you set global defaults and override them on a
module-by-module basis. If multiple pattern sections match a module, :ref:`the options from the
most specific section are used where they disagree `.
Some other options, as specified in their description,
may only be set in the global section (``[mypy]``).
Inverting option values
***********************
Options that take a boolean value may be inverted by adding ``no_`` to
their name or by (when applicable) swapping their prefix from
``disallow`` to ``allow`` (and vice versa).
Examples
********
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.
.. code-block:: ini
# Global options:
[mypy]
python_version = 2.7
warn_return_any = True
warn_unused_configs = True
# Per-module options:
[mypy-mycode.foo.*]
disallow_untyped_defs = True
[mypy-mycode.bar]
warn_return_any = False
[mypy-somelibrary]
ignore_missing_imports = True
This config file specifies three global options in the ``[mypy]`` section. These three
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
to have type ``Any``.
3. 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
type checks code in ``mycode.foo.*`` and ``mycode.bar``, which we assume here are two modules
that you wrote. The final config option changes how mypy type checks ``somelibrary``, which we
assume here is some 3rd party library you've installed and are importing. These options will:
1. Selectively disallow untyped function definitions only within the ``mycode.foo``
package -- that is, only for function definitions defined in the
``mycode/foo`` directory.
2. Selectively *disable* the "function is returning any" warnings within
``mycode.bar`` only. This overrides the global default we set earlier.
3. Suppress any error messages generated when your codebase tries importing the
module ``somelibrary``. This is useful if ``somelibrary`` is some 3rd party library
missing type hints.
.. _config-file-import-discovery:
Import discovery
****************
For more information, see the :ref:`Import discovery `
section of the command line docs.
.. confval:: mypy_path
:type: string
Specifies the paths to use, after trying the paths from ``MYPYPATH`` environment
variable. Useful if you'd like to keep stubs in your repo, along with the config file.
Multiple paths are always separated with a ``:`` or ``,`` regardless of the platform.
User home directory and environment variables will be expanded.
Relative paths are treated relative to the working directory of the mypy command,
not the config file.
Use the ``MYPY_CONFIG_FILE_DIR`` environment variable to refer to paths relative to
the config file (e.g. ``mypy_path = $MYPY_CONFIG_FILE_DIR/src``).
This option may only be set in the global section (``[mypy]``).
**Note:** On Windows, use UNC paths to avoid using ``:`` (e.g. ``\\127.0.0.1\X$\MyDir`` where ``X`` is the drive letter).
.. confval:: files
:type: comma-separated list of strings
A comma-separated list of paths which should be checked by mypy if none are given on the command
line. Supports recursive file globbing using :py:mod:`glob`, where ``*`` (e.g. ``*.py``) matches
files in the current directory and ``**/`` (e.g. ``**/*.py``) matches files in any directories below
the current one. User home directory and environment variables will be expanded.
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 (``/``) 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
Enables :pep:`420` style namespace packages. See the
corresponding flag :option:`--namespace-packages ` for more information.
This option may only be set in the global section (``[mypy]``).
.. confval:: explicit_package_bases
:type: boolean
:default: False
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
paths to modules ` for details.
This option may only be set in the global section (``[mypy]``).
.. confval:: ignore_missing_imports
:type: boolean
:default: False
Suppresses error messages about imports that cannot be resolved.
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.
.. confval:: follow_imports
:type: string
:default: ``normal``
Directs what to do with imports when the imported module is found
as a ``.py`` file and not part of the files, modules and packages
provided on the command line.
The four possible values are ``normal``, ``silent``, ``skip`` and
``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.
.. confval:: follow_imports_for_stubs
:type: boolean
:default: False
Determines whether to respect the :confval:`follow_imports` setting even for
stub (``.pyi``) files.
Used in conjunction with :confval:`follow_imports=skip `, this can be used
to suppress the import of a module from ``typeshed``, replacing it
with ``Any``.
Used in conjunction with :confval:`follow_imports=error `, this can be used
to make any use of a particular ``typeshed`` module an error.
.. note::
This is not supported by the mypy daemon.
.. confval:: python_executable
:type: string
Specifies the path to the Python executable to inspect to collect
a list of available :ref:`PEP 561 packages `. User
home directory and environment variables will be expanded. Defaults to
the executable used to run mypy.
This option may only be set in the global section (``[mypy]``).
.. confval:: no_site_packages
:type: bool
:default: False
Disables using type information in installed packages (see :pep:`561`).
This will also disable searching for a usable Python executable. This acts
the same as :option:`--no-site-packages ` command
line flag.
.. confval:: no_silence_site_packages
:type: boolean
:default: False
Enables reporting error messages generated within installed packages (see
:pep:`561` for more details on distributing type information). Those error
messages are suppressed by default, since you are usually not able to
control errors in 3rd party code.
This option may only be set in the global section (``[mypy]``).
Platform configuration
**********************
.. confval:: python_version
:type: string
Specifies the Python version used to parse and check the target
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.
This option may only be set in the global section (``[mypy]``).
.. confval:: platform
:type: string
Specifies the OS platform for the target program, for example
``darwin`` or ``win32`` (meaning OS X or Windows, respectively).
The default is the current platform as revealed by Python's
:py:data:`sys.platform` variable.
This option may only be set in the global section (``[mypy]``).
.. confval:: always_true
:type: comma-separated list of strings
Specifies a list of variables that mypy will treat as
compile-time constants that are always true.
.. confval:: always_false
:type: comma-separated list of strings
Specifies a list of variables that mypy will treat as
compile-time constants that are always false.
Disallow dynamic typing
***********************
For more information, see the :ref:`Disallow dynamic typing `
section of the command line docs.
.. confval:: disallow_any_unimported
:type: boolean
:default: False
Disallows usage of types that come from unfollowed imports (anything imported from
an unfollowed import is automatically given a type of ``Any``).
.. confval:: disallow_any_expr
:type: boolean
:default: False
Disallows all expressions in the module that have type ``Any``.
.. confval:: disallow_any_decorated
:type: boolean
:default: False
Disallows functions that have ``Any`` in their signature after decorator transformation.
.. confval:: disallow_any_explicit
:type: boolean
:default: False
Disallows explicit ``Any`` in type positions such as type annotations and generic
type parameters.
.. confval:: disallow_any_generics
:type: boolean
:default: False
Disallows usage of generic types that do not specify explicit type parameters.
.. confval:: disallow_subclassing_any
:type: boolean
:default: False
Disallows subclassing a value of type ``Any``.
Untyped definitions and calls
*****************************
For more information, see the :ref:`Untyped definitions and calls `
section of the command line docs.
.. confval:: disallow_untyped_calls
:type: boolean
:default: False
Disallows calling functions without type annotations from functions with type
annotations.
.. confval:: disallow_untyped_defs
:type: boolean
:default: False
Disallows defining functions without type annotations or with incomplete type
annotations.
.. confval:: disallow_incomplete_defs
:type: boolean
:default: False
Disallows defining functions with incomplete type annotations.
.. confval:: check_untyped_defs
:type: boolean
:default: False
Type-checks the interior of functions without type annotations.
.. confval:: disallow_untyped_decorators
:type: boolean
:default: False
Reports an error whenever a function with type annotations is decorated with a
decorator without annotations.
.. _config-file-none-and-optional-handling:
None and Optional handling
**************************
For more information, see the :ref:`None and Optional handling `
section of the command line docs.
.. confval:: no_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`.
.. confval:: strict_optional
:type: boolean
:default: True
Enables or disables strict Optional checks. If False, mypy treats ``None``
as compatible with every type.
**Note:** This was False by default in mypy versions earlier than 0.600.
Configuring warnings
********************
For more information, see the :ref:`Configuring warnings `
section of the command line docs.
.. confval:: warn_redundant_casts
:type: boolean
:default: False
Warns about casting an expression to its inferred type.
This option may only be set in the global section (``[mypy]``).
.. confval:: warn_unused_ignores
:type: boolean
:default: False
Warns about unneeded ``# type: ignore`` comments.
.. confval:: warn_no_return
:type: boolean
:default: True
Shows errors for missing return statements on some execution paths.
.. confval:: warn_return_any
:type: boolean
:default: False
Shows a warning when returning a value with type ``Any`` from a function
declared with a non- ``Any`` return type.
.. confval:: warn_unreachable
:type: boolean
:default: False
Shows a warning when encountering any code inferred to be unreachable or
redundant after performing type analysis.
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
:default: False
Ignores all non-fatal errors.
Miscellaneous strictness flags
******************************
For more information, see the :ref:`Miscellaneous strictness flags `
section of the command line docs.
.. confval:: allow_untyped_globals
:type: boolean
:default: False
Causes mypy to suppress errors caused by not being able to fully
infer the types of global and class variables.
.. confval:: allow_redefinition
:type: boolean
:default: False
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
:type: boolean
:default: False
Disallows inferring variable type for ``None`` from two assignments in different scopes.
This is always implicitly enabled when using the :ref:`mypy daemon `.
.. confval:: disable_error_code
:type: comma-separated list of strings
Allows disabling one or multiple error codes globally.
.. confval:: implicit_reexport
:type: boolean
:default: True
By default, imported values to a module are treated as exported and mypy allows
other modules to import them. When false, mypy will not re-export unless
the item is imported using from-as or is included in ``__all__``. Note that mypy
treats stub files as if this is always disabled. For example:
.. code-block:: python
# This won't re-export the value
from foo import bar
# 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']
.. confval:: strict_equality
:type: boolean
:default: False
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
**************************
For more information, see the :ref:`Configuring error messages `
section of the command line docs.
These options may only be set in the global section (``[mypy]``).
.. confval:: show_error_context
:type: boolean
:default: False
Prefixes each error with the relevant context.
.. confval:: show_column_numbers
:type: boolean
:default: False
Shows column numbers in error messages.
.. confval:: show_error_codes
:type: boolean
:default: False
Shows error codes in error messages. See :ref:`error-codes` for more information.
.. confval:: pretty
:type: boolean
:default: False
Use visually nicer output in error messages: use soft word wrap,
show source code snippets, and show error location markers.
.. confval:: color_output
:type: boolean
:default: True
Shows error messages with color enabled.
.. confval:: error_summary
:type: boolean
:default: True
Shows a short summary line after error messages.
.. confval:: show_absolute_path
:type: boolean
:default: False
Show absolute paths to files.
Incremental mode
****************
These options may only be set in the global section (``[mypy]``).
.. confval:: incremental
:type: boolean
:default: True
Enables :ref:`incremental mode `.
.. confval:: cache_dir
:type: string
:default: ``.mypy_cache``
Specifies the location where mypy stores incremental cache info.
User home directory and environment variables will be expanded.
This setting will be overridden by the ``MYPY_CACHE_DIR`` environment
variable.
Note that the cache is only read when incremental mode is enabled
but is always written to, unless the value is set to ``/dev/null``
(UNIX) or ``nul`` (Windows).
.. confval:: sqlite_cache
:type: boolean
:default: False
Use an `SQLite`_ database to store the cache.
.. confval:: cache_fine_grained
:type: boolean
:default: False
Include fine-grained dependency information in the cache for the mypy daemon.
.. confval:: skip_version_check
:type: boolean
:default: False
Makes mypy use incremental cache data even if it was generated by a
different version of mypy. (By default, mypy will perform a version
check and regenerate the cache if it was written by older versions of mypy.)
.. confval:: skip_cache_mtime_checks
:type: boolean
:default: False
Skip cache internal consistency checks based on mtime.
Advanced options
****************
These options may only be set in the global section (``[mypy]``).
.. confval:: plugins
:type: comma-separated list of strings
A comma-separated list of mypy plugins. See :ref:`extending-mypy-using-plugins`.
.. confval:: pdb
:type: boolean
:default: False
Invokes :mod:`pdb` on fatal error.
.. confval:: show_traceback
:type: boolean
:default: False
Shows traceback on fatal error.
.. confval:: raise_exceptions
:type: boolean
:default: False
Raise exception on fatal error.
.. confval:: custom_typing_module
:type: string
Specifies a custom module to use as a substitute for the :py:mod:`typing` module.
.. confval:: custom_typeshed_dir
: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.
.. confval:: warn_incomplete_stub
:type: boolean
:default: False
Warns about missing type annotations in typeshed. This is only relevant
in combination with :confval:`disallow_untyped_defs` or :confval:`disallow_incomplete_defs`.
Report generation
*****************
If these options are set, mypy will generate a report in the specified
format into the specified directory.
.. confval:: any_exprs_report
:type: string
Causes mypy to generate a text file report documenting how many
expressions of type ``Any`` are present within your codebase.
.. confval:: cobertura_xml_report
:type: string
Causes mypy to generate a Cobertura XML type checking coverage 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
:type: string
Causes mypy to generate an HTML type checking coverage 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
:type: string
Causes mypy to generate a text file report documenting the functions
and lines that are typed and untyped within your codebase.
.. confval:: linecoverage_report
:type: string
Causes mypy to generate a JSON file that maps each source file's
absolute filename to a list of line numbers that belong to typed
functions in that file.
.. confval:: lineprecision_report
:type: string
Causes mypy to generate a flat text file report with per-module
statistics of how many lines are typechecked etc.
.. confval:: txt_report / xslt_txt_report
:type: string
Causes mypy to generate a text file type checking coverage 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
:type: string
Causes mypy to generate an XML type checking coverage report.
To generate this report, you must either manually install the `lxml`_
library or specify mypy installation with the setuptools extra
``mypy[reports]``.
Miscellaneous
*************
These options may only be set in the global section (``[mypy]``).
.. confval:: junit_xml
:type: string
Causes mypy to generate a JUnit XML test result document with
type checking results. This can make it easier to integrate mypy
with continuous integration (CI) tools.
.. confval:: scripts_are_modules
:type: boolean
:default: False
Makes script ``x`` become module ``x`` instead of ``__main__``. This is
useful when checking multiple scripts in a single run.
.. confval:: warn_unused_configs
:type: boolean
:default: False
Warns about per-module sections in the config file that do not
match any files processed when invoking mypy.
(This requires turning off incremental mode using :confval:`incremental = False `.)
.. confval:: verbosity
:type: integer
:default: 0
Controls how much debug output will be generated. Higher numbers are more verbose.
.. _using-a-pyproject-toml:
Using a pyproject.toml file
***************************
Instead of using a ``mypy.ini`` file, a ``pyproject.toml`` file (as specified by
`PEP 518`_) may be used instead. A few notes on doing so:
* The ``[mypy]`` section should have ``tool.`` prepended to its name:
* I.e., ``[mypy]`` would become ``[tool.mypy]``
* The module specific sections should be moved into ``[[tool.mypy.overrides]]`` sections:
* For example, ``[mypy-packagename]`` would become:
.. code-block:: toml
[[tool.mypy.overrides]]
module = 'packagename'
...
* Multi-module specific sections can be moved into a single ``[[tool.mypy.overrides]]`` section with a
module property set to an array of modules:
* For example, ``[mypy-packagename,packagename2]`` would become:
.. code-block:: toml
[[tool.mypy.overrides]]
module = [
'packagename',
'packagename2'
]
...
* The following care should be given to values in the ``pyproject.toml`` files as compared to ``ini`` files:
* Strings must be wrapped in double quotes, or single quotes if the string contains special characters
* Boolean values should be all lower case
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``
**************************
Here is an example of a ``pyproject.toml`` file. To use this config file, place it at the root
of your repo (or append it to the end of an existing ``pyproject.toml`` file) and run mypy.
.. code-block:: toml
# mypy global options:
[tool.mypy]
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:
[[tool.mypy.overrides]]
module = "mycode.foo.*"
disallow_untyped_defs = true
[[tool.mypy.overrides]]
module = "mycode.bar"
warn_return_any = false
[[tool.mypy.overrides]]
module = [
"somelibrary",
"some_other_library"
]
ignore_missing_imports = true
.. _lxml: https://pypi.org/project/lxml/
.. _SQLite: https://www.sqlite.org/
.. _PEP 518: https://www.python.org/dev/peps/pep-0518/
.. _TOML Documentation: https://toml.io/
mypy-0.942/docs/source/duck_type_compatibility.rst 0000644 0001751 0000171 00000003614 14217067311 023235 0 ustar runner docker 0000000 0000000 Duck type compatibility
-----------------------
In Python, certain types are compatible even though they aren't subclasses of
each other. For example, ``int`` objects are valid whenever ``float`` objects
are expected. Mypy supports this idiom via *duck type compatibility*. This is
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
and also behaves as expected:
.. code-block:: python
import math
def degrees_to_radians(degrees: float) -> float:
return math.pi * degrees / 180
n = 90 # Inferred type 'int'
print(degrees_to_radians(n)) # Okay!
You can also often use :ref:`protocol-types` to achieve a similar effect in
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.
mypy-0.942/docs/source/dynamic_typing.rst 0000644 0001751 0000171 00000004737 14217067311 021342 0 ustar runner docker 0000000 0000000 .. _dynamic-typing:
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``:
.. 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
Operations on Any values
------------------------
You can do anything using a value with type ``Any``, and type checker
does not complain:
.. code-block:: python
def f(x: Any) -> int:
# All of these are valid!
x.foobar(1, y=2)
print(x[3] + 'f')
if x:
x.z = x(2)
open(x).read()
return x
Values derived from an ``Any`` value also often 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``:
.. code-block:: python
def f(x: Any) -> None:
y = x.foo() # y has type Any
y.bar() # Okay as well!
``Any`` types may propagate through your program, making type checking
less effective, unless you are careful.
Any vs. object
--------------
The type :py:class:`object` is another type that can have an instance of arbitrary
type as a value. Unlike ``Any``, :py:class:`object` is an ordinary static type (it
is similar to ``Object`` in Java), and only operations valid for *all*
types are accepted for :py:class:`object` values. These are all valid:
.. code-block:: python
def f(o: object) -> None:
if o:
print(o)
print(isinstance(o, int))
o = 2
o = 'foo'
These are, however, flagged as errors, since not all objects support these
operations:
.. code-block:: python
def f(o: object) -> None:
o.foo() # Error!
o + 2 # Error!
open(o) # Error!
n = 1 # type: int
n = o # Error!
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``).
mypy-0.942/docs/source/error_code_list.rst 0000644 0001751 0000171 00000050665 14217067311 021503 0 ustar runner docker 0000000 0000000 .. _error-code-list:
Error codes enabled by default
==============================
This section documents various errors codes that mypy can generate
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.
Check that attribute exists [attr-defined]
------------------------------------------
Mypy checks that an attribute is defined in the target class or module
when using the dot operator. This applies to both getting and setting
an attribute. New attributes are defined by assignments in the class
body, or assignments to ``self.x`` in methods. These assignments don't
generate ``attr-defined`` errors.
Example:
.. code-block:: python
class Resource:
def __init__(self, name: str) -> None:
self.name = name
r = Resource('x')
print(r.name) # OK
print(r.id) # Error: "Resource" has no attribute "id" [attr-defined]
r.id = 5 # Error: "Resource" has no attribute "id" [attr-defined]
This error code is also generated if an imported name is not defined
in the module in a ``from ... import`` statement (as long as the
target module can be found):
.. code-block:: python
# Error: Module "os" has no attribute "non_existent" [attr-defined]
from os import non_existent
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.
Check that attribute exists in each union item [union-attr]
-----------------------------------------------------------
If you access the attribute of a value with a union type, mypy checks
that the attribute is defined for *every* type in that
union. Otherwise the operation can fail at runtime. This also applies
to optional types.
Example:
.. code-block:: python
from typing import Union
class Cat:
def sleep(self) -> None: ...
def miaow(self) -> None: ...
class Dog:
def sleep(self) -> None: ...
def follow_me(self) -> None: ...
def func(animal: Union[Cat, Dog]) -> None:
# OK: 'sleep' is defined for both Cat and Dog
animal.sleep()
# Error: Item "Cat" of "Union[Cat, Dog]" has no attribute "follow_me" [union-attr]
animal.follow_me()
You can often work around these errors by using ``assert isinstance(obj, ClassName)``
or ``assert obj is not None`` to tell mypy that you know that the type is more specific
than what mypy thinks.
Check that name is defined [name-defined]
-----------------------------------------
Mypy expects that all references to names have a corresponding
definition in an active scope, such as an assignment, function
definition or an import. This can catch missing definitions, missing
imports, and typos.
This example accidentally calls ``sort()`` instead of :py:func:`sorted`:
.. code-block:: python
x = sort([3, 2, 4]) # Error: Name "sort" is not defined [name-defined]
Check arguments in calls [call-arg]
-----------------------------------
Mypy expects that the number and names of arguments match the called function.
Note that argument type checks have a separate error code ``arg-type``.
Example:
.. code-block:: python
from typing import Sequence
def greet(name: str) -> None:
print('hello', name)
greet('jack') # OK
greet('jill', 'jack') # Error: Too many arguments for "greet" [call-arg]
Check argument types [arg-type]
-------------------------------
Mypy checks that argument types in a call match the declared argument
types in the signature of the called function (if one exists).
Example:
.. code-block:: python
from typing import Optional
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))
Check calls to overloaded functions [call-overload]
---------------------------------------------------
When you call an overloaded function, mypy checks that at least one of
the signatures of the overload items match the argument types in the
call.
Example:
.. code-block:: python
from typing import overload, Optional
@overload
def inc_maybe(x: None) -> None: ...
@overload
def inc_maybe(x: int) -> int: ...
def inc_maybe(x: Optional[int]) -> Optional[int]:
if x is None:
return None
else:
return x + 1
inc_maybe(None) # OK
inc_maybe(5) # OK
# Error: No overload variant of "inc_maybe" matches argument type "float" [call-overload]
inc_maybe(1.2)
Check validity of types [valid-type]
------------------------------------
Mypy checks that each type annotation and any expression that
represents a type is a valid type. Examples of valid types include
classes, union types, callable types, type aliases, and literal types.
Examples of invalid types include bare integer literals, functions,
variables, and modules.
This example incorrectly uses the function ``log`` as a type:
.. code-block:: python
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)
You can use :py:data:`~typing.Callable` as the type for callable objects:
.. code-block:: python
from typing import Callable
# OK
def log_all(objs: list[object], f: Callable[[object], None]) -> None:
for x in objs:
f(x)
Require annotation if variable type is unclear [var-annotated]
--------------------------------------------------------------
In some cases mypy can't infer the type of a variable without an
explicit annotation. Mypy treats this as an error. This typically
happens when you initialize a variable with an empty collection or
``None``. If mypy can't infer the collection item type, mypy replaces
any parts of the type it couldn't infer with ``Any`` and generates an
error.
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 = []
reveal_type(Bundle().items) # list[Any]
To address this, we add an explicit annotation:
.. code-block:: python
class Bundle:
def __init__(self) -> None:
self.items: list[str] = [] # OK
reveal_type(Bundle().items) # list[str]
Check validity of overrides [override]
--------------------------------------
Mypy checks that an overridden method or attribute is compatible with
the base class. A method in a subclass must accept all arguments
that the base class method accepts, and the return type must conform
to the return type in the base class (Liskov substitution principle).
Argument types can be more general is a subclass (i.e., they can vary
contravariantly). The return type can be narrowed in a subclass
(i.e., it can vary covariantly). It's okay to define additional
arguments in a subclass method, as long all extra arguments have default
values or can be left out (``*args``, for example).
Example:
.. code-block:: python
from typing import Optional, Union
class Base:
def method(self,
arg: int) -> Optional[int]:
...
class Derived(Base):
def method(self,
arg: Union[int, str]) -> int: # OK
...
class DerivedBad(Base):
# Error: Argument 1 of "method" is incompatible with "Base" [override]
def method(self,
arg: bool) -> int:
...
Check that function returns a value [return]
--------------------------------------------
If a function has a non-``None`` return type, mypy expects that the
function always explicitly returns a value (or raises an exception).
The function should not fall off the end of the function, since this
is often a bug.
Example:
.. code-block:: python
# Error: Missing return statement [return]
def show(x: int) -> int:
print(x)
# Error: Missing return statement [return]
def pred1(x: int) -> int:
if x > 0:
return x - 1
# OK
def pred2(x: int) -> int:
if x > 0:
return x - 1
else:
raise ValueError('not defined for zero')
Check that return value is compatible [return-value]
----------------------------------------------------
Mypy checks that the returned value is compatible with the type
signature of the function.
Example:
.. code-block:: python
def func(x: int) -> str:
# Error: Incompatible return value type (got "int", expected "str") [return-value]
return x + 1
Check types in assignment statement [assignment]
------------------------------------------------
Mypy checks that the assigned expression is compatible with the
assignment target (or targets).
Example:
.. code-block:: python
class Resource:
def __init__(self, name: str) -> None:
self.name = name
r = Resource('A')
r.name = 'B' # OK
# Error: Incompatible types in assignment (expression has type "int",
# variable has type "str") [assignment]
r.name = 5
Check type variable values [type-var]
-------------------------------------
Mypy checks that value of a type variable is compatible with a value
restriction or the upper bound type.
Example:
.. code-block:: python
from typing import TypeVar
T1 = TypeVar('T1', int, float)
def add(x: T1, y: T1) -> T1:
return x + y
add(4, 5.5) # OK
# Error: Value of type variable "T1" of "add" cannot be "str" [type-var]
add('x', 'y')
Check uses of various operators [operator]
------------------------------------------
Mypy checks that operands support a binary or unary operation, such as
``+`` or ``~``. Indexing operations are so common that they have their
own error code ``index`` (see below).
Example:
.. code-block:: python
# Error: Unsupported operand types for + ("int" and "str") [operator]
1 + 'x'
Check indexing operations [index]
---------------------------------
Mypy checks that the indexed value in indexing operation such as
``x[y]`` supports indexing, and that the index expression has a valid
type.
Example:
.. code-block:: python
a = {'x': 1, 'y': 2}
a['x'] # OK
# 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]
a[b'x'] = 4
Check list items [list-item]
----------------------------
When constructing a list using ``[item, ...]``, mypy checks that each item
is compatible with the list type that is inferred from the surrounding
context.
Example:
.. code-block:: python
# Error: List item 0 has incompatible type "int"; expected "str" [list-item]
a: list[str] = [0]
Check dict items [dict-item]
----------------------------
When constructing a dictionary using ``{key: value, ...}`` or ``dict(key=value, ...)``,
mypy checks that each key and value is compatible with the dictionary type that is
inferred from the surrounding context.
Example:
.. code-block:: python
# Error: Dict entry 0 has incompatible type "str": "str"; expected "str": "int" [dict-item]
d: dict[str, int] = {'key': 'value'}
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 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:
.. code-block:: python
from typing_extensions import TypedDict
class Point(TypedDict):
x: int
y: int
# Error: Incompatible types (expression has type "float",
# TypedDict item "x" has type "int") [typeddict-item]
p: Point = {'x': 1.2, 'y': 4}
Check that type of target is known [has-type]
---------------------------------------------
Mypy sometimes generates an error when it hasn't inferred any type for
a variable being referenced. This can happen for references to
variables that are initialized later in the source file, and for
references across modules that form an import cycle. When this
happens, the reference gets an implicit ``Any`` type.
In this example the definitions of ``x`` and ``y`` are circular:
.. code-block:: python
class Problem:
def set_x(self) -> None:
# Error: Cannot determine type of "y" [has-type]
self.x = self.y
def set_y(self) -> None:
self.y = self.x
To work around this error, you can add an explicit type annotation to
the target variable or attribute. Sometimes you can also reorganize
the code so that the definition of the variable is placed earlier than
the reference to the variable in a source file. Untangling cyclic
imports may also help.
We add an explicit annotation to the ``y`` attribute to work around
the issue:
.. code-block:: python
class Problem:
def set_x(self) -> None:
self.x = self.y # OK
def set_y(self) -> None:
self.y: int = self.x # Added annotation here
Check that import target can be found [import]
----------------------------------------------
Mypy generates an error if it can't find the source code or a stub file
for an imported module.
Example:
.. code-block:: python
# Error: Cannot find implementation or library stub for module named 'acme' [import]
import acme
See :ref:`ignore-missing-imports` for how to work around these errors.
Check that each name is defined once [no-redef]
-----------------------------------------------
Mypy may generate an error if you have multiple definitions for a name
in the same namespace. The reason is that this is often an error, as
the second definition may overwrite the first one. Also, mypy often
can't be able to determine whether references point to the first or
the second definition, which would compromise type checking.
If you silence this error, all references to the defined name refer to
the *first* definition.
Example:
.. code-block:: python
class A:
def __init__(self, x: int) -> None: ...
class A: # Error: Name "A" already defined on line 1 [no-redef]
def __init__(self, x: str) -> None: ...
# Error: Argument 1 to "A" has incompatible type "str"; expected "int"
# (the first definition wins!)
A('x')
Check that called function returns a value [func-returns-value]
---------------------------------------------------------------
Mypy reports an error if you call a function with a ``None``
return type and don't ignore the return value, as this is
usually (but not always) a programming error.
In this example, the ``if f()`` check is always false since ``f``
returns ``None``:
.. code-block:: python
def f() -> None:
...
# OK: we don't do anything with the return value
f()
# Error: "f" does not return a value [func-returns-value]
if f():
print("not false")
Check instantiation of abstract classes [abstract]
--------------------------------------------------
Mypy generates an error if you try to instantiate an abstract base
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
unimplemented abstract method. In a case like this you need to provide
an implementation for the method to make the class concrete
(non-abstract).
Example:
.. code-block:: python
from abc import ABCMeta, abstractmethod
class Persistent(metaclass=ABCMeta):
@abstractmethod
def save(self) -> None: ...
class Thing(Persistent):
def __init__(self) -> None:
...
... # No "save" method
# Error: Cannot instantiate abstract class "Thing" with abstract attribute "save" [abstract]
t = Thing()
Check the target of NewType [valid-newtype]
-------------------------------------------
The target of a :py:func:`NewType ` definition must be a class type. It can't
be a union type, ``Any``, or various other special types.
You can also get this error if the target has been imported from a
module whose source mypy cannot find, since any such definitions are
treated by mypy as values with ``Any`` types. Example:
.. code-block:: python
from typing import NewType
# The source for "acme" is not available for mypy
from acme import Entity # type: ignore
# Error: Argument 2 to NewType(...) must be subclassable (got "Any") [valid-newtype]
UserEntity = NewType('UserEntity', Entity)
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.
Check the return type of __exit__ [exit-return]
-----------------------------------------------
If mypy can determine that :py:meth:`__exit__ ` always returns ``False``, mypy
checks that the return type is *not* ``bool``. The boolean value of
the return type affects which lines mypy thinks are reachable after a
``with`` statement, since any :py:meth:`__exit__ ` method that can return
``True`` may swallow exceptions. An imprecise return type can result
in mysterious errors reported near ``with`` statements.
To fix this, use either ``typing_extensions.Literal[False]`` or
``None`` as the return type. Returning ``None`` is equivalent to
returning ``False`` in this context, since both are treated as false
values.
Example:
.. code-block:: python
class MyContext:
...
def __exit__(self, exc, value, tb) -> bool: # Error
print('exit')
return False
This produces the following output from mypy:
.. code-block:: text
example.py:3: error: "bool" is invalid as return type for "__exit__" that always returns False
example.py:3: note: Use "typing_extensions.Literal[False]" as the return type or change it to
"None"
example.py:3: note: If return type of "__exit__" implies that it may return True, the context
manager may swallow exceptions
You can use ``Literal[False]`` to fix the error:
.. code-block:: python
from typing_extensions import Literal
class MyContext:
...
def __exit__(self, exc, value, tb) -> Literal[False]: # OK
print('exit')
return False
You can also use ``None``:
.. code-block:: python
class MyContext:
...
def __exit__(self, exc, value, tb) -> None: # Also OK
print('exit')
Check that naming is consistent [name-match]
--------------------------------------------
The definition of a named tuple or a TypedDict must be named
consistently when using the call-based syntax. Example:
.. code-block:: python
from typing import NamedTuple
# Error: First argument to namedtuple() should be "Point2D", not "Point"
Point2D = NamedTuple("Point", [("x", int), ("y", int)])
Check that overloaded functions have an implementation [no-overload-impl]
-------------------------------------------------------------------------
Overloaded functions outside of stub files must be followed by a non overloaded
implementation.
.. code-block:: python
from typing import overload
@overload
def func(value: int) -> int:
...
@overload
def func(value: str) -> str:
...
# presence of required function below is checked
def func(value):
pass # actual implementation
Report syntax errors [syntax]
-----------------------------
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.
Miscellaneous checks [misc]
---------------------------
Mypy performs numerous other, less commonly failing checks that don't
have specific error codes. These use the ``misc`` error code. Other
than being used for multiple unrelated errors, the ``misc`` error code
is not special. For example, you can ignore all errors in this
category by using ``# type: ignore[misc]`` comment. Since these errors
are not expected to be common, it's unlikely that you'll see two
*different* errors with the ``misc`` code on a single line -- though
this can certainly happen once in a while.
.. note::
Future mypy versions will likely add new error codes for some errors
that currently use the ``misc`` error code.
mypy-0.942/docs/source/error_code_list2.rst 0000644 0001751 0000171 00000023164 14217067311 021557 0 ustar runner docker 0000000 0000000 .. _error-codes-optional:
Error codes for optional checks
===============================
This section documents various errors codes that mypy generates only
if you enable certain options. See :ref:`error-codes` for general
documentation about error codes. :ref:`error-code-list` documents
error codes that are enabled by default.
.. note::
The examples in this section use :ref:`inline configuration
` to specify mypy options. You can also set the same
options by using a :ref:`configuration file ` or
:ref:`command-line options `.
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.
Example:
.. code-block:: python
# mypy: disallow-any-generics
# Error: Missing type parameters for generic type "list" [type-arg]
def remove_dups(items: list) -> list:
...
Check that every function has an annotation [no-untyped-def]
------------------------------------------------------------
If you use :option:`--disallow-untyped-defs `, mypy requires that all functions
have annotations (either a Python 3 annotation or a type comment).
Example:
.. code-block:: python
# mypy: disallow-untyped-defs
def inc(x): # Error: Function is missing a type annotation [no-untyped-def]
return x + 1
def inc_ok(x: int) -> int: # OK
return x + 1
class Counter:
# Error: Function is missing a type annotation [no-untyped-def]
def __init__(self):
self.value = 0
class CounterOk:
# OK: An explicit "-> None" is needed if "__init__" takes no arguments
def __init__(self) -> None:
self.value = 0
Check that cast is not redundant [redundant-cast]
-------------------------------------------------
If you use :option:`--warn-redundant-casts `, mypy will generate an error if the source
type of a cast is the same as the target type.
Example:
.. code-block:: python
# mypy: warn-redundant-casts
from typing import cast
Count = int
def example(x: Count) -> int:
# Error: Redundant cast to "int" [redundant-cast]
return cast(int, x)
Check that comparisons are overlapping [comparison-overlap]
-----------------------------------------------------------
If you use :option:`--strict-equality `, mypy will generate an error if it
thinks that a comparison operation is always true or false. These are
often bugs. Sometimes mypy is too picky and the comparison can
actually be useful. Instead of disabling strict equality checking
everywhere, you can use ``# type: ignore[comparison-overlap]`` to
ignore the issue on a particular line only.
Example:
.. code-block:: python
# mypy: strict-equality
def is_magic(x: bytes) -> bool:
# Error: Non-overlapping equality check (left operand type: "bytes",
# right operand type: "str") [comparison-overlap]
return x == 'magic'
We can fix the error by changing the string literal to a bytes
literal:
.. code-block:: python
# mypy: strict-equality
def is_magic(x: bytes) -> bool:
return x == b'magic' # OK
Check that no untyped functions are called [no-untyped-call]
------------------------------------------------------------
If you use :option:`--disallow-untyped-calls `, mypy generates an error when you
call an unannotated function in an annotated function.
Example:
.. code-block:: python
# mypy: disallow-untyped-calls
def do_it() -> None:
# Error: Call to untyped function "bad" in typed context [no-untyped-call]
bad()
def bad():
...
Check that function does not return Any value [no-any-return]
-------------------------------------------------------------
If you use :option:`--warn-return-any `, mypy generates an error if you return a
value with an ``Any`` type in a function that is annotated to return a
non-``Any`` value.
Example:
.. code-block:: python
# mypy: warn-return-any
def fields(s):
return s.split(',')
def first_field(x: str) -> str:
# Error: Returning Any from function declared to return "str" [no-any-return]
return fields(x)[0]
Check that types have no Any components due to missing imports [no-any-unimported]
----------------------------------------------------------------------------------
If you use :option:`--disallow-any-unimported `, mypy generates an error if a component of
a type becomes ``Any`` because mypy couldn't resolve an import. These "stealth"
``Any`` types can be surprising and accidentally cause imprecise type checking.
In this example, we assume that mypy can't find the module ``animals``, which means
that ``Cat`` falls back to ``Any`` in a type annotation:
.. code-block:: python
# mypy: disallow-any-unimported
from animals import Cat # type: ignore
# Error: Argument 1 to "feed" becomes "Any" due to an unfollowed import [no-any-unimported]
def feed(cat: Cat) -> None:
...
Check that statement or expression is unreachable [unreachable]
---------------------------------------------------------------
If you use :option:`--warn-unreachable `, mypy generates an error if it
thinks that a statement or expression will never be executed. In most cases, this is due to
incorrect control flow or conditional checks that are accidentally always true or false.
.. code-block:: python
# mypy: warn-unreachable
def example(x: int) -> None:
# Error: Right operand of "or" is never evaluated [unreachable]
assert isinstance(x, int) or x == 'unused'
return
# Error: Statement is unreachable [unreachable]
print('unreachable')
Check that expression is redundant [redundant-expr]
---------------------------------------------------
If you use :option:`--enable-error-code redundant-expr `,
mypy generates an error if it thinks that an expression is redundant.
.. code-block:: python
# mypy: enable-error-code redundant-expr
def example(x: int) -> None:
# Error: Left operand of "and" is always true [redundant-expr]
if isinstance(x, int) and x > 0:
pass
# Error: If condition is always true [redundant-expr]
1 if isinstance(x, int) else 0
# Error: If condition in comprehension is always true [redundant-expr]
[i for i in range(x) if isinstance(i, int)]
Check that expression is not implicitly true in boolean context [truthy-bool]
-----------------------------------------------------------------------------
Warn when an expression whose type does not implement ``__bool__`` or ``__len__`` is used in boolean context,
since unless implemented by a sub-type, the expression will always evaluate to true.
.. code-block:: python
# 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:
...
This check might falsely imply an error. For example, ``Iterable`` does not implement
``__len__`` and so this code will be flagged:
.. code-block:: python
# mypy: enable-error-code truthy-bool
from typing import Iterable
def transform(items: Iterable[int]) -> Iterable[int]:
# Error: "items" has type "Iterable[int]" which does not implement __bool__ or __len__ so it could always be true in boolean context [truthy-bool]
if not items:
return [42]
return [x + 1 for x in items]
If called as ``transform((int(s) for s in []))``, this function would not return ``[42]`` unlike what the author
might have intended. Of course it's possible that ``transform`` is only passed ``list`` objects, and so there is
no error in practice. In such case, it might be prudent to annotate ``items: Sequence[int]``.
This is similar in concept to ensuring that an expression's type implements an expected interface (e.g. ``Sized``),
except that attempting to invoke an undefined method (e.g. ``__len__``) results in an error,
while attempting to evaluate an object in boolean context without a concrete implementation results in a truthy value.
.. _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
# 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]
mypy-0.942/docs/source/error_codes.rst 0000644 0001751 0000171 00000004113 14217067311 020616 0 ustar runner docker 0000000 0000000 .. _error-codes:
Error codes
===========
Mypy can optionally display an error code such as ``[attr-defined]``
after each error message. Error codes serve two purposes:
1. It's possible to silence specific error codes on a line using ``#
type: ignore[code]``. This way you won't accidentally ignore other,
potentially more serious errors.
2. The error code can be used to find documentation about the error.
The next two topics (:ref:`error-code-list` and
:ref:`error-codes-optional`) document the various error codes
mypy can report.
Most error codes are shared between multiple related error messages.
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:
.. code-block:: text
$ mypy --show-error-codes 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
-------------------------------------
You can use a special comment ``# type: ignore[code, ...]`` to only
ignore errors with a specific error code (or codes) on a particular
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.
This example shows how to ignore an error about an imported name mypy
thinks is undefined:
.. code-block:: python
# 'foo' is defined in 'foolib', even though mypy can't see the
# definition.
from foolib import foo # type: ignore[attr-defined]
mypy-0.942/docs/source/existing_code.rst 0000644 0001751 0000171 00000014475 14217067311 021150 0 ustar runner docker 0000000 0000000 .. _existing-code:
Using mypy with an existing codebase
====================================
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:
1. Start small -- get a clean mypy build for some files, with few
annotations
2. Write a mypy runner script to ensure consistent results
3. Run mypy in Continuous Integration to prevent type errors
4. Gradually annotate commonly imported modules
5. Write annotations as you modify existing code and write new code
6. Use :doc:`monkeytype:index` or `PyAnnotate`_ to automatically annotate legacy code
We discuss all of these points in some detail below, and a few optional
follow-up steps.
Start small
-----------
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.
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.
In particular, mypy often generates errors about modules that it can't
find or that don't have stub files:
.. code-block:: text
core/config.py:7: error: Cannot find implementation or library stub for module named 'frobnicate'
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,
here we ignore an error about a third-party module ``frobnicate`` that
doesn't have stubs using ``# type: ignore``:
.. code-block:: python
import frobnicate # 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
codebase, use a config like this:
.. code-block:: text
[mypy-frobnicate.*]
ignore_missing_imports = True
[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:
.. code-block:: text
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
--------------------------------
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.
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
conventions:
1. Developers should add annotations for any new code.
2. It's also encouraged to write annotations when you modify existing code.
This way you'll gradually increase annotation coverage in your
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`_.
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
slow).
Another approach is to enable type collection for a small, random
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.
Introduce stricter options
--------------------------
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.
.. _PyAnnotate: https://github.com/dropbox/pyannotate
mypy-0.942/docs/source/extending_mypy.rst 0000644 0001751 0000171 00000024717 14217067311 021367 0 ustar runner docker 0000000 0000000 .. _extending-mypy:
Extending and integrating mypy
==============================
.. _integrating-mypy:
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
what normally would have been the command line arguments to mypy.
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
returns to the operating system.
A trivial example of using the api is the following
.. code-block:: python
import sys
from mypy import api
result = api.run(sys.argv[1:])
if result[0]:
print('\nType checking report:\n')
print(result[0]) # stdout
if result[1]:
print('\nError report:\n')
print(result[1]) # stderr
print('\nExit status:', result[2])
.. _extending-mypy-using-plugins:
Extending mypy using plugins
****************************
Python is a highly dynamic language and has extensive metaprogramming
capabilities. Many popular libraries use these to create APIs that may
be more flexible and/or natural for humans, but are hard to express using
static types. Extending the :pep:`484` type system to accommodate all existing
dynamic patterns is impractical and often just impossible.
Mypy supports a plugin system that lets you customize the way mypy type checks
code. This can be useful if you want to extend mypy so it can type check code
that uses a library that is difficult to express using just :pep:`484` types.
The plugin system is focused on improving mypy's understanding
of *semantics* of third party frameworks. There is currently no way to define
new first class kinds of types.
.. note::
The plugin system is experimental and prone to change. If you want to write
a mypy plugin, we recommend you start by contacting the mypy core developers
on `gitter `_. In particular, there are
no guarantees about backwards compatibility.
Backwards incompatible changes may be made without a deprecation period,
but we will announce them in
`the plugin API changes announcement issue `_.
Configuring mypy to use plugins
*******************************
Plugins are Python files that can be specified in a mypy
:ref:`config file ` using the :confval:`plugins` option and one of the two formats: relative or
absolute path to the plugin file, or a module name (if the plugin
is installed using ``pip install`` in the same virtual environment where mypy
is running). The two formats can be mixed, for example:
.. code-block:: ini
[mypy]
plugins = /one/plugin.py, other.plugin
Mypy will try to import the plugins and will look for an entry point function
named ``plugin``. If the plugin entry point function has a different name, it
can be specified after colon:
.. code-block:: ini
[mypy]
plugins = custom_plugin:custom_entry_point
In the following sections we describe the basics of the plugin system with
some examples. For more technical details, please read the docstrings in
`mypy/plugin.py `_
in mypy source code. Also you can find good examples in the bundled plugins
located in `mypy/plugins `_.
High-level overview
*******************
Every entry point function should accept a single string argument
that is a full mypy version and return a subclass of ``mypy.plugin.Plugin``:
.. code-block:: python
from mypy.plugin import Plugin
class CustomPlugin(Plugin):
def get_type_analyze_hook(self, fullname: str):
# see explanation below
...
def plugin(version: str):
# ignore version argument if the plugin works with all mypy versions.
return CustomPlugin
During different phases of analyzing the code (first in semantic analysis,
and then in type checking) mypy calls plugin methods such as
``get_type_analyze_hook()`` on user plugins. This particular method, for example,
can return a callback that mypy will use to analyze unbound types with the given
full name. See the full plugin hook method list :ref:`below `.
Mypy maintains a list of plugins it gets from the config file plus the default
(built-in) plugin that is always enabled. Mypy calls a method once for each
plugin in the list until one of the methods returns a non-``None`` value.
This callback will be then used to customize the corresponding aspect of
analyzing/checking the current abstract syntax tree node.
The callback returned by the ``get_xxx`` method will be given a detailed
current context and an API to create new nodes, new types, emit error messages,
etc., and the result will be used for further processing.
Plugin developers should ensure that their plugins work well in incremental and
daemon modes. In particular, plugins should not hold global state due to caching
of plugin hook results.
.. _plugin_hooks:
Current list of plugin hooks
****************************
**get_type_analyze_hook()** customizes behaviour of the type analyzer.
For example, :pep:`484` doesn't support defining variadic generic types:
.. code-block:: python
from lib import Vector
a: Vector[int, int]
b: Vector[int, int, int]
When analyzing this code, mypy will call ``get_type_analyze_hook("lib.Vector")``,
so the plugin can return some valid type for each variable.
**get_function_hook()** is used to adjust the return type of a function call.
This is a good choice if the return type of some function depends on *values*
of some arguments that can't be expressed using literal types (for example
a function may return an ``int`` for positive arguments and a ``float`` for
negative arguments). This hook will be also called for instantiation of classes.
For example:
.. code-block:: python
from contextlib import contextmanager
from typing import TypeVar, Callable
T = TypeVar('T')
@contextmanager # built-in plugin can infer a precise type here
def stopwatch(timer: Callable[[], T]) -> Iterator[T]:
...
yield timer()
**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.
**get_method_signature_hook()** is used to adjust the signature of a method.
This includes special Python methods except :py:meth:`~object.__init__` and :py:meth:`~object.__new__`.
For example in this code:
.. code-block:: python
from ctypes import Array, c_int
x: Array[c_int]
x[0] = 42
mypy will call ``get_method_signature_hook("ctypes.Array.__setitem__")``
so that the plugin can mimic the :py:mod:`ctypes` auto-convert behavior.
**get_attribute_hook()** overrides instance member field lookups and property
access (not assignments, and not method calls). This hook is only called for
fields which already exist on the class. *Exception:* if :py:meth:`__getattr__ ` or
:py:meth:`__getattribute__ ` is a method on the class, the hook is called for all
fields which do not refer to methods.
**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:
.. code-block:: python
from dataclasses import dataclass
@dataclass # built-in plugin adds `__init__` method here
class User:
name: str
user = User(name='example') # mypy can understand this using a plugin
**get_metaclass_hook()** is similar to above, but for metaclasses.
**get_base_class_hook()** is similar to above, but for base classes.
**get_dynamic_class_hook()** can be used to allow dynamic class definitions
in mypy. This plugin hook is called for every assignment to a simple name
where right hand side is a function call:
.. code-block:: python
from lib import dynamic_class
X = dynamic_class('X', [])
For such definition, mypy will call ``get_dynamic_class_hook("lib.dynamic_class")``.
The plugin should create the corresponding ``mypy.nodes.TypeInfo`` object, and
place it into a relevant symbol table. (Instances of this class represent
classes in mypy and hold essential information such as qualified name,
method resolution order, etc.)
**get_customize_class_mro_hook()** can be used to modify class MRO (for example
insert some entries there) before the class body is analyzed.
**get_additional_deps()** can be used to add new dependencies for a
module. It is called before semantic analysis. For example, this can
be used if a library has dependencies that are dynamically loaded
based on configuration information.
**report_config_data()** can be used if the plugin has some sort of
per-module configuration that can affect typechecking. In that case,
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 should 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.
mypy-0.942/docs/source/faq.rst 0000644 0001751 0000171 00000022565 14217067311 017072 0 ustar runner docker 0000000 0000000 Frequently Asked Questions
==========================
Why have both dynamic and static typing?
****************************************
Dynamic typing can be flexible, powerful, convenient and easy. But
it's not always the best approach; there are good reasons why many
developers choose to use statically typed languages or static typing
for Python.
Here are some potential benefits of mypy-style static typing:
- Static typing can make programs easier to understand and
maintain. Type declarations can serve as machine-checked
documentation. This is important as code is typically read much more
often than modified, and this is especially important for large and
complex programs.
- Static typing can help you find bugs earlier and with less testing
and debugging. Especially in large and complex projects this can be
a major time-saver.
- Static typing can help you find difficult-to-find bugs before your
code goes into production. This can improve reliability and reduce
the number of security issues.
- Static typing makes it practical to build very useful development
tools that can improve programming productivity or software quality,
including IDEs with precise and reliable code completion, static
analysis tools, etc.
- You can get the benefits of both dynamic and static typing in a
single language. Dynamic typing can be perfect for a small project
or for writing the UI of your program, for example. As your program
grows, you can adapt tricky application logic to static typing to
help maintenance.
See also the `front page `_ of the mypy web
site.
Would my project benefit from static typing?
********************************************
For many projects dynamic typing is perfectly fine (we think that
Python is a great language). But sometimes your projects demand bigger
guns, and that's when mypy may come in handy.
If some of these ring true for your projects, mypy (and static typing)
may be useful:
- Your project is large or complex.
- Your codebase must be maintained for a long time.
- Multiple developers are working on the same code.
- Running tests takes a lot of time or work (type checking helps
you find errors quickly early in development, reducing the number of
testing iterations).
- Some project members (devs or management) don't like dynamic typing,
but others prefer dynamic typing and Python syntax. Mypy could be a
solution that everybody finds easy to accept.
- You want to future-proof your project even if currently none of the
above really apply. The earlier you start, the easier it will be to
adopt static typing.
Can I use mypy to type check my existing Python code?
*****************************************************
Mypy supports most Python features and idioms, and many large Python
projects are using mypy successfully. Code that uses complex
introspection or metaprogramming may be impractical to type check, but
it should still be possible to use static typing in other parts of a
codebase that are less dynamic.
Will static typing make my programs run faster?
***********************************************
Mypy only does static type checking and it does not improve
performance. It has a minimal performance impact. In the future, there
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?
*************
Yes. Mypy is free software, and it can also be used for commercial and
proprietary projects. Mypy is available under the MIT license.
Can I use duck typing with mypy?
********************************
Mypy provides support for both `nominal subtyping
`_ and
`structural subtyping
`_.
Structural subtyping can be thought of as "static duck typing".
Some argue that structural subtyping is better suited for languages with duck
typing such as Python. Mypy however primarily uses nominal subtyping,
leaving structural subtyping mostly opt-in (except for built-in protocols
such as :py:class:`~typing.Iterable` that always support structural subtyping). Here are some
reasons why:
1. It is easy to generate short and informative error messages when
using a nominal type system. This is especially important when
using type inference.
2. Python provides built-in support for nominal :py:func:`isinstance` tests and
they are widely used in programs. Only limited support for structural
:py:func:`isinstance` is available, and it's less type safe than nominal type tests.
3. Many programmers are already familiar with static, nominal subtyping and it
has been successfully used in languages such as Java, C++ and
C#. Fewer languages use structural subtyping.
However, structural subtyping can also be useful. For example, a "public API"
may be more flexible if it is typed with protocols. Also, using protocol types
removes the necessity to explicitly declare implementations of ABCs.
As a rule of thumb, we recommend using nominal classes where possible, and
protocols where necessary. For more details about protocol types and structural
subtyping see :ref:`protocol-types` and :pep:`544`.
I like Python and I have no need for static typing
**************************************************
The aim of mypy is not to convince everybody to write statically typed
Python -- static typing is entirely optional, now and in the
future. The goal is to give more options for Python programmers, to
make Python a more competitive alternative to other statically typed
languages in large projects, to improve programmer productivity, and
to improve software quality.
How are mypy programs different from normal Python?
***************************************************
Since you use a vanilla Python implementation to run mypy programs,
mypy programs are also Python programs. The type checker may give
warnings for some valid Python code, but the code is still always
runnable. Also, some Python features and syntax are still not
supported by mypy, but this is gradually improving.
The obvious difference is the availability of static type
checking. The section :ref:`common_issues` mentions some
modifications to Python code that may be required to make code type
check without errors. Also, your code must make attributes explicit.
Mypy supports modular, efficient type checking, and this seems to
rule out type checking some language features, such as arbitrary
monkey patching of methods.
How is mypy different from Cython?
**********************************
:doc:`Cython ` is a variant of Python that supports
compilation to CPython C modules. It can give major speedups to
certain classes of programs compared to CPython, and it provides
static typing (though this is different from mypy). Mypy differs in
the following aspects, among others:
- Cython is much more focused on performance than mypy. Mypy is only
about static type checking, and increasing performance is not a
direct goal.
- The mypy syntax is arguably simpler and more "Pythonic" (no cdef/cpdef, etc.) for statically typed code.
- The mypy syntax is compatible with Python. Mypy programs are normal
Python programs that can be run using any Python
implementation. Cython has many incompatible extensions to Python
syntax, and Cython programs generally cannot be run without first
compiling them to CPython extension modules via C. Cython also has a
pure Python mode, but it seems to support only a subset of Cython
functionality, and the syntax is quite verbose.
- Mypy has a different set of type system features. For example, mypy
has genericity (parametric polymorphism), function types and
bidirectional type inference, which are not supported by
Cython. (Cython has fused types that are different but related to
mypy generics. Mypy also has a similar feature as an extension of
generics.)
- The mypy type checker knows about the static types of many Python
stdlib modules and can effectively type check code that uses them.
- Cython supports accessing C functions directly and many features are
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?
*********************
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).
Mypy is a cool project. Can I help?
***********************************
Any help is much appreciated! `Contact
`_ 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
can help, even beginners! However, some knowledge of compilers and/or
type systems is essential if you want to work on mypy internals.
mypy-0.942/docs/source/final_attrs.rst 0000644 0001751 0000171 00000015616 14217067311 020630 0 ustar runner docker 0000000 0000000 .. _final_attrs:
Final names, methods and classes
================================
This section introduces these related features:
1. *Final names* are variables or attributes that should not be reassigned after
initialization. They are useful for declaring constants.
2. *Final methods* should not be overridden in a subclass.
3. *Final classes* should not be subclassed.
All of these are only enforced by mypy, and only in annotated code.
There is no runtime enforcement by the Python runtime.
.. note::
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
``typing_extensions`` package.
Final names
-----------
You can use the ``typing.Final`` qualifier to indicate that
a name or attribute should not be reassigned, redefined, or
overridden. This is often useful for module and class level constants
as a way to prevent unintended modification. Mypy will prevent
further assignments to final names in type-checked code:
.. code-block:: python
from typing import Final
RATE: Final = 3000
class Base:
DEFAULT_ID: Final = 0
RATE = 300 # Error: can't assign to final attribute
Base.DEFAULT_ID = 1 # Error: can't override a final attribute
Another use case for final attributes is to protect certain attributes
from being overridden in a subclass:
.. code-block:: python
from typing import Final
class Window:
BORDER_WIDTH: Final = 2.5
...
class ListView(Window):
BORDER_WIDTH = 3 # Error: can't override a final attribute
You can use :py:class:`@property ` to make an attribute read-only, but unlike ``Final``,
it doesn't work with module attributes, and it doesn't prevent overriding in
subclasses.
Syntax variants
***************
You can use ``Final`` in one of these forms:
* You can provide an explicit type using the syntax ``Final[]``. Example:
.. code-block:: python
ID: Final[int] = 1
Here mypy will infer type ``int`` for ``ID``.
* You can omit the type:
.. code-block:: python
ID: Final = 1
Here mypy will infer type ``Literal[1]`` for ``ID``. Note that unlike for
generic classes this is *not* the same as ``Final[Any]``.
* In class bodies and stub files you can omit the right hand side and just write
``ID: Final[int]``.
* Finally, you can write ``self.id: Final = 1`` (also optionally with
a type in square brackets). This is allowed *only* in
:py:meth:`__init__ ` methods, so that the final instance attribute is
assigned only once when an instance is created.
Details of using ``Final``
**************************
These are the two main rules for defining a final name:
* There can be *at most one* final declaration per module or class for
a given attribute. There can't be separate class-level and instance-level
constants with the same name.
* There must be *exactly one* assignment to a final name.
A final attribute declared in a class body without an initializer must
be initialized in the :py:meth:`__init__ ` method (you can skip the
initializer in stub files):
.. code-block:: python
class ImmutablePoint:
x: Final[int]
y: Final[int] # Error: final attribute without an initializer
def __init__(self) -> None:
self.x = 1 # Good
``Final`` can only be used as the outermost type in assignments or variable
annotations. Using it in any other position is an error. In particular,
``Final`` can't be used in annotations for function arguments:
.. code-block:: python
x: list[Final[int]] = [] # Error!
def fun(x: Final[list[int]]) -> None: # Error!
...
``Final`` and :py:data:`~typing.ClassVar` should not be used together. Mypy will infer
the scope of a final declaration automatically depending on whether it was
initialized in the class body or in :py:meth:`__init__ `.
A final attribute can't be overridden by a subclass (even with another
explicit final declaration). Note however that a final attribute can
override a read-only property:
.. code-block:: python
class Base:
@property
def ID(self) -> int: ...
class Derived(Base):
ID: Final = 1 # OK
Declaring a name as final only guarantees that the name will not be re-bound
to another value. It doesn't make the value immutable. You can use immutable ABCs
and containers to prevent mutating such values:
.. code-block:: python
x: Final = ['a', 'b']
x.append('c') # OK
y: Final[Sequence[str]] = ['a', 'b']
y.append('x') # Error: Sequence is immutable
z: Final = ('a', 'b') # Also an option
Final methods
-------------
Like with attributes, sometimes it is useful to protect a method from
overriding. You can use the ``typing.final`` decorator for this purpose:
.. code-block:: python
from typing import final
class Base:
@final
def common_name(self) -> None:
...
class Derived(Base):
def common_name(self) -> None: # Error: cannot override a final method
...
This ``@final`` decorator can be used with instance methods, class methods,
static methods, and properties.
For overloaded methods you should add ``@final`` on the implementation
to make it final (or on the first overload in stubs):
.. code-block:: python
from typing import Any, overload
class Base:
@overload
def method(self) -> None: ...
@overload
def method(self, arg: int) -> int: ...
@final
def method(self, x=None):
...
Final classes
-------------
You can apply the ``typing.final`` decorator to a class to indicate
to mypy that it should not be subclassed:
.. code-block:: python
from typing import final
@final
class Leaf:
...
class MyLeaf(Leaf): # Error: Leaf can't be subclassed
...
The decorator acts as a declaration for mypy (and as documentation for
humans), but it doesn't actually prevent subclassing at runtime.
Here are some situations where using a final class may be useful:
* A class wasn't designed to be subclassed. Perhaps subclassing would not
work as expected, or subclassing would be error-prone.
* Subclassing would make code harder to understand or maintain.
For example, you may want to prevent unnecessarily tight coupling between
base classes and subclasses.
* You want to retain the freedom to arbitrarily change the class implementation
in the future, and these changes might break subclasses.
An abstract class that defines at least one abstract method or
property and has ``@final`` decorator will generate an error from
mypy, since those attributes could never be implemented.
.. code-block:: python
from abc import ABCMeta, abstractmethod
from typing import final
@final
class A(metaclass=ABCMeta): # error: Final class A has abstract attributes "f"
@abstractmethod
def f(self, x: int) -> None: pass
mypy-0.942/docs/source/generics.rst 0000644 0001751 0000171 00000061023 14217067311 020112 0 ustar runner docker 0000000 0000000 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]``.
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.
.. _generic-classes:
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``.
Programs can also define new generic classes. Here is a very simple
generic class that represents a stack:
.. code-block:: python
from typing import TypeVar, Generic
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
# Create an empty list with items of type T
self.items: list[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
def empty(self) -> bool:
return not self.items
The ``Stack`` class can be used to represent a stack of any type:
``Stack[int]``, ``Stack[tuple[int, str]]``, etc.
Using ``Stack`` is similar to built-in container types:
.. code-block:: python
# Construct an empty Stack[int] instance
stack = Stack[int]()
stack.push(2)
stack.pop()
stack.push('x') # Type error
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:
.. code-block:: python
class Box(Generic[T]):
def __init__(self, content: T) -> None:
self.content = content
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``. Indexing ``Stack`` returns a *generic alias*
to ``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
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
.. note::
In Python 3.6 indexing generic types or type aliases results in actual
type objects. This means that generic types in type annotations can
have a significant runtime cost. This was changed in Python 3.7, and
indexing generic types became a cheap operation.
.. _generic-subclasses:
Defining sub-classes 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:
.. code-block:: python
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:
...
items: MyMap[str, int] # Okay
class StrDict(dict[str, str]): # This is a non-generic subclass of dict
def __str__(self) -> str:
return 'StrDict({})'.format(super().__str__())
data: StrDict[int, int] # Error! StrDict is not generic
data2: StrDict # OK
class Receiver(Generic[T]):
def accept(self, value: T) -> None:
...
class AdvancedReceiver(Receiver[T]):
...
.. note::
You have to add an explicit :py:class:`~typing.Mapping` base class
if you want mypy to consider a user-defined class as a mapping (and
:py:class:`~typing.Sequence` for sequences, etc.). This is because mypy doesn't use
*structural subtyping* for these ABCs, unlike simpler protocols
like :py:class:`~typing.Iterable`, which use :ref:`structural subtyping `.
:py:class:`Generic ` can be omitted from bases if there are
other base classes that include type variables, such as ``Mapping[KT, VT]``
in the above example. If you include ``Generic[...]`` in bases, then
it should list all type variables present in other bases (or more,
if needed). The order of type variables is defined by the following
rules:
* If ``Generic[...]`` is present, then the order of variables is
always determined by their order in ``Generic[...]``.
* If there are no ``Generic[...]`` in bases, then all type variables
are collected in the lexicographic order (i.e. by first appearance).
For example:
.. code-block:: python
from typing import Generic, TypeVar, Any
T = TypeVar('T')
S = TypeVar('S')
U = TypeVar('U')
class One(Generic[T]): ...
class Another(Generic[T]): ...
class First(One[T], Another[S]): ...
class Second(One[T], Another[S], Generic[S, U, T]): ...
x: First[int, str] # Here T is bound to int, S is bound to str
y: Second[int, str, Any] # Here T is Any, S is int, and U is str
.. _generic-functions:
Generic functions
*****************
Generic type variables can also be used to define generic functions:
.. code-block:: python
from typing import TypeVar, Sequence
T = TypeVar('T') # Declare type variable
def first(seq: Sequence[T]) -> T: # Generic function
return seq[0]
As with generic classes, the type variable can be replaced with any
type. That means ``first`` can be used with any sequence type, and the
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.
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
example we use the same type variable in two generic functions:
.. code-block:: python
from typing import TypeVar, Sequence
T = TypeVar('T') # Declare type variable
def first(seq: Sequence[T]) -> T:
return seq[0]
def last(seq: Sequence[T]) -> T:
return seq[-1]
A variable cannot have a type variable in its type unless the type
variable is bound in a containing generic class or function.
.. _generic-methods-and-generic-self:
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:
.. code-block:: python
from typing import TypeVar
T = TypeVar('T', bound='Shape')
class Shape:
def set_scale(self: T, scale: float) -> T:
self.scale = scale
return self
class Circle(Shape):
def set_radius(self, r: float) -> 'Circle':
self.radius = r
return self
class Square(Shape):
def set_width(self, w: float) -> 'Square':
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
Without using generic ``self``, the last two lines could not be type-checked properly.
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, Type
T = TypeVar('T', bound='Friend')
class Friend:
other = None # type: Friend
@classmethod
def make_pair(cls: Type[T]) -> tuple[T, T]:
a, b = cls(), cls()
a.other = b
b.other = a
return a, b
class SuperFriend(Friend):
pass
a, b = SuperFriend.make_pair()
Note that when overriding a method with generic ``self``, you must either
return a generic ``self`` too, or return an instance of the current class.
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.
For some advanced uses of self-types see :ref:`additional examples `.
.. _variance-of-generics:
Variance of generic types
*************************
There are three main kinds of generic types with respect to subtype
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
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
def salaries(staff: list[Manager],
accountant: Callable[[Manager], int]) -> list[int]: ...
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:
.. code-block:: python
class Shape:
pass
class Circle(Shape):
def rotate(self):
...
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
Another example of invariant type is :py:class:`~typing.Dict`. Most mutable containers
are invariant.
By default, mypy assumes that all user-defined generics are invariant.
To declare a given generic class as covariant or contravariant use
type variables defined with special keyword arguments ``covariant`` or
``contravariant``. For example:
.. code-block:: python
from typing import Generic, TypeVar
T_co = TypeVar('T_co', covariant=True)
class Box(Generic[T_co]): # this type is declared covariant
def __init__(self, content: T_co) -> None:
self._content = content
def get_content(self) -> T_co:
return self._content
def look_into(box: Box[Animal]): ...
my_box = Box(Cat())
look_into(my_box) # OK, but mypy would complain here for an invariant type
.. _type-variable-value-restriction:
Type variables with value restriction
*************************************
By default, a type variable can be replaced with any type. However, sometimes
it's useful to have a type variable that can only have some specific types
as its value. A typical example is a type variable that can only have values
``str`` and ``bytes``:
.. code-block:: python
from typing import TypeVar
AnyStr = TypeVar('AnyStr', str, bytes)
This is actually such a common type variable that :py:data:`~typing.AnyStr` is
defined in :py:mod:`typing` and we don't need to define it ourselves.
We can use :py:data:`~typing.AnyStr` to define a function that can concatenate
two strings or bytes objects, but it can't be called with other
argument types:
.. code-block:: python
from typing import AnyStr
def concat(x: AnyStr, y: AnyStr) -> AnyStr:
return x + y
concat('a', 'b') # Okay
concat(b'a', b'b') # Okay
concat(1, 2) # Error!
Note that this is different from a union type, since combinations
of ``str`` and ``bytes`` are not accepted:
.. code-block:: python
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:
.. code-block:: python
def union_concat(x: Union[str, bytes], y: Union[str, bytes]) -> Union[str, bytes]:
return x + y # Error: can't concatenate str and bytes
Another interesting special case is calling ``concat()`` with a
subtype of ``str``:
.. code-block:: python
class S(str): pass
ss = concat(S('foo'), S('bar'))
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
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
``str`` instance in the above example:
.. code-block:: python
>>> print(type(ss))
You can also use a :py:class:`~typing.TypeVar` with a restricted set of possible
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`.
.. 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.
A type variable may not have both a value restriction (see
:ref:`type-variable-value-restriction`) and an upper bound.
.. _declaring-decorators:
Declaring decorators
********************
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.
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:
.. code-block:: python
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 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"
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).
The bound on ``F`` is used so that calling the decorator on a
non-function (e.g. ``my_decorator(1)``) will be rejected.
Also note that the ``wrapper()`` function is not type-checked. 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 `.
.. _decorator-factories:
Decorator factories
-------------------
Functions that take arguments and return a decorator (also called second-order decorators), are
similarly supported via generics:
.. code-block:: python
from typing import Any, Callable, TypeVar
F = TypeVar('F', bound=Callable[..., Any])
def route(url: str) -> Callable[[F], F]:
...
@route(url='/')
def index(request: Any) -> str:
return 'Hello world'
Sometimes the same decorator supports both bare calls and calls with arguments. This can be
achieved by combining with :py:func:`@overload `:
.. code-block:: python
from typing import Any, Callable, TypeVar, overload
F = TypeVar('F', bound=Callable[..., Any])
# Bare decorator usage
@overload
def atomic(__func: F) -> F: ...
# Decorator with arguments
@overload
def atomic(*, savepoint: bool = True) -> Callable[[F], F]: ...
# Implementation
def atomic(__func: Callable[..., Any] = None, *, savepoint: bool = True):
def decorator(func: Callable[..., Any]):
... # Code goes here
if __func is not None:
return decorator(__func)
else:
return decorator
# Usage
@atomic
def func1() -> None: ...
@atomic(savepoint=False)
def func2() -> None: ...
Generic protocols
*****************
Mypy supports generic protocols (see also :ref:`protocol-types`). Several
:ref:`predefined protocols ` are generic, such as
:py:class:`Iterable[T] `, and you can define additional generic protocols. Generic
protocols mostly follow the normal rules for generic classes. Example:
.. code-block:: python
from typing import TypeVar
from typing_extensions import Protocol
T = TypeVar('T')
class Box(Protocol[T]):
content: T
def do_stuff(one: Box[str], other: Box[bytes]) -> None:
...
class StringWrapper:
def __init__(self, content: str) -> None:
self.content = content
class BytesWrapper:
def __init__(self, content: bytes) -> None:
self.content = content
do_stuff(StringWrapper('one'), BytesWrapper(b'other')) # OK
x: Box[float] = ...
y: Box[int] = ...
x = y # Error -- Box is invariant
Per :pep:`PEP 544: Generic protocols <544#generic-protocols>`, ``class
ClassName(Protocol[T])`` is allowed as a shorthand for ``class
ClassName(Protocol, Generic[T])``.
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
definition. The protocol in this example is rejected, since the type
variable ``T`` is used covariantly as a return type, but the type
variable is invariant:
.. code-block:: python
from typing import TypeVar
from typing_extensions import Protocol
T = TypeVar('T')
class ReadOnlyBox(Protocol[T]): # Error: covariant type variable 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
T_co = TypeVar('T_co', covariant=True)
class ReadOnlyBox(Protocol[T_co]): # OK
def content(self) -> T_co: ...
ax: ReadOnlyBox[float] = ...
ay: ReadOnlyBox[int] = ...
ax = ay # OK -- ReadOnlyBox is covariant
See :ref:`variance-of-generics` for more about variance.
Generic protocols can also be recursive. Example:
.. code-block:: python
T = TypeVar('T')
class Linked(Protocol[T]):
val: T
def next(self) -> 'Linked[T]': ...
class L:
val: int
... # details omitted
def next(self) -> 'L':
... # details omitted
def last(seq: Linked[T]) -> T:
... # implementation omitted
result = last(L()) # Inferred type of 'result' is 'int'
.. _generic-type-aliases:
Generic type aliases
********************
Type aliases can be generic. In this case they can be used in two ways:
Subscripted aliases are equivalent to original types with substituted type
variables, so the number of type arguments must match the number of free type variables
in the generic type alias. Unsubscripted aliases are treated as original types with free
variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases
<484#type-aliases>`):
.. code-block:: python
from typing import TypeVar, Iterable, Union, Callable
S = TypeVar('S')
TInt = tuple[int, S]
UInt = Union[S, int]
CBack = Callable[..., S]
def response(query: str) -> UInt[str]: # Same as Union[str, int]
...
def activate(cb: CBack[S]) -> S: # Same as Callable[..., S]
...
table_entry: TInt # Same as tuple[int, Any]
T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T:
return sum(x*y for x, y in v)
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]]
v3: Vec[int, int] = [] # Error: Invalid alias, too many type arguments!
Type aliases can be imported from modules just like other names. An
alias can also target another alias, although building complex chains
of aliases is not recommended -- this impedes code readability, thus
defeating the purpose of using aliases. Example:
.. code-block:: python
from typing import TypeVar, Generic, Optional
from example1 import AliasType
from example2 import Vec
# AliasType and Vec are type aliases (Vec as defined above)
def fun() -> AliasType:
...
T = TypeVar('T')
class NewVec(Vec[T]):
...
for i, j in NewVec[int]():
...
OIntVec = Optional[Vec[int]]
.. note::
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.
mypy-0.942/docs/source/getting_started.rst 0000644 0001751 0000171 00000040165 14217067311 021506 0 ustar runner docker 0000000 0000000 .. _getting-started:
Getting started
===============
This chapter introduces some core concepts of mypy, including function
annotations, the :py:mod:`typing` module, library stubs, and more.
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.6 or later to run. Once you've
`installed Python 3 `_,
install mypy using pip:
.. code-block:: shell
$ python3 -m pip install mypy
Once mypy is installed, run it by using the ``mypy`` tool:
.. code-block:: shell
$ mypy program.py
This command makes mypy *type check* your ``program.py`` file and print
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.
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.
.. code-block:: shell
$ mypy --py2 program.py
Function signatures and dynamic vs static typing
************************************************
A function without type annotations is considered to be *dynamically typed* by mypy:
.. code-block:: python
def greeting(name):
return 'Hello ' + name
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.
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
and returns a string like so:
.. code-block:: python
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:
.. code-block:: python
def greeting(name: str) -> str:
return 'Hello ' + name
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"
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.
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
Python codebase to use static types, it's usually easier to migrate by incrementally
adding type hints to your code rather than adding them all at once. Similarly,
when you are prototyping a new feature, it may be convenient to initially implement
the code using dynamic typing and only add type hints later once the code is more stable.
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.
.. 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.
More function signatures
************************
Here are a few more examples of adding type hints to function signatures.
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:
.. code-block:: python
def p() -> None:
print('hello')
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
***************************************
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,
such as "a list of strings" or "an iterable of ints"?
For example, to indicate that some function can accept a list of
strings, use the ``list[str]`` type (Python 3.9 and later):
.. code-block:: python
def greet_all(names: list[str]) -> None:
for name in names:
print('Hello ' + name)
names = ["Alice", "Bob", "Charlie"]
ages = [10, 20, 30]
greet_all(names) # Ok!
greet_all(ages) # Error due to incompatible types
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` (or :py:class:`typing.Iterable` in Python
3.8 and earlier) type instead of :py:class:`list` :
.. code-block:: python
from collections.abc import Iterable # or "from typing import Iterable"
def greet_all(names: Iterable[str]) -> None:
for name in names:
print('Hello ' + name)
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:
.. code-block:: python
from typing import Union
def normalize_id(user_id: Union[int, str]) -> str:
if isinstance(user_id, int):
return 'user-{}'.format(100000 + 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
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
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
:ref:`type system reference `.
.. note::
When adding types, the convention is to import types
using the form ``from typing import Union`` (as opposed to doing
just ``import typing`` or ``import typing as t`` or ``from typing import *``).
For brevity, we often omit imports from :py:mod:`typing` or :py:mod:`collections.abc`
in code examples, but mypy will give an error if you use types such as
:py:class:`~typing.Iterable` without first importing them.
.. note::
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 using Python 3.8 or earlier.
Local type inference
********************
Once you have added type hints to a function (i.e. made it statically typed),
mypy will automatically type check that function's body. While doing so,
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.
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``:
.. code-block:: python
def nums_below(numbers: Iterable[float], limit: float) -> list[float]:
output = []
for num in numbers:
if num < limit:
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"
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
**************************
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.
For example, consider this code:
.. code-block:: python
x = chr(4)
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.
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:
.. code-block:: shell
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:
.. code-block:: text
prog.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8)
prog.py:1: note: Hint: "python3 -m pip install types-PyYAML"
...
.. 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.
You can also :ref:`create
stubs ` easily. We discuss ways of silencing complaints
about missing stubs in :ref:`ignore-missing-imports`.
Configuring mypy
****************
Mypy supports many command line options that you can use to tweak how
mypy behaves: see :ref:`command-line` for more details.
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.
Another potentially useful flag is :option:`--strict `, which enables many
(though not all) of the available strictness options -- including
:option:`--disallow-untyped-defs `.
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.
Next steps
**********
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 :ref:`existing-code` if you have a significant existing
codebase without many type annotations.
* Read the `blog post `_
about the Zulip project's experiences with adopting mypy.
* If you prefer watching talks instead of reading, here are
some ideas:
* Carl Meyer:
`Type Checked Python in the Real World `_
(PyCon 2018)
* Greg Price:
`Clearer Code at Scale: Static Types at Zulip and Dropbox `_
(PyCon 2018)
* Look at :ref:`solutions to common issues ` with mypy if
you encounter problems.
* You can ask questions about mypy in the
`mypy issue tracker `_ and
typing `Gitter chat `_.
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.
mypy-0.942/docs/source/index.rst 0000644 0001751 0000171 00000002612 14217067311 017421 0 ustar runner docker 0000000 0000000 .. Mypy documentation master file, created by
sphinx-quickstart on Sun Sep 14 19:50:35 2014.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to mypy documentation!
==============================
Mypy is a static type checker for Python 3 and Python 2.7.
.. toctree::
:maxdepth: 2
:caption: First steps
introduction
getting_started
existing_code
.. _overview-cheat-sheets:
.. toctree::
:maxdepth: 2
:caption: Cheat sheets
cheat_sheet_py3
cheat_sheet
.. _overview-type-system-reference:
.. toctree::
:maxdepth: 2
:caption: Type system reference
builtin_types
type_inference_and_annotations
kinds_of_types
class_basics
runtime_troubles
protocols
dynamic_typing
python2
type_narrowing
duck_type_compatibility
stubs
generics
more_types
literal_types
final_attrs
metaclasses
.. toctree::
:maxdepth: 2
:caption: Configuring and running mypy
running_mypy
command_line
config_file
inline_config
mypy_daemon
installed_packages
extending_mypy
stubgen
stubtest
.. toctree::
:maxdepth: 2
:caption: Miscellaneous
common_issues
supported_python_features
error_codes
error_code_list
error_code_list2
additional_features
faq
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`
mypy-0.942/docs/source/inline_config.rst 0000644 0001751 0000171 00000002214 14217067311 021113 0 ustar runner docker 0000000 0000000 .. _inline-config:
Inline configuration
====================
Mypy supports setting per-file configuration options inside files themselves
using ``# mypy:`` comments. For example:
.. code-block:: python
# mypy: disallow-any-generics
Inline configuration comments take precedence over all other
configuration mechanisms.
Configuration comment format
****************************
Flags correspond to :ref:`config file flags ` but allow
hyphens to be substituted for underscores.
Values are specified using ``=``, but ``= True`` may be omitted:
.. code-block:: python
# mypy: disallow-any-generics
# mypy: always-true=FOO
Multiple flags can be separated by commas or placed on separate
lines. To include a comma as part of an option's value, place the
value inside quotes:
.. code-block:: python
# mypy: disallow-untyped-defs, always-false="FOO,BAR"
Like in the configuration file, options that take a boolean value may be
inverted by adding ``no-`` to their name or by (when applicable)
swapping their prefix from ``disallow`` to ``allow`` (and vice versa):
.. code-block:: python
# mypy: allow-untyped-defs, no-strict-optional
mypy-0.942/docs/source/installed_packages.rst 0000644 0001751 0000171 00000014264 14217067311 022135 0 ustar runner docker 0000000 0000000 .. _installed-packages:
Using installed packages
========================
Packages installed with pip can declare that they support type
checking. For example, the `aiohttp
`_ package has built-in support
for type checking.
Packages can also provide stubs for a library. For example,
``types-requests`` is a stub-only package that provides stubs for the
`requests `_ package.
Stub packages are usually published from `typeshed
`_, a shared repository for Python
library stubs, and have a name of form ``types-``. Note that
many stub packages are not maintained by the original maintainers of
the package.
The sections below explain how mypy can use these packages, and how
you can create such packages.
.. note::
:pep:`561` specifies how a package can declare that it supports
type checking.
Using installed packages with mypy (PEP 561)
********************************************
Typically mypy will automatically find and use installed packages that
support type checking or provide stubs. This requires that you install
the packages in the Python environment that you use to run mypy. As
many packages don't support type checking yet, you may also have to
install a separate stub package, usually named
``types-``. (See :ref:`fix-missing-imports` for how to deal
with libraries that don't support type checking and are also missing
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
:option:`--python-executable ` flag to point
to the target Python executable, 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.
If you don't want to use installed packages that provide type
information at all, use the :option:`--no-site-packages ` flag to disable searching for installed packages.
Note that stub-only packages cannot be used with ``MYPYPATH``. If you
want mypy to find the package, it must be installed. For a package
``foo``, the name of the stub-only package (``foo-stubs``) is not a
legal package name, so mypy will not find it, unless it is installed
(see :pep:`PEP 561: Stub-only Packages <561#stub-only-packages>` for
more information).
Creating PEP 561 compatible packages
************************************
.. note::
You can generally ignore this section unless you maintain a package on
PyPI, or want to publish type information for an existing PyPI
package.
:pep:`561` describes three main ways to distribute type
information:
1. A package has inline type annotations in the Python implementation.
2. A package ships :ref:`stub files ` with type
information alongside the Python implementation.
3. A package ships type information for another package separately as
stub files (also known as a "stub-only package").
If you want to create a stub-only package for an existing library, the
simplest way is to contribute stubs to the `typeshed
`_ repository, and a stub package
will automatically be uploaded to PyPI.
If you would like to publish a library package to a package repository
yourself (e.g. on PyPI) for either internal or external use in type
checking, packages that supply type information via type comments or
annotations in the code should put a ``py.typed`` file in their
package directory. For example, here is a typical directory structure:
.. code-block:: text
setup.py
package_a/
__init__.py
lib.py
py.typed
The ``setup.py`` file could look like this:
.. code-block:: python
from distutils.core import setup
setup(
name="SuperPackageA",
author="Me",
version="0.1",
package_data={"package_a": ["py.typed"]},
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:
.. code-block:: text
setup.py
package_b/
__init__.py
lib.py
lib.pyi
py.typed
The ``setup.py`` file might look like this:
.. code-block:: python
from distutils.core import setup
setup(
name="SuperPackageB",
author="Me",
version="0.1",
package_data={"package_b": ["py.typed", "lib.pyi"]},
packages=["package_b"]
)
In this example, both ``lib.py`` and the ``lib.pyi`` stub file exist. At
runtime, the Python interpreter will use ``lib.py``, but mypy will use
``lib.pyi`` instead.
If the package is stub-only (not imported at runtime), the package should have
a prefix of the runtime package name and a suffix of ``-stubs``.
A ``py.typed`` file is not needed for stub-only packages. For example, if we
had stubs for ``package_c``, we might do the following:
.. code-block:: text
setup.py
package_c-stubs/
__init__.pyi
lib.pyi
The ``setup.py`` might look like this:
.. code-block:: python
from distutils.core import setup
setup(
name="SuperPackageC",
author="Me",
version="0.1",
package_data={"package_c-stubs": ["__init__.pyi", "lib.pyi"]},
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
mypy-0.942/docs/source/introduction.rst 0000644 0001751 0000171 00000003104 14217067311 021030 0 ustar runner docker 0000000 0000000 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.
mypy-0.942/docs/source/kinds_of_types.rst 0000644 0001751 0000171 00000063065 14217067311 021343 0 ustar runner docker 0000000 0000000 Kinds of types
==============
We've mostly restricted ourselves to built-in types until now. This
section introduces several additional kinds of types. You are likely
to need at least some of them to type check any non-trivial programs.
Class types
***********
Every class is also a valid type. Any instance of a subclass is also
compatible with all superclasses -- it follows that every value is compatible
with the :py:class:`object` type (and incidentally also the ``Any`` type, discussed
below). Mypy analyzes the bodies of classes to determine which methods and
attributes are available in instances. This example uses subclassing:
.. code-block:: python
class A:
def f(self) -> int: # Type of self inferred (A)
return 2
class B(A):
def f(self) -> int:
return 3
def g(self) -> int:
return 4
def foo(a: A) -> None:
print(a.f()) # 3
a.g() # Error: "A" has no attribute "g"
foo(B()) # OK (B is a subclass of A)
The Any type
************
A value with the ``Any`` type is dynamically typed. Mypy doesn't know
anything about the possible runtime types of such value. Any
operations are permitted on the value, and the operations are only checked
at runtime. You can use ``Any`` as an "escape hatch" when you can't use
a more precise type for some reason.
``Any`` is compatible with every other type, and vice versa. You can freely
assign a value of type ``Any`` to a variable with a more precise type:
.. code-block:: python
a: Any = None
s: str = ''
a = 2 # OK (assign "int" to "Any")
s = a # OK (assign "Any" to "str")
Declared (and inferred) types are ignored (or *erased*) at runtime. They are
basically treated as comments, and thus the above code does not
generate a runtime error, even though ``s`` gets an ``int`` value when
the program is run, while the declared type of ``s`` is actually
``str``! You need to be careful with ``Any`` types, since they let you
lie to mypy, and this could easily hide bugs.
If you do not define a function return value or argument types, these
default to ``Any``:
.. code-block:: python
def show_heading(s) -> None:
print('=== ' + s + ' ===') # No static type checking, as s has type Any
show_heading(1) # OK (runtime error only; mypy won't generate an error)
You should give a statically typed function an explicit ``None``
return type even if it doesn't return a value, as this lets mypy catch
additional type errors:
.. code-block:: python
def wait(t: float): # Implicit Any return value
print('Waiting...')
time.sleep(t)
if wait(2) > 1: # Mypy doesn't catch this error!
...
If we had used an explicit ``None`` return type, mypy would have caught
the error:
.. code-block:: python
def wait(t: float) -> None:
print('Waiting...')
time.sleep(t)
if wait(2) > 1: # Error: can't compare None and int
...
The ``Any`` type is discussed in more detail in section :ref:`dynamic-typing`.
.. note::
A function without any types in the signature is dynamically
typed. The body of a dynamically typed function is not checked
statically, and local variables have implicit ``Any`` types.
This makes it easier to migrate legacy Python code to mypy, as
mypy won't complain about dynamically typed functions.
.. _tuple-types:
Tuple types
***********
The type ``tuple[T1, ..., Tn]`` represents a tuple with the item types ``T1``, ..., ``Tn``:
.. code-block:: python
# 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
a literal ``...`` -- it's part of the syntax) for this
purpose. Example:
.. code-block:: python
def print_squared(t: tuple[int, ...]) -> None:
for n in t:
print(n, n ** 2)
print_squared(()) # OK
print_squared((1, 3, 5)) # OK
print_squared([1, 2]) # Error: only a tuple is valid
.. note::
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
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`).
.. _callable-types:
Callable types (and lambdas)
****************************
You can pass around function objects and bound methods in statically
typed code. The type of a function that accepts arguments ``A1``, ..., ``An``
and returns ``Rt`` is ``Callable[[A1, ..., An], Rt]``. Example:
.. code-block:: python
from typing import Callable
def twice(i: int, next: Callable[[int], int]) -> int:
return next(next(i))
def add(i: int) -> int:
return i + 1
print(twice(3, add)) # 5
You can only have positional arguments, and only ones without default
values, in callable types. These cover the vast majority of uses of
callable types, but sometimes this isn't quite enough. Mypy recognizes
a special form ``Callable[..., T]`` (with a literal ``...``) which can
be used in less typical cases. It is compatible with arbitrary
callable objects that return a type compatible with ``T``, independent
of the number, types or kinds of arguments. Mypy lets you call such
callable values with arbitrary arguments, without any checking -- in
this respect they are treated similar to a ``(*args: Any, **kwargs:
Any)`` function signature. Example:
.. code-block:: python
from typing import Callable
def arbitrary_call(f: Callable[..., int]) -> int:
return f('x') + f(y=2) # OK
arbitrary_call(ord) # No static error, but fails at runtime
arbitrary_call(open) # Error: does not return an int
arbitrary_call(1) # Error: 'int' is not callable
In situations where more precise or complex types of callbacks are
necessary one can use flexible :ref:`callback protocols `.
Lambdas are also supported. The lambda argument and return value types
cannot be given explicitly; they are always inferred based on context
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]
If you want to give the argument or return value types explicitly, use
an ordinary, perhaps nested function definition.
.. _union-types:
Union types
***********
Python functions often accept values of two or more different
types. You can use :ref:`overloading ` to
represent this, but union types are often more convenient.
Use the ``Union[T1, ..., Tn]`` type constructor to construct a union
type. For example, if an argument has type ``Union[int, str]``, both
integers and strings are valid argument values.
You can use an :py:func:`isinstance` check to narrow down a union type to a
more specific type:
.. code-block:: python
from typing import Union
def f(x: Union[int, str]) -> None:
x + 1 # Error: str + int is not valid
if isinstance(x, int):
# Here type of x is int.
x + 1 # OK
else:
# Here type of x is str.
x + 'a' # OK
f(1) # OK
f('x') # OK
f(1.1) # Error
.. note::
Operations are valid for union types only if they are valid for *every*
union item. This is why it's often necessary to use an :py:func:`isinstance`
check to first narrow down a union type to a non-union type. This also
means that it's recommended to avoid union types as function return types,
since the caller may have to use :py:func:`isinstance` before doing anything
interesting with the value.
.. _strict_optional:
Optional types and the None type
********************************
You can use the :py:data:`~typing.Optional` type modifier to define a type variant
that allows ``None``, such as ``Optional[int]`` (``Optional[X]`` is
the preferred shorthand for ``Union[X, None]``):
.. code-block:: python
from typing import Optional
def strlen(s: str) -> Optional[int]:
if not s:
return None # OK
return len(s)
def strlen_invalid(s: str) -> int:
if not s:
return None # Error: None not compatible with int
return len(s)
Most operations will not be allowed on unguarded ``None`` or :py:data:`~typing.Optional`
values:
.. code-block:: python
def my_inc(x: Optional[int]) -> int:
return x + 1 # Error: Cannot add None and int
Instead, an explicit ``None`` check is required. Mypy has
powerful type inference that lets you use regular Python
idioms to guard against ``None`` values. For example, mypy
recognizes ``is None`` checks:
.. code-block:: python
def my_inc(x: Optional[int]) -> int:
if x is None:
return 0
else:
# The inferred type of x is just int here.
return x + 1
Mypy will infer the type of ``x`` to be ``int`` in the else block due to the
check against ``None`` in the if condition.
Other supported checks for guarding against a ``None`` value include
``if x is not None``, ``if x`` and ``if not x``. Additionally, mypy understands
``None`` checks within logical expressions:
.. code-block:: python
def concat(x: Optional[str], y: Optional[str]) -> Optional[str]:
if x is not None and y is not None:
# Both x and y are not None here
return x + y
else:
return None
Sometimes mypy doesn't realize that a value is never ``None``. This notably
happens when a class instance can exist in a partially defined state,
where some attribute is initialized to ``None`` during object
construction, but a method assumes that the attribute is no longer ``None``. Mypy
will complain about the possible ``None`` value. You can use
``assert x is not None`` to work around this in the method:
.. code-block:: python
class Resource:
path: Optional[str] = None
def initialize(self, path: str) -> None:
self.path = path
def read(self) -> str:
# We require that the object has been initialized.
assert self.path is not None
with open(self.path) as f: # OK
return f.read()
r = Resource()
r.initialize('/foo/bar')
r.read()
When initializing a variable as ``None``, ``None`` is usually an
empty place-holder value, and the actual value has a different type.
This is why you need to annotate an attribute in cases like the class
``Resource`` above:
.. code-block:: python
class Resource:
path: Optional[str] = None
...
This also works for attributes defined within methods:
.. code-block:: python
class Counter:
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
class Container:
items = None # type: list[str] # OK (only with type comment)
This is not a problem when using variable annotations, since no initializer
is needed:
.. code-block:: python
class Container:
items: list[str] # No initializer
Mypy generally uses the first assignment to a variable to
infer the type of the variable. However, if you assign both a ``None``
value and a non-``None`` value in the same scope, mypy can usually do
the right thing without an annotation:
.. code-block:: python
def f(i: int) -> None:
n = None # Inferred type Optional[int] because of the assignment below
if i > 0:
n = i
...
Sometimes you may get the error "Cannot determine type of ". In this
case you should add an explicit ``Optional[...]`` annotation (or type comment).
.. note::
``None`` is a type with only one value, ``None``. ``None`` is also used
as the return type for functions that don't return a value, i.e. functions
that implicitly return ``None``.
.. note::
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.)
.. 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.
.. _alternative_union_syntax:
X | Y syntax for Unions
-----------------------
:pep:`604` introduced an alternative way for spelling union types. In Python
3.10 and later, you can write ``Union[int, str]`` as ``int | str``. It is
possible to use this syntax in versions of Python where it isn't supported by
the runtime with some limitations (see :ref:`runtime_troubles`).
.. code-block:: python
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
**********************************
Mypy also has an option to treat ``None`` as a valid value for every
type (in case you know Java, it's useful to think of it as similar to
the Java ``null``). In this mode ``None`` is also valid for primitive
types such as ``int`` and ``float``, and :py:data:`~typing.Optional` types are
not required.
The mode is enabled through the :option:`--no-strict-optional ` command-line
option. In mypy versions before 0.600 this was the default mode. You
can enable this option explicitly for backward compatibility with
earlier mypy versions, in case you don't want to introduce optional
types to your codebase yet.
It will cause mypy to silently accept some buggy code, such as
this example -- it's not recommended if you can avoid it:
.. code-block:: python
def inc(x: int) -> int:
return x + 1
x = inc(None) # No error reported by mypy if strict optional mode disabled!
However, making code "optional clean" can take some work! You can also use
:ref:`the mypy configuration file ` to migrate your code
to strict optional checking one file at a time, since there exists
the per-module flag
:confval:`strict_optional` to control strict optional mode.
Often it's still useful to document whether a variable can be
``None``. For example, this function accepts a ``None`` argument,
but it's not obvious from its signature:
.. code-block:: python
def greeting(name: str) -> str:
if name:
return 'Hello, {}'.format(name)
else:
return 'Hello, stranger'
print(greeting('Python')) # Okay!
print(greeting(None)) # Also okay!
You can still use :py:data:`Optional[t] ` to document that ``None`` is a
valid argument type, even if strict ``None`` checking is not
enabled:
.. code-block:: python
from typing import Optional
def greeting(name: Optional[str]) -> str:
if name:
return 'Hello, {}'.format(name)
else:
return 'Hello, stranger'
Mypy treats this as semantically equivalent to the previous example
if strict optional checking is disabled, since ``None`` is implicitly
valid for any type, but it's much more
useful for a programmer who is reading the code. This also makes
it easier to migrate to strict ``None`` checking in the future.
.. _type-aliases:
Type aliases
************
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]]]:
...
When cases like this arise, you can define a type alias by simply
assigning the type to a variable:
.. code-block:: python
AliasType = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]]
# Now we can use AliasType in place of the full name:
def f() -> AliasType:
...
.. note::
A type alias does not create a new type. It's just a shorthand notation for
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
************
Mypy recognizes named tuples and can type check code that defines or
uses them. In this example, we can detect code trying to access a
missing attribute:
.. code-block:: python
Point = namedtuple('Point', ['x', 'y'])
p = Point(x=1, y=2)
print(p.z) # Error: Point has no attribute 'z'
If you use :py:func:`namedtuple ` to define your named tuple, all the items
are assumed to have ``Any`` types. That is, mypy doesn't know anything
about item types. You can use :py:class:`~typing.NamedTuple` to also define
item types:
.. code-block:: python
from typing import NamedTuple
Point = NamedTuple('Point', [('x', int),
('y', int)])
p = Point(x=1, y='x') # Argument has incompatible type "str"; expected "int"
Python 3.6 introduced an alternative, class-based syntax for named tuples with types:
.. code-block:: python
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
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
*************************
(Freely after :pep:`PEP 484: 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
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
argument annotation declares that the argument is a class object
deriving from ``C`` (or ``C`` itself).
For example, assume the following classes:
.. code-block:: python
class User:
# Defines fields like name, email
class BasicUser(User):
def upgrade(self):
"""Upgrade to Pro"""
class ProUser(User):
def pay(self):
"""Pay bill"""
Note that ``ProUser`` doesn't inherit from ``BasicUser``.
Here's a function that creates an instance of one of these classes if
you pass it the right class object:
.. code-block:: python
def new_user(user_class):
user = user_class()
# (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
could do would be:
.. code-block:: python
def new_user(user_class: type) -> User:
# Same implementation as before
This seems reasonable, except that in the following example, mypy
doesn't see that the ``buyer`` variable has type ``ProUser``:
.. code-block:: python
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
: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:
# Same implementation as before
Now mypy will infer the correct type of the result when we call
``new_user()`` with a specific subclass of ``User``:
.. code-block:: python
beginner = new_user(BasicUser) # Inferred type is BasicUser
beginner.upgrade() # OK
.. note::
The value corresponding to :py:class:`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
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 succinctly annotated as having a return
type of either :py:class:`Iterator[YieldType] ` or :py:class:`Iterable[YieldType] `. For example:
.. code-block:: python
def squares(n: int) -> Iterator[int]:
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, 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
def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'
Note that unlike many other generics in the typing module, the ``SendType`` of
:py:class:`~typing.Generator` behaves contravariantly, not covariantly or invariantly.
If you do not plan on receiving or returning values, then set the ``SendType``
or ``ReturnType`` to ``None``, as appropriate. For example, we could have
annotated the first example as the following:
.. code-block:: python
def squares(n: int) -> Generator[int, None, None]:
for i in range(n):
yield i * i
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 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`.
mypy-0.942/docs/source/literal_types.rst 0000644 0001751 0000171 00000041512 14217067311 021174 0 ustar runner docker 0000000 0000000 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"]``,
mypy will understand that variable is not only of type ``str``, but is also
equal to specifically the string ``"foo"``.
This feature is primarily useful when annotating functions that behave
differently based on the exact value the caller provides. For example,
suppose we have a function ``fetch_data(...)`` that returns ``bytes`` if the
first argument is ``True``, and ``str`` if it's ``False``. We can construct a
precise type signature for this function using ``Literal[...]`` and overloads:
.. code-block:: python
from typing import overload, Union, Literal
# The first two overloads use Literal[...] so we can
# have precise return types:
@overload
def fetch_data(raw: Literal[True]) -> bytes: ...
@overload
def fetch_data(raw: Literal[False]) -> str: ...
# The last overload is a fallback in case the caller
# provides a regular bool:
@overload
def fetch_data(raw: bool) -> Union[bytes, str]: ...
def fetch_data(raw: bool) -> Union[bytes, str]:
# Implementation is omitted
...
reveal_type(fetch_data(True)) # Revealed type is "bytes"
reveal_type(fetch_data(False)) # Revealed type is "str"
# Variables declared without annotations will continue to have an
# inferred type of 'bool'.
variable = True
reveal_type(fetch_data(variable)) # Revealed type is "Union[bytes, str]"
.. note::
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.
Parameterizing Literals
***********************
Literal types may contain one or more literal bools, ints, strs, bytes, and
enum values. However, literal types **cannot** contain arbitrary expressions:
types like ``Literal[my_string.trim()]``, ``Literal[x > 3]``, or ``Literal[3j + 4]``
are all illegal.
Literals containing two or more values are equivalent to the union of those values.
So, ``Literal[-3, b"foo", MyEnum.A]`` is equivalent to
``Union[Literal[-3], Literal[b"foo"], Literal[MyEnum.A]]``. This makes writing more
complex types involving literals a little more convenient.
Literal types may also contain ``None``. Mypy will treat ``Literal[None]`` as being
equivalent to just ``None``. This means that ``Literal[4, None]``,
``Union[Literal[4], None]``, and ``Optional[Literal[4]]`` are all equivalent.
Literals may also contain aliases to other literal types. For example, the
following program is legal:
.. code-block:: python
PrimaryColors = Literal["red", "blue", "yellow"]
SecondaryColors = Literal["purple", "green", "orange"]
AllowedColors = Literal[PrimaryColors, SecondaryColors]
def paint(color: AllowedColors) -> None: ...
paint("red") # Type checks!
paint("turquoise") # Does not type check
Literals may not contain any other kind of type or expression. This means doing
``Literal[my_instance]``, ``Literal[Any]``, ``Literal[3.14]``, or
``Literal[{"foo": 2, "bar": 5}]`` are all illegal.
Declaring literal variables
***************************
You must explicitly add an annotation to a variable to declare that it has
a literal type:
.. code-block:: python
a: Literal[19] = 19
reveal_type(a) # Revealed type is "Literal[19]"
In order to preserve backwards-compatibility, variables without this annotation
are **not** assumed to be literals:
.. code-block:: python
b = 19
reveal_type(b) # Revealed type is "int"
If you find repeating the value of the variable in the type hint to be tedious,
you can instead change the variable to be ``Final`` (see :ref:`final_attrs`):
.. code-block:: python
from typing import Final, Literal
def expects_literal(x: Literal[19]) -> None: pass
c: Final = 19
reveal_type(c) # Revealed type is "Literal[19]?"
expects_literal(c) # ...and this type checks!
If you do not provide an explicit type in the ``Final``, the type of ``c`` becomes
*context-sensitive*: mypy will basically try "substituting" the original assigned
value whenever it's used before performing type checking. This is why the revealed
type of ``c`` is ``Literal[19]?``: the question mark at the end reflects this
context-sensitive nature.
For example, mypy will type check the above program almost as if it were written like so:
.. code-block:: python
from typing import Final, Literal
def expects_literal(x: Literal[19]) -> None: pass
reveal_type(19)
expects_literal(19)
This means that while changing a variable to be ``Final`` is not quite the same thing
as adding an explicit ``Literal[...]`` annotation, it often leads to the same effect
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[...]``.
For example, compare and contrast what happens when you try appending these types to a list:
.. code-block:: python
from typing import Final, Literal
a: Final = 19
b: Literal[19] = 19
# 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]"
# But if the variable you're appending is an explicit Literal, mypy
# will infer list[Literal[19]].
list_of_lits = []
list_of_lits.append(b)
reveal_type(list_of_lits) # Revealed type is "list[Literal[19]]"
Intelligent indexing
********************
We can use Literal types to more precisely index into structured heterogeneous
types such as tuples, NamedTuples, and TypedDicts. This feature is known as
*intelligent indexing*.
For example, when we index into a tuple using some int, the inferred type is
normally the union of the tuple item types. However, if we want just the type
corresponding to some particular index, we can use Literal types like so:
.. code-block:: python
from typing import TypedDict
tup = ("foo", 3.4)
# Indexing with an int literal gives us the exact type for that index
reveal_type(tup[0]) # Revealed type is "str"
# 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 = 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[0] = 0
fin_index: Final = 0
reveal_type(tup[lit_index]) # Revealed type is "str"
reveal_type(tup[fin_index]) # Revealed type is "str"
# We can do the same thing with with TypedDict and str keys:
class MyDict(TypedDict):
name: str
main_id: int
backup_id: int
d: MyDict = {"name": "Saanvi", "main_id": 111, "backup_id": 222}
name_key: Final = "name"
reveal_type(d[name_key]) # Revealed type is "str"
# You can also index using unions of literals
id_key: Literal["main_id", "backup_id"]
reveal_type(d[id_key]) # Revealed type is "int"
.. _tagged_unions:
Tagged unions
*************
When you have a union of types, you can normally discriminate between each type
in the union by using ``isinstance`` checks. For example, if you had a variable ``x`` of
type ``Union[int, str]``, you could write some code that runs only if ``x`` is an int
by doing ``if isinstance(x, int): ...``.
However, it is not always possible or convenient to do this. For example, it is not
possible to use ``isinstance`` to distinguish between two different TypedDicts since
at runtime, your variable will simply be just a dict.
Instead, what you can do is *label* or *tag* your TypedDicts with a distinct Literal
type. Then, you can discriminate between each kind of TypedDict by checking the label:
.. code-block:: python
from typing import Literal, TypedDict, Union
class NewJobEvent(TypedDict):
tag: Literal["new-job"]
job_name: str
config_file_path: str
class CancelJobEvent(TypedDict):
tag: Literal["cancel-job"]
job_id: int
Event = Union[NewJobEvent, CancelJobEvent]
def process_event(event: Event) -> None:
# Since we made sure both TypedDicts have a key named 'tag', it's
# safe to do 'event["tag"]'. This expression normally has the type
# 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
# or CancelJobEvent.
if event["tag"] == "new-job":
print(event["job_name"])
else:
print(event["job_id"])
While this feature is mostly useful when working with TypedDicts, you can also
use the same technique with regular objects, tuples, or namedtuples.
Similarly, tags do not need to be specifically str Literals: they can be any type
you can normally narrow within ``if`` statements and the like. For example, you
could have your tags be int or Enum Literals or even regular classes you narrow
using ``isinstance()``:
.. code-block:: python
from typing import Generic, TypeVar, Union
T = TypeVar('T')
class Wrapper(Generic[T]):
def __init__(self, inner: T) -> None:
self.inner = inner
def process(w: Union[Wrapper[int], Wrapper[str]]) -> None:
# Doing `if isinstance(w, Wrapper[int])` does not work: isinstance requires
# that the second argument always be an *erased* type, with no generics.
# This is because generics are a typing-only concept and do not exist at
# runtime in a way `isinstance` can always check.
#
# However, we can side-step this by checking the type of `w.inner` to
# narrow `w` itself:
if isinstance(w.inner, int):
reveal_type(w) # Revealed type is "Wrapper[int]"
else:
reveal_type(w) # Revealed type is "Wrapper[str]"
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
***********
Mypy will not understand expressions that use variables of type ``Literal[..]``
on a deep level. For example, if you have a variable ``a`` of type ``Literal[3]``
and another variable ``b`` of type ``Literal[5]``, mypy will infer that
``a + b`` has type ``int``, **not** type ``Literal[8]``.
The basic rule is that literal types are treated as just regular subtypes of
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 "Movemement" 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, 'This code should never be reached, got: {0}'.format(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: Other: cannot extend enumeration 'Some'
Mypy also catches this error:
.. code-block:: python
class AllDirection(Direction): # E: Cannot inherit from final class "Some"
left = 'left'
right = 'right'
- All ``Enum`` fields are implictly ``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"
...
mypy-0.942/docs/source/metaclasses.rst 0000644 0001751 0000171 00000005441 14217067311 020621 0 ustar runner docker 0000000 0000000 .. _metaclasses:
Metaclasses
===========
A :ref:`metaclass ` is a class that describes
the construction and behavior of other classes, similarly to how classes
describe the construction and behavior of objects.
The default metaclass is :py:class:`type`, but it's possible to use other metaclasses.
Metaclasses allows one to create "a different kind of class", such as
:py:class:`~enum.Enum`\s, :py:class:`~typing.NamedTuple`\s and singletons.
Mypy has some special understanding of :py:class:`~abc.ABCMeta` and ``EnumMeta``.
.. _defining:
Defining a metaclass
********************
.. code-block:: python
class M(type):
pass
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
***********************
Mypy supports the lookup of attributes in the metaclass:
.. code-block:: python
from typing import Type, TypeVar, ClassVar
T = TypeVar('T')
class M(type):
count: ClassVar[int] = 0
def make(cls: Type[T]) -> T:
M.count += 1
return cls()
class A(metaclass=M):
pass
a: A = A.make() # make() is looked up at M; the result is an object of type A
print(A.count)
class B(A):
pass
b: B = B.make() # metaclasses are inherited
print(B.count + " objects were created") # Error: Unsupported operand types for + ("int" and "str")
.. _limitations:
Gotchas and limitations of metaclass support
********************************************
Note that metaclasses pose some requirements on the inheritance structure,
so it's better not to combine metaclasses and class hierarchies:
.. code-block:: python
class M1(type): pass
class M2(type): pass
class A1(metaclass=M1): pass
class A2(metaclass=M2): pass
class B1(A1, metaclass=M2): pass # Mypy Error: Inconsistent metaclass structure for "B1"
# 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
* Mypy does not understand dynamically-computed metaclasses,
such as ``class A(metaclass=f()): ...``
* Mypy does not and cannot understand arbitrary metaclass code.
* Mypy only recognizes subclasses of :py:class:`type` as potential metaclasses.
mypy-0.942/docs/source/more_types.rst 0000644 0001751 0000171 00000120165 14217067311 020504 0 ustar runner docker 0000000 0000000 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
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.
Here's a quick summary of what's covered here:
* :py:data:`~typing.NoReturn` lets you tell mypy that a function never returns normally.
* :py:func:`NewType ` lets you define a variant of a type that is treated as a
separate type by mypy but is identical to the original type at runtime.
For example, you can have ``UserId`` as a variant of ``int`` that is
just an ``int`` at runtime.
* :py:func:`@overload ` lets you define a function that can accept multiple distinct
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:
The NoReturn type
*****************
Mypy provides support for functions that never return. For
example, a function that unconditionally raises an exception:
.. code-block:: python
from typing import NoReturn
def stop() -> NoReturn:
raise Exception('no way')
Mypy will ensure that functions annotated as returning :py:data:`~typing.NoReturn`
truly never return, either implicitly or explicitly. Mypy will also
recognize that the code after calls to such functions is unreachable
and will behave accordingly:
.. code-block:: python
def f(x: int) -> int:
if x == 0:
return x
stop()
return 'whatever works' # No error in an unreachable block
In earlier Python versions you need to install ``typing_extensions`` using
pip to use :py:data:`~typing.NoReturn` in your code. Python 3 command line:
.. code-block:: text
python3 -m pip install --upgrade typing-extensions
This works for Python 2:
.. code-block:: text
pip install --upgrade typing-extensions
.. _newtypes:
NewTypes
********
There are situations where you may want to avoid programming errors by
creating simple derived classes that are only used to distinguish
certain values from base class instances. Example:
.. code-block:: python
class UserId(int):
pass
def get_by_user_id(user_id: UserId):
...
However, this approach introduces some runtime overhead. To avoid this, the typing
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:
.. code-block:: python
class Derived(Base):
def __init__(self, _x: Base) -> None:
...
However, at runtime, ``NewType('Derived', Base)`` will return a dummy callable that
simply returns its argument:
.. code-block:: python
def Derived(_x):
return _x
Mypy will require explicit casts from ``int`` where ``UserId`` is expected, while
implicitly casting from ``UserId`` where ``int`` is expected. Examples:
.. code-block:: python
from typing import NewType
UserId = NewType('UserId', int)
def name_by_id(user_id: UserId) -> str:
...
UserId('user') # Fails type check
name_by_id(42) # Fails type check
name_by_id(UserId(42)) # OK
num = UserId(5) + 1 # type: int
: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 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:
.. code-block:: python
from typing import NewType
class PacketId:
def __init__(self, major: int, minor: int) -> None:
self._major = major
self._minor = minor
TcpPacketId = NewType('TcpPacketId', PacketId)
packet = PacketId(100, 100)
tcp_packet = TcpPacketId(packet) # OK
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`, nor can you subclass an object returned by :py:func:`~typing.NewType`.
.. note::
Unlike type aliases, :py:func:`NewType ` will create an entirely new and
unique type when used. The intended purpose of :py:func:`NewType ` is to help you
detect cases where you accidentally mixed together the old base type and the
new derived type.
For example, the following will successfully typecheck when using type
aliases:
.. code-block:: python
UserId = int
def name_by_id(user_id: UserId) -> str:
...
name_by_id(3) # ints and UserId are synonymous
But a similar example using :py:func:`NewType ` will not typecheck:
.. code-block:: python
from typing import NewType
UserId = NewType('UserId', int)
def name_by_id(user_id: UserId) -> str:
...
name_by_id(3) # int is not the same as UserId
.. _function-overloading:
Function overloading
********************
Sometimes the arguments and types in a function depend on each other
in ways that can't be captured with a :py:data:`~typing.Union`. For example, suppose
we want to write a function that can accept x-y coordinates. If we pass
in just a single x-y coordinate, we return a ``ClickEvent`` object. However,
if we pass in two x-y coordinates, we return a ``DragEvent`` object.
Our first attempt at writing this function might look like this:
.. code-block:: python
from typing import Union, Optional
def mouse_event(x1: int,
y1: int,
x2: Optional[int] = None,
y2: Optional[int] = None) -> Union[ClickEvent, DragEvent]:
if x2 is None and y2 is None:
return ClickEvent(x1, y1)
elif x2 is not None and y2 is not None:
return DragEvent(x1, y1, x2, y2)
else:
raise TypeError("Bad arguments")
While this function signature works, it's too loose: it implies ``mouse_event``
could return either object regardless of the number of arguments
we pass in. It also does not prohibit a caller from passing in the wrong
number of ints: mypy would treat calls like ``mouse_event(1, 2, 20)`` as being
valid, for example.
We can do better by using :pep:`overloading <484#function-method-overloading>`
which lets us give the same function multiple type annotations (signatures)
to more accurately describe the function's behavior:
.. code-block:: python
from typing import Union, overload
# Overload *variants* for 'mouse_event'.
# These variants give extra information to the type checker.
# They are ignored at runtime.
@overload
def mouse_event(x1: int, y1: int) -> ClickEvent: ...
@overload
def mouse_event(x1: int, y1: int, x2: int, y2: int) -> DragEvent: ...
# The actual *implementation* of 'mouse_event'.
# The implementation contains the actual runtime logic.
#
# It may or may not have type hints. If it does, mypy
# will check the body of the implementation against the
# type hints.
#
# Mypy will also check and make sure the signature is
# consistent with the provided variants.
def mouse_event(x1: int,
y1: int,
x2: Optional[int] = None,
y2: Optional[int] = None) -> Union[ClickEvent, DragEvent]:
if x2 is None and y2 is None:
return ClickEvent(x1, y1)
elif x2 is not None and y2 is not None:
return DragEvent(x1, y1, x2, y2)
else:
raise TypeError("Bad arguments")
This allows mypy to understand calls to ``mouse_event`` much more precisely.
For example, mypy will understand that ``mouse_event(5, 25)`` will
always have a return type of ``ClickEvent`` and will report errors for
calls like ``mouse_event(5, 25, 2)``.
As another example, suppose we want to write a custom container class that
implements the :py:meth:`__getitem__ ` method (``[]`` bracket indexing). If this
method receives an integer we return a single item. If it receives a
``slice``, we return a :py:class:`~typing.Sequence` of items.
We can precisely encode this relationship between the argument and the
return type by using overloads like so:
.. code-block:: python
from typing import Sequence, TypeVar, Union, overload
T = TypeVar('T')
class MyList(Sequence[T]):
@overload
def __getitem__(self, index: int) -> T: ...
@overload
def __getitem__(self, index: slice) -> Sequence[T]: ...
def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]:
if isinstance(index, int):
# Return a T here
elif isinstance(index, slice):
# Return a sequence of Ts here
else:
raise TypeError(...)
.. note::
If you just need to constrain a type variable to certain types or
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
----------------
An overloaded function must consist of two or more overload *variants*
followed by an *implementation*. The variants and the implementations
must be adjacent in the code: think of them as one indivisible unit.
The variant bodies must all be empty; only the implementation is allowed
to contain code. This is because at runtime, the variants are completely
ignored: they're overridden by the final implementation function.
This means that an overloaded function is still an ordinary Python
function! There is no automatic dispatch handling and you must manually
handle the different types in the implementation (e.g. by using
``if`` statements and :py:func:`isinstance ` checks).
If you are adding an overload within a stub file, the implementation
function should be omitted: stubs do not contain runtime logic.
.. note::
While we can leave the variant body empty using the ``pass`` keyword,
the more common convention is to instead use the ellipsis (``...``) literal.
Type checking calls to overloads
--------------------------------
When you call an overloaded function, mypy will infer the correct return
type by picking the best matching variant, after taking into consideration
both the argument types and arity. However, a call is never type
checked against the implementation. This is why mypy will report calls
like ``mouse_event(5, 25, 3)`` as being invalid even though it matches the
implementation signature.
If there are multiple equally good matching variants, mypy will select
the variant that was defined first. For example, consider the following
program:
.. code-block:: python
# 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: ...
@overload
def summarize(data: list[str]) -> str: ...
def summarize(data):
if not data:
return 0.0
elif isinstance(data[0], int):
# Do int specific code
else:
# Do str-specific code
# What is the type of 'output'? float or str?
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
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.
However, there are two exceptions to the "pick the first match" rule.
First, if multiple variants match due to an argument being of type
``Any``, mypy will make the inferred type also be ``Any``:
.. code-block:: python
dynamic_var: Any = some_dynamic_function()
# output2 is of type 'Any'
output2 = summarize(dynamic_var)
Second, if multiple variants match due to one or more of the arguments
being a union, mypy will make the inferred type be the union of the
matching variant returns:
.. code-block:: python
some_list: Union[list[int], list[str]]
# output3 is of type 'Union[float, str]'
output3 = summarize(some_list)
.. note::
Due to the "pick the first match" rule, changing the order of your
overload variants can change how mypy type checks your program.
To minimize potential issues, we recommend that you:
1. Make sure your overload variants are listed in the same order as
the runtime checks (e.g. :py:func:`isinstance ` checks) in your implementation.
2. Order your variants and runtime checks from most to least specific.
(See the following section for an example).
Type checking the variants
--------------------------
Mypy will perform several checks on your overload variant definitions
to ensure they behave as expected. First, mypy will check and make sure
that no overload variant is shadowing a subsequent one. For example,
consider the following function which adds together two ``Expression``
objects, and contains a special-case to handle receiving two ``Literal``
types:
.. code-block:: python
from typing import overload, Union
class Expression:
# ...snip...
class Literal(Expression):
# ...snip...
# Warning -- the first overload variant shadows the second!
@overload
def add(left: Expression, right: Expression) -> Expression: ...
@overload
def add(left: Literal, right: Literal) -> Literal: ...
def add(left: Expression, right: Expression) -> Expression:
# ...snip...
While this code snippet is technically type-safe, it does contain an
anti-pattern: the second variant will never be selected! If we try calling
``add(Literal(3), Literal(4))``, mypy will always pick the first variant
and evaluate the function call to be of type ``Expression``, not ``Literal``.
This is because ``Literal`` is a subtype of ``Expression``, which means
the "pick the first match" rule will always halt after considering the
first overload.
Because having an overload variant that can never be matched is almost
certainly a mistake, mypy will report an error. To fix the error, we can
either 1) delete the second overload or 2) swap the order of the overloads:
.. code-block:: python
# Everything is ok now -- the variants are correctly ordered
# from most to least specific.
@overload
def add(left: Literal, right: Literal) -> Literal: ...
@overload
def add(left: Expression, right: Expression) -> Expression: ...
def add(left: Expression, right: Expression) -> Expression:
# ...snip...
Mypy will also type check the different variants and flag any overloads
that have inherently unsafely overlapping variants. For example, consider
the following unsafe overload definition:
.. code-block:: python
from typing import overload, Union
@overload
def unsafe_func(x: int) -> int: ...
@overload
def unsafe_func(x: object) -> str: ...
def unsafe_func(x: object) -> Union[int, str]:
if isinstance(x, int):
return 42
else:
return "some string"
On the surface, this function definition appears to be fine. However, it will
result in a discrepancy between the inferred type and the actual runtime type
when we try using it like so:
.. code-block:: python
some_obj: object = 42
unsafe_func(some_obj) + " danger danger" # Type checks, yet crashes at runtime!
Since ``some_obj`` is of type :py:class:`object`, mypy will decide that ``unsafe_func``
must return something of type ``str`` and concludes the above will type check.
But in reality, ``unsafe_func`` will return an int, causing the code to crash
at runtime!
To prevent these kinds of issues, mypy will detect and prohibit inherently unsafely
overlapping overloads on a best-effort basis. Two variants are considered unsafely
overlapping when both of the following are true:
1. All of the arguments of the first variant are compatible with the second.
2. The return type of the first variant is *not* compatible with (e.g. is not a
subtype of) the second.
So in this example, the ``int`` argument in the first variant is a subtype of
the ``object`` argument in the second, yet the ``int`` return type is not a subtype of
``str``. Both conditions are true, so mypy will correctly flag ``unsafe_func`` as
being unsafe.
However, mypy will not detect *all* unsafe uses of overloads. For example,
suppose we modify the above snippet so it calls ``summarize`` instead of
``unsafe_func``:
.. code-block:: python
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
annotations on the overloads. But since ``summarize(...)`` is designed to be biased
towards returning a float when it receives an empty list, this program will actually
crash during runtime.
The reason mypy does not flag definitions like ``summarize`` as being potentially
unsafe is because if it did, it would be extremely difficult to write a safe
overload. For example, suppose we define an overload with two variants that accept
types ``A`` and ``B`` respectively. Even if those two types were completely unrelated,
the user could still potentially trigger a runtime error similar to the ones above by
passing in a value of some third type ``C`` that inherits from both ``A`` and ``B``.
Thankfully, these types of situations are relatively rare. What this does mean,
however, is that you should exercise caution when designing or using an overloaded
function that can potentially receive values that are an instance of two seemingly
unrelated types.
Type checking the implementation
--------------------------------
The body of an implementation is type-checked against the
type hints provided on the implementation. For example, in the
``MyList`` example up above, the code in the body is checked with
argument list ``index: Union[int, slice]`` and a return type of
``Union[T, Sequence[T]]``. If there are no annotations on the
implementation, then the body is not type checked. If you want to
force mypy to check the body anyways, use the :option:`--check-untyped-defs `
flag (:ref:`more details here `).
The variants must also also be compatible with the implementation
type hints. In the ``MyList`` example, mypy will check that the
parameter type ``int`` and the return type ``T`` are compatible with
``Union[int, slice]`` and ``Union[T, Sequence]`` for the
first variant. For the second variant it verifies the parameter
type ``slice`` and the return type ``Sequence[T]`` are compatible
with ``Union[int, slice]`` and ``Union[T, Sequence]``.
.. note::
The overload semantics documented above are new as of mypy 0.620.
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]``.
This restriction was removed in mypy 0.620.
Mypy also previously used to select the best matching variant using a different
algorithm. If this algorithm failed to find a match, it would default to returning
``Any``. The new algorithm uses the "pick the first match" rule and will fall back
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
***************************
Normally, mypy doesn't require annotations for the first arguments of instance and
class methods. However, they may be needed to have more precise static typing
for certain programming patterns.
Restricted methods in generic classes
-------------------------------------
In generic classes some methods may be allowed to be called only
for certain values of type arguments:
.. code-block:: python
T = TypeVar('T')
class Tag(Generic[T]):
item: T
def uppercase_item(self: Tag[str]) -> str:
return self.item.upper()
def label(ti: Tag[int], ts: Tag[str]) -> None:
ti.uppercase_item() # E: Invalid self argument "Tag[int]" to attribute function
# "uppercase_item" with type "Callable[[Tag[str]], str]"
ts.uppercase_item() # This is OK
This pattern also allows matching on nested types in situations where the type
argument is itself generic:
.. code-block:: python
T = TypeVar('T', covariant=True)
S = TypeVar('S')
class Storage(Generic[T]):
def __init__(self, content: T) -> None:
self.content = content
def first_chunk(self: Storage[Sequence[S]]) -> S:
return self.content[0]
page: Storage[list[str]]
page.first_chunk() # OK, type is "str"
Storage(0).first_chunk() # Error: Invalid self argument "Storage[int]" to attribute function
# "first_chunk" with type "Callable[[Storage[Sequence[S]]], S]"
Finally, one can use overloads on self-type to express precise types of
some tricky methods:
.. code-block:: python
T = TypeVar('T')
class Tag(Generic[T]):
@overload
def export(self: Tag[str]) -> str: ...
@overload
def export(self, converter: Callable[[T], str]) -> str: ...
def export(self, converter=None):
if isinstance(self.item, str):
return self.item
return converter(self.item)
In particular, an :py:meth:`~object.__init__` method overloaded on self-type
may be useful to annotate generic class constructors where type arguments
depend on constructor parameters in a non-trivial way, see e.g. :py:class:`~subprocess.Popen`.
Mixin classes
-------------
Using host class protocol as a self-type in mixin methods allows
more code re-usability for static typing of mixin classes. For example,
one can define a protocol that defines common functionality for
host classes instead of adding required abstract methods to every mixin:
.. code-block:: python
class Lockable(Protocol):
@property
def lock(self) -> Lock: ...
class AtomicCloseMixin:
def atomic_close(self: Lockable) -> int:
with self.lock:
# perform actions
class AtomicOpenMixin:
def atomic_open(self: Lockable) -> int:
with self.lock:
# perform actions
class File(AtomicCloseMixin, AtomicOpenMixin):
def __init__(self) -> None:
self.lock = Lock()
class Bad(AtomicCloseMixin):
pass
f = File()
b: Bad
f.atomic_close() # OK
b.atomic_close() # Error: Invalid self type for "atomic_close"
Note that the explicit self-type is *required* to be a protocol whenever it
is not a supertype of the current class. In this case mypy will check the validity
of the self-type only at the call site.
Precise typing of alternative constructors
------------------------------------------
Some classes may define alternative constructors. If these
classes are generic, self-type allows giving them precise signatures:
.. code-block:: python
T = TypeVar('T')
class Base(Generic[T]):
Q = TypeVar('Q', bound='Base[T]')
def __init__(self, item: T) -> None:
self.item = item
@classmethod
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]]"
bad = Sub[int].make_pair('no') # Error: Argument 1 to "make_pair" of "Base"
# has incompatible type "str"; expected "int"
.. _async-and-await:
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`.
Functions defined using ``async def`` are typed just like 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.
.. code-block:: python
import asyncio
async def format_string(tag: str, count: int) -> str:
return 'T-minus {} ({})'.format(count, tag)
async def countdown_1(tag: str, count: int) -> str:
while count > 0:
my_str = await format_string(tag, count) # has type '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()
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
:py:class:`Awaitable[T] `:
.. code-block:: python
my_coroutine = countdown_1("Millennium Falcon", 5)
reveal_type(my_coroutine) # has type 'Coroutine[Any, Any, str]'
.. note::
:ref:`reveal_type() ` displays the inferred static type of
an expression.
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`:
.. code-block:: python
from typing import Optional, AsyncIterator
import asyncio
class arange(AsyncIterator[int]):
def __init__(self, start: int, stop: int, step: int) -> None:
self.start = start
self.stop = stop
self.step = step
self.count = start - step
def __aiter__(self) -> AsyncIterator[int]:
return self
async def __anext__(self) -> int:
self.count += self.step
if self.count == self.stop:
raise StopAsyncIteration
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))
await asyncio.sleep(0.1)
return "Blastoff!"
loop = asyncio.get_event_loop()
loop.run_until_complete(countdown_4("Serenity", 5))
loop.close()
If you use coroutines in legacy code that was originally written for
Python 3.4, which did not support the ``async def`` syntax, you would
instead use the :py:func:`@asyncio.coroutine `
decorator to convert a generator into a coroutine, and use a
generator type as the return type:
.. code-block:: python
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()
.. _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:`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:`dict`.
Now mypy will recognize these as valid:
.. code-block:: python
name = movie['name'] # Okay; type of name is str
year = movie['year'] # Okay; type of year is int
Mypy will detect an invalid key as an error:
.. code-block:: python
director = movie['director'] # Error: 'director' is not a valid key
Mypy will also reject a runtime-computed expression as a key, as
it can't verify that it's a valid key. You can only use string
literals as ``TypedDict`` keys.
The ``TypedDict`` type object can also act as a constructor. It
returns a normal :py:class:`dict` object at runtime -- a ``TypedDict`` does
not define a new runtime type:
.. code-block:: python
toy_story = Movie(name='Toy Story', year=1995)
This is equivalent to just constructing a dictionary directly using
``{ ... }`` or ``dict(key=value, ...)``. The constructor form is
sometimes convenient, since it can be used without a type annotation,
and it also makes the type of the object explicit.
Like all types, ``TypedDict``\s can be used as components to build
arbitrarily complex types. For example, you can define nested
``TypedDict``\s and containers with ``TypedDict`` items.
Unlike most other types, mypy uses structural compatibility checking
(or structural subtyping) with ``TypedDict``\s. A ``TypedDict`` object with
extra items is 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:`dict` allows arbitrary keys to be
added and removed, unlike ``TypedDict``. However, any ``TypedDict`` object is
a subtype of (that is, compatible with) ``Mapping[str, object]``, since
:py:class:`~typing.Mapping` only provides read-only access to the dictionary items:
.. code-block:: python
def print_typed_dict(obj: Mapping[str, object]) -> None:
for key, value in obj.items():
print('{}: {}'.format(key, value))
print_typed_dict(Movie(name='Toy Story', year=1995)) # OK
.. note::
Unless you are on Python 3.8 or newer (where ``TypedDict`` is available in
standard library :py:mod:`typing` module) you need to install ``typing_extensions``
using pip to use ``TypedDict``:
.. code-block:: text
python3 -m pip install --upgrade typing-extensions
Or, if you are using Python 2:
.. code-block:: text
pip install --upgrade typing-extensions
Totality
--------
By default mypy ensures that a ``TypedDict`` object has all the specified
keys. This will be flagged as an error:
.. code-block:: python
# Error: 'year' missing
toy_story = {'name': 'Toy Story'} # type: Movie
Sometimes you want to allow keys to be left out when creating a
``TypedDict`` object. You can provide the ``total=False`` argument to
``TypedDict(...)`` to achieve this:
.. code-block:: python
GuiOptions = TypedDict(
'GuiOptions', {'language': str, 'color': str}, total=False)
options = {} # type: GuiOptions # Okay
options['language'] = 'en'
You may need to use :py:meth:`~dict.get` to access items of a partial (non-total)
``TypedDict``, since indexing using ``[]`` could fail at runtime.
However, mypy still lets use ``[]`` with a partial ``TypedDict`` -- you
just need to be careful with it, as it could result in a :py:exc:`KeyError`.
Requiring :py:meth:`~dict.get` everywhere would be too cumbersome. (Note that you
are free to use :py:meth:`~dict.get` with total ``TypedDict``\s as well.)
Keys that aren't required are shown with a ``?`` in error messages:
.. code-block:: python
# Revealed type is "TypedDict('GuiOptions', {'language'?: builtins.str,
# 'color'?: builtins.str})"
reveal_type(options)
Totality also affects structural compatibility. You can't use a partial
``TypedDict`` when a total one is expected. Also, a total ``TypedDict`` is not
valid when a partial one is expected.
Supported operations
--------------------
``TypedDict`` objects support a subset of dictionary operations and methods.
You must use string literals as keys when calling most of the methods,
as otherwise mypy won't be able to check that the key is valid. List
of supported operations:
* Anything included in :py:class:`~typing.Mapping`:
* ``d[key]``
* ``key in d``
* ``len(d)``
* ``for key in d`` (iteration)
* :py:meth:`d.get(key[, default]) `
* :py:meth:`d.keys() `
* :py:meth:`d.values() `
* :py:meth:`d.items() `
* :py:meth:`d.copy() `
* :py:meth:`d.setdefault(key, default) `
* :py:meth:`d1.update(d2) `
* :py:meth:`d.pop(key[, default]) ` (partial ``TypedDict``\s only)
* ``del d[key]`` (partial ``TypedDict``\s only)
In Python 2 code, these methods are also supported:
* ``has_key(key)``
* ``viewitems()``
* ``viewkeys()``
* ``viewvalues()``
.. note::
:py:meth:`~dict.clear` and :py:meth:`~dict.popitem` are not supported since they are unsafe
-- they could delete required ``TypedDict`` items that are not visible to
mypy because of structural subtyping.
Class-based syntax
------------------
An alternative, class-based syntax to define a ``TypedDict`` is supported
in Python 3.6 and later:
.. code-block:: python
from typing_extensions import TypedDict
class Movie(TypedDict):
name: str
year: int
The above definition is equivalent to the original ``Movie``
definition. It doesn't actually define a real class. This syntax also
supports a form of inheritance -- subclasses can define additional
items. However, this is primarily a notational shortcut. Since mypy
uses structural compatibility with ``TypedDict``\s, inheritance is not
required for compatibility. Here is an example of inheritance:
.. code-block:: python
class Movie(TypedDict):
name: str
year: int
class BookBasedMovie(Movie):
based_on: str
Now ``BookBasedMovie`` has keys ``name``, ``year`` and ``based_on``.
Mixing required and non-required items
--------------------------------------
In addition to allowing reuse across ``TypedDict`` types, inheritance also allows
you to mix required and non-required (using ``total=False``) items
in a single ``TypedDict``. Example:
.. code-block:: python
class MovieBase(TypedDict):
name: str
year: int
class Movie(MovieBase, total=False):
based_on: str
Now ``Movie`` has required keys ``name`` and ``year``, while ``based_on``
can be left out when constructing an object. A ``TypedDict`` with a mix of required
and non-required keys, such as ``Movie`` above, will only be compatible with
another ``TypedDict`` if all required keys in the other ``TypedDict`` are required keys in the
first ``TypedDict``, and all non-required keys of the other ``TypedDict`` are also non-required keys
in the first ``TypedDict``.
Unions of TypedDicts
--------------------
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.
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
:ref:`Literal type `. Then, check that key to distinguish
between your TypedDicts.
mypy-0.942/docs/source/mypy_daemon.rst 0000644 0001751 0000171 00000023145 14217067311 020637 0 ustar runner docker 0000000 0000000 .. _mypy_daemon:
.. program:: dmypy
Mypy daemon (mypy server)
=========================
Instead of running mypy as a command-line tool, you can also run it as
a long-running daemon (server) process and use a command-line client to
send type-checking requests to the server. This way mypy can perform type
checking much faster, since program state cached from previous runs is kept
in memory and doesn't have to be read from the file system on each run.
The server also uses finer-grained dependency tracking to reduce the amount
of work that needs to be done.
If you have a large codebase to check, running mypy using the mypy
daemon can be *10 or more times faster* than the regular command-line
``mypy`` tool, especially if your workflow involves running mypy
repeatedly after small edits -- which is often a good idea, as this way
you'll find errors sooner.
.. note::
The command-line interface of mypy daemon may change in future mypy
releases.
.. note::
Each mypy daemon process supports one user and one set of source files,
and it can only process one type checking request at a time. You can
run multiple mypy daemon processes to type check multiple repositories.
Basic usage
***********
The client utility ``dmypy`` is used to control the mypy daemon.
Use ``dmypy run -- `` to type check a set of files
(or directories). This will launch the daemon if it is not running.
You can use almost arbitrary mypy flags after ``--``. The daemon
will always run on the current host. Example::
dmypy run -- prog.py pkg/*.py
``dmypy run`` will automatically restart the daemon if the
configuration or mypy version changes.
The initial run will process all the code and may take a while to
finish, but subsequent runs will be quick, especially if you've only
changed a few files. (You can use :ref:`remote caching `
to speed up the initial run. The speedup can be significant if
you have a large codebase.)
.. note::
Mypy 0.780 added support for following imports in dmypy (enabled by
default). This functionality is still experimental. You can use
``--follow-imports=skip`` or ``--follow-imports=error`` to fall
back to the stable functionality. See :ref:`follow-imports` for
details on how these work.
Daemon client commands
**********************
While ``dmypy run`` is sufficient for most uses, some workflows
(ones using :ref:`remote caching `, perhaps),
require more precise control over the lifetime of the daemon process:
* ``dmypy stop`` stops the daemon.
* ``dmypy start -- `` starts the daemon but does not check any files.
You can use almost arbitrary mypy flags after ``--``.
* ``dmypy restart -- `` restarts the daemon. The flags are the same
as with ``dmypy start``. This is equivalent to a stop command followed
by a start.
* Use ``dmypy run --timeout SECONDS -- `` (or
``start`` or ``restart``) to automatically
shut down the daemon after inactivity. By default, the daemon runs
until it's explicitly stopped.
* ``dmypy check `` checks a set of files using an already
running daemon.
* ``dmypy recheck`` checks the same set of files as the most recent
``check`` or ``recheck`` command. (You can also use the :option:`--update`
and :option:`--remove` options to alter the set of files, and to define
which files should be processed.)
* ``dmypy status`` checks whether a daemon is running. It prints a
diagnostic and exits with ``0`` if there is a running daemon.
Use ``dmypy --help`` for help on additional commands and command-line
options not discussed here, and ``dmypy --help`` for help on
command-specific options.
Additional daemon flags
***********************
.. option:: --status-file FILE
Use ``FILE`` as the status file for storing daemon runtime state. This is
normally a JSON file that contains information about daemon process and
connection. The default path is ``.dmypy.json`` in the current working
directory.
.. option:: --log-file FILE
Direct daemon stdout/stderr to ``FILE``. This is useful for debugging daemon
crashes, since the server traceback is not always printed by the client.
This is available for the ``start``, ``restart``, and ``run`` commands.
.. option:: --timeout TIMEOUT
Automatically shut down server after ``TIMEOUT`` seconds of inactivity.
This is available for the ``start``, ``restart``, and ``run`` commands.
.. option:: --update FILE
Re-check ``FILE``, or add it to the set of files being
checked (and check it). This option may be repeated, and it's only available for
the ``recheck`` command. By default, mypy finds and checks all files changed
since the previous run and files that depend on them. However, if you use this option
(and/or :option:`--remove`), mypy assumes that only the explicitly
specified files have changed. This is only useful to
speed up mypy if you type check a very large number of files, and use an
external, fast file system watcher, such as `watchman`_ or
`watchdog`_, to determine which files got edited or deleted.
*Note:* This option is never required and is only available for
performance tuning.
.. option:: --remove FILE
Remove ``FILE`` from the set of files being checked. This option may be
repeated. This is only available for the
``recheck`` command. See :option:`--update` above for when this may be useful.
*Note:* This option is never required and is only available for performance
tuning.
.. option:: --fswatcher-dump-file FILE
Collect information about the current internal file state. This is
only available for the ``status`` command. This will dump JSON to
``FILE`` in the format ``{path: [modification_time, size,
content_hash]}``. This is useful for debugging the built-in file
system watcher. *Note:* This is an internal flag and the format may
change.
.. option:: --perf-stats-file FILE
Write performance profiling information to ``FILE``. This is only available
for the ``check``, ``recheck``, and ``run`` commands.
Static inference of annotations
*******************************
The mypy daemon supports (as an experimental feature) statically inferring
draft function and method type annotations. Use ``dmypy suggest FUNCTION`` to
generate a draft signature in the format
``(param_type_1, param_type_2, ...) -> ret_type`` (types are included for all
arguments, including keyword-only arguments, ``*args`` and ``**kwargs``).
This is a low-level feature intended to be used by editor integrations,
IDEs, and other tools (for example, the `mypy plugin for PyCharm`_),
to automatically add annotations to source files, or to propose function
signatures.
In this example, the function ``format_id()`` has no annotation:
.. code-block:: python
def format_id(user):
return "User: {}".format(user)
root = format_id(0)
``dmypy suggest`` uses call sites, return statements, and other heuristics (such as
looking for signatures in base classes) to infer that ``format_id()`` accepts
an ``int`` argument and returns a ``str``. Use ``dmypy suggest module.format_id`` to
print the suggested signature for the function.
More generally, the target function may be specified in two ways:
* By its fully qualified name, i.e. ``[package.]module.[class.]function``.
* By its location in a source file, i.e. ``/path/to/file.py:line``. The path can be
absolute or relative, and ``line`` can refer to any line number within
the function body.
This command can also be used to find a more precise alternative for an existing,
imprecise annotation with some ``Any`` types.
The following flags customize various aspects of the ``dmypy suggest``
command.
.. option:: --json
Output the signature as JSON, so that `PyAnnotate`_ can read it and add
the signature to the source file. Here is what the JSON looks like:
.. code-block:: python
[{"func_name": "example.format_id",
"line": 1,
"path": "/absolute/path/to/example.py",
"samples": 0,
"signature": {"arg_types": ["int"], "return_type": "str"}}]
.. option:: --no-errors
Only produce suggestions that cause no errors in the checked code. By default,
mypy will try to find the most precise type, even if it causes some type errors.
.. option:: --no-any
Only produce suggestions that don't contain ``Any`` types. By default mypy
proposes the most precise signature found, even if it contains ``Any`` types.
.. option:: --flex-any FRACTION
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.
This will produce a list with line numbers and types of actual
arguments for each call: ``/path/to/file.py:line: (arg_type_1, arg_type_2, ...)``.
.. option:: --use-fixme NAME
Use a dummy name instead of plain ``Any`` for types that cannot
be inferred. This may be useful to emphasize to a user that a given type
couldn't be inferred and needs to be entered manually.
.. option:: --max-guesses NUMBER
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.
.. _watchman: https://facebook.github.io/watchman/
.. _watchdog: https://pypi.org/project/watchdog/
.. _PyAnnotate: https://github.com/dropbox/pyannotate
.. _mypy plugin for PyCharm: https://github.com/dropbox/mypy-PyCharm-plugin
mypy-0.942/docs/source/protocols.rst 0000644 0001751 0000171 00000032474 14217067311 020347 0 ustar runner docker 0000000 0000000 .. _protocol-types:
Protocols and structural subtyping
==================================
Mypy supports two ways of deciding whether two classes are compatible
as types: nominal subtyping and structural subtyping. *Nominal*
subtyping is strictly based on the class hierarchy. If class ``D``
inherits class ``C``, it's also a subtype of ``C``, and instances of
``D`` can be used when ``C`` instances are expected. This form of
subtyping is used by default in mypy, since it's easy to understand
and produces clear and concise error messages, and since it matches
how the native :py:func:`isinstance ` check works -- based on class
hierarchy. *Structural* subtyping can also be useful. Class ``D`` is
a structural subtype of class ``C`` if the former has all attributes
and methods of the latter, and with compatible types.
Structural subtyping can be seen as a static equivalent of duck
typing, which is well known to Python programmers. Mypy provides
support for structural subtyping via protocol classes described
below. See :pep:`544` for the detailed specification of protocols
and structural subtyping in Python.
.. _predefined_protocols:
Predefined protocols
********************
The :py:mod:`typing` module defines various protocol classes that correspond
to common Python protocols, such as :py:class:`Iterable[T] `. If a class
defines a suitable :py:meth:`__iter__ ` method, mypy understands that it
implements the iterable protocol and is compatible with :py:class:`Iterable[T] `.
For example, ``IntList`` below is iterable, over ``int`` values:
.. code-block:: python
from typing import Iterator, Iterable, Optional
class IntList:
def __init__(self, value: int, next: Optional['IntList']) -> None:
self.value = value
self.next = next
def __iter__(self) -> Iterator[int]:
current = self
while current:
yield current.value
current = current.next
def print_numbered(items: Iterable[int]) -> None:
for n, x in enumerate(items):
print(n + 1, x)
x = IntList(3, IntList(5, None))
print_numbered(x) # OK
print_numbered([4, 5]) # Also OK
The subsections below introduce all built-in protocols defined in
:py:mod:`typing` and the signatures of the corresponding methods you need to define
to implement each protocol (the signatures can be left out, as always, but mypy
won't type check unannotated methods).
Iteration protocols
...................
The iteration protocols are useful in many contexts. For example, they allow
iteration of objects in for loops.
Iterable[T]
-----------
The :ref:`example above ` has a simple implementation of an
:py:meth:`__iter__