diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-09-15 20:42:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-15 20:42:22 +0200 |
commit | 22e56c07cf745d695df1d52fe3988cc071f0951b (patch) | |
tree | 713b888a2f24239932b7d8a6a1d9f8bffe0026cd /pylint/checkers | |
parent | cb896128b0e8f62c0650e980ef77a3c8af21ef8d (diff) | |
download | pylint-git-22e56c07cf745d695df1d52fe3988cc071f0951b.tar.gz |
Add typing to all calls to ``self.stats`` (#4973)
* Add typing to all calls to ``self.stats``
All checkers inherit from a baseclass which has a ``stats`` attribute.
This attribute has a fairly unmanageable type, but the current typing includes all variations of the attribute.
Other changes not directly related to ``self.stats`` are due to ``mypy``warnings.
This incorporate the feedback received in #4954
* Add ``CheckerStatistic`` class to ``pylint/typing``
* Guard `typing.Counter` import
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Diffstat (limited to 'pylint/checkers')
-rw-r--r-- | pylint/checkers/__init__.py | 17 | ||||
-rw-r--r-- | pylint/checkers/base.py | 31 | ||||
-rw-r--r-- | pylint/checkers/base_checker.py | 2 | ||||
-rw-r--r-- | pylint/checkers/design_analysis.py | 3 | ||||
-rw-r--r-- | pylint/checkers/imports.py | 8 | ||||
-rw-r--r-- | pylint/checkers/raw_metrics.py | 17 | ||||
-rw-r--r-- | pylint/checkers/similar.py | 9 |
7 files changed, 57 insertions, 30 deletions
diff --git a/pylint/checkers/__init__.py b/pylint/checkers/__init__.py index ffc940223..584f476fc 100644 --- a/pylint/checkers/__init__.py +++ b/pylint/checkers/__init__.py @@ -46,28 +46,35 @@ messages nor reports. XXX not true, emit a 07 report ! """ +from typing import Iterable, List, Union + from pylint.checkers.base_checker import BaseChecker, BaseTokenChecker from pylint.checkers.deprecated import DeprecatedMixin from pylint.checkers.mapreduce_checker import MapReduceMixin +from pylint.typing import CheckerStats from pylint.utils import diff_string, register_plugins -def table_lines_from_stats(stats, old_stats, columns): +def table_lines_from_stats( + stats: CheckerStats, + old_stats: CheckerStats, + columns: Iterable[str], +) -> List[str]: """get values listed in <columns> from <stats> and <old_stats>, and return a formated list of values, designed to be given to a ureport.Table object """ - lines = [] + lines: List[str] = [] for m_type in columns: - new = stats[m_type] - old = old_stats.get(m_type) + new: Union[int, str] = stats[m_type] # type: ignore + old: Union[int, str, None] = old_stats.get(m_type) # type: ignore if old is not None: diff_str = diff_string(old, new) else: old, diff_str = "NC", "NC" new = f"{new:.3f}" if isinstance(new, float) else str(new) old = f"{old:.3f}" if isinstance(old, float) else str(old) - lines += (m_type.replace("_", " "), new, old, diff_str) + lines.extend((m_type.replace("_", " "), new, old, diff_str)) return lines diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py index d839d921e..2f1579cd6 100644 --- a/pylint/checkers/base.py +++ b/pylint/checkers/base.py @@ -66,7 +66,7 @@ import collections import itertools import re import sys -from typing import Any, Iterator, Optional, Pattern +from typing import Any, Dict, Iterator, Optional, Pattern, Union import astroid from astroid import nodes @@ -81,6 +81,7 @@ from pylint.checkers.utils import ( is_property_setter, ) from pylint.reporters.ureports import nodes as reporter_nodes +from pylint.typing import CheckerStats class NamingStyle: @@ -386,36 +387,42 @@ def _has_abstract_methods(node): return len(utils.unimplemented_abstract_methods(node)) > 0 -def report_by_type_stats(sect, stats, old_stats): +def report_by_type_stats( + sect, + stats: CheckerStats, + old_stats: CheckerStats, +): """make a report of * percentage of different types documented * percentage of different types with a bad name """ # percentage of different types documented and/or with a bad name - nice_stats = {} + nice_stats: Dict[str, Dict[str, str]] = {} for node_type in ("module", "class", "method", "function"): try: - total = stats[node_type] + total: int = stats[node_type] # type: ignore except KeyError as e: raise exceptions.EmptyReportError() from e nice_stats[node_type] = {} if total != 0: try: - documented = total - stats["undocumented_" + node_type] + undocumented_node: int = stats["undocumented_" + node_type] # type: ignore + documented = total - undocumented_node percent = (documented * 100.0) / total nice_stats[node_type]["percent_documented"] = f"{percent:.2f}" except KeyError: nice_stats[node_type]["percent_documented"] = "NC" try: - percent = (stats["badname_" + node_type] * 100.0) / total + badname_node: int = stats["badname_" + node_type] # type: ignore + percent = (badname_node * 100.0) / total nice_stats[node_type]["percent_badname"] = f"{percent:.2f}" except KeyError: nice_stats[node_type]["percent_badname"] = "NC" lines = ["type", "number", "old number", "difference", "%documented", "%badname"] for node_type in ("module", "class", "method", "function"): new = stats[node_type] - old = old_stats.get(node_type, None) + old: Optional[Union[str, int]] = old_stats.get(node_type, None) # type: ignore if old is not None: diff_str = lint_utils.diff_string(old, new) else: @@ -1082,7 +1089,7 @@ class BasicChecker(_BasicChecker): def __init__(self, linter): _BasicChecker.__init__(self, linter) - self.stats = None + self.stats: CheckerStats = {} self._tryfinallys = None def open(self): @@ -1159,13 +1166,13 @@ class BasicChecker(_BasicChecker): def visit_module(self, _: nodes.Module) -> None: """check module name, docstring and required arguments""" - self.stats["module"] += 1 + self.stats["module"] += 1 # type: ignore def visit_classdef(self, _: nodes.ClassDef) -> None: """check module name, docstring and redefinition increment branch counter """ - self.stats["class"] += 1 + self.stats["class"] += 1 # type: ignore @utils.check_messages( "pointless-statement", "pointless-string-statement", "expression-not-assigned" @@ -1304,7 +1311,7 @@ class BasicChecker(_BasicChecker): """check function name, docstring, arguments, redefinition, variable names, max locals """ - self.stats["method" if node.is_method() else "function"] += 1 + self.stats["method" if node.is_method() else "function"] += 1 # type: ignore self._check_dangerous_default(node) visit_asyncfunctiondef = visit_functiondef @@ -2040,7 +2047,7 @@ class NameChecker(_BasicChecker): ) self.add_message(warning, node=node, args=args, confidence=confidence) - self.stats["badname_" + node_type] += 1 + self.stats["badname_" + node_type] += 1 # type: ignore def _name_allowed_by_regex(self, name: str) -> bool: return name in self.config.good_names or any( diff --git a/pylint/checkers/base_checker.py b/pylint/checkers/base_checker.py index 5dfd7ea78..791a3cb1e 100644 --- a/pylint/checkers/base_checker.py +++ b/pylint/checkers/base_checker.py @@ -24,6 +24,7 @@ from pylint.constants import _MSG_ORDER, WarningScope from pylint.exceptions import InvalidMessageError from pylint.interfaces import UNDEFINED, IRawChecker, ITokenChecker, implements from pylint.message.message_definition import MessageDefinition +from pylint.typing import CheckerStats from pylint.utils import get_rst_section, get_rst_title @@ -51,6 +52,7 @@ class BaseChecker(OptionsProviderMixIn): self.name = self.name.lower() OptionsProviderMixIn.__init__(self) self.linter = linter + self.stats: CheckerStats = {} def __gt__(self, other): """Permit to sort a list of Checker by name.""" diff --git a/pylint/checkers/design_analysis.py b/pylint/checkers/design_analysis.py index 9777b568e..362d299de 100644 --- a/pylint/checkers/design_analysis.py +++ b/pylint/checkers/design_analysis.py @@ -35,6 +35,7 @@ from pylint import utils from pylint.checkers import BaseChecker from pylint.checkers.utils import check_messages from pylint.interfaces import IAstroidChecker +from pylint.typing import CheckerStats MSGS = { # pylint: disable=consider-using-namedtuple-or-dataclass "R0901": ( @@ -391,7 +392,7 @@ class MisdesignChecker(BaseChecker): def __init__(self, linter=None): BaseChecker.__init__(self, linter) - self.stats = None + self.stats: CheckerStats = {} self._returns = None self._branches = None self._stmts = None diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index 7e0cda26d..8b413253f 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -68,6 +68,7 @@ from pylint.graph import DotBackend, get_cycles from pylint.interfaces import IAstroidChecker from pylint.lint import PyLinter from pylint.reporters.ureports.nodes import Paragraph, VerbatimText, VNode +from pylint.typing import CheckerStats from pylint.utils import IsortDriver, get_global_option @@ -423,7 +424,7 @@ class ImportsChecker(DeprecatedMixin, BaseChecker): self, linter: PyLinter = None ): # pylint: disable=super-init-not-called # See https://github.com/PyCQA/pylint/issues/4941 BaseChecker.__init__(self, linter) - self.stats: Dict[Any, Any] = {} + self.stats: CheckerStats = {} self.import_graph: collections.defaultdict = collections.defaultdict(set) self._imports_stack: List[Tuple[Any, Any]] = [] self._first_non_import_node = None @@ -839,9 +840,8 @@ class ImportsChecker(DeprecatedMixin, BaseChecker): self._module_pkg[context_name] = context_name.rsplit(".", 1)[0] # handle dependencies - importedmodnames = self.stats["dependencies"].setdefault( - importedmodname, set() - ) + dependencies_stat: Dict[str, Union[Set]] = self.stats["dependencies"] # type: ignore + importedmodnames = dependencies_stat.setdefault(importedmodname, set()) if context_name not in importedmodnames: importedmodnames.add(context_name) diff --git a/pylint/checkers/raw_metrics.py b/pylint/checkers/raw_metrics.py index 028c68e7a..cc3f2729d 100644 --- a/pylint/checkers/raw_metrics.py +++ b/pylint/checkers/raw_metrics.py @@ -15,27 +15,32 @@ # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE import tokenize -from typing import Any +from typing import Any, Optional, Union from pylint.checkers import BaseTokenChecker from pylint.exceptions import EmptyReportError from pylint.interfaces import ITokenChecker from pylint.reporters.ureports.nodes import Table +from pylint.typing import CheckerStats from pylint.utils import diff_string -def report_raw_stats(sect, stats, old_stats): +def report_raw_stats( + sect, + stats: CheckerStats, + old_stats: CheckerStats, +): """calculate percentage of code / doc / comment / empty""" - total_lines = stats["total_lines"] + total_lines: int = stats["total_lines"] # type: ignore if not total_lines: raise EmptyReportError() sect.description = f"{total_lines} lines have been analyzed" lines = ["type", "number", "%", "previous", "difference"] for node_type in ("code", "docstring", "comment", "empty"): key = node_type + "_lines" - total = stats[key] + total: int = stats[key] # type: ignore percent = float(total * 100) / total_lines - old = old_stats.get(key, None) + old: Optional[Union[int, str]] = old_stats.get(key, None) # type: ignore if old is not None: diff_str = diff_string(old, total) else: @@ -66,7 +71,7 @@ class RawMetricsChecker(BaseTokenChecker): def __init__(self, linter): BaseTokenChecker.__init__(self, linter) - self.stats = None + self.stats: CheckerStats = {} def open(self): """init statistics""" diff --git a/pylint/checkers/similar.py b/pylint/checkers/similar.py index 4ceb5d660..2a28e7d6c 100644 --- a/pylint/checkers/similar.py +++ b/pylint/checkers/similar.py @@ -73,6 +73,7 @@ from astroid import nodes from pylint.checkers import BaseChecker, MapReduceMixin, table_lines_from_stats from pylint.interfaces import IRawChecker from pylint.reporters.ureports.nodes import Table +from pylint.typing import CheckerStats from pylint.utils import decoding_stream DEFAULT_MIN_SIMILARITY_LINE = 4 @@ -721,7 +722,11 @@ MSGS = { } -def report_similarities(sect, stats, old_stats): +def report_similarities( + sect, + stats: CheckerStats, + old_stats: CheckerStats, +): """make a layout with some stats about duplication""" lines = ["", "now", "previous", "difference"] lines += table_lines_from_stats( @@ -804,7 +809,7 @@ class SimilarChecker(BaseChecker, Similar, MapReduceMixin): ignore_imports=self.config.ignore_imports, ignore_signatures=self.config.ignore_signatures, ) - self.stats = None + self.stats: CheckerStats = {} def set_option(self, optname, value, action=None, optdict=None): """method called to set an option (registered in the options list) |