aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2021-09-08 21:41:00 +0200
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-09-13 13:32:34 +0200
commitc17457f7efbef06e2488cee4bd770cfdcf4ee04e (patch)
treeaa02626bfa3d5bb171975afc7068458dacd9e65c
parente726eb40eabc29beacb18d174b3b75217326a7b9 (diff)
downloadpylint-c17457f7efbef06e2488cee4bd770cfdcf4ee04e.tar.gz
Add typing to most reference of ``stream``
-rw-r--r--pylint/checkers/misc.py11
-rw-r--r--pylint/checkers/similar.py30
-rw-r--r--pylint/config/man_help_formatter.py1
-rw-r--r--pylint/config/option_manager_mixin.py12
-rw-r--r--pylint/lint/pylinter.py20
-rw-r--r--pylint/message/message_handler_mix_in.py16
-rw-r--r--pylint/reporters/ureports/__init__.py7
-rw-r--r--pylint/testutils/lint_module_test.py23
-rw-r--r--pylint/utils/utils.py20
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)