diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-09-08 21:41:00 +0200 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2021-09-13 13:32:34 +0200 |
commit | c17457f7efbef06e2488cee4bd770cfdcf4ee04e (patch) | |
tree | aa02626bfa3d5bb171975afc7068458dacd9e65c | |
parent | e726eb40eabc29beacb18d174b3b75217326a7b9 (diff) | |
download | pylint-git-c17457f7efbef06e2488cee4bd770cfdcf4ee04e.tar.gz |
Add typing to most reference of ``stream``
-rw-r--r-- | pylint/checkers/misc.py | 11 | ||||
-rw-r--r-- | pylint/checkers/similar.py | 30 | ||||
-rw-r--r-- | pylint/config/man_help_formatter.py | 1 | ||||
-rw-r--r-- | pylint/config/option_manager_mixin.py | 12 | ||||
-rw-r--r-- | pylint/lint/pylinter.py | 20 | ||||
-rw-r--r-- | pylint/message/message_handler_mix_in.py | 16 | ||||
-rw-r--r-- | pylint/reporters/ureports/__init__.py | 7 | ||||
-rw-r--r-- | pylint/testutils/lint_module_test.py | 23 | ||||
-rw-r--r-- | pylint/utils/utils.py | 20 |
9 files changed, 85 insertions, 55 deletions
diff --git a/pylint/checkers/misc.py b/pylint/checkers/misc.py index 60d30c91b..2a0defcb4 100644 --- a/pylint/checkers/misc.py +++ b/pylint/checkers/misc.py @@ -28,6 +28,7 @@ import re import tokenize +from typing import Optional from astroid import nodes @@ -116,13 +117,19 @@ class EncodingChecker(BaseChecker): self._fixme_pattern = re.compile(regex_string, re.I) - def _check_encoding(self, lineno, line, file_encoding): + def _check_encoding( + self, lineno: int, line: bytes, file_encoding: str + ) -> Optional[str]: try: return line.decode(file_encoding) except UnicodeDecodeError: pass except LookupError: - if line.startswith("#") and "coding" in line and file_encoding in line: + if ( + line.startswith(b"#") + and "coding" in str(line) + and file_encoding in str(line) + ): msg = f"Cannot decode using encoding '{file_encoding}', bad encoding" self.add_message("syntax-error", line=lineno, args=msg) return None diff --git a/pylint/checkers/similar.py b/pylint/checkers/similar.py index fb92e7035..4ceb5d660 100644 --- a/pylint/checkers/similar.py +++ b/pylint/checkers/similar.py @@ -49,6 +49,7 @@ import re import sys from collections import defaultdict from getopt import getopt +from io import BufferedIOBase, BufferedReader, BytesIO from itertools import chain, groupby from typing import ( Any, @@ -59,9 +60,11 @@ from typing import ( List, NamedTuple, NewType, + Optional, Set, TextIO, Tuple, + Union, ) import astroid @@ -96,6 +99,9 @@ HashToIndex_T = Dict["LinesChunk", List[Index]] # Links index in the lineset's stripped lines to the real lines in the file IndexToLines_T = Dict[Index, "SuccessiveLinesLimits"] +# The types the streams read by pylint can take. Originating from astroid.nodes.Module.stream() and open() +STREAM_TYPES = Union[TextIO, BufferedReader, BytesIO] + class CplSuccessiveLinesLimits: """ @@ -368,12 +374,16 @@ class Similar: self.ignore_signatures = ignore_signatures self.linesets: List["LineSet"] = [] - def append_stream(self, streamid: str, stream: TextIO, encoding=None) -> None: + def append_stream( + self, streamid: str, stream: STREAM_TYPES, encoding: Optional[str] = None + ) -> None: """append a file to search for similarities""" - if encoding is None: - readlines = stream.readlines - else: + if isinstance(stream, BufferedIOBase): + if encoding is None: + raise ValueError readlines = decoding_stream(stream, encoding).readlines + else: + readlines = stream.readlines # type: ignore # hint parameter is incorrectly typed as non-optional try: self.linesets.append( LineSet( @@ -658,12 +668,12 @@ class LineSet: def __init__( self, - name, - lines, - ignore_comments=False, - ignore_docstrings=False, - ignore_imports=False, - ignore_signatures=False, + name: str, + lines: List[str], + ignore_comments: bool = False, + ignore_docstrings: bool = False, + ignore_imports: bool = False, + ignore_signatures: bool = False, ) -> None: self.name = name self._real_lines = lines diff --git a/pylint/config/man_help_formatter.py b/pylint/config/man_help_formatter.py index edef771a4..4b078146d 100644 --- a/pylint/config/man_help_formatter.py +++ b/pylint/config/man_help_formatter.py @@ -14,6 +14,7 @@ class _ManHelpFormatter(optparse.HelpFormatter): optparse.HelpFormatter.__init__( self, indent_increment, max_help_position, width, short_first ) + self.output_level: int def format_heading(self, heading): return f".SH {heading.upper()}\n" diff --git a/pylint/config/option_manager_mixin.py b/pylint/config/option_manager_mixin.py index 106ec47cc..c48d20713 100644 --- a/pylint/config/option_manager_mixin.py +++ b/pylint/config/option_manager_mixin.py @@ -10,6 +10,8 @@ import functools import optparse # pylint: disable=deprecated-module import os import sys +from types import ModuleType +from typing import Dict, List, Optional, TextIO, Tuple import toml @@ -186,11 +188,13 @@ class OptionsManagerMixIn: """set option on the correct option provider""" self._all_options[opt].set_option(opt, value) - def generate_config(self, stream=None, skipsections=()): + def generate_config( + self, stream: Optional[TextIO] = None, skipsections: Tuple[str, ...] = () + ) -> None: """write a configuration file according to the current configuration into the given stream or stdout """ - options_by_section = {} + options_by_section: Dict[str, List[Tuple]] = {} sections = [] for provider in self.options_providers: for section, options in provider.options_by_section(): @@ -219,7 +223,9 @@ class OptionsManagerMixIn: ) printed = True - def generate_manpage(self, pkginfo, section=1, stream=sys.stdout): + def generate_manpage( + self, pkginfo: ModuleType, section: int = 1, stream: TextIO = sys.stdout + ) -> None: with _patch_optparse(): formatter = _ManHelpFormatter() formatter.output_level = self._maxlevel diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py index 59276a50a..54614ad89 100644 --- a/pylint/lint/pylinter.py +++ b/pylint/lint/pylinter.py @@ -13,7 +13,7 @@ import warnings from io import TextIOWrapper import astroid -from astroid import AstroidError +from astroid import AstroidError, nodes from pylint import checkers, config, exceptions, interfaces, reporters from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES @@ -1180,10 +1180,12 @@ class PyLinter( return retval - def _check_astroid_module(self, ast_node, walker, rawcheckers, tokencheckers): + def _check_astroid_module( + self, node: nodes.Module, walker, rawcheckers, tokencheckers + ): """Check given AST node with given walker and checkers - :param astroid.nodes.Module ast_node: AST node of the module to check + :param astroid.nodes.Module node: AST node of the module to check :param pylint.utils.ast_walker.ASTWalker walker: AST walker :param list rawcheckers: List of token checkers to use :param list tokencheckers: List of raw checkers to use @@ -1193,13 +1195,13 @@ class PyLinter( :rtype: bool """ try: - tokens = utils.tokenize_module(ast_node) + tokens = utils.tokenize_module(node) except tokenize.TokenError as ex: self.add_message("syntax-error", line=ex.args[1][0], args=ex.args[0]) return None - if not ast_node.pure_python: - self.add_message("raw-checker-failed", args=ast_node.name) + if not node.pure_python: + self.add_message("raw-checker-failed", args=node.name) else: # assert astroid.file.endswith('.py') # invoke ITokenChecker interface on self to fetch module/block @@ -1208,14 +1210,14 @@ class PyLinter( if self._ignore_file: return False # walk ast to collect line numbers - self.file_state.collect_block_lines(self.msgs_store, ast_node) + self.file_state.collect_block_lines(self.msgs_store, node) # run raw and tokens checkers for checker in rawcheckers: - checker.process_module(ast_node) + checker.process_module(node) for checker in tokencheckers: checker.process_tokens(tokens) # generate events to astroid checkers - walker.walk(ast_node) + walker.walk(node) return True # IAstroidChecker interface ################################################# diff --git a/pylint/message/message_handler_mix_in.py b/pylint/message/message_handler_mix_in.py index 00adfa5d9..6d24131a7 100644 --- a/pylint/message/message_handler_mix_in.py +++ b/pylint/message/message_handler_mix_in.py @@ -2,7 +2,8 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE import sys -from typing import List, Tuple, Union +from io import TextIOWrapper +from typing import List, TextIO, Tuple, Union from pylint.constants import ( _SCOPE_EXEMPT, @@ -390,20 +391,13 @@ Below is a list of all checkers and their features. result += checker.get_full_documentation(**information) return result - def print_full_documentation(self, stream=None): + def print_full_documentation(self, stream: TextIO = sys.stdout) -> None: """output a full documentation in ReST format""" - if not stream: - stream = sys.stdout print(self.get_checkers_documentation()[:-1], file=stream) @staticmethod - def _print_checker_doc(information, stream=None): - """Helper method for print_full_documentation. - - Also used by doc/exts/pylint_extensions.py. - """ - if not stream: - stream = sys.stdout + def _print_checker_doc(information, stream: TextIOWrapper) -> None: + """Helper method used by doc/exts/pylint_extensions.py.""" checker = information["checker"] del information["checker"] print(checker.get_full_documentation(**information)[:-1], file=stream) diff --git a/pylint/reporters/ureports/__init__.py b/pylint/reporters/ureports/__init__.py index 4126cf4ce..f0651f98c 100644 --- a/pylint/reporters/ureports/__init__.py +++ b/pylint/reporters/ureports/__init__.py @@ -18,20 +18,19 @@ formatted as text and html. import os import sys from io import StringIO +from typing import Iterator, TextIO class BaseWriter: """base class for ureport writers""" - def format(self, layout, stream=None, encoding=None): + def format(self, layout, stream: TextIO = sys.stdout, encoding=None) -> None: """format and write the given layout into the stream object unicode policy: unicode strings may be found in the layout; try to call stream.write with it, but give it back encoded using the given encoding if it fails """ - if stream is None: - stream = sys.stdout if not encoding: encoding = getattr(stream, "encoding", "UTF-8") self.encoding = encoding or "UTF-8" @@ -79,7 +78,7 @@ class BaseWriter: result[-1] += [""] * (cols - len(result[-1])) return result - def compute_content(self, layout): + def compute_content(self, layout) -> Iterator[str]: """trick to compute the formatting of children layout before actually writing it diff --git a/pylint/testutils/lint_module_test.py b/pylint/testutils/lint_module_test.py index 2b5ad2dcb..c15d01271 100644 --- a/pylint/testutils/lint_module_test.py +++ b/pylint/testutils/lint_module_test.py @@ -6,8 +6,8 @@ import operator import platform import sys from collections import Counter -from io import StringIO -from typing import Dict, List, Optional, Tuple +from io import StringIO, TextIOWrapper +from typing import TYPE_CHECKING, Dict, List, Optional, Tuple import pytest from _pytest.config import Config @@ -24,6 +24,9 @@ from pylint.testutils.output_line import OutputLine from pylint.testutils.reporter_for_tests import FunctionalTestReporter from pylint.utils import utils +if TYPE_CHECKING: + from typing import Counter as CounterType # typing.Counter added in Python 3.6.1 + class LintModuleTest: maxDiff = None @@ -88,7 +91,7 @@ class LintModuleTest: return f"{self._test_file.base} ({self.__class__.__module__}.{self.__class__.__name__})" @staticmethod - def get_expected_messages(stream): + def get_expected_messages(stream: TextIOWrapper) -> "CounterType[Tuple[int, str]]": """Parses a file and get expected messages. :param stream: File-like input stream. @@ -96,18 +99,18 @@ class LintModuleTest: :returns: A dict mapping line,msg-symbol tuples to the count on this line. :rtype: dict """ - messages = Counter() + messages: "CounterType[Tuple[int, str]]" = Counter() for i, line in enumerate(stream): match = _EXPECTED_RE.search(line) if match is None: continue line = match.group("line") if line is None: - line = i + 1 + lineno = i + 1 elif line.startswith("+") or line.startswith("-"): - line = i + 1 + int(line) + lineno = i + 1 + int(line) else: - line = int(line) + lineno = int(line) version = match.group("version") op = match.group("op") @@ -117,13 +120,13 @@ class LintModuleTest: continue for msg_id in match.group("msgs").split(","): - messages[line, msg_id.strip()] += 1 + messages[lineno, msg_id.strip()] += 1 return messages @staticmethod def multiset_difference( - expected_entries: Counter, actual_entries: Counter - ) -> Tuple[Counter, Dict[str, int]]: + expected_entries: "CounterType", actual_entries: "CounterType" + ) -> Tuple["CounterType", Dict[str, int]]: """Takes two multisets and compares them. A multiset is a dict with the cardinality of the key as the value.""" diff --git a/pylint/utils/utils.py b/pylint/utils/utils.py index c41b35bd7..231983aa6 100644 --- a/pylint/utils/utils.py +++ b/pylint/utils/utils.py @@ -17,18 +17,20 @@ import re import sys import textwrap import tokenize +from io import BufferedReader, BytesIO from typing import ( TYPE_CHECKING, List, Optional, Pattern, + TextIO, Tuple, TypeVar, Union, overload, ) -from astroid import Module, modutils +from astroid import Module, modutils, nodes from pylint.constants import PY_EXTS @@ -143,7 +145,11 @@ def safe_decode(line, encoding, *args, **kwargs): return line.decode(sys.getdefaultencoding(), *args, **kwargs) -def decoding_stream(stream, encoding, errors="strict"): +def decoding_stream( + stream: Union[BufferedReader, BytesIO], + encoding: str, + errors: Literal["strict"] = "strict", +) -> codecs.StreamReader: try: reader_cls = codecs.getreader(encoding or sys.getdefaultencoding()) except LookupError: @@ -151,8 +157,8 @@ def decoding_stream(stream, encoding, errors="strict"): return reader_cls(stream, errors) -def tokenize_module(module): - with module.stream() as stream: +def tokenize_module(node: nodes.Module) -> List[tokenize.TokenInfo]: + with node.stream() as stream: readline = stream.readline return list(tokenize.tokenize(readline)) @@ -348,7 +354,9 @@ def _format_option_value(optdict, value): return value -def format_section(stream, section, options, doc=None): +def format_section( + stream: TextIO, section: str, options: List[Tuple], doc: Optional[str] = None +) -> None: """format an options section using the INI format""" if doc: print(_comment(doc), file=stream) @@ -356,7 +364,7 @@ def format_section(stream, section, options, doc=None): _ini_format(stream, options) -def _ini_format(stream, options): +def _ini_format(stream: TextIO, options: List[Tuple]) -> None: """format options using the INI format""" for optname, optdict, value in options: value = _format_option_value(optdict, value) |