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

1"""Manages vulture.""" 

2 

3import re 

4from pathlib import Path 

5from typing import ( 

6 List, 

7 Optional, 

8) 

9 

10from vulture import Vulture 

11from vulture.core import Item 

12 

13from pytest_vulture.conf.reader import IniReader 

14from pytest_vulture.setup_manager import SetupManager 

15from pytest_vulture.vulture.comment import CommentFinder 

16 

17 

18class VultureManager: 

19 """The vulture manager for pytest.""" 

20 

21 __root_dir: Path 

22 _results: List[Item] 

23 _config: IniReader 

24 _setup_manager: SetupManager 

25 _COMMENT_FINDER: CommentFinder = CommentFinder() 

26 

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) 

33 

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)] 

50 

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) 

73 

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 ) 

84 

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() 

92 

93 def __check_ignore_type(self, vulture_output: Item) -> bool: 

94 return vulture_output.typ in self._config.vulture_configuration.ignore_types 

95 

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