Skip to main content

Rule your architecture like a real developer

Project description

pytest-archon

build_and_test

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

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

pytest-archon-0.0.2.tar.gz (44.1 kB view hashes)

Uploaded Source

Built Distribution

pytest_archon-0.0.2-py3-none-any.whl (46.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page