diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index e9e81b0daa52..48d60522762d 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -3,542 +3,545 @@ The mypy command line ===================== -This section documents many of mypy's command line flags. A quick -summary of command line flags can always be printed using the ``-h`` -flag (or its long form ``--help``):: - - $ mypy -h - usage: mypy [-h] [-v] [-V] [--python-version x.y] [--platform PLATFORM] [-2] - [--ignore-missing-imports] - [--follow-imports {normal,silent,skip,error}] - [--disallow-any-unimported] [--disallow-any-expr] - [--disallow-any-decorated] [--disallow-any-explicit] - [--disallow-any-generics] [--disallow-untyped-calls] - [--disallow-untyped-defs] [--disallow-incomplete-defs] - [--check-untyped-defs] [--disallow-subclassing-any] - [--warn-incomplete-stub] [--disallow-untyped-decorators] - [--warn-redundant-casts] [--no-warn-no-return] [--warn-return-any] - [--warn-unused-ignores] [--warn-unused-configs] - [--show-error-context] [--no-implicit-optional] [--no-incremental] - [--quick-and-dirty] [--cache-dir DIR] [--cache-fine-grained] - [--skip-version-check] [--no-strict-optional] - [--strict-optional-whitelist [GLOB [GLOB ...]]] - [--always-true NAME] [--always-false NAME] [--junit-xml JUNIT_XML] - [--pdb] [--show-traceback] [--stats] [--inferstats] - [--custom-typing MODULE] [--custom-typeshed-dir DIR] - [--scripts-are-modules] [--config-file CONFIG_FILE] - [--show-column-numbers] [--find-occurrences CLASS.MEMBER] - [--strict] [--shadow-file SOURCE_FILE SHADOW_FILE] - [--any-exprs-report DIR] [--cobertura-xml-report DIR] - [--html-report DIR] [--linecount-report DIR] - [--linecoverage-report DIR] [--memory-xml-report DIR] - [--txt-report DIR] [--xml-report DIR] [--xslt-html-report DIR] - [--xslt-txt-report DIR] [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] - [files [files ...]] - - (etc., too long to show everything here) - -Specifying files and directories to be checked -********************************************** - -You've already seen ``mypy program.py`` as a way to type check the -file ``program.py``. More generally you can pass any number of files -and directories on the command line and they will all be type checked -together. - -- Files ending in ``.py`` (and stub files ending in ``.pyi``) are - checked as Python modules. - -- Files not ending in ``.py`` or ``.pyi`` are assumed to be Python - scripts and checked as such. - -- Directories representing Python packages (i.e. containing a - ``__init__.py[i]`` file) are checked as Python packages; all - submodules and subpackages will be checked (subpackages must - themselves have a ``__init__.py[i]`` file). - -- Directories that don't represent Python packages (i.e. not directly - containing an ``__init__.py[i]`` file) are checked as follows: - - - All ``*.py[i]`` files contained directly therein are checked as - toplevel Python modules; - - - All packages contained directly therein (i.e. immediate - subdirectories with an ``__init__.py[i]`` file) are checked as - toplevel Python packages. - -One more thing about checking modules and packages: if the directory -*containing* a module or package specified on the command line has an -``__init__.py[i]`` file, mypy assigns these an absolute module name by -crawling up the path until no ``__init__.py[i]`` file is found. For -example, suppose we run the command ``mypy foo/bar/baz.py`` where -``foo/bar/__init__.py`` exists but ``foo/__init__.py`` does not. Then -the module name assumed is ``bar.baz`` and the directory ``foo`` is -added to mypy's module search path. On the other hand, if -``foo/bar/__init__.py`` did not exist, ``foo/bar`` would be added to -the module search path instead, and the module name assumed is just -``baz``. - -If a script (a file not ending in ``.py[i]``) is processed, the module -name assumed is always ``__main__`` (matching the behavior of the -Python interpreter). - -Other ways of specifying code to be checked -******************************************* - -The flag ``-m`` (long form: ``--module``) lets you specify a module -name to be found using the default module search path. The module -name may contain dots. For example:: - - $ mypy -m html.parser - -will type check the module ``html.parser`` (this happens to be a -library stub). - -The flag ``-p`` (long form: ``--package``) is similar to ``-m`` but -you give it a package name and it will type check all submodules and -subpackages (recursively) of that package. (If you pass a package -name to ``-m`` it will just type check the package's ``__init__.py`` -and anything imported from there.) For example:: - - $ mypy -p html - -will type check the entire ``html`` package (of library stubs). One can -specify multiple packages and modules on the command line, for example:: - - $ mypy --package p.a --package p.b --module c - -Finally the flag ``-c`` (long form: ``--command``) will take a string -from the command line and type check it as a small program. For -example:: - - $ mypy -c 'x = [1, 2]; print(x())' - -will type check that little program (and complain that ``List[int]`` -is not callable). - -Reading a list of files from a file -*********************************** +This section documents mypy's command line interface. You can view +a quick summary of the available flags by running ``mypy --help``. -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:: +.. note:: + + Command line flags are liable to change between releases. + + +Specifying what to type check +***************************** + +By default, you can specify what code you want mypy to type check +by passing in the paths to what you want to have type checked:: + + $ mypy foo.py bar.py some_directory + +Note that directories are checked recursively. + +Mypy also lets you specify what code to type check in several other +ways. A short summary of the relevant flags is included below: +for full details, see :ref:`running-mypy`. + +``-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. + +``-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 ``-module`` apart from this + behavior. - mypy $(cat file_of_files) +``-c PROGRAM_TEXT``, ``--command PROGRAM_TEXT`` + Asks mypy to type check the provided string as a program. + -you can use this instead:: +.. _config-file-flag: + +Config file +*********** + +``--config-file CONFIG_FILE`` + This flag makes mypy read configuration settings from the given file. + + By default settings are read from ``mypy.ini`` or ``setup.cfg`` in the + current directory, or ``.mypy.ini`` in the user's home directory. + Settings override mypy's built-in defaults and command line flags + can override settings. + + See :ref:`config-file` for the syntax of configuration files. + +``--warn-unused-configs`` + This flag makes mypy warn about unused ``[mypy-]`` config + file sections. - mypy @file_of_files -Such a file can also contain other flags, but a preferred way of -reading flags (not files) from a file is to use a -:ref:`configuration file `. +.. _import-discovery: +Import discovery +**************** -.. _finding-imports: +The following flags customize how exactly mypy discovers and follows +imports. -How imports are found -********************* +``--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. -When mypy encounters an `import` statement it tries to find the module -on the file system, similar to the way Python finds it. -However, there are some differences. + Note that this flag does *not* suppress errors about missing names + in successfully resolved modules. For example, if one has the + following files:: -First, mypy has its own search path. -This is computed from the following items: + package/__init__.py + package/mod.py -- The ``MYPYPATH`` environment variable - (a colon-separated list of directories). -- The directories containing the sources given on the command line - (see below). -- The installed packages marked as safe for type checking (see - :ref:`PEP 561 support `) -- The relevant directories of the - `typeshed `_ repo. + Then mypy will generate the following errors with ``--ignore-missing-imports``: -For sources given on the command line, the path is adjusted by crawling -up from the given file or package to the nearest directory that does not -contain an ``__init__.py`` or ``__init__.pyi`` file. + .. code-block:: python -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: + import package.unknown # No error, ignored + x = package.unknown.func() # OK. 'func' is assumed to be of type 'Any' -- 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. + from package import unknown # No error, ignored + from package.mod import NonExisting # Error: Module has no attribute 'NonExisting' -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. + For more details, see :ref:`ignore-missing-imports`. -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.) +``--follow-imports {normal,silent,skip,error}`` + This flag adjusts how mypy follows imported modules that were not + explicitly passed in via the command line. -NOTE: These rules are relevant to the following section too: -the ``--follow-imports`` flag described below is applied *after* the -above algorithm has determined which package, stub or module to use. + The default option is ``normal``: mypy will follow and type check + all modules. For more information on what the other options do, + see :ref:`Following imports `. -.. _follow-imports: +``--python-executable EXECUTABLE`` + This flag will have mypy collect type information from `PEP 561`_ + compliant packages installed for the Python executable ``EXECUTABLE``. + If not provided, mypy will use PEP 561 compliant packages installed for + the Python executable running mypy. + + See :ref:`installed-packages` for more on making PEP 561 compliant packages. + This flag will attempt to set ``--python-version`` if not already set. -Following imports or not? -************************* +``--no-site-packages`` + This flag will disable searching for `PEP 561`_ compliant packages. This + will also disable searching for a usable Python executable. + + Use this flag if mypy cannot find a Python executable for the version of + Python being checked, and you don't need to use PEP 561 typed packages. + Otherwise, use ``--python-executable``. -When you're first attacking a large existing codebase with mypy, you -may only want to check selected files. For example, you may only want -to check those files to which you have already added annotations. -This is easily accomplished using a shell pipeline like this:: +``--no-silence-site-packages`` + By default, mypy will suppress any error messages generated within PEP 561 + compliant packages. Adding this flag will disable this behavior. - mypy $(find . -name \*.py | xargs grep -l '# type:') -(While there are many improvements possible to make this example more -robust, this is not the place for a tutorial in shell programming.) +Platform configuration +********************** -However, by default mypy doggedly tries to :ref:`follow imports -`. This may cause several types of problems that you -may want to silence during your initial conquest: +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. -- Your code may import library modules for which no stub files exist - yet. This can cause a lot of errors like the following:: +For more information on how to use these flags, see :ref:`version_and_platform_checks`. - main.py:1: error: No library stub file for standard library module 'antigravity' - main.py:2: error: No library stub file for module 'flask' - main.py:3: error: Cannot find module named 'sir_not_appearing_in_this_film' +``--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 ``-2`` and + ``--py2`` flags are aliases for ``--python-version 2.7``. + + This flag will attempt to find a Python executable of the corresponding + version to search for `PEP 561`_ compliant packages. If you'd like to + disable this, use the ``--no-site-packages`` flag (see + :ref:`import-discovery` for more details). - If you see only a few of these you may be able to silence them by - putting ``# type: ignore`` on the respective ``import`` statements, - but it's usually easier to silence all such errors by using - :ref:`--ignore-missing-imports `. +``-2``, ``--py2`` + Equivalent to running ``--python-version 2.7``. + +``--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 `_. + +.. _always-true: -- Your project's directory structure may hinder mypy in finding - certain modules that are part of your project, e.g. modules hidden - away in a subdirectory that's not a package. You can usually deal - with this by setting the ``MYPYPATH`` variable (see - :ref:`finding-imports`). +``--always-true NAME`` + This flag will treat all variables named ``NAME`` as + compile-time constants that are always true. This flag may + be repeated. -- When following imports mypy may find a module that's part of your - project but which you haven't annotated yet, mypy may report errors - for the top level code in that module (where the top level includes - class bodies and function/method default values). Here the - ``--follow-imports`` flag comes in handy. - -The ``--follow-imports`` flag takes a mandatory string value that can -take one of four values. It only applies to modules for which a -``.py`` file is found (but no corresponding ``.pyi`` stub file) and -that are not given on the command line. Passing a package or -directory on the command line implies all modules in that package or -directory. The four possible values are: - -- ``normal`` (the default) follow imports normally and type check all - top level code (as well as the bodies of all functions and methods - with at least one type annotation in the signature). - -- ``silent`` follow imports normally and even "type check" them - normally, but *suppress any error messages*. This is typically the - best option for a new codebase. - -- ``skip`` *don't* follow imports, silently replacing the module (and - everything imported *from* it) with an object of type ``Any``. - (This option used to be known as ``--silent-imports`` and while it - is very powerful it can also cause hard-to-debug errors, hence the - recommendation of using ``silent`` instead.) - -- ``error`` the same behavior as ``skip`` but not quite as silent -- - it flags the import as an error, like this:: - - main.py:1: note: Import of 'submodule' ignored - main.py:1: note: (Using --follow-imports=error, module not passed on command line) +``--always-false NAME`` + This flag will treat all variables named ``NAME`` as + compile-time constants that are always false. This flag may + be repeated. .. _disallow-any: -Disallow Any Flags -****************** +Disallow Any +************ The ``--disallow-any`` family of flags disallows various types of ``Any`` in a module. The following options are available: -- ``--disallow-any-unimported`` 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 ``--follow-imports=skip`` - is set. +``--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 ``--follow-imports=skip`` + is set. + +``--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`` 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. + +``--disallow-any-decorated`` + This flag disallows functions that have ``Any`` in their signature + after decorator transformation. + +``--disallow-any-explicit`` + This flag disallows explicit ``Any`` in type positions such as type + annotations and generic type parameters. + +``--disallow-any-generics`` + This flag disallows usage of generic types that do not specify explicit + type parameters. Moreover, built-in collections (such as ``list`` and + ``dict``) become disallowed as you should use their aliases from the typing + module (such as ``List[int]`` and ``Dict[str, str]``). -- ``--disallow-any-expr`` 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`` 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. +.. _disallow-subclassing-any: -- ``--disallow-any-decorated`` disallows functions that have ``Any`` in their signature - after decorator transformation. +``--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 + :ref:`--ignore-missing-imports `) or is + ignored due to :ref:`--follow-imports=skip ` or a + ``# type: ignore`` comment on the ``import`` statement. + + Since the module is silenced, the imported class is given a type of ``Any``. + By default mypy will assume that the subclass correctly inherited + the base class even though that may not actually be the case. This + flag makes mypy raise an error instead. + +.. _untyped-definitions-and-calls: + +Untyped definitions and calls +***************************** -- ``--disallow-any-explicit`` disallows explicit ``Any`` in type positions such as type - annotations and generic type parameters. +The following flags configure how mypy handles untyped function +definitions or calls. -- ``--disallow-any-generics`` disallows usage of generic types that do not specify explicit - type parameters. Moreover, built-in collections (such as ``list`` and - ``dict``) become disallowed as you should use their aliases from the typing - module (such as ``List[int]`` and ``Dict[str, str]``). +``--disallow-untyped-calls`` + This flag reports an error whenever a function with type annotations + calls a function defined without annotations. +``--disallow-untyped-defs`` + This flag reports an error whenever it encounters a function definition + without type annotations. -.. _additional-command-line-flags: +.. _disallow-incomplete-defs: -Additional command line flags -***************************** +``--disallow-incomplete-defs`` + This flag reports an error whenever it encounters a partly annotated + function definition. -Here are some more useful flags: +``--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. -.. _ignore-missing-imports: +``--disallow-untyped-decorators`` + This flag reports an error whenever a function with type annotations + is decorated with a decorator without annotations. -- ``--ignore-missing-imports`` suppresses error messages about imports - that cannot be resolved (see :ref:`follow-imports` for some examples). - This doesn't suppress errors about missing names in successfully resolved - modules. For example, if one has the following files:: - package/__init__.py - package/mod.py +None and Optional handling +************************** - Then mypy will generate the following errors with ``--ignore-missing-imports``: +The following flags adjust how mypy handles values of type `None`. +For more details, see :ref:`no_strict_optional`. - .. code-block:: python +.. _no-implicit-optional: - import package.unknown # No error, ignored - x = package.unknown.func() # OK +``--no-implicit-optional`` + This flag causes mypy to stop treating arguments with a ``None`` + default value as having an implicit ``Optional[...]`` type. - from package import unknown # No error, ignored - from package.mod import NonExisting # Error: Module has no attribute 'NonExisting' + For example, by default mypy will assume that the ``x`` parameter + is of type ``Optional[int]`` in the code snippet below since + the default pararameter is ``None``: -- ``--no-strict-optional`` disables strict checking of ``Optional[...]`` - types and ``None`` values. With this option, mypy doesn't - generally check the use of ``None`` values -- they are valid - everywhere. See :ref:`no_strict_optional` for more about this feature. + .. code-block:: python - **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). + def foo(x: int = None) -> None: + print(x) -- ``--disallow-untyped-defs`` reports an error whenever it encounters - a function definition without type annotations. + If this flag is set, the above snippet will no longer type check: + we must now explicitly indicate that the type is ``Optional[int]``: -- ``--check-untyped-defs`` is less severe than the previous option -- - 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. + .. code-block:: python -- ``--disallow-incomplete-defs`` reports an error whenever it - encounters a partly annotated function definition. + def foo(x: Optional[int] = None) -> None: + print(x) -- ``--disallow-untyped-calls`` reports an error whenever a function - with type annotations calls a function defined without annotations. +``--no-strict-optional`` + This flag disables strict checking of ``Optional[...]`` + types and ``None`` values. With this option, mypy doesn't + generally check the use of ``None`` values -- they are valid + everywhere. See :ref:`no_strict_optional` for more about this feature. -- ``--disallow-untyped-decorators`` reports an error whenever a function - with type annotations is decorated with a decorator without annotations. +.. 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). -.. _disallow-subclassing-any: -- ``--disallow-subclassing-any`` 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 - :ref:`--ignore-missing-imports `) or is - ignored due to :ref:`--follow-imports=skip ` 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. +Configuring warnings +******************** -.. _incremental: +The follow flags enable warnings for code that is sound but is +potentially problematic or redundant in some way. -- Incremental mode enables a module cache, using results from - previous runs to speed up type checking. Incremental mode can help - when most parts of your program haven't changed since the previous - mypy run. +``--warn-redundant-casts`` + This flag will make mypy report an error whenever your code uses + an unnecessary cast that can safely be removed. - Incremental mode is the default and may be disabled with - ``--no-incremental``. +``--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. -- ``--cache-dir DIR`` is a companion flag to incremental mode, which - specifies where the cache files are written. By default this is - ``.mypy_cache`` in the current directory. While the cache is only - read in incremental mode, it is written even in non-incremental - mode, in order to "warm" the cache. To disable writing the cache, - use ``--cache-dir=/dev/null`` (UNIX) or ``--cache-dir=nul`` - (Windows). Cache files belonging to a different mypy version are - ignored. This flag can be useful for controlling cache use when using - :ref:`remote caching `. + This flag, along with the ``--warn-unsued-casts`` flag, are both + particularly useful when you are upgrading mypy. Previously, + you may have needed to add casts or ``# type: ignore`` annotations + to work around bugs in mypy or missing stubs for 3rd party libraries. -.. _quick-mode: + These two flags let you discover cases where either workarounds are + no longer necessary. -- ``--quick-and-dirty`` is an experimental, unsafe variant of - :ref:`incremental mode `. Quick mode is faster than - regular incremental mode, because it only re-checks modules that - were modified since their cache file was last written (regular - incremental mode also re-checks all modules that depend on one or - more modules that were re-checked). Quick mode is unsafe because it - may miss problems caused by a change in a dependency. Quick mode - updates the cache, but regular incremental mode ignores cache files - written by quick mode. - -- ``--python-executable EXECUTABLE`` will have mypy collect type information - from `PEP 561`_ compliant packages installed for the Python executable - ``EXECUTABLE``. If not provided, mypy will use PEP 561 compliant packages - installed for the Python executable running mypy. See - :ref:`installed-packages` for more on making PEP 561 compliant packages. - This flag will attempt to set ``--python-version`` if not already set. - -- ``--python-version X.Y`` will make mypy typecheck 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 ``-2`` and - ``--py2`` flags are aliases for ``--python-version 2.7``. See - :ref:`version_and_platform_checks` for more about this feature. This flag - will attempt to find a Python executable of the corresponding version to - search for `PEP 561`_ compliant packages. If you'd like to disable this, - see ``--no-site-packages`` below. - -- ``--no-site-packages`` will disable searching for `PEP 561`_ compliant - packages. This will also disable searching for a usable Python executable. - Use this flag if mypy cannot find a Python executable for the version of - Python being checked, and you don't need to use PEP 561 typed packages. - Otherwise, use ``--python-executable``. - -- ``--platform PLATFORM`` will make mypy typecheck 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. See - :ref:`version_and_platform_checks` for more about this feature. +``--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: -.. _always-true: + - 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. -- ``--always-true NAME`` will treat all variables named ``NAME`` as - compile-time constants that are always true. May be repeated. + Passing in ``--no-warn-no-return`` will disable these error + messages in all cases. -- ``--always-false NAME`` will treat all variables named ``NAME`` as - compile-time constants that are always false. May be repeated. +``--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. -- ``--show-column-numbers`` 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): +Miscellaneous strictness flags +****************************** - .. code-block:: python +This section documents any other flags that do not neatly fall under any +of the above sections. - main.py:12:9: error: Unsupported operand types for / ("int" and "str") +``--strict`` + This flag mode enables all optional error checking flags. You can see the + list of flags enabled by strict mode in the full ``mypy --help`` output. -- ``--scripts-are-modules`` 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__``. This allows checking more than one script in a - single mypy invocation. (The default ``__main__`` is technically - more correct, but if you have many scripts that import a large - package, the behavior enabled by this flag is often more - convenient.) + Note: the exact list of flags enabled by running ``--strict`` may change + over time. -- ``--custom-typeshed-dir DIR`` specifies the directory where mypy looks for - 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. +Configuring error messages +************************** -.. _config-file-flag: +The following flags let you adjust how much detail mypy displays +in error messages. + +``--show-error-context`` + This flag will precede all errors with "note" messages explaining the + context of the error. For example, consider the following program: + + .. code-block:: python + + class Test: + def foo(self, x: int) -> int: + return x + "bar" + + Mypy normally displays an error message that looks like this:: + + main.py:3: error: Unsupported operand types for + ("int" and "str") + + If we enable this flag, the error message now looks like this:: + + main.py: note: In member "foo" of class "Test": + main.py:3: error: Unsupported operand types for + ("int" and "str") + +``--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") + + +.. _incremental: + +Incremental mode +**************** -- ``--config-file CONFIG_FILE`` causes configuration settings to be - read from the given file. By default settings are read from ``mypy.ini`` - or ``setup.cfg`` in the current directory, or ``.mypy.ini`` in the user home - directory. Settings override mypy's built-in defaults and command line flags - can override settings. See :ref:`config-file` for the syntax of configuration - files. +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. -- ``--junit-xml JUNIT_XML`` will make mypy generate a JUnit XML test - result document with type checking results. This can make it easier - to integrate mypy with continuous integration (CI) tools. +If you want to speed up how long it takes to recheck your code +beyond what incremental mode can offer, try running mypy in +:ref:`daemon mode `. -- ``--find-occurrences CLASS.MEMBER`` will make mypy print out all - usages of a class member based on static type information. This - feature is experimental. +``--no-incremental`` + This flag disables incremental mode: mypy will no longer reference + the cache when re-run. -- ``--cobertura-xml-report DIR`` causes mypy to generate a Cobertura - XML type checking coverage report. + Note that mypy will still write out to the cache even when + incremental mode is disabled: see the ``--cache-dir`` flag below + for more details. -- ``--warn-no-return`` causes mypy to generate errors for missing return - statements on some execution paths. Mypy doesn't generate these errors - for functions with ``None`` or ``Any`` return types. Mypy - also currently ignores functions with an empty body or a body that is - just ellipsis (``...``), since these can be valid as abstract methods. - This option is on by default. +``--cache-dir DIR`` + By default, mypy stores all cache data inside of a folder named + ``.mypy_cache`` in the current directory. This flag lets you + change this folder. This flag can also be useful for controlling + cache use when using :ref:`remote caching `. -- ``--warn-return-any`` causes mypy to generate a warning when returning a value - with type ``Any`` from a function declared with a non- ``Any`` return type. + 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). -- ``--strict`` mode enables all optional error checking flags. You can see the - list of flags enabled by strict mode in the full ``mypy -h`` output. +``--skip-version-check`` + By default, mypy will ignore cache data generated by a different + version of mypy. This flag disables that behavior. + +.. _quick-mode: + +``--quick-and-dirty`` + This flag enables an experimental, unsafe variant of incremental mode. + Quick mode is faster than regular incremental mode because it only + re-checks modules that were modified since their cache file was + last written: regular incremental mode also re-checks all modules + that depend on one or more modules that were re-checked. + + Quick mode is unsafe because it may miss problems caused by a change + in a dependency. Quick mode updates the cache, but regular incremental + mode ignores cache files written by quick mode. + + We recommend that you try using the :ref:`mypy_daemon` before + attempting to use this feature. + +Advanced flags +************** + +The following flags are useful mostly for people who are interested +in developing or debugging mypy internals. + +``--pdb`` + This flag will invoke the Python debugger when mypy encounters + a fatal error. + +``--show-traceback``, ``--tb`` + If set, this flag will display a full traceback when mypy + encounters a fatal error. + +``--custom-typing MODULE`` + This flag lets you use a custom module as a substitute for the + ``typing`` module. + +``--custom-typeshed-dir DIR`` + This flag specifies the directory where mypy looks for 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. .. _shadow-file: -- ``--shadow-file SOURCE_FILE SHADOW_FILE``: when mypy is asked to typecheck - ``SOURCE_FILE``, this makes it read from and typecheck 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 typecheck the contents of ``temp.py`` instead of ``original.py``, - but error messages will still reference ``original.py``. +``--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. -.. _no-implicit-optional: + 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``. -- ``--no-implicit-optional`` causes mypy to stop treating arguments - with a ``None`` default value as having an implicit ``Optional[...]`` - type. +Report generation +***************** -For the remaining flags you can read the full ``mypy -h`` output. +If these flags are set, mypy will generate a report in the specified +format into the specified directory. -.. note:: +``--any-exprs-report DIR`` + Causes mypy to generate a text file report documenting how many + expressions of type ``Any`` are present within your codebase. - Command line flags are liable to change between releases. +``--linecount-report DIR`` + Causes mypy to generate a text file report documenting the functions + and lines that are typed and untyped within your codebase. -.. _PEP 561: https://www.python.org/dev/peps/pep-0561/ +``--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. + +``--cobertura-xml-report DIR`` + Causes mypy to generate a Cobertura XML type checking coverage report. + + You must install the `lxml`_ library to generate this report. -.. _integrating-mypy: +``--html-report DIR``, ``--xslt-html-report DIR`` + Causes mypy to generate an HTML type checking coverage report. -Integrating mypy into another Python application -************************************************ + You must install the `lxml`_ library to generate this report. -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. +``--txt-report DIR``, ``--xslt-txt-report DIR`` + Causes mypy to generate a text file type checking coverage report. -Function ``run`` returns a ``Tuple[str, str, int]``, namely -``(, , )``, in which ```` -is what mypy normally writes to ``sys.stdout``, ```` is what mypy -normally writes to ``sys.stderr`` and ``exit_status`` is the exit status mypy normally -returns to the operating system. + You must install the `lxml`_ library to generate this report. -A trivial example of using the api is the following:: +``--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. - import sys - from mypy import api - result = api.run(sys.argv[1:]) +Miscellaneous +************* - if result[0]: - print('\nType checking report:\n') - print(result[0]) # stdout +``--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. + +``--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__``. + + This lets you check more than one script in a single mypy invocation. + (The default ``__main__`` is technically more correct, but if you + have many scripts that import a large package, the behavior enabled + by this flag is often more convenient.) + +.. _PEP 561: https://www.python.org/dev/peps/pep-0561/ - if result[1]: - print('\nError report:\n') - print(result[1]) # stderr +.. _lxml: https://pypi.org/project/lxml/ - print ('\nExit status:', result[2]) diff --git a/docs/source/extending_mypy.rst b/docs/source/extending_mypy.rst new file mode 100644 index 000000000000..48155475b991 --- /dev/null +++ b/docs/source/extending_mypy.rst @@ -0,0 +1,52 @@ +.. _extending-mypy: + +Extending and integrating mypy +============================== + +.. _integrating-mypy: + +Integrating mypy into another Python application +************************************************ + +It is possible to integrate mypy into another Python 3 application by +importing ``mypy.api`` and calling the ``run`` function with a parameter of type ``List[str]``, containing +what normally would have been the command line arguments to mypy. + +Function ``run`` returns a ``Tuple[str, str, int]``, namely +``(, , )``, in which ```` +is what mypy normally writes to ``sys.stdout``, ```` is what mypy +normally writes to ``sys.stderr`` and ``exit_status`` is the exit status mypy normally +returns to the operating system. + +A trivial example of using the api is the following + +.. code-block:: python + + import sys + from mypy import api + + result = api.run(sys.argv[1:]) + + if result[0]: + print('\nType checking report:\n') + print(result[0]) # stdout + + if result[1]: + print('\nError report:\n') + print(result[1]) # stderr + + print ('\nExit status:', result[2]) + +Extending mypy using plugins +**************************** + +Mypy supports a plugin system that lets you customize the way mypy type checks +code. This can be useful if you want to extend mypy so it can type check code +that uses a library that is difficult to express using just PEP 484 types, for +example. + +*Warning:* The plugin system is extremely experimental and prone to change. If you want +to contribute a plugin to mypy, we recommend you start by contacting the mypy +core developers either on `gitter `_ or on mypy's +`issue tracker `_. + diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 64524d99ceb7..4cafc9e6ebe4 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -1,3 +1,5 @@ +.. _getting-started: + Getting started =============== diff --git a/docs/source/index.rst b/docs/source/index.rst index f80bd00b3660..9c7e043f2822 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -45,10 +45,12 @@ Mypy is a static type checker for Python 3 and Python 2.7. :maxdepth: 2 :caption: Configuring and running mypy + running_mypy command_line config_file mypy_daemon installed_packages + extending_mypy .. toctree:: :maxdepth: 2 diff --git a/docs/source/more_types.rst b/docs/source/more_types.rst index 0649fc81b6c6..0e7815ad8280 100644 --- a/docs/source/more_types.rst +++ b/docs/source/more_types.rst @@ -537,7 +537,7 @@ 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 ``--check-untyped-defs`` -flag (:ref:`more details here `). +flag (:ref:`more details here `). The variants must also also be compatible with the implementation type hints. In the ``MyList`` example, mypy will check that the diff --git a/docs/source/running_mypy.rst b/docs/source/running_mypy.rst new file mode 100644 index 000000000000..949538642f93 --- /dev/null +++ b/docs/source/running_mypy.rst @@ -0,0 +1,332 @@ +.. _running-mypy: + +Running mypy and managing imports +================================= + +The :ref:`getting-started` 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 +:ref:`command-line` guide. + + +.. _specifying-code-to-be-checked: + +Specifying code to be checked +***************************** + +Mypy lets you specify what files it should type check in several +different ways. + +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 + :ref:`Mapping file paths to modules `. + +2. Second, you can use the ``-m`` flag (long form: ``--module``) 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 :ref:`finding-imports`. + +3. Third, you can use the ``-p`` (long form: ``--package``) flag to + specify a package to be (recursively) type checked. This flag + is almost identical to the ``-m`` 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 ``-m`` 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 ``-c`` (long form: ``--command``) + 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). + + +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 +:ref:`configuration file ` instead. + + + +How mypy handles imports +************************ + +When mypy encounters an ``import`` statement, it will first +:ref:`attempt to locate ` 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. + +.. _ignore-missing-imports: + +Missing imports +--------------- + +When you import a module, mypy may report that it is unable to +follow the import. + +This could happen if the code is importing a non-existant module +or if the code is importing a library that does not use type hints. +Specifically, the library is neither declared to be a +:ref:`PEP 561 compliant package ` nor has registered +any stubs on `typeshed `_, the +repository of stubs for the standard library and popular 3rd party libraries. + +This can cause a lot of errors that look like the following:: + + main.py:1: error: No library stub file for standard library module 'antigravity' + main.py:2: error: No library stub file for module 'flask' + main.py:3: error: Cannot find module named 'this_module_does_not_exist' + +If the module genuinely does not exist, you should of course fix the +import statement. If the module is a module within your codebase that mypy +is somehow unable to discover, we recommend reading the :ref:`finding-imports` +section below to help you debug the issue. + +If the module is a library that does not use type hints, the easiest fix +is to silence the error messages by adding a ``# type: ignore`` comment on +each respective import statement. + +If you have many of these errors, you can silence them all at once by using +the ``--ignore-missing-imports`` flag. We recommend using this flag only +as a last resort: it's equivalent to adding a ``# type: ignore`` comment +to all unresolved imports in your codebase. + +A more involved solution would be to reverse-engineer how the library +works, create type hints for the library, and point mypy at those +type hints either by passing in in via the command line or by adding +the location of your custom stubs to the ``MYPYPATH`` environment variable. + +If you want to share your work, you can either open a pull request on +typeshed or modify the library itself to be +:ref:`PEP 561 compliant `. + + +.. _follow-imports: + +Following imports +----------------- + +Mypy is designed to :ref:`doggedly follow all imports `, +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 +``mypy -m mycode.foo`` and mypy discovers that ``mycode.foo`` imports +``mycode.bar``. + +How do we want mypy to type check ``mycode.bar``? We can configure the +desired behavior by using the ``--follow-imports`` flag. This flag +accepts one of four string values: + +- ``normal`` (the default) 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``. + + (Note: this option used to be known as ``--silent-imports``.) + +- ``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 ``--follow-imports=normal`` +(the default) or ``--follow-imports=error``. 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 ``--follow-imports=normal``. +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. + +If doing this is intractable, we recommend passing mypy just the files +you want to type check and use ``--follow-imports=silent``. 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 :ref:`existing-code` 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. + + + +.. _mapping-paths-to-modules: + +Mapping file paths to modules +***************************** + +One of the main ways you can tell mypy what files to type check +is by providing mypy the paths to those files. 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. + +- Files ending in ``.py`` (and stub files ending in ``.pyi``) are + checked as Python modules. + +- Files not ending in ``.py`` or ``.pyi`` are assumed to be Python + scripts and checked as such. + +- Directories representing Python packages (i.e. containing a + ``__init__.py[i]`` file) are checked as Python packages; all + submodules and subpackages will be checked (subpackages must + themselves have a ``__init__.py[i]`` file). + +- Directories that don't represent Python packages (i.e. not directly + containing an ``__init__.py[i]`` file) are checked as follows: + + - All ``*.py[i]`` files contained directly therein are checked as + toplevel Python modules; + + - All packages contained directly therein (i.e. immediate + subdirectories with an ``__init__.py[i]`` file) are checked as + toplevel Python packages. + +One more thing about checking modules and packages: if the directory +*containing* a module or package specified on the command line has an +``__init__.py[i]`` file, mypy assigns these an absolute module name by +crawling up the path until no ``__init__.py[i]`` file is found. + +For example, suppose we run the command ``mypy foo/bar/baz.py`` where +``foo/bar/__init__.py`` exists but ``foo/__init__.py`` does not. Then +the module name assumed is ``bar.baz`` and the directory ``foo`` is +added to mypy's module search path. + +On the other hand, if ``foo/bar/__init__.py`` did not exist, ``foo/bar`` +would be added to the module search path instead, and the module name +assumed is just ``baz``. + +If a script (a file not ending in ``.py[i]``) is processed, the module +name assumed is ``__main__`` (matching the behavior of the +Python interpreter), unless ``--scripts-are-modules`` is passed. + + +.. _finding-imports: + +How imports are found +********************* + +When mypy encounters an ``import`` statement or receives module +names from the command line via the ``--module`` or ``--package`` +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 directories containing the sources given on the command line + (see below). +- The installed packages marked as safe for type checking (see + :ref:`PEP 561 support `) +- The relevant directories of the + `typeshed `_ repo. + +For sources given on the command line, the path is adjusted by crawling +up from the given file or package to the nearest directory that does not +contain an ``__init__.py`` or ``__init__.pyi`` file. + +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.) +