diff options
author | Andreas Finkler <3929834+DudeNr33@users.noreply.github.com> | 2022-05-15 08:07:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-15 08:07:36 +0200 |
commit | c6d5cfef4f5359dea1e2558c18e6792d6d726edf (patch) | |
tree | 7e545faab8ea641a648a682516386cc0fdb16bb9 | |
parent | e72fe660f9b4bcd8f8910998dc93c7989d9f8872 (diff) | |
download | pylint-git-c6d5cfef4f5359dea1e2558c18e6792d6d726edf.tar.gz |
Add typing to `pylint.pyreverse.inspector` (#6614)
* Add typing to `pylint.pyreverse.inspector`
* Import `Callable` from `typing` to fix compatibility with Python 3.7 and 3.8
* Fix return type of `interfaces` function
-rw-r--r-- | pylint/pyreverse/inspector.py | 67 | ||||
-rw-r--r-- | pylint/pyreverse/writer.py | 9 |
2 files changed, 49 insertions, 27 deletions
diff --git a/pylint/pyreverse/inspector.py b/pylint/pyreverse/inspector.py index 56d7599cd..afd55c0a6 100644 --- a/pylint/pyreverse/inspector.py +++ b/pylint/pyreverse/inspector.py @@ -6,22 +6,31 @@ Try to resolve definitions (namespace) dictionary, relationship... """ + +from __future__ import annotations + import collections import os import traceback +from collections.abc import Generator +from typing import Any, Callable, Optional import astroid from astroid import nodes from pylint.pyreverse import utils +_WrapperFuncT = Callable[[Callable[[str], nodes.Module], str], Optional[nodes.Module]] + -def _iface_hdlr(_): +def _iface_hdlr(_: nodes.NodeNG | Any) -> bool: """Handler used by interfaces to handle suspicious interface nodes.""" return True -def _astroid_wrapper(func, modname): +def _astroid_wrapper( + func: Callable[[str], nodes.Module], modname: str +) -> nodes.Module | None: print(f"parsing {modname}...") try: return func(modname) @@ -32,7 +41,11 @@ def _astroid_wrapper(func, modname): return None -def interfaces(node, herited=True, handler_func=_iface_hdlr): +def interfaces( + node: nodes.ClassDef, + herited: bool = True, + handler_func: Callable[[nodes.NodeNG | Any], bool] = _iface_hdlr, +) -> Generator[Any, None, None]: """Return an iterator on interfaces implemented by the given class node.""" try: implements = astroid.bases.Instance(node).getattr("__implements__")[0] @@ -56,14 +69,14 @@ def interfaces(node, herited=True, handler_func=_iface_hdlr): class IdGeneratorMixIn: """Mixin adding the ability to generate integer uid.""" - def __init__(self, start_value=0): + def __init__(self, start_value: int = 0) -> None: self.id_count = start_value - def init_counter(self, start_value=0): + def init_counter(self, start_value: int = 0) -> None: """Init the id counter.""" self.id_count = start_value - def generate_id(self): + def generate_id(self) -> int: """Generate a new identifier.""" self.id_count += 1 return self.id_count @@ -72,29 +85,29 @@ class IdGeneratorMixIn: class Project: """A project handle a set of modules / packages.""" - def __init__(self, name=""): + def __init__(self, name: str = ""): self.name = name - self.uid = None - self.path = None - self.modules = [] - self.locals = {} + self.uid: int | None = None + self.path: str = "" + self.modules: list[nodes.Module] = [] + self.locals: dict[str, nodes.Module] = {} self.__getitem__ = self.locals.__getitem__ self.__iter__ = self.locals.__iter__ self.values = self.locals.values self.keys = self.locals.keys self.items = self.locals.items - def add_module(self, node): + def add_module(self, node: nodes.Module) -> None: self.locals[node.name] = node self.modules.append(node) - def get_module(self, name): + def get_module(self, name: str) -> nodes.Module: return self.locals[name] - def get_children(self): + def get_children(self) -> list[nodes.Module]: return self.modules - def __repr__(self): + def __repr__(self) -> str: return f"<Project {self.name!r} at {id(self)} ({len(self.modules)} modules)>" @@ -121,7 +134,9 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): list of implemented interface _objects_ (only on astroid.Class nodes) """ - def __init__(self, project, inherited_interfaces=0, tag=False): + def __init__( + self, project: Project, inherited_interfaces: bool = False, tag: bool = False + ) -> None: IdGeneratorMixIn.__init__(self) utils.LocalsVisitor.__init__(self) # take inherited interface in consideration or not @@ -180,7 +195,8 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): self.handle_assignattr_type(assignattr, node) # resolve implemented interface try: - node.implements = list(interfaces(node, self.inherited_interfaces)) + ifaces = interfaces(node, self.inherited_interfaces) + node.implements = list(ifaces) if ifaces is not None else [] except astroid.InferenceError: node.implements = [] @@ -232,7 +248,7 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): frame.locals_type[node.name] = list(set(current) | utils.infer_node(node)) @staticmethod - def handle_assignattr_type(node, parent): + def handle_assignattr_type(node: nodes.AssignAttr, parent: nodes.ClassDef) -> None: """Handle an astroid.assignattr node. handle instance_attrs_type @@ -276,7 +292,7 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): if fullname != basename: self._imported_module(node, fullname, relative) - def compute_module(self, context_name, mod_path): + def compute_module(self, context_name: str, mod_path: str) -> int: """Return true if the module should be added to dependencies.""" package_dir = os.path.dirname(self.project.path) if context_name == mod_path: @@ -285,7 +301,9 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): return 1 return 0 - def _imported_module(self, node, mod_path, relative): + def _imported_module( + self, node: nodes.Import | nodes.ImportFrom, mod_path: str, relative: bool + ) -> None: """Notify an imported module, used to analyze dependencies.""" module = node.root() context_name = module.name @@ -301,11 +319,14 @@ class Linker(IdGeneratorMixIn, utils.LocalsVisitor): def project_from_files( - files, func_wrapper=_astroid_wrapper, project_name="no name", black_list=("CVS",) -): + files: list[str], + func_wrapper: _WrapperFuncT = _astroid_wrapper, + project_name: str = "no name", + black_list: tuple[str, ...] = ("CVS",), +) -> Project: """Return a Project from a list of files or modules.""" # build the project representation - astroid_manager = astroid.manager.AstroidManager() + astroid_manager = astroid.MANAGER project = Project(project_name) for something in files: if not os.path.exists(something): diff --git a/pylint/pyreverse/writer.py b/pylint/pyreverse/writer.py index 91229dc03..12a76df9b 100644 --- a/pylint/pyreverse/writer.py +++ b/pylint/pyreverse/writer.py @@ -9,6 +9,7 @@ from __future__ import annotations import argparse import itertools import os +from collections.abc import Iterable from astroid import modutils, nodes @@ -56,7 +57,7 @@ class DiagramWriter: ) self.used_colors: dict[str, str] = {} - def write(self, diadefs): + def write(self, diadefs: Iterable[ClassDiagram | PackageDiagram]) -> None: """Write files for <project> according to <diadefs>.""" for diagram in diadefs: basename = diagram.title.strip().replace(" ", "_") @@ -64,10 +65,10 @@ class DiagramWriter: if os.path.exists(self.config.output_directory): file_name = os.path.join(self.config.output_directory, file_name) self.set_printer(file_name, basename) - if diagram.TYPE == "class": - self.write_classes(diagram) - else: + if isinstance(diagram, PackageDiagram): self.write_packages(diagram) + else: + self.write_classes(diagram) self.save() def write_packages(self, diagram: PackageDiagram) -> None: |