The Principal Dev – Masterclass for Tech Leads

The Principal Dev – Masterclass for Tech LeadsJuly 17-18

Join

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 pytest-archon

Usage

pytest-archon can be used to define architectural boundaries from (unit) tests. Because they're 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")
    )

The check() method can have a few optional parameters, that alter the way the checks are performed.

Check toplevel imports Check TYPE_CHECKING imports Check conditional imports, and imports in functions and methods Check transitive imports
no options enabled
skip_type_checking=True
only_toplevel_imports=True
only_direct_imports=True

Example

Domain model has no dependencies

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*") # matches packageX.domain and packageX.domain.*
        .should_not_import("packageX*")
        .may_import("packageX.domain.*")
        .check("packageX")
    )

util module is used at more than one place

You can also supply custom constraints as predicate functions.

If you, for example, have a common or util module, you might want to make sure that it is used at least at two places (otherwise it would not make sense to have a separate module).

from pytest_archon import archrule


def test_utils_are_shared():
    def have_at_least_two_users(util_module, direct_imports, all_imports):
        # iterate through all imports and find modules using the util_module in question
        users = [k for k, v in all_imports.items() if util_module in v]
        # return True if more than two modules use the util_module
        return len(users) > 2

    archrule("util_is_shared").match("pkg.util").should(have_at_least_two_users).check("pkg")

See also

The blog post How to tame your Python codebase is also a good overview.

Similar projects

Join libs.tech

...and unlock some superpowers

GitHub

We won't share your data with anyone else.