Coverage for src/pytest_vulture/vulture/manager.py: 0.00%
49 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-22 10:23 +0100
« prev ^ index » next coverage.py v7.6.1, created at 2024-11-22 10:23 +0100
1"""Manages vulture."""
3import re
4from pathlib import Path
5from typing import (
6 List,
7 Optional,
8)
10from vulture import Vulture
11from vulture.core import Item
13from pytest_vulture.conf.reader import IniReader
14from pytest_vulture.setup_manager import SetupManager
15from pytest_vulture.vulture.comment import CommentFinder
18class VultureManager:
19 """The vulture manager for pytest."""
21 __root_dir: Path
22 _results: List[Item]
23 _config: IniReader
24 _setup_manager: SetupManager
25 _COMMENT_FINDER: CommentFinder = CommentFinder()
27 def __init__(self, root_dir: Path, config: IniReader) -> None:
28 """Type of root_dir can be py._path.local.LocalPath. It depends on the version of pytest."""
29 self.__root_dir = root_dir
30 self._config = config
31 self._results = []
32 self.__setup_manager = SetupManager(self._config)
34 def call(self) -> None:
35 """Call vulture on a folder
36 Example::
37 >>> import py
38 >>> config = IniReader(path_ini=Path("vulture.ini"), is_pyproject=False)
39 >>> config.read_ini()
40 >>> manager = VultureManager(Path("/tmp"), config)
41 >>> manager.call()
42 """
43 vulture_configuration = self._config.vulture_configuration
44 vulture = Vulture(
45 ignore_names=vulture_configuration.ignore_names,
46 ignore_decorators=vulture_configuration.ignore_decorators,
47 )
48 vulture.scavenge([str(self.__root_dir)], exclude=vulture_configuration.exclude)
49 self._results = [elem for elem in vulture.get_unused_code() if not self.__filter_results(elem)]
51 def get_file_errors(self, path: str) -> Optional[str]:
52 """Get file errors
53 Example::
54 >>> import py
55 >>> from pathlib import Path
56 >>> Path("/tmp/package").mkdir(exist_ok=True)
57 >>> Path("/tmp/package/test.py").write_text("def test():pass")
58 15
59 >>> config = IniReader(path_ini=Path("vulture.ini"))
60 >>> config.read_ini()
61 >>> manager = VultureManager(Path("/tmp/package"), config)
62 >>> manager.call()
63 >>> manager.get_file_errors(Path("/tmp/package/test.py"))
64 "line 1 : unused function 'test'"
65 """
66 errors = []
67 for error_vulture in self._results:
68 if self.__path_equals(path, error_vulture.filename.as_posix(), str(self.__root_dir)):
69 errors.append(f"line {error_vulture.first_lineno} : {error_vulture.message}") # noqa: PERF401
70 if not errors:
71 return None
72 return "\n".join(errors)
74 def __filter_results(self, vulture_output: Item) -> bool:
75 """Check if the vulture output concerns an ignore path, an entry point or a # vulture: ignore."""
76 for ignored_path in self._config.vulture_configuration.ignore:
77 if self.__check_path(ignored_path, vulture_output.filename):
78 return True
79 return (
80 self.__setup_manager.is_entry_point(vulture_output)
81 or self.__check_ignore_type(vulture_output)
82 or self._COMMENT_FINDER.check_comment(vulture_output)
83 )
85 def __check_path(self, path_exclude: str, path_to_check: Path) -> bool:
86 match = re.compile(path_exclude.replace("*", ".*")).match(path_to_check.as_posix()) or re.compile(
87 str(self.__root_dir / path_exclude).replace("*", ".*")
88 ).match(path_to_check.as_posix())
89 if not match:
90 return self.__path_equals(path_exclude, path_to_check.absolute().as_posix(), str(self.__root_dir))
91 return match.group() == path_to_check.as_posix()
93 def __check_ignore_type(self, vulture_output: Item) -> bool:
94 return vulture_output.typ in self._config.vulture_configuration.ignore_types
96 @classmethod
97 def __path_equals(cls, path_1: str, path_2: str, root_dir: str) -> bool:
98 """Manage tox and pytest weird path usages, to simplify."""
99 path_1_full = (Path(root_dir) / Path(str(path_1))).as_posix()
100 path_2_full = (Path(root_dir) / Path(str(path_2))).as_posix()
101 return path_1_full == path_2_full