Rule your architecture like a real developer
Project description
pytest-archon
pytest-archon
is a little tool that helps you structure (large) Python projects. This
tool allows you to define architectural boundaries in your code, also known as
forbidden dependencies.
Explicitly defined architectural boundaries helps you keep your code in shape. It avoids the creation of circular dependencies. New people on the project are made aware of the structure through a simple set of rules, instead of lore.
Installation
The simple way:
pip install git+https://github.com/jwbargsten/pytest-archon.git
Usage
pytest-archon
can be used to define architectural boundaries from (unit) tests. Because
they're unit tests, they can be closely tied to the actual application.
You can use pytest-archon
in tests by simply importing the archrule
function. Using
this function you can construct import tests:
from pytest_archon import archrule
def test_rule_basic():
(
archrule("name", comment="some comment")
.match("pytest_archon.col*")
.exclude("pytest_archon.colgate")
.should_not_import("pytest_archon.import_finder")
.should_import("pytest_archon.core*")
.check("pytest_archon")
)
- To match the modules and constraints, fnmatch syntax is used.
.exclude()
is optional.should_import()
and.should_not_import()
can be combined and can occur multiple times..check()
needs either a module object or a string
Examples
def test_module_boundaries():
# you can do:
# from packageX.moduleA import functionX
# you cannot do
# from packageX.moduleA.internal.functionY
# so packageX/moduleA/__init__.py contains the exposed API functions,
# and only they can be used
modules = [
"moduleA",
"moduleB",
]
for m in modules:
# Match all files,
# but exclude files from the module you want to check
# (because the module itself needs to import its internals).
# Make sure that nobody imports internal functions or objects
# from the module we are looking at.
# Run the rule check on packageX.
# But do only check direct imports, not transitive ones
# (including transitive imports would mean that we will violate the rule,
# because an import of "module" will reach "module.internal.B" due to transitivity).
(
archrule(
"respect module boundaries",
comment="respect the module boundary and only import from the (sub-)module API",
)
.match("*")
.exclude(f"packageX.{m}.*")
.exclude(f"packageX.{m}")
.should_not_import(f"packageX.{m}.*")
.check("packageX", only_direct_imports=True)
)
def test_domain():
# test if the domain model does not import other submodules
# (the domain model should be standing on its own and be used by other modules)
(
archrule("domain", comment="domain does not import any other submodules")
.match("packageX.domain.*")
.match("packageX.domain")
.should_not_import("packageX*")
.may_import("packageX.domain.*")
.check("packageX")
)
Similar projects
- Archunit (Java)
- Dependency Cruiser (Javascript)
- import-linter (Python)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for pytest_archon-0.0.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 384f2d0c736524e8730501e6a8e4b244e81b2496858602f85ce561c3b43de55f |
|
MD5 | 110f2425a4f6b5c87c2e7a4109d0fde9 |
|
BLAKE2b-256 | 8ef101670d257375cef3eacf6049a25ac739458e25b407052238e56432c6f4fb |