Skip to content

Commit

Permalink
Implement as_packages for forbidden contracts
Browse files Browse the repository at this point in the history
Implement the funcitonality for treating the forbidden modules as a module rather than a package. If this is specified, we set the source_moduels and forbidden_modules as the package name rather than finding all downstream modules of that package.
  • Loading branch information
NicholasBunn committed Dec 4, 2024
1 parent b3dcae3 commit 4860c3d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
8 changes: 6 additions & 2 deletions docs/contract_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ Forbidden modules

Forbidden contracts check that one set of modules are not imported by another set of modules.

Descendants of each module will be checked - so if ``mypackage.one`` is forbidden from importing ``mypackage.two``, then
``mypackage.one.blue`` will be forbidden from importing ``mypackage.two.green``. Indirect imports will also be checked.
By default, descendants of each module will be checked - so if ``mypackage.one`` is forbidden from importing ``mypackage.two``, then
``mypackage.one.blue`` will be forbidden from importing ``mypackage.two.green``. Indirect imports will also be checked. This can be
changed by setting add_packages to False: in that case, only explicitly listed modules will be checked, not their descendants.

External packages may also be forbidden.

Expand Down Expand Up @@ -66,6 +67,9 @@ External packages may also be forbidden.
- ``unmatched_ignore_imports_alerting``: See :ref:`Shared options`.
- ``allow_indirect_imports``: If ``True``, allow indirect imports to forbidden modules without interpreting them
as a reason to mark the contract broken. (Optional.)
- ``as_packages``: Whether to treat the source and forbidden modules as packages. If ``False``, each of the modules
passed in will be treated as a module rather than a package. Default behaviour is ``True`` (treat modules as
packages).

Independence
------------
Expand Down
24 changes: 20 additions & 4 deletions src/importlinter/contracts/forbidden.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class ForbiddenContract(Contract):
- unmatched_ignore_imports_alerting: Decides how to report when the expression in the
`ignore_imports` set is not found in the graph. Valid values are
"none", "warn", "error". Default value is "error".
- as_packages: Whether to treat the source and forbidden modules as packages. If
False, each of the modules passed in will be treated as a module
rather than a package. Default behaviour is True (treat modules as
packages).
"""

type_name = "forbidden"
Expand Down Expand Up @@ -88,10 +92,14 @@ def sort_key(module):
}

if str(self.allow_indirect_imports).lower() == "true":
chains = self._get_direct_chains(source_module, forbidden_module, graph, self.as_packages)
chains = self._get_direct_chains(
source_module, forbidden_module, graph, self.as_packages # type:ignore
)
else:
chains = graph.find_shortest_chains(
importer=source_module.name, imported=forbidden_module.name
importer=source_module.name,
imported=forbidden_module.name,
as_packages=self.as_packages, # type:ignore
)
if chains:
is_kept = False
Expand Down Expand Up @@ -200,8 +208,16 @@ def _get_direct_chains(
as_packages: bool,
) -> set[tuple[str, ...]]:
chains: set[tuple[str, ...]] = set()
source_modules = self._get_all_modules_in_package(source_package, graph)
forbidden_modules = self._get_all_modules_in_package(forbidden_package, graph)
source_modules = (
self._get_all_modules_in_package(source_package, graph)
if as_packages
else {source_package}
)
forbidden_modules = (
self._get_all_modules_in_package(forbidden_package, graph)
if as_packages
else {forbidden_package}
)
for source_module in source_modules:
imported_module_names = graph.find_modules_directly_imported_by(source_module.name)
for imported_module_name in imported_module_names:
Expand Down

0 comments on commit 4860c3d

Please sign in to comment.