From 4a48003c423ee75bdd64a31b52950d21bd411128 Mon Sep 17 00:00:00 2001 From: Marcus Kammer Date: Thu, 7 Apr 2022 13:56:21 +0200 Subject: [PATCH] Update info dir --- info/Mypy.info | 18112 +++++++++++++++++++++++++++++++++++++++++++++++ info/dir | 1 + 2 files changed, 18113 insertions(+) create mode 100644 info/Mypy.info diff --git a/info/Mypy.info b/info/Mypy.info new file mode 100644 index 00000000..7b79edf5 --- /dev/null +++ b/info/Mypy.info @@ -0,0 +1,18112 @@ +This is Mypy.info, produced by makeinfo version 6.7 from Mypy.texi. + + Mypy 0.942, Apr 07, 2022 + + Jukka + + Copyright © 2016, Jukka Lehtosalo + +INFO-DIR-SECTION Miscellaneous +START-INFO-DIR-ENTRY +* Mypy: (Mypy.info). One line description of project. +END-INFO-DIR-ENTRY + + + Generated by Sphinx 4.5.0. + + +File: Mypy.info, Node: Top, Next: Introduction, Up: (dir) + +Mypy Documentation +****************** + + Mypy 0.942, Apr 07, 2022 + + Jukka + + Copyright © 2016, Jukka Lehtosalo + +Mypy is a static type checker for Python 3 and Python 2.7. + +* Menu: + +* Introduction:: +* Getting started:: +* Using mypy with an existing codebase:: +* Type hints cheat sheet (Python 3): Type hints cheat sheet Python 3. +* Type hints cheat sheet (Python 2): Type hints cheat sheet Python 2. +* Built-in types: Built-in types<3>. +* Type inference and type annotations:: +* Kinds of types:: +* Class basics:: +* Annotation issues at runtime:: +* Protocols and structural subtyping:: +* Dynamically typed code:: +* Type checking Python 2 code:: +* Type narrowing:: +* Duck type compatibility:: +* Stub files:: +* Generics:: +* More types:: +* Literal types and Enums:: +* Final names, methods and classes: Final names methods and classes. +* Metaclasses:: +* Running mypy and managing imports:: +* The mypy command line:: +* The mypy configuration file:: +* Inline configuration:: +* Mypy daemon (mypy server): Mypy daemon mypy server. +* Using installed packages:: +* Extending and integrating mypy:: +* Automatic stub generation (stubgen): Automatic stub generation stubgen. +* Automatic stub testing (stubtest): Automatic stub testing stubtest. +* Common issues and solutions:: +* Supported Python features:: +* Error codes:: +* Error codes enabled by default:: +* Error codes for optional checks:: +* Additional features:: +* Frequently Asked Questions:: +* Indices and tables:: +* Index:: + + +File: Mypy.info, Node: Introduction, Next: Getting started, Prev: Top, Up: Top + +1 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(1) and PEP 526(2) +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. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + (2) https://peps.python.org/pep-0526/ + + +File: Mypy.info, Node: Getting started, Next: Using mypy with an existing codebase, Prev: Introduction, Up: Top + +2 Getting started +***************** + +This chapter introduces some core concepts of mypy, including function +annotations, the typing(1) module, library stubs, and more. + +Be sure to read this chapter carefully, as the rest of the documentation +may not make much sense otherwise. + +* Menu: + +* Installing and running mypy:: +* Function signatures and dynamic vs static typing:: +* More function signatures:: +* Additional types, and the typing module: Additional types and the typing module. +* Local type inference:: +* Library stubs and typeshed:: +* Configuring mypy:: +* Next steps:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Installing and running mypy, Next: Function signatures and dynamic vs static typing, Up: Getting started + +2.1 Installing and running mypy +=============================== + +Mypy requires Python 3.6 or later to run. Once you’ve installed Python +3(1), install mypy using pip: + + $ python3 -m pip install mypy + +Once mypy is installed, run it by using the ‘mypy’ tool: + + $ 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 + *note –py2: 8. flag. See *note Type checking Python 2 code: 9. for + more details. + + $ mypy --py2 program.py + + ---------- Footnotes ---------- + + (1) https://www.python.org/downloads/ + + +File: Mypy.info, Node: Function signatures and dynamic vs static typing, Next: More function signatures, Prev: Installing and running mypy, Up: Getting started + +2.2 Function signatures and dynamic vs static typing +==================================================== + +A function without type annotations is considered to be `dynamically +typed' by mypy: + + 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: + + 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: + + 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 as a part of Python +3.0(1). + +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 *note typing Python 2 code: 9. 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 +*note –disallow-untyped-defs: b. flag. See *note The mypy command line: +c. 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. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-3107/ + + +File: Mypy.info, Node: More function signatures, Next: Additional types and the typing module, Prev: Function signatures and dynamic vs static typing, Up: Getting started + +2.3 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: + + 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: + + 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: + + 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: + + 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) + + +File: Mypy.info, Node: Additional types and the typing module, Next: Local type inference, Prev: More function signatures, Up: Getting started + +2.4 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): + + 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 list(1) type is an example of something called a `generic type': it +can accept one or more `type parameters'. In this case, we +`parameterized' list(2) 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 List(3) type from +the typing(4) module: + + 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 typing(5) +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 collections.abc.Iterable(6) (or +typing.Iterable(7) in Python 3.8 and earlier) type instead of list(8) : + + 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 Union(9) type: + + 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 Union(10) 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: + + 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 typing(11) module contains many other useful types. You can find a +quick overview by looking through the *note mypy cheatsheets: f. and a +more detailed overview (including information on how to make your own +generic types or your own type aliases) by looking through the *note +type system reference: 10. + + 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 typing(12) or + collections.abc(13) in code examples, but mypy will give an error + if you use types such as Iterable(14) 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#list + + (2) https://docs.python.org/3/library/stdtypes.html#list + + (3) https://docs.python.org/3/library/typing.html#typing.List + + (4) https://docs.python.org/3/library/typing.html#module-typing + + (5) https://docs.python.org/3/library/typing.html#module-typing + + (6) +https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable + + (7) https://docs.python.org/3/library/typing.html#typing.Iterable + + (8) https://docs.python.org/3/library/stdtypes.html#list + + (9) https://docs.python.org/3/library/typing.html#typing.Union + + (10) https://docs.python.org/3/library/typing.html#typing.Union + + (11) https://docs.python.org/3/library/typing.html#module-typing + + (12) https://docs.python.org/3/library/typing.html#module-typing + + (13) +https://docs.python.org/3/library/collections.abc.html#module-collections.abc + + (14) https://docs.python.org/3/library/typing.html#typing.Iterable + + +File: Mypy.info, Node: Local type inference, Next: Library stubs and typeshed, Prev: Additional types and the typing module, Up: Getting started + +2.5 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 isinstance(1) 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’: + + 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: + + 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(2)) or using a +comment-based syntax like so: + + # 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] + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://peps.python.org/pep-0526/ + + +File: Mypy.info, Node: Library stubs and typeshed, Next: Configuring mypy, Prev: Local type inference, Up: Getting started + +2.6 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(1) project, which contains library +stubs for the Python builtins, the standard library, and selected +third-party packages. + +For example, consider this code: + + x = chr(4) + +Without a library stub, mypy would have no way of inferring the type of +‘x’ and checking that the argument to chr()(2) 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 *note Missing imports: 14. and *note +Using installed packages: 15. for the details). For example, you can +install the stubs for the ‘requests’ package like this: + + 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: + + 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 *note create stubs: 16. easily. We discuss ways of +silencing complaints about missing stubs in *note Missing imports: 17. + + ---------- Footnotes ---------- + + (1) https://github.com/python/typeshed + + (2) https://docs.python.org/3/library/functions.html#chr + + +File: Mypy.info, Node: Configuring mypy, Next: Next steps, Prev: Library stubs and typeshed, Up: Getting started + +2.7 Configuring mypy +==================== + +Mypy supports many command line options that you can use to tweak how +mypy behaves: see *note The mypy command line: c. 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 *note –disallow-untyped-defs: b. flag. + +Another potentially useful flag is *note –strict: 19, which enables many +(though not all) of the available strictness options – including *note +–disallow-untyped-defs: b. + +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 *note Using mypy with an +existing codebase: 1a. for more suggestions on how to handle the latter +case. + + +File: Mypy.info, Node: Next steps, Prev: Configuring mypy, Up: Getting started + +2.8 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 *note mypy cheatsheet: 1c. (also for *note Python 2: 1d.). + + * Read *note Using mypy with an existing codebase: 1a. if you have a + significant existing codebase without many type annotations. + + * Read the blog post(1) 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(2) (PyCon + 2018) + + * Greg Price: Clearer Code at Scale: Static Types at Zulip and + Dropbox(3) (PyCon 2018) + + * Look at *note solutions to common issues: 1e. with mypy if you + encounter problems. + + * You can ask questions about mypy in the mypy issue tracker(4) and + typing Gitter chat(5). + +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. + + ---------- Footnotes ---------- + + (1) https://blog.zulip.org/2016/10/13/static-types-in-python-oh-mypy/ + + (2) https://www.youtube.com/watch?v=pMgmKJyWKn8 + + (3) https://www.youtube.com/watch?v=0c46YHS3RY8 + + (4) https://github.com/python/mypy/issues + + (5) https://gitter.im/python/typing + + +File: Mypy.info, Node: Using mypy with an existing codebase, Next: Type hints cheat sheet Python 3, Prev: Getting started, Up: Top + +3 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 MonkeyType(1) or PyAnnotate(2) to automatically annotate legacy + code + +We discuss all of these points in some detail below, and a few optional +follow-up steps. + +* Menu: + +* Start small:: +* Mypy runner script:: +* Continuous Integration:: +* Annotate widely imported modules:: +* Write annotations as you go:: +* Automate annotation of legacy code:: +* Speed up mypy runs:: +* Introduce stricter options:: + + ---------- Footnotes ---------- + + (1) https://monkeytype.readthedocs.io/en/latest/index.html + + (2) https://github.com/dropbox/pyannotate + + +File: Mypy.info, Node: Start small, Next: Mypy runner script, Up: Using mypy with an existing codebase + +3.1 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: + + 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’: + + 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: + + [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: + + 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 *note here: 22. + +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. + + +File: Mypy.info, Node: Mypy runner script, Next: Continuous Integration, Prev: Start small, Up: Using mypy with an existing codebase + +3.2 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. + + +File: Mypy.info, Node: Continuous Integration, Next: Annotate widely imported modules, Prev: Mypy runner script, Up: Using mypy with an existing codebase + +3.3 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: + + python3 -m pip install mypy==0.790 # Pinned version avoids surprises + scripts/mypy # Run the mypy runner script you set up + + +File: Mypy.info, Node: Annotate widely imported modules, Next: Write annotations as you go, Prev: Continuous Integration, Up: Using mypy with an existing codebase + +3.4 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. + + +File: Mypy.info, Node: Write annotations as you go, Next: Automate annotation of legacy code, Prev: Annotate widely imported modules, Up: Using mypy with an existing codebase + +3.5 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. + + +File: Mypy.info, Node: Automate annotation of legacy code, Next: Speed up mypy runs, Prev: Write annotations as you go, Up: Using mypy with an existing codebase + +3.6 Automate annotation of legacy code +====================================== + +There are tools for automatically adding draft annotations based on type +profiles collected at runtime. Tools include MonkeyType(1) (Python 3) +and PyAnnotate(2). + +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. + + ---------- Footnotes ---------- + + (1) https://monkeytype.readthedocs.io/en/latest/index.html + + (2) https://github.com/dropbox/pyannotate + + +File: Mypy.info, Node: Speed up mypy runs, Next: Introduce stricter options, Prev: Automate annotation of legacy code, Up: Using mypy with an existing codebase + +3.7 Speed up mypy runs +====================== + +You can use *note mypy daemon: 29. 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 *note remote caching: 2a. for further speedups. + + +File: Mypy.info, Node: Introduce stricter options, Prev: Speed up mypy runs, Up: Using mypy with an existing codebase + +3.8 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 *note disallow_untyped_defs: 2c, +or type check code without annotations as well with *note +check_untyped_defs: 2d. Refer to *note The mypy configuration file: 2e. +for the details. + + +File: Mypy.info, Node: Type hints cheat sheet Python 3, Next: Type hints cheat sheet Python 2, Prev: Using mypy with an existing codebase, Up: Top + +4 Type hints cheat sheet (Python 3) +*********************************** + +This document is a quick cheat sheet showing how the PEP 484(1) 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. + +* Menu: + +* Variables:: +* Built-in types:: +* Functions:: +* When you’re puzzled or when things are complicated:: +* Standard “duck types”:: +* Classes:: +* Coroutines and asyncio:: +* Miscellaneous:: +* Decorators:: + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + +File: Mypy.info, Node: Variables, Next: Built-in types, Up: Type hints cheat sheet Python 3 + +4.1 Variables +============= + +Python 3.6 introduced a syntax for annotating variables in PEP 526(1) +and we use it in most examples. + + # 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 + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0526/ + + +File: Mypy.info, Node: Built-in types, Next: Functions, Prev: Variables, Up: Type hints cheat sheet Python 3 + +4.2 Built-in types +================== + + 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()) + + +File: Mypy.info, Node: Functions, Next: When you’re puzzled or when things are complicated, Prev: Built-in types, Up: Type hints cheat sheet Python 3 + +4.3 Functions +============= + +Python 3 supports an annotation syntax for function declarations. + + 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 + + +File: Mypy.info, Node: When you’re puzzled or when things are complicated, Next: Standard “duck types”, Prev: Functions, Up: Type hints cheat sheet Python 3 + +4.4 When you’re puzzled or when things are complicated +====================================================== + + 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 + + +File: Mypy.info, Node: Standard “duck types”, Next: Classes, Prev: When you’re puzzled or when things are complicated, Up: Type hints cheat sheet Python 3 + +4.5 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. + + 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 *note Protocols and +structural subtyping: 37. + + +File: Mypy.info, Node: Classes, Next: Coroutines and asyncio, Prev: Standard “duck types”, Up: Type hints cheat sheet Python 3 + +4.6 Classes +=========== + + 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] = [] + + +File: Mypy.info, Node: Coroutines and asyncio, Next: Miscellaneous, Prev: Classes, Up: Type hints cheat sheet Python 3 + +4.7 Coroutines and asyncio +========================== + +See *note Typing async/await: 3a. for the full detail on typing +coroutines and asynchronous code. + + 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!" + + +File: Mypy.info, Node: Miscellaneous, Next: Decorators, Prev: Coroutines and asyncio, Up: Type hints cheat sheet Python 3 + +4.8 Miscellaneous +================= + + 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 + ... + + +File: Mypy.info, Node: Decorators, Prev: Miscellaneous, Up: Type hints cheat sheet Python 3 + +4.9 Decorators +============== + +Decorator functions can be expressed via generics. See *note Declaring +decorators: 3d. for more details. + + 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]: + ... + + +File: Mypy.info, Node: Type hints cheat sheet Python 2, Next: Built-in types<3>, Prev: Type hints cheat sheet Python 3, Up: Top + +5 Type hints cheat sheet (Python 2) +*********************************** + +This document is a quick cheat sheet showing how the PEP 484(1) 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]'’. + +* Menu: + +* Built-in types: Built-in types<2>. +* Functions: Functions<2>. +* When you’re puzzled or when things are complicated: When you’re puzzled or when things are complicated<2>. +* Standard “duck types”: Standard “duck types”<2>. +* Classes: Classes<2>. +* Miscellaneous: Miscellaneous<2>. +* Decorators: Decorators<2>. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + +File: Mypy.info, Node: Built-in types<2>, Next: Functions<2>, Up: Type hints cheat sheet Python 2 + +5.1 Built-in types +================== + + 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() + + +File: Mypy.info, Node: Functions<2>, Next: When you’re puzzled or when things are complicated<2>, Prev: Built-in types<2>, Up: Type hints cheat sheet Python 2 + +5.2 Functions +============= + + 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 + ... + + +File: Mypy.info, Node: When you’re puzzled or when things are complicated<2>, Next: Standard “duck types”<2>, Prev: Functions<2>, Up: Type hints cheat sheet Python 2 + +5.3 When you’re puzzled or when things are complicated +====================================================== + + 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 + + +File: Mypy.info, Node: Standard “duck types”<2>, Next: Classes<2>, Prev: When you’re puzzled or when things are complicated<2>, Up: Type hints cheat sheet Python 2 + +5.4 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. + + 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'}) + + +File: Mypy.info, Node: Classes<2>, Next: Miscellaneous<2>, Prev: Standard “duck types”<2>, Up: Type hints cheat sheet Python 2 + +5.5 Classes +=========== + + 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 + + +File: Mypy.info, Node: Miscellaneous<2>, Next: Decorators<2>, Prev: Classes<2>, Up: Type hints cheat sheet Python 2 + +5.6 Miscellaneous +================= + + 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 + + +File: Mypy.info, Node: Decorators<2>, Prev: Miscellaneous<2>, Up: Type hints cheat sheet Python 2 + +5.7 Decorators +============== + +Decorator functions can be expressed via generics. See *note Declaring +decorators: 3d. for the more details. + + 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] + ... + + +File: Mypy.info, Node: Built-in types<3>, Next: Type inference and type annotations, Prev: Type hints cheat sheet Python 2, Up: Top + +6 Built-in types +**************** + +This chapter introduces some commonly used built-in types. We will +cover many other kinds of types later. + +* Menu: + +* Simple types:: +* Any type:: +* Generic types:: + + +File: Mypy.info, Node: Simple types, Next: Any type, Up: Built-in types<3> + +6.1 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. + + +File: Mypy.info, Node: Any type, Next: Generic types, Prev: Simple types, Up: Built-in types<3> + +6.2 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 typing(1) module. See *note +Dynamically typed code: 4b. for more details. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Generic types, Prev: Any type, Up: Built-in types<3> + +6.3 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 collections.abc(1) instead of importing from +typing(2) in Python 3.9. + +See *note Using generic builtins: 4d. for more details, including how +you can use these in annotations also in Python 3.7 and 3.8. + +These legacy types defined in typing(3) 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 collections.abc(4) (formerly +‘collections’), they are not identical, since the latter don’t support +indexing prior to Python 3.9. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/collections.abc.html#module-collections.abc + + (2) https://docs.python.org/3/library/typing.html#module-typing + + (3) https://docs.python.org/3/library/typing.html#module-typing + + (4) +https://docs.python.org/3/library/collections.abc.html#module-collections.abc + + +File: Mypy.info, Node: Type inference and type annotations, Next: Kinds of types, Prev: Built-in types<3>, Up: Top + +7 Type inference and type annotations +************************************* + +* Menu: + +* Type inference:: +* Explicit types for variables:: +* Explicit types for collections:: +* Compatibility of container types:: +* Context in type inference:: +* Declaring multiple variable types at a time:: +* Starred expressions:: +* Silencing type errors:: + + +File: Mypy.info, Node: Type inference, Next: Explicit types for variables, Up: Type inference and type annotations + +7.1 Type inference +================== + +Mypy considers the initial assignment as the definition of a variable. +If you do not explicitly specify the type of the variable, mypy infers +the type based on the static type of the value expression: + + i = 1 # Infer type "int" for i + l = [1, 2] # Infer type "list[int]" for l + +Type inference is not used in dynamically typed functions (those without +a function type annotation) — every local variable type defaults to +‘Any’ in such functions. ‘Any’ is discussed later in more detail. + + +File: Mypy.info, Node: Explicit types for variables, Next: Explicit types for collections, Prev: Type inference, Up: Type inference and type annotations + +7.2 Explicit types for variables +================================ + +You can override the inferred type of a variable by using a variable +type annotation: + + from typing import Union + + x: Union[int, str] = 1 + +Without the type annotation, the type of ‘x’ would be just ‘int’. We +use an annotation to give it a more general type ‘Union[int, str]’ (this +type means that the value can be either an ‘int’ or a ‘str’). Mypy +checks that the type of the initializer is compatible with the declared +type. The following example is not valid, since the initializer is a +floating point number, and this is incompatible with the declared type: + + x: Union[int, str] = 1.1 # Error! + +The variable annotation syntax is available starting from Python 3.6. +In earlier Python versions, you can use a special comment after an +assignment statement to declare the type of a variable: + + x = 1 # type: Union[int, str] + +We’ll use both syntax variants in examples. The syntax variants are +mostly interchangeable, but the variable annotation syntax allows +defining the type of a variable without initialization, which is not +possible with the comment syntax: + + x: str # Declare type of 'x' without initialization + + Note: The best way to think about this is that the type annotation + sets the type of the variable, not the type of the expression. To + force the type of an expression you can use cast(, + )(1). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.cast + + +File: Mypy.info, Node: Explicit types for collections, Next: Compatibility of container types, Prev: Explicit types for variables, Up: Type inference and type annotations + +7.3 Explicit types for collections +================================== + +The type checker cannot always infer the type of a list or a dictionary. +This often arises when creating an empty list or dictionary and +assigning it to a new variable that doesn’t have an explicit variable +type. Here is an example where mypy can’t infer the type without some +help: + + l = [] # Error: Need type annotation for "l" + +In these cases you can give the type explicitly using a type annotation: + + l: list[int] = [] # Create empty list with type list[int] + d: dict[str, int] = {} # Create empty dictionary (str -> int) + +Similarly, you can also give an explicit type when creating an empty +set: + + s: set[int] = set() + + Note: Using type arguments (e.g. ‘list[int]’) on builtin + collections like list(1), dict(2), tuple(3), and set(4) only works + in Python 3.9 and later. For Python 3.8 and earlier, you must use + List(5) (e.g. ‘List[int]’), Dict(6), and so on. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#list + + (2) https://docs.python.org/3/library/stdtypes.html#dict + + (3) https://docs.python.org/3/library/stdtypes.html#tuple + + (4) https://docs.python.org/3/library/stdtypes.html#set + + (5) https://docs.python.org/3/library/typing.html#typing.List + + (6) https://docs.python.org/3/library/typing.html#typing.Dict + + +File: Mypy.info, Node: Compatibility of container types, Next: Context in type inference, Prev: Explicit types for collections, Up: Type inference and type annotations + +7.4 Compatibility of container types +==================================== + +The following program generates a mypy error, since ‘list[int]’ is not +compatible with ‘list[object]’: + + def f(l: list[object], k: list[int]) -> None: + l = k # Type check error: incompatible types in assignment + +The reason why the above assignment is disallowed is that allowing the +assignment could result in non-int values stored in a list of ‘int’: + + def f(l: list[object], k: list[int]) -> None: + l = k + l.append('x') + print(k[-1]) # Ouch; a string in list[int] + +Other container types like dict(1) and set(2) behave similarly. We will +discuss how you can work around this in *note Invariance vs covariance: +55. + +You can still run the above program; it prints ‘x’. This illustrates +the fact that static types are used during type checking, but they do +not affect the runtime behavior of programs. You can run programs with +type check failures, which is often very handy when performing a large +refactoring. Thus you can always ‘work around’ the type system, and it +doesn’t really limit what you can do in your program. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#dict + + (2) https://docs.python.org/3/library/stdtypes.html#set + + +File: Mypy.info, Node: Context in type inference, Next: Declaring multiple variable types at a time, Prev: Compatibility of container types, Up: Type inference and type annotations + +7.5 Context in type inference +============================= + +Type inference is `bidirectional' and takes context into account. For +example, the following is valid: + + def f(l: list[object]) -> None: + l = [1, 2] # Infer type list[object] for [1, 2], not list[int] + +In an assignment, the type context is determined by the assignment +target. In this case this is ‘l’, which has the type ‘list[object]’. +The value expression ‘[1, 2]’ is type checked in this context and given +the type ‘list[object]’. In the previous example we introduced a new +variable ‘l’, and here the type context was empty. + +Declared argument types are also used for type context. In this program +mypy knows that the empty list ‘[]’ should have type ‘list[int]’ based +on the declared type of ‘arg’ in ‘foo’: + + def foo(arg: list[int]) -> None: + print('Items:', ''.join(str(a) for a in arg)) + + foo([]) # OK + +However, context only works within a single statement. Here mypy +requires an annotation for the empty list, since the context would only +be available in the following statement: + + def foo(arg: list[int]) -> None: + print('Items:', ', '.join(arg)) + + a = [] # Error: Need type annotation for "a" + foo(a) + +Working around the issue is easy by adding a type annotation: + + ... + a: list[int] = [] # OK + foo(a) + + +File: Mypy.info, Node: Declaring multiple variable types at a time, Next: Starred expressions, Prev: Context in type inference, Up: Type inference and type annotations + +7.6 Declaring multiple variable types at a time +=============================================== + +You can declare more than a single variable at a time, but only with a +type comment. In order to nicely work with multiple assignment, you +must give each variable a type separately: + + i, found = 0, False # type: int, bool + +You can optionally use parentheses around the types, assignment targets +and assigned expression: + + i, found = 0, False # type: (int, bool) # OK + (i, found) = 0, False # type: int, bool # OK + i, found = (0, False) # type: int, bool # OK + (i, found) = (0, False) # type: (int, bool) # OK + + +File: Mypy.info, Node: Starred expressions, Next: Silencing type errors, Prev: Declaring multiple variable types at a time, Up: Type inference and type annotations + +7.7 Starred expressions +======================= + +In most cases, mypy can infer the type of starred expressions from the +right-hand side of an assignment, but not always: + + a, *bs = 1, 2, 3 # OK + p, q, *rs = 1, 2 # Error: Type of rs cannot be inferred + +On first line, the type of ‘bs’ is inferred to be ‘list[int]’. However, +on the second line, mypy cannot infer the type of ‘rs’, because there is +no right-hand side value for ‘rs’ to infer the type from. In cases like +these, the starred expression needs to be annotated with a starred type: + + p, q, *rs = 1, 2 # type: int, int, list[int] + +Here, the type of ‘rs’ is set to ‘list[int]’. + + +File: Mypy.info, Node: Silencing type errors, Prev: Starred expressions, Up: Type inference and type annotations + +7.8 Silencing type errors +========================= + +You might want to disable type checking on specific lines, or within +specific files in your codebase. To do that, you can use a ‘# type: +ignore’ comment. + +For example, say that the web framework that you use now takes an +integer argument to ‘run()’, which starts it on localhost on that port. +Like so: + + # Starting app on http://localhost:8000 + app.run(8000) + +However, the type stubs that the package uses is not up-to-date, and it +still expects only ‘str’ types for ‘run()’. This would give you the +following error: + + error: Argument 1 to "run" of "A" has incompatible type "int"; expected "str" + +If you cannot directly fix the type stubs yourself, you can temporarily +disable type checking on that line, by adding a ‘# type: ignore’: + + # Starting app on http://localhost:8000 + app.run(8000) # type: ignore + +This will suppress any mypy errors that would have raised on that +specific line. + +You should probably add some more information on the ‘# type: ignore’ +comment, to explain why the ignore was added in the first place. This +could be a link to an issue on the repository responsible for the type +stubs, or it could be a short explanation of the bug. To do that, use +this format: + + # Starting app on http://localhost:8000 + app.run(8000) # type: ignore # `run()` now accepts an `int`, as a port + +Mypy displays an error code for each error if you use *note +–show-error-codes: 5a.: + + error: "str" has no attribute "trim" [attr-defined] + +It is possible to add a specific error-code in your ignore comment (e.g. +‘# type: ignore[attr-defined]’) to clarify what’s being silenced. You +can find more information about error codes *note here: 5b. + +Similarly, you can also ignore all mypy checks in a file, by adding a ‘# +type: ignore’ at the top of the file: + + # type: ignore + # This is a test file, skipping type checking in it. + import unittest + ... + + +File: Mypy.info, Node: Kinds of types, Next: Class basics, Prev: Type inference and type annotations, Up: Top + +8 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. + +* Menu: + +* Class types:: +* The Any type:: +* Tuple types:: +* Callable types (and lambdas): Callable types and lambdas. +* Union types:: +* Optional types and the None type:: +* Disabling strict optional checking:: +* Type aliases:: +* Named tuples:: +* The type of class objects:: +* Text and AnyStr:: +* Generators:: + + +File: Mypy.info, Node: Class types, Next: The Any type, Up: Kinds of types + +8.1 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 object(1) 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: + + 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) + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#object + + +File: Mypy.info, Node: The Any type, Next: Tuple types, Prev: Class types, Up: Kinds of types + +8.2 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: + + 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’: + + 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: + + 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: + + 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 *note Dynamically +typed code: 4b. + + 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. + + +File: Mypy.info, Node: Tuple types, Next: Callable types and lambdas, Prev: The Any type, Up: Kinds of types + +8.3 Tuple types +=============== + +The type ‘tuple[T1, ..., Tn]’ represents a tuple with the item types +‘T1’, …, ‘Tn’: + + # 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: + + 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 Sequence(1) 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 *note Named tuples: 62.). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Sequence + + +File: Mypy.info, Node: Callable types and lambdas, Next: Union types, Prev: Tuple types, Up: Kinds of types + +8.4 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: + + 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: + + 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 *note callback protocols: 65. 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: + + 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. + + +File: Mypy.info, Node: Union types, Next: Optional types and the None type, Prev: Callable types and lambdas, Up: Kinds of types + +8.5 Union types +=============== + +Python functions often accept values of two or more different types. +You can use *note overloading: 68. 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 isinstance()(1) check to narrow down a union type to a +more specific type: + + 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 + isinstance()(2) 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 isinstance()(3) before doing anything interesting with the + value. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://docs.python.org/3/library/functions.html#isinstance + + (3) https://docs.python.org/3/library/functions.html#isinstance + + +File: Mypy.info, Node: Optional types and the None type, Next: Disabling strict optional checking, Prev: Union types, Up: Kinds of types + +8.6 Optional types and the None type +==================================== + +You can use the Optional(1) type modifier to define a type variant that +allows ‘None’, such as ‘Optional[int]’ (‘Optional[X]’ is the preferred +shorthand for ‘Union[X, None]’): + + 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 Optional(2) +values: + + 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: + + 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: + + 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: + + 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: + + class Resource: + path: Optional[str] = None + ... + +This also works for attributes defined within methods: + + 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: + + 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: + + 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: + + 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 *note –no-implicit-optional: + 6b. 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. + +* Menu: + +* X | Y syntax for Unions:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Optional + + (2) https://docs.python.org/3/library/typing.html#typing.Optional + + +File: Mypy.info, Node: X | Y syntax for Unions, Up: Optional types and the None type + +8.6.1 X | Y syntax for Unions +----------------------------- + +PEP 604(1) 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 *note Annotation +issues at runtime: 6e.). + + t1: int | str # equivalent to Union[int, str] + + t2: int | None # equivalent to Optional[int] + + # Usable in type comments + t3 = 42 # type: int | str + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0604/ + + +File: Mypy.info, Node: Disabling strict optional checking, Next: Type aliases, Prev: Optional types and the None type, Up: Kinds of types + +8.7 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 Optional(1) types are not required. + +The mode is enabled through the *note –no-strict-optional: 71. +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: + + 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 *note the mypy configuration file: 2e. to migrate your code to +strict optional checking one file at a time, since there exists the +per-module flag *note strict_optional: 72. 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: + + 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 Optional[t](2) to document that ‘None’ is a valid +argument type, even if strict ‘None’ checking is not enabled: + + 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Optional + + (2) https://docs.python.org/3/library/typing.html#typing.Optional + + +File: Mypy.info, Node: Type aliases, Next: Named tuples, Prev: Disabling strict optional checking, Up: Kinds of types + +8.8 Type aliases +================ + +In certain situations, type names may end up being long and painful to +type: + + 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: + + 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 *note generic aliases: 75. + +Since Mypy 0.930 you can also use `explicit type aliases', which were +introduced in PEP 613(1). + +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: + + 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]]] + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0613/ + + +File: Mypy.info, Node: Named tuples, Next: The type of class objects, Prev: Type aliases, Up: Kinds of types + +8.9 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: + + Point = namedtuple('Point', ['x', 'y']) + p = Point(x=1, y=2) + print(p.z) # Error: Point has no attribute 'z' + +If you use namedtuple(1) 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 NamedTuple(2) to also define item types: + + 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: + + 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: + + 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. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/collections.html#collections.namedtuple + + (2) https://docs.python.org/3/library/typing.html#typing.NamedTuple + + +File: Mypy.info, Node: The type of class objects, Next: Text and AnyStr, Prev: Named tuples, Up: Kinds of types + +8.10 The type of class objects +============================== + +(Freely after PEP 484: The type of class objects(1).) + +Sometimes you want to talk about class objects that inherit from a given +class. This can be spelled as Type[C](2) 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 Type[C](3) as an argument annotation +declares that the argument is a class object deriving from ‘C’ (or ‘C’ +itself). + +For example, assume the following classes: + + 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: + + 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 Type(4) the best we could +do would be: + + 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’: + + buyer = new_user(ProUser) + buyer.pay() # Rejected, not a method on User + +However, using Type(5) and a type variable with an upper bound (see +*note Type variables with upper bounds: 79.) we can do better: + + 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’: + + beginner = new_user(BasicUser) # Inferred type is BasicUser + beginner.upgrade() # OK + + Note: The value corresponding to Type[C](6) 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 484: The type of class +objects(7). + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/#the-type-of-class-objects + + (2) https://docs.python.org/3/library/typing.html#typing.Type + + (3) https://docs.python.org/3/library/typing.html#typing.Type + + (4) https://docs.python.org/3/library/typing.html#typing.Type + + (5) https://docs.python.org/3/library/typing.html#typing.Type + + (6) https://docs.python.org/3/library/typing.html#typing.Type + + (7) https://peps.python.org/pep-0484/#the-type-of-class-objects + + +File: Mypy.info, Node: Text and AnyStr, Next: Generators, Prev: The type of class objects, Up: Kinds of types + +8.11 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 Text(1) 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: + + 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 AnyStr(2): + + 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 *note Type variables with value restriction: 7c. + + Note: How ‘bytes’, ‘str’, and ‘unicode’ are handled between Python + 2 and Python 3 may change in future versions of mypy. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Text + + (2) https://docs.python.org/3/library/typing.html#typing.AnyStr + + +File: Mypy.info, Node: Generators, Prev: Text and AnyStr, Up: Kinds of types + +8.12 Generators +=============== + +A basic generator that only yields values can be succinctly annotated as +having a return type of either Iterator[YieldType](1) or +Iterable[YieldType](2). For example: + + 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 Iterator[YieldType](3) over +Iterable[YieldType](4) as the return-type annotation for a generator +function, as it lets mypy know that users are able to call next()(5) 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 send()(6) method or +return a value, on the other hand, you should use the +Generator[YieldType, SendType, ReturnType](7) generic type instead of +either ‘Iterator’ or ‘Iterable’. For example: + + 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 Generator(8) 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: + + 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 close()(9), send()(10), and +throw()(11) methods that generic iterators and iterables don’t. If you +plan to call these methods on the returned generator, use the +Generator(12) type instead of Iterator(13) or Iterable(14). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Iterator + + (2) https://docs.python.org/3/library/typing.html#typing.Iterable + + (3) https://docs.python.org/3/library/typing.html#typing.Iterator + + (4) https://docs.python.org/3/library/typing.html#typing.Iterable + + (5) https://docs.python.org/3/library/functions.html#next + + (6) +https://docs.python.org/3/reference/expressions.html#generator.send + + (7) https://docs.python.org/3/library/typing.html#typing.Generator + + (8) https://docs.python.org/3/library/typing.html#typing.Generator + + (9) +https://docs.python.org/3/reference/expressions.html#generator.close + + (10) +https://docs.python.org/3/reference/expressions.html#generator.send + + (11) +https://docs.python.org/3/reference/expressions.html#generator.throw + + (12) https://docs.python.org/3/library/typing.html#typing.Generator + + (13) https://docs.python.org/3/library/typing.html#typing.Iterator + + (14) https://docs.python.org/3/library/typing.html#typing.Iterable + + +File: Mypy.info, Node: Class basics, Next: Annotation issues at runtime, Prev: Kinds of types, Up: Top + +9 Class basics +************** + +This section will help get you started annotating your classes. +Built-in classes such as ‘int’ also follow these same rules. + +* Menu: + +* Instance and class attributes:: +* Annotating __init__ methods:: +* Class attribute annotations:: +* Overriding statically typed methods:: +* Abstract base classes and multiple inheritance:: +* Slots:: + + +File: Mypy.info, Node: Instance and class attributes, Next: Annotating __init__ methods, Up: Class basics + +9.1 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: + + 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 __slots__(1) +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: + + 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 ClassVar(2) annotation.) + +Type comments work as well, if you need to support Python versions +earlier than 3.6: + + 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: + + 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’: + + class A: + def __init__(self) -> None: + self.y = 1 # Define 'y' + a = self + a.x = 1 # Error: 'x' not defined + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__slots__ + + (2) https://docs.python.org/3/library/typing.html#typing.ClassVar + + +File: Mypy.info, Node: Annotating __init__ methods, Next: Class attribute annotations, Prev: Instance and class attributes, Up: Class basics + +9.2 Annotating __init__ methods +=============================== + +The __init__(1) 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 +__init__(2) methods `if at least one argument is annotated'. For +example, in the following classes __init__(3) is considered fully +annotated: + + class C1: + def __init__(self) -> None: + self.var = 42 + + class C2: + def __init__(self, arg: int): + self.var = arg + +However, if __init__(4) has no annotated arguments and no return type +annotation, it is considered an untyped method: + + class C3: + def __init__(self): + # This body is not type checked + self.var = 42 + 'abc' + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (2) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (3) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (4) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + +File: Mypy.info, Node: Class attribute annotations, Next: Overriding statically typed methods, Prev: Annotating __init__ methods, Up: Class basics + +9.3 Class attribute annotations +=============================== + +You can use a ClassVar[t](1) annotation to explicitly declare that a +particular attribute should not be set on instances: + + 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 ClassVar(2). +An attribute without the ClassVar(3) 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: + + 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 ClassVar(4) is not a class, and you can’t use it with +isinstance()(5) or issubclass()(6). 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 +ClassVar(7) annotation, but this might not do what you’d expect: + + 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 ClassVar(8) type parameter cannot include type variables: + ‘ClassVar[T]’ and ‘ClassVar[list[T]]’ are both invalid if ‘T’ is a + type variable (see *note Defining generic classes: 84. for more + about type variables). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (2) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (3) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (4) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (5) https://docs.python.org/3/library/functions.html#isinstance + + (6) https://docs.python.org/3/library/functions.html#issubclass + + (7) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (8) https://docs.python.org/3/library/typing.html#typing.ClassVar + + +File: Mypy.info, Node: Overriding statically typed methods, Next: Abstract base classes and multiple inheritance, Prev: Class attribute annotations, Up: Class basics + +9.4 Overriding statically typed methods +======================================= + +When overriding a statically typed method, mypy checks that the override +has a compatible signature: + + 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: + + 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 + + +File: Mypy.info, Node: Abstract base classes and multiple inheritance, Next: Slots, Prev: Overriding statically typed methods, Up: Class basics + +9.5 Abstract base classes and multiple inheritance +================================================== + +Mypy supports Python abstract base classes(1) (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 abc.ABCMeta(2) metaclass and the +@abc.abstractmethod(3) function decorator. Example: + + 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 @abc.abstractproperty(4) to + define an abstract property. + +Note that mypy performs checking for unimplemented abstract methods even +if you omit the ABCMeta(5) 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): + + 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: + + 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: + + 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/abc.html + + (2) https://docs.python.org/3/library/abc.html#abc.ABCMeta + + (3) https://docs.python.org/3/library/abc.html#abc.abstractmethod + + (4) https://docs.python.org/3/library/abc.html#abc.abstractproperty + + (5) https://docs.python.org/3/library/abc.html#abc.ABCMeta + + +File: Mypy.info, Node: Slots, Prev: Abstract base classes and multiple inheritance, Up: Class basics + +9.6 Slots +========= + +When a class has explicitly defined __slots__(1), mypy will check that +all attributes assigned to are members of ‘__slots__’: + + 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/reference/datamodel.html#slots + + +File: Mypy.info, Node: Annotation issues at runtime, Next: Protocols and structural subtyping, Prev: Class basics, Up: Top + +10 Annotation issues at runtime +******************************* + +Idiomatic use of type annotations can sometimes run up against what a +given version of Python considers legal code. This section describes +these scenarios and explains how to get your code running again. +Generally speaking, we have three tools at our disposal: + + * For Python 3.7 through 3.9, use of ‘from __future__ import + annotations’ ( PEP 563(1)), made the default in Python 3.11 and + later + + * Use of string literal types or type comments + + * Use of ‘typing.TYPE_CHECKING’ + +We provide a description of these before moving onto discussion of +specific problems you may encounter. + +* Menu: + +* String literal types:: +* Future annotations import (PEP 563): Future annotations import PEP 563. +* typing.TYPE_CHECKING: typing TYPE_CHECKING. +* Class name forward references:: +* Import cycles:: +* Using classes that are generic in stubs but not at runtime:: +* Using types defined in stubs but not at runtime:: +* Using generic builtins:: +* Using X | Y syntax for Unions:: +* Using new additions to the typing module:: + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0563/ + + +File: Mypy.info, Node: String literal types, Next: Future annotations import PEP 563, Up: Annotation issues at runtime + +10.1 String literal types +========================= + +Type comments can’t cause runtime errors because comments are not +evaluated by Python. In a similar way, using string literal types +sidesteps the problem of annotations that would cause runtime errors. + +Any type can be entered as a string literal, and you can combine +string-literal types with non-string-literal types freely: + + def f(a: list['A']) -> None: ... # OK + def g(n: 'int') -> None: ... # OK, though not useful + + class A: pass + +String literal types are never needed in ‘# type:’ comments and *note +stub files: 16. + +String literal types must be defined (or imported) later `in the same +module'. They cannot be used to leave cross-module references +unresolved. (For dealing with import cycles, see *note Import cycles: +8c.) + + +File: Mypy.info, Node: Future annotations import PEP 563, Next: typing TYPE_CHECKING, Prev: String literal types, Up: Annotation issues at runtime + +10.2 Future annotations import (PEP 563) +======================================== + +Many of the issues described here are caused by Python trying to +evaluate annotations. From Python 3.11 on, Python will no longer +attempt to evaluate function and variable annotations. This behaviour +is made available in Python 3.7 and later through the use of ‘from +__future__ import annotations’. + +This can be thought of as automatic string literal-ification of all +function and variable annotations. Note that function and variable +annotations are still required to be valid Python syntax. For more +details, see PEP 563(1). + + Note: Even with the ‘__future__’ import, there are some scenarios + that could still require string literals or result in errors, + typically involving use of forward references or generics in: + + * *note type aliases: 74.; + + * *note type narrowing: 8f.; + + * type definitions (see TypeVar(2), ‘NewType()’, NamedTuple(3)); + + * base classes. + + # base class example + from __future__ import annotations + class A(tuple['B', 'C']): ... # String literal types needed here + class B: ... + class C: ... + + Note: Some libraries may have use cases for dynamic evaluation of + annotations, for instance, through use of ‘typing.get_type_hints’ + or ‘eval’. If your annotation would raise an error when evaluated + (say by using PEP 604(4) syntax with Python 3.9), you may need to + be careful when using such libraries. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0563/ + + (2) https://docs.python.org/3/library/typing.html#typing.TypeVar + + (3) https://docs.python.org/3/library/typing.html#typing.NamedTuple + + (4) https://peps.python.org/pep-0604/ + + +File: Mypy.info, Node: typing TYPE_CHECKING, Next: Class name forward references, Prev: Future annotations import PEP 563, Up: Annotation issues at runtime + +10.3 typing.TYPE_CHECKING +========================= + +The typing(1) module defines a TYPE_CHECKING(2) constant that is ‘False’ +at runtime but treated as ‘True’ while type checking. + +Since code inside ‘if TYPE_CHECKING:’ is not executed at runtime, it +provides a convenient way to tell mypy something without the code being +evaluated at runtime. This is most useful for resolving *note import +cycles: 8c. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + (2) +https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING + + +File: Mypy.info, Node: Class name forward references, Next: Import cycles, Prev: typing TYPE_CHECKING, Up: Annotation issues at runtime + +10.4 Class name forward references +================================== + +Python does not allow references to a class object before the class is +defined (aka forward reference). Thus this code does not work as +expected: + + def f(x: A) -> None: ... # NameError: name "A" is not defined + class A: ... + +Starting from Python 3.7, you can add ‘from __future__ import +annotations’ to resolve this, as discussed earlier: + + from __future__ import annotations + + def f(x: A) -> None: ... # OK + class A: ... + +For Python 3.6 and below, you can enter the type as a string literal or +type comment: + + def f(x: 'A') -> None: ... # OK + + # Also OK + def g(x): # type: (A) -> None + ... + + class A: ... + +Of course, instead of using future annotations import or string literal +types, you could move the function definition after the class +definition. This is not always desirable or even possible, though. + + +File: Mypy.info, Node: Import cycles, Next: Using classes that are generic in stubs but not at runtime, Prev: Class name forward references, Up: Annotation issues at runtime + +10.5 Import cycles +================== + +An import cycle occurs where module A imports module B and module B +imports module A (perhaps indirectly, e.g. ‘A -> B -> C -> A’). +Sometimes in order to add type annotations you have to add extra imports +to a module and those imports cause cycles that didn’t exist before. +This can lead to errors at runtime like: + + ImportError: cannot import name 'b' from partially initialized module 'A' (most likely due to a circular import) + +If those cycles do become a problem when running your program, there’s a +trick: if the import is only needed for type annotations and you’re +using a) the *note future annotations import: 8d, or b) string literals +or type comments for the relevant annotations, you can write the imports +inside ‘if TYPE_CHECKING:’ so that they are not executed at runtime. +Example: + +File ‘foo.py’: + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + import bar + + def listify(arg: 'bar.BarClass') -> 'list[bar.BarClass]': + return [arg] + +File ‘bar.py’: + + from foo import listify + + class BarClass: + def listifyme(self) -> 'list[BarClass]': + return listify(self) + + +File: Mypy.info, Node: Using classes that are generic in stubs but not at runtime, Next: Using types defined in stubs but not at runtime, Prev: Import cycles, Up: Annotation issues at runtime + +10.6 Using classes that are generic in stubs but not at runtime +=============================================================== + +Some classes are declared as *note generic: 84. in stubs, but not at +runtime. + +In Python 3.8 and earlier, there are several examples within the +standard library, for instance, os.PathLike(1) and queue.Queue(2). +Subscripting such a class will result in a runtime error: + + from queue import Queue + + class Tasks(Queue[str]): # TypeError: 'type' object is not subscriptable + ... + + results: Queue[int] = Queue() # TypeError: 'type' object is not subscriptable + +To avoid errors from use of these generics in annotations, just use the +*note future annotations import: 8d. (or string literals or type +comments for Python 3.6 and below). + +To avoid errors when inheriting from these classes, things are a little +more complicated and you need to use *note typing.TYPE_CHECKING: 91.: + + from typing import TYPE_CHECKING + from queue import Queue + + if TYPE_CHECKING: + BaseQueue = Queue[str] # this is only processed by mypy + else: + BaseQueue = Queue # this is not seen by mypy but will be executed at runtime + + class Tasks(BaseQueue): # OK + ... + + task_queue: Tasks + reveal_type(task_queue.get()) # Reveals str + +If your subclass is also generic, you can use the following: + + from typing import TYPE_CHECKING, TypeVar, Generic + from queue import Queue + + _T = TypeVar("_T") + if TYPE_CHECKING: + class _MyQueueBase(Queue[_T]): pass + else: + class _MyQueueBase(Generic[_T], Queue): pass + + class MyQueue(_MyQueueBase[_T]): pass + + task_queue: MyQueue[str] + reveal_type(task_queue.get()) # Reveals str + +In Python 3.9, we can just inherit directly from ‘Queue[str]’ or +‘Queue[T]’ since its queue.Queue(3) implements ‘__class_getitem__()’, so +the class object can be subscripted at runtime without issue. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/os.html#os.PathLike + + (2) https://docs.python.org/3/library/queue.html#queue.Queue + + (3) https://docs.python.org/3/library/queue.html#queue.Queue + + +File: Mypy.info, Node: Using types defined in stubs but not at runtime, Next: Using generic builtins, Prev: Using classes that are generic in stubs but not at runtime, Up: Annotation issues at runtime + +10.7 Using types defined in stubs but not at runtime +==================================================== + +Sometimes stubs that you’re using may define types you wish to re-use +that do not exist at runtime. Importing these types naively will cause +your code to fail at runtime with ‘ImportError’ or +‘ModuleNotFoundError’. Similar to previous sections, these can be dealt +with by using *note typing.TYPE_CHECKING: 91.: + + from typing import TYPE_CHECKING + if TYPE_CHECKING: + from _typeshed import SupportsLessThan + + +File: Mypy.info, Node: Using generic builtins, Next: Using X | Y syntax for Unions, Prev: Using types defined in stubs but not at runtime, Up: Annotation issues at runtime + +10.8 Using generic builtins +=========================== + +Starting with Python 3.9 ( PEP 585(1)), the type objects of many +collections in the standard library support subscription at runtime. +This means that you no longer have to import the equivalents from +typing(2); you can simply use the built-in collections or those from +collections.abc(3): + + from collections.abc import Sequence + x: list[str] + y: dict[int, str] + z: Sequence[str] = x + +There is limited support for using this syntax in Python 3.7 and later +as well. If you use ‘from __future__ import annotations’, mypy will +understand this syntax in annotations. However, since this will not be +supported by the Python interpreter at runtime, make sure you’re aware +of the caveats mentioned in the notes at *note future annotations +import: 8d. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0585/ + + (2) https://docs.python.org/3/library/typing.html#module-typing + + (3) +https://docs.python.org/3/library/collections.abc.html#module-collections.abc + + +File: Mypy.info, Node: Using X | Y syntax for Unions, Next: Using new additions to the typing module, Prev: Using generic builtins, Up: Annotation issues at runtime + +10.9 Using X | Y syntax for Unions +================================== + +Starting with Python 3.10 ( PEP 604(1)), you can spell union types as +‘x: int | str’, instead of ‘x: typing.Union[int, str]’. + +There is limited support for using this syntax in Python 3.7 and later +as well. If you use ‘from __future__ import annotations’, mypy will +understand this syntax in annotations, string literal types, type +comments and stub files. However, since this will not be supported by +the Python interpreter at runtime (if evaluated, ‘int | str’ will raise +‘TypeError: unsupported operand type(s) for |: 'type' and 'type'’), make +sure you’re aware of the caveats mentioned in the notes at *note future +annotations import: 8d. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0604/ + + +File: Mypy.info, Node: Using new additions to the typing module, Prev: Using X | Y syntax for Unions, Up: Annotation issues at runtime + +10.10 Using new additions to the typing module +============================================== + +You may find yourself wanting to use features added to the typing(1) +module in earlier versions of Python than the addition, for example, +using any of ‘Literal’, ‘Protocol’, ‘TypedDict’ with Python 3.6. + +The easiest way to do this is to install and use the ‘typing_extensions’ +package from PyPI for the relevant imports, for example: + + from typing_extensions import Literal + x: Literal["open", "close"] + +If you don’t want to rely on ‘typing_extensions’ being installed on +newer Pythons, you could alternatively use: + + import sys + if sys.version_info >= (3, 8): + from typing import Literal + else: + from typing_extensions import Literal + + x: Literal["open", "close"] + +This plays nicely well with following PEP 508(2) dependency +specification: ‘typing_extensions; python_version<"3.8"’ + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + (2) https://peps.python.org/pep-0508/ + + +File: Mypy.info, Node: Protocols and structural subtyping, Next: Dynamically typed code, Prev: Annotation issues at runtime, Up: Top + +11 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 isinstance(1) 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(2) for the detailed specification of protocols and structural +subtyping in Python. + +* Menu: + +* Predefined protocols:: +* Simple user-defined protocols:: +* Defining subprotocols and subclassing protocols:: +* Recursive protocols:: +* Using isinstance() with protocols: Using isinstance with protocols. +* Callback protocols:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://peps.python.org/pep-0544/ + + +File: Mypy.info, Node: Predefined protocols, Next: Simple user-defined protocols, Up: Protocols and structural subtyping + +11.1 Predefined protocols +========================= + +The typing(1) module defines various protocol classes that correspond to +common Python protocols, such as Iterable[T](2). If a class defines a +suitable __iter__(3) method, mypy understands that it implements the +iterable protocol and is compatible with Iterable[T](4). For example, +‘IntList’ below is iterable, over ‘int’ values: + + 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 +typing(5) 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). + +* Menu: + +* Iteration protocols:: +* Collection protocols:: +* One-off protocols:: +* Async protocols:: +* Context manager protocols:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + (2) https://docs.python.org/3/library/typing.html#typing.Iterable + + (3) +https://docs.python.org/3/reference/datamodel.html#object.__iter__ + + (4) https://docs.python.org/3/library/typing.html#typing.Iterable + + (5) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Iteration protocols, Next: Collection protocols, Up: Predefined protocols + +11.1.1 Iteration protocols +-------------------------- + +The iteration protocols are useful in many contexts. For example, they +allow iteration of objects in for loops. + +* Menu: + +* Iterable[T]:: +* Iterator[T]:: + + +File: Mypy.info, Node: Iterable[T], Next: Iterator[T], Up: Iteration protocols + +11.1.1.1 Iterable[T] +.................... + +The *note example above: 9d. has a simple implementation of an +__iter__(1) method. + + def __iter__(self) -> Iterator[T] + +See also Iterable(2). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__iter__ + + (2) https://docs.python.org/3/library/typing.html#typing.Iterable + + +File: Mypy.info, Node: Iterator[T], Prev: Iterable[T], Up: Iteration protocols + +11.1.1.2 Iterator[T] +.................... + + def __next__(self) -> T + def __iter__(self) -> Iterator[T] + +See also Iterator(1). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Iterator + + +File: Mypy.info, Node: Collection protocols, Next: One-off protocols, Prev: Iteration protocols, Up: Predefined protocols + +11.1.2 Collection protocols +--------------------------- + +Many of these are implemented by built-in container types such as +list(1) and dict(2), and these are also useful for user-defined +collection objects. + +* Menu: + +* Sized:: +* Container[T]:: +* Collection[T]:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#list + + (2) https://docs.python.org/3/library/stdtypes.html#dict + + +File: Mypy.info, Node: Sized, Next: Container[T], Up: Collection protocols + +11.1.2.1 Sized +.............. + +This is a type for objects that support len(x)(1). + + def __len__(self) -> int + +See also Sized(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#len + + (2) https://docs.python.org/3/library/typing.html#typing.Sized + + +File: Mypy.info, Node: Container[T], Next: Collection[T], Prev: Sized, Up: Collection protocols + +11.1.2.2 Container[T] +..................... + +This is a type for objects that support the ‘in’ operator. + + def __contains__(self, x: object) -> bool + +See also Container(1). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Container + + +File: Mypy.info, Node: Collection[T], Prev: Container[T], Up: Collection protocols + +11.1.2.3 Collection[T] +...................... + + def __len__(self) -> int + def __iter__(self) -> Iterator[T] + def __contains__(self, x: object) -> bool + +See also Collection(1). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Collection + + +File: Mypy.info, Node: One-off protocols, Next: Async protocols, Prev: Collection protocols, Up: Predefined protocols + +11.1.3 One-off protocols +------------------------ + +These protocols are typically only useful with a single standard library +function or class. + +* Menu: + +* Reversible[T]:: +* SupportsAbs[T]:: +* SupportsBytes:: +* SupportsComplex:: +* SupportsFloat:: +* SupportsInt:: +* SupportsRound[T]:: + + +File: Mypy.info, Node: Reversible[T], Next: SupportsAbs[T], Up: One-off protocols + +11.1.3.1 Reversible[T] +...................... + +This is a type for objects that support reversed(x)(1). + + def __reversed__(self) -> Iterator[T] + +See also Reversible(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#reversed + + (2) https://docs.python.org/3/library/typing.html#typing.Reversible + + +File: Mypy.info, Node: SupportsAbs[T], Next: SupportsBytes, Prev: Reversible[T], Up: One-off protocols + +11.1.3.2 SupportsAbs[T] +....................... + +This is a type for objects that support abs(x)(1). ‘T’ is the type of +value returned by abs(x)(2). + + def __abs__(self) -> T + +See also SupportsAbs(3). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#abs + + (2) https://docs.python.org/3/library/functions.html#abs + + (3) https://docs.python.org/3/library/typing.html#typing.SupportsAbs + + +File: Mypy.info, Node: SupportsBytes, Next: SupportsComplex, Prev: SupportsAbs[T], Up: One-off protocols + +11.1.3.3 SupportsBytes +...................... + +This is a type for objects that support bytes(x)(1). + + def __bytes__(self) -> bytes + +See also SupportsBytes(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#bytes + + (2) +https://docs.python.org/3/library/typing.html#typing.SupportsBytes + + +File: Mypy.info, Node: SupportsComplex, Next: SupportsFloat, Prev: SupportsBytes, Up: One-off protocols + +11.1.3.4 SupportsComplex +........................ + +This is a type for objects that support complex(x)(1). Note that no +arithmetic operations are supported. + + def __complex__(self) -> complex + +See also SupportsComplex(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#complex + + (2) +https://docs.python.org/3/library/typing.html#typing.SupportsComplex + + +File: Mypy.info, Node: SupportsFloat, Next: SupportsInt, Prev: SupportsComplex, Up: One-off protocols + +11.1.3.5 SupportsFloat +...................... + +This is a type for objects that support float(x)(1). Note that no +arithmetic operations are supported. + + def __float__(self) -> float + +See also SupportsFloat(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#float + + (2) +https://docs.python.org/3/library/typing.html#typing.SupportsFloat + + +File: Mypy.info, Node: SupportsInt, Next: SupportsRound[T], Prev: SupportsFloat, Up: One-off protocols + +11.1.3.6 SupportsInt +.................... + +This is a type for objects that support int(x)(1). Note that no +arithmetic operations are supported. + + def __int__(self) -> int + +See also SupportsInt(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#int + + (2) https://docs.python.org/3/library/typing.html#typing.SupportsInt + + +File: Mypy.info, Node: SupportsRound[T], Prev: SupportsInt, Up: One-off protocols + +11.1.3.7 SupportsRound[T] +......................... + +This is a type for objects that support round(x)(1). + + def __round__(self) -> T + +See also SupportsRound(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#round + + (2) +https://docs.python.org/3/library/typing.html#typing.SupportsRound + + +File: Mypy.info, Node: Async protocols, Next: Context manager protocols, Prev: One-off protocols, Up: Predefined protocols + +11.1.4 Async protocols +---------------------- + +These protocols can be useful in async code. See *note Typing +async/await: 3a. for more information. + +* Menu: + +* Awaitable[T]:: +* AsyncIterable[T]:: +* AsyncIterator[T]:: + + +File: Mypy.info, Node: Awaitable[T], Next: AsyncIterable[T], Up: Async protocols + +11.1.4.1 Awaitable[T] +..................... + + def __await__(self) -> Generator[Any, None, T] + +See also Awaitable(1). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Awaitable + + +File: Mypy.info, Node: AsyncIterable[T], Next: AsyncIterator[T], Prev: Awaitable[T], Up: Async protocols + +11.1.4.2 AsyncIterable[T] +......................... + + def __aiter__(self) -> AsyncIterator[T] + +See also AsyncIterable(1). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/typing.html#typing.AsyncIterable + + +File: Mypy.info, Node: AsyncIterator[T], Prev: AsyncIterable[T], Up: Async protocols + +11.1.4.3 AsyncIterator[T] +......................... + + def __anext__(self) -> Awaitable[T] + def __aiter__(self) -> AsyncIterator[T] + +See also AsyncIterator(1). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/typing.html#typing.AsyncIterator + + +File: Mypy.info, Node: Context manager protocols, Prev: Async protocols, Up: Predefined protocols + +11.1.5 Context manager protocols +-------------------------------- + +There are two protocols for context managers – one for regular context +managers and one for async ones. These allow defining objects that can +be used in ‘with’ and ‘async with’ statements. + +* Menu: + +* ContextManager[T]:: +* AsyncContextManager[T]:: + + +File: Mypy.info, Node: ContextManager[T], Next: AsyncContextManager[T], Up: Context manager protocols + +11.1.5.1 ContextManager[T] +.......................... + + def __enter__(self) -> T + def __exit__(self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType]) -> Optional[bool] + +See also ContextManager(1). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/typing.html#typing.ContextManager + + +File: Mypy.info, Node: AsyncContextManager[T], Prev: ContextManager[T], Up: Context manager protocols + +11.1.5.2 AsyncContextManager[T] +............................... + + def __aenter__(self) -> Awaitable[T] + def __aexit__(self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]] + +See also AsyncContextManager(1). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/typing.html#typing.AsyncContextManager + + +File: Mypy.info, Node: Simple user-defined protocols, Next: Defining subprotocols and subclassing protocols, Prev: Predefined protocols, Up: Protocols and structural subtyping + +11.2 Simple user-defined protocols +================================== + +You can define your own protocol class by inheriting the special +‘Protocol’ class: + + from typing import Iterable + from typing_extensions import Protocol + + class SupportsClose(Protocol): + def close(self) -> None: + ... # Empty method body (explicit '...') + + class Resource: # No SupportsClose base class! + # ... some methods ... + + def close(self) -> None: + self.resource.release() + + def close_all(items: Iterable[SupportsClose]) -> None: + for item in items: + item.close() + + close_all([Resource(), open('some/file')]) # Okay! + +‘Resource’ is a subtype of the ‘SupportsClose’ protocol since it defines +a compatible ‘close’ method. Regular file objects returned by open()(1) +are similarly compatible with the protocol, as they support ‘close()’. + + Note: The ‘Protocol’ base class is provided in the + ‘typing_extensions’ package for Python 2.7 and 3.4-3.7. Starting + with Python 3.8, ‘Protocol’ is included in the ‘typing’ module. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#open + + +File: Mypy.info, Node: Defining subprotocols and subclassing protocols, Next: Recursive protocols, Prev: Simple user-defined protocols, Up: Protocols and structural subtyping + +11.3 Defining subprotocols and subclassing protocols +==================================================== + +You can also define subprotocols. Existing protocols can be extended +and merged using multiple inheritance. Example: + + # ... continuing from the previous example + + class SupportsRead(Protocol): + def read(self, amount: int) -> bytes: ... + + class TaggedReadableResource(SupportsClose, SupportsRead, Protocol): + label: str + + class AdvancedResource(Resource): + def __init__(self, label: str) -> None: + self.label = label + + def read(self, amount: int) -> bytes: + # some implementation + ... + + resource: TaggedReadableResource + resource = AdvancedResource('handle with care') # OK + +Note that inheriting from an existing protocol does not automatically +turn the subclass into a protocol – it just creates a regular +(non-protocol) class or ABC that implements the given protocol (or +protocols). The ‘Protocol’ base class must always be explicitly present +if you are defining a protocol: + + class NotAProtocol(SupportsClose): # This is NOT a protocol + new_attr: int + + class Concrete: + new_attr: int = 0 + + def close(self) -> None: + ... + + # Error: nominal subtyping used by default + x: NotAProtocol = Concrete() # Error! + +You can also include default implementations of methods in protocols. +If you explicitly subclass these protocols you can inherit these default +implementations. Explicitly including a protocol as a base class is +also a way of documenting that your class implements a particular +protocol, and it forces mypy to verify that your class implementation is +actually compatible with the protocol. + + Note: You can use Python 3.6 variable annotations ( PEP 526(1)) to + declare protocol attributes. On Python 2.7 and earlier Python 3 + versions you can use type comments and properties. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0526/ + + +File: Mypy.info, Node: Recursive protocols, Next: Using isinstance with protocols, Prev: Defining subprotocols and subclassing protocols, Up: Protocols and structural subtyping + +11.4 Recursive protocols +======================== + +Protocols can be recursive (self-referential) and mutually recursive. +This is useful for declaring abstract recursive collections such as +trees and linked lists: + + from typing import TypeVar, Optional + from typing_extensions import Protocol + + class TreeLike(Protocol): + value: int + + @property + def left(self) -> Optional['TreeLike']: ... + + @property + def right(self) -> Optional['TreeLike']: ... + + class SimpleTree: + def __init__(self, value: int) -> None: + self.value = value + self.left: Optional['SimpleTree'] = None + self.right: Optional['SimpleTree'] = None + + root: TreeLike = SimpleTree(0) # OK + + +File: Mypy.info, Node: Using isinstance with protocols, Next: Callback protocols, Prev: Recursive protocols, Up: Protocols and structural subtyping + +11.5 Using isinstance() with protocols +====================================== + +You can use a protocol class with isinstance()(1) if you decorate it +with the ‘@runtime_checkable’ class decorator. The decorator adds +support for basic runtime structural checks: + + from typing_extensions import Protocol, runtime_checkable + + @runtime_checkable + class Portable(Protocol): + handles: int + + class Mug: + def __init__(self) -> None: + self.handles = 1 + + def use(handles: int) -> None: ... + + mug = Mug() + if isinstance(mug, Portable): + use(mug.handles) # Works statically and at runtime + +isinstance()(2) also works with the *note predefined protocols: 9d. in +typing(3) such as Iterable(4). + + Note: isinstance()(5) with protocols is not completely safe at + runtime. For example, signatures of methods are not checked. The + runtime implementation only checks that all protocol members are + defined. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://docs.python.org/3/library/functions.html#isinstance + + (3) https://docs.python.org/3/library/typing.html#module-typing + + (4) https://docs.python.org/3/library/typing.html#typing.Iterable + + (5) https://docs.python.org/3/library/functions.html#isinstance + + +File: Mypy.info, Node: Callback protocols, Prev: Using isinstance with protocols, Up: Protocols and structural subtyping + +11.6 Callback protocols +======================= + +Protocols can be used to define flexible callback types that are hard +(or even impossible) to express using the Callable[...](1) syntax, such +as variadic, overloaded, and complex generic callbacks. They are +defined with a special __call__(2) member: + + from typing import Optional, Iterable + from typing_extensions import Protocol + + class Combiner(Protocol): + def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ... + + def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: + for item in data: + ... + + def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: + ... + def bad_cb(*vals: bytes, maxitems: Optional[int]) -> list[bytes]: + ... + + batch_proc([], good_cb) # OK + batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of + # different name and kind in the callback + +Callback protocols and Callable(3) types can be used interchangeably. +Keyword argument names in __call__(4) methods must be identical, unless +a double underscore prefix is used. For example: + + from typing import Callable, TypeVar + from typing_extensions import Protocol + + T = TypeVar('T') + + class Copy(Protocol): + def __call__(self, __origin: T) -> T: ... + + copy_a: Callable[[T], T] + copy_b: Copy + + copy_a = copy_b # OK + copy_b = copy_a # Also OK + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Callable + + (2) +https://docs.python.org/3/reference/datamodel.html#object.__call__ + + (3) https://docs.python.org/3/library/typing.html#typing.Callable + + (4) +https://docs.python.org/3/reference/datamodel.html#object.__call__ + + +File: Mypy.info, Node: Dynamically typed code, Next: Type checking Python 2 code, Prev: Protocols and structural subtyping, Up: Top + +12 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’: + + 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 + +* Menu: + +* Operations on Any values:: +* Any vs. object: Any vs object. + + +File: Mypy.info, Node: Operations on Any values, Next: Any vs object, Up: Dynamically typed code + +12.1 Operations on Any values +============================= + +You can do anything using a value with type ‘Any’, and type checker does +not complain: + + 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’: + + 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. + + +File: Mypy.info, Node: Any vs object, Prev: Operations on Any values, Up: Dynamically typed code + +12.2 Any vs. object +=================== + +The type object(1) is another type that can have an instance of +arbitrary type as a value. Unlike ‘Any’, object(2) is an ordinary +static type (it is similar to ‘Object’ in Java), and only operations +valid for `all' types are accepted for object(3) values. These are all +valid: + + 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: + + 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 *note type narrowing: 8f. techniques to narrow +object(4) to a more specific type (subtype) such as ‘int’. Type +narrowing is not needed with dynamically typed values (values with type +‘Any’). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#object + + (2) https://docs.python.org/3/library/functions.html#object + + (3) https://docs.python.org/3/library/functions.html#object + + (4) https://docs.python.org/3/library/functions.html#object + + +File: Mypy.info, Node: Type checking Python 2 code, Next: Type narrowing, Prev: Dynamically typed code, Up: Top + +13 Type checking Python 2 code +****************************** + +For code that needs to be Python 2.7 compatible, function type +annotations are given in comments, since the function annotation syntax +was introduced in Python 3. The comment-based syntax is specified in +PEP 484(1). + +Mypy requires typed-ast in order to check Python 2 code. You can +install it using ‘pip install 'mypy[python2]'’. + +Run mypy in Python 2 mode by using the *note –py2: 8. option: + + $ mypy --py2 program.py + +To run your program, you must have the ‘typing’ module in your Python 2 +module search path. Use ‘pip install typing’ to install the module. +This also works for Python 3 versions prior to 3.5 that don’t include +typing(2) in the standard library. + +The example below illustrates the Python 2 function type annotation +syntax. This syntax is also valid in Python 3 mode: + + from typing import List + + def hello(): # type: () -> None + print 'hello' + + class Example: + def method(self, lst, opt=0, *args, **kwargs): + # type: (List[str], int, *str, **bool) -> int + """Docstring comes after type comment.""" + ... + +It’s worth going through these details carefully to avoid surprises: + + - You don’t provide an annotation for the ‘self’ / ‘cls’ variable of + methods. + + - Docstring always comes `after' the type comment. + + - For ‘*args’ and ‘**kwargs’ the type should be prefixed with ‘*’ or + ‘**’, respectively (except when using the multi-line annotation + syntax described below). Again, the above example illustrates + this. + + - Things like ‘Any’ must be imported from ‘typing’, even if they are + only used in comments. + + - In Python 2 mode ‘str’ is implicitly promoted to ‘unicode’, similar + to how ‘int’ is compatible with ‘float’. This is unlike ‘bytes’ + and ‘str’ in Python 3, which are incompatible. ‘bytes’ in Python 2 + is equivalent to ‘str’. (This might change in the future.) + +* Menu: + +* Multi-line Python 2 function annotations:: +* Additional notes:: + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + (2) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Multi-line Python 2 function annotations, Next: Additional notes, Up: Type checking Python 2 code + +13.1 Multi-line Python 2 function annotations +============================================= + +Mypy also supports a multi-line comment annotation syntax. You can +provide a separate annotation for each argument using the variable +annotation syntax. When using the single-line annotation syntax +described above, functions with long argument lists tend to result in +overly long type comments and it’s often tricky to see which argument +type corresponds to which argument. The alternative, multi-line +annotation syntax makes long annotations easier to read and write. + +Here is an example (from PEP 484(1)): + + def send_email(address, # type: Union[str, List[str]] + sender, # type: str + cc, # type: Optional[List[str]] + bcc, # type: Optional[List[str]] + subject='', + body=None # type: List[str] + ): + # type: (...) -> bool + """Send an email message. Return True if successful.""" + + +You write a separate annotation for each function argument on the same +line as the argument. Each annotation must be on a separate line. If +you leave out an annotation for an argument, it defaults to ‘Any’. You +provide a return type annotation in the body of the function using the +form ‘# type: (...) -> rt’, where ‘rt’ is the return type. Note that +the return type annotation contains literal three dots. + +When using multi-line comments, you do not need to prefix the types of +your ‘*arg’ and ‘**kwarg’ parameters with ‘*’ or ‘**’. For example, +here is how you would annotate the first example using multi-line +comments: + + from typing import List + + class Example: + def method(self, + lst, # type: List[str] + opt=0, # type: int + *args, # type: str + **kwargs # type: bool + ): + # type: (...) -> int + """Docstring comes after type comment.""" + ... + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + +File: Mypy.info, Node: Additional notes, Prev: Multi-line Python 2 function annotations, Up: Type checking Python 2 code + +13.2 Additional notes +===================== + + - You should include types for arguments with default values in the + annotation. The ‘opt’ argument of ‘method’ in the example at the + beginning of this section is an example of this. + + - The annotation can be on the same line as the function header or on + the following line. + + - Variables use a comment-based type syntax (explained in *note + Explicit types for variables: 52.). + + - You don’t need to use string literal escapes for forward references + within comments (string literal escapes are explained later). + + - Mypy uses a separate set of library stub files in typeshed(1) for + Python 2. Library support may vary between Python 2 and Python 3. + + ---------- Footnotes ---------- + + (1) https://github.com/python/typeshed + + +File: Mypy.info, Node: Type narrowing, Next: Duck type compatibility, Prev: Type checking Python 2 code, Up: Top + +14 Type narrowing +***************** + +This section is dedicated to several type narrowing techniques which are +supported by mypy. + +Type narrowing is when you convince a type checker that a broader type +is actually more specific, for instance, that an object of type ‘Shape’ +is actually of the narrower type ‘Square’. + +* Menu: + +* Type narrowing expressions:: +* Casts:: +* User-Defined Type Guards:: + + +File: Mypy.info, Node: Type narrowing expressions, Next: Casts, Up: Type narrowing + +14.1 Type narrowing expressions +=============================== + +The simplest way to narrow a type is to use one of the supported +expressions: + + - isinstance()(1) like in ‘isinstance(obj, float)’ will narrow ‘obj’ + to have ‘float’ type + + - issubclass()(2) like in ‘issubclass(cls, MyClass)’ will narrow + ‘cls’ to be ‘Type[MyClass]’ + + - ‘type()’ like in ‘type(obj) is int’ will narrow ‘obj’ to have ‘int’ + type + + - callable()(3) like in ‘callable(obj)’ will narrow object to + callable type + +Type narrowing is contextual. For example, based on the condition, mypy +will narrow an expression only within an ‘if’ branch: + + def function(arg: object): + if isinstance(arg, int): + # Type is narrowed within the ``if`` branch only + reveal_type(arg) # Revealed type: "builtins.int" + elif isinstance(arg, str) or isinstance(arg, bool): + # Type is narrowed differently within this ``elif`` branch: + reveal_type(arg) # Revealed type: "builtins.str | builtins.bool" + + # Subsequent narrowing operations will narrow the type further + if isinstance(arg, bool): + reveal_type(arg) # Revealed type: "builtins.bool" + + # Back outside of the ``if`` statement, the type isn't narrowed: + reveal_type(arg) # Revealed type: "builtins.object" + +Mypy understands the implications ‘return’ or exception raising can have +for what type an object could be: + + def function(arg: int | str): + if isinstance(arg, int): + return + + # `arg` can't be `int` at this point: + reveal_type(arg) # Revealed type: "builtins.str" + +We can also use ‘assert’ to narrow types in the same context: + + def function(arg: Any): + assert isinstance(arg, int) + reveal_type(arg) # Revealed type: "builtins.int" + + Note: With *note –warn-unreachable: c6. narrowing types to some + impossible state will be treated as an error. + + def function(arg: int): + # error: Subclass of "int" and "str" cannot exist: + # would have incompatible method signatures + assert isinstance(arg, str) + + # error: Statement is unreachable + print("so mypy concludes the assert will always trigger") + + Without ‘--warn-unreachable’ mypy will simply not check code it + deems to be unreachable. See *note Unreachable code: c7. for more + information. + + x: int = 1 + assert isinstance(x, str) + reveal_type(x) # Revealed type is "builtins.int" + print(x + '!') # Typechecks with `mypy`, but fails in runtime. + +* Menu: + +* issubclass:: +* callable:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://docs.python.org/3/library/functions.html#issubclass + + (3) https://docs.python.org/3/library/functions.html#callable + + +File: Mypy.info, Node: issubclass, Next: callable, Up: Type narrowing expressions + +14.1.1 issubclass +----------------- + +Mypy can also use issubclass()(1) for better type inference when working +with types and metaclasses: + + class MyCalcMeta(type): + @classmethod + def calc(cls) -> int: + ... + + def f(o: object) -> None: + t = type(o) # We must use a variable here + reveal_type(t) # Revealed type is "builtins.type" + + if issubtype(t, MyCalcMeta): # `issubtype(type(o), MyCalcMeta)` won't work + reveal_type(t) # Revealed type is "Type[MyCalcMeta]" + t.calc() # Okay + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#issubclass + + +File: Mypy.info, Node: callable, Prev: issubclass, Up: Type narrowing expressions + +14.1.2 callable +--------------- + +Mypy knows what types are callable and which ones are not during type +checking. So, we know what ‘callable()’ will return. For example: + + from typing import Callable + + x: Callable[[], int] + + if callable(x): + reveal_type(x) # N: Revealed type is "def () -> builtins.int" + else: + ... # Will never be executed and will raise error with `--warn-unreachable` + +‘callable’ function can even split ‘Union’ type for callable and +non-callable parts: + + from typing import Callable, Union + + x: Union[int, Callable[[], int]] + + if callable(x): + reveal_type(x) # N: Revealed type is "def () -> builtins.int" + else: + reveal_type(x) # N: Revealed type is "builtins.int" + + +File: Mypy.info, Node: Casts, Next: User-Defined Type Guards, Prev: Type narrowing expressions, Up: Type narrowing + +14.2 Casts +========== + +Mypy supports type casts that are usually used to coerce a statically +typed value to a subtype. Unlike languages such as Java or C#, however, +mypy casts are only used as hints for the type checker, and they don’t +perform a runtime type check. Use the function cast()(1) to perform a +cast: + + from typing import cast + + o: object = [1] + x = cast(list[int], o) # OK + y = cast(list[str], o) # OK (cast performs no actual runtime check) + +To support runtime checking of casts such as the above, we’d have to +check the types of all list items, which would be very inefficient for +large lists. Casts are used to silence spurious type checker warnings +and give the type checker a little help when it can’t quite understand +what is going on. + + Note: You can use an assertion if you want to perform an actual + runtime check: + + def foo(o: object) -> None: + print(o + 5) # Error: can't add 'object' and 'int' + assert isinstance(o, int) + print(o + 5) # OK: type of 'o' is 'int' here + +You don’t need a cast for expressions with type ‘Any’, or when assigning +to a variable with type ‘Any’, as was explained earlier. You can also +use ‘Any’ as the cast target type – this lets you perform any operations +on the result. For example: + + from typing import cast, Any + + x = 1 + x.whatever() # Type check error + y = cast(Any, x) + y.whatever() # Type check OK (runtime error) + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.cast + + +File: Mypy.info, Node: User-Defined Type Guards, Prev: Casts, Up: Type narrowing + +14.3 User-Defined Type Guards +============================= + +Mypy supports User-Defined Type Guards ( PEP 647(1)). + +A type guard is a way for programs to influence conditional type +narrowing employed by a type checker based on runtime checks. + +Basically, a ‘TypeGuard’ is a “smart” alias for a ‘bool’ type. Let’s +have a look at the regular ‘bool’ example: + + def is_str_list(val: list[object]) -> bool: + """Determines whether all objects in the list are strings""" + return all(isinstance(x, str) for x in val) + + def func1(val: list[object]) -> None: + if is_str_list(val): + reveal_type(val) # Reveals list[object] + print(" ".join(val)) # Error: incompatible type + +The same example with ‘TypeGuard’: + + from typing import TypeGuard # use `typing_extensions` for Python 3.9 and below + + def is_str_list(val: list[object]) -> TypeGuard[list[str]]: + """Determines whether all objects in the list are strings""" + return all(isinstance(x, str) for x in val) + + def func1(val: list[object]) -> None: + if is_str_list(val): + reveal_type(val) # list[str] + print(" ".join(val)) # ok + +How does it work? ‘TypeGuard’ narrows the first function argument +(‘val’) to the type specified as the first type parameter (‘list[str]’). + + Note: Narrowing is not strict(2). For example, you can narrow + ‘str’ to ‘int’: + + def f(value: str) -> TypeGuard[int]: + return True + + Note: since strict narrowing is not enforced, it’s easy to break + type safety. + + However, there are many ways a determined or uninformed developer + can subvert type safety – most commonly by using cast or Any. If a + Python developer takes the time to learn about and implement + user-defined type guards within their code, it is safe to assume + that they are interested in type safety and will not write their + type guard functions in a way that will undermine type safety or + produce nonsensical results. + +* Menu: + +* Generic TypeGuards:: +* Typeguards with parameters:: +* TypeGuards as methods:: +* Assignment expressions as TypeGuards:: + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0647/ + + (2) +https://www.python.org/dev/peps/pep-0647/#enforcing-strict-narrowing + + +File: Mypy.info, Node: Generic TypeGuards, Next: Typeguards with parameters, Up: User-Defined Type Guards + +14.3.1 Generic TypeGuards +------------------------- + +‘TypeGuard’ can also work with generic types: + + from typing import TypeVar + from typing import TypeGuard # use `typing_extensions` for `python<3.10` + + _T = TypeVar("_T") + + def is_two_element_tuple(val: tuple[_T, ...]) -> TypeGuard[tuple[_T, _T]]: + return len(val) == 2 + + def func(names: tuple[str, ...]): + if is_two_element_tuple(names): + reveal_type(names) # tuple[str, str] + else: + reveal_type(names) # tuple[str, ...] + + +File: Mypy.info, Node: Typeguards with parameters, Next: TypeGuards as methods, Prev: Generic TypeGuards, Up: User-Defined Type Guards + +14.3.2 Typeguards with parameters +--------------------------------- + +Type guard functions can accept extra arguments: + + from typing import Type, TypeVar + from typing import TypeGuard # use `typing_extensions` for `python<3.10` + + _T = TypeVar("_T") + + def is_set_of(val: set[Any], type: Type[_T]) -> TypeGuard[set[_T]]: + return all(isinstance(x, type) for x in val) + + items: set[Any] + if is_set_of(items, str): + reveal_type(items) # set[str] + + +File: Mypy.info, Node: TypeGuards as methods, Next: Assignment expressions as TypeGuards, Prev: Typeguards with parameters, Up: User-Defined Type Guards + +14.3.3 TypeGuards as methods +---------------------------- + + A method can also serve as the ‘TypeGuard’: + + class StrValidator: + def is_valid(self, instance: object) -> TypeGuard[str]: + return isinstance(instance, str) + + def func(to_validate: object) -> None: + if StrValidator().is_valid(to_validate): + reveal_type(to_validate) # Revealed type is "builtins.str" + + Note: Note, that ‘TypeGuard’ does not narrow(1) types of ‘self’ or + ‘cls’ implicit arguments. + + If narrowing of ‘self’ or ‘cls’ is required, the value can be + passed as an explicit argument to a type guard function: + + class Parent: + def method(self) -> None: + reveal_type(self) # Revealed type is "Parent" + if is_child(self): + reveal_type(self) # Revealed type is "Child" + + class Child(Parent): + ... + + def is_child(instance: Parent) -> TypeGuard[Child]: + return isinstance(instance, Child) + + ---------- Footnotes ---------- + + (1) +https://www.python.org/dev/peps/pep-0647/#narrowing-of-implicit-self-and-cls-parameters + + +File: Mypy.info, Node: Assignment expressions as TypeGuards, Prev: TypeGuards as methods, Up: User-Defined Type Guards + +14.3.4 Assignment expressions as TypeGuards +------------------------------------------- + +Sometimes you might need to create a new variable and narrow it to some +specific type at the same time. This can be achieved by using +‘TypeGuard’ together with := operator(1). + + from typing import TypeGuard # use `typing_extensions` for `python<3.10` + + def is_float(a: object) -> TypeGuard[float]: + return isinstance(a, float) + + def main(a: object) -> None: + if is_float(x := a): + reveal_type(x) # N: Revealed type is 'builtins.float' + reveal_type(a) # N: Revealed type is 'builtins.object' + reveal_type(x) # N: Revealed type is 'builtins.object' + reveal_type(a) # N: Revealed type is 'builtins.object' + +What happens here? + + 1. We create a new variable ‘x’ and assign a value of ‘a’ to it + + 2. We run ‘is_float()’ type guard on ‘x’ + + 3. It narrows ‘x’ to be ‘float’ in the ‘if’ context and does not touch + ‘a’ + + Note: The same will work with ‘isinstance(x := a, float)’ as well. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions + + +File: Mypy.info, Node: Duck type compatibility, Next: Stub files, Prev: Type narrowing, Up: Top + +15 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: + + 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 *note Protocols and structural subtyping: 37. 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 *note Text and AnyStr: 7b. for details on how to enforce that a + value must be a unicode string in a cross-compatible way. + + +File: Mypy.info, Node: Stub files, Next: Generics, Prev: Duck type compatibility, Up: Top + +16 Stub files +************* + +Mypy uses stub files stored in the typeshed(1) repository to determine +the types of standard library and third-party library functions, +classes, and other definitions. You can also create your own stubs that +will be used to type check your code. The basic properties of stubs +were introduced back in *note Library stubs and typeshed: 13. + +* Menu: + +* Creating a stub:: +* Stub file syntax:: +* Using stub file syntax at runtime:: + + ---------- Footnotes ---------- + + (1) https://github.com/python/typeshed + + +File: Mypy.info, Node: Creating a stub, Next: Stub file syntax, Up: Stub files + +16.1 Creating a stub +==================== + +Here is an overview of how to create a stub file: + + * Write a stub file for the library (or an arbitrary module) and + store it as a ‘.pyi’ file in the same directory as the library + module. + + * Alternatively, put your stubs (‘.pyi’ files) in a directory + reserved for stubs (e.g., ‘myproject/stubs’). In this case you + have to set the environment variable ‘MYPYPATH’ to refer to the + directory. For example: + + $ export MYPYPATH=~/work/myproject/stubs + +Use the normal Python file name conventions for modules, e.g. ‘csv.pyi’ +for module ‘csv’. Use a subdirectory with ‘__init__.pyi’ for packages. +Note that PEP 561(1) stub-only packages must be installed, and may not +be pointed at through the ‘MYPYPATH’ (see *note PEP 561 support: 15.). + +If a directory contains both a ‘.py’ and a ‘.pyi’ file for the same +module, the ‘.pyi’ file takes precedence. This way you can easily add +annotations for a module even if you don’t want to modify the source +code. This can be useful, for example, if you use 3rd party open source +libraries in your program (and there are no stubs in typeshed yet). + +That’s it! + +Now you can access the module in mypy programs and type check code that +uses the library. If you write a stub for a library module, consider +making it available for other programmers that use mypy by contributing +it back to the typeshed repo. + +Mypy also ships with two tools for making it easier to create and +maintain stubs: *note Automatic stub generation (stubgen): d7. and *note +Automatic stub testing (stubtest): d8. + +The following sections explain the kinds of type annotations you can use +in your programs and stub files. + + Note: You may be tempted to point ‘MYPYPATH’ to the standard + library or to the ‘site-packages’ directory where your 3rd party + packages are installed. This is almost always a bad idea – you + will likely get tons of error messages about code you didn’t write + and that mypy can’t analyze all that well yet, and in the worst + case scenario mypy may crash due to some construct in a 3rd party + package that it didn’t expect. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0561/ + + +File: Mypy.info, Node: Stub file syntax, Next: Using stub file syntax at runtime, Prev: Creating a stub, Up: Stub files + +16.2 Stub file syntax +===================== + +Stub files are written in normal Python 3 syntax, but generally leaving +out runtime logic like variable initializers, function bodies, and +default arguments. + +If it is not possible to completely leave out some piece of runtime +logic, the recommended convention is to replace or elide them with +ellipsis expressions (‘...’). Each ellipsis below is literally written +in the stub file as three dots: + + # Variables with annotations do not need to be assigned a value. + # So by convention, we omit them in the stub file. + x: int + + # Function bodies cannot be completely removed. By convention, + # we replace them with `...` instead of the `pass` statement. + def func_1(code: str) -> int: ... + + # We can do the same with default arguments. + def func_2(a: int, b: int = ...) -> int: ... + + Note: The ellipsis ‘...’ is also used with a different meaning in + *note callable types: 63. and *note tuple types: 61. + + Note: It is always legal to use Python 3 syntax in stub files, even + when writing Python 2 code. The example above is a valid stub file + for both Python 2 and 3. + + +File: Mypy.info, Node: Using stub file syntax at runtime, Prev: Stub file syntax, Up: Stub files + +16.3 Using stub file syntax at runtime +====================================== + +You may also occasionally need to elide actual logic in regular Python +code – for example, when writing methods in *note overload variants: 68. +or *note custom protocols: 37. + +The recommended style is to use ellipses to do so, just like in stub +files. It is also considered stylistically acceptable to throw a +NotImplementedError(1) in cases where the user of the code may +accidentally call functions with no actual logic. + +You can also elide default arguments as long as the function body also +contains no runtime logic: the function body only contains a single +ellipsis, the pass statement, or a ‘raise NotImplementedError()’. It is +also acceptable for the function body to contain a docstring. For +example: + + from typing_extensions import Protocol + + class Resource(Protocol): + def ok_1(self, foo: list[str] = ...) -> None: ... + + def ok_2(self, foo: list[str] = ...) -> None: + raise NotImplementedError() + + def ok_3(self, foo: list[str] = ...) -> None: + """Some docstring""" + pass + + # Error: Incompatible default for argument "foo" (default has + # type "ellipsis", argument has type "list[str]") + def not_ok(self, foo: list[str] = ...) -> None: + print(foo) + + Note: Ellipsis expressions are legal syntax in Python 3 only. This + means it is not possible to elide default arguments in Python 2 + code. You can still elide function bodies in Python 2 by using + either the ‘pass’ statement or by throwing a + NotImplementedError(2). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/exceptions.html#NotImplementedError + + (2) +https://docs.python.org/3/library/exceptions.html#NotImplementedError + + +File: Mypy.info, Node: Generics, Next: More types, Prev: Stub files, Up: Top + +17 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. + +* Menu: + +* Defining generic classes:: +* Generic class internals:: +* Defining sub-classes of generic classes:: +* Generic functions:: +* Generic methods and generic self:: +* Variance of generic types:: +* Type variables with value restriction:: +* Type variables with upper bounds:: +* Declaring decorators:: +* Generic protocols:: +* Generic type aliases:: + + +File: Mypy.info, Node: Defining generic classes, Next: Generic class internals, Up: Generics + +17.1 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: + + 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: + + # 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: + + def process(stack: Stack[int]) -> None: ... + + process(Stack()) # Argument has inferred type Stack[int] + +Construction of instances of generic types is also type checked: + + 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 + + +File: Mypy.info, Node: Generic class internals, Next: Defining sub-classes of generic classes, Prev: Defining generic classes, Up: Generics + +17.2 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: + + >>> 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 list(1), dict(2) +and others do not support indexing. This is why we have the aliases +List(3), Dict(4) and so on in the typing(5) 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: + + >>> # 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: + + >>> 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#list + + (2) https://docs.python.org/3/library/stdtypes.html#dict + + (3) https://docs.python.org/3/library/typing.html#typing.List + + (4) https://docs.python.org/3/library/typing.html#typing.Dict + + (5) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Defining sub-classes of generic classes, Next: Generic functions, Prev: Generic class internals, Up: Generics + +17.3 Defining sub-classes of generic classes +============================================ + +User-defined generic classes and generic classes defined in typing(1) +can be used as base classes for another classes, both generic and +non-generic. For example: + + 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 Mapping(2) base class if you want + mypy to consider a user-defined class as a mapping (and Sequence(3) + for sequences, etc.). This is because mypy doesn’t use `structural + subtyping' for these ABCs, unlike simpler protocols like + Iterable(4), which use *note structural subtyping: 37. + +Generic(5) 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: + + 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 + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + (2) https://docs.python.org/3/library/typing.html#typing.Mapping + + (3) https://docs.python.org/3/library/typing.html#typing.Sequence + + (4) https://docs.python.org/3/library/typing.html#typing.Iterable + + (5) https://docs.python.org/3/library/typing.html#typing.Generic + + +File: Mypy.info, Node: Generic functions, Next: Generic methods and generic self, Prev: Defining sub-classes of generic classes, Up: Generics + +17.4 Generic functions +====================== + +Generic type variables can also be used to define generic functions: + + 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: + + # 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: + + 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. + + +File: Mypy.info, Node: Generic methods and generic self, Next: Variance of generic types, Prev: Generic functions, Up: Generics + +17.5 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: + + 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 Type[T](1): + + 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 *note additional examples: e5. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Type + + +File: Mypy.info, Node: Variance of generic types, Next: Type variables with value restriction, Prev: Generic methods and generic self, Up: Generics + +17.6 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: + + * Union(1) 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 Sequence(2) and FrozenSet(3) are also covariant. + + * Callable(4) 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: + + 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. + + * List(5) is an invariant generic type. Naively, one would think + that it is covariant, but let us consider this code: + + 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 Dict(6). 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: + + 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 + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Union + + (2) https://docs.python.org/3/library/typing.html#typing.Sequence + + (3) https://docs.python.org/3/library/typing.html#typing.FrozenSet + + (4) https://docs.python.org/3/library/typing.html#typing.Callable + + (5) https://docs.python.org/3/library/typing.html#typing.List + + (6) https://docs.python.org/3/library/typing.html#typing.Dict + + +File: Mypy.info, Node: Type variables with value restriction, Next: Type variables with upper bounds, Prev: Variance of generic types, Up: Generics + +17.7 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’: + + from typing import TypeVar + + AnyStr = TypeVar('AnyStr', str, bytes) + +This is actually such a common type variable that AnyStr(1) is defined +in typing(2) and we don’t need to define it ourselves. + +We can use AnyStr(3) to define a function that can concatenate two +strings or bytes objects, but it can’t be called with other argument +types: + + 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: + + 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: + + 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’: + + 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: + + >>> print(type(ss)) + + +You can also use a TypeVar(4) with a restricted set of possible values +when defining a generic class. For example, mypy uses the type +Pattern[AnyStr](5) for the return value of re.compile()(6), since +regular expressions can be based on a string or a bytes pattern. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.AnyStr + + (2) https://docs.python.org/3/library/typing.html#module-typing + + (3) https://docs.python.org/3/library/typing.html#typing.AnyStr + + (4) https://docs.python.org/3/library/typing.html#typing.TypeVar + + (5) https://docs.python.org/3/library/typing.html#typing.Pattern + + (6) https://docs.python.org/3/library/re.html#re.compile + + +File: Mypy.info, Node: Type variables with upper bounds, Next: Declaring decorators, Prev: Type variables with value restriction, Up: Generics + +17.8 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 +TypeVar(1). + + 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’. + + 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, + + 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 *note Type +variables with value restriction: 7c.) and an upper bound. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.TypeVar + + +File: Mypy.info, Node: Declaring decorators, Next: Generic protocols, Prev: Type variables with upper bounds, Up: Generics + +17.9 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: + + 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 cast()(1) call in the ‘return’ statement +in ‘my_decorator()’. See *note casts: ca. + +* Menu: + +* Decorator factories:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.cast + + +File: Mypy.info, Node: Decorator factories, Up: Declaring decorators + +17.9.1 Decorator factories +-------------------------- + +Functions that take arguments and return a decorator (also called +second-order decorators), are similarly supported via generics: + + 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 @overload(1): + + 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: ... + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.overload + + +File: Mypy.info, Node: Generic protocols, Next: Generic type aliases, Prev: Declaring decorators, Up: Generics + +17.10 Generic protocols +======================= + +Mypy supports generic protocols (see also *note Protocols and structural +subtyping: 37.). Several *note predefined protocols: 9d. are generic, +such as Iterable[T](1), and you can define additional generic protocols. +Generic protocols mostly follow the normal rules for generic classes. +Example: + + 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 544: Generic protocols(2), ‘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: + + 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: + + 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 *note Variance of generic types: e7. for more about variance. + +Generic protocols can also be recursive. Example: + + 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' + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Iterable + + (2) https://peps.python.org/pep-0544/#generic-protocols + + +File: Mypy.info, Node: Generic type aliases, Prev: Generic protocols, Up: Generics + +17.11 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 484: Type aliases(1)): + + 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: + + 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. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/#type-aliases + + +File: Mypy.info, Node: More types, Next: Literal types and Enums, Prev: Generics, Up: Top + +18 More types +************* + +This section introduces a few additional kinds of types, including +NoReturn(1), ‘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: + + * NoReturn(2) lets you tell mypy that a function never returns + normally. + + * ‘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. + + * @overload(3) 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’. + +* Menu: + +* The NoReturn type:: +* NewTypes:: +* Function overloading:: +* Advanced uses of self-types:: +* Typing async/await:: +* TypedDict:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.NoReturn + + (2) https://docs.python.org/3/library/typing.html#typing.NoReturn + + (3) https://docs.python.org/3/library/typing.html#typing.overload + + +File: Mypy.info, Node: The NoReturn type, Next: NewTypes, Up: More types + +18.1 The NoReturn type +====================== + +Mypy provides support for functions that never return. For example, a +function that unconditionally raises an exception: + + from typing import NoReturn + + def stop() -> NoReturn: + raise Exception('no way') + +Mypy will ensure that functions annotated as returning NoReturn(1) 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: + + 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 NoReturn(2) in your code. Python 3 command line: + + python3 -m pip install --upgrade typing-extensions + +This works for Python 2: + + pip install --upgrade typing-extensions + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.NoReturn + + (2) https://docs.python.org/3/library/typing.html#typing.NoReturn + + +File: Mypy.info, Node: NewTypes, Next: Function overloading, Prev: The NoReturn type, Up: More types + +18.2 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: + + 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 ‘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: + + 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: + + 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: + + 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 + +‘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 Union(1), etc. + +The callable returned by ‘NewType’ accepts only one argument; this is +equivalent to supporting only one constructor accepting an instance of +the base class (see above). Example: + + 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 isinstance()(2) or issubclass()(3) on the object returned +by ‘NewType()’, nor can you subclass an object returned by ‘NewType()’. + + Note: Unlike type aliases, ‘NewType’ will create an entirely new + and unique type when used. The intended purpose of ‘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: + + UserId = int + + def name_by_id(user_id: UserId) -> str: + ... + + name_by_id(3) # ints and UserId are synonymous + + But a similar example using ‘NewType’ will not typecheck: + + 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 + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Union + + (2) https://docs.python.org/3/library/functions.html#isinstance + + (3) https://docs.python.org/3/library/functions.html#issubclass + + +File: Mypy.info, Node: Function overloading, Next: Advanced uses of self-types, Prev: NewTypes, Up: More types + +18.3 Function overloading +========================= + +Sometimes the arguments and types in a function depend on each other in +ways that can’t be captured with a Union(1). 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: + + 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 overloading(2) which lets us give the same +function multiple type annotations (signatures) to more accurately +describe the function’s behavior: + + 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 __getitem__(3) method (‘[]’ bracket indexing). If +this method receives an integer we return a single item. If it receives +a ‘slice’, we return a Sequence(4) of items. + +We can precisely encode this relationship between the argument and the +return type by using overloads like so: + + 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 *note value restriction: 7c. + +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: + + 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: + ... + +* Menu: + +* Runtime behavior:: +* Type checking calls to overloads:: +* Type checking the variants:: +* Type checking the implementation:: +* Conditional overloads:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Union + + (2) https://peps.python.org/pep-0484/#function-method-overloading + + (3) +https://docs.python.org/3/reference/datamodel.html#object.__getitem__ + + (4) https://docs.python.org/3/library/typing.html#typing.Sequence + + +File: Mypy.info, Node: Runtime behavior, Next: Type checking calls to overloads, Up: Function overloading + +18.3.1 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 isinstance(1) 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + +File: Mypy.info, Node: Type checking calls to overloads, Next: Type checking the variants, Prev: Runtime behavior, Up: Function overloading + +18.3.2 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: + + # 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’: + + 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: + + 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. isinstance(1) checks) in your + implementation. + + 2. Order your variants and runtime checks from most to least + specific. (See the following section for an example). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + +File: Mypy.info, Node: Type checking the variants, Next: Type checking the implementation, Prev: Type checking calls to overloads, Up: Function overloading + +18.3.3 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: + + 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: + + # 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: + + 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: + + some_obj: object = 42 + unsafe_func(some_obj) + " danger danger" # Type checks, yet crashes at runtime! + +Since ‘some_obj’ is of type object(1), 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’: + + 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#object + + +File: Mypy.info, Node: Type checking the implementation, Next: Conditional overloads, Prev: Type checking the variants, Up: Function overloading + +18.3.4 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 *note –check-untyped-defs: fa. flag (*note more details here: fb.). + +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’. + + +File: Mypy.info, Node: Conditional overloads, Prev: Type checking the implementation, Up: Function overloading + +18.3.5 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 TYPE_CHECKING(1), ‘MYPY’, *note + Python version and system platform checks: fd, *note –always-true: + fe, and *note –always-false: ff. values. + + 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" + + # 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 *note + –python-version 3.10: 100. 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. + + 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" + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING + + +File: Mypy.info, Node: Advanced uses of self-types, Next: Typing async/await, Prev: Function overloading, Up: More types + +18.4 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. + +* Menu: + +* Restricted methods in generic classes:: +* Mixin classes:: +* Precise typing of alternative constructors:: + + +File: Mypy.info, Node: Restricted methods in generic classes, Next: Mixin classes, Up: Advanced uses of self-types + +18.4.1 Restricted methods in generic classes +-------------------------------------------- + +In generic classes some methods may be allowed to be called only for +certain values of type arguments: + + 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: + + 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: + + 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 __init__()(1) 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. +Popen(2). + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (2) +https://docs.python.org/3/library/subprocess.html#subprocess.Popen + + +File: Mypy.info, Node: Mixin classes, Next: Precise typing of alternative constructors, Prev: Restricted methods in generic classes, Up: Advanced uses of self-types + +18.4.2 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: + + 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. + + +File: Mypy.info, Node: Precise typing of alternative constructors, Prev: Mixin classes, Up: Advanced uses of self-types + +18.4.3 Precise typing of alternative constructors +------------------------------------------------- + +Some classes may define alternative constructors. If these classes are +generic, self-type allows giving them precise signatures: + + 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" + + +File: Mypy.info, Node: Typing async/await, Next: TypedDict, Prev: Advanced uses of self-types, Up: More types + +18.5 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(1). + +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. + + 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 Coroutine[Any, Any, T](2), which is a subtype of +Awaitable[T](3): + + my_coroutine = countdown_1("Millennium Falcon", 5) + reveal_type(my_coroutine) # has type 'Coroutine[Any, Any, str]' + + Note: *note reveal_type(): 106. displays the inferred static type + of an expression. + +You may also choose to create a subclass of Awaitable(4) instead: + + 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 AsyncIterator(5): + + 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 @asyncio.coroutine(6) decorator to convert a generator +into a coroutine, and use a generator type as the return type: + + 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() + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0492/ + + (2) https://docs.python.org/3/library/typing.html#typing.Coroutine + + (3) https://docs.python.org/3/library/typing.html#typing.Awaitable + + (4) https://docs.python.org/3/library/typing.html#typing.Awaitable + + (5) +https://docs.python.org/3/library/typing.html#typing.AsyncIterator + + (6) +https://docs.python.org/3/library/asyncio-task.html#asyncio.coroutine + + +File: Mypy.info, Node: TypedDict, Prev: Typing async/await, Up: More types + +18.6 TypedDict +============== + +Python programs often use dictionaries with string keys to represent +objects. Here is a typical example: + + 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: + + 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 dict(1) 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 dict(2). + +Now mypy will recognize these as valid: + + 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: + + 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 dict(3) object at runtime – a ‘TypedDict’ does not define a new +runtime type: + + 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 dict(4) 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 +Mapping(5) only provides read-only access to the dictionary items: + + 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 typing(6) module) you need to install + ‘typing_extensions’ using pip to use ‘TypedDict’: + + python3 -m pip install --upgrade typing-extensions + + Or, if you are using Python 2: + + pip install --upgrade typing-extensions + +* Menu: + +* Totality:: +* Supported operations:: +* Class-based syntax:: +* Mixing required and non-required items:: +* Unions of TypedDicts:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#dict + + (2) https://docs.python.org/3/library/stdtypes.html#dict + + (3) https://docs.python.org/3/library/stdtypes.html#dict + + (4) https://docs.python.org/3/library/stdtypes.html#dict + + (5) https://docs.python.org/3/library/typing.html#typing.Mapping + + (6) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Totality, Next: Supported operations, Up: TypedDict + +18.6.1 Totality +--------------- + +By default mypy ensures that a ‘TypedDict’ object has all the specified +keys. This will be flagged as an error: + + # 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: + + GuiOptions = TypedDict( + 'GuiOptions', {'language': str, 'color': str}, total=False) + options = {} # type: GuiOptions # Okay + options['language'] = 'en' + +You may need to use get()(1) 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 KeyError(2). Requiring +get()(3) everywhere would be too cumbersome. (Note that you are free to +use get()(4) with total ‘TypedDict’s as well.) + +Keys that aren’t required are shown with a ‘?’ in error messages: + + # 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/stdtypes.html#dict.get + + (2) https://docs.python.org/3/library/exceptions.html#KeyError + + (3) https://docs.python.org/3/library/stdtypes.html#dict.get + + (4) https://docs.python.org/3/library/stdtypes.html#dict.get + + +File: Mypy.info, Node: Supported operations, Next: Class-based syntax, Prev: Totality, Up: TypedDict + +18.6.2 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 Mapping(1): + + * ‘d[key]’ + + * ‘key in d’ + + * ‘len(d)’ + + * ‘for key in d’ (iteration) + + * d.get(key[, default])(2) + + * d.keys()(3) + + * d.values()(4) + + * d.items()(5) + + * d.copy()(6) + + * d.setdefault(key, default)(7) + + * d1.update(d2)(8) + + * d.pop(key[, default])(9) (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: clear()(10) and popitem()(11) are not supported since they + are unsafe – they could delete required ‘TypedDict’ items that are + not visible to mypy because of structural subtyping. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Mapping + + (2) https://docs.python.org/3/library/stdtypes.html#dict.get + + (3) https://docs.python.org/3/library/stdtypes.html#dict.keys + + (4) https://docs.python.org/3/library/stdtypes.html#dict.values + + (5) https://docs.python.org/3/library/stdtypes.html#dict.items + + (6) https://docs.python.org/3/library/stdtypes.html#dict.copy + + (7) https://docs.python.org/3/library/stdtypes.html#dict.setdefault + + (8) https://docs.python.org/3/library/stdtypes.html#dict.update + + (9) https://docs.python.org/3/library/stdtypes.html#dict.pop + + (10) https://docs.python.org/3/library/stdtypes.html#dict.clear + + (11) https://docs.python.org/3/library/stdtypes.html#dict.popitem + + +File: Mypy.info, Node: Class-based syntax, Next: Mixing required and non-required items, Prev: Supported operations, Up: TypedDict + +18.6.3 Class-based syntax +------------------------- + +An alternative, class-based syntax to define a ‘TypedDict’ is supported +in Python 3.6 and later: + + 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: + + class Movie(TypedDict): + name: str + year: int + + class BookBasedMovie(Movie): + based_on: str + +Now ‘BookBasedMovie’ has keys ‘name’, ‘year’ and ‘based_on’. + + +File: Mypy.info, Node: Mixing required and non-required items, Next: Unions of TypedDicts, Prev: Class-based syntax, Up: TypedDict + +18.6.4 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: + + 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’. + + +File: Mypy.info, Node: Unions of TypedDicts, Prev: Mixing required and non-required items, Up: TypedDict + +18.6.5 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 *note tagged union pattern: 10e. 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 *note Literal type: 10f. Then, check that key +to distinguish between your TypedDicts. + + +File: Mypy.info, Node: Literal types and Enums, Next: Final names methods and classes, Prev: More types, Up: Top + +19 Literal types and Enums +************************** + +* Menu: + +* Literal types:: +* Enums:: + + +File: Mypy.info, Node: Literal types, Next: Enums, Up: Literal types and Enums + +19.1 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: + + 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. + +* Menu: + +* Parameterizing Literals:: +* Declaring literal variables:: +* Intelligent indexing:: +* Tagged unions:: +* Exhaustiveness checking:: +* Limitations:: + + +File: Mypy.info, Node: Parameterizing Literals, Next: Declaring literal variables, Up: Literal types + +19.1.1 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: + + 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. + + +File: Mypy.info, Node: Declaring literal variables, Next: Intelligent indexing, Prev: Parameterizing Literals, Up: Literal types + +19.1.2 Declaring literal variables +---------------------------------- + +You must explicitly add an annotation to a variable to declare that it +has a literal type: + + 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: + + 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 *note +Final names, methods and classes: 115.): + + 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: + + 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: + + 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]]" + + +File: Mypy.info, Node: Intelligent indexing, Next: Tagged unions, Prev: Declaring literal variables, Up: Literal types + +19.1.3 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: + + 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" + + +File: Mypy.info, Node: Tagged unions, Next: Exhaustiveness checking, Prev: Intelligent indexing, Up: Literal types + +19.1.4 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: + + 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()’: + + 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. + + +File: Mypy.info, Node: Exhaustiveness checking, Next: Limitations, Prev: Tagged unions, Up: Literal types + +19.1.5 Exhaustiveness checking +------------------------------ + +You may want to check that some code covers all possible ‘Literal’ or +‘Enum’ cases. Example: + + 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: + + 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: + + 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: + + 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: + + 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): + + def validate(x: PossibleValues) -> bool: + match x: + case 'one': + return True + case 'two': + return False + assert_never(x) + + +File: Mypy.info, Node: Limitations, Prev: Exhaustiveness checking, Up: Literal types + +19.1.6 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__’. + + +File: Mypy.info, Node: Enums, Prev: Literal types, Up: Literal types and Enums + +19.2 Enums +========== + +Mypy has special support for enum.Enum(1) and its subclasses: +enum.IntEnum(2), enum.Flag(3), enum.IntFlag(4), and ‘enum.StrEnum’. + + 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: + + 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" + +* Menu: + +* Exhaustiveness checking: Exhaustiveness checking<2>. +* Extra Enum checks:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/enum.html#enum.Enum + + (2) https://docs.python.org/3/library/enum.html#enum.IntEnum + + (3) https://docs.python.org/3/library/enum.html#enum.Flag + + (4) https://docs.python.org/3/library/enum.html#enum.IntFlag + + +File: Mypy.info, Node: Exhaustiveness checking<2>, Next: Extra Enum checks, Up: Enums + +19.2.1 Exhaustiveness checking +------------------------------ + +Similar to ‘Literal’ types, ‘Enum’ supports exhaustiveness checking. +Let’s start with a definition: + + 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: + + 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: + + 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). + + +File: Mypy.info, Node: Extra Enum checks, Prev: Exhaustiveness checking<2>, Up: Enums + +19.2.2 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 *note final: 115. This + is what happens in CPython: + + >>> class AllDirection(Direction): + ... left = 'left' + ... right = 'right' + Traceback (most recent call last): + ... + TypeError: Other: cannot extend enumeration 'Some' + + Mypy also catches this error: + + class AllDirection(Direction): # E: Cannot inherit from final class "Some" + left = 'left' + right = 'right' + + - All ‘Enum’ fields are implictly ‘final’ as well. + + Direction.up = '^' # E: Cannot assign to final attribute "up" + + - All field names are checked to be unique. + + 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. + + 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" + ... + + +File: Mypy.info, Node: Final names methods and classes, Next: Metaclasses, Prev: Literal types and Enums, Up: Top + +20 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. + +* Menu: + +* Final names:: +* Final methods:: +* Final classes:: + + +File: Mypy.info, Node: Final names, Next: Final methods, Up: Final names methods and classes + +20.1 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: + + 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: + + 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 @property(1) to make an attribute read-only, but unlike +‘Final’, it doesn’t work with module attributes, and it doesn’t prevent +overriding in subclasses. + +* Menu: + +* Syntax variants:: +* Details of using Final:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#property + + +File: Mypy.info, Node: Syntax variants, Next: Details of using Final, Up: Final names + +20.1.1 Syntax variants +---------------------- + +You can use ‘Final’ in one of these forms: + + * You can provide an explicit type using the syntax ‘Final[]’. + Example: + + ID: Final[int] = 1 + + Here mypy will infer type ‘int’ for ‘ID’. + + * You can omit the type: + + 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 __init__(1) + methods, so that the final instance attribute is assigned only once + when an instance is created. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + +File: Mypy.info, Node: Details of using Final, Prev: Syntax variants, Up: Final names + +20.1.2 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 __init__(1) method (you can skip the initializer +in stub files): + + 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: + + x: list[Final[int]] = [] # Error! + + def fun(x: Final[list[int]]) -> None: # Error! + ... + +‘Final’ and ClassVar(2) 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 __init__(3). + +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: + + 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: + + 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 + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (2) https://docs.python.org/3/library/typing.html#typing.ClassVar + + (3) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + +File: Mypy.info, Node: Final methods, Next: Final classes, Prev: Final names, Up: Final names methods and classes + +20.2 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: + + 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): + + 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): + ... + + +File: Mypy.info, Node: Final classes, Prev: Final methods, Up: Final names methods and classes + +20.3 Final classes +================== + +You can apply the ‘typing.final’ decorator to a class to indicate to +mypy that it should not be subclassed: + + 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. + + 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 + + +File: Mypy.info, Node: Metaclasses, Next: Running mypy and managing imports, Prev: Final names methods and classes, Up: Top + +21 Metaclasses +************** + +A metaclass(1) 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 type(2), but it’s +possible to use other metaclasses. Metaclasses allows one to create “a +different kind of class”, such as Enum(3)s, NamedTuple(4)s and +singletons. + +Mypy has some special understanding of ABCMeta(5) and ‘EnumMeta’. + +* Menu: + +* Defining a metaclass:: +* Metaclass usage example:: +* Gotchas and limitations of metaclass support:: + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/reference/datamodel.html#metaclasses + + (2) https://docs.python.org/3/library/functions.html#type + + (3) https://docs.python.org/3/library/enum.html#enum.Enum + + (4) https://docs.python.org/3/library/typing.html#typing.NamedTuple + + (5) https://docs.python.org/3/library/abc.html#abc.ABCMeta + + +File: Mypy.info, Node: Defining a metaclass, Next: Metaclass usage example, Up: Metaclasses + +21.1 Defining a metaclass +========================= + + class M(type): + pass + + class A(metaclass=M): + pass + +In Python 2, the syntax for defining a metaclass is different: + + class A(object): + __metaclass__ = M + +Mypy also supports using six.with_metaclass()(1) and +@six.add_metaclass(2) to define metaclass in a portable way: + + import six + + class A(six.with_metaclass(M)): + pass + + @six.add_metaclass(M) + class C(object): + pass + + ---------- Footnotes ---------- + + (1) https://six.readthedocs.io/index.html#six.with_metaclass + + (2) https://six.readthedocs.io/index.html#six.add_metaclass + + +File: Mypy.info, Node: Metaclass usage example, Next: Gotchas and limitations of metaclass support, Prev: Defining a metaclass, Up: Metaclasses + +21.2 Metaclass usage example +============================ + +Mypy supports the lookup of attributes in the metaclass: + + 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") + + +File: Mypy.info, Node: Gotchas and limitations of metaclass support, Prev: Metaclass usage example, Up: Metaclasses + +21.3 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: + + 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 type(1) as potential + metaclasses. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#type + + +File: Mypy.info, Node: Running mypy and managing imports, Next: The mypy command line, Prev: Metaclasses, Up: Top + +22 Running mypy and managing imports +************************************ + +The *note Getting started: 5. page should have already introduced you to +the basics of how to run mypy – pass in the files and directories you +want to type check via the command line: + + $ mypy foo.py bar.py some_directory + +This page discusses in more detail how exactly to specify what files you +want mypy to type check, how mypy discovers imported modules, and +recommendations on how to handle any issues you may encounter along the +way. + +If you are interested in learning about how to configure the actual way +mypy type checks your code, see our *note The mypy command line: c. +guide. + +* Menu: + +* Specifying code to be checked:: +* Reading a list of files from a file:: +* How mypy handles imports:: +* Missing imports:: +* Following imports:: +* Mapping file paths to modules:: +* How imports are found:: +* Other advice and best practices:: +* Directories specific to Python 2 (@python2): Directories specific to Python 2 @python2. + + +File: Mypy.info, Node: Specifying code to be checked, Next: Reading a list of files from a file, Up: Running mypy and managing imports + +22.1 Specifying code to be checked +================================== + +Mypy lets you specify what files it should type check in several +different ways. + +Note that if you use namespace packages (in particular, packages without +‘__init__.py’), you’ll need to specify *note –namespace-packages: 132. + + 1. First, you can pass in paths to Python files and directories you + want to type check. For example: + + $ mypy file_1.py foo/file_2.py file_3.pyi some/directory + + The above command tells mypy it should type check all of the + provided files together. In addition, mypy will recursively type + check the entire contents of any provided directories. + + For more details about how exactly this is done, see *note Mapping + file paths to modules: 133. + + 2. Second, you can use the *note -m: 134. flag (long form: *note + –module: 134.) to specify a module name to be type checked. The + name of a module is identical to the name you would use to import + that module within a Python program. For example, running: + + $ mypy -m html.parser + + …will type check the module ‘html.parser’ (this happens to be a + library stub). + + Mypy will use an algorithm very similar to the one Python uses to + find where modules and imports are located on the file system. For + more details, see *note How imports are found: 135. + + 3. Third, you can use the *note -p: 136. (long form: *note –package: + 136.) flag to specify a package to be (recursively) type checked. + This flag is almost identical to the *note -m: 134. flag except + that if you give it a package name, mypy will recursively type + check all submodules and subpackages of that package. For example, + running: + + $ mypy -p html + + …will type check the entire ‘html’ package (of library stubs). In + contrast, if we had used the *note -m: 134. flag, mypy would have + type checked just ‘html’’s ‘__init__.py’ file and anything imported + from there. + + Note that we can specify multiple packages and modules on the + command line. For example: + + $ mypy --package p.a --package p.b --module c + + 4. Fourth, you can also instruct mypy to directly type check small + strings as programs by using the *note -c: 137. (long form: *note + –command: 137.) flag. For example: + + $ mypy -c 'x = [1, 2]; print(x())' + + …will type check the above string as a mini-program (and in this + case, will report that ‘list[int]’ is not callable). + + +File: Mypy.info, Node: Reading a list of files from a file, Next: How mypy handles imports, Prev: Specifying code to be checked, Up: Running mypy and managing imports + +22.2 Reading a list of files from a file +======================================== + +Finally, any command-line argument starting with ‘@’ reads additional +command-line arguments from the file following the ‘@’ character. This +is primarily useful if you have a file containing a list of files that +you want to be type-checked: instead of using shell syntax like: + + $ mypy $(cat file_of_files.txt) + +you can use this instead: + + $ mypy @file_of_files.txt + +This file can technically also contain any command line flag, not just +file paths. However, if you want to configure many different flags, the +recommended approach is to use a *note configuration file: 2e. instead. + + +File: Mypy.info, Node: How mypy handles imports, Next: Missing imports, Prev: Reading a list of files from a file, Up: Running mypy and managing imports + +22.3 How mypy handles imports +============================= + +When mypy encounters an ‘import’ statement, it will first *note attempt +to locate: 135. that module or type stubs for that module in the file +system. Mypy will then type check the imported module. There are three +different outcomes of this process: + + 1. Mypy is unable to follow the import: the module either does not + exist, or is a third party library that does not use type hints. + + 2. Mypy is able to follow and type check the import, but you did not + want mypy to type check that module at all. + + 3. Mypy is able to successfully both follow and type check the module, + and you want mypy to type check that module. + +The third outcome is what mypy will do in the ideal case. The following +sections will discuss what to do in the other two cases. + + +File: Mypy.info, Node: Missing imports, Next: Following imports, Prev: How mypy handles imports, Up: Running mypy and managing imports + +22.4 Missing imports +==================== + +When you import a module, mypy may report that it is unable to follow +the import. This can cause errors that look like the following: + + main.py:1: error: Skipping analyzing 'django': module is installed, but missing library stubs or py.typed marker + main.py:2: error: Library stubs not installed for "requests" (or incompatible with Python 3.8) + main.py:3: error: Cannot find implementation or library stub for module named "this_module_does_not_exist" + +If you get any of these errors on an import, mypy will assume the type +of that module is ‘Any’, the dynamic type. This means attempting to +access any attribute of the module will automatically succeed: + + # Error: Cannot find implementation or library stub for module named 'does_not_exist' + import does_not_exist + + # But this type checks, and x will have type 'Any' + x = does_not_exist.foobar() + +The next sections describe what each of these errors means and +recommended next steps; scroll to the section that matches your error. + +* Menu: + +* Missing library stubs or py.typed marker: Missing library stubs or py typed marker. +* Library stubs not installed:: +* Cannot find implementation or library stub:: + + +File: Mypy.info, Node: Missing library stubs or py typed marker, Next: Library stubs not installed, Up: Missing imports + +22.4.1 Missing library stubs or py.typed marker +----------------------------------------------- + +If you are getting a ‘Skipping analyzing X: module is installed, but +missing library stubs or py.typed marker’, error, this means mypy was +able to find the module you were importing, but no corresponding type +hints. + +Mypy will not try inferring the types of any 3rd party libraries you +have installed unless they either have declared themselves to be *note +PEP 561 compliant stub package: 15. (e.g. with a ‘py.typed’ file) or +have registered themselves on typeshed(1), the repository of types for +the standard library and some 3rd party libraries. + +If you are getting this error, try: + + 1. Upgrading the version of the library you’re using, in case a newer + version has started to include type hints. + + 2. Searching to see if there is a *note PEP 561 compliant stub + package: 15. corresponding to your third party library. Stub + packages let you install type hints independently from the library + itself. + + For example, if you want type hints for the ‘django’ library, you + can install the django-stubs(2) package. + + 3. *note Writing your own stub files: 16. containing type hints for + the library. You can point mypy at your type hints either by + passing them in via the command line, by using the *note files: + 13c. or *note mypy_path: 13d. config file options, or by adding the + location to the ‘MYPYPATH’ environment variable. + + These stub files do not need to be complete! A good strategy is to + use stubgen, a program that comes bundled with mypy, to generate a + first rough draft of the stubs. You can then iterate on just the + parts of the library you need. + + If you want to share your work, you can try contributing your stubs + back to the library – see our documentation on creating *note PEP + 561 compliant packages: 15. + +If you are unable to find any existing type hints nor have time to write +your own, you can instead `suppress' the errors. All this will do is +make mypy stop reporting an error on the line containing the import: the +imported module will continue to be of type ‘Any’. + + 1. To suppress a `single' missing import error, add a ‘# type: ignore’ + at the end of the line containing the import. + + 2. To suppress `all' missing import imports errors from a single + library, add a section to your *note mypy config file: 2e. for that + library setting *note ignore_missing_imports: 13e. to True. For + example, suppose your codebase makes heavy use of an (untyped) + library named ‘foobar’. You can silence all import errors + associated with that library and that library alone by adding the + following section to your config file: + + [mypy-foobar.*] + ignore_missing_imports = True + + Note: this option is equivalent to adding a ‘# type: ignore’ to + every import of ‘foobar’ in your codebase. For more information, + see the documentation about configuring *note import discovery: + 13f. in config files. The ‘.*’ after ‘foobar’ will ignore imports + of ‘foobar’ modules and subpackages in addition to the ‘foobar’ + top-level package namespace. + + 3. To suppress `all' missing import errors for `all' libraries in your + codebase, invoke mypy with the *note –ignore-missing-imports: 140. + command line flag or set the *note ignore_missing_imports: 13e. + config file option to True in the `global' section of your mypy + config file: + + [mypy] + ignore_missing_imports = True + + We recommend using this approach only as a last resort: it’s + equivalent to adding a ‘# type: ignore’ to all unresolved imports + in your codebase. + + ---------- Footnotes ---------- + + (1) https://github.com/python/typeshed + + (2) https://pypi.org/project/django-stubs/ + + +File: Mypy.info, Node: Library stubs not installed, Next: Cannot find implementation or library stub, Prev: Missing library stubs or py typed marker, Up: Missing imports + +22.4.2 Library stubs not installed +---------------------------------- + +If mypy can’t find stubs for a third-party library, and it knows that +stubs exist for the library, you will get a message like this: + + main.py:1: error: Library stubs not installed for "yaml" (or incompatible with Python 3.8) + main.py:1: note: Hint: "python3 -m pip install types-PyYAML" + main.py:1: note: (or run "mypy --install-types" to install all missing stub packages) + +You can resolve the issue by running the suggested pip command or +commands. Alternatively, you can use *note –install-types: 142. to +install all known missing stubs: + + mypy --install-types + +This installs any stub packages that were suggested in the previous mypy +run. You can also use your normal mypy command line with the extra +*note –install-types: 142. option to install missing stubs at the end of +the run (if any were found). + +Use *note –install-types: 142. with *note –non-interactive: 143. to +install all suggested stub packages without asking for confirmation, +`and' type check your code, in a single command: + + mypy --install-types --non-interactive src/ + +This can be useful in Continuous Integration jobs if you’d prefer not to +manage stub packages manually. This is somewhat slower than explicitly +installing stubs before running mypy, since it may type check your code +twice – the first time to find the missing stubs, and the second time to +type check your code properly after mypy has installed the stubs. + + +File: Mypy.info, Node: Cannot find implementation or library stub, Prev: Library stubs not installed, Up: Missing imports + +22.4.3 Cannot find implementation or library stub +------------------------------------------------- + +If you are getting a ‘Cannot find implementation or library stub for +module’ error, this means mypy was not able to find the module you are +trying to import, whether it comes bundled with type hints or not. If +you are getting this error, try: + + 1. Making sure your import does not contain a typo. + + 2. If the module is a third party library, making sure that mypy is + able to find the interpreter containing the installed library. + + For example, if you are running your code in a virtualenv, make + sure to install and use mypy within the virtualenv. Alternatively, + if you want to use a globally installed mypy, set the *note + –python-executable: 146. command line flag to point the Python + interpreter containing your installed third party packages. + + 2. Reading the *note How imports are found: 135. section below to make + sure you understand how exactly mypy searches for and finds modules + and modify how you’re invoking mypy accordingly. + + 3. Directly specifying the directory containing the module you want to + type check from the command line, by using the *note mypy_path: + 13d. or *note files: 13c. config file options, or by using the + ‘MYPYPATH’ environment variable. + + Note: if the module you are trying to import is actually a + `submodule' of some package, you should specify the directory + containing the `entire' package. For example, suppose you are + trying to add the module ‘foo.bar.baz’ which is located at + ‘~/foo-project/src/foo/bar/baz.py’. In this case, you must run + ‘mypy ~/foo-project/src’ (or set the ‘MYPYPATH’ to + ‘~/foo-project/src’. + + 4. If you are using namespace packages – packages which do not contain + ‘__init__.py’ files within each subfolder – using the *note + –namespace-packages: 132. command line flag. + +In some rare cases, you may get the “Cannot find implementation or +library stub for module” error even when the module is installed in your +system. This can happen when the module is both missing type hints and +is installed on your system in a unconventional way. + +In this case, follow the steps above on how to handle *note missing type +hints in third party libraries: 145. + + +File: Mypy.info, Node: Following imports, Next: Mapping file paths to modules, Prev: Missing imports, Up: Running mypy and managing imports + +22.5 Following imports +====================== + +Mypy is designed to *note doggedly follow all imports: 135, even if the +imported module is not a file you explicitly wanted mypy to check. + +For example, suppose we have two modules ‘mycode.foo’ and ‘mycode.bar’: +the former has type hints and the latter does not. We run *note mypy -m +mycode.foo: 134. and mypy discovers that ‘mycode.foo’ imports +‘mycode.bar’. + +How do we want mypy to type check ‘mycode.bar’? Mypy’s behaviour here +is configurable – although we `strongly recommend' using the default – +by using the *note –follow-imports: 148. flag. This flag accepts one of +four string values: + + - ‘normal’ (the default, recommended) follows all imports normally + and type checks all top level code (as well as the bodies of all + functions and methods with at least one type annotation in the + signature). + + - ‘silent’ behaves in the same way as ‘normal’ but will additionally + `suppress' any error messages. + + - ‘skip’ will `not' follow imports and instead will silently replace + the module (and `anything imported from it') with an object of type + ‘Any’. + + - ‘error’ behaves in the same way as ‘skip’ but is not quite as + silent – it will flag the import as an error, like this: + + main.py:1: note: Import of "mycode.bar" ignored + main.py:1: note: (Using --follow-imports=error, module not passed on command line) + +If you are starting a new codebase and plan on using type hints from the +start, we recommend you use either *note –follow-imports=normal: 148. +(the default) or *note –follow-imports=error: 148. Either option will +help make sure you are not skipping checking any part of your codebase +by accident. + +If you are planning on adding type hints to a large, existing code base, +we recommend you start by trying to make your entire codebase (including +files that do not use type hints) pass under *note +–follow-imports=normal: 148. This is usually not too difficult to do: +mypy is designed to report as few error messages as possible when it is +looking at unannotated code. + +Only if doing this is intractable, we recommend passing mypy just the +files you want to type check and use *note –follow-imports=silent: 148. +Even if mypy is unable to perfectly type check a file, it can still +glean some useful information by parsing it (for example, understanding +what methods a given object has). See *note Using mypy with an existing +codebase: 1a. for more recommendations. + +We do not recommend using ‘skip’ unless you know what you are doing: +while this option can be quite powerful, it can also cause many +hard-to-debug errors. + +Adjusting import following behaviour is often most useful when +restricted to specific modules. This can be accomplished by setting a +per-module *note follow_imports: 149. config option. + + +File: Mypy.info, Node: Mapping file paths to modules, Next: How imports are found, Prev: Following imports, Up: Running mypy and managing imports + +22.6 Mapping file paths to modules +================================== + +One of the main ways you can tell mypy what to type check is by +providing mypy a list of paths. For example: + + $ mypy file_1.py foo/file_2.py file_3.pyi some/directory + +This section describes how exactly mypy maps the provided paths to +modules to type check. + + - Mypy will check all paths provided that correspond to files. + + - Mypy will recursively discover and check all files ending in ‘.py’ + or ‘.pyi’ in directory paths provided, after accounting for *note + –exclude: 14b. + + - For each file to be checked, mypy will attempt to associate the + file (e.g. ‘project/foo/bar/baz.py’) with a fully qualified module + name (e.g. ‘foo.bar.baz’). The directory the package is in + (‘project’) is then added to mypy’s module search paths. + +How mypy determines fully qualified module names depends on if the +options *note –namespace-packages: 132. and *note +–explicit-package-bases: 14c. are set. + + 1. If *note –namespace-packages: 132. is off, mypy will rely solely + upon the presence of ‘__init__.py[i]’ files to determine the fully + qualified module name. That is, mypy will crawl up the directory + tree for as long as it continues to find ‘__init__.py’ (or + ‘__init__.pyi’) files. + + For example, if your directory tree consists of + ‘pkg/subpkg/mod.py’, mypy would require ‘pkg/__init__.py’ and + ‘pkg/subpkg/__init__.py’ to exist in order correctly associate + ‘mod.py’ with ‘pkg.subpkg.mod’ + + 2. If *note –namespace-packages: 132. is on, but *note + –explicit-package-bases: 14c. is off, mypy will allow for the + possibility that directories without ‘__init__.py[i]’ are packages. + Specifically, mypy will look at all parent directories of the file + and use the location of the highest ‘__init__.py[i]’ in the + directory tree to determine the top-level package. + + For example, say your directory tree consists solely of + ‘pkg/__init__.py’ and ‘pkg/a/b/c/d/mod.py’. When determining + ‘mod.py’’s fully qualified module name, mypy will look at + ‘pkg/__init__.py’ and conclude that the associated module name is + ‘pkg.a.b.c.d.mod’. + + 3. You’ll notice that the above case still relies on ‘__init__.py’. + If you can’t put an ‘__init__.py’ in your top-level package, but + still wish to pass paths (as opposed to packages or modules using + the ‘-p’ or ‘-m’ flags), *note –explicit-package-bases: 14c. + provides a solution. + + With *note –explicit-package-bases: 14c, mypy will locate the + nearest parent directory that is a member of the ‘MYPYPATH’ + environment variable, the *note mypy_path: 13d. config or is the + current working directory. Mypy will then use the relative path to + determine the fully qualified module name. + + For example, say your directory tree consists solely of + ‘src/namespace_pkg/mod.py’. If you run the following command, mypy + will correctly associate ‘mod.py’ with ‘namespace_pkg.mod’: + + $ MYPYPATH=src mypy --namespace-packages --explicit-package-bases . + +If you pass a file not ending in ‘.py[i]’, the module name assumed is +‘__main__’ (matching the behavior of the Python interpreter), unless +*note –scripts-are-modules: 14d. is passed. + +Passing *note -v: 14e. will show you the files and associated module +names that mypy will check. + + +File: Mypy.info, Node: How imports are found, Next: Other advice and best practices, Prev: Mapping file paths to modules, Up: Running mypy and managing imports + +22.7 How imports are found +========================== + +When mypy encounters an ‘import’ statement or receives module names from +the command line via the *note –module: 134. or *note –package: 136. +flags, mypy tries to find the module on the file system similar to the +way Python finds it. However, there are some differences. + +First, mypy has its own search path. This is computed from the +following items: + + - The ‘MYPYPATH’ environment variable (a colon-separated list of + directories). + + - The *note mypy_path: 13d. config file option. + + - The directories containing the sources given on the command line + (see *note Mapping file paths to modules: 133.). + + - The installed packages marked as safe for type checking (see *note + PEP 561 support: 15.) + + - The relevant directories of the typeshed(1) repo. + + Note: You cannot point to a stub-only package ( PEP 561(2)) via the + ‘MYPYPATH’, it must be installed (see *note PEP 561 support: 15.) + +Second, mypy searches for stub files in addition to regular Python files +and packages. The rules for searching for a module ‘foo’ are as +follows: + + - The search looks in each of the directories in the search path (see + above) until a match is found. + + - If a package named ‘foo’ is found (i.e. a directory ‘foo’ + containing an ‘__init__.py’ or ‘__init__.pyi’ file) that’s a match. + + - If a stub file named ‘foo.pyi’ is found, that’s a match. + + - If a Python module named ‘foo.py’ is found, that’s a match. + +These matches are tried in order, so that if multiple matches are found +in the same directory on the search path (e.g. a package and a Python +file, or a stub file and a Python file) the first one in the above list +wins. + +In particular, if a Python file and a stub file are both present in the +same directory on the search path, only the stub file is used. +(However, if the files are in different directories, the one found in +the earlier directory is used.) + + ---------- Footnotes ---------- + + (1) https://github.com/python/typeshed + + (2) https://peps.python.org/pep-0561/ + + +File: Mypy.info, Node: Other advice and best practices, Next: Directories specific to Python 2 @python2, Prev: How imports are found, Up: Running mypy and managing imports + +22.8 Other advice and best practices +==================================== + +There are multiple ways of telling mypy what files to type check, +ranging from passing in command line arguments to using the *note files: +13c. or *note mypy_path: 13d. config file options to setting the +‘MYPYPATH’ environment variable. + +However, in practice, it is usually sufficient to just use either +command line arguments or the *note files: 13c. config file option (the +two are largely interchangeable). + +Setting *note mypy_path: 13d./‘MYPYPATH’ is mostly useful in the case +where you want to try running mypy against multiple distinct sets of +files that happen to share some common dependencies. + +For example, if you have multiple projects that happen to be using the +same set of work-in-progress stubs, it could be convenient to just have +your ‘MYPYPATH’ point to a single directory containing the stubs. + + +File: Mypy.info, Node: Directories specific to Python 2 @python2, Prev: Other advice and best practices, Up: Running mypy and managing imports + +22.9 Directories specific to Python 2 (@python2) +================================================ + +When type checking in Python 2 mode, mypy also looks for files under the +‘@python2’ subdirectory of each ‘MYPYPATH’ and ‘mypy_path’ entry, if the +subdirectory exists. Files under the subdirectory take precedence over +the parent directory. This can be used to provide separate Python 2 +versions of stubs. + + Note: This does not need to be used (and cannot be used) with *note + PEP 561 compliant stub packages: 15. + + +File: Mypy.info, Node: The mypy command line, Next: The mypy configuration file, Prev: Running mypy and managing imports, Up: Top + +23 The mypy command line +************************ + +This section documents mypy’s command line interface. You can view a +quick summary of the available flags by running *note mypy –help: 154. + + Note: Command line flags are liable to change between releases. + +* Menu: + +* Specifying what to type check:: +* Optional arguments:: +* Config file:: +* Import discovery:: +* Platform configuration:: +* Disallow dynamic typing:: +* Untyped definitions and calls:: +* None and Optional handling:: +* Configuring warnings:: +* Miscellaneous strictness flags:: +* Configuring error messages:: +* Incremental mode:: +* Advanced options:: +* Report generation:: +* Miscellaneous: Miscellaneous<3>. + + +File: Mypy.info, Node: Specifying what to type check, Next: Optional arguments, Up: The mypy command line + +23.1 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 *note Running mypy and managing imports: 12e. + + -- 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 *note –module: 134. 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 *note import + following: 22. You can use a per-module *note follow_imports: 149. + 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’. + + +File: Mypy.info, Node: Optional arguments, Next: Config file, Prev: Specifying what to type check, Up: The mypy command line + +23.2 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. + + +File: Mypy.info, Node: Config file, Next: Import discovery, Prev: Optional arguments, Up: The mypy command line + +23.3 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 *note –config-file=: 160. (with no filename) will ignore + `all' config files. + + See *note The mypy configuration file: 2e. 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 + *note –no-incremental: 162.) + + +File: Mypy.info, Node: Import discovery, Next: Platform configuration, Prev: Config file, Up: The mypy command line + +23.4 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(1)). 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 *note mypy_path: 13d. 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 *note Mapping file paths to modules: 133. 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 *note mypy_path: 13d. config option. This + option is only useful in conjunction with *note + –namespace-packages: 132. See *note Mapping file paths to modules: + 133. 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 *note + –ignore-missing-imports: 140.: + + 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 *note Missing imports: 17. + + -- 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 + *note Following imports: 22. + + -- Option: --python-executable EXECUTABLE + + This flag will have mypy collect type information from PEP 561(2) + 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 *note Using installed packages: 15. for more on making PEP 561 + compliant packages. + + -- Option: --no-site-packages + + This flag will disable searching for PEP 561(3) 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 *note –python-executable: 146. + + -- Option: --no-silence-site-packages + + By default, mypy will suppress any error messages generated within + PEP 561(4) compliant packages. Adding this flag will disable this + behavior. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0420/ + + (2) https://peps.python.org/pep-0561/ + + (3) https://peps.python.org/pep-0561/ + + (4) https://peps.python.org/pep-0561/ + + +File: Mypy.info, Node: Platform configuration, Next: Disallow dynamic typing, Prev: Import discovery, Up: The mypy command line + +23.5 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 *note Python version +and system platform checks: fd. + + -- 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 + *note -2: 8. and *note –py2: 8. flags are aliases for *note + –python-version 2.7: 100. + + This flag will attempt to find a Python executable of the + corresponding version to search for PEP 561(1) compliant packages. + If you’d like to disable this, use the *note –no-site-packages: + 165. flag (see *note Import discovery: 164. for more details). + + -- Option: -2, --py2 + + Equivalent to running *note –python-version 2.7: 100. + + 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 + sys.platform(2). + -- 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. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0561/ + + (2) https://docs.python.org/3/library/sys.html#sys.platform + + +File: Mypy.info, Node: Disallow dynamic typing, Next: Untyped definitions and calls, Prev: Platform configuration, Up: The mypy command line + +23.6 Disallow dynamic typing +============================ + +The ‘Any’ type is used to represent a value that has a *note dynamic +type: 4b. 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 *note + –follow-imports=skip: 148. 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 cast()(1) 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 *note + –ignore-missing-imports: 140.) or is ignored due to *note + –follow-imports=skip: 148. 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.cast + + +File: Mypy.info, Node: Untyped definitions and calls, Next: None and Optional handling, Prev: Disallow dynamic typing, Up: The mypy command line + +23.7 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. + + +File: Mypy.info, Node: None and Optional handling, Next: Configuring warnings, Prev: Untyped definitions and calls, Up: The mypy command line + +23.8 None and Optional handling +=============================== + +The following flags adjust how mypy handles values of type ‘None’. For +more details, see *note Disabling strict optional checking: 70. + -- Option: --no-implicit-optional + + This flag causes mypy to stop treating arguments with a ‘None’ + default value as having an implicit Optional(1) 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’: + + 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]’: + + def foo(x: Optional[int] = None) -> None: + print(x) + + -- Option: --no-strict-optional + + This flag disables strict checking of Optional(2) types and ‘None’ + values. With this option, mypy doesn’t generally check the use of + ‘None’ values – they are valid everywhere. See *note Disabling + strict optional checking: 70. 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). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Optional + + (2) https://docs.python.org/3/library/typing.html#typing.Optional + + +File: Mypy.info, Node: Configuring warnings, Next: Miscellaneous strictness flags, Prev: None and Optional handling, Up: The mypy command line + +23.9 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 *note –warn-redundant-casts: 17d. 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 *note –no-warn-no-return: 17f. 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. + + 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 + NoReturn(1) 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 *note Python version and system platform + checks: fd. + + Note: Mypy currently cannot detect and report unreachable or + redundant code inside any functions using *note Type variables + with value restriction: 7c. + + This limitation will be removed in future releases of mypy. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.NoReturn + + +File: Mypy.info, Node: Miscellaneous strictness flags, Next: Configuring error messages, Prev: Configuring warnings, Up: The mypy command line + +23.10 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: + + 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: + + 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: + + 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: + + # 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: + + 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 *note mypy + –help: 154. output. + + Note: the exact list of flags enabled by running *note –strict: 19. + may change over time. + + -- Option: --disable-error-code + + This flag allows disabling one or multiple error codes globally. + + # 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 + + # --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] + + +File: Mypy.info, Node: Configuring error messages, Next: Incremental mode, Prev: Miscellaneous strictness flags, Up: The mypy command line + +23.11 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: + + 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 *note Error codes: 18e. 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. + + +File: Mypy.info, Node: Incremental mode, Next: Advanced options, Prev: Configuring error messages, Up: The mypy command line + +23.12 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 *note daemon mode: +29. + + -- 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 *note –cache-dir: 196. 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 *note remote caching: 2a. + + 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(1) 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. + + ---------- Footnotes ---------- + + (1) https://www.sqlite.org/ + + +File: Mypy.info, Node: Advanced options, Next: Report generation, Prev: Incremental mode, Up: The mypy command line + +23.13 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 + typing(1) 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. + -- Option: --warn-incomplete-stub + + This flag modifies both the *note –disallow-untyped-defs: b. and + *note –disallow-incomplete-defs: 176. flags so they also report + errors if stubs in typeshed are missing type annotations or has + incomplete annotations. If both flags are missing, *note + –warn-incomplete-stub: 1a3. 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 *note –disallow-untyped-calls: 175. flag. See *note + Untyped definitions and calls: fb. for more details. + -- 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’. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Report generation, Next: Miscellaneous<3>, Prev: Advanced options, Up: The mypy command line + +23.14 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(1) 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(2) 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(3) 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(4) library or specify mypy installation with the setuptools + extra ‘mypy[reports]’. + + ---------- Footnotes ---------- + + (1) https://pypi.org/project/lxml/ + + (2) https://pypi.org/project/lxml/ + + (3) https://pypi.org/project/lxml/ + + (4) https://pypi.org/project/lxml/ + + +File: Mypy.info, Node: Miscellaneous<3>, Prev: Report generation, Up: The mypy command line + +23.15 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 *note –install-types: 142, 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 + __main__(1). + + This lets you check more than one script in a single mypy + invocation. (The default __main__(2) 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.) + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/__main__.html#module-__main__ + + (2) https://docs.python.org/3/library/__main__.html#module-__main__ + + +File: Mypy.info, Node: The mypy configuration file, Next: Inline configuration, Prev: The mypy command line, Up: Top + +24 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 *note –config-file: 160. command-line flag can be used to +read a different file instead (see *note Config file: 15f.). + +It is important to understand that there is no merging of configuration +files, as it would lead to ambiguity. The *note –config-file: 160. 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 *note command-line flags: c. 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}’. + +* Menu: + +* Config file format:: +* Per-module and global options:: +* Inverting option values:: +* Examples:: +* Import discovery: Import discovery<2>. +* Platform configuration: Platform configuration<2>. +* Disallow dynamic typing: Disallow dynamic typing<2>. +* Untyped definitions and calls: Untyped definitions and calls<2>. +* None and Optional handling: None and Optional handling<2>. +* Configuring warnings: Configuring warnings<2>. +* Suppressing errors:: +* Miscellaneous strictness flags: Miscellaneous strictness flags<2>. +* Configuring error messages: Configuring error messages<2>. +* Incremental mode: Incremental mode<2>. +* Advanced options: Advanced options<2>. +* Report generation: Report generation<2>. +* Miscellaneous: Miscellaneous<4>. +* Using a pyproject.toml file: Using a pyproject toml file. +* Example pyproject.toml: Example pyproject toml. + + +File: Mypy.info, Node: Config file format, Next: Per-module and global options, Up: The mypy configuration file + +24.1 Config file format +======================= + +The configuration file format is the usual ini file(1) 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’). When options conflict, the precedence + order for configuration is: + + 1. *note Inline configuration: 1b7. 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 *note warn_unused_configs: 1b8. flag may be useful to + debug misspelled section names. + + Note: Configuration flags are liable to change between releases. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/configparser.html + + +File: Mypy.info, Node: Per-module and global options, Next: Inverting option values, Prev: Config file format, Up: The mypy configuration file + +24.2 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, *note the options from the most +specific section are used where they disagree: 1b6. + +Some other options, as specified in their description, may only be set +in the global section (‘[mypy]’). + + +File: Mypy.info, Node: Inverting option values, Next: Examples, Prev: Per-module and global options, Up: The mypy configuration file + +24.3 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). + + +File: Mypy.info, Node: Examples, Next: Import discovery<2>, Prev: Inverting option values, Up: The mypy configuration file + +24.4 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. + + # 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 *note –python-version 2.7: + 100. or *note -2: 8. 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. + + +File: Mypy.info, Node: Import discovery<2>, Next: Platform configuration<2>, Prev: Examples, Up: The mypy configuration file + +24.5 Import discovery +===================== + +For more information, see the *note Import discovery: 164. section of +the command line docs. + + -- Configuration Value: 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). + + -- Configuration Value: 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 glob(1), 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]’). + + -- Configuration Value: 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. + + [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(2). The above is equivalent to: + ‘(^one\.py$|two\.pyi$|^three\.)’. + + For more details, see *note –exclude: 14b. + + 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: + + [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: + + [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 *note Using a pyproject.toml file: 1be. + + -- Configuration Value: namespace_packages + + + Type: boolean + + + Default: False + + Enables PEP 420(3) style namespace packages. See the corresponding + flag *note –namespace-packages: 132. for more information. + + This option may only be set in the global section (‘[mypy]’). + + -- Configuration Value: 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 *note mypy_path: 13d. config option. This + option is only useful in conjunction with *note namespace_packages: + 1bf. See *note Mapping file paths to modules: 133. for details. + + This option may only be set in the global section (‘[mypy]’). + + -- Configuration Value: 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. + + -- Configuration Value: 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 *note + –follow-imports: 148. 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. + + -- Configuration Value: follow_imports_for_stubs + + + Type: boolean + + + Default: False + + Determines whether to respect the *note follow_imports: 149. + setting even for stub (‘.pyi’) files. + + Used in conjunction with *note follow_imports=skip: 149, this can + be used to suppress the import of a module from ‘typeshed’, + replacing it with ‘Any’. + + Used in conjunction with *note follow_imports=error: 149, this can + be used to make any use of a particular ‘typeshed’ module an error. + + Note: This is not supported by the mypy daemon. + + -- Configuration Value: python_executable + + + Type: string + + Specifies the path to the Python executable to inspect to collect a + list of available *note PEP 561 packages: 15. 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]’). + + -- Configuration Value: no_site_packages + + + Type: bool + + + Default: False + + Disables using type information in installed packages (see PEP + 561(4)). This will also disable searching for a usable Python + executable. This acts the same as *note –no-site-packages: 165. + command line flag. + + -- Configuration Value: no_silence_site_packages + + + Type: boolean + + + Default: False + + Enables reporting error messages generated within installed + packages (see PEP 561(5) 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]’). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/glob.html#module-glob + + (2) https://docs.python.org/3/library/re.html#re.X + + (3) https://peps.python.org/pep-0420/ + + (4) https://peps.python.org/pep-0561/ + + (5) https://peps.python.org/pep-0561/ + + +File: Mypy.info, Node: Platform configuration<2>, Next: Disallow dynamic typing<2>, Prev: Import discovery<2>, Up: The mypy configuration file + +24.6 Platform configuration +=========================== + + -- Configuration Value: 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]’). + + -- Configuration Value: 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 + sys.platform(1) variable. + + This option may only be set in the global section (‘[mypy]’). + + -- Configuration Value: 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. + + -- Configuration Value: 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/sys.html#sys.platform + + +File: Mypy.info, Node: Disallow dynamic typing<2>, Next: Untyped definitions and calls<2>, Prev: Platform configuration<2>, Up: The mypy configuration file + +24.7 Disallow dynamic typing +============================ + +For more information, see the *note Disallow dynamic typing: 16c. +section of the command line docs. + + -- Configuration Value: 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’). + + -- Configuration Value: disallow_any_expr + + + Type: boolean + + + Default: False + + Disallows all expressions in the module that have type ‘Any’. + + -- Configuration Value: disallow_any_decorated + + + Type: boolean + + + Default: False + + Disallows functions that have ‘Any’ in their signature after + decorator transformation. + + -- Configuration Value: disallow_any_explicit + + + Type: boolean + + + Default: False + + Disallows explicit ‘Any’ in type positions such as type annotations + and generic type parameters. + + -- Configuration Value: disallow_any_generics + + + Type: boolean + + + Default: False + + Disallows usage of generic types that do not specify explicit type + parameters. + + -- Configuration Value: disallow_subclassing_any + + + Type: boolean + + + Default: False + + Disallows subclassing a value of type ‘Any’. + + +File: Mypy.info, Node: Untyped definitions and calls<2>, Next: None and Optional handling<2>, Prev: Disallow dynamic typing<2>, Up: The mypy configuration file + +24.8 Untyped definitions and calls +================================== + +For more information, see the *note Untyped definitions and calls: fb. +section of the command line docs. + + -- Configuration Value: disallow_untyped_calls + + + Type: boolean + + + Default: False + + Disallows calling functions without type annotations from functions + with type annotations. + + -- Configuration Value: disallow_untyped_defs + + + Type: boolean + + + Default: False + + Disallows defining functions without type annotations or with + incomplete type annotations. + + -- Configuration Value: disallow_incomplete_defs + + + Type: boolean + + + Default: False + + Disallows defining functions with incomplete type annotations. + + -- Configuration Value: check_untyped_defs + + + Type: boolean + + + Default: False + + Type-checks the interior of functions without type annotations. + + -- Configuration Value: disallow_untyped_decorators + + + Type: boolean + + + Default: False + + Reports an error whenever a function with type annotations is + decorated with a decorator without annotations. + + +File: Mypy.info, Node: None and Optional handling<2>, Next: Configuring warnings<2>, Prev: Untyped definitions and calls<2>, Up: The mypy configuration file + +24.9 None and Optional handling +=============================== + +For more information, see the *note None and Optional handling: 179. +section of the command line docs. + + -- Configuration Value: no_implicit_optional + + + Type: boolean + + + Default: False + + Changes the treatment of arguments with a default value of ‘None’ + by not implicitly making their type Optional(1). + + -- Configuration Value: 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Optional + + +File: Mypy.info, Node: Configuring warnings<2>, Next: Suppressing errors, Prev: None and Optional handling<2>, Up: The mypy configuration file + +24.10 Configuring warnings +========================== + +For more information, see the *note Configuring warnings: 17b. section +of the command line docs. + + -- Configuration Value: 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]’). + + -- Configuration Value: warn_unused_ignores + + + Type: boolean + + + Default: False + + Warns about unneeded ‘# type: ignore’ comments. + + -- Configuration Value: warn_no_return + + + Type: boolean + + + Default: True + + Shows errors for missing return statements on some execution paths. + + -- Configuration Value: 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. + + -- Configuration Value: warn_unreachable + + + Type: boolean + + + Default: False + + Shows a warning when encountering any code inferred to be + unreachable or redundant after performing type analysis. + + +File: Mypy.info, Node: Suppressing errors, Next: Miscellaneous strictness flags<2>, Prev: Configuring warnings<2>, Up: The mypy configuration file + +24.11 Suppressing errors +======================== + +Note: these configuration options are available in the config file only. +There is no analog available via the command line options. + + -- Configuration Value: show_none_errors + + + Type: boolean + + + Default: True + + Shows errors related to strict ‘None’ checking, if the global *note + strict_optional: 72. flag is enabled. + + -- Configuration Value: ignore_errors + + + Type: boolean + + + Default: False + + Ignores all non-fatal errors. + + +File: Mypy.info, Node: Miscellaneous strictness flags<2>, Next: Configuring error messages<2>, Prev: Suppressing errors, Up: The mypy configuration file + +24.12 Miscellaneous strictness flags +==================================== + +For more information, see the *note Miscellaneous strictness flags: 182. +section of the command line docs. + + -- Configuration Value: 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. + + -- Configuration Value: 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: + + 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: + + 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 + + -- Configuration Value: 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 *note mypy daemon: 29. + + -- Configuration Value: disable_error_code + + + Type: comma-separated list of strings + + Allows disabling one or multiple error codes globally. + + -- Configuration Value: 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: + + # 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'] + + -- Configuration Value: strict_equality + + + type: boolean + + + default: False + + Prohibit equality checks, identity checks, and container checks + between non-overlapping types. + + -- Configuration Value: 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 *note mypy –help: 154. + output. + + Note: the exact list of flags enabled by *note strict: 1e8. may + change over time. + + +File: Mypy.info, Node: Configuring error messages<2>, Next: Incremental mode<2>, Prev: Miscellaneous strictness flags<2>, Up: The mypy configuration file + +24.13 Configuring error messages +================================ + +For more information, see the *note Configuring error messages: 18a. +section of the command line docs. + +These options may only be set in the global section (‘[mypy]’). + + -- Configuration Value: show_error_context + + + Type: boolean + + + Default: False + + Prefixes each error with the relevant context. + + -- Configuration Value: show_column_numbers + + + Type: boolean + + + Default: False + + Shows column numbers in error messages. + + -- Configuration Value: show_error_codes + + + Type: boolean + + + Default: False + + Shows error codes in error messages. See *note Error codes: 18e. + for more information. + + -- Configuration Value: 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. + + -- Configuration Value: color_output + + + Type: boolean + + + Default: True + + Shows error messages with color enabled. + + -- Configuration Value: error_summary + + + Type: boolean + + + Default: True + + Shows a short summary line after error messages. + + -- Configuration Value: show_absolute_path + + + Type: boolean + + + Default: False + + Show absolute paths to files. + + +File: Mypy.info, Node: Incremental mode<2>, Next: Advanced options<2>, Prev: Configuring error messages<2>, Up: The mypy configuration file + +24.14 Incremental mode +====================== + +These options may only be set in the global section (‘[mypy]’). + + -- Configuration Value: incremental + + + Type: boolean + + + Default: True + + Enables *note incremental mode: 194. + + -- Configuration Value: 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). + + -- Configuration Value: sqlite_cache + + + Type: boolean + + + Default: False + + Use an SQLite(1) database to store the cache. + + -- Configuration Value: cache_fine_grained + + + Type: boolean + + + Default: False + + Include fine-grained dependency information in the cache for the + mypy daemon. + + -- Configuration Value: 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.) + + -- Configuration Value: skip_cache_mtime_checks + + + Type: boolean + + + Default: False + + Skip cache internal consistency checks based on mtime. + + ---------- Footnotes ---------- + + (1) https://www.sqlite.org/ + + +File: Mypy.info, Node: Advanced options<2>, Next: Report generation<2>, Prev: Incremental mode<2>, Up: The mypy configuration file + +24.15 Advanced options +====================== + +These options may only be set in the global section (‘[mypy]’). + + -- Configuration Value: plugins + + + Type: comma-separated list of strings + + A comma-separated list of mypy plugins. See *note Extending mypy + using plugins: 1fa. + + -- Configuration Value: pdb + + + Type: boolean + + + Default: False + + Invokes pdb(1) on fatal error. + + -- Configuration Value: show_traceback + + + Type: boolean + + + Default: False + + Shows traceback on fatal error. + + -- Configuration Value: raise_exceptions + + + Type: boolean + + + Default: False + + Raise exception on fatal error. + + -- Configuration Value: custom_typing_module + + + Type: string + + Specifies a custom module to use as a substitute for the typing(2) + module. + + -- Configuration Value: 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. + + -- Configuration Value: warn_incomplete_stub + + + Type: boolean + + + Default: False + + Warns about missing type annotations in typeshed. This is only + relevant in combination with *note disallow_untyped_defs: 2c. or + *note disallow_incomplete_defs: 1d3. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/pdb.html#module-pdb + + (2) https://docs.python.org/3/library/typing.html#module-typing + + +File: Mypy.info, Node: Report generation<2>, Next: Miscellaneous<4>, Prev: Advanced options<2>, Up: The mypy configuration file + +24.16 Report generation +======================= + +If these options are set, mypy will generate a report in the specified +format into the specified directory. + + -- Configuration Value: 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. + + -- Configuration Value: 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(1) library or specify mypy installation with the setuptools + extra ‘mypy[reports]’. + + -- Configuration Value: 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(2) library or specify mypy installation with the setuptools + extra ‘mypy[reports]’. + + -- Configuration Value: 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. + + -- Configuration Value: 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. + + -- Configuration Value: lineprecision_report + + + Type: string + + Causes mypy to generate a flat text file report with per-module + statistics of how many lines are typechecked etc. + + -- Configuration Value: 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(3) library or specify mypy installation with the setuptools + extra ‘mypy[reports]’. + + -- Configuration Value: 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(4) library or specify mypy installation with the setuptools + extra ‘mypy[reports]’. + + ---------- Footnotes ---------- + + (1) https://pypi.org/project/lxml/ + + (2) https://pypi.org/project/lxml/ + + (3) https://pypi.org/project/lxml/ + + (4) https://pypi.org/project/lxml/ + + +File: Mypy.info, Node: Miscellaneous<4>, Next: Using a pyproject toml file, Prev: Report generation<2>, Up: The mypy configuration file + +24.17 Miscellaneous +=================== + +These options may only be set in the global section (‘[mypy]’). + + -- Configuration Value: 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. + + -- Configuration Value: 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. + + -- Configuration Value: 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 *note incremental = False: 1f2.) + + -- Configuration Value: verbosity + + + Type: integer + + + Default: 0 + + Controls how much debug output will be generated. Higher numbers + are more verbose. + + +File: Mypy.info, Node: Using a pyproject toml file, Next: Example pyproject toml, Prev: Miscellaneous<4>, Up: The mypy configuration file + +24.18 Using a pyproject.toml file +================================= + +Instead of using a ‘mypy.ini’ file, a ‘pyproject.toml’ file (as +specified by PEP 518(1)) 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: + + [[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: + + [[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(2) for more details and information on +what is allowed in a ‘toml’ file. See PEP 518(3) for more information +on the layout and structure of the ‘pyproject.toml’ file. + + ---------- Footnotes ---------- + + (1) https://www.python.org/dev/peps/pep-0518/ + + (2) https://toml.io/ + + (3) https://www.python.org/dev/peps/pep-0518/ + + +File: Mypy.info, Node: Example pyproject toml, Prev: Using a pyproject toml file, Up: The mypy configuration file + +24.19 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. + + # 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 + + +File: Mypy.info, Node: Inline configuration, Next: Mypy daemon mypy server, Prev: The mypy configuration file, Up: Top + +25 Inline configuration +*********************** + +Mypy supports setting per-file configuration options inside files +themselves using ‘# mypy:’ comments. For example: + + # mypy: disallow-any-generics + +Inline configuration comments take precedence over all other +configuration mechanisms. + +* Menu: + +* Configuration comment format:: + + +File: Mypy.info, Node: Configuration comment format, Up: Inline configuration + +25.1 Configuration comment format +================================= + +Flags correspond to *note config file flags: 2e. but allow hyphens to be +substituted for underscores. + +Values are specified using ‘=’, but ‘= True’ may be omitted: + + # 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: + + # 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): + + # mypy: allow-untyped-defs, no-strict-optional + + +File: Mypy.info, Node: Mypy daemon mypy server, Next: Using installed packages, Prev: Inline configuration, Up: Top + +26 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. + +* Menu: + +* Basic usage:: +* Daemon client commands:: +* Additional daemon flags:: +* Static inference of annotations:: + + +File: Mypy.info, Node: Basic usage, Next: Daemon client commands, Up: Mypy daemon mypy server + +26.1 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 *note remote caching: 2a. 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 *note Following + imports: 22. for details on how these work. + + +File: Mypy.info, Node: Daemon client commands, Next: Additional daemon flags, Prev: Basic usage, Up: Mypy daemon mypy server + +26.2 Daemon client commands +=========================== + +While ‘dmypy run’ is sufficient for most uses, some workflows (ones +using *note remote caching: 2a, 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 *note –update: + 21a. and *note –remove: 21b. 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. + + +File: Mypy.info, Node: Additional daemon flags, Next: Static inference of annotations, Prev: Daemon client commands, Up: Mypy daemon mypy server + +26.3 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 *note –remove: 21b.), 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(1) or watchdog(2), 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 *note –update: 21a. 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. + + ---------- Footnotes ---------- + + (1) https://facebook.github.io/watchman/ + + (2) https://pypi.org/project/watchdog/ + + +File: Mypy.info, Node: Static inference of annotations, Prev: Additional daemon flags, Up: Mypy daemon mypy server + +26.4 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(1)), to +automatically add annotations to source files, or to propose function +signatures. + +In this example, the function ‘format_id()’ has no annotation: + + 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(2) can read it and + add the signature to the source file. Here is what the JSON looks + like: + + [{"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’). + + ---------- Footnotes ---------- + + (1) https://github.com/dropbox/mypy-PyCharm-plugin + + (2) https://github.com/dropbox/pyannotate + + +File: Mypy.info, Node: Using installed packages, Next: Extending and integrating mypy, Prev: Mypy daemon mypy server, Up: Top + +27 Using installed packages +*************************** + +Packages installed with pip can declare that they support type checking. +For example, the aiohttp(1) 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(2) package. Stub packages are usually published from +typeshed(3), 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(4) specifies how a package can declare that it + supports type checking. + +* Menu: + +* Using installed packages with mypy (PEP 561): Using installed packages with mypy PEP 561. +* Creating PEP 561 compatible packages:: + + ---------- Footnotes ---------- + + (1) https://docs.aiohttp.org/en/stable/ + + (2) https://requests.readthedocs.io/en/master/ + + (3) https://github.com/python/typeshed + + (4) https://peps.python.org/pep-0561/ + + +File: Mypy.info, Node: Using installed packages with mypy PEP 561, Next: Creating PEP 561 compatible packages, Up: Using installed packages + +27.1 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 +*note Missing imports: 14. 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 *note +–python-executable: 146. 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 *note –no-site-packages: 165. 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 +561: Stub-only Packages(1) for more information). + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0561/#stub-only-packages + + +File: Mypy.info, Node: Creating PEP 561 compatible packages, Prev: Using installed packages with mypy PEP 561, Up: Using installed packages + +27.2 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(1) describes three main ways to distribute type information: + + 1. A package has inline type annotations in the Python implementation. + + 2. A package ships *note stub files: 16. 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(2) 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: + + setup.py + package_a/ + __init__.py + lib.py + py.typed + +The ‘setup.py’ file could look like this: + + 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 setuptools(3), 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: + + setup.py + package_b/ + __init__.py + lib.py + lib.pyi + py.typed + +The ‘setup.py’ file might look like this: + + 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: + + setup.py + package_c-stubs/ + __init__.pyi + lib.pyi + +The ‘setup.py’ might look like this: + + 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’: + + global-include *.pyi + global-include *.typed + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0561/ + + (2) https://github.com/python/typeshed + + (3) https://setuptools.pypa.io/en/latest/index.html + + +File: Mypy.info, Node: Extending and integrating mypy, Next: Automatic stub generation stubgen, Prev: Using installed packages, Up: Top + +28 Extending and integrating mypy +********************************* + +* Menu: + +* Integrating mypy into another Python application:: +* Extending mypy using plugins:: +* Configuring mypy to use plugins:: +* High-level overview:: +* Current list of plugin hooks:: +* Notes about the semantic analyzer:: + + +File: Mypy.info, Node: Integrating mypy into another Python application, Next: Extending mypy using plugins, Up: Extending and integrating mypy + +28.1 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 sys.stdout(1), +‘’ is what mypy normally writes to sys.stderr(2) and +‘exit_status’ is the exit status mypy normally returns to the operating +system. + +A trivial example of using the api is the following + + 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]) + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/sys.html#sys.stdout + + (2) https://docs.python.org/3/library/sys.html#sys.stderr + + +File: Mypy.info, Node: Extending mypy using plugins, Next: Configuring mypy to use plugins, Prev: Integrating mypy into another Python application, Up: Extending and integrating mypy + +28.2 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(1) 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(2) 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(3). 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(4). + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + (2) https://peps.python.org/pep-0484/ + + (3) https://gitter.im/python/typing + + (4) https://github.com/python/mypy/issues/6617 + + +File: Mypy.info, Node: Configuring mypy to use plugins, Next: High-level overview, Prev: Extending mypy using plugins, Up: Extending and integrating mypy + +28.3 Configuring mypy to use plugins +==================================== + +Plugins are Python files that can be specified in a mypy *note config +file: 2e. using the *note plugins: 1f9. 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: + + [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: + + [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(1) in mypy source code. Also you can find +good examples in the bundled plugins located in mypy/plugins(2). + + ---------- Footnotes ---------- + + (1) https://github.com/python/mypy/blob/master/mypy/plugin.py + + (2) https://github.com/python/mypy/tree/master/mypy/plugins + + +File: Mypy.info, Node: High-level overview, Next: Current list of plugin hooks, Prev: Configuring mypy to use plugins, Up: Extending and integrating mypy + +28.4 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’: + + 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 +*note below: 238. + +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. + + +File: Mypy.info, Node: Current list of plugin hooks, Next: Notes about the semantic analyzer, Prev: High-level overview, Up: Extending and integrating mypy + +28.5 Current list of plugin hooks +================================= + +`get_type_analyze_hook()' customizes behaviour of the type analyzer. +For example, PEP 484(1) doesn’t support defining variadic generic types: + + 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: + + 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 __init__()(2) and +__new__()(3). For example in this code: + + 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 ctypes(4) 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 __getattr__(5) or __getattribute__(6) 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: + + 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: + + 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. + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + (2) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (3) https://docs.python.org/3/reference/datamodel.html#object.__new__ + + (4) https://docs.python.org/3/library/ctypes.html#module-ctypes + + (5) +https://docs.python.org/3/reference/datamodel.html#object.__getattr__ + + (6) +https://docs.python.org/3/reference/datamodel.html#object.__getattribute__ + + +File: Mypy.info, Node: Notes about the semantic analyzer, Prev: Current list of plugin hooks, Up: Extending and integrating mypy + +28.6 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(1) for more details. + + ---------- Footnotes ---------- + + (1) https://github.com/python/mypy/blob/master/mypy/plugin.py + + +File: Mypy.info, Node: Automatic stub generation stubgen, Next: Automatic stub testing stubtest, Prev: Extending and integrating mypy, Up: Top + +29 Automatic stub generation (stubgen) +************************************** + +A stub file (see PEP 484(1)) contains only type hints for the public +interface of a module, with empty function bodies. Mypy can use a stub +file instead of the real implementation to provide type information for +the module. They are useful for third-party modules whose authors have +not yet added type hints (and when no stubs are available in typeshed) +and C extension modules (which mypy can’t directly process). + +Mypy includes the ‘stubgen’ tool that can automatically generate stub +files (‘.pyi’ files) for Python modules and C extension modules. For +example, consider this source file: + + from other_module import dynamic + + BORDER_WIDTH = 15 + + class Window: + parent = dynamic() + def __init__(self, width, height): + self.width = width + self.height = height + + def create_empty() -> Window: + return Window(0, 0) + +Stubgen can generate this stub file based on the above file: + + from typing import Any + + BORDER_WIDTH: int = ... + + class Window: + parent: Any = ... + width: Any = ... + height: Any = ... + def __init__(self, width, height) -> None: ... + + def create_empty() -> Window: ... + +Stubgen generates `draft' stubs. The auto-generated stub files often +require some manual updates, and most types will default to ‘Any’. The +stubs will be much more useful if you add more precise type annotations, +at least for the most commonly used functionality. + +The rest of this section documents the command line interface of +stubgen. Run *note stubgen –help: 23d. for a quick summary of options. + + Note: The command-line flags may change between releases. + +* Menu: + +* Specifying what to stub:: +* Specifying how to generate stubs:: +* Additional flags:: + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0484/ + + +File: Mypy.info, Node: Specifying what to stub, Next: Specifying how to generate stubs, Up: Automatic stub generation stubgen + +29.1 Specifying what to stub +============================ + +You can give stubgen paths of the source files for which you want to +generate stubs: + + $ stubgen foo.py bar.py + +This generates stubs ‘out/foo.pyi’ and ‘out/bar.pyi’. The default +output directory ‘out’ can be overridden with *note -o DIR: 23f. + +You can also pass directories, and stubgen will recursively search them +for any ‘.py’ files and generate stubs for all of them: + + $ stubgen my_pkg_dir + +Alternatively, you can give module or package names using the *note -m: +240. or *note -p: 241. options: + + $ stubgen -m foo -m bar -p my_pkg_dir + +Details of the options: + + -- Option: -m MODULE, --module MODULE + + Generate a stub file for the given module. This flag may be + repeated multiple times. + + Stubgen `will not' recursively generate stubs for any submodules of + the provided module. + + -- Option: -p PACKAGE, --package PACKAGE + + Generate stubs for the given package. This flag maybe repeated + multiple times. + + Stubgen `will' recursively generate stubs for all submodules of the + provided package. This flag is identical to *note –module: 240. + apart from this behavior. + + Note: You can’t mix paths and *note -m: 240./*note -p: 241. options + in the same stubgen invocation. + +Stubgen applies heuristics to avoid generating stubs for submodules that +include tests or vendored third-party packages. + + +File: Mypy.info, Node: Specifying how to generate stubs, Next: Additional flags, Prev: Specifying what to stub, Up: Automatic stub generation stubgen + +29.2 Specifying how to generate stubs +===================================== + +By default stubgen will try to import the target modules and packages. +This allows stubgen to use runtime introspection to generate stubs for C +extension modules and to improve the quality of the generated stubs. By +default, stubgen will also use mypy to perform light-weight semantic +analysis of any Python modules. Use the following flags to alter the +default behavior: + + -- Option: --no-import + + Don’t try to import modules. Instead only use mypy’s normal search + mechanism to find sources. This does not support C extension + modules. This flag also disables runtime introspection + functionality, which mypy uses to find the value of ‘__all__’. As + result the set of exported imported names in stubs may be + incomplete. This flag is generally only useful when importing a + module causes unwanted side effects, such as the running of tests. + Stubgen tries to skip test modules even without this option, but + this does not always work. + + -- Option: --parse-only + + Don’t perform semantic analysis of source files. This may generate + worse stubs – in particular, some module, class, and function + aliases may be represented as variables with the ‘Any’ type. This + is generally only useful if semantic analysis causes a critical + mypy error. + + -- Option: --doc-dir PATH + + Try to infer better signatures by parsing .rst documentation in + ‘PATH’. This may result in better stubs, but currently it only + works for C extension modules. + + +File: Mypy.info, Node: Additional flags, Prev: Specifying how to generate stubs, Up: Automatic stub generation stubgen + +29.3 Additional flags +===================== + + -- Option: -h, --help + + Show help message and exit. + + -- Option: --py2 + + Run stubgen in Python 2 mode (the default is Python 3 mode). + + -- Option: --ignore-errors + + If an exception was raised during stub generation, continue to + process any remaining modules instead of immediately failing with + an error. + + -- Option: --include-private + + Include definitions that are considered private in stubs (with + names such as ‘_foo’ with single leading underscore and no trailing + underscores). + + -- Option: --export-less + + Don’t export all names imported from other modules within the same + package. Instead, only export imported names that are not + referenced in the module that contains the import. + + -- Option: --search-path PATH + + Specify module search directories, separated by colons (only used + if *note –no-import: 245. is given). + + -- Option: --python-executable PATH + + Use Python interpreter at ‘PATH’ for importing modules and runtime + introspection. This has no effect with *note –no-import: 245, and + this only works in Python 2 mode. In Python 3 mode the Python + interpreter used to run stubgen will always be used. + + -- Option: -o PATH, --output PATH + + Change the output directory. By default the stubs are written in + the ‘./out’ directory. The output directory will be created if it + doesn’t exist. Existing stubs in the output directory will be + overwritten without warning. + + -- Option: -v, --verbose + + Produce more verbose output. + + -- Option: -q, --quiet + + Produce less verbose output. + + +File: Mypy.info, Node: Automatic stub testing stubtest, Next: Common issues and solutions, Prev: Automatic stub generation stubgen, Up: Top + +30 Automatic stub testing (stubtest) +************************************ + +Stub files are files containing type annotations. See PEP 484(1) for +more motivation and details. + +A common problem with stub files is that they tend to diverge from the +actual implementation. Mypy includes the ‘stubtest’ tool that can +automatically check for discrepancies between the stubs and the +implementation at runtime. + +* Menu: + +* What stubtest does and does not do:: +* Example:: +* Usage:: + + ---------- Footnotes ---------- + + (1) https://www.python.org/dev/peps/pep-0484/#stub-files + + +File: Mypy.info, Node: What stubtest does and does not do, Next: Example, Up: Automatic stub testing stubtest + +30.1 What stubtest does and does not do +======================================= + +Stubtest will import your code and introspect your code objects at +runtime, for example, by using the capabilities of the inspect(1) +module. Stubtest will then analyse the stub files, and compare the two, +pointing out things that differ between stubs and the implementation at +runtime. + +It’s important to be aware of the limitations of this comparison. +Stubtest will not make any attempt to statically analyse your actual +code and relies only on dynamic runtime introspection (in particular, +this approach means stubtest works well with extension modules). +However, this means that stubtest has limited visibility; for instance, +it cannot tell if a return type of a function is accurately typed in the +stubs. + +For clarity, here are some additional things stubtest can’t do: + + * Type check your code – use ‘mypy’ instead + + * Generate stubs – use ‘stubgen’ or ‘pyright --createstub’ instead + + * Generate stubs based on running your application or test suite – + use ‘monkeytype’ instead + + * Apply stubs to code to produce inline types – use ‘retype’ or + ‘libcst’ instead + +In summary, stubtest works very well for ensuring basic consistency +between stubs and implementation or to check for stub completeness. +It’s used to test Python’s official collection of library stubs, +typeshed(2). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/inspect.html#module-inspect + + (2) https://github.com/python/typeshed + + +File: Mypy.info, Node: Example, Next: Usage, Prev: What stubtest does and does not do, Up: Automatic stub testing stubtest + +30.2 Example +============ + +Here’s a quick example of what stubtest can do: + + $ python3 -m pip install mypy + + $ cat library.py + x = "hello, stubtest" + + def foo(x=None): + print(x) + + $ cat library.pyi + x: int + + def foo(x: int) -> None: ... + + $ python3 -m mypy.stubtest library + error: library.foo is inconsistent, runtime argument "x" has a default value but stub argument does not + Stub: at line 3 + def (x: builtins.int) + Runtime: at line 3 in file ~/library.py + def (x=None) + + error: library.x variable differs from runtime type Literal['hello, stubtest'] + Stub: at line 1 + builtins.int + Runtime: + hello, stubtest + + +File: Mypy.info, Node: Usage, Prev: Example, Up: Automatic stub testing stubtest + +30.3 Usage +========== + +Running stubtest can be as simple as ‘stubtest module_to_check’. Run +*note stubtest –help: 25a. for a quick summary of options. + +Subtest must be able to import the code to be checked, so make sure that +mypy is installed in the same environment as the library to be tested. +In some cases, setting ‘PYTHONPATH’ can help stubtest find the code to +import. + +Similarly, stubtest must be able to find the stubs to be checked. +Stubtest respects the ‘MYPYPATH’ environment variable. + +If you wish to ignore some of stubtest’s complaints, stubtest supports a +pretty handy allowlist system. + +The rest of this section documents the command line interface of +stubtest. + + -- Option: --concise + + Makes stubtest’s output more concise, one line per error + + -- Option: --ignore-missing-stub + + Ignore errors for stub missing things that are present at runtime + + -- Option: --ignore-positional-only + + Ignore errors for whether an argument should or shouldn’t be + positional-only + + -- Option: --allowlist FILE + + Use file as an allowlist. Can be passed multiple times to combine + multiple allowlists. Allowlists can be created with + –generate-allowlist. Allowlists support regular expressions. + + -- Option: --generate-allowlist + + Print an allowlist (to stdout) to be used with –allowlist + + -- Option: --ignore-unused-allowlist + + Ignore unused allowlist entries + + -- Option: --mypy-config-file FILE + + Use specified mypy config file to determine mypy plugins and mypy + path + + -- Option: --custom-typeshed-dir DIR + + Use the custom typeshed in DIR + + -- Option: --check-typeshed + + Check all stdlib modules in typeshed + + -- Option: --help + + Show a help message :-) + + +File: Mypy.info, Node: Common issues and solutions, Next: Supported Python features, Prev: Automatic stub testing stubtest, Up: Top + +31 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. + +* Menu: + +* Can’t install mypy using pip:: +* No errors reported for obviously wrong code:: +* Spurious errors and locally silencing the checker:: +* Ignoring a whole file:: +* Unexpected errors about ‘None’ and/or ‘Optional’ types:: +* Issues with code at runtime:: +* Mypy runs are slow:: +* Types of empty collections:: +* Redefinitions with incompatible types:: +* Invariance vs covariance:: +* Declaring a supertype as variable type:: +* Complex type tests:: +* Python version and system platform checks:: +* Displaying the type of an expression:: +* Silencing linters:: +* Covariant subtyping of mutable protocol members is rejected:: +* Dealing with conflicting names:: +* Using a development mypy build:: +* Variables vs type aliases:: +* Incompatible overrides:: +* Unreachable code:: +* Narrowing and inner functions:: + + +File: Mypy.info, Node: Can’t install mypy using pip, Next: No errors reported for obviously wrong code, Up: Common issues and solutions + +31.1 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’. + + +File: Mypy.info, Node: No errors reported for obviously wrong code, Next: Spurious errors and locally silencing the checker, Prev: Can’t install mypy using pip, Up: Common issues and solutions + +31.2 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 +*note –check-untyped-defs: fa. + +Example: + + 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: + + 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: + + 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, *note reveal_type(): +106. might come in handy. + +Note that sometimes library stubs have imprecise type information, e.g. +the pow()(1) builtin returns ‘Any’ (see typeshed issue 285(2) for the +reason). + +__init__(3) `method has no annotated arguments or return type +annotation.' __init__(4) 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 __init__(5) method that has no argument, +you’ll have to explicitly annotate the return type as ‘None’ to +type-check this __init__(6) method: + + 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 *note –ignore-missing-imports: 140. and *note +–follow-imports=skip: 148. flags. When you use *note +–ignore-missing-imports: 140, any imported module that cannot be found +is silently replaced with ‘Any’. When using *note –follow-imports=skip: +148. 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 *note +–follow-imports: 148.) To help debug the former situation (no module +found at all) leave out *note –ignore-missing-imports: 140.; to get +clarity about the latter use *note –follow-imports=error: 148. You can +read up about these and other useful flags in *note The mypy command +line: c. + +`A function annotated as returning a non-optional type returns ‘None’ +and mypy doesn’t complain'. + + def foo() -> str: + return None # No error! + +You may have disabled strict optional checking (see *note Disabling +strict optional checking: 70. for more). + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#pow + + (2) https://github.com/python/typeshed/issues/285 + + (3) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (4) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (5) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (6) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + +File: Mypy.info, Node: Spurious errors and locally silencing the checker, Next: Ignoring a whole file, Prev: No errors reported for obviously wrong code, Up: Common issues and solutions + +31.3 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: + + import frobnicate # Error: No module "frobnicate" + frobnicate.start() + +You can add a ‘# type: ignore’ comment to tell mypy to ignore this +error: + + 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 *note + Error codes: 18e. 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 __getattr__(1): + + 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. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__getattr__ + + +File: Mypy.info, Node: Ignoring a whole file, Next: Unexpected errors about ‘None’ and/or ‘Optional’ types, Prev: Spurious errors and locally silencing the checker, Up: Common issues and solutions + +31.4 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. + + # type: ignore + + import foo + + foo.bar() + + +File: Mypy.info, Node: Unexpected errors about ‘None’ and/or ‘Optional’ types, Next: Issues with code at runtime, Prev: Ignoring a whole file, Up: Common issues and solutions + +31.5 Unexpected errors about ‘None’ and/or ‘Optional’ types +=========================================================== + +Starting from mypy 0.600, mypy uses *note strict optional checking: 6a. +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 *note Disabling strict optional +checking: 70.). 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. + + +File: Mypy.info, Node: Issues with code at runtime, Next: Mypy runs are slow, Prev: Unexpected errors about ‘None’ and/or ‘Optional’ types, Up: Common issues and solutions + +31.6 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 *note Annotation issues at runtime: 6e. + + +File: Mypy.info, Node: Mypy runs are slow, Next: Types of empty collections, Prev: Issues with code at runtime, Up: Common issues and solutions + +31.7 Mypy runs are slow +======================= + +If your mypy runs feel slow, you should probably use the *note mypy +daemon: 29, which can speed up incremental mypy runtimes by a factor of +10 or more. *note Remote caching: 2a. can make cold mypy runs several +times faster. + + +File: Mypy.info, Node: Types of empty collections, Next: Redefinitions with incompatible types, Prev: Mypy runs are slow, Up: Common issues and solutions + +31.8 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: + + 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): + + 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! + + +File: Mypy.info, Node: Redefinitions with incompatible types, Next: Invariance vs covariance, Prev: Types of empty collections, Up: Common issues and solutions + +31.9 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. + + 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: + + 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! + + +File: Mypy.info, Node: Invariance vs covariance, Next: Declaring a supertype as variable type, Prev: Redefinitions with incompatible types, Up: Common issues and solutions + +31.10 Invariance vs covariance +============================== + +Most mutable generic collections are invariant, and mypy considers all +user-defined generic classes invariant by default (see *note Variance of +generic types: e7. for motivation). This could lead to some unexpected +errors when combined with type inference. For example: + + 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: + + new_lst: List[A] = [B(), B()] + lst = new_lst # OK + + * Make a copy of the right hand side: + + lst = list(new_lst) # Also OK + + * Use immutable collections as annotations whenever possible: + + 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 + + +File: Mypy.info, Node: Declaring a supertype as variable type, Next: Complex type tests, Prev: Invariance vs covariance, Up: Common issues and solutions + +31.11 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’): + + 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: + + shape = Circle() # type: Shape # The variable s can be any Shape, + # not just Circle + ... + shape = Triangle() # OK + + +File: Mypy.info, Node: Complex type tests, Next: Python version and system platform checks, Prev: Declaring a supertype as variable type, Up: Common issues and solutions + +31.12 Complex type tests +======================== + +Mypy can usually infer the types correctly when using isinstance(1), +issubclass(2), or ‘type(obj) is some_class’ type tests, and even *note +user-defined type guards: cc, but for other kinds of checks you may need +to add an explicit type cast: + + 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: + + 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 object(3) type used in the above example is + similar to ‘Object’ in Java: it only supports operations defined + for `all' objects, such as equality and isinstance()(4). 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 *note here: + 8f. + +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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#isinstance + + (2) https://docs.python.org/3/library/functions.html#issubclass + + (3) https://docs.python.org/3/library/functions.html#object + + (4) https://docs.python.org/3/library/functions.html#isinstance + + +File: Mypy.info, Node: Python version and system platform checks, Next: Displaying the type of an expression, Prev: Complex type tests, Up: Common issues and solutions + +31.13 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 sys.version_info(1) +and sys.platform(2) checks within ‘if/elif/else’ statements. For +example: + + 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: + + import sys + + assert sys.platform != 'win32' + + # The rest of this file doesn't apply to Windows. + +Some other expressions exhibit similar behavior; in particular, +TYPE_CHECKING(3), variables named ‘MYPY’, and any variable whose name is +passed to *note –always-true: fe. or *note –always-false: ff. (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 sys.version_info(4) + or sys.platform(5) 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 sys.version_info(6) and +sys.platform(7). + +To target a different Python version, use the *note –python-version X.Y: +100. flag. For example, to verify your code typechecks if were run +using Python 2, pass in *note –python-version 2.7: 100. 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 *note –platform +PLATFORM: 16a. flag. For example, to verify your code typechecks if it +were run in Windows, pass in *note –platform win32: 16a. See the +documentation for sys.platform(8) for examples of valid platform +parameters. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/sys.html#sys.version_info + + (2) https://docs.python.org/3/library/sys.html#sys.platform + + (3) +https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING + + (4) https://docs.python.org/3/library/sys.html#sys.version_info + + (5) https://docs.python.org/3/library/sys.html#sys.platform + + (6) https://docs.python.org/3/library/sys.html#sys.version_info + + (7) https://docs.python.org/3/library/sys.html#sys.platform + + (8) https://docs.python.org/3/library/sys.html#sys.platform + + +File: Mypy.info, Node: Displaying the type of an expression, Next: Silencing linters, Prev: Python version and system platform checks, Up: Common issues and solutions + +31.14 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: + + 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: + + 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. + + +File: Mypy.info, Node: Silencing linters, Next: Covariant subtyping of mutable protocol members is rejected, Prev: Displaying the type of an expression, Up: Common issues and solutions + +31.15 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: + + # 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: + + a = some_complex_thing() # type: ignore # noqa + + +File: Mypy.info, Node: Covariant subtyping of mutable protocol members is rejected, Next: Dealing with conflicting names, Prev: Silencing linters, Up: Common issues and solutions + +31.16 Covariant subtyping of mutable protocol members is rejected +================================================================= + +Mypy rejects this because this is potentially unsafe. Consider this +example: + + 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 @property(1) in the protocol +definition: + + 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 + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#property + + +File: Mypy.info, Node: Dealing with conflicting names, Next: Using a development mypy build, Prev: Covariant subtyping of mutable protocol members is rejected, Up: Common issues and solutions + +31.17 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.: + + 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: + + bytes_ = bytes + class Message: + def bytes(self): + ... + def register(self, path: bytes_): + ... + + +File: Mypy.info, Node: Using a development mypy build, Next: Variables vs type aliases, Prev: Dealing with conflicting names, Up: Common issues and solutions + +31.18 Using a development mypy build +==================================== + +You can install the latest development version of mypy from source. +Clone the mypy repository on GitHub(1), and then run ‘pip install’ +locally: + + git clone https://github.com/python/mypy.git + cd mypy + sudo python3 -m pip install --upgrade . + + ---------- Footnotes ---------- + + (1) https://github.com/python/mypy + + +File: Mypy.info, Node: Variables vs type aliases, Next: Incompatible overrides, Prev: Using a development mypy build, Up: Common issues and solutions + +31.19 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: + + 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: + + class A: ... + Alias = A + + You can also use ‘TypeAlias’ ( PEP 613(1)) to define an `explicit + type alias': + + 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 *note supported Python version and platform checks: fd.): + + 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 + + ---------- Footnotes ---------- + + (1) https://peps.python.org/pep-0613/ + + +File: Mypy.info, Node: Incompatible overrides, Next: Unreachable code, Prev: Variables vs type aliases, Up: Common issues and solutions + +31.20 Incompatible overrides +============================ + +It’s unsafe to override a method with a more specific argument type, as +it violates the Liskov substitution principle(1). 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: + + 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: + + class NarrowerArgument(A): + def test(self, t: List[int]) -> Sequence[str]: # type: ignore[override] + ... + + ---------- Footnotes ---------- + + (1) +https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle + + +File: Mypy.info, Node: Unreachable code, Next: Narrowing and inner functions, Prev: Incompatible overrides, Up: Common issues and solutions + +31.21 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: + + 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: + + 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: + + class Foo: + bar: str = '' + + def bar() -> None: + foo: Foo = Foo() + if not foo.bar: + return + x: int = 'abc' # Reachable -- error + +If you use the *note –warn-unreachable: c6. flag, mypy will generate an +error about each unreachable code block. + + +File: Mypy.info, Node: Narrowing and inner functions, Prev: Unreachable code, Up: Common issues and solutions + +31.22 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: + + 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. + + +File: Mypy.info, Node: Supported Python features, Next: Error codes, Prev: Common issues and solutions, Up: Top + +32 Supported Python features +**************************** + +A list of unsupported Python features is maintained in the mypy wiki: + + - Unsupported Python features(1) + +* Menu: + +* Runtime definition of methods and functions:: + + ---------- Footnotes ---------- + + (1) https://github.com/python/mypy/wiki/Unsupported-Python-Features + + +File: Mypy.info, Node: Runtime definition of methods and functions, Up: Supported Python features + +32.1 Runtime definition of methods and functions +================================================ + +By default, mypy will complain if you add a function to a class or +module outside its definition – but only if this is visible to the type +checker. This only affects static checking, as mypy performs no +additional type checking at runtime. You can easily work around this. +For example, you can use dynamically typed code or values with ‘Any’ +types, or you can use setattr()(1) or other introspection features. +However, you need to be careful if you decide to do this. If used +indiscriminately, you may have difficulty using static typing +effectively, since the type checker cannot see functions defined at +runtime. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#setattr + + +File: Mypy.info, Node: Error codes, Next: Error codes enabled by default, Prev: Supported Python features, Up: Top + +33 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 (*note Error codes enabled by default: 284. and + *note Error codes for optional checks: 285.) 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. + +* Menu: + +* Displaying error codes:: +* Silencing errors based on error codes:: + + +File: Mypy.info, Node: Displaying error codes, Next: Silencing errors based on error codes, Up: Error codes + +33.1 Displaying error codes +=========================== + +Error codes are not displayed by default. Use *note –show-error-codes: +5a. or config ‘show_error_codes = True’ to display error codes. Error +codes are shown inside square brackets: + + $ 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 *note ignore-without-code: 287. for more information. + + +File: Mypy.info, Node: Silencing errors based on error codes, Prev: Displaying error codes, Up: Error codes + +33.2 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 *note + –disallow-untyped-defs: b, which enables the ‘no-untyped-def’ error + code. + +This example shows how to ignore an error about an imported name mypy +thinks is undefined: + + # 'foo' is defined in 'foolib', even though mypy can't see the + # definition. + from foolib import foo # type: ignore[attr-defined] + + +File: Mypy.info, Node: Error codes enabled by default, Next: Error codes for optional checks, Prev: Error codes, Up: Top + +34 Error codes enabled by default +********************************* + +This section documents various errors codes that mypy can generate with +default options. See *note Error codes: 18e. for general documentation +about error codes. *note Error codes for optional checks: 285. +documents additional error codes that you can enable. + +* Menu: + +* Check that attribute exists [attr-defined]:: +* Check that attribute exists in each union item [union-attr]:: +* Check that name is defined [name-defined]:: +* Check arguments in calls [call-arg]:: +* Check argument types [arg-type]:: +* Check calls to overloaded functions [call-overload]:: +* Check validity of types [valid-type]:: +* Require annotation if variable type is unclear [var-annotated]:: +* Check validity of overrides [override]:: +* Check that function returns a value [return]:: +* Check that return value is compatible [return-value]:: +* Check types in assignment statement [assignment]:: +* Check type variable values [type-var]:: +* Check uses of various operators [operator]:: +* Check indexing operations [index]:: +* Check list items [list-item]:: +* Check dict items [dict-item]:: +* Check TypedDict items [typeddict-item]:: +* Check that type of target is known [has-type]:: +* Check that import target can be found [import]:: +* Check that each name is defined once [no-redef]:: +* Check that called function returns a value [func-returns-value]:: +* Check instantiation of abstract classes [abstract]:: +* Check the target of NewType [valid-newtype]:: +* Check the return type of __exit__ [exit-return]:: +* Check that naming is consistent [name-match]:: +* Check that overloaded functions have an implementation [no-overload-impl]:: +* Report syntax errors [syntax]:: +* Miscellaneous checks [misc]:: + + +File: Mypy.info, Node: Check that attribute exists [attr-defined], Next: Check that attribute exists in each union item [union-attr], Up: Error codes enabled by default + +34.1 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: + + 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): + + # 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. + + +File: Mypy.info, Node: Check that attribute exists in each union item [union-attr], Next: Check that name is defined [name-defined], Prev: Check that attribute exists [attr-defined], Up: Error codes enabled by default + +34.2 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: + + 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. + + +File: Mypy.info, Node: Check that name is defined [name-defined], Next: Check arguments in calls [call-arg], Prev: Check that attribute exists in each union item [union-attr], Up: Error codes enabled by default + +34.3 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 sorted()(1): + + x = sort([3, 2, 4]) # Error: Name "sort" is not defined [name-defined] + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/functions.html#sorted + + +File: Mypy.info, Node: Check arguments in calls [call-arg], Next: Check argument types [arg-type], Prev: Check that name is defined [name-defined], Up: Error codes enabled by default + +34.4 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: + + 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] + + +File: Mypy.info, Node: Check argument types [arg-type], Next: Check calls to overloaded functions [call-overload], Prev: Check arguments in calls [call-arg], Up: Error codes enabled by default + +34.5 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: + + 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)) + + +File: Mypy.info, Node: Check calls to overloaded functions [call-overload], Next: Check validity of types [valid-type], Prev: Check argument types [arg-type], Up: Error codes enabled by default + +34.6 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: + + 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) + + +File: Mypy.info, Node: Check validity of types [valid-type], Next: Require annotation if variable type is unclear [var-annotated], Prev: Check calls to overloaded functions [call-overload], Up: Error codes enabled by default + +34.7 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: + + 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 Callable(1) as the type for callable objects: + + from typing import Callable + + # OK + def log_all(objs: list[object], f: Callable[[object], None]) -> None: + for x in objs: + f(x) + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Callable + + +File: Mypy.info, Node: Require annotation if variable type is unclear [var-annotated], Next: Check validity of overrides [override], Prev: Check validity of types [valid-type], Up: Error codes enabled by default + +34.8 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: + + 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: + + class Bundle: + def __init__(self) -> None: + self.items: list[str] = [] # OK + + reveal_type(Bundle().items) # list[str] + + +File: Mypy.info, Node: Check validity of overrides [override], Next: Check that function returns a value [return], Prev: Require annotation if variable type is unclear [var-annotated], Up: Error codes enabled by default + +34.9 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: + + 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: + ... + + +File: Mypy.info, Node: Check that function returns a value [return], Next: Check that return value is compatible [return-value], Prev: Check validity of overrides [override], Up: Error codes enabled by default + +34.10 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: + + # 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') + + +File: Mypy.info, Node: Check that return value is compatible [return-value], Next: Check types in assignment statement [assignment], Prev: Check that function returns a value [return], Up: Error codes enabled by default + +34.11 Check that return value is compatible [return-value] +========================================================== + +Mypy checks that the returned value is compatible with the type +signature of the function. + +Example: + + def func(x: int) -> str: + # Error: Incompatible return value type (got "int", expected "str") [return-value] + return x + 1 + + +File: Mypy.info, Node: Check types in assignment statement [assignment], Next: Check type variable values [type-var], Prev: Check that return value is compatible [return-value], Up: Error codes enabled by default + +34.12 Check types in assignment statement [assignment] +====================================================== + +Mypy checks that the assigned expression is compatible with the +assignment target (or targets). + +Example: + + 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 + + +File: Mypy.info, Node: Check type variable values [type-var], Next: Check uses of various operators [operator], Prev: Check types in assignment statement [assignment], Up: Error codes enabled by default + +34.13 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: + + 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') + + +File: Mypy.info, Node: Check uses of various operators [operator], Next: Check indexing operations [index], Prev: Check type variable values [type-var], Up: Error codes enabled by default + +34.14 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: + + # Error: Unsupported operand types for + ("int" and "str") [operator] + 1 + 'x' + + +File: Mypy.info, Node: Check indexing operations [index], Next: Check list items [list-item], Prev: Check uses of various operators [operator], Up: Error codes enabled by default + +34.15 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: + + 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 + + +File: Mypy.info, Node: Check list items [list-item], Next: Check dict items [dict-item], Prev: Check indexing operations [index], Up: Error codes enabled by default + +34.16 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: + + # Error: List item 0 has incompatible type "int"; expected "str" [list-item] + a: list[str] = [0] + + +File: Mypy.info, Node: Check dict items [dict-item], Next: Check TypedDict items [typeddict-item], Prev: Check list items [list-item], Up: Error codes enabled by default + +34.17 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: + + # Error: Dict entry 0 has incompatible type "str": "str"; expected "str": "int" [dict-item] + d: dict[str, int] = {'key': 'value'} + + +File: Mypy.info, Node: Check TypedDict items [typeddict-item], Next: Check that type of target is known [has-type], Prev: Check dict items [dict-item], Up: Error codes enabled by default + +34.18 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: + + 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} + + +File: Mypy.info, Node: Check that type of target is known [has-type], Next: Check that import target can be found [import], Prev: Check TypedDict items [typeddict-item], Up: Error codes enabled by default + +34.19 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: + + 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: + + 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 + + +File: Mypy.info, Node: Check that import target can be found [import], Next: Check that each name is defined once [no-redef], Prev: Check that type of target is known [has-type], Up: Error codes enabled by default + +34.20 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: + + # Error: Cannot find implementation or library stub for module named 'acme' [import] + import acme + +See *note Missing imports: 17. for how to work around these errors. + + +File: Mypy.info, Node: Check that each name is defined once [no-redef], Next: Check that called function returns a value [func-returns-value], Prev: Check that import target can be found [import], Up: Error codes enabled by default + +34.21 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: + + 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') + + +File: Mypy.info, Node: Check that called function returns a value [func-returns-value], Next: Check instantiation of abstract classes [abstract], Prev: Check that each name is defined once [no-redef], Up: Error codes enabled by default + +34.22 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’: + + 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") + + +File: Mypy.info, Node: Check instantiation of abstract classes [abstract], Next: Check the target of NewType [valid-newtype], Prev: Check that called function returns a value [func-returns-value], Up: Error codes enabled by default + +34.23 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 abc(1) 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: + + 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() + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/abc.html#module-abc + + +File: Mypy.info, Node: Check the target of NewType [valid-newtype], Next: Check the return type of __exit__ [exit-return], Prev: Check instantiation of abstract classes [abstract], Up: Error codes enabled by default + +34.24 Check the target of NewType [valid-newtype] +================================================= + +The target of a ‘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: + + 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 *note Missing +imports: 17. for more information. + + +File: Mypy.info, Node: Check the return type of __exit__ [exit-return], Next: Check that naming is consistent [name-match], Prev: Check the target of NewType [valid-newtype], Up: Error codes enabled by default + +34.25 Check the return type of __exit__ [exit-return] +===================================================== + +If mypy can determine that __exit__(1) 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 __exit__(2) 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: + + class MyContext: + ... + def __exit__(self, exc, value, tb) -> bool: # Error + print('exit') + return False + +This produces the following output from mypy: + + 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: + + 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’: + + class MyContext: + ... + def __exit__(self, exc, value, tb) -> None: # Also OK + print('exit') + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__exit__ + + (2) +https://docs.python.org/3/reference/datamodel.html#object.__exit__ + + +File: Mypy.info, Node: Check that naming is consistent [name-match], Next: Check that overloaded functions have an implementation [no-overload-impl], Prev: Check the return type of __exit__ [exit-return], Up: Error codes enabled by default + +34.26 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: + + from typing import NamedTuple + + # Error: First argument to namedtuple() should be "Point2D", not "Point" + Point2D = NamedTuple("Point", [("x", int), ("y", int)]) + + +File: Mypy.info, Node: Check that overloaded functions have an implementation [no-overload-impl], Next: Report syntax errors [syntax], Prev: Check that naming is consistent [name-match], Up: Error codes enabled by default + +34.27 Check that overloaded functions have an implementation [no-overload-impl] +=============================================================================== + +Overloaded functions outside of stub files must be followed by a non +overloaded implementation. + + 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 + + +File: Mypy.info, Node: Report syntax errors [syntax], Next: Miscellaneous checks [misc], Prev: Check that overloaded functions have an implementation [no-overload-impl], Up: Error codes enabled by default + +34.28 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. + + +File: Mypy.info, Node: Miscellaneous checks [misc], Prev: Report syntax errors [syntax], Up: Error codes enabled by default + +34.29 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. + + +File: Mypy.info, Node: Error codes for optional checks, Next: Additional features, Prev: Error codes enabled by default, Up: Top + +35 Error codes for optional checks +********************************** + +This section documents various errors codes that mypy generates only if +you enable certain options. See *note Error codes: 18e. for general +documentation about error codes. *note Error codes enabled by default: +284. documents error codes that are enabled by default. + + Note: The examples in this section use *note inline configuration: + 1b7. to specify mypy options. You can also set the same options by + using a *note configuration file: 2e. or *note command-line + options: c. + +* Menu: + +* Check that type arguments exist [type-arg]:: +* Check that every function has an annotation [no-untyped-def]:: +* Check that cast is not redundant [redundant-cast]:: +* Check that comparisons are overlapping [comparison-overlap]:: +* Check that no untyped functions are called [no-untyped-call]:: +* Check that function does not return Any value [no-any-return]:: +* Check that types have no Any components due to missing imports [no-any-unimported]:: +* Check that statement or expression is unreachable [unreachable]:: +* Check that expression is redundant [redundant-expr]:: +* Check that expression is not implicitly true in boolean context [truthy-bool]:: +* Check that # type; ignore include an error code [ignore-without-code]: Check that # type ignore include an error code [ignore-without-code]. + + +File: Mypy.info, Node: Check that type arguments exist [type-arg], Next: Check that every function has an annotation [no-untyped-def], Up: Error codes for optional checks + +35.1 Check that type arguments exist [type-arg] +=============================================== + +If you use *note –disallow-any-generics: 172, 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: + + # mypy: disallow-any-generics + + # Error: Missing type parameters for generic type "list" [type-arg] + def remove_dups(items: list) -> list: + ... + + +File: Mypy.info, Node: Check that every function has an annotation [no-untyped-def], Next: Check that cast is not redundant [redundant-cast], Prev: Check that type arguments exist [type-arg], Up: Error codes for optional checks + +35.2 Check that every function has an annotation [no-untyped-def] +================================================================= + +If you use *note –disallow-untyped-defs: b, mypy requires that all +functions have annotations (either a Python 3 annotation or a type +comment). + +Example: + + # 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 + + +File: Mypy.info, Node: Check that cast is not redundant [redundant-cast], Next: Check that comparisons are overlapping [comparison-overlap], Prev: Check that every function has an annotation [no-untyped-def], Up: Error codes for optional checks + +35.3 Check that cast is not redundant [redundant-cast] +====================================================== + +If you use *note –warn-redundant-casts: 17d, mypy will generate an error +if the source type of a cast is the same as the target type. + +Example: + + # 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) + + +File: Mypy.info, Node: Check that comparisons are overlapping [comparison-overlap], Next: Check that no untyped functions are called [no-untyped-call], Prev: Check that cast is not redundant [redundant-cast], Up: Error codes for optional checks + +35.4 Check that comparisons are overlapping [comparison-overlap] +================================================================ + +If you use *note –strict-equality: 187, 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: + + # 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: + + # mypy: strict-equality + + def is_magic(x: bytes) -> bool: + return x == b'magic' # OK + + +File: Mypy.info, Node: Check that no untyped functions are called [no-untyped-call], Next: Check that function does not return Any value [no-any-return], Prev: Check that comparisons are overlapping [comparison-overlap], Up: Error codes for optional checks + +35.5 Check that no untyped functions are called [no-untyped-call] +================================================================= + +If you use *note –disallow-untyped-calls: 175, mypy generates an error +when you call an unannotated function in an annotated function. + +Example: + + # mypy: disallow-untyped-calls + + def do_it() -> None: + # Error: Call to untyped function "bad" in typed context [no-untyped-call] + bad() + + def bad(): + ... + + +File: Mypy.info, Node: Check that function does not return Any value [no-any-return], Next: Check that types have no Any components due to missing imports [no-any-unimported], Prev: Check that no untyped functions are called [no-untyped-call], Up: Error codes for optional checks + +35.6 Check that function does not return Any value [no-any-return] +================================================================== + +If you use *note –warn-return-any: 180, 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: + + # 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] + + +File: Mypy.info, Node: Check that types have no Any components due to missing imports [no-any-unimported], Next: Check that statement or expression is unreachable [unreachable], Prev: Check that function does not return Any value [no-any-return], Up: Error codes for optional checks + +35.7 Check that types have no Any components due to missing imports [no-any-unimported] +======================================================================================= + +If you use *note –disallow-any-unimported: 16e, 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: + + # 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: + ... + + +File: Mypy.info, Node: Check that statement or expression is unreachable [unreachable], Next: Check that expression is redundant [redundant-expr], Prev: Check that types have no Any components due to missing imports [no-any-unimported], Up: Error codes for optional checks + +35.8 Check that statement or expression is unreachable [unreachable] +==================================================================== + +If you use *note –warn-unreachable: c6, 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. + + # 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') + + +File: Mypy.info, Node: Check that expression is redundant [redundant-expr], Next: Check that expression is not implicitly true in boolean context [truthy-bool], Prev: Check that statement or expression is unreachable [unreachable], Up: Error codes for optional checks + +35.9 Check that expression is redundant [redundant-expr] +======================================================== + +If you use *note –enable-error-code redundant-expr: 189, mypy generates +an error if it thinks that an expression is redundant. + + # 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)] + + +File: Mypy.info, Node: Check that expression is not implicitly true in boolean context [truthy-bool], Next: Check that # type ignore include an error code [ignore-without-code], Prev: Check that expression is redundant [redundant-expr], Up: Error codes for optional checks + +35.10 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. + + # 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: + + # 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. + + +File: Mypy.info, Node: Check that # type ignore include an error code [ignore-without-code], Prev: Check that expression is not implicitly true in boolean context [truthy-bool], Up: Error codes for optional checks + +35.11 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: + + # 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] + + +File: Mypy.info, Node: Additional features, Next: Frequently Asked Questions, Prev: Error codes for optional checks, Up: Top + +36 Additional features +********************** + +This section discusses various features that did not fit in naturally in +one of the previous sections. + +* Menu: + +* Dataclasses:: +* The attrs package:: +* Using a remote cache to speed up mypy runs:: +* Extended Callable types:: + + +File: Mypy.info, Node: Dataclasses, Next: The attrs package, Up: Additional features + +36.1 Dataclasses +================ + +In Python 3.7, a new dataclasses(1) module has been added to the +standard library. This module allows defining and customizing simple +boilerplate-free classes. They can be defined using the +@dataclasses.dataclass(2) decorator: + + 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 __lt__(3)) depending on the +flags used to define dataclasses. For example: + + 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: + + 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 official docs(4) and PEP 557(5). + +* Menu: + +* Caveats/Known Issues:: + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/dataclasses.html#module-dataclasses + + (2) +https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass + + (3) https://docs.python.org/3/reference/datamodel.html#object.__lt__ + + (4) https://docs.python.org/3/library/dataclasses.html + + (5) https://peps.python.org/pep-0557/ + + +File: Mypy.info, Node: Caveats/Known Issues, Up: Dataclasses + +36.1.1 Caveats/Known Issues +--------------------------- + +Some functions in the dataclasses(1) module, such as replace()(2) and +asdict()(3), have imprecise (too permissive) types. This will be fixed +in future releases. + +Mypy does not yet recognize aliases of dataclasses.dataclass(4), and +will probably never recognize dynamically computed decorators. The +following examples do `not' work: + + 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 + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/library/dataclasses.html#module-dataclasses + + (2) +https://docs.python.org/3/library/dataclasses.html#dataclasses.replace + + (3) +https://docs.python.org/3/library/dataclasses.html#dataclasses.asdict + + (4) +https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass + + +File: Mypy.info, Node: The attrs package, Next: Using a remote cache to speed up mypy runs, Prev: Dataclasses, Up: Additional features + +36.2 The attrs package +====================== + +attrs(1) 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: + + 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. + + 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. attr.ib()(2) and ‘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: + + 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 + +* Menu: + +* Caveats/Known Issues: Caveats/Known Issues<2>. + + ---------- Footnotes ---------- + + (1) https://www.attrs.org/en/stable/index.html + + (2) https://www.attrs.org/en/stable/api.html#attr.ib + + +File: Mypy.info, Node: Caveats/Known Issues<2>, Up: The attrs package + +36.2.1 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: + + 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 __init__(1) will be replaced by + ‘Any’. + + * Validator decorators(2) and default decorators(3) are not + type-checked against the attribute they are setting/validating. + + * Method definitions added by mypy currently overwrite any existing + method definitions. + + ---------- Footnotes ---------- + + (1) +https://docs.python.org/3/reference/datamodel.html#object.__init__ + + (2) https://www.attrs.org/en/stable/examples.html#examples-validators + + (3) http://www.attrs.org/en/stable/examples.html#defaults + + +File: Mypy.info, Node: Using a remote cache to speed up mypy runs, Next: Extended Callable types, Prev: The attrs package, Up: Additional features + +36.3 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. + +* Menu: + +* Shared repository for cache files:: +* Continuous Integration build:: +* Mypy wrapper script:: +* Caching with mypy daemon:: +* Refinements:: + + +File: Mypy.info, Node: Shared repository for cache files, Next: Continuous Integration build, Up: Using a remote cache to speed up mypy runs + +36.3.1 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. + + +File: Mypy.info, Node: Continuous Integration build, Next: Mypy wrapper script, Prev: Shared repository for cache files, Up: Using a remote cache to speed up mypy runs + +36.3.2 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. + + +File: Mypy.info, Node: Mypy wrapper script, Next: Caching with mypy daemon, Prev: Continuous Integration build, Up: Using a remote cache to speed up mypy runs + +36.3.3 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: + + 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! + + +File: Mypy.info, Node: Caching with mypy daemon, Next: Refinements, Prev: Mypy wrapper script, Up: Using a remote cache to speed up mypy runs + +36.3.4 Caching with mypy daemon +------------------------------- + +You can also use remote caching with the *note mypy daemon: 29. 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 *note –cache-fine-grained: 198. 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. + + +File: Mypy.info, Node: Refinements, Prev: Caching with mypy daemon, Up: Using a remote cache to speed up mypy runs + +36.3.5 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 *note –cache-dir: 196. 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). + + +File: Mypy.info, Node: Extended Callable types, Prev: Using a remote cache to speed up mypy runs, Up: Additional features + +36.4 Extended Callable types +============================ + + Note: This feature is deprecated. You can use *note callback + protocols: 65. as a replacement. + +As an experimental mypy extension, you can specify Callable(1) types +that support keyword arguments, optional arguments, and more. When you +specify the arguments of a Callable(2), 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 Callable(3): + + 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: + + 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 Callable(4) such as + + MyFunc = Callable[[int, str, int], float] + +is equivalent to the following: + + MyFunc = Callable[[Arg(int), Arg(str), Arg(int)], float] + +A Callable(5) with unspecified argument types, such as + + MyOtherFunc = Callable[..., int] + +is (roughly) equivalent to + + 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. + + ---------- Footnotes ---------- + + (1) https://docs.python.org/3/library/typing.html#typing.Callable + + (2) https://docs.python.org/3/library/typing.html#typing.Callable + + (3) https://docs.python.org/3/library/typing.html#typing.Callable + + (4) https://docs.python.org/3/library/typing.html#typing.Callable + + (5) https://docs.python.org/3/library/typing.html#typing.Callable + + +File: Mypy.info, Node: Frequently Asked Questions, Next: Indices and tables, Prev: Additional features, Up: Top + +37 Frequently Asked Questions +***************************** + +* Menu: + +* Why have both dynamic and static typing?:: +* Would my project benefit from static typing?:: +* Can I use mypy to type check my existing Python code?:: +* Will static typing make my programs run faster?:: +* How do I type check my Python 2 code?:: +* Is mypy free?:: +* Can I use duck typing with mypy?:: +* I like Python and I have no need for static typing:: +* How are mypy programs different from normal Python?:: +* How is mypy different from Cython?:: +* Does it run on PyPy?:: +* Mypy is a cool project. Can I help?: Mypy is a cool project Can I help?. + + +File: Mypy.info, Node: Why have both dynamic and static typing?, Next: Would my project benefit from static typing?, Up: Frequently Asked Questions + +37.1 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(1) of the mypy web site. + + ---------- Footnotes ---------- + + (1) http://www.mypy-lang.org + + +File: Mypy.info, Node: Would my project benefit from static typing?, Next: Can I use mypy to type check my existing Python code?, Prev: Why have both dynamic and static typing?, Up: Frequently Asked Questions + +37.2 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. + + +File: Mypy.info, Node: Can I use mypy to type check my existing Python code?, Next: Will static typing make my programs run faster?, Prev: Would my project benefit from static typing?, Up: Frequently Asked Questions + +37.3 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. + + +File: Mypy.info, Node: Will static typing make my programs run faster?, Next: How do I type check my Python 2 code?, Prev: Can I use mypy to type check my existing Python code?, Up: Frequently Asked Questions + +37.4 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. + + +File: Mypy.info, Node: How do I type check my Python 2 code?, Next: Is mypy free?, Prev: Will static typing make my programs run faster?, Up: Frequently Asked Questions + +37.5 How do I type check my Python 2 code? +========================================== + +You can use a comment-based function annotation syntax(1) and use the +*note –py2: 8. command-line option to type check your Python 2 code. +You’ll also need to install ‘typing’ for Python 2 via ‘pip install +typing’. + + ---------- Footnotes ---------- + + (1) +https://peps.python.org/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code + + +File: Mypy.info, Node: Is mypy free?, Next: Can I use duck typing with mypy?, Prev: How do I type check my Python 2 code?, Up: Frequently Asked Questions + +37.6 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. + + +File: Mypy.info, Node: Can I use duck typing with mypy?, Next: I like Python and I have no need for static typing, Prev: Is mypy free?, Up: Frequently Asked Questions + +37.7 Can I use duck typing with mypy? +===================================== + +Mypy provides support for both nominal subtyping(1) and structural +subtyping(2). 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 Iterable(3) 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 isinstance()(4) tests + and they are widely used in programs. Only limited support for + structural isinstance()(5) 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 *note Protocols and +structural subtyping: 37. and PEP 544(6). + + ---------- Footnotes ---------- + + (1) https://en.wikipedia.org/wiki/Nominative_type_system + + (2) https://en.wikipedia.org/wiki/Structural_type_system + + (3) https://docs.python.org/3/library/typing.html#typing.Iterable + + (4) https://docs.python.org/3/library/functions.html#isinstance + + (5) https://docs.python.org/3/library/functions.html#isinstance + + (6) https://peps.python.org/pep-0544/ + + +File: Mypy.info, Node: I like Python and I have no need for static typing, Next: How are mypy programs different from normal Python?, Prev: Can I use duck typing with mypy?, Up: Frequently Asked Questions + +37.8 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. + + +File: Mypy.info, Node: How are mypy programs different from normal Python?, Next: How is mypy different from Cython?, Prev: I like Python and I have no need for static typing, Up: Frequently Asked Questions + +37.9 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 *note Common issues and solutions: 1e. 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. + + +File: Mypy.info, Node: How is mypy different from Cython?, Next: Does it run on PyPy?, Prev: How are mypy programs different from normal Python?, Up: Frequently Asked Questions + +37.10 How is mypy different from Cython? +======================================== + +Cython(1) 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. + + ---------- Footnotes ---------- + + (1) http://docs.cython.org/en/latest/index.html + + +File: Mypy.info, Node: Does it run on PyPy?, Next: Mypy is a cool project Can I help?, Prev: How is mypy different from Cython?, Up: Frequently Asked Questions + +37.11 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(1), which uses +several APIs that PyPy does not support (including some internal CPython +APIs). + + ---------- Footnotes ---------- + + (1) https://github.com/python/typed_ast + + +File: Mypy.info, Node: Mypy is a cool project Can I help?, Prev: Does it run on PyPy?, Up: Frequently Asked Questions + +37.12 Mypy is a cool project. Can I help? +========================================= + +Any help is much appreciated! Contact(1) 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. + + ---------- Footnotes ---------- + + (1) http://www.mypy-lang.org/contact.html + + +File: Mypy.info, Node: Indices and tables, Next: Index, Prev: Frequently Asked Questions, Up: Top + +Indices and tables +****************** + + * genindex + + * search + + +File: Mypy.info, Node: Index, Prev: Indices and tables, Up: Top + +Index +***** + +[index] +* Menu: + +* allow_redefinition; configuration value: Miscellaneous strictness flags<2>. + (line 20) +* allow_untyped_globals; configuration value: Miscellaneous strictness flags<2>. + (line 9) +* always_false; configuration value: Platform configuration<2>. + (line 38) +* always_true; configuration value: Platform configuration<2>. + (line 30) +* any_exprs_report; configuration value: Report generation<2>. + (line 9) +* cache_dir; configuration value: Incremental mode<2>. (line 18) +* cache_fine_grained; configuration value: Incremental mode<2>. + (line 45) +* check_untyped_defs; configuration value: Untyped definitions and calls<2>. + (line 41) +* cobertura_xml_report; configuration value: Report generation<2>. + (line 17) +* color_output; configuration value: Configuring error messages<2>. + (line 53) +* custom_typeshed_dir; configuration value: Advanced options<2>. + (line 54) +* custom_typing_module; configuration value: Advanced options<2>. + (line 46) +* disable_error_code; configuration value: Miscellaneous strictness flags<2>. + (line 57) +* disallow_any_decorated; configuration value: Disallow dynamic typing<2>. + (line 31) +* disallow_any_explicit; configuration value: Disallow dynamic typing<2>. + (line 42) +* disallow_any_expr; configuration value: Disallow dynamic typing<2>. + (line 21) +* disallow_any_generics; configuration value: Disallow dynamic typing<2>. + (line 53) +* disallow_any_unimported; configuration value: Disallow dynamic typing<2>. + (line 9) +* disallow_incomplete_defs; configuration value: Untyped definitions and calls<2>. + (line 31) +* disallow_subclassing_any; configuration value: Disallow dynamic typing<2>. + (line 64) +* disallow_untyped_calls; configuration value: Untyped definitions and calls<2>. + (line 9) +* disallow_untyped_decorators; configuration value: Untyped definitions and calls<2>. + (line 51) +* disallow_untyped_defs; configuration value: Untyped definitions and calls<2>. + (line 20) +* dmypy command line option; –callsites: Static inference of annotations. + (line 81) +* dmypy command line option; –flex-any: Static inference of annotations. + (line 70) +* dmypy command line option; –fswatcher-dump-file: Additional daemon flags. + (line 48) +* dmypy command line option; –json: Static inference of annotations. + (line 46) +* dmypy command line option; –log-file: Additional daemon flags. + (line 13) +* dmypy command line option; –max-guesses: Static inference of annotations. + (line 94) +* dmypy command line option; –no-any: Static inference of annotations. + (line 64) +* dmypy command line option; –no-errors: Static inference of annotations. + (line 58) +* dmypy command line option; –perf-stats-file: Additional daemon flags. + (line 57) +* dmypy command line option; –remove: Additional daemon flags. + (line 40) +* dmypy command line option; –status-file: Additional daemon flags. + (line 6) +* dmypy command line option; –timeout: Additional daemon flags. + (line 20) +* dmypy command line option; –try-text: Static inference of annotations. + (line 76) +* dmypy command line option; –update: Additional daemon flags. + (line 26) +* dmypy command line option; –use-fixme: Static inference of annotations. + (line 88) +* error_summary; configuration value: Configuring error messages<2>. + (line 63) +* exclude; configuration value: Import discovery<2>. (line 44) +* explicit_package_bases; configuration value: Import discovery<2>. + (line 111) +* files; configuration value: Import discovery<2>. (line 30) +* follow_imports; configuration value: Import discovery<2>. (line 141) +* follow_imports_for_stubs; configuration value: Import discovery<2>. + (line 165) +* html_report / xslt_html_report; configuration value: Report generation<2>. + (line 29) +* ignore_errors; configuration value: Suppressing errors. (line 20) +* ignore_missing_imports; configuration value: Import discovery<2>. + (line 127) +* implicit_reexport; configuration value: Miscellaneous strictness flags<2>. + (line 64) +* incremental; configuration value: Incremental mode<2>. (line 8) +* junit_xml; configuration value: Miscellaneous<4>. (line 8) +* linecount_report; configuration value: Report generation<2>. + (line 40) +* linecoverage_report; configuration value: Report generation<2>. + (line 49) +* lineprecision_report; configuration value: Report generation<2>. + (line 58) +* local_partial_types; configuration value: Miscellaneous strictness flags<2>. + (line 45) +* mypy command line option; -2: Platform configuration. + (line 26) +* mypy command line option; –allow-redefinition: Miscellaneous strictness flags. + (line 14) +* mypy command line option; –allow-untyped-globals: Miscellaneous strictness flags. + (line 9) +* mypy command line option; –always-false: Platform configuration. + (line 46) +* mypy command line option; –always-true: Platform configuration. + (line 41) +* mypy command line option; –any-exprs-report: Report generation. + (line 9) +* mypy command line option; -c: Specifying what to type check. + (line 34) +* mypy command line option; –cache-dir: Incremental mode. (line 25) +* mypy command line option; –cache-fine-grained: Incremental mode. + (line 44) +* mypy command line option; –check-untyped-defs: Untyped definitions and calls. + (line 24) +* mypy command line option; –cobertura-xml-report: Report generation. + (line 14) +* mypy command line option; –command: Specifying what to type check. + (line 34) +* mypy command line option; –config-file: Config file. (line 6) +* mypy command line option; –custom-typeshed-dir: Advanced options. + (line 28) +* mypy command line option; –custom-typing-module: Advanced options. + (line 23) +* mypy command line option; –disable-error-code: Miscellaneous strictness flags. + (line 110) +* mypy command line option; –disallow-any-decorated: Disallow dynamic typing. + (line 32) +* mypy command line option; –disallow-any-explicit: Disallow dynamic typing. + (line 37) +* mypy command line option; –disallow-any-expr: Disallow dynamic typing. + (line 20) +* mypy command line option; –disallow-any-generics: Disallow dynamic typing. + (line 42) +* mypy command line option; –disallow-any-unimported: Disallow dynamic typing. + (line 13) +* mypy command line option; –disallow-incomplete-defs: Untyped definitions and calls. + (line 19) +* mypy command line option; –disallow-subclassing-any: Disallow dynamic typing. + (line 49) +* mypy command line option; –disallow-untyped-calls: Untyped definitions and calls. + (line 9) +* mypy command line option; –disallow-untyped-decorators: Untyped definitions and calls. + (line 34) +* mypy command line option; –disallow-untyped-defs: Untyped definitions and calls. + (line 14) +* mypy command line option; –enable-error-code: Miscellaneous strictness flags. + (line 122) +* mypy command line option; –exclude: Specifying what to type check. + (line 38) +* mypy command line option; –explicit-package-bases: Import discovery. + (line 26) +* mypy command line option; –find-occurrences: Miscellaneous<3>. + (line 47) +* mypy command line option; –follow-imports: Import discovery. + (line 59) +* mypy command line option; -h: Optional arguments. (line 6) +* mypy command line option; –help: Optional arguments. (line 6) +* mypy command line option; –html-report: Report generation. (line 23) +* mypy command line option; –ignore-missing-imports: Import discovery. + (line 35) +* mypy command line option; –install-types: Miscellaneous<3>. (line 6) +* mypy command line option; –junit-xml: Miscellaneous<3>. (line 41) +* mypy command line option; –linecount-report: Report generation. + (line 31) +* mypy command line option; –linecoverage-report: Report generation. + (line 37) +* mypy command line option; –lineprecision-report: Report generation. + (line 43) +* mypy command line option; –local-partial-types: Miscellaneous strictness flags. + (line 35) +* mypy command line option; -m: Specifying what to type check. + (line 17) +* mypy command line option; –module: Specifying what to type check. + (line 17) +* mypy command line option; –namespace-packages: Import discovery. + (line 9) +* mypy command line option; –no-color-output: Configuring error messages. + (line 50) +* mypy command line option; –no-error-summary: Configuring error messages. + (line 55) +* mypy command line option; –no-implicit-optional: None and Optional handling. + (line 7) +* mypy command line option; –no-implicit-reexport: Miscellaneous strictness flags. + (line 62) +* mypy command line option; –no-incremental: Incremental mode. + (line 16) +* mypy command line option; –no-silence-site-packages: Import discovery. + (line 87) +* mypy command line option; –no-site-packages: Import discovery. + (line 78) +* mypy command line option; –no-strict-optional: None and Optional handling. + (line 26) +* mypy command line option; –no-warn-no-return: Configuring warnings. + (line 29) +* mypy command line option; –non-interactive: Miscellaneous<3>. + (line 27) +* mypy command line option; -p: Specifying what to type check. + (line 25) +* mypy command line option; –package: Specifying what to type check. + (line 25) +* mypy command line option; –pdb: Advanced options. (line 9) +* mypy command line option; –platform: Platform configuration. + (line 33) +* mypy command line option; –pretty: Configuring error messages. + (line 45) +* mypy command line option; –py2: Platform configuration. + (line 26) +* mypy command line option; –python-executable: Import discovery. + (line 68) +* mypy command line option; –python-version: Platform configuration. + (line 13) +* mypy command line option; –raise-exceptions: Advanced options. + (line 19) +* mypy command line option; –scripts-are-modules: Miscellaneous<3>. + (line 52) +* mypy command line option; –shadow-file: Advanced options. (line 53) +* mypy command line option; –show-absolute-path: Configuring error messages. + (line 61) +* mypy command line option; –show-column-numbers: Configuring error messages. + (line 28) +* mypy command line option; –show-error-codes: Configuring error messages. + (line 36) +* mypy command line option; –show-error-context: Configuring error messages. + (line 9) +* mypy command line option; –show-traceback: Advanced options. + (line 14) +* mypy command line option; –skip-cache-mtime-checks: Incremental mode. + (line 54) +* mypy command line option; –skip-version-check: Incremental mode. + (line 49) +* mypy command line option; –soft-error-limit: Configuring error messages. + (line 65) +* mypy command line option; –sqlite-cache: Incremental mode. (line 40) +* mypy command line option; –strict: Miscellaneous strictness flags. + (line 101) +* mypy command line option; –strict-equality: Miscellaneous strictness flags. + (line 83) +* mypy command line option; –tb: Advanced options. (line 14) +* mypy command line option; –txt-report: Report generation. (line 48) +* mypy command line option; -v: Optional arguments. (line 10) +* mypy command line option; -V: Optional arguments. (line 14) +* mypy command line option; –verbose: Optional arguments. (line 10) +* mypy command line option; –version: Optional arguments. (line 14) +* mypy command line option; –warn-incomplete-stub: Advanced options. + (line 37) +* mypy command line option; –warn-redundant-casts: Configuring warnings. + (line 9) +* mypy command line option; –warn-return-any: Configuring warnings. + (line 43) +* mypy command line option; –warn-unreachable: Configuring warnings. + (line 49) +* mypy command line option; –warn-unused-configs: Config file. + (line 22) +* mypy command line option; –warn-unused-ignores: Configuring warnings. + (line 14) +* mypy command line option; –xml-report: Report generation. (line 56) +* mypy_path; configuration value: Import discovery<2>. (line 9) +* namespace_packages; configuration value: Import discovery<2>. + (line 98) +* no_implicit_optional; configuration value: None and Optional handling<2>. + (line 9) +* no_silence_site_packages; configuration value: Import discovery<2>. + (line 210) +* no_site_packages; configuration value: Import discovery<2>. (line 197) +* pdb; configuration value: Advanced options<2>. (line 16) +* platform; configuration value: Platform configuration<2>. + (line 18) +* plugins; configuration value: Advanced options<2>. (line 8) +* pretty; configuration value: Configuring error messages<2>. + (line 42) +* Python Enhancement Proposals; PEP 3107: Function signatures and dynamic vs static typing. + (line 40) +* Python Enhancement Proposals; PEP 420: Import discovery. (line 11) +* Python Enhancement Proposals; PEP 420 <1>: Import discovery<2>. + (line 106) +* Python Enhancement Proposals; PEP 484: Introduction. (line 13) +* Python Enhancement Proposals; PEP 484 <1>: Type hints cheat sheet Python 3. + (line 6) +* Python Enhancement Proposals; PEP 484 <2>: Type hints cheat sheet Python 2. + (line 6) +* Python Enhancement Proposals; PEP 484 <3>: Type checking Python 2 code. + (line 8) +* Python Enhancement Proposals; PEP 484 <4>: Multi-line Python 2 function annotations. + (line 14) +* Python Enhancement Proposals; PEP 484 <5>: Extending mypy using plugins. + (line 9) +* Python Enhancement Proposals; PEP 484 <6>: Extending mypy using plugins. + (line 15) +* Python Enhancement Proposals; PEP 484 <7>: Current list of plugin hooks. + (line 7) +* Python Enhancement Proposals; PEP 484 <8>: Automatic stub generation stubgen. + (line 6) +* Python Enhancement Proposals; PEP 484#function-method-overloading: Function overloading. + (line 33) +* Python Enhancement Proposals; PEP 484#suggested-syntax-for-python-2-7-and-straddling-code: How do I type check my Python 2 code?. + (line 6) +* Python Enhancement Proposals; PEP 484#the-type-of-class-objects: The type of class objects. + (line 6) +* Python Enhancement Proposals; PEP 484#the-type-of-class-objects <1>: The type of class objects. + (line 70) +* Python Enhancement Proposals; PEP 484#type-aliases: Generic type aliases. + (line 11) +* Python Enhancement Proposals; PEP 492: Typing async/await. (line 8) +* Python Enhancement Proposals; PEP 508: Using new additions to the typing module. + (line 27) +* Python Enhancement Proposals; PEP 526: Introduction. (line 13) +* Python Enhancement Proposals; PEP 526 <1>: Local type inference. + (line 39) +* Python Enhancement Proposals; PEP 526 <2>: Variables. (line 6) +* Python Enhancement Proposals; PEP 526 <3>: Defining subprotocols and subclassing protocols. + (line 53) +* Python Enhancement Proposals; PEP 544: Protocols and structural subtyping. + (line 19) +* Python Enhancement Proposals; PEP 544 <1>: Can I use duck typing with mypy?. + (line 33) +* Python Enhancement Proposals; PEP 544#generic-protocols: Generic protocols. + (line 37) +* Python Enhancement Proposals; PEP 557: Dataclasses. (line 57) +* Python Enhancement Proposals; PEP 561: Creating a stub. (line 21) +* Python Enhancement Proposals; PEP 561 <1>: How imports are found. + (line 27) +* Python Enhancement Proposals; PEP 561 <2>: Import discovery. + (line 70) +* Python Enhancement Proposals; PEP 561 <3>: Import discovery. + (line 80) +* Python Enhancement Proposals; PEP 561 <4>: Import discovery. + (line 89) +* Python Enhancement Proposals; PEP 561 <5>: Platform configuration. + (line 22) +* Python Enhancement Proposals; PEP 561 <6>: Import discovery<2>. + (line 205) +* Python Enhancement Proposals; PEP 561 <7>: Import discovery<2>. + (line 219) +* Python Enhancement Proposals; PEP 561 <8>: Using installed packages. + (line 20) +* Python Enhancement Proposals; PEP 561 <9>: Creating PEP 561 compatible packages. + (line 10) +* Python Enhancement Proposals; PEP 561#stub-only-packages: Using installed packages with mypy PEP 561. + (line 31) +* Python Enhancement Proposals; PEP 563: Annotation issues at runtime. + (line 12) +* Python Enhancement Proposals; PEP 563 <1>: Future annotations import PEP 563. + (line 15) +* Python Enhancement Proposals; PEP 585: Using generic builtins. + (line 6) +* Python Enhancement Proposals; PEP 604: X | Y syntax for Unions. + (line 6) +* Python Enhancement Proposals; PEP 604 <1>: Future annotations import PEP 563. + (line 38) +* Python Enhancement Proposals; PEP 604 <2>: Using X | Y syntax for Unions. + (line 6) +* Python Enhancement Proposals; PEP 613: Type aliases. (line 27) +* Python Enhancement Proposals; PEP 613 <1>: Variables vs type aliases. + (line 22) +* Python Enhancement Proposals; PEP 647: User-Defined Type Guards. + (line 6) +* python_executable; configuration value: Import discovery<2>. + (line 185) +* python_version; configuration value: Platform configuration<2>. + (line 6) +* raise_exceptions; configuration value: Advanced options<2>. (line 36) +* scripts_are_modules; configuration value: Miscellaneous<4>. (line 17) +* show_absolute_path; configuration value: Configuring error messages<2>. + (line 73) +* show_column_numbers; configuration value: Configuring error messages<2>. + (line 21) +* show_error_codes; configuration value: Configuring error messages<2>. + (line 31) +* show_error_context; configuration value: Configuring error messages<2>. + (line 11) +* show_none_errors; configuration value: Suppressing errors. (line 9) +* show_traceback; configuration value: Advanced options<2>. (line 26) +* skip_cache_mtime_checks; configuration value: Incremental mode<2>. + (line 69) +* skip_version_check; configuration value: Incremental mode<2>. + (line 56) +* sqlite_cache; configuration value: Incremental mode<2>. (line 35) +* strict; configuration value: Miscellaneous strictness flags<2>. + (line 97) +* strict_equality; configuration value: Miscellaneous strictness flags<2>. + (line 86) +* strict_optional; configuration value: None and Optional handling<2>. + (line 20) +* stubgen command line option; –doc-dir: Specifying how to generate stubs. + (line 33) +* stubgen command line option; –export-less: Additional flags. + (line 26) +* stubgen command line option; -h: Additional flags. (line 6) +* stubgen command line option; –help: Additional flags. (line 6) +* stubgen command line option; –ignore-errors: Additional flags. + (line 14) +* stubgen command line option; –include-private: Additional flags. + (line 20) +* stubgen command line option; -m: Specifying what to stub. + (line 26) +* stubgen command line option; –module: Specifying what to stub. + (line 26) +* stubgen command line option; –no-import: Specifying how to generate stubs. + (line 13) +* stubgen command line option; -o: Additional flags. (line 44) +* stubgen command line option; –output: Additional flags. (line 44) +* stubgen command line option; -p: Specifying what to stub. + (line 34) +* stubgen command line option; –package: Specifying what to stub. + (line 34) +* stubgen command line option; –parse-only: Specifying how to generate stubs. + (line 25) +* stubgen command line option; –py2: Additional flags. (line 10) +* stubgen command line option; –python-executable: Additional flags. + (line 37) +* stubgen command line option; -q: Additional flags. (line 55) +* stubgen command line option; –quiet: Additional flags. (line 55) +* stubgen command line option; –search-path: Additional flags. + (line 32) +* stubgen command line option; -v: Additional flags. (line 51) +* stubgen command line option; –verbose: Additional flags. (line 51) +* stubtest command line option; –allowlist: Usage. (line 36) +* stubtest command line option; –check-typeshed: Usage. (line 59) +* stubtest command line option; –concise: Usage. (line 23) +* stubtest command line option; –custom-typeshed-dir: Usage. (line 55) +* stubtest command line option; –generate-allowlist: Usage. (line 42) +* stubtest command line option; –help: Usage. (line 63) +* stubtest command line option; –ignore-missing-stub: Usage. (line 27) +* stubtest command line option; –ignore-positional-only: Usage. + (line 31) +* stubtest command line option; –ignore-unused-allowlist: Usage. + (line 46) +* stubtest command line option; –mypy-config-file: Usage. (line 50) +* txt_report / xslt_txt_report; configuration value: Report generation<2>. + (line 66) +* verbosity; configuration value: Miscellaneous<4>. (line 40) +* warn_incomplete_stub; configuration value: Advanced options<2>. + (line 63) +* warn_no_return; configuration value: Configuring warnings<2>. + (line 31) +* warn_redundant_casts; configuration value: Configuring warnings<2>. + (line 9) +* warn_return_any; configuration value: Configuring warnings<2>. + (line 41) +* warn_unreachable; configuration value: Configuring warnings<2>. + (line 52) +* warn_unused_configs; configuration value: Miscellaneous<4>. (line 28) +* warn_unused_ignores; configuration value: Configuring warnings<2>. + (line 21) +* xml_report; configuration value: Report generation<2>. + (line 77) + + + +Tag Table: +Node: Top311 +Ref: index doc498 +Ref: 0498 +Node: Introduction1853 +Ref: introduction doc1939 +Ref: 11939 +Ref: introduction introduction1939 +Ref: 21939 +Ref: introduction welcome-to-mypy-documentation1939 +Ref: 31939 +Ref: Introduction-Footnote-13603 +Ref: Introduction-Footnote-23645 +Node: Getting started3687 +Ref: getting_started doc3806 +Ref: 43806 +Ref: getting_started getting-started3806 +Ref: 53806 +Ref: getting_started id13806 +Ref: 63806 +Ref: Getting started-Footnote-14419 +Node: Installing and running mypy4487 +Ref: getting_started installing-and-running-mypy4621 +Ref: 74621 +Ref: Installing and running mypy-Footnote-15859 +Node: Function signatures and dynamic vs static typing5901 +Ref: getting_started function-signatures-and-dynamic-vs-static-typing6068 +Ref: a6068 +Ref: Function signatures and dynamic vs static typing-Footnote-18845 +Node: More function signatures8887 +Ref: getting_started more-function-signatures9065 +Ref: d9065 +Node: Additional types and the typing module10358 +Ref: getting_started additional-types-and-the-typing-module10508 +Ref: e10508 +Ref: Additional types and the typing module-Footnote-114531 +Ref: Additional types and the typing module-Footnote-214592 +Ref: Additional types and the typing module-Footnote-314653 +Ref: Additional types and the typing module-Footnote-414719 +Ref: Additional types and the typing module-Footnote-514787 +Ref: Additional types and the typing module-Footnote-614855 +Ref: Additional types and the typing module-Footnote-714944 +Ref: Additional types and the typing module-Footnote-815014 +Ref: Additional types and the typing module-Footnote-915075 +Ref: Additional types and the typing module-Footnote-1015142 +Ref: Additional types and the typing module-Footnote-1115210 +Ref: Additional types and the typing module-Footnote-1215279 +Ref: Additional types and the typing module-Footnote-1315348 +Ref: Additional types and the typing module-Footnote-1415436 +Node: Local type inference15507 +Ref: getting_started local-type-inference15659 +Ref: 1115659 +Ref: Local type inference-Footnote-117712 +Ref: Local type inference-Footnote-217780 +Node: Library stubs and typeshed17822 +Ref: getting_started library-stubs-and-typeshed17952 +Ref: 1217952 +Ref: getting_started stubs-intro17952 +Ref: 1317952 +Ref: Library stubs and typeshed-Footnote-120126 +Ref: Library stubs and typeshed-Footnote-220169 +Node: Configuring mypy20230 +Ref: getting_started configuring-mypy20350 +Ref: 1820350 +Node: Next steps21417 +Ref: getting_started next-steps21502 +Ref: 1b21502 +Ref: Next steps-Footnote-122629 +Ref: Next steps-Footnote-222703 +Ref: Next steps-Footnote-322755 +Ref: Next steps-Footnote-422807 +Ref: Next steps-Footnote-522853 +Node: Using mypy with an existing codebase22893 +Ref: existing_code doc23031 +Ref: 1f23031 +Ref: existing_code existing-code23031 +Ref: 1a23031 +Ref: existing_code using-mypy-with-an-existing-codebase23031 +Ref: 2023031 +Ref: Using mypy with an existing codebase-Footnote-124145 +Ref: Using mypy with an existing codebase-Footnote-224208 +Node: Start small24254 +Ref: existing_code start-small24363 +Ref: 2124363 +Node: Mypy runner script26604 +Ref: existing_code mypy-runner-script26744 +Ref: 2326744 +Node: Continuous Integration27204 +Ref: existing_code continuous-integration27365 +Ref: 2427365 +Node: Annotate widely imported modules27808 +Ref: existing_code annotate-widely-imported-modules27978 +Ref: 2527978 +Node: Write annotations as you go28470 +Ref: existing_code write-annotations-as-you-go28652 +Ref: 2628652 +Node: Automate annotation of legacy code29105 +Ref: existing_code automate-annotation-of-legacy-code29273 +Ref: 2729273 +Ref: Automate annotation of legacy code-Footnote-129923 +Ref: Automate annotation of legacy code-Footnote-229986 +Node: Speed up mypy runs30032 +Ref: existing_code speed-up-mypy-runs30199 +Ref: 2830199 +Node: Introduce stricter options30518 +Ref: existing_code introduce-stricter-options30642 +Ref: 2b30642 +Ref: index overview-cheat-sheets31208 +Ref: f31208 +Node: Type hints cheat sheet Python 331210 +Ref: cheat_sheet_py3 doc31364 +Ref: 2f31364 +Ref: cheat_sheet_py3 cheat-sheet-py331364 +Ref: 1c31364 +Ref: cheat_sheet_py3 pyannotate31364 +Ref: 3031364 +Ref: cheat_sheet_py3 type-hints-cheat-sheet-python-331364 +Ref: 3131364 +Ref: Type hints cheat sheet Python 3-Footnote-132090 +Node: Variables32132 +Ref: cheat_sheet_py3 variables32230 +Ref: 3232230 +Ref: Variables-Footnote-132894 +Node: Built-in types32936 +Ref: cheat_sheet_py3 built-in-types33052 +Ref: 3333052 +Node: Functions34590 +Ref: cheat_sheet_py3 functions34749 +Ref: 3434749 +Node: When you’re puzzled or when things are complicated36250 +Ref: cheat_sheet_py3 when-you-re-puzzled-or-when-things-are-complicated36420 +Ref: 3536420 +Node: Standard “duck types”38989 +Ref: cheat_sheet_py3 standard-duck-types39157 +Ref: 3639157 +Node: Classes40550 +Ref: cheat_sheet_py3 classes40688 +Ref: 3840688 +Node: Coroutines and asyncio41693 +Ref: cheat_sheet_py3 coroutines-and-asyncio41819 +Ref: 3941819 +Node: Miscellaneous42276 +Ref: cheat_sheet_py3 miscellaneous42405 +Ref: 3b42405 +Node: Decorators43379 +Ref: cheat_sheet_py3 decorators43477 +Ref: 3c43477 +Node: Type hints cheat sheet Python 243834 +Ref: cheat_sheet doc43969 +Ref: 3e43969 +Ref: cheat_sheet cheat-sheet-py243969 +Ref: 1d43969 +Ref: cheat_sheet type-hints-cheat-sheet-python-243969 +Ref: 3f43969 +Ref: Type hints cheat sheet Python 2-Footnote-144922 +Node: Built-in types<2>44964 +Ref: cheat_sheet built-in-types45068 +Ref: 4045068 +Node: Functions<2>46291 +Ref: cheat_sheet functions46459 +Ref: 4146459 +Node: When you’re puzzled or when things are complicated<2>48398 +Ref: cheat_sheet when-you-re-puzzled-or-when-things-are-complicated48577 +Ref: 4248577 +Node: Standard “duck types”<2>51095 +Ref: cheat_sheet standard-duck-types51272 +Ref: 4351272 +Node: Classes<2>52534 +Ref: cheat_sheet classes52672 +Ref: 4452672 +Node: Miscellaneous<2>53225 +Ref: cheat_sheet miscellaneous53348 +Ref: 4553348 +Node: Decorators<2>53988 +Ref: cheat_sheet decorators54092 +Ref: 4654092 +Ref: index overview-type-system-reference54472 +Ref: 1054472 +Node: Built-in types<3>54473 +Ref: builtin_types doc54612 +Ref: 4754612 +Ref: builtin_types built-in-types54612 +Ref: 4854612 +Node: Simple types54813 +Ref: builtin_types simple-types54894 +Ref: 4954894 +Node: Any type55873 +Ref: builtin_types any-type55976 +Ref: 4a55976 +Ref: Any type-Footnote-156521 +Node: Generic types56589 +Ref: builtin_types generic-types56671 +Ref: 4c56671 +Ref: Generic types-Footnote-160274 +Ref: Generic types-Footnote-260361 +Ref: Generic types-Footnote-360429 +Ref: Generic types-Footnote-460497 +Node: Type inference and type annotations60584 +Ref: type_inference_and_annotations doc60706 +Ref: 4e60706 +Ref: type_inference_and_annotations type-inference-and-type-annotations60706 +Ref: 4f60706 +Node: Type inference61045 +Ref: type_inference_and_annotations type-inference61166 +Ref: 5061166 +Node: Explicit types for variables61725 +Ref: type_inference_and_annotations explicit-types-for-variables61885 +Ref: 5161885 +Ref: type_inference_and_annotations explicit-var-types61885 +Ref: 5261885 +Ref: Explicit types for variables-Footnote-163383 +Node: Explicit types for collections63449 +Ref: type_inference_and_annotations explicit-types-for-collections63627 +Ref: 5363627 +Ref: Explicit types for collections-Footnote-164658 +Ref: Explicit types for collections-Footnote-264719 +Ref: Explicit types for collections-Footnote-364780 +Ref: Explicit types for collections-Footnote-464842 +Ref: Explicit types for collections-Footnote-564902 +Ref: Explicit types for collections-Footnote-664968 +Node: Compatibility of container types65034 +Ref: type_inference_and_annotations compatibility-of-container-types65209 +Ref: 5465209 +Ref: Compatibility of container types-Footnote-166411 +Ref: Compatibility of container types-Footnote-266472 +Node: Context in type inference66532 +Ref: type_inference_and_annotations context-in-type-inference66720 +Ref: 5666720 +Node: Declaring multiple variable types at a time68101 +Ref: type_inference_and_annotations declaring-multiple-variable-types-at-a-time68276 +Ref: 5768276 +Node: Starred expressions68925 +Ref: type_inference_and_annotations starred-expressions69096 +Ref: 5869096 +Node: Silencing type errors69776 +Ref: type_inference_and_annotations silencing-type-errors69895 +Ref: 5969895 +Node: Kinds of types71889 +Ref: kinds_of_types doc72006 +Ref: 5c72006 +Ref: kinds_of_types kinds-of-types72006 +Ref: 5d72006 +Node: Class types72563 +Ref: kinds_of_types class-types72644 +Ref: 5e72644 +Ref: Class types-Footnote-173460 +Node: The Any type73524 +Ref: kinds_of_types the-any-type73625 +Ref: 5f73625 +Node: Tuple types75985 +Ref: kinds_of_types id176101 +Ref: 6076101 +Ref: kinds_of_types tuple-types76101 +Ref: 6176101 +Ref: Tuple types-Footnote-177421 +Node: Callable types and lambdas77491 +Ref: kinds_of_types callable-types77606 +Ref: 6377606 +Ref: kinds_of_types callable-types-and-lambdas77606 +Ref: 6477606 +Node: Union types79598 +Ref: kinds_of_types id279734 +Ref: 6679734 +Ref: kinds_of_types union-types79734 +Ref: 6779734 +Ref: Union types-Footnote-181050 +Ref: Union types-Footnote-281118 +Ref: Union types-Footnote-381186 +Node: Optional types and the None type81254 +Ref: kinds_of_types optional-types-and-the-none-type81398 +Ref: 6981398 +Ref: kinds_of_types strict-optional81398 +Ref: 6a81398 +Ref: Optional types and the None type-Footnote-186608 +Ref: Optional types and the None type-Footnote-286678 +Node: X | Y syntax for Unions86748 +Ref: kinds_of_types alternative-union-syntax86838 +Ref: 6c86838 +Ref: kinds_of_types x-y-syntax-for-unions86838 +Ref: 6d86838 +Ref: X | Y syntax for Unions-Footnote-187422 +Node: Disabling strict optional checking87464 +Ref: kinds_of_types disabling-strict-optional-checking87609 +Ref: 6f87609 +Ref: kinds_of_types no-strict-optional87609 +Ref: 7087609 +Ref: Disabling strict optional checking-Footnote-189955 +Ref: Disabling strict optional checking-Footnote-290025 +Node: Type aliases90095 +Ref: kinds_of_types id390220 +Ref: 7390220 +Ref: kinds_of_types type-aliases90220 +Ref: 7490220 +Ref: Type aliases-Footnote-191757 +Node: Named tuples91799 +Ref: kinds_of_types id491915 +Ref: 7691915 +Ref: kinds_of_types named-tuples91915 +Ref: 6291915 +Ref: Named tuples-Footnote-193825 +Ref: Named tuples-Footnote-293908 +Node: The type of class objects93980 +Ref: kinds_of_types the-type-of-class-objects94099 +Ref: 7794099 +Ref: kinds_of_types type-of-class94099 +Ref: 7894099 +Ref: The type of class objects-Footnote-196514 +Ref: The type of class objects-Footnote-296582 +Ref: The type of class objects-Footnote-396648 +Ref: The type of class objects-Footnote-496714 +Ref: The type of class objects-Footnote-596780 +Ref: The type of class objects-Footnote-696846 +Ref: The type of class objects-Footnote-796912 +Node: Text and AnyStr96980 +Ref: kinds_of_types id597097 +Ref: 7a97097 +Ref: kinds_of_types text-and-anystr97097 +Ref: 7b97097 +Ref: Text and AnyStr-Footnote-198411 +Ref: Text and AnyStr-Footnote-298477 +Node: Generators98545 +Ref: kinds_of_types generators98628 +Ref: 7d98628 +Ref: kinds_of_types id698628 +Ref: 7e98628 +Ref: Generators-Footnote-1100829 +Ref: Generators-Footnote-2100899 +Ref: Generators-Footnote-3100969 +Ref: Generators-Footnote-4101039 +Ref: Generators-Footnote-5101109 +Ref: Generators-Footnote-6101171 +Ref: Generators-Footnote-7101248 +Ref: Generators-Footnote-8101319 +Ref: Generators-Footnote-9101390 +Ref: Generators-Footnote-10101468 +Ref: Generators-Footnote-11101546 +Ref: Generators-Footnote-12101625 +Ref: Generators-Footnote-13101697 +Ref: Generators-Footnote-14101768 +Node: Class basics101839 +Ref: class_basics doc101949 +Ref: 7f101949 +Ref: class_basics class-basics101949 +Ref: 80101949 +Node: Instance and class attributes102319 +Ref: class_basics instance-and-class-attributes102431 +Ref: 81102431 +Ref: Instance and class attributes-Footnote-1104561 +Ref: Instance and class attributes-Footnote-2104638 +Node: Annotating __init__ methods104708 +Ref: class_basics annotating-init-methods104856 +Ref: 82104856 +Ref: Annotating __init__ methods-Footnote-1105723 +Ref: Annotating __init__ methods-Footnote-2105799 +Ref: Annotating __init__ methods-Footnote-3105875 +Ref: Annotating __init__ methods-Footnote-4105951 +Node: Class attribute annotations106027 +Ref: class_basics class-attribute-annotations106181 +Ref: 83106181 +Ref: Class attribute annotations-Footnote-1107886 +Ref: Class attribute annotations-Footnote-2107956 +Ref: Class attribute annotations-Footnote-3108026 +Ref: Class attribute annotations-Footnote-4108096 +Ref: Class attribute annotations-Footnote-5108166 +Ref: Class attribute annotations-Footnote-6108234 +Ref: Class attribute annotations-Footnote-7108302 +Ref: Class attribute annotations-Footnote-8108372 +Node: Overriding statically typed methods108442 +Ref: class_basics overriding-statically-typed-methods108615 +Ref: 85108615 +Node: Abstract base classes and multiple inheritance110508 +Ref: class_basics abstract-base-classes-and-multiple-inheritance110659 +Ref: 86110659 +Ref: Abstract base classes and multiple inheritance-Footnote-1113716 +Ref: Abstract base classes and multiple inheritance-Footnote-2113767 +Ref: Abstract base classes and multiple inheritance-Footnote-3113830 +Ref: Abstract base classes and multiple inheritance-Footnote-4113900 +Ref: Abstract base classes and multiple inheritance-Footnote-5113972 +Node: Slots114035 +Ref: class_basics slots114142 +Ref: 87114142 +Ref: Slots-Footnote-1115200 +Node: Annotation issues at runtime115265 +Ref: runtime_troubles doc115395 +Ref: 88115395 +Ref: runtime_troubles annotation-issues-at-runtime115395 +Ref: 89115395 +Ref: runtime_troubles runtime-troubles115395 +Ref: 6e115395 +Ref: Annotation issues at runtime-Footnote-1116532 +Node: String literal types116574 +Ref: runtime_troubles id1116699 +Ref: 8a116699 +Ref: runtime_troubles string-literal-types116699 +Ref: 8b116699 +Node: Future annotations import PEP 563117512 +Ref: runtime_troubles future-annotations117666 +Ref: 8d117666 +Ref: runtime_troubles future-annotations-import-pep-563117666 +Ref: 8e117666 +Ref: Future annotations import PEP 563-Footnote-1119243 +Ref: Future annotations import PEP 563-Footnote-2119285 +Ref: Future annotations import PEP 563-Footnote-3119354 +Ref: Future annotations import PEP 563-Footnote-4119426 +Node: typing TYPE_CHECKING119468 +Ref: runtime_troubles id2119631 +Ref: 90119631 +Ref: runtime_troubles typing-type-checking119631 +Ref: 91119631 +Ref: typing TYPE_CHECKING-Footnote-1120084 +Ref: typing TYPE_CHECKING-Footnote-2120152 +Node: Class name forward references120228 +Ref: runtime_troubles class-name-forward-references120371 +Ref: 92120371 +Node: Import cycles121305 +Ref: runtime_troubles id3121486 +Ref: 93121486 +Ref: runtime_troubles import-cycles121486 +Ref: 8c121486 +Node: Using classes that are generic in stubs but not at runtime122685 +Ref: runtime_troubles not-generic-runtime122884 +Ref: 94122884 +Ref: runtime_troubles using-classes-that-are-generic-in-stubs-but-not-at-runtime122884 +Ref: 95122884 +Ref: Using classes that are generic in stubs but not at runtime-Footnote-1124867 +Ref: Using classes that are generic in stubs but not at runtime-Footnote-2124929 +Ref: Using classes that are generic in stubs but not at runtime-Footnote-3124994 +Node: Using types defined in stubs but not at runtime125059 +Ref: runtime_troubles using-types-defined-in-stubs-but-not-at-runtime125267 +Ref: 96125267 +Node: Using generic builtins125808 +Ref: runtime_troubles generic-builtins125987 +Ref: 4d125987 +Ref: runtime_troubles using-generic-builtins125987 +Ref: 97125987 +Ref: Using generic builtins-Footnote-1126848 +Ref: Using generic builtins-Footnote-2126890 +Ref: Using generic builtins-Footnote-3126958 +Node: Using X | Y syntax for Unions127045 +Ref: runtime_troubles using-x-y-syntax-for-unions127217 +Ref: 98127217 +Ref: Using X | Y syntax for Unions-Footnote-1127992 +Node: Using new additions to the typing module128034 +Ref: runtime_troubles using-new-additions-to-the-typing-module128175 +Ref: 99128175 +Ref: Using new additions to the typing module-Footnote-1129156 +Ref: Using new additions to the typing module-Footnote-2129224 +Node: Protocols and structural subtyping129266 +Ref: protocols doc129406 +Ref: 9a129406 +Ref: protocols protocol-types129406 +Ref: 37129406 +Ref: protocols protocols-and-structural-subtyping129406 +Ref: 9b129406 +Ref: Protocols and structural subtyping-Footnote-1130803 +Ref: Protocols and structural subtyping-Footnote-2130871 +Node: Predefined protocols130913 +Ref: protocols id1131040 +Ref: 9c131040 +Ref: protocols predefined-protocols131040 +Ref: 9d131040 +Ref: Predefined protocols-Footnote-1132488 +Ref: Predefined protocols-Footnote-2132556 +Ref: Predefined protocols-Footnote-3132626 +Ref: Predefined protocols-Footnote-4132702 +Ref: Predefined protocols-Footnote-5132772 +Node: Iteration protocols132840 +Ref: protocols iteration-protocols132943 +Ref: 9e132943 +Node: Iterable[T]133154 +Ref: protocols iterable-t133239 +Ref: 9f133239 +Ref: Iterable[T]-Footnote-1133465 +Ref: Iterable[T]-Footnote-2133541 +Node: Iterator[T]133611 +Ref: protocols iterator-t133696 +Ref: a0133696 +Ref: Iterator[T]-Footnote-1133867 +Node: Collection protocols133937 +Ref: protocols collection-protocols134066 +Ref: a1134066 +Ref: Collection protocols-Footnote-1134365 +Ref: Collection protocols-Footnote-2134426 +Node: Sized134487 +Ref: protocols sized134568 +Ref: a2134568 +Ref: Sized-Footnote-1134738 +Ref: Sized-Footnote-2134799 +Node: Container[T]134866 +Ref: protocols container-t134969 +Ref: a3134969 +Ref: Container[T]-Footnote-1135186 +Node: Collection[T]135257 +Ref: protocols collection-t135346 +Ref: a4135346 +Ref: Collection[T]-Footnote-1135571 +Node: One-off protocols135643 +Ref: protocols one-off-protocols135768 +Ref: a5135768 +Node: Reversible[T]136052 +Ref: protocols reversible-t136140 +Ref: a6136140 +Ref: Reversible[T]-Footnote-1136349 +Ref: Reversible[T]-Footnote-2136415 +Node: SupportsAbs[T]136487 +Ref: protocols supportsabs-t136597 +Ref: a7136597 +Ref: SupportsAbs[T]-Footnote-1136842 +Ref: SupportsAbs[T]-Footnote-2136903 +Ref: SupportsAbs[T]-Footnote-3136964 +Node: SupportsBytes137037 +Ref: protocols supportsbytes137149 +Ref: a8137149 +Ref: SupportsBytes-Footnote-1137349 +Ref: SupportsBytes-Footnote-2137411 +Node: SupportsComplex137487 +Ref: protocols supports-int-etc137598 +Ref: a9137598 +Ref: protocols supportscomplex137598 +Ref: aa137598 +Ref: SupportsComplex-Footnote-1137861 +Ref: SupportsComplex-Footnote-2137926 +Node: SupportsFloat138004 +Ref: protocols supportsfloat138113 +Ref: ab138113 +Ref: SupportsFloat-Footnote-1138364 +Ref: SupportsFloat-Footnote-2138427 +Node: SupportsInt138503 +Ref: protocols supportsint138613 +Ref: ac138613 +Ref: SupportsInt-Footnote-1138852 +Ref: SupportsInt-Footnote-2138913 +Node: SupportsRound[T]138986 +Ref: protocols supportsround-t139074 +Ref: ad139074 +Ref: SupportsRound[T]-Footnote-1139276 +Ref: SupportsRound[T]-Footnote-2139339 +Node: Async protocols139415 +Ref: protocols async-protocols139545 +Ref: ae139545 +Node: Awaitable[T]139764 +Ref: protocols awaitable-t139851 +Ref: af139851 +Ref: Awaitable[T]-Footnote-1140009 +Node: AsyncIterable[T]140080 +Ref: protocols asynciterable-t140192 +Ref: b0140192 +Ref: AsyncIterable[T]-Footnote-1140355 +Node: AsyncIterator[T]140431 +Ref: protocols asynciterator-t140522 +Ref: b1140522 +Ref: AsyncIterator[T]-Footnote-1140726 +Node: Context manager protocols140802 +Ref: protocols context-manager-protocols140906 +Ref: b2140906 +Node: ContextManager[T]141233 +Ref: protocols contextmanager-t141341 +Ref: b3141341 +Ref: ContextManager[T]-Footnote-1141701 +Node: AsyncContextManager[T]141778 +Ref: protocols asynccontextmanager-t141886 +Ref: b4141886 +Ref: AsyncContextManager[T]-Footnote-1142288 +Node: Simple user-defined protocols142370 +Ref: protocols simple-user-defined-protocols142553 +Ref: b5142553 +Ref: Simple user-defined protocols-Footnote-1143728 +Node: Defining subprotocols and subclassing protocols143790 +Ref: protocols defining-subprotocols-and-subclassing-protocols143972 +Ref: b6143972 +Ref: Defining subprotocols and subclassing protocols-Footnote-1145967 +Node: Recursive protocols146009 +Ref: protocols recursive-protocols146193 +Ref: b7146193 +Node: Using isinstance with protocols146950 +Ref: protocols using-isinstance-with-protocols147105 +Ref: b8147105 +Ref: Using isinstance with protocols-Footnote-1148114 +Ref: Using isinstance with protocols-Footnote-2148182 +Ref: Using isinstance with protocols-Footnote-3148250 +Ref: Using isinstance with protocols-Footnote-4148318 +Ref: Using isinstance with protocols-Footnote-5148388 +Node: Callback protocols148456 +Ref: protocols callback-protocols148583 +Ref: 65148583 +Ref: protocols id2148583 +Ref: b9148583 +Ref: Callback protocols-Footnote-1150110 +Ref: Callback protocols-Footnote-2150180 +Ref: Callback protocols-Footnote-3150256 +Ref: Callback protocols-Footnote-4150326 +Node: Dynamically typed code150402 +Ref: dynamic_typing doc150541 +Ref: ba150541 +Ref: dynamic_typing dynamic-typing150541 +Ref: 4b150541 +Ref: dynamic_typing dynamically-typed-code150541 +Ref: bb150541 +Node: Operations on Any values151258 +Ref: dynamic_typing operations-on-any-values151361 +Ref: bc151361 +Node: Any vs object152180 +Ref: dynamic_typing any-vs-object152283 +Ref: bd152283 +Ref: Any vs object-Footnote-1153285 +Ref: Any vs object-Footnote-2153349 +Ref: Any vs object-Footnote-3153413 +Ref: Any vs object-Footnote-4153477 +Node: Type checking Python 2 code153541 +Ref: python2 doc153660 +Ref: be153660 +Ref: python2 python2153660 +Ref: 9153660 +Ref: python2 type-checking-python-2-code153660 +Ref: bf153660 +Ref: Type checking Python 2 code-Footnote-1155829 +Ref: Type checking Python 2 code-Footnote-2155871 +Node: Multi-line Python 2 function annotations155939 +Ref: python2 multi-line-annotation156066 +Ref: c0156066 +Ref: python2 multi-line-python-2-function-annotations156066 +Ref: c1156066 +Ref: Multi-line Python 2 function annotations-Footnote-1158197 +Node: Additional notes158239 +Ref: python2 additional-notes158366 +Ref: c2158366 +Ref: Additional notes-Footnote-1159147 +Node: Type narrowing159190 +Ref: type_narrowing doc159310 +Ref: c3159310 +Ref: type_narrowing id1159310 +Ref: c4159310 +Ref: type_narrowing type-narrowing159310 +Ref: 8f159310 +Node: Type narrowing expressions159715 +Ref: type_narrowing type-narrowing-expressions159804 +Ref: c5159804 +Ref: Type narrowing expressions-Footnote-1162596 +Ref: Type narrowing expressions-Footnote-2162664 +Ref: Type narrowing expressions-Footnote-3162732 +Node: issubclass162798 +Ref: type_narrowing issubclass162886 +Ref: c8162886 +Ref: issubclass-Footnote-1163488 +Node: callable163556 +Ref: type_narrowing callable163644 +Ref: c9163644 +Node: Casts164413 +Ref: type_narrowing casts164535 +Ref: ca164535 +Ref: type_narrowing id2164535 +Ref: cb164535 +Ref: Casts-Footnote-1166069 +Node: User-Defined Type Guards166135 +Ref: type_narrowing type-guards166222 +Ref: cc166222 +Ref: type_narrowing user-defined-type-guards166222 +Ref: cd166222 +Ref: User-Defined Type Guards-Footnote-1168468 +Ref: User-Defined Type Guards-Footnote-2168510 +Node: Generic TypeGuards168588 +Ref: type_narrowing generic-typeguards168700 +Ref: ce168700 +Node: Typeguards with parameters169250 +Ref: type_narrowing typeguards-with-parameters169392 +Ref: cf169392 +Node: TypeGuards as methods169875 +Ref: type_narrowing typeguards-as-methods170035 +Ref: d0170035 +Ref: TypeGuards as methods-Footnote-1171140 +Node: Assignment expressions as TypeGuards171237 +Ref: type_narrowing assignment-expressions-as-typeguards171362 +Ref: d1171362 +Ref: Assignment expressions as TypeGuards-Footnote-1172492 +Node: Duck type compatibility172568 +Ref: duck_type_compatibility doc172671 +Ref: d2172671 +Ref: duck_type_compatibility duck-type-compatibility172671 +Ref: d3172671 +Node: Stub files174705 +Ref: stubs doc174802 +Ref: d4174802 +Ref: stubs id1174802 +Ref: d5174802 +Ref: stubs stub-files174802 +Ref: 16174802 +Ref: Stub files-Footnote-1175297 +Node: Creating a stub175340 +Ref: stubs creating-a-stub175425 +Ref: d6175425 +Ref: Creating a stub-Footnote-1177690 +Node: Stub file syntax177732 +Ref: stubs stub-file-syntax177859 +Ref: d9177859 +Node: Using stub file syntax at runtime179033 +Ref: stubs using-stub-file-syntax-at-runtime179136 +Ref: da179136 +Ref: Using stub file syntax at runtime-Footnote-1180819 +Ref: Using stub file syntax at runtime-Footnote-2180898 +Node: Generics180977 +Ref: generics doc181061 +Ref: db181061 +Ref: generics generics181061 +Ref: dc181061 +Node: Defining generic classes181749 +Ref: generics defining-generic-classes181848 +Ref: dd181848 +Ref: generics generic-classes181848 +Ref: 84181848 +Node: Generic class internals183548 +Ref: generics generic-class-internals183695 +Ref: de183695 +Ref: Generic class internals-Footnote-1185580 +Ref: Generic class internals-Footnote-2185641 +Ref: Generic class internals-Footnote-3185702 +Ref: Generic class internals-Footnote-4185768 +Ref: Generic class internals-Footnote-5185834 +Node: Defining sub-classes of generic classes185902 +Ref: generics defining-sub-classes-of-generic-classes186042 +Ref: df186042 +Ref: generics generic-subclasses186042 +Ref: e0186042 +Ref: Defining sub-classes of generic classes-Footnote-1188598 +Ref: Defining sub-classes of generic classes-Footnote-2188666 +Ref: Defining sub-classes of generic classes-Footnote-3188735 +Ref: Defining sub-classes of generic classes-Footnote-4188805 +Ref: Defining sub-classes of generic classes-Footnote-5188875 +Node: Generic functions188944 +Ref: generics generic-functions189093 +Ref: e1189093 +Ref: generics id1189093 +Ref: e2189093 +Node: Generic methods and generic self190284 +Ref: generics generic-methods-and-generic-self190419 +Ref: e3190419 +Ref: generics id2190419 +Ref: e4190419 +Ref: Generic methods and generic self-Footnote-1192877 +Node: Variance of generic types192943 +Ref: generics variance-of-generic-types193098 +Ref: e6193098 +Ref: generics variance-of-generics193098 +Ref: e7193098 +Ref: Variance of generic types-Footnote-1196128 +Ref: Variance of generic types-Footnote-2196195 +Ref: Variance of generic types-Footnote-3196265 +Ref: Variance of generic types-Footnote-4196336 +Ref: Variance of generic types-Footnote-5196406 +Ref: Variance of generic types-Footnote-6196472 +Node: Type variables with value restriction196538 +Ref: generics type-variable-value-restriction196693 +Ref: 7c196693 +Ref: generics type-variables-with-value-restriction196693 +Ref: e8196693 +Ref: Type variables with value restriction-Footnote-1199032 +Ref: Type variables with value restriction-Footnote-2199100 +Ref: Type variables with value restriction-Footnote-3199168 +Ref: Type variables with value restriction-Footnote-4199236 +Ref: Type variables with value restriction-Footnote-5199305 +Ref: Type variables with value restriction-Footnote-6199374 +Node: Type variables with upper bounds199435 +Ref: generics type-variable-upper-bound199585 +Ref: 79199585 +Ref: generics type-variables-with-upper-bounds199585 +Ref: e9199585 +Ref: Type variables with upper bounds-Footnote-1201039 +Node: Declaring decorators201108 +Ref: generics declaring-decorators201238 +Ref: 3d201238 +Ref: generics id3201238 +Ref: ea201238 +Ref: Declaring decorators-Footnote-1202911 +Node: Decorator factories202977 +Ref: generics decorator-factories203051 +Ref: eb203051 +Ref: generics id4203051 +Ref: ec203051 +Ref: Decorator factories-Footnote-1204377 +Node: Generic protocols204447 +Ref: generics generic-protocols204565 +Ref: ed204565 +Ref: Generic protocols-Footnote-1207174 +Ref: Generic protocols-Footnote-2207244 +Node: Generic type aliases207304 +Ref: generics generic-type-aliases207393 +Ref: 75207393 +Ref: generics id5207393 +Ref: ee207393 +Ref: Generic type aliases-Footnote-1209690 +Node: More types209745 +Ref: more_types doc209842 +Ref: ef209842 +Ref: more_types more-types209842 +Ref: f0209842 +Ref: More types-Footnote-1211286 +Ref: More types-Footnote-2211356 +Ref: More types-Footnote-3211426 +Node: The NoReturn type211496 +Ref: more_types noreturn211575 +Ref: f1211575 +Ref: more_types the-noreturn-type211575 +Ref: f2211575 +Ref: The NoReturn type-Footnote-1212538 +Ref: The NoReturn type-Footnote-2212608 +Node: NewTypes212678 +Ref: more_types id1212786 +Ref: f3212786 +Ref: more_types newtypes212786 +Ref: f4212786 +Ref: NewTypes-Footnote-1216004 +Ref: NewTypes-Footnote-2216071 +Ref: NewTypes-Footnote-3216139 +Node: Function overloading216207 +Ref: more_types function-overloading216325 +Ref: 68216325 +Ref: more_types id2216325 +Ref: f5216325 +Ref: Function overloading-Footnote-1221053 +Ref: Function overloading-Footnote-2221120 +Ref: Function overloading-Footnote-3221190 +Ref: Function overloading-Footnote-4221269 +Node: Runtime behavior221339 +Ref: more_types runtime-behavior221451 +Ref: f6221451 +Ref: Runtime behavior-Footnote-1222524 +Node: Type checking calls to overloads222592 +Ref: more_types type-checking-calls-to-overloads222739 +Ref: f7222739 +Ref: Type checking calls to overloads-Footnote-1225456 +Node: Type checking the variants225524 +Ref: more_types type-checking-the-variants225687 +Ref: f8225687 +Ref: Type checking the variants-Footnote-1230759 +Node: Type checking the implementation230823 +Ref: more_types type-checking-the-implementation230975 +Ref: f9230975 +Node: Conditional overloads232772 +Ref: more_types conditional-overloads232889 +Ref: fc232889 +Ref: Conditional overloads-Footnote-1235566 +Node: Advanced uses of self-types235642 +Ref: more_types advanced-self235770 +Ref: e5235770 +Ref: more_types advanced-uses-of-self-types235770 +Ref: 101235770 +Node: Restricted methods in generic classes236153 +Ref: more_types restricted-methods-in-generic-classes236274 +Ref: 102236274 +Ref: Restricted methods in generic classes-Footnote-1238275 +Ref: Restricted methods in generic classes-Footnote-2238351 +Node: Mixin classes238427 +Ref: more_types mixin-classes238599 +Ref: 103238599 +Node: Precise typing of alternative constructors239790 +Ref: more_types precise-typing-of-alternative-constructors239916 +Ref: 104239916 +Node: Typing async/await240724 +Ref: more_types async-and-await240841 +Ref: 3a240841 +Ref: more_types typing-async-await240841 +Ref: 105240841 +Ref: Typing async/await-Footnote-1244718 +Ref: Typing async/await-Footnote-2244760 +Ref: Typing async/await-Footnote-3244831 +Ref: Typing async/await-Footnote-4244902 +Ref: Typing async/await-Footnote-5244973 +Ref: Typing async/await-Footnote-6245049 +Node: TypedDict245128 +Ref: more_types id3245209 +Ref: 107245209 +Ref: more_types typeddict245209 +Ref: 108245209 +Ref: TypedDict-Footnote-1249442 +Ref: TypedDict-Footnote-2249503 +Ref: TypedDict-Footnote-3249564 +Ref: TypedDict-Footnote-4249625 +Ref: TypedDict-Footnote-5249686 +Ref: TypedDict-Footnote-6249755 +Node: Totality249823 +Ref: more_types totality249904 +Ref: 109249904 +Ref: Totality-Footnote-1251405 +Ref: Totality-Footnote-2251470 +Ref: Totality-Footnote-3251537 +Ref: Totality-Footnote-4251602 +Node: Supported operations251667 +Ref: more_types supported-operations251775 +Ref: 10a251775 +Ref: Supported operations-Footnote-1252931 +Ref: Supported operations-Footnote-2253000 +Ref: Supported operations-Footnote-3253065 +Ref: Supported operations-Footnote-4253131 +Ref: Supported operations-Footnote-5253199 +Ref: Supported operations-Footnote-6253266 +Ref: Supported operations-Footnote-7253332 +Ref: Supported operations-Footnote-8253404 +Ref: Supported operations-Footnote-9253472 +Ref: Supported operations-Footnote-10253537 +Ref: Supported operations-Footnote-11253605 +Node: Class-based syntax253675 +Ref: more_types class-based-syntax253813 +Ref: 10b253813 +Node: Mixing required and non-required items254697 +Ref: more_types mixing-required-and-non-required-items254835 +Ref: 10c254835 +Node: Unions of TypedDicts255742 +Ref: more_types unions-of-typeddicts255853 +Ref: 10d255853 +Node: Literal types and Enums256448 +Ref: literal_types doc256568 +Ref: 110256568 +Ref: literal_types literal-types-and-enums256568 +Ref: 111256568 +Node: Literal types256661 +Ref: literal_types id1256746 +Ref: 112256746 +Ref: literal_types literal-types256746 +Ref: 10f256746 +Node: Parameterizing Literals258820 +Ref: literal_types parameterizing-literals258927 +Ref: 113258927 +Node: Declaring literal variables260412 +Ref: literal_types declaring-literal-variables260548 +Ref: 114260548 +Node: Intelligent indexing262957 +Ref: literal_types intelligent-indexing263083 +Ref: 116263083 +Node: Tagged unions264748 +Ref: literal_types id2264870 +Ref: 117264870 +Ref: literal_types tagged-unions264870 +Ref: 10e264870 +Node: Exhaustiveness checking267928 +Ref: literal_types exhaustiveness-checking268041 +Ref: 118268041 +Node: Limitations270598 +Ref: literal_types limitations270689 +Ref: 119270689 +Node: Enums271393 +Ref: literal_types enums271478 +Ref: 11a271478 +Ref: Enums-Footnote-1272388 +Ref: Enums-Footnote-2272450 +Ref: Enums-Footnote-3272515 +Ref: Enums-Footnote-4272577 +Node: Exhaustiveness checking<2>272642 +Ref: literal_types id3272734 +Ref: 11b272734 +Node: Extra Enum checks274091 +Ref: literal_types extra-enum-checks274183 +Ref: 11c274183 +Node: Final names methods and classes275525 +Ref: final_attrs doc275646 +Ref: 11d275646 +Ref: final_attrs final-attrs275646 +Ref: 115275646 +Ref: final_attrs final-names-methods-and-classes275646 +Ref: 11e275646 +Node: Final names276489 +Ref: final_attrs final-names276588 +Ref: 11f276588 +Ref: Final names-Footnote-1277745 +Node: Syntax variants277811 +Ref: final_attrs syntax-variants277903 +Ref: 120277903 +Ref: Syntax variants-Footnote-1278782 +Node: Details of using Final278858 +Ref: final_attrs details-of-using-final278950 +Ref: 121278950 +Ref: Details of using Final-Footnote-1280952 +Ref: Details of using Final-Footnote-2281028 +Ref: Details of using Final-Footnote-3281098 +Node: Final methods281174 +Ref: final_attrs final-methods281295 +Ref: 122281295 +Node: Final classes282217 +Ref: final_attrs final-classes282318 +Ref: 123282318 +Node: Metaclasses283729 +Ref: metaclasses doc283860 +Ref: 124283860 +Ref: metaclasses id1283860 +Ref: 125283860 +Ref: metaclasses metaclasses283860 +Ref: 126283860 +Ref: Metaclasses-Footnote-1284473 +Ref: Metaclasses-Footnote-2284544 +Ref: Metaclasses-Footnote-3284606 +Ref: Metaclasses-Footnote-4284668 +Ref: Metaclasses-Footnote-5284740 +Node: Defining a metaclass284803 +Ref: metaclasses defining284901 +Ref: 127284901 +Ref: metaclasses defining-a-metaclass284901 +Ref: 128284901 +Ref: Defining a metaclass-Footnote-1285429 +Ref: Defining a metaclass-Footnote-2285494 +Node: Metaclass usage example285558 +Ref: metaclasses examples285709 +Ref: 129285709 +Ref: metaclasses metaclass-usage-example285709 +Ref: 12a285709 +Node: Gotchas and limitations of metaclass support286379 +Ref: metaclasses gotchas-and-limitations-of-metaclass-support286501 +Ref: 12b286501 +Ref: metaclasses limitations286501 +Ref: 12c286501 +Ref: Gotchas and limitations of metaclass support-Footnote-1287554 +Node: Running mypy and managing imports287616 +Ref: running_mypy doc287737 +Ref: 12d287737 +Ref: running_mypy running-mypy287737 +Ref: 12e287737 +Ref: running_mypy running-mypy-and-managing-imports287737 +Ref: 12f287737 +Node: Specifying code to be checked288747 +Ref: running_mypy id1288888 +Ref: 130288888 +Ref: running_mypy specifying-code-to-be-checked288888 +Ref: 131288888 +Node: Reading a list of files from a file291451 +Ref: running_mypy reading-a-list-of-files-from-a-file291625 +Ref: 138291625 +Node: How mypy handles imports292309 +Ref: running_mypy how-mypy-handles-imports292469 +Ref: 139292469 +Ref: running_mypy ignore-missing-imports293300 +Ref: 17293300 +Node: Missing imports293302 +Ref: running_mypy fix-missing-imports293444 +Ref: 14293444 +Ref: running_mypy missing-imports293444 +Ref: 13a293444 +Node: Missing library stubs or py typed marker294681 +Ref: running_mypy missing-library-stubs-or-py-typed-marker294807 +Ref: 13b294807 +Ref: Missing library stubs or py typed marker-Footnote-1298638 +Ref: Missing library stubs or py typed marker-Footnote-2298681 +Node: Library stubs not installed298728 +Ref: running_mypy library-stubs-not-installed298905 +Ref: 141298905 +Node: Cannot find implementation or library stub300411 +Ref: running_mypy cannot-find-implementation-or-library-stub300539 +Ref: 144300539 +Ref: running_mypy missing-type-hints-for-third-party-library300539 +Ref: 145300539 +Node: Following imports302897 +Ref: running_mypy follow-imports303044 +Ref: 22303044 +Ref: running_mypy following-imports303044 +Ref: 147303044 +Node: Mapping file paths to modules305943 +Ref: running_mypy mapping-file-paths-to-modules306096 +Ref: 14a306096 +Ref: running_mypy mapping-paths-to-modules306096 +Ref: 133306096 +Node: How imports are found309635 +Ref: running_mypy finding-imports309802 +Ref: 135309802 +Ref: running_mypy how-imports-are-found309802 +Ref: 14f309802 +Ref: How imports are found-Footnote-1311849 +Ref: How imports are found-Footnote-2311892 +Node: Other advice and best practices311934 +Ref: running_mypy other-advice-and-best-practices312113 +Ref: 150312113 +Node: Directories specific to Python 2 @python2313014 +Ref: running_mypy directories-specific-to-python-2-python2313163 +Ref: 151313163 +Node: The mypy command line313697 +Ref: command_line doc313834 +Ref: 152313834 +Ref: command_line command-line313834 +Ref: c313834 +Ref: command_line the-mypy-command-line313834 +Ref: 153313834 +Node: Specifying what to type check314515 +Ref: command_line specifying-what-to-type-check314627 +Ref: 155314627 +Ref: command_line cmdoption-mypy-m315119 +Ref: 134315119 +Ref: command_line cmdoption-mypy-module315119 +Ref: 156315119 +Ref: command_line cmdoption-mypy-p315347 +Ref: 136315347 +Ref: command_line cmdoption-mypy-package315347 +Ref: 157315347 +Ref: command_line cmdoption-mypy-c315656 +Ref: 137315656 +Ref: command_line cmdoption-mypy-command315656 +Ref: 158315656 +Ref: command_line cmdoption-mypy-exclude315773 +Ref: 14b315773 +Node: Optional arguments317472 +Ref: command_line optional-arguments317604 +Ref: 159317604 +Ref: command_line cmdoption-mypy-h317653 +Ref: 154317653 +Ref: command_line cmdoption-mypy-help317653 +Ref: 15a317653 +Ref: command_line cmdoption-mypy-v317711 +Ref: 14e317711 +Ref: command_line cmdoption-mypy-verbose317711 +Ref: 15b317711 +Ref: command_line cmdoption-mypy-V317767 +Ref: 15c317767 +Ref: command_line cmdoption-mypy-version317767 +Ref: 15d317767 +Node: Config file317842 +Ref: command_line config-file317961 +Ref: 15e317961 +Ref: command_line config-file-flag317961 +Ref: 15f317961 +Ref: command_line cmdoption-mypy-config-file317996 +Ref: 160317996 +Ref: command_line cmdoption-mypy-warn-unused-configs318556 +Ref: 161318556 +Node: Import discovery318773 +Ref: command_line id1318896 +Ref: 163318896 +Ref: command_line import-discovery318896 +Ref: 164318896 +Ref: command_line cmdoption-mypy-namespace-packages319020 +Ref: 132319020 +Ref: command_line cmdoption-mypy-explicit-package-bases319888 +Ref: 14c319888 +Ref: command_line cmdoption-mypy-ignore-missing-imports320286 +Ref: 140320286 +Ref: command_line cmdoption-mypy-follow-imports321172 +Ref: 148321172 +Ref: command_line cmdoption-mypy-python-executable321531 +Ref: 146321531 +Ref: command_line cmdoption-mypy-no-site-packages321942 +Ref: 165321942 +Ref: command_line cmdoption-mypy-no-silence-site-packages322330 +Ref: 166322330 +Ref: Import discovery-Footnote-1322566 +Ref: Import discovery-Footnote-2322608 +Ref: Import discovery-Footnote-3322650 +Ref: Import discovery-Footnote-4322692 +Node: Platform configuration322734 +Ref: command_line id2322869 +Ref: 167322869 +Ref: command_line platform-configuration322869 +Ref: 168322869 +Ref: command_line cmdoption-mypy-python-version323231 +Ref: 100323231 +Ref: command_line cmdoption-mypy-2323855 +Ref: 8323855 +Ref: command_line cmdoption-mypy-py2323855 +Ref: 169323855 +Ref: command_line cmdoption-mypy-platform324071 +Ref: 16a324071 +Ref: command_line always-true324405 +Ref: 16b324405 +Ref: command_line cmdoption-mypy-always-true324405 +Ref: fe324405 +Ref: command_line cmdoption-mypy-always-false324576 +Ref: ff324576 +Ref: Platform configuration-Footnote-1324785 +Ref: Platform configuration-Footnote-2324827 +Node: Disallow dynamic typing324891 +Ref: command_line disallow-dynamic-typing325039 +Ref: 16c325039 +Ref: command_line id3325039 +Ref: 16d325039 +Ref: command_line cmdoption-mypy-disallow-any-unimported325410 +Ref: 16e325410 +Ref: command_line cmdoption-mypy-disallow-any-expr325706 +Ref: 16f325706 +Ref: command_line cmdoption-mypy-disallow-any-decorated326263 +Ref: 170326263 +Ref: command_line cmdoption-mypy-disallow-any-explicit326413 +Ref: 171326413 +Ref: command_line cmdoption-mypy-disallow-any-generics326572 +Ref: 172326572 +Ref: command_line cmdoption-mypy-disallow-subclassing-any326838 +Ref: 173326838 +Ref: Disallow dynamic typing-Footnote-1327557 +Node: Untyped definitions and calls327623 +Ref: command_line id4327775 +Ref: 174327775 +Ref: command_line untyped-definitions-and-calls327775 +Ref: fb327775 +Ref: command_line cmdoption-mypy-disallow-untyped-calls327933 +Ref: 175327933 +Ref: command_line cmdoption-mypy-disallow-untyped-defs328097 +Ref: b328097 +Ref: command_line cmdoption-mypy-disallow-incomplete-defs328243 +Ref: 176328243 +Ref: command_line cmdoption-mypy-check-untyped-defs328384 +Ref: fa328384 +Ref: command_line cmdoption-mypy-disallow-untyped-decorators328775 +Ref: 177328775 +Node: None and Optional handling328949 +Ref: command_line id5329098 +Ref: 178329098 +Ref: command_line none-and-optional-handling329098 +Ref: 179329098 +Ref: command_line no-implicit-optional329302 +Ref: 17a329302 +Ref: command_line cmdoption-mypy-no-implicit-optional329302 +Ref: 6b329302 +Ref: command_line cmdoption-mypy-no-strict-optional329944 +Ref: 71329944 +Ref: None and Optional handling-Footnote-1330514 +Ref: None and Optional handling-Footnote-2330584 +Node: Configuring warnings330654 +Ref: command_line configuring-warnings330804 +Ref: 17b330804 +Ref: command_line id6330804 +Ref: 17c330804 +Ref: command_line cmdoption-mypy-warn-redundant-casts330974 +Ref: 17d330974 +Ref: command_line cmdoption-mypy-warn-unused-ignores331134 +Ref: 17e331134 +Ref: command_line cmdoption-mypy-no-warn-no-return331744 +Ref: 17f331744 +Ref: command_line cmdoption-mypy-warn-return-any332252 +Ref: 180332252 +Ref: command_line cmdoption-mypy-warn-unreachable332445 +Ref: c6332445 +Ref: Configuring warnings-Footnote-1334175 +Node: Miscellaneous strictness flags334245 +Ref: command_line id7334395 +Ref: 181334395 +Ref: command_line miscellaneous-strictness-flags334395 +Ref: 182334395 +Ref: command_line cmdoption-mypy-allow-untyped-globals334567 +Ref: 183334567 +Ref: command_line cmdoption-mypy-allow-redefinition334737 +Ref: 184334737 +Ref: command_line cmdoption-mypy-local-partial-types335665 +Ref: 185335665 +Ref: command_line cmdoption-mypy-no-implicit-reexport336776 +Ref: 186336776 +Ref: command_line cmdoption-mypy-strict-equality337502 +Ref: 187337502 +Ref: command_line cmdoption-mypy-strict338104 +Ref: 19338104 +Ref: command_line cmdoption-mypy-disable-error-code338402 +Ref: 188338402 +Ref: command_line cmdoption-mypy-enable-error-code338719 +Ref: 189338719 +Node: Configuring error messages339191 +Ref: command_line configuring-error-messages339337 +Ref: 18a339337 +Ref: command_line id8339337 +Ref: 18b339337 +Ref: command_line cmdoption-mypy-show-error-context339489 +Ref: 18c339489 +Ref: command_line cmdoption-mypy-show-column-numbers340136 +Ref: 18d340136 +Ref: command_line cmdoption-mypy-show-error-codes340430 +Ref: 5a340430 +Ref: command_line cmdoption-mypy-pretty340722 +Ref: 18f340722 +Ref: command_line cmdoption-mypy-no-color-output340880 +Ref: 190340880 +Ref: command_line cmdoption-mypy-no-error-summary340997 +Ref: 191340997 +Ref: command_line cmdoption-mypy-show-absolute-path341213 +Ref: 192341213 +Ref: command_line cmdoption-mypy-soft-error-limit341283 +Ref: 193341283 +Node: Incremental mode341647 +Ref: command_line incremental341779 +Ref: 194341779 +Ref: command_line incremental-mode341779 +Ref: 195341779 +Ref: command_line cmdoption-mypy-no-incremental342277 +Ref: 162342277 +Ref: command_line cmdoption-mypy-cache-dir342575 +Ref: 196342575 +Ref: command_line cmdoption-mypy-sqlite-cache343209 +Ref: 197343209 +Ref: command_line cmdoption-mypy-cache-fine-grained343289 +Ref: 198343289 +Ref: command_line cmdoption-mypy-skip-version-check343412 +Ref: 199343412 +Ref: command_line cmdoption-mypy-skip-cache-mtime-checks343574 +Ref: 19a343574 +Ref: Incremental mode-Footnote-1343710 +Node: Advanced options343742 +Ref: command_line advanced-options343865 +Ref: 19b343865 +Ref: command_line cmdoption-mypy-pdb344024 +Ref: 19c344024 +Ref: command_line cmdoption-mypy-show-traceback344132 +Ref: 19d344132 +Ref: command_line cmdoption-mypy-tb344132 +Ref: 19e344132 +Ref: command_line cmdoption-mypy-raise-exceptions344263 +Ref: 19f344263 +Ref: command_line cmdoption-mypy-custom-typing-module344333 +Ref: 1a0344333 +Ref: command_line cmdoption-mypy-custom-typeshed-dir344468 +Ref: 1a1344468 +Ref: command_line warn-incomplete-stub344892 +Ref: 1a2344892 +Ref: command_line cmdoption-mypy-warn-incomplete-stub344892 +Ref: 1a3344892 +Ref: command_line shadow-file345688 +Ref: 1a4345688 +Ref: command_line cmdoption-mypy-shadow-file345688 +Ref: 1a5345688 +Ref: Advanced options-Footnote-1346704 +Node: Report generation346772 +Ref: command_line report-generation346895 +Ref: 1a6346895 +Ref: command_line cmdoption-mypy-any-exprs-report347051 +Ref: 1a7347051 +Ref: command_line cmdoption-mypy-cobertura-xml-report347226 +Ref: 1a8347226 +Ref: command_line cmdoption-mypy-html-report347518 +Ref: 1a9347518 +Ref: command_line cmdoption-mypy-linecount-report347809 +Ref: 1aa347809 +Ref: command_line cmdoption-mypy-linecoverage-report347989 +Ref: 1ab347989 +Ref: command_line cmdoption-mypy-lineprecision-report348200 +Ref: 1ac348200 +Ref: command_line cmdoption-mypy-txt-report348365 +Ref: 1ad348365 +Ref: command_line cmdoption-mypy-xml-report348658 +Ref: 1ae348658 +Ref: Report generation-Footnote-1348962 +Ref: Report generation-Footnote-2349001 +Ref: Report generation-Footnote-3349040 +Ref: Report generation-Footnote-4349079 +Node: Miscellaneous<3>349118 +Ref: command_line miscellaneous349216 +Ref: 1af349216 +Ref: command_line cmdoption-mypy-install-types349257 +Ref: 142349257 +Ref: command_line cmdoption-mypy-non-interactive350284 +Ref: 143350284 +Ref: command_line cmdoption-mypy-junit-xml350923 +Ref: 1b0350923 +Ref: command_line cmdoption-mypy-find-occurrences351142 +Ref: 1b1351142 +Ref: command_line cmdoption-mypy-scripts-are-modules351327 +Ref: 14d351327 +Ref: Miscellaneous<3>-Footnote-1351887 +Ref: Miscellaneous<3>-Footnote-2351959 +Node: The mypy configuration file352031 +Ref: config_file doc352155 +Ref: 1b2352155 +Ref: config_file config-file352155 +Ref: 2e352155 +Ref: config_file sqlite352155 +Ref: 1b3352155 +Ref: config_file the-mypy-configuration-file352155 +Ref: 1b4352155 +Node: Config file format354327 +Ref: config_file config-file-format354445 +Ref: 1b5354445 +Ref: config_file config-precedence355802 +Ref: 1b6355802 +Ref: Config file format-Footnote-1356875 +Node: Per-module and global options356935 +Ref: config_file per-module-and-global-options357085 +Ref: 1b9357085 +Node: Inverting option values357742 +Ref: config_file inverting-option-values357882 +Ref: 1ba357882 +Node: Examples358125 +Ref: config_file examples358255 +Ref: 1bb358255 +Node: Import discovery<2>360197 +Ref: config_file config-file-import-discovery360329 +Ref: 13f360329 +Ref: config_file import-discovery360329 +Ref: 1bc360329 +Ref: config_file confval-mypy_path360468 +Ref: 13d360468 +Ref: config_file confval-files361368 +Ref: 13c361368 +Ref: config_file confval-exclude361929 +Ref: 1bd361929 +Ref: config_file confval-namespace_packages364041 +Ref: 1bf364041 +Ref: config_file confval-explicit_package_bases364341 +Ref: 1c0364341 +Ref: config_file confval-ignore_missing_imports364857 +Ref: 13e364857 +Ref: config_file confval-follow_imports365196 +Ref: 149365196 +Ref: config_file confval-follow_imports_for_stubs366030 +Ref: 1c1366030 +Ref: config_file confval-python_executable366622 +Ref: 1c2366622 +Ref: config_file confval-no_site_packages367004 +Ref: 1c3367004 +Ref: config_file confval-no_silence_site_packages367320 +Ref: 1c4367320 +Ref: Import discovery<2>-Footnote-1367797 +Ref: Import discovery<2>-Footnote-2367861 +Ref: Import discovery<2>-Footnote-3367916 +Ref: Import discovery<2>-Footnote-4367958 +Ref: Import discovery<2>-Footnote-5368000 +Node: Platform configuration<2>368042 +Ref: config_file platform-configuration368192 +Ref: 1c5368192 +Ref: config_file confval-python_version368249 +Ref: 1c6368249 +Ref: config_file confval-platform368629 +Ref: 1c7368629 +Ref: config_file confval-always_true368997 +Ref: 1c8368997 +Ref: config_file confval-always_false369190 +Ref: 1c9369190 +Ref: Platform configuration<2>-Footnote-1369421 +Node: Disallow dynamic typing<2>369485 +Ref: config_file disallow-dynamic-typing369648 +Ref: 1ca369648 +Ref: config_file confval-disallow_any_unimported369808 +Ref: 1cb369808 +Ref: config_file confval-disallow_any_expr370066 +Ref: 1cc370066 +Ref: config_file confval-disallow_any_decorated370225 +Ref: 1cd370225 +Ref: config_file confval-disallow_any_explicit370419 +Ref: 1ce370419 +Ref: config_file confval-disallow_any_generics370622 +Ref: 1cf370622 +Ref: config_file confval-disallow_subclassing_any370803 +Ref: 1d0370803 +Node: Untyped definitions and calls<2>370952 +Ref: config_file untyped-definitions-and-calls371119 +Ref: 1d1371119 +Ref: config_file confval-disallow_untyped_calls371296 +Ref: 1d2371296 +Ref: config_file confval-disallow_untyped_defs371490 +Ref: 2c371490 +Ref: config_file confval-disallow_incomplete_defs371683 +Ref: 1d3371683 +Ref: config_file confval-check_untyped_defs371846 +Ref: 2d371846 +Ref: config_file confval-disallow_untyped_decorators372004 +Ref: 1d4372004 +Node: None and Optional handling<2>372222 +Ref: config_file config-file-none-and-optional-handling372386 +Ref: 1d5372386 +Ref: config_file none-and-optional-handling372386 +Ref: 1d6372386 +Ref: config_file confval-no_implicit_optional372555 +Ref: 1d7372555 +Ref: config_file confval-strict_optional372775 +Ref: 72372775 +Ref: None and Optional handling<2>-Footnote-1373097 +Node: Configuring warnings<2>373167 +Ref: config_file configuring-warnings373317 +Ref: 1d8373317 +Ref: config_file confval-warn_redundant_casts373470 +Ref: 1d9373470 +Ref: config_file confval-warn_unused_ignores373694 +Ref: 1da373694 +Ref: config_file confval-warn_no_return373841 +Ref: 1db373841 +Ref: config_file confval-warn_return_any373998 +Ref: 1dc373998 +Ref: config_file confval-warn_unreachable374213 +Ref: 1dd374213 +Node: Suppressing errors374425 +Ref: config_file suppressing-errors374579 +Ref: 1de374579 +Ref: config_file confval-show_none_errors374763 +Ref: 1df374763 +Ref: config_file confval-ignore_errors374969 +Ref: 1e0374969 +Node: Miscellaneous strictness flags<2>375088 +Ref: config_file miscellaneous-strictness-flags375248 +Ref: 1e1375248 +Ref: config_file confval-allow_untyped_globals375431 +Ref: 1e2375431 +Ref: config_file confval-allow_redefinition375645 +Ref: 1e3375645 +Ref: config_file confval-local_partial_types376499 +Ref: 1e4376499 +Ref: config_file confval-disable_error_code376768 +Ref: 1e5376768 +Ref: config_file confval-implicit_reexport376919 +Ref: 1e6376919 +Ref: config_file confval-strict_equality377621 +Ref: 1e7377621 +Ref: config_file confval-strict377822 +Ref: 1e8377822 +Node: Configuring error messages<2>378158 +Ref: config_file configuring-error-messages378319 +Ref: 1e9378319 +Ref: config_file confval-show_error_context378559 +Ref: 1ea378559 +Ref: config_file confval-show_column_numbers378700 +Ref: 1eb378700 +Ref: config_file confval-show_error_codes378835 +Ref: 1ec378835 +Ref: config_file confval-pretty379020 +Ref: 1ed379020 +Ref: config_file confval-color_output379232 +Ref: 1ee379232 +Ref: config_file confval-error_summary379360 +Ref: 1ef379360 +Ref: config_file confval-show_absolute_path379497 +Ref: 1f0379497 +Node: Incremental mode<2>379621 +Ref: config_file incremental-mode379768 +Ref: 1f1379768 +Ref: config_file confval-incremental379884 +Ref: 1f2379884 +Ref: config_file confval-cache_dir380007 +Ref: 1f3380007 +Ref: config_file confval-sqlite_cache380511 +Ref: 1f4380511 +Ref: config_file confval-cache_fine_grained380645 +Ref: 1f5380645 +Ref: config_file confval-skip_version_check380822 +Ref: 1f6380822 +Ref: config_file confval-skip_cache_mtime_checks381145 +Ref: 1f7381145 +Ref: Incremental mode<2>-Footnote-1381335 +Node: Advanced options<2>381367 +Ref: config_file advanced-options381505 +Ref: 1f8381505 +Ref: config_file confval-plugins381621 +Ref: 1f9381621 +Ref: config_file confval-pdb381797 +Ref: 1fb381797 +Ref: config_file confval-show_traceback381907 +Ref: 1fc381907 +Ref: config_file confval-raise_exceptions382029 +Ref: 1fd382029 +Ref: config_file confval-custom_typing_module382153 +Ref: 1fe382153 +Ref: config_file confval-custom_typeshed_dir382306 +Ref: 1ff382306 +Ref: config_file confval-warn_incomplete_stub382555 +Ref: 200382555 +Ref: Advanced options<2>-Footnote-1382863 +Ref: Advanced options<2>-Footnote-2382925 +Node: Report generation<2>382993 +Ref: config_file report-generation383128 +Ref: 201383128 +Ref: config_file confval-any_exprs_report383286 +Ref: 202383286 +Ref: config_file confval-cobertura_xml_report383488 +Ref: 203383488 +Ref: config_file confval-html_report-xslt_html_report383807 +Ref: 204383807 +Ref: config_file confval-html_report / xslt_html_report383807 +Ref: 205383807 +Ref: config_file confval-linecount_report384123 +Ref: 206384123 +Ref: config_file confval-linecoverage_report384330 +Ref: 207384330 +Ref: config_file confval-lineprecision_report384568 +Ref: 208384568 +Ref: config_file confval-txt_report-xslt_txt_report384760 +Ref: 209384760 +Ref: config_file confval-txt_report / xslt_txt_report384760 +Ref: 20a384760 +Ref: config_file confval-xml_report385078 +Ref: 20b385078 +Ref: Report generation<2>-Footnote-1385409 +Ref: Report generation<2>-Footnote-2385448 +Ref: Report generation<2>-Footnote-3385487 +Ref: Report generation<2>-Footnote-4385526 +Node: Miscellaneous<4>385565 +Ref: config_file miscellaneous385708 +Ref: 20c385708 +Ref: config_file confval-junit_xml385818 +Ref: 20d385818 +Ref: config_file confval-scripts_are_modules386058 +Ref: 20e386058 +Ref: config_file confval-warn_unused_configs386292 +Ref: 1b8386292 +Ref: config_file confval-verbosity386590 +Ref: 20f386590 +Node: Using a pyproject toml file386760 +Ref: config_file using-a-pyproject-toml386905 +Ref: 1be386905 +Ref: config_file using-a-pyproject-toml-file386905 +Ref: 210386905 +Ref: Using a pyproject toml file-Footnote-1388380 +Ref: Using a pyproject toml file-Footnote-2388430 +Ref: Using a pyproject toml file-Footnote-3388455 +Node: Example pyproject toml388505 +Ref: config_file example-pyproject-toml388625 +Ref: 211388625 +Node: Inline configuration389592 +Ref: inline_config doc389718 +Ref: 212389718 +Ref: inline_config inline-config389718 +Ref: 1b7389718 +Ref: inline_config inline-configuration389718 +Ref: 213389718 +Ref: inline_config toml-documentation389718 +Ref: 214389718 +Node: Configuration comment format390056 +Ref: inline_config configuration-comment-format390139 +Ref: 215390139 +Node: Mypy daemon mypy server390929 +Ref: mypy_daemon doc391052 +Ref: 216391052 +Ref: mypy_daemon mypy-daemon391052 +Ref: 29391052 +Ref: mypy_daemon mypy-daemon-mypy-server391052 +Ref: 217391052 +Node: Basic usage392348 +Ref: mypy_daemon basic-usage392448 +Ref: 218392448 +Node: Daemon client commands393565 +Ref: mypy_daemon daemon-client-commands393697 +Ref: 219393697 +Node: Additional daemon flags395207 +Ref: mypy_daemon additional-daemon-flags395359 +Ref: 21c395359 +Ref: mypy_daemon cmdoption-dmypy-status-file395418 +Ref: 21d395418 +Ref: mypy_daemon cmdoption-dmypy-log-file395704 +Ref: 21e395704 +Ref: mypy_daemon cmdoption-dmypy-timeout395986 +Ref: 21f395986 +Ref: mypy_daemon cmdoption-dmypy-update396186 +Ref: 21a396186 +Ref: mypy_daemon cmdoption-dmypy-remove396977 +Ref: 21b396977 +Ref: mypy_daemon cmdoption-dmypy-fswatcher-dump-file397316 +Ref: 220397316 +Ref: mypy_daemon cmdoption-dmypy-perf-stats-file397729 +Ref: 221397729 +Ref: Additional daemon flags-Footnote-1397951 +Ref: Additional daemon flags-Footnote-2397996 +Node: Static inference of annotations398039 +Ref: mypy_daemon static-inference-of-annotations398160 +Ref: 222398160 +Ref: mypy_daemon cmdoption-dmypy-json399846 +Ref: 223399846 +Ref: mypy_daemon cmdoption-dmypy-no-errors400243 +Ref: 224400243 +Ref: mypy_daemon cmdoption-dmypy-no-any400444 +Ref: 225400444 +Ref: mypy_daemon cmdoption-dmypy-flex-any400642 +Ref: 226400642 +Ref: mypy_daemon cmdoption-dmypy-try-text400846 +Ref: 227400846 +Ref: mypy_daemon cmdoption-dmypy-callsites401010 +Ref: 228401010 +Ref: mypy_daemon cmdoption-dmypy-use-fixme401277 +Ref: 229401277 +Ref: mypy_daemon cmdoption-dmypy-max-guesses401520 +Ref: 22a401520 +Ref: Static inference of annotations-Footnote-1401676 +Ref: Static inference of annotations-Footnote-2401731 +Node: Using installed packages401777 +Ref: installed_packages doc401910 +Ref: 22b401910 +Ref: installed_packages installed-packages401910 +Ref: 15401910 +Ref: installed_packages mypy-plugin-for-pycharm401910 +Ref: 22c401910 +Ref: installed_packages using-installed-packages401910 +Ref: 22d401910 +Ref: Using installed packages-Footnote-1402887 +Ref: Using installed packages-Footnote-2402931 +Ref: Using installed packages-Footnote-3402982 +Ref: Using installed packages-Footnote-4403025 +Node: Using installed packages with mypy PEP 561403067 +Ref: installed_packages using-installed-packages-with-mypy-pep-561403213 +Ref: 22e403213 +Ref: Using installed packages with mypy PEP 561-Footnote-1404869 +Node: Creating PEP 561 compatible packages404930 +Ref: installed_packages creating-pep-561-compatible-packages405076 +Ref: 22f405076 +Ref: Creating PEP 561 compatible packages-Footnote-1408731 +Ref: Creating PEP 561 compatible packages-Footnote-2408773 +Ref: Creating PEP 561 compatible packages-Footnote-3408816 +Node: Extending and integrating mypy408872 +Ref: extending_mypy doc409015 +Ref: 230409015 +Ref: extending_mypy extending-and-integrating-mypy409015 +Ref: 231409015 +Ref: extending_mypy extending-mypy409015 +Ref: 232409015 +Node: Integrating mypy into another Python application409311 +Ref: extending_mypy integrating-mypy409461 +Ref: 233409461 +Ref: extending_mypy integrating-mypy-into-another-python-application409461 +Ref: 234409461 +Ref: Integrating mypy into another Python application-Footnote-1410576 +Ref: Integrating mypy into another Python application-Footnote-2410638 +Node: Extending mypy using plugins410700 +Ref: extending_mypy extending-mypy-using-plugins410890 +Ref: 1fa410890 +Ref: extending_mypy id1410890 +Ref: 235410890 +Ref: Extending mypy using plugins-Footnote-1412195 +Ref: Extending mypy using plugins-Footnote-2412237 +Ref: Extending mypy using plugins-Footnote-3412279 +Ref: Extending mypy using plugins-Footnote-4412319 +Node: Configuring mypy to use plugins412370 +Ref: extending_mypy configuring-mypy-to-use-plugins412531 +Ref: 236412531 +Ref: Configuring mypy to use plugins-Footnote-1413584 +Ref: Configuring mypy to use plugins-Footnote-2413650 +Node: High-level overview413714 +Ref: extending_mypy high-level-overview413875 +Ref: 237413875 +Node: Current list of plugin hooks415530 +Ref: extending_mypy current-list-of-plugin-hooks415693 +Ref: 239415693 +Ref: extending_mypy plugin-hooks415693 +Ref: 238415693 +Ref: Current list of plugin hooks-Footnote-1419768 +Ref: Current list of plugin hooks-Footnote-2419810 +Ref: Current list of plugin hooks-Footnote-3419886 +Ref: Current list of plugin hooks-Footnote-4419960 +Ref: Current list of plugin hooks-Footnote-5420028 +Ref: Current list of plugin hooks-Footnote-6420107 +Node: Notes about the semantic analyzer420191 +Ref: extending_mypy notes-about-the-semantic-analyzer420326 +Ref: 23a420326 +Ref: Notes about the semantic analyzer-Footnote-1421488 +Node: Automatic stub generation stubgen421554 +Ref: stubgen doc421704 +Ref: 23b421704 +Ref: stubgen automatic-stub-generation-stubgen421704 +Ref: 23c421704 +Ref: stubgen stubgen421704 +Ref: d7421704 +Ref: Automatic stub generation stubgen-Footnote-1423598 +Node: Specifying what to stub423640 +Ref: stubgen specifying-what-to-stub423772 +Ref: 23e423772 +Ref: stubgen cmdoption-stubgen-m424426 +Ref: 240424426 +Ref: stubgen cmdoption-stubgen-module424426 +Ref: 242424426 +Ref: stubgen cmdoption-stubgen-p424663 +Ref: 241424663 +Ref: stubgen cmdoption-stubgen-package424663 +Ref: 243424663 +Node: Specifying how to generate stubs425209 +Ref: stubgen specifying-how-to-generate-stubs425366 +Ref: 244425366 +Ref: stubgen cmdoption-stubgen-no-import425818 +Ref: 245425818 +Ref: stubgen cmdoption-stubgen-parse-only426432 +Ref: 246426432 +Ref: stubgen cmdoption-stubgen-doc-dir426765 +Ref: 247426765 +Node: Additional flags426972 +Ref: stubgen additional-flags427097 +Ref: 248427097 +Ref: stubgen cmdoption-stubgen-h427142 +Ref: 23d427142 +Ref: stubgen cmdoption-stubgen-help427142 +Ref: 249427142 +Ref: stubgen cmdoption-stubgen-py2427200 +Ref: 24a427200 +Ref: stubgen cmdoption-stubgen-ignore-errors427286 +Ref: 24b427286 +Ref: stubgen cmdoption-stubgen-include-private427470 +Ref: 24c427470 +Ref: stubgen cmdoption-stubgen-export-less427666 +Ref: 24d427666 +Ref: stubgen cmdoption-stubgen-search-path427888 +Ref: 24e427888 +Ref: stubgen cmdoption-stubgen-python-executable428036 +Ref: 24f428036 +Ref: stubgen cmdoption-stubgen-o428351 +Ref: 23f428351 +Ref: stubgen cmdoption-stubgen-output428351 +Ref: 250428351 +Ref: stubgen cmdoption-stubgen-v428639 +Ref: 251428639 +Ref: stubgen cmdoption-stubgen-verbose428639 +Ref: 252428639 +Ref: stubgen cmdoption-stubgen-q428701 +Ref: 253428701 +Ref: stubgen cmdoption-stubgen-quiet428701 +Ref: 254428701 +Node: Automatic stub testing stubtest428761 +Ref: stubtest doc428908 +Ref: 255428908 +Ref: stubtest automatic-stub-testing-stubtest428908 +Ref: 256428908 +Ref: stubtest stubtest428908 +Ref: d8428908 +Ref: Automatic stub testing stubtest-Footnote-1429424 +Node: What stubtest does and does not do429485 +Ref: stubtest what-stubtest-does-and-does-not-do429601 +Ref: 257429601 +Ref: What stubtest does and does not do-Footnote-1431059 +Ref: What stubtest does and does not do-Footnote-2431129 +Node: Example431172 +Ref: stubtest example431302 +Ref: 258431302 +Node: Usage431998 +Ref: stubtest usage432085 +Ref: 259432085 +Ref: stubtest cmdoption-stubtest-concise432781 +Ref: 25b432781 +Ref: stubtest cmdoption-stubtest-ignore-missing-stub432869 +Ref: 25c432869 +Ref: stubtest cmdoption-stubtest-ignore-positional-only432976 +Ref: 25d432976 +Ref: stubtest cmdoption-stubtest-allowlist433104 +Ref: 25e433104 +Ref: stubtest cmdoption-stubtest-generate-allowlist433334 +Ref: 25f433334 +Ref: stubtest cmdoption-stubtest-ignore-unused-allowlist433434 +Ref: 260433434 +Ref: stubtest cmdoption-stubtest-mypy-config-file433511 +Ref: 261433511 +Ref: stubtest cmdoption-stubtest-custom-typeshed-dir433630 +Ref: 262433630 +Ref: stubtest cmdoption-stubtest-check-typeshed433706 +Ref: 263433706 +Ref: stubtest cmdoption-stubtest-help433779 +Ref: 25a433779 +Node: Common issues and solutions433829 +Ref: common_issues doc433968 +Ref: 264433968 +Ref: common_issues common-issues433968 +Ref: 1e433968 +Ref: common_issues common-issues-and-solutions433968 +Ref: 265433968 +Node: Can’t install mypy using pip435166 +Ref: common_issues can-t-install-mypy-using-pip435310 +Ref: 266435310 +Node: No errors reported for obviously wrong code435569 +Ref: common_issues annotations-needed435771 +Ref: 267435771 +Ref: common_issues no-errors-reported-for-obviously-wrong-code435771 +Ref: 268435771 +Ref: No errors reported for obviously wrong code-Footnote-1439674 +Ref: No errors reported for obviously wrong code-Footnote-2439735 +Ref: No errors reported for obviously wrong code-Footnote-3439789 +Ref: No errors reported for obviously wrong code-Footnote-4439865 +Ref: No errors reported for obviously wrong code-Footnote-5439941 +Ref: No errors reported for obviously wrong code-Footnote-6440017 +Node: Spurious errors and locally silencing the checker440093 +Ref: common_issues silencing-checker440286 +Ref: 269440286 +Ref: common_issues spurious-errors-and-locally-silencing-the-checker440286 +Ref: 26a440286 +Ref: Spurious errors and locally silencing the checker-Footnote-1442356 +Node: Ignoring a whole file442435 +Ref: common_issues ignoring-a-whole-file442647 +Ref: 26b442647 +Node: Unexpected errors about ‘None’ and/or ‘Optional’ types442916 +Ref: common_issues unexpected-errors-about-none-and-or-optional-types443106 +Ref: 26c443106 +Node: Issues with code at runtime443783 +Ref: common_issues issues-with-code-at-runtime443970 +Ref: 26d443970 +Node: Mypy runs are slow444742 +Ref: common_issues mypy-runs-are-slow444893 +Ref: 26e444893 +Node: Types of empty collections445168 +Ref: common_issues types-of-empty-collections445329 +Ref: 26f445329 +Node: Redefinitions with incompatible types446294 +Ref: common_issues redefinitions-with-incompatible-types446461 +Ref: 270446461 +Node: Invariance vs covariance447362 +Ref: common_issues invariance-vs-covariance447541 +Ref: 271447541 +Ref: common_issues variance447541 +Ref: 55447541 +Node: Declaring a supertype as variable type448604 +Ref: common_issues declaring-a-supertype-as-variable-type448764 +Ref: 272448764 +Node: Complex type tests449486 +Ref: common_issues complex-type-tests449663 +Ref: 273449663 +Ref: Complex type tests-Footnote-1451832 +Ref: Complex type tests-Footnote-2451900 +Ref: Complex type tests-Footnote-3451968 +Ref: Complex type tests-Footnote-4452032 +Node: Python version and system platform checks452100 +Ref: common_issues python-version-and-system-platform-checks452275 +Ref: 274452275 +Ref: common_issues version-and-platform-checks452275 +Ref: fd452275 +Ref: Python version and system platform checks-Footnote-1455019 +Ref: Python version and system platform checks-Footnote-2455087 +Ref: Python version and system platform checks-Footnote-3455151 +Ref: Python version and system platform checks-Footnote-4455227 +Ref: Python version and system platform checks-Footnote-5455295 +Ref: Python version and system platform checks-Footnote-6455359 +Ref: Python version and system platform checks-Footnote-7455427 +Ref: Python version and system platform checks-Footnote-8455491 +Node: Displaying the type of an expression455555 +Ref: common_issues displaying-the-type-of-an-expression455729 +Ref: 275455729 +Ref: common_issues reveal-type455729 +Ref: 106455729 +Node: Silencing linters456706 +Ref: common_issues id1456898 +Ref: 276456898 +Ref: common_issues silencing-linters456898 +Ref: 277456898 +Node: Covariant subtyping of mutable protocol members is rejected457407 +Ref: common_issues covariant-subtyping-of-mutable-protocol-members-is-rejected457593 +Ref: 278457593 +Ref: Covariant subtyping of mutable protocol members is rejected-Footnote-1458491 +Node: Dealing with conflicting names458557 +Ref: common_issues dealing-with-conflicting-names458756 +Ref: 279458756 +Node: Using a development mypy build459495 +Ref: common_issues using-a-development-mypy-build459660 +Ref: 27a459660 +Ref: Using a development mypy build-Footnote-1460029 +Node: Variables vs type aliases460068 +Ref: common_issues variables-vs-type-aliases460225 +Ref: 27b460225 +Ref: Variables vs type aliases-Footnote-1462042 +Node: Incompatible overrides462084 +Ref: common_issues incompatible-overrides462227 +Ref: 27c462227 +Ref: Incompatible overrides-Footnote-1464104 +Node: Unreachable code464211 +Ref: common_issues unreachable464358 +Ref: c7464358 +Ref: common_issues unreachable-code464358 +Ref: 27d464358 +Node: Narrowing and inner functions465885 +Ref: common_issues narrowing-and-inner-functions466001 +Ref: 27e466001 +Node: Supported Python features466910 +Ref: supported_python_features doc467029 +Ref: 27f467029 +Ref: supported_python_features supported-python-features467029 +Ref: 280467029 +Ref: Supported Python features-Footnote-1467290 +Node: Runtime definition of methods and functions467362 +Ref: supported_python_features runtime-definition-of-methods-and-functions467465 +Ref: 281467465 +Ref: Runtime definition of methods and functions-Footnote-1468225 +Node: Error codes468290 +Ref: error_codes doc468412 +Ref: 282468412 +Ref: error_codes error-codes468412 +Ref: 18e468412 +Ref: error_codes id1468412 +Ref: 283468412 +Node: Displaying error codes469211 +Ref: error_codes displaying-error-codes469325 +Ref: 286469325 +Node: Silencing errors based on error codes469817 +Ref: error_codes silence-error-codes469931 +Ref: 5b469931 +Ref: error_codes silencing-errors-based-on-error-codes469931 +Ref: 288469931 +Node: Error codes enabled by default470799 +Ref: error_code_list doc470927 +Ref: 289470927 +Ref: error_code_list error-code-list470927 +Ref: 284470927 +Ref: error_code_list error-codes-enabled-by-default470927 +Ref: 28a470927 +Node: Check that attribute exists [attr-defined]472673 +Ref: error_code_list check-that-attribute-exists-attr-defined472848 +Ref: 28b472848 +Node: Check that attribute exists in each union item [union-attr]474039 +Ref: error_code_list check-that-attribute-exists-in-each-union-item-union-attr474264 +Ref: 28c474264 +Node: Check that name is defined [name-defined]475294 +Ref: error_code_list check-that-name-is-defined-name-defined475512 +Ref: 28d475512 +Ref: Check that name is defined [name-defined]-Footnote-1476009 +Node: Check arguments in calls [call-arg]476073 +Ref: error_code_list check-arguments-in-calls-call-arg476263 +Ref: 28e476263 +Node: Check argument types [arg-type]476718 +Ref: error_code_list check-argument-types-arg-type476918 +Ref: 28f476918 +Node: Check calls to overloaded functions [call-overload]477414 +Ref: error_code_list check-calls-to-overloaded-functions-call-overload477615 +Ref: 290477615 +Node: Check validity of types [valid-type]478361 +Ref: error_code_list check-validity-of-types-valid-type478593 +Ref: 291478593 +Ref: Check validity of types [valid-type]-Footnote-1479526 +Node: Require annotation if variable type is unclear [var-annotated]479596 +Ref: error_code_list require-annotation-if-variable-type-is-unclear-var-annotated479815 +Ref: 292479815 +Node: Check validity of overrides [override]480800 +Ref: error_code_list check-validity-of-overrides-override481027 +Ref: 293481027 +Node: Check that function returns a value [return]482201 +Ref: error_code_list check-that-function-returns-a-value-return482418 +Ref: 294482418 +Node: Check that return value is compatible [return-value]483136 +Ref: error_code_list check-that-return-value-is-compatible-return-value483363 +Ref: 295483363 +Node: Check types in assignment statement [assignment]483730 +Ref: error_code_list check-types-in-assignment-statement-assignment483950 +Ref: 296483950 +Node: Check type variable values [type-var]484462 +Ref: error_code_list check-type-variable-values-type-var484672 +Ref: 297484672 +Node: Check uses of various operators [operator]485128 +Ref: error_code_list check-uses-of-various-operators-operator485323 +Ref: 298485323 +Node: Check indexing operations [index]485710 +Ref: error_code_list check-indexing-operations-index485896 +Ref: 299485896 +Node: Check list items [list-item]486395 +Ref: error_code_list check-list-items-list-item486567 +Ref: 29a486567 +Node: Check dict items [dict-item]486914 +Ref: error_code_list check-dict-items-dict-item487091 +Ref: 29b487091 +Node: Check TypedDict items [typeddict-item]487528 +Ref: error_code_list check-typeddict-items-typeddict-item487722 +Ref: 29c487722 +Node: Check that type of target is known [has-type]488433 +Ref: error_code_list check-that-type-of-target-is-known-has-type488645 +Ref: 29d488645 +Node: Check that import target can be found [import]489921 +Ref: error_code_list check-that-import-target-can-be-found-import490142 +Ref: 29e490142 +Node: Check that each name is defined once [no-redef]490536 +Ref: error_code_list check-that-each-name-is-defined-once-no-redef490775 +Ref: 29f490775 +Node: Check that called function returns a value [func-returns-value]491649 +Ref: error_code_list check-that-called-function-returns-a-value-func-returns-value491892 +Ref: 2a0491892 +Node: Check instantiation of abstract classes [abstract]492501 +Ref: error_code_list check-instantiation-of-abstract-classes-abstract492740 +Ref: 2a1492740 +Ref: Check instantiation of abstract classes [abstract]-Footnote-1493705 +Node: Check the target of NewType [valid-newtype]493767 +Ref: error_code_list check-the-target-of-newtype-valid-newtype493990 +Ref: 2a2493990 +Node: Check the return type of __exit__ [exit-return]494877 +Ref: error_code_list check-the-return-type-of-exit-exit-return495094 +Ref: 2a3495094 +Ref: Check the return type of __exit__ [exit-return]-Footnote-1496840 +Ref: Check the return type of __exit__ [exit-return]-Footnote-2496916 +Node: Check that naming is consistent [name-match]496992 +Ref: error_code_list check-that-naming-is-consistent-name-match497239 +Ref: 2a4497239 +Node: Check that overloaded functions have an implementation [no-overload-impl]497637 +Ref: error_code_list check-that-overloaded-functions-have-an-implementation-no-overload-impl497866 +Ref: 2a5497866 +Node: Report syntax errors [syntax]498400 +Ref: error_code_list report-syntax-errors-syntax498612 +Ref: 2a6498612 +Node: Miscellaneous checks [misc]498886 +Ref: error_code_list miscellaneous-checks-misc499016 +Ref: 2a7499016 +Node: Error codes for optional checks499757 +Ref: error_code_list2 doc499893 +Ref: 2a8499893 +Ref: error_code_list2 error-codes-for-optional-checks499893 +Ref: 2a9499893 +Ref: error_code_list2 error-codes-optional499893 +Ref: 285499893 +Node: Check that type arguments exist [type-arg]501269 +Ref: error_code_list2 check-that-type-arguments-exist-type-arg501446 +Ref: 2aa501446 +Node: Check that every function has an annotation [no-untyped-def]502118 +Ref: error_code_list2 check-that-every-function-has-an-annotation-no-untyped-def502353 +Ref: 2ab502353 +Node: Check that cast is not redundant [redundant-cast]503172 +Ref: error_code_list2 check-that-cast-is-not-redundant-redundant-cast503424 +Ref: 2ac503424 +Node: Check that comparisons are overlapping [comparison-overlap]503890 +Ref: error_code_list2 check-that-comparisons-are-overlapping-comparison-overlap504142 +Ref: 2ad504142 +Node: Check that no untyped functions are called [no-untyped-call]505093 +Ref: error_code_list2 check-that-no-untyped-functions-are-called-no-untyped-call505357 +Ref: 2ae505357 +Node: Check that function does not return Any value [no-any-return]505832 +Ref: error_code_list2 check-that-function-does-not-return-any-value-no-any-return506119 +Ref: 2af506119 +Node: Check that types have no Any components due to missing imports [no-any-unimported]506677 +Ref: error_code_list2 check-that-types-have-no-any-components-due-to-missing-imports-no-any-unimported506967 +Ref: 2b0506967 +Node: Check that statement or expression is unreachable [unreachable]507787 +Ref: error_code_list2 check-that-statement-or-expression-is-unreachable-unreachable508067 +Ref: 2b1508067 +Node: Check that expression is redundant [redundant-expr]508758 +Ref: error_code_list2 check-that-expression-is-redundant-redundant-expr509033 +Ref: 2b2509033 +Node: Check that expression is not implicitly true in boolean context [truthy-bool]509733 +Ref: error_code_list2 check-that-expression-is-not-implicitly-true-in-boolean-context-truthy-bool510013 +Ref: 2b3510013 +Node: Check that # type ignore include an error code [ignore-without-code]511814 +Ref: error_code_list2 check-that-type-ignore-include-an-error-code-ignore-without-code512034 +Ref: 2b4512034 +Ref: error_code_list2 ignore-without-code512034 +Ref: 287512034 +Node: Additional features513030 +Ref: additional_features doc513162 +Ref: 2b5513162 +Ref: additional_features additional-features513162 +Ref: 2b6513162 +Node: Dataclasses513436 +Ref: additional_features dataclasses513527 +Ref: 2b7513527 +Ref: additional_features dataclasses-support513527 +Ref: 2b8513527 +Ref: Dataclasses-Footnote-1515094 +Ref: Dataclasses-Footnote-2515173 +Ref: Dataclasses-Footnote-3515255 +Ref: Dataclasses-Footnote-4515328 +Ref: Dataclasses-Footnote-5515387 +Node: Caveats/Known Issues515429 +Ref: additional_features caveats-known-issues515495 +Ref: 2b9515495 +Ref: Caveats/Known Issues-Footnote-1516697 +Ref: Caveats/Known Issues-Footnote-2516776 +Ref: Caveats/Known Issues-Footnote-3516856 +Ref: Caveats/Known Issues-Footnote-4516935 +Node: The attrs package517017 +Ref: additional_features attrs-package517159 +Ref: 2ba517159 +Ref: additional_features the-attrs-package517159 +Ref: 2bb517159 +Ref: The attrs package-Footnote-1518523 +Ref: The attrs package-Footnote-2518574 +Node: Caveats/Known Issues<2>518631 +Ref: additional_features id1518706 +Ref: 2bc518706 +Ref: Caveats/Known Issues<2>-Footnote-1519714 +Ref: Caveats/Known Issues<2>-Footnote-2519790 +Ref: Caveats/Known Issues<2>-Footnote-3519864 +Node: Using a remote cache to speed up mypy runs519926 +Ref: additional_features remote-cache520080 +Ref: 2a520080 +Ref: additional_features using-a-remote-cache-to-speed-up-mypy-runs520080 +Ref: 2bd520080 +Node: Shared repository for cache files521836 +Ref: additional_features shared-repository-for-cache-files521983 +Ref: 2be521983 +Node: Continuous Integration build522529 +Ref: additional_features continuous-integration-build522704 +Ref: 2bf522704 +Node: Mypy wrapper script523440 +Ref: additional_features mypy-wrapper-script523606 +Ref: 2c0523606 +Node: Caching with mypy daemon524538 +Ref: additional_features caching-with-mypy-daemon524687 +Ref: 2c1524687 +Node: Refinements525622 +Ref: additional_features refinements525743 +Ref: 2c2525743 +Node: Extended Callable types527773 +Ref: additional_features extended-callable527901 +Ref: 2c3527901 +Ref: additional_features extended-callable-types527901 +Ref: 2c4527901 +Ref: Extended Callable types-Footnote-1531752 +Ref: Extended Callable types-Footnote-2531822 +Ref: Extended Callable types-Footnote-3531892 +Ref: Extended Callable types-Footnote-4531962 +Ref: Extended Callable types-Footnote-5532032 +Node: Frequently Asked Questions532102 +Ref: faq doc532221 +Ref: 2c5532221 +Ref: faq frequently-asked-questions532221 +Ref: 2c6532221 +Node: Why have both dynamic and static typing?532843 +Ref: faq why-have-both-dynamic-and-static-typing532997 +Ref: 2c7532997 +Ref: Why have both dynamic and static typing?-Footnote-1534661 +Node: Would my project benefit from static typing?534694 +Ref: faq would-my-project-benefit-from-static-typing534910 +Ref: 2c8534910 +Node: Can I use mypy to type check my existing Python code?535982 +Ref: faq can-i-use-mypy-to-type-check-my-existing-python-code536205 +Ref: 2c9536205 +Node: Will static typing make my programs run faster?536628 +Ref: faq will-static-typing-make-my-programs-run-faster536844 +Ref: 2ca536844 +Node: How do I type check my Python 2 code?537256 +Ref: faq how-do-i-type-check-my-python-2-code537432 +Ref: 2cb537432 +Ref: How do I type check my Python 2 code?-Footnote-1537783 +Node: Is mypy free?537878 +Ref: faq is-mypy-free538039 +Ref: 2cc538039 +Node: Can I use duck typing with mypy?538215 +Ref: faq can-i-use-duck-typing-with-mypy538389 +Ref: 2cd538389 +Ref: Can I use duck typing with mypy?-Footnote-1540046 +Ref: Can I use duck typing with mypy?-Footnote-2540107 +Ref: Can I use duck typing with mypy?-Footnote-3540168 +Ref: Can I use duck typing with mypy?-Footnote-4540238 +Ref: Can I use duck typing with mypy?-Footnote-5540306 +Ref: Can I use duck typing with mypy?-Footnote-6540374 +Node: I like Python and I have no need for static typing540416 +Ref: faq i-like-python-and-i-have-no-need-for-static-typing540628 +Ref: 2ce540628 +Node: How are mypy programs different from normal Python?541111 +Ref: faq how-are-mypy-programs-different-from-normal-python541325 +Ref: 2cf541325 +Node: How is mypy different from Cython?542189 +Ref: faq how-is-mypy-different-from-cython542373 +Ref: 2d0542373 +Ref: How is mypy different from Cython?-Footnote-1544271 +Node: Does it run on PyPy?544323 +Ref: faq does-it-run-on-pypy544490 +Ref: 2d1544490 +Ref: Does it run on PyPy?-Footnote-1544801 +Node: Mypy is a cool project Can I help?544845 +Ref: faq mypy-is-a-cool-project-can-i-help544969 +Ref: 2d2544969 +Ref: Mypy is a cool project Can I help?-Footnote-1545499 +Node: Indices and tables545545 +Ref: index indices-and-tables545650 +Ref: 2d3545650 +Node: Index545717 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/info/dir b/info/dir index b07696cd..2c67b9a8 100644 --- a/info/dir +++ b/info/dir @@ -28,3 +28,4 @@ Miscellaneous * Invoke: (invoke.info). One line description of project * Pytest: (pytest.info). One line description of project * Sphinx: (sphinx.info). One line description of project +* Mypy: (Mypy.info). One line description of project