Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imports with package names different from module names are wrongly reported as missing instead of transitive #827

Open
Willa1228 opened this issue Aug 21, 2024 · 2 comments · May be fixed by #854
Assignees
Labels
bug Something isn't working

Comments

@Willa1228
Copy link

Environment

  • deptry version: 0.16.1
  • Python version: 3.11
  • Operating system (e.g. Ubuntu 22.04, Windows 11): Mac OS 14.0

Describe the issue

I have a project which has django-cms in its requirements.txt, and I import those packages depend on django-cms like django-classy-tags, django-formtools... those should be detected as a transitive dependency, but it seems deptry can't recognize those with a - packages's name, so it turns out detected as a missing dependency.

Minimal way to reproduce the issue

  1. Have a new project with django-cms in the requirements, and install in a conda environment
  2. In project
    import classytags
    from formtools.wizard.views import WizardView
    import sekizai
    from treebeard.mp_tree import MP_Node
    from packaging import version
  3. python -m deptry .

those with - will be detected as DEP001 incorrectly, but without dash's package can be detected as transitive successfully.

@Willa1228 Willa1228 added the bug Something isn't working label Aug 21, 2024
@mkniewallner
Copy link
Collaborator

Thanks for the report, the issue is not exactly about having - (we even have a fallback mechanism for this specific case since it's so common). It actually happens whenever the package name and the module name are different. For instance, it's also possible to reproduce with the following requirements.txt:

itchiodl==2.3.0

and the following Python file:

import bs4
import itchiodl

(itchiodl depends on beautifulsoup4, which is imported as bs4)

Then if we run deptry .:

$ deptry .
Scanning 1 file...

foo.py:1:8: DEP001 'bs4' imported but missing from the dependency definitions
Found 1 dependency issue.

The issue is that we currently try to guess the Python module names for each package by only taking into account the direct dependencies (defined for instance in requirements.txt, or in pyproject.toml).

In order to handle this case properly, we'd need to be able to apply the reverse logic, i.e. after we parse all imports in the codebase, we guess the Python package from the module names. We'll need to check if it's possible to do easily without breaking the current logic.

@mkniewallner mkniewallner self-assigned this Aug 29, 2024
@mkniewallner mkniewallner changed the title If there's a - in package name it can't be detect as a transitive dependency correctly Imports with package names different from module names are wrongly reported as missing instead of transitive Aug 29, 2024
@mkniewallner mkniewallner linked a pull request Sep 12, 2024 that will close this issue
@Willa1228
Copy link
Author

Hi ,
I noticed that if a package name is present, it can be detected as a transitive dependency. This got me thinking that perhaps it could simply check whether a module with the same name as the import exists. For example, if we have django-cms in our requirements and we import classytags, but can't find its metadata (since the metadata is under django-classy-tags), we could just check if there’s a module called classytags and return classytags as the package name.
These are just some ideas I not sure it's workable or not realistic, and I saw you have work on this issue, hope this won't bother you. Thank you very much!

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 = metadata(self.name)["Name"]
    except PackageNotFoundError:
        name = self.is_package_installed(self.name)
        if name:
            return name
        return None
    else:
        return name

def is_package_installed(self, package_name: str):
    if importlib.util.find_spec(package_name):
        return package_name
    return None`

@mkniewallner mkniewallner added this to the 0.21.0 milestone Oct 22, 2024
@mkniewallner mkniewallner removed this from the 0.21.0 milestone Nov 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants