diff options
-rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | pylint/checkers/utils.py | 24 | ||||
-rw-r--r-- | tests/functional/i/import_error.py | 7 | ||||
-rw-r--r-- | tests/functional/i/import_error.txt | 6 | ||||
-rw-r--r-- | tests/functional/n/no/no_name_in_module.py | 11 | ||||
-rw-r--r-- | tests/functional/n/no/no_name_in_module.txt | 10 |
7 files changed, 49 insertions, 14 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 4f4164cfa..9e44c497b 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -548,3 +548,5 @@ contributors: - Fixed `toml` dependency issue * Tim Martin: contributor + +* Samuel Forestier: contributor @@ -11,6 +11,9 @@ Release date: TBA .. Put new features here and also in 'doc/whatsnew/2.12.rst' +* Added support for ``ModuleNotFoundError`` (``import-error`` and ``no-name-in-module``). + ``ModuleNotFoundError`` inherits from ``ImportError`` and was added in Python ``3.6`` + * Improve and flatten ``unused-wildcard-import`` message Closes #3859 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index d67d13c61..1cc74d49c 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -60,7 +60,18 @@ import numbers import re import string from functools import lru_cache, partial -from typing import Callable, Dict, Iterable, List, Match, Optional, Set, Tuple, Union +from typing import ( + Callable, + Dict, + Iterable, + List, + Match, + Optional, + Set, + Tuple, + Type, + Union, +) import _string import astroid @@ -942,14 +953,17 @@ def is_from_fallback_block(node: nodes.NodeNG) -> bool: isinstance(import_node, (nodes.ImportFrom, nodes.Import)) for import_node in other_body ) - ignores_import_error = _except_handlers_ignores_exception(handlers, ImportError) + ignores_import_error = _except_handlers_ignores_exceptions( + handlers, (ImportError, ModuleNotFoundError) + ) return ignores_import_error or has_fallback_imports -def _except_handlers_ignores_exception( - handlers: nodes.ExceptHandler, exception +def _except_handlers_ignores_exceptions( + handlers: nodes.ExceptHandler, + exceptions: Tuple[Type[ImportError], Type[ModuleNotFoundError]], ) -> bool: - func = partial(error_of_type, error_type=(exception,)) + func = partial(error_of_type, error_type=exceptions) return any(func(handler) for handler in handlers) diff --git a/tests/functional/i/import_error.py b/tests/functional/i/import_error.py index 21c06d1e3..79d8b3416 100644 --- a/tests/functional/i/import_error.py +++ b/tests/functional/i/import_error.py @@ -1,5 +1,5 @@ """ Test that import errors are detected. """ -# pylint: disable=invalid-name, unused-import, bare-except, broad-except, wrong-import-order, wrong-import-position +# pylint: disable=invalid-name, unused-import, bare-except, broad-except, wrong-import-order, wrong-import-position import totally_missing # [import-error] try: @@ -8,6 +8,11 @@ except ImportError: maybe_missing = None try: + import maybe_missing +except ModuleNotFoundError: + maybe_missing = None + +try: import maybe_missing_1 except (ImportError, SyntaxError): maybe_missing_1 = None diff --git a/tests/functional/i/import_error.txt b/tests/functional/i/import_error.txt index 4cc479698..8a63cacc3 100644 --- a/tests/functional/i/import_error.txt +++ b/tests/functional/i/import_error.txt @@ -1,4 +1,4 @@ import-error:3:0::Unable to import 'totally_missing' -import-error:16:4::Unable to import 'maybe_missing_2' -no-name-in-module:28:0::No name 'syntax_error' in module 'functional.s' -syntax-error:28:0::Cannot import 'functional.s.syntax_error' due to syntax error 'invalid syntax (<unknown>, line 1)' +import-error:21:4::Unable to import 'maybe_missing_2' +no-name-in-module:33:0::No name 'syntax_error' in module 'functional.s' +syntax-error:33:0::Cannot import 'functional.s.syntax_error' due to syntax error 'invalid syntax (<unknown>, line 1)' diff --git a/tests/functional/n/no/no_name_in_module.py b/tests/functional/n/no/no_name_in_module.py index ba67fbdb7..3a93fb444 100644 --- a/tests/functional/n/no/no_name_in_module.py +++ b/tests/functional/n/no/no_name_in_module.py @@ -41,6 +41,11 @@ except ImportError: pass try: + import collections.missing +except ModuleNotFoundError: + pass + +try: import collections.indeed_missing # [no-name-in-module] except ValueError: pass @@ -56,6 +61,12 @@ except ImportError: pass try: + import collections.emit1 +except ModuleNotFoundError: + pass + + +try: if something: import collections.emit2 # [no-name-in-module] except Exception: diff --git a/tests/functional/n/no/no_name_in_module.txt b/tests/functional/n/no/no_name_in_module.txt index 883e6b5d7..25b868076 100644 --- a/tests/functional/n/no/no_name_in_module.txt +++ b/tests/functional/n/no/no_name_in_module.txt @@ -7,8 +7,8 @@ no-name-in-module:23:0::No name 'compiile' in module 're' no-name-in-module:23:0::No name 'findiiter' in module 're' pointless-statement:26:0::Statement seems to have no effect no-name-in-module:34:4::No name 'anything' in module 'collections' -no-name-in-module:44:4::No name 'indeed_missing' in module 'collections' -no-name-in-module:49:4::No name 'emit' in module 'collections' -no-name-in-module:60:8::No name 'emit2' in module 'collections' -no-name-in-module:65:0::No name 'lala' in module 'functional.n.no.no_self_use' -no-name-in-module:66:0::No name 'bla' in module 'functional.n.no.no_self_use' +no-name-in-module:49:4::No name 'indeed_missing' in module 'collections' +no-name-in-module:54:4::No name 'emit' in module 'collections' +no-name-in-module:71:8::No name 'emit2' in module 'collections' +no-name-in-module:76:0::No name 'lala' in module 'functional.n.no.no_self_use' +no-name-in-module:77:0::No name 'bla' in module 'functional.n.no.no_self_use' |