Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codecov.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ ignore:
project:
default:
target: auto
threshold: 0%
threshold: .5%
7 changes: 5 additions & 2 deletions deptry/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ def run(self) -> Dict:
imported_modules = [ModuleBuilder(mod, dependencies, dev_dependencies).build() for mod in imported_modules]
imported_modules = [mod for mod in imported_modules if not mod.standard_library]

issues = self._find_issues(imported_modules, dependencies)
issues = self._find_issues(imported_modules, dependencies, dev_dependencies)
ResultLogger(issues=issues).log_and_exit()

def _find_issues(self, imported_modules: List[Module], dependencies: List[Dependency]):
def _find_issues(
self, imported_modules: List[Module], dependencies: List[Dependency], dev_dependencies: List[Dependency]
):
result = {}
if not self.skip_obsolete:
result["obsolete"] = ObsoleteDependenciesFinder(
Expand All @@ -83,6 +85,7 @@ def _find_issues(self, imported_modules: List[Module], dependencies: List[Depend
result["misplaced_dev"] = MisplacedDevDependenciesFinder(
imported_modules=imported_modules,
dependencies=dependencies,
dev_dependencies=dev_dependencies,
ignore_misplaced_dev=self.ignore_misplaced_dev,
).find()
return result
Expand Down
46 changes: 38 additions & 8 deletions deptry/issue_finders/misplaced_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,58 @@ class MisplacedDevDependenciesFinder:
"""

def __init__(
self, imported_modules: List[Module], dependencies: List[Dependency], ignore_misplaced_dev: List[str] = []
self,
imported_modules: List[Module],
dependencies: List[Dependency],
dev_dependencies: List[Dependency],
ignore_misplaced_dev: List[str] = [],
) -> None:
self.imported_modules = imported_modules
self.dependencies = dependencies
self.dev_dependencies = dev_dependencies
self.ignore_misplaced_dev = ignore_misplaced_dev

def find(self) -> List[str]:
"""
In this function, we use 'corresponding_package_name' instead of module.package, since it can happen that a
development dependency is not installed, but it's still found to be used in the codebase, due to simple name matching.
In that case, it's added under module.dev_top_levels. _get_package_name is added for these edge-cases.
"""
logging.debug("\nScanning for incorrect development dependencies...")
dev_dependencies = []
misplaced_dev_dependencies = []
for module in self.imported_modules:
logging.debug(f"Scanning module {module.name}...")
if self._is_development_dependency(module):
dev_dependencies.append(module.package)
return dev_dependencies
corresponding_package_name = self._get_package_name(module)
if corresponding_package_name:
if self._is_development_dependency(module, corresponding_package_name):
misplaced_dev_dependencies.append(corresponding_package_name)
return misplaced_dev_dependencies

def _is_development_dependency(self, module: Module) -> bool:
def _is_development_dependency(self, module: Module, corresponding_package_name: str) -> bool:
if module.is_dev_dependency:
if module.name in self.ignore_misplaced_dev:
logging.debug(
f"Module '{module.package}' found to be a misplaced development dependency, but ignoring."
f"Module '{corresponding_package_name}' found to be a misplaced development dependency, but ignoring."
)
else:
logging.debug(f"Dependency '{module.package}' marked as a misplaced development dependency.")
logging.debug(
f"Dependency '{corresponding_package_name}' marked as a misplaced development dependency."
)
return True
return False

def _get_package_name(self, module: Module):
if module.package:
return module.package
if module.dev_top_levels:
if len(module.dev_top_levels) > 1:
logging.debug(
f"Module {module.name} is found in the top-level module names of multiple development dependencies. Skipping."
)
elif len(module.dev_top_levels) == 0:
logging.debug(
f"Module {module.name} has no metadata and it is not found in any top-level module names. Skipping."
)
else:
return module.dev_top_levels[0]
return None
12 changes: 12 additions & 0 deletions tests/test_missing_dependencies_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@ def test_simple_with_ignore():
imported_modules=modules, dependencies=dependencies, ignore_missing=["foobar"]
).find()
assert len(deps) == 0


def test_no_error():
"""
This should run without an error, even though `foo` is not installed.
"""

dep = Dependency("foo")
module = ModuleBuilder("foo", [dep]).build()

deps = MissingDependenciesFinder(imported_modules=[module], dependencies=[dep]).find()
assert len(deps) == 0