Skip to content

Commit

Permalink
Add typing and fix small issue in pylint.reporters
Browse files Browse the repository at this point in the history
Fix typing error in pylint/checkers/imports.py. Add typing
of report related code outside of pylint.reporters.
  • Loading branch information
Pierre-Sassoulas committed Sep 15, 2021
1 parent d4e61b9 commit 82a7ff1
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 70 deletions.
2 changes: 1 addition & 1 deletion pylint/checkers/imports.py
Expand Up @@ -191,7 +191,7 @@ def _make_graph(filename: str, dep_info: Dict[str, List[str]], sect: VNode, gtyp
report's section
"""
outputfile = _dependencies_graph(filename, dep_info)
sect.append(Paragraph(f"{gtype}imports graph has been written to {outputfile}"))
sect.append(Paragraph((f"{gtype}imports graph has been written to {outputfile}",)))


# the import checker itself ###################################################
Expand Down
5 changes: 3 additions & 2 deletions pylint/interfaces.py
Expand Up @@ -17,6 +17,7 @@

"""Interfaces for Pylint objects"""
from collections import namedtuple
from typing import Tuple

from astroid import nodes

Expand All @@ -40,7 +41,7 @@ def is_implemented_by(cls, instance):
return implements(instance, cls)


def implements(obj, interface):
def implements(obj: "Interface", interface: Tuple[type, type]) -> bool:
"""Return true if the give object (maybe an instance or class) implements
the interface.
"""
Expand Down Expand Up @@ -101,4 +102,4 @@ def display_reports(self, layout):
"""display results encapsulated in the layout tree"""


__all__ = ("IRawChecker", "IAstroidChecker", "ITokenChecker", "IReporter")
__all__ = ("IRawChecker", "IAstroidChecker", "ITokenChecker", "IReporter", "IChecker")
24 changes: 11 additions & 13 deletions pylint/lint/report_functions.py
Expand Up @@ -2,10 +2,10 @@
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE

import collections
from typing import DefaultDict, Dict, List, Tuple, Union
from typing import DefaultDict, Dict, List, Tuple

from pylint import checkers, exceptions
from pylint.reporters.ureports import nodes as report_nodes
from pylint.reporters.ureports.nodes import Table
from pylint.typing import CheckerStats


Expand All @@ -19,7 +19,7 @@ def report_total_messages_stats(
lines += checkers.table_lines_from_stats(
stats, previous_stats, ("convention", "refactor", "warning", "error")
)
sect.append(report_nodes.Table(children=lines, cols=4, rheaders=1))
sect.append(Table(children=lines, cols=4, rheaders=1))


def report_messages_stats(
Expand All @@ -38,10 +38,10 @@ def report_messages_stats(
if not msg_id.startswith("I")
)
in_order.reverse()
lines = ["message id", "occurrences"]
lines: List[str] = ["message id", "occurrences"]
for value, msg_id in in_order:
lines += [msg_id, str(value)]
sect.append(report_nodes.Table(children=lines, cols=2, rheaders=1))
sect.append(Table(children=lines, cols=2, rheaders=1))


def report_messages_by_module_stats(
Expand All @@ -54,14 +54,12 @@ def report_messages_by_module_stats(
if len(module_stats) == 1:
# don't print this report when we are analysing a single module
raise exceptions.EmptyReportError()
by_mod: DefaultDict[str, Dict[str, Union[int, float]]] = collections.defaultdict(
dict
)
by_mod: DefaultDict = collections.defaultdict(dict)
for m_type in ("fatal", "error", "warning", "refactor", "convention"):
total: int = stats[m_type] # type: ignore
for module in module_stats.keys():
mod_total = module_stats[module][m_type]
percent = 0 if total == 0 else float((mod_total) * 100) / total
total = stats[m_type]
for module in stats["by_module"].keys(): # type: ignore
mod_total = stats["by_module"][module][m_type] # type: ignore
percent = 0 if total == 0 else float(mod_total * 100) / total # type: ignore
by_mod[module][m_type] = percent
sorted_result = []
for module, mod_info in by_mod.items():
Expand All @@ -86,4 +84,4 @@ def report_messages_by_module_stats(
lines.append(f"{val:.2f}")
if len(lines) == 5:
raise exceptions.EmptyReportError()
sect.append(report_nodes.Table(children=lines, cols=5, rheaders=1))
sect.append(Table(children=lines, cols=5, rheaders=1))
9 changes: 6 additions & 3 deletions pylint/reporters/__init__.py
Expand Up @@ -21,7 +21,7 @@
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE

"""utilities methods and classes for reporters"""

from typing import TYPE_CHECKING

from pylint import utils
from pylint.reporters.base_reporter import BaseReporter
Expand All @@ -30,10 +30,13 @@
from pylint.reporters.multi_reporter import MultiReporter
from pylint.reporters.reports_handler_mix_in import ReportsHandlerMixIn

if TYPE_CHECKING:
from pylint.lint.pylinter import PyLinter


def initialize(linter):
def initialize(linter: "PyLinter") -> None:
"""initialize linter with reporters in this package"""
utils.register_plugins(linter, __path__[0])
utils.register_plugins(linter, __path__[0]) # type: ignore # Fixed in https://github.com/python/mypy/pull/9454


__all__ = [
Expand Down
4 changes: 2 additions & 2 deletions pylint/reporters/collecting_reporter.py
Expand Up @@ -8,11 +8,11 @@ class CollectingReporter(BaseReporter):

name = "collector"

def __init__(self):
def __init__(self) -> None:
BaseReporter.__init__(self)
self.messages = []

def reset(self):
def reset(self) -> None:
self.messages = []

_display = None
2 changes: 1 addition & 1 deletion pylint/reporters/multi_reporter.py
Expand Up @@ -43,7 +43,7 @@ def __init__(

self.set_output(output)

def __del__(self):
def __del__(self) -> None:
self.close_output_files()

@property
Expand Down
24 changes: 15 additions & 9 deletions pylint/reporters/reports_handler_mix_in.py
Expand Up @@ -2,9 +2,10 @@
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE

import collections
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Callable, DefaultDict, Dict, List, Tuple

from pylint.exceptions import EmptyReportError
from pylint.interfaces import IChecker
from pylint.reporters.ureports.nodes import Section
from pylint.typing import CheckerStats

Expand All @@ -17,17 +18,21 @@ class ReportsHandlerMixIn:
related methods for the main lint class
"""

def __init__(self):
self._reports = collections.defaultdict(list)
self._reports_state = {}
def __init__(self) -> None:
self._reports: DefaultDict[
IChecker, List[Tuple[str, str, Callable]]
] = collections.defaultdict(list)
self._reports_state: Dict[str, bool] = {}

def report_order(self):
"""Return a list of reports, sorted in the order
in which they must be called.
"""
return list(self._reports)

def register_report(self, reportid, r_title, r_cb, checker):
def register_report(
self, reportid: str, r_title: str, r_cb: Callable, checker: IChecker
) -> None:
"""register a report
reportid is the unique identifier for the report
Expand All @@ -38,17 +43,17 @@ def register_report(self, reportid, r_title, r_cb, checker):
reportid = reportid.upper()
self._reports[checker].append((reportid, r_title, r_cb))

def enable_report(self, reportid):
def enable_report(self, reportid: str) -> None:
"""disable the report of the given id"""
reportid = reportid.upper()
self._reports_state[reportid] = True

def disable_report(self, reportid):
def disable_report(self, reportid: str) -> None:
"""disable the report of the given id"""
reportid = reportid.upper()
self._reports_state[reportid] = False

def report_is_enabled(self, reportid):
def report_is_enabled(self, reportid: str) -> bool:
"""return true if the report associated to the given identifier is
enabled
"""
Expand All @@ -58,7 +63,7 @@ def make_reports( # type: ignore # ReportsHandlerMixIn is always mixed with PyL
self: "PyLinter",
stats: CheckerStats,
old_stats: CheckerStats,
):
) -> Section:
"""render registered reports"""
sect = Section("Report", f"{self.stats['statement']} statements analysed.")
for checker in self.report_order():
Expand All @@ -83,6 +88,7 @@ def add_stats( # type: ignore # ReportsHandlerMixIn is always mixed with PyLint
for key, value in kwargs.items():
if key[-1] == "_":
key = key[:-1]
# self.stats is defined in another class (this is a mixin)
assert key not in self.stats
self.stats[key] = value
return self.stats
26 changes: 18 additions & 8 deletions pylint/reporters/ureports/base_writer.py
Expand Up @@ -18,7 +18,15 @@
import os
import sys
from io import StringIO
from typing import Iterator, TextIO
from typing import TYPE_CHECKING, Iterator, List, TextIO, Union

if TYPE_CHECKING:
from pylint.reporters.ureports.nodes import (
EvaluationSection,
Paragraph,
Section,
Table,
)


class BaseWriter:
Expand All @@ -39,34 +47,36 @@ def format(self, layout, stream: TextIO = sys.stdout, encoding=None) -> None:
layout.accept(self)
self.end_format()

def format_children(self, layout):
def format_children(
self, layout: Union["EvaluationSection", "Paragraph", "Section"]
) -> None:
"""recurse on the layout children and call their accept method
(see the Visitor pattern)
"""
for child in getattr(layout, "children", ()):
child.accept(self)

def writeln(self, string=""):
def writeln(self, string: str = "") -> None:
"""write a line in the output buffer"""
self.write(string + os.linesep)

def write(self, string):
def write(self, string: str) -> None:
"""write a string in the output buffer"""
self.out.write(string)

def begin_format(self):
def begin_format(self) -> None:
"""begin to format a layout"""
self.section = 0

def end_format(self):
def end_format(self) -> None:
"""finished to format a layout"""

def get_table_content(self, table):
def get_table_content(self, table: "Table") -> List[List[str]]:
"""trick to get table content without actually writing it
return an aligned list of lists containing table cells values as string
"""
result = [[]]
result: List[List[str]] = [[]]
cols = table.cols
for cell in self.compute_content(table):
if cols == 0:
Expand Down

0 comments on commit 82a7ff1

Please sign in to comment.