Skip to content

Commit dc0c7e9

Browse files
Add typing in pylint.reporters (#5004)
* Add typing and fix small issue in pylint.reporters Fix typing error in pylint/checkers/imports.py. Add typing of report related code outside of pylint.reporters. * Remove unused argument in pylint.reporters.VNode constructor * Simplify and specify the typing in reporters nodes Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
1 parent 14f4db5 commit dc0c7e9

11 files changed

+118
-73
lines changed

pylint/checkers/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def table_lines_from_stats(
6161
columns: Iterable[str],
6262
) -> List[str]:
6363
"""get values listed in <columns> from <stats> and <old_stats>,
64-
and return a formated list of values, designed to be given to a
64+
and return a formatted list of values, designed to be given to a
6565
ureport.Table object
6666
"""
6767
lines: List[str] = []

pylint/checkers/imports.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ def _make_graph(
193193
report's section
194194
"""
195195
outputfile = _dependencies_graph(filename, dep_info)
196-
sect.append(Paragraph(f"{gtype}imports graph has been written to {outputfile}"))
196+
sect.append(Paragraph((f"{gtype}imports graph has been written to {outputfile}",)))
197197

198198

199199
# the import checker itself ###################################################

pylint/interfaces.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
"""Interfaces for Pylint objects"""
1919
from collections import namedtuple
20+
from typing import Tuple
2021

2122
from astroid import nodes
2223

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

4243

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

103104

104-
__all__ = ("IRawChecker", "IAstroidChecker", "ITokenChecker", "IReporter")
105+
__all__ = ("IRawChecker", "IAstroidChecker", "ITokenChecker", "IReporter", "IChecker")

pylint/lint/report_functions.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import DefaultDict, Dict, List, Tuple, Union
66

77
from pylint import checkers, exceptions
8-
from pylint.reporters.ureports import nodes as report_nodes
8+
from pylint.reporters.ureports.nodes import Table
99
from pylint.typing import CheckerStats
1010

1111

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

2424

2525
def report_messages_stats(
@@ -41,7 +41,7 @@ def report_messages_stats(
4141
lines = ["message id", "occurrences"]
4242
for value, msg_id in in_order:
4343
lines += [msg_id, str(value)]
44-
sect.append(report_nodes.Table(children=lines, cols=2, rheaders=1))
44+
sect.append(Table(children=lines, cols=2, rheaders=1))
4545

4646

4747
def report_messages_by_module_stats(
@@ -61,7 +61,7 @@ def report_messages_by_module_stats(
6161
total: int = stats[m_type] # type: ignore
6262
for module in module_stats.keys():
6363
mod_total = module_stats[module][m_type]
64-
percent = 0 if total == 0 else float((mod_total) * 100) / total
64+
percent = 0 if total == 0 else float(mod_total * 100) / total
6565
by_mod[module][m_type] = percent
6666
sorted_result = []
6767
for module, mod_info in by_mod.items():
@@ -86,4 +86,4 @@ def report_messages_by_module_stats(
8686
lines.append(f"{val:.2f}")
8787
if len(lines) == 5:
8888
raise exceptions.EmptyReportError()
89-
sect.append(report_nodes.Table(children=lines, cols=5, rheaders=1))
89+
sect.append(Table(children=lines, cols=5, rheaders=1))

pylint/reporters/__init__.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
2222

2323
"""utilities methods and classes for reporters"""
24-
24+
from typing import TYPE_CHECKING
2525

2626
from pylint import utils
2727
from pylint.reporters.base_reporter import BaseReporter
@@ -30,10 +30,13 @@
3030
from pylint.reporters.multi_reporter import MultiReporter
3131
from pylint.reporters.reports_handler_mix_in import ReportsHandlerMixIn
3232

33+
if TYPE_CHECKING:
34+
from pylint.lint.pylinter import PyLinter
35+
3336

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

3841

3942
__all__ = [

pylint/reporters/collecting_reporter.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ class CollectingReporter(BaseReporter):
88

99
name = "collector"
1010

11-
def __init__(self):
11+
def __init__(self) -> None:
1212
BaseReporter.__init__(self)
1313
self.messages = []
1414

15-
def reset(self):
15+
def reset(self) -> None:
1616
self.messages = []
1717

1818
_display = None

pylint/reporters/multi_reporter.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __init__(
4343

4444
self.set_output(output)
4545

46-
def __del__(self):
46+
def __del__(self) -> None:
4747
self.close_output_files()
4848

4949
@property

pylint/reporters/reports_handler_mix_in.py

+14-9
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
33

44
import collections
5-
from typing import TYPE_CHECKING, Any
5+
from typing import TYPE_CHECKING, Any, Callable, DefaultDict, Dict, List, Tuple
66

77
from pylint.exceptions import EmptyReportError
8+
from pylint.interfaces import IChecker
89
from pylint.reporters.ureports.nodes import Section
910
from pylint.typing import CheckerStats
1011

@@ -17,17 +18,21 @@ class ReportsHandlerMixIn:
1718
related methods for the main lint class
1819
"""
1920

20-
def __init__(self):
21-
self._reports = collections.defaultdict(list)
22-
self._reports_state = {}
21+
def __init__(self) -> None:
22+
self._reports: DefaultDict[
23+
IChecker, List[Tuple[str, str, Callable]]
24+
] = collections.defaultdict(list)
25+
self._reports_state: Dict[str, bool] = {}
2326

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

30-
def register_report(self, reportid, r_title, r_cb, checker):
33+
def register_report(
34+
self, reportid: str, r_title: str, r_cb: Callable, checker: IChecker
35+
) -> None:
3136
"""register a report
3237
3338
reportid is the unique identifier for the report
@@ -38,17 +43,17 @@ def register_report(self, reportid, r_title, r_cb, checker):
3843
reportid = reportid.upper()
3944
self._reports[checker].append((reportid, r_title, r_cb))
4045

41-
def enable_report(self, reportid):
46+
def enable_report(self, reportid: str) -> None:
4247
"""disable the report of the given id"""
4348
reportid = reportid.upper()
4449
self._reports_state[reportid] = True
4550

46-
def disable_report(self, reportid):
51+
def disable_report(self, reportid: str) -> None:
4752
"""disable the report of the given id"""
4853
reportid = reportid.upper()
4954
self._reports_state[reportid] = False
5055

51-
def report_is_enabled(self, reportid):
56+
def report_is_enabled(self, reportid: str) -> bool:
5257
"""return true if the report associated to the given identifier is
5358
enabled
5459
"""
@@ -58,7 +63,7 @@ def make_reports( # type: ignore # ReportsHandlerMixIn is always mixed with PyL
5863
self: "PyLinter",
5964
stats: CheckerStats,
6065
old_stats: CheckerStats,
61-
):
66+
) -> Section:
6267
"""render registered reports"""
6368
sect = Section("Report", f"{self.stats['statement']} statements analysed.")
6469
for checker in self.report_order():

pylint/reporters/ureports/base_writer.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@
1818
import os
1919
import sys
2020
from io import StringIO
21-
from typing import Iterator, TextIO
21+
from typing import TYPE_CHECKING, Iterator, List, TextIO, Union
22+
23+
if TYPE_CHECKING:
24+
from pylint.reporters.ureports.nodes import (
25+
EvaluationSection,
26+
Paragraph,
27+
Section,
28+
Table,
29+
)
2230

2331

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

42-
def format_children(self, layout):
50+
def format_children(
51+
self, layout: Union["EvaluationSection", "Paragraph", "Section"]
52+
) -> None:
4353
"""recurse on the layout children and call their accept method
4454
(see the Visitor pattern)
4555
"""
4656
for child in getattr(layout, "children", ()):
4757
child.accept(self)
4858

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

53-
def write(self, string):
63+
def write(self, string: str) -> None:
5464
"""write a string in the output buffer"""
5565
self.out.write(string)
5666

57-
def begin_format(self):
67+
def begin_format(self) -> None:
5868
"""begin to format a layout"""
5969
self.section = 0
6070

61-
def end_format(self):
71+
def end_format(self) -> None:
6272
"""finished to format a layout"""
6373

64-
def get_table_content(self, table):
74+
def get_table_content(self, table: "Table") -> List[List[str]]:
6575
"""trick to get table content without actually writing it
6676
6777
return an aligned list of lists containing table cells values as string
6878
"""
69-
result = [[]]
79+
result: List[List[str]] = [[]]
7080
cols = table.cols
7181
for cell in self.compute_content(table):
7282
if cols == 0:

pylint/reporters/ureports/nodes.py

+37-27
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@
1414
1515
A micro report is a tree of layout and content objects.
1616
"""
17-
from typing import Optional
17+
from typing import Any, Iterable, Iterator, List, Optional, Union
18+
19+
from pylint.reporters.ureports.text_writer import TextWriter
1820

1921

2022
class VNode:
21-
def __init__(self, nid=None):
22-
self.id = nid
23-
# navigation
24-
self.parent = None
25-
self.children = []
26-
self.visitor_name = self.__class__.__name__.lower()
27-
28-
def __iter__(self):
23+
def __init__(self) -> None:
24+
self.parent: Optional["BaseLayout"] = None
25+
self.children: List["VNode"] = []
26+
self.visitor_name: str = self.__class__.__name__.lower()
27+
28+
def __iter__(self) -> Iterator["VNode"]:
2929
return iter(self.children)
3030

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

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

47-
def __init__(self, children=(), **kwargs):
48-
super().__init__(**kwargs)
47+
def __init__(self, children: Iterable[Union["Text", str]] = ()) -> None:
48+
super().__init__()
4949
for child in children:
5050
if isinstance(child, VNode):
5151
self.append(child)
@@ -63,14 +63,14 @@ def insert(self, index: int, child: VNode) -> None:
6363
self.children.insert(index, child)
6464
child.parent = self
6565

66-
def parents(self):
66+
def parents(self) -> List["BaseLayout"]:
6767
"""return the ancestor nodes"""
6868
assert self.parent is not self
6969
if self.parent is None:
7070
return []
7171
return [self.parent] + self.parent.parents()
7272

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

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

88-
def __init__(self, data, escaped=True, **kwargs):
89-
super().__init__(**kwargs)
90-
# if isinstance(data, unicode):
91-
# data = data.encode('ascii')
92-
assert isinstance(data, str), data.__class__
88+
def __init__(self, data: str, escaped: bool = True) -> None:
89+
super().__init__()
9390
self.escaped = escaped
9491
self.data = data
9592

@@ -117,22 +114,28 @@ class Section(BaseLayout):
117114
as a first paragraph
118115
"""
119116

120-
def __init__(self, title=None, description=None, **kwargs):
121-
super().__init__(**kwargs)
117+
def __init__(
118+
self,
119+
title: Optional[str] = None,
120+
description: Optional[str] = None,
121+
children: Iterable[Union["Text", str]] = (),
122+
) -> None:
123+
super().__init__(children=children)
122124
if description:
123125
self.insert(0, Paragraph([Text(description)]))
124126
if title:
125127
self.insert(0, Title(children=(title,)))
126-
self.report_id: Optional[str] = None
128+
self.report_id: str = "" # Used in ReportHandlerMixin.make_reports
127129

128130

129131
class EvaluationSection(Section):
130-
def __init__(self, message, **kwargs):
131-
super().__init__(**kwargs)
132+
def __init__(
133+
self, message: str, children: Iterable[Union["Text", str]] = ()
134+
) -> None:
135+
super().__init__(children=children)
132136
title = Paragraph()
133137
title.append(Text("-" * len(message)))
134138
self.append(title)
135-
136139
message_body = Paragraph()
137140
message_body.append(Text(message))
138141
self.append(message_body)
@@ -169,8 +172,15 @@ class Table(BaseLayout):
169172
* title : the table's optional title
170173
"""
171174

172-
def __init__(self, cols, title=None, rheaders=0, cheaders=0, **kwargs):
173-
super().__init__(**kwargs)
175+
def __init__(
176+
self,
177+
cols: int,
178+
title: Optional[str] = None,
179+
rheaders: int = 0,
180+
cheaders: int = 0,
181+
children: Iterable[Union["Text", str]] = (),
182+
) -> None:
183+
super().__init__(children=children)
174184
assert isinstance(cols, int)
175185
self.cols = cols
176186
self.title = title

0 commit comments

Comments
 (0)