seddonym / import-linter

Import Linter allows you to define and enforce rules for the internal and external imports within your Python project.
https://import-linter.readthedocs.io/
BSD 2-Clause "Simplified" License
664 stars 45 forks source link

Query about forbidden contracts and direct imports #193

Open seddonym opened 1 year ago

seddonym commented 1 year ago

Opening on behalf of @pwalsh (originally posted in different ticket).

Original post

With (snippets from pyproject.toml):

[tool.importlinter]
root_packages = ["survey", "api", "django"]
include_external_packages = true

[[tool.importlinter.contracts]]
name = "Dont use cache dependencies directly"
type = "forbidden"
source_modules = ["survey", "api"]
forbidden_modules = ["django.core.cache"]

I would expect django.core.cache to be forbidden, but, I get a huge list of import errors as any import under django.* is listed as an error.

If I change root_packages to either

root_packages = ["survey", "api", "django.core"]
#
root_packages = ["survey", "api", "django.core.cache"]

then no linting errors related to the Django package are detected.

I'd like to, for example, prevent usage of anything under django.core.cache by raising lint errors. is this possible some other way?

seddonym commented 1 year ago

I get a huge list of import errors as any import under django.* is listed as an error.

Is it possible that the problem might be because a lot of django modules indirectly depend on django.core.cache?

For example, on a sample project I set up, I included an import of django.db.models in survey.main. I get this contract failure:

----------------
Broken contracts
----------------

Dont use cache dependencies directly
------------------------------------

survey is not allowed to import django.core.cache:

-   survey.main -> django.db.models (l.1)
    django.db.models -> django.db.models.fields (l.39, l.38)
    django.db.models.fields -> django.core.checks (l.14)
    django.core.checks -> django.core.checks.caches (l.18)
    django.core.checks.caches -> django.core.cache (l.4)

-   survey.main -> django.db.models (l.1)
    django.db.models -> django.db.models.fields (l.39, l.38)
    django.db.models.fields -> django.core.checks (l.14)
    django.core.checks -> django.core.checks.caches (l.18)
    django.core.checks.caches -> django.core.cache.backends.filebased (l.5)

If you don't mind indirect imports, you could add allow_indirect_imports = true to the contract, i.e.

[[tool.importlinter.contracts]]
name = "Dont use cache dependencies directly"
type = "forbidden"
source_modules = ["survey", "api"]
forbidden_modules = ["django.core.cache"]
allow_indirect_imports = true

Does that solve your problem?