Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typing in pylint.reporters #5004

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pylint/checkers/imports.py
Expand Up @@ -193,7 +193,7 @@ def _make_graph(
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}",)))
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved


# 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")
10 changes: 5 additions & 5 deletions pylint/lint/report_functions.py
Expand Up @@ -5,7 +5,7 @@
from typing import DefaultDict, Dict, List, Tuple, Union

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 @@ -41,7 +41,7 @@ def report_messages_stats(
lines = ["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 @@ -61,7 +61,7 @@ def report_messages_by_module_stats(
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
percent = 0 if total == 0 else float(mod_total * 100) / total
by_mod[module][m_type] = percent
sorted_result = []
for module, mod_info in by_mod.items():
Expand All @@ -86,4 +86,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
23 changes: 14 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 Down
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
56 changes: 33 additions & 23 deletions pylint/reporters/ureports/nodes.py
Expand Up @@ -14,21 +14,21 @@

A micro report is a tree of layout and content objects.
"""
from typing import Optional
from typing import Any, Iterator, List, Optional, Tuple, Union

from pylint.reporters.ureports.text_writer import TextWriter


class VNode:
def __init__(self, nid=None):
self.id = nid
# navigation
self.parent = None
self.children = []
self.visitor_name = self.__class__.__name__.lower()

def __iter__(self):
def __init__(self) -> None:
self.parent: Optional[Any] = None
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
self.children: List["VNode"] = []
self.visitor_name: str = self.__class__.__name__.lower()

def __iter__(self) -> Iterator["VNode"]:
return iter(self.children)

def accept(self, visitor, *args, **kwargs):
def accept(self, visitor: TextWriter, *args: Any, **kwargs: Any) -> None:
func = getattr(visitor, f"visit_{self.visitor_name}")
return func(self, *args, **kwargs)

Expand All @@ -44,8 +44,8 @@ class BaseLayout(VNode):
* children : components in this table (i.e. the table's cells)
"""

def __init__(self, children=(), **kwargs):
super().__init__(**kwargs)
def __init__(self, children: Union[List["Text"], Tuple[str, ...]] = ()) -> None:
super().__init__()
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
for child in children:
if isinstance(child, VNode):
self.append(child)
Expand All @@ -63,14 +63,14 @@ def insert(self, index: int, child: VNode) -> None:
self.children.insert(index, child)
child.parent = self

def parents(self):
def parents(self) -> List["VNode"]:
"""return the ancestor nodes"""
assert self.parent is not self
if self.parent is None:
return []
return [self.parent] + self.parent.parents()

def add_text(self, text):
def add_text(self, text: str) -> None:
"""shortcut to add text data"""
self.children.append(Text(text))

Expand All @@ -85,11 +85,8 @@ class Text(VNode):
* data : the text value as an encoded or unicode string
"""

def __init__(self, data, escaped=True, **kwargs):
super().__init__(**kwargs)
# if isinstance(data, unicode):
# data = data.encode('ascii')
assert isinstance(data, str), data.__class__
def __init__(self, data: str, escaped: bool = True) -> None:
super().__init__()
self.escaped = escaped
self.data = data

Expand Down Expand Up @@ -117,17 +114,23 @@ class Section(BaseLayout):
as a first paragraph
"""

def __init__(self, title=None, description=None, **kwargs):
def __init__(
self,
title: Optional[str] = None,
description: Optional[str] = None,
**kwargs: Any,
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
super().__init__(**kwargs)
if description:
self.insert(0, Paragraph([Text(description)]))
if title:
self.insert(0, Title(children=(title,)))
self.report_id: Optional[str] = None
# Used in ReportHandlerMixin make_reports
self.report_id: str = ""
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved


class EvaluationSection(Section):
def __init__(self, message, **kwargs):
def __init__(self, message: str, **kwargs: Any) -> None:
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
super().__init__(**kwargs)
title = Paragraph()
title.append(Text("-" * len(message)))
Expand Down Expand Up @@ -169,7 +172,14 @@ class Table(BaseLayout):
* title : the table's optional title
"""

def __init__(self, cols, title=None, rheaders=0, cheaders=0, **kwargs):
def __init__(
self,
cols: int,
title: Optional[str] = None,
rheaders: int = 0,
cheaders: int = 0,
**kwargs: Any,
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
) -> None:
super().__init__(**kwargs)
assert isinstance(cols, int)
self.cols = cols
Expand Down