Skip to content

Adds the --ignore-missing-stubs command line option #4491

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ flag (or its long form ``--help``)::
$ mypy -h
usage: mypy [-h] [-v] [-V] [--python-version x.y] [--platform PLATFORM] [-2]
[--ignore-missing-imports]
[--ignore-missing-stubs MODULE-1[,MODULE-2...]]
[--follow-imports {normal,silent,skip,error}]
[--disallow-any-{unimported,expr,decorated,explicit,generics}]
[--disallow-untyped-calls] [--disallow-untyped-defs]
Expand Down Expand Up @@ -205,10 +206,8 @@ may want to silence during your initial conquest:
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'

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 <ignore-missing-imports>`.
You can silence these by specifying the module names on the command
line by using :ref:`--ignore-missing-stubs <ignore-missing-stubs>`.

- Your project's directory structure may hinder mypy in finding
certain modules that are part of your project, e.g. modules hidden
Expand Down Expand Up @@ -292,6 +291,10 @@ Here are some more useful flags:
- ``--ignore-missing-imports`` suppresses error messages about imports
that cannot be resolved (see :ref:`follow-imports` for some examples).

.. _ignore-missing-stubs:
- ``--ignore-missing-stubs MODULE-1[,MODULE-2...]`` suppresses error messages about imports
for ``MODULE`` when it can be resolved but it lacks library stub files.

- ``--strict-optional`` enables experimental strict checking of ``Optional[...]``
types and ``None`` values. Without this option, mypy doesn't generally check the
use of ``None`` values -- they are valid everywhere. See :ref:`strict_optional` for
Expand Down
4 changes: 4 additions & 0 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ overridden by the pattern sections matching the module name.
pattern matching is used, the pattern should match the name of the
*imported* module, not the module containing the import statement.

- ``ignore_missing_stubs`` (List[str], default []) suppress error
messages about imports that are resolved but are missing library
stubs.

- ``silent_imports`` (Boolean, deprecated) equivalent to
``follow_imports=skip`` plus ``ignore_missing_imports=True``.

Expand Down
8 changes: 6 additions & 2 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,12 @@ def module_not_found(self, path: str, source: str, line: int, target: str) -> No
line, 0, "No library stub file for standard library module '{}'".format(target))
self.errors.report(line, 0, stub_msg, severity='note', only_once=True)
elif moduleinfo.is_third_party_module(target):
self.errors.report(line, 0, "No library stub file for module '{}'".format(target))
self.errors.report(line, 0, stub_msg, severity='note', only_once=True)
if target not in self.options.ignore_missing_stubs:
self.errors.report(line, 0, "No library stub file for module '{}'".format(target))
self.errors.report(
line, 0, "(To suppress this error add this module to --ignore-missing-stubs)",
severity='note', only_once=True)
self.errors.report(line, 0, stub_msg, severity='note', only_once=True)
else:
self.errors.report(line, 0, "Cannot find module named '{}'".format(target))
self.errors.report(line, 0, '(Perhaps setting MYPYPATH '
Expand Down
25 changes: 24 additions & 1 deletion mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import sys
import time

from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Tuple, Callable
from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Tuple, Callable, Union

from mypy import build
from mypy import defaults
Expand Down Expand Up @@ -205,6 +205,18 @@ def invert_flag_name(flag: str) -> str:
return '--no-{}'.format(flag[2:])


class IgnoreMissingStubsParseAction(argparse.Action):
def __call__(self, parser: argparse.ArgumentParser,
namespace: argparse.Namespace, values: Union[str, Sequence[Any], None],
option_string: str = "") -> None:
if not isinstance(values, str):
# this should never happen
parser.error("%s: %s" % (option_string, "Argument must be of type string"))
return # this should never be reached because parser.error should exit the program
modules = [m.strip() for m in values.split(",")]
namespace.ignore_missing_stubs = modules


def process_options(args: List[str],
require_targets: bool = True
) -> Tuple[List[BuildSource], Options]:
Expand Down Expand Up @@ -262,6 +274,9 @@ def add_invertible_flag(flag: str,
const=defaults.PYTHON2_VERSION, help="use Python 2 mode")
parser.add_argument('--ignore-missing-imports', action='store_true',
help="silently ignore imports of missing modules")
parser.add_argument('--ignore-missing-stubs', action=IgnoreMissingStubsParseAction,
metavar="MODULE-1[,MODULE-2...]",
help="silently ignore missing library stubs for the specified modules")
parser.add_argument('--follow-imports', choices=['normal', 'silent', 'skip', 'error'],
default='normal', help="how to treat imports (default normal)")
parser.add_argument('--disallow-any-unimported', default=False, action='store_true',
Expand Down Expand Up @@ -763,6 +778,14 @@ def parse_section(prefix: str, template: Options,
try:
if ct is bool:
v = section.getboolean(key) # type: ignore # Until better stub
elif ct is list:
value = section.get(key)
if value is None:
print("%s: %s: value is None" % (prefix, key), file=sys.stderr)
continue
else:
# based on suggestion here: https://stackoverflow.com/a/335754/755934
v = [item.strip() for item in value.split(",")]
elif callable(ct):
try:
v = ct(section.get(key))
Expand Down
1 change: 1 addition & 0 deletions mypy/moduleinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@

# for use in tests
'__dummy_third_party1',
'__dummy_third_party2'
}

# Modules and packages common to Python 2.7 and 3.x.
Expand Down
2 changes: 2 additions & 0 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Options:

PER_MODULE_OPTIONS = {
"ignore_missing_imports",
"ignore_missing_stubs",
"follow_imports",
"disallow_any_generics",
"disallow_any_unimported",
Expand Down Expand Up @@ -58,6 +59,7 @@ def __init__(self) -> None:
self.mypy_path = [] # type: List[str]
self.report_dirs = {} # type: Dict[str, str]
self.ignore_missing_imports = False
self.ignore_missing_stubs = [] # type: List[str]
self.follow_imports = 'normal' # normal|silent|skip|error

# disallow_any options
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'check-statements.test',
'check-generics.test',
'check-dynamic-typing.test',
'check-ignore-missing-stubs.test',
'check-inference.test',
'check-inference-context.test',
'check-kwargs.test',
Expand Down
96 changes: 96 additions & 0 deletions test-data/unit/check-ignore-missing-stubs.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
-- Test cases for the --ignore-missing-stubs command line option
-- Also test ignore_missing_stubs config file option

-- these testcases are for the command line option

[case testIgnoreMissingStubs_Cli_IgnoreNothingFail]
import missing # Expect error here
[out]
main:1: error: Cannot find module named 'missing'
main:1: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)

[case testIgnoreMissingStubs_Cli_IgnoreOneModuleFail]
import __dummy_third_party1 # third-party module without type defs
[out]
main:1: error: No library stub file for module '__dummy_third_party1'
main:1: note: (To suppress this error add this module to --ignore-missing-stubs)
main:1: note: (Stub files are from https://github.com/python/typeshed)

[case testIgnoreMissingStubs_Cli_IgnoreOneModulePass]
# flags: --ignore-missing-stubs __dummy_third_party1
import __dummy_third_party1 # third-party module without type defs

[case testIgnoreMissingStubs_Cli_IgnoreTwoModulesFail]
# flags: --ignore-missing-stubs __dummy_third_party1
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[out]
main:3: error: No library stub file for module '__dummy_third_party2'
main:3: note: (To suppress this error add this module to --ignore-missing-stubs)
main:3: note: (Stub files are from https://github.com/python/typeshed)

[case testIgnoreMissingStubs_Cli_IgnoreTwoModulesFail]
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[out]
main:1: error: No library stub file for module '__dummy_third_party1'
main:1: note: (To suppress this error add this module to --ignore-missing-stubs)
main:1: note: (Stub files are from https://github.com/python/typeshed)
main:2: error: No library stub file for module '__dummy_third_party2'

[case testIgnoreMissingStubs_Cli_IgnoreTwoModulesWrongModules]
# flags: --ignore-missing-stubs __dummy_third_party2,bar
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[out]
main:2: error: No library stub file for module '__dummy_third_party1'
main:2: note: (To suppress this error add this module to --ignore-missing-stubs)
main:2: note: (Stub files are from https://github.com/python/typeshed)

[case testIgnoreMissingStubs_Cli_IgnoreTwoModulesPass]
# flags: --ignore-missing-stubs __dummy_third_party1,__dummy_third_party2
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs

-- these testcases are for the config option

[case testIgnoreMissingStubs_Config_IgnoreOneModule]
# flags: --config-file tmp/mypy.ini
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[file mypy.ini]
[[mypy]
ignore_missing_stubs = __dummy_third_party1
[out]
main:3: error: No library stub file for module '__dummy_third_party2'
main:3: note: (To suppress this error add this module to --ignore-missing-stubs)
main:3: note: (Stub files are from https://github.com/python/typeshed)

[case testIgnoreMissingStubs_Config_IgnoreWrongModule]
# flags: --config-file tmp/mypy.ini
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[file mypy.ini]
[[mypy]
ignore_missing_stubs = foo
[out]
main:2: error: No library stub file for module '__dummy_third_party1'
main:2: note: (To suppress this error add this module to --ignore-missing-stubs)
main:2: note: (Stub files are from https://github.com/python/typeshed)
main:3: error: No library stub file for module '__dummy_third_party2'

[case testIgnoreMissingStubs_Config_IgnoreBothModules]
# flags: --config-file tmp/mypy.ini
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[file mypy.ini]
[[mypy]
ignore_missing_stubs = __dummy_third_party1, __dummy_third_party2

[case testIgnoreMissingStubs_Config_IgnoreBothModulesNoSpaces]
# flags: --config-file tmp/mypy.ini
import __dummy_third_party1 # third-party module without type defs
import __dummy_third_party2 # third-party module without type defs
[file mypy.ini]
[[mypy]
ignore_missing_stubs = __dummy_third_party1,__dummy_third_party2
1 change: 1 addition & 0 deletions test-data/unit/semanal-errors.test
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,7 @@ y = 1
import __dummy_third_party1
[out]
main:1: error: No library stub file for module '__dummy_third_party1'
main:1: note: (To suppress this error add this module to --ignore-missing-stubs)
main:1: note: (Stub files are from https://github.com/python/typeshed)

[case testMissingStubForStdLibModule]
Expand Down