Skip to content

Commit

Permalink
feat(module): use packages_distributions
Browse files Browse the repository at this point in the history
  • Loading branch information
mkniewallner committed Sep 12, 2024
1 parent 939b9de commit 4d229ae
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 37 deletions.
41 changes: 21 additions & 20 deletions python/deptry/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Module:
name: The name of the imported module.
standard_library: Whether the module is part of the Python standard library.
local_module: Whether the module is a local module.
package: The name of the package that contains the module.
packages: The names of the packages that contain the module.
top_levels: A list of dependencies that contain this module in their top-level module
names. This can be multiple, e.g. `google-cloud-api` and `google-cloud-bigquery` both have
`google` in their top-level module names.
Expand All @@ -33,7 +33,7 @@ class Module:
name: str
standard_library: bool = False
local_module: bool = False
package: str | None = None
packages: list[str] | None = None
top_levels: list[str] | None = None
dev_top_levels: list[str] | None = None
is_provided_by_dependency: bool | None = None
Expand Down Expand Up @@ -97,31 +97,24 @@ def build(self) -> Module:
if self._is_local_module():
return Module(self.name, local_module=True)

package = self._get_package_name_from_metadata()
packages = self._get_package_names_from_metadata()
top_levels = self._get_corresponding_top_levels_from(self.dependencies)
dev_top_levels = self._get_corresponding_top_levels_from(self.dev_dependencies)

is_provided_by_dependency = self._has_matching_dependency(package, top_levels)
is_provided_by_dev_dependency = self._has_matching_dev_dependency(package, dev_top_levels)
is_provided_by_dependency = self._has_matching_dependency(packages, top_levels)
is_provided_by_dev_dependency = self._has_matching_dev_dependency(packages, dev_top_levels)

return Module(
self.name,
package=package,
packages=packages,
top_levels=top_levels,
dev_top_levels=dev_top_levels,
is_provided_by_dependency=is_provided_by_dependency,
is_provided_by_dev_dependency=is_provided_by_dev_dependency,
)

def _get_package_name_from_metadata(self) -> str | None:
"""
Most packages simply have a field called "Name" in their metadata. This method extracts that field.
"""
try:
name: str = importlib_metadata.metadata(self.name)["Name"]
except importlib_metadata.PackageNotFoundError:
return None
else:
return name
def _get_package_names_from_metadata(self) -> list[str] | None:
return importlib_metadata.packages_distributions().get(self.name)

def _get_corresponding_top_levels_from(self, dependencies: list[Dependency]) -> list[str]:
"""
Expand All @@ -146,15 +139,23 @@ def _is_local_module(self) -> bool:
"""
return self.name in self.local_modules

def _has_matching_dependency(self, package: str | None, top_levels: list[str]) -> bool:
def _has_matching_dependency(self, packages: list[str] | None, top_levels: list[str]) -> bool:
"""
Check if this module is provided by a listed dependency. This is the case if either the package name that was
found in the metadata is listed as a dependency, or if we found a top-level module name match earlier.
"""
return package and (package in [dep.name for dep in self.dependencies]) or len(top_levels) > 0
if not packages:
return False

def _has_matching_dev_dependency(self, package: str | None, dev_top_levels: list[str]) -> bool:
return any(package in [dep.name for dep in self.dependencies] or len(top_levels) > 0 for package in packages)

def _has_matching_dev_dependency(self, packages: list[str] | None, dev_top_levels: list[str]) -> bool:
"""
Same as _has_matching_dependency, but for development dependencies.
"""
return package and (package in [dep.name for dep in self.dev_dependencies]) or len(dev_top_levels) > 0
if not packages:
return False

return any(
package in [dep.name for dep in self.dev_dependencies] or len(dev_top_levels) > 0 for package in packages
)
2 changes: 1 addition & 1 deletion python/deptry/violations/dep001_missing/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def find(self) -> list[Violation]:

def _is_missing(self, module: Module) -> bool:
if any([
module.package is not None,
module.packages is not None,
module.is_provided_by_dependency,
module.is_provided_by_dev_dependency,
module.local_module,
Expand Down
10 changes: 6 additions & 4 deletions python/deptry/violations/dep002_unused/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ def _is_unused(self, dependency: Dependency) -> bool:
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
)
for module_with_locations in self.imported_modules_with_locations:
if module_with_locations.module.packages:
for package in module_with_locations.module.packages:
if package == dependency.name:
return True
return False

def _any_of_the_top_levels_imported(self, dependency: Dependency) -> bool:
if not dependency.top_levels:
Expand Down
6 changes: 3 additions & 3 deletions python/deptry/violations/dep003_transitive/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ def find(self) -> list[Violation]:

def _is_transitive(self, module: Module) -> bool:
if any([
module.package is None,
module.packages is None,
module.is_provided_by_dependency,
module.is_provided_by_dev_dependency,
module.local_module,
]):
return False

if module.name in self.ignored_modules:
logging.debug("Dependency '%s' found to be a transitive dependency, but ignoring.", module.package)
logging.debug("Dependency '%s' found to be a transitive dependency, but ignoring.", module.packages)
return False

logging.debug("Dependency '%s' marked as a transitive dependency.", module.package)
logging.debug("Dependency '%s' marked as a transitive dependency.", module.packages)
return True
18 changes: 9 additions & 9 deletions python/deptry/violations/dep004_misplaced_dev/finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ def find(self) -> list[Violation]:
continue

logging.debug("Scanning module %s...", module.name)
corresponding_package_name = self._get_package_name(module)
corresponding_package_names = self._get_package_names(module)

if corresponding_package_name and self._is_development_dependency(module, corresponding_package_name):
if corresponding_package_names and self._is_development_dependency(module, corresponding_package_names):
for location in module_with_locations.locations:
misplaced_dev_dependencies.append(self.violation(module, location))

return misplaced_dev_dependencies

def _is_development_dependency(self, module: Module, corresponding_package_name: str) -> bool:
def _is_development_dependency(self, module: Module, corresponding_package_names: list[str]) -> bool:
# Module can be provided both by a regular and by a development dependency.
# Only continue if module is ONLY provided by a dev dependency.
if not module.is_provided_by_dev_dependency or module.is_provided_by_dependency:
Expand All @@ -57,16 +57,16 @@ def _is_development_dependency(self, module: Module, corresponding_package_name:
if module.name in self.ignored_modules:
logging.debug(
"Dependency '%s' found to be a misplaced development dependency, but ignoring.",
corresponding_package_name,
corresponding_package_names,
)
return False

logging.debug("Dependency '%s' marked as a misplaced development dependency.", corresponding_package_name)
logging.debug("Dependency '%s' marked as a misplaced development dependency.", corresponding_package_names)
return True

def _get_package_name(self, module: Module) -> str | None:
if module.package:
return module.package
def _get_package_names(self, module: Module) -> list[str] | None:
if module.packages:
return module.packages
if module.dev_top_levels:
if len(module.dev_top_levels) > 1:
logging.debug(
Expand All @@ -79,5 +79,5 @@ def _get_package_name(self, module: Module) -> str | None:
module.name,
)
else:
return module.dev_top_levels[0]
return module.dev_top_levels
return None

0 comments on commit 4d229ae

Please sign in to comment.