Files
Buffteks-Website/venv/lib/python3.12/site-packages/deptry/violations/dep002_unused/finder.py
2025-05-08 21:10:14 -05:00

72 lines
2.7 KiB
Python

from __future__ import annotations
import logging
from dataclasses import dataclass
from typing import TYPE_CHECKING
from deptry.imports.location import Location
from deptry.violations.base import ViolationsFinder
from deptry.violations.dep002_unused.violation import DEP002UnusedDependencyViolation
if TYPE_CHECKING:
from deptry.dependency import Dependency
from deptry.violations import Violation
@dataclass
class DEP002UnusedDependenciesFinder(ViolationsFinder):
"""
Finds unused dependencies by comparing a list of imported modules to a list of project dependencies.
A dependency is considered unused if none of the following conditions hold:
- A module with the exact name of the dependency is imported.
- Any of the top-level modules of the dependency are imported.
For example, 'matplotlib' has top-levels ['matplotlib', 'mpl_toolkits', 'pylab']. `mpl_toolkits` does not have
any associated metadata, but if this is imported the associated dependency `matplotlib` is not unused,
even if `matplotlib` itself is not imported anywhere.
"""
violation = DEP002UnusedDependencyViolation
def find(self) -> list[Violation]:
logging.debug("\nScanning for unused dependencies...")
unused_dependencies: list[Violation] = []
for dependency in self.dependencies:
logging.debug("Scanning module %s...", dependency.name)
if self._is_unused(dependency):
unused_dependencies.append(self.violation(dependency, Location(dependency.definition_file)))
return unused_dependencies
def _is_unused(self, dependency: Dependency) -> bool:
if self._dependency_found_in_imported_modules(dependency) or self._any_of_the_top_levels_imported(dependency):
return False
if dependency.name in self.ignored_modules:
logging.debug("Dependency '%s' found to be unused, but ignoring.", dependency.name)
return False
logging.debug("Dependency '%s' does not seem to be used.", dependency.name)
return True
def _dependency_found_in_imported_modules(self, dependency: Dependency) -> bool:
return any(
module_with_locations.module.package == dependency.name
for module_with_locations in self.imported_modules_with_locations
)
def _any_of_the_top_levels_imported(self, dependency: Dependency) -> bool:
if not dependency.top_levels:
return False
return any(
any(
module_with_locations.module.name == top_level
for module_with_locations in self.imported_modules_with_locations
)
for top_level in dependency.top_levels
)