Mini Shell
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
from __future__ import annotations
from typing import Literal, TypedDict, cast
from pylint.typing import MessageTypesFullName
class BadNames(TypedDict):
"""TypedDict to store counts of node types with bad names."""
argument: int
attr: int
klass: int
class_attribute: int
class_const: int
const: int
inlinevar: int
function: int
method: int
module: int
variable: int
typevar: int
typealias: int
class CodeTypeCount(TypedDict):
"""TypedDict to store counts of lines of code types."""
code: int
comment: int
docstring: int
empty: int
total: int
class DuplicatedLines(TypedDict):
"""TypedDict to store counts of lines of duplicated code."""
nb_duplicated_lines: int
percent_duplicated_lines: float
class NodeCount(TypedDict):
"""TypedDict to store counts of different types of nodes."""
function: int
klass: int
method: int
module: int
class UndocumentedNodes(TypedDict):
"""TypedDict to store counts of undocumented node types."""
function: int
klass: int
method: int
module: int
class ModuleStats(TypedDict):
"""TypedDict to store counts of types of messages and statements."""
convention: int
error: int
fatal: int
info: int
refactor: int
statement: int
warning: int
# pylint: disable-next=too-many-instance-attributes
class LinterStats:
"""Class used to linter stats."""
def __init__(
self,
bad_names: BadNames | None = None,
by_module: dict[str, ModuleStats] | None = None,
by_msg: dict[str, int] | None = None,
code_type_count: CodeTypeCount | None = None,
dependencies: dict[str, set[str]] | None = None,
duplicated_lines: DuplicatedLines | None = None,
node_count: NodeCount | None = None,
undocumented: UndocumentedNodes | None = None,
) -> None:
self.bad_names = bad_names or BadNames(
argument=0,
attr=0,
klass=0,
class_attribute=0,
class_const=0,
const=0,
inlinevar=0,
function=0,
method=0,
module=0,
variable=0,
typevar=0,
typealias=0,
)
self.by_module: dict[str, ModuleStats] = by_module or {}
self.by_msg: dict[str, int] = by_msg or {}
self.code_type_count = code_type_count or CodeTypeCount(
code=0, comment=0, docstring=0, empty=0, total=0
)
self.dependencies: dict[str, set[str]] = dependencies or {}
self.duplicated_lines = duplicated_lines or DuplicatedLines(
nb_duplicated_lines=0, percent_duplicated_lines=0.0
)
self.node_count = node_count or NodeCount(
function=0, klass=0, method=0, module=0
)
self.undocumented = undocumented or UndocumentedNodes(
function=0, klass=0, method=0, module=0
)
self.convention = 0
self.error = 0
self.fatal = 0
self.info = 0
self.refactor = 0
self.statement = 0
self.warning = 0
self.global_note = 0
self.nb_duplicated_lines = 0
self.percent_duplicated_lines = 0.0
def __repr__(self) -> str:
return str(self)
def __str__(self) -> str:
return f"""{self.bad_names}
{sorted(self.by_module.items())}
{sorted(self.by_msg.items())}
{self.code_type_count}
{sorted(self.dependencies.items())}
{self.duplicated_lines}
{self.undocumented}
{self.convention}
{self.error}
{self.fatal}
{self.info}
{self.refactor}
{self.statement}
{self.warning}
{self.global_note}
{self.nb_duplicated_lines}
{self.percent_duplicated_lines}"""
def init_single_module(self, module_name: str) -> None:
"""Use through PyLinter.set_current_module so PyLinter.current_name is
consistent.
"""
self.by_module[module_name] = ModuleStats(
convention=0, error=0, fatal=0, info=0, refactor=0, statement=0, warning=0
)
def get_bad_names(
self,
node_name: Literal[
"argument",
"attr",
"class",
"class_attribute",
"class_const",
"const",
"inlinevar",
"function",
"method",
"module",
"variable",
"typevar",
"typealias",
],
) -> int:
"""Get a bad names node count."""
if node_name == "class":
return self.bad_names.get("klass", 0)
return self.bad_names.get(node_name, 0)
def increase_bad_name(self, node_name: str, increase: int) -> None:
"""Increase a bad names node count."""
if node_name not in {
"argument",
"attr",
"class",
"class_attribute",
"class_const",
"const",
"inlinevar",
"function",
"method",
"module",
"variable",
"typevar",
"typealias",
}:
raise ValueError("Node type not part of the bad_names stat")
node_name = cast(
Literal[
"argument",
"attr",
"class",
"class_attribute",
"class_const",
"const",
"inlinevar",
"function",
"method",
"module",
"variable",
"typevar",
"typealias",
],
node_name,
)
if node_name == "class":
self.bad_names["klass"] += increase
else:
self.bad_names[node_name] += increase
def reset_bad_names(self) -> None:
"""Resets the bad_names attribute."""
self.bad_names = BadNames(
argument=0,
attr=0,
klass=0,
class_attribute=0,
class_const=0,
const=0,
inlinevar=0,
function=0,
method=0,
module=0,
variable=0,
typevar=0,
typealias=0,
)
def get_code_count(
self, type_name: Literal["code", "comment", "docstring", "empty", "total"]
) -> int:
"""Get a code type count."""
return self.code_type_count.get(type_name, 0)
def reset_code_count(self) -> None:
"""Resets the code_type_count attribute."""
self.code_type_count = CodeTypeCount(
code=0, comment=0, docstring=0, empty=0, total=0
)
def reset_duplicated_lines(self) -> None:
"""Resets the duplicated_lines attribute."""
self.duplicated_lines = DuplicatedLines(
nb_duplicated_lines=0, percent_duplicated_lines=0.0
)
def get_node_count(
self, node_name: Literal["function", "class", "method", "module"]
) -> int:
"""Get a node count while handling some extra conditions."""
if node_name == "class":
return self.node_count.get("klass", 0)
return self.node_count.get(node_name, 0)
def reset_node_count(self) -> None:
"""Resets the node count attribute."""
self.node_count = NodeCount(function=0, klass=0, method=0, module=0)
def get_undocumented(
self, node_name: Literal["function", "class", "method", "module"]
) -> float:
"""Get a undocumented node count."""
if node_name == "class":
return self.undocumented["klass"]
return self.undocumented[node_name]
def reset_undocumented(self) -> None:
"""Resets the undocumented attribute."""
self.undocumented = UndocumentedNodes(function=0, klass=0, method=0, module=0)
def get_global_message_count(self, type_name: str) -> int:
"""Get a global message count."""
return getattr(self, type_name, 0)
def get_module_message_count(
self, modname: str, type_name: MessageTypesFullName
) -> int:
"""Get a module message count."""
return self.by_module[modname].get(type_name, 0)
def increase_single_message_count(self, type_name: str, increase: int) -> None:
"""Increase the message type count of an individual message type."""
setattr(self, type_name, getattr(self, type_name) + increase)
def increase_single_module_message_count(
self, modname: str, type_name: MessageTypesFullName, increase: int
) -> None:
"""Increase the message type count of an individual message type of a
module.
"""
self.by_module[modname][type_name] += increase
def reset_message_count(self) -> None:
"""Resets the message type count of the stats object."""
self.convention = 0
self.error = 0
self.fatal = 0
self.info = 0
self.refactor = 0
self.warning = 0
def merge_stats(stats: list[LinterStats]) -> LinterStats:
"""Used to merge multiple stats objects into a new one when pylint is run in
parallel mode.
"""
merged = LinterStats()
for stat in stats:
merged.bad_names["argument"] += stat.bad_names["argument"]
merged.bad_names["attr"] += stat.bad_names["attr"]
merged.bad_names["klass"] += stat.bad_names["klass"]
merged.bad_names["class_attribute"] += stat.bad_names["class_attribute"]
merged.bad_names["class_const"] += stat.bad_names["class_const"]
merged.bad_names["const"] += stat.bad_names["const"]
merged.bad_names["inlinevar"] += stat.bad_names["inlinevar"]
merged.bad_names["function"] += stat.bad_names["function"]
merged.bad_names["method"] += stat.bad_names["method"]
merged.bad_names["module"] += stat.bad_names["module"]
merged.bad_names["variable"] += stat.bad_names["variable"]
merged.bad_names["typevar"] += stat.bad_names["typevar"]
merged.bad_names["typealias"] += stat.bad_names["typealias"]
for mod_key, mod_value in stat.by_module.items():
merged.by_module[mod_key] = mod_value
for msg_key, msg_value in stat.by_msg.items():
try:
merged.by_msg[msg_key] += msg_value
except KeyError:
merged.by_msg[msg_key] = msg_value
merged.code_type_count["code"] += stat.code_type_count["code"]
merged.code_type_count["comment"] += stat.code_type_count["comment"]
merged.code_type_count["docstring"] += stat.code_type_count["docstring"]
merged.code_type_count["empty"] += stat.code_type_count["empty"]
merged.code_type_count["total"] += stat.code_type_count["total"]
for dep_key, dep_value in stat.dependencies.items():
try:
merged.dependencies[dep_key].update(dep_value)
except KeyError:
merged.dependencies[dep_key] = dep_value
merged.duplicated_lines["nb_duplicated_lines"] += stat.duplicated_lines[
"nb_duplicated_lines"
]
merged.duplicated_lines["percent_duplicated_lines"] += stat.duplicated_lines[
"percent_duplicated_lines"
]
merged.node_count["function"] += stat.node_count["function"]
merged.node_count["klass"] += stat.node_count["klass"]
merged.node_count["method"] += stat.node_count["method"]
merged.node_count["module"] += stat.node_count["module"]
merged.undocumented["function"] += stat.undocumented["function"]
merged.undocumented["klass"] += stat.undocumented["klass"]
merged.undocumented["method"] += stat.undocumented["method"]
merged.undocumented["module"] += stat.undocumented["module"]
merged.convention += stat.convention
merged.error += stat.error
merged.fatal += stat.fatal
merged.info += stat.info
merged.refactor += stat.refactor
merged.statement += stat.statement
merged.warning += stat.warning
merged.global_note += stat.global_note
return merged
Zerion Mini Shell 1.0