Skip to main content

Archetype statically analyzes Python projects to enforce architectural rules as code.

Project description

PyPI Python License CI

Architectural rules should not live in people’s heads

Architectural rules usually exist in engineers’ heads but nowhere in the codebase. Archetype turns those rules into executable Python checks that run in archetype check and pytest.

# architecture.py
from archetype import imports, rule

@rule("api does not import db")
def api_not_db() -> None:
    imports("myapp.api").must_not_import("myapp.db")

@rule("services only import db")
def services_only_db() -> None:
    imports("myapp.services").must_only_import_from("myapp.db")
$ archetype check .
✓ api does not import db
✗ services only import db
  - myapp.services.user -> myapp.cache: Module 'myapp.services.user' imports 'myapp.cache', which is outside the allowed set: ('myapp.db',).
Summary: 1 passed, 1 failed, 2 total rules.

Installation

pip install archetype-py

Quickstart

  1. Install Archetype.
pip install archetype-py
  1. Create architecture.py in your project root.
touch architecture.py
  1. Add your first rule with the imports DSL.
# architecture.py
from archetype import imports, rule

@rule("api does not import db")
def api_not_db() -> None:
    imports("myapp.api").must_not_import("myapp.db")
  1. Run the checker.
archetype check .
  1. Read the output and fix violations.
✓ api does not import db
Summary: 1 passed, 0 failed, 1 total rules.

If your project already runs pytest, running pytest is sufficient because Archetype rules are collected and executed by the pytest plugin.

Why Archetype exists

Style tools enforce how code looks. Type tools enforce what values can flow through code. Architectural tools enforce which parts of the system are allowed to depend on which other parts.

Pylint and similar linters are strong at local code quality checks, and Mypy is strong at static type correctness. Neither is designed to express team-level dependency contracts like “API cannot import DB” or “internal modules are private outside their package boundary.”

Archetype keeps rules in architecture.py as normal Python functions, not static YAML declarations. That makes rules executable, reviewable, testable, and easy to evolve with the codebase using the same language and tooling your team already uses.

Built-in rules reference

layers

Enforces that lower layers do not import upper layers.

from archetype import rule
from archetype.rules import layers

@rule("layers are ordered")
def layer_order() -> None:
    layers(["myapp.api", "myapp.services", "myapp.db"]).are_ordered()

module (module boundaries)

Enforces that a protected internal module is only imported from an allowed parent scope.

from archetype import rule
from archetype.rules import module

@rule("internal auth is private")
def auth_boundary() -> None:
    module("myapp.auth.internal").only_imported_within("myapp.auth")

classes_in and functions_in (naming conventions)

Enforces class naming patterns and required top-level functions in matched modules.

from archetype import rule
from archetype.rules import classes_in, functions_in

@rule("service classes end with Service")
def class_names() -> None:
    classes_in("myapp.services").all_match(r".*Service$")

@rule("api modules expose handle")
def api_handle_exists() -> None:
    functions_in("myapp.api").must_include("handle")

no_cycles

Enforces that there are no import cycles in the whole project or in a selected module scope.

from archetype import rule
from archetype.rules import no_cycles

@rule("no cycles in services")
def services_no_cycles() -> None:
    no_cycles("myapp.services")

Writing custom rules

from archetype import imports, rule

@rule("custom architecture policy")
def custom_policy() -> None:
    imports("myapp.api").must_not_import("myapp.db")
    imports("myapp.services").has_no_cycles()
    imports("myapp.services").must_only_import_from("myapp.db", "myapp.shared")

Any Python function decorated with @rule that returns without raising is a passing rule. Rules can use the full Python language, so you can encode architecture constraints that do not fit generic linters or static config.

CI integration

name: Archetype Check

on:
  push:
    branches: [main]
  pull_request:

jobs:
  archetype:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - run: |
          python -m pip install --upgrade pip
          pip install archetype-py
      - run: archetype check .

If your CI already runs pytest, no additional CI configuration is required.

Contributing

Source code and issue tracking are in the GitHub repository: https://github.com/your-org/your-repo. Contributions are welcome; open an issue first to discuss scope before submitting a pull request.

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

archetype_py-0.1.0.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

archetype_py-0.1.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file archetype_py-0.1.0.tar.gz.

File metadata

  • Download URL: archetype_py-0.1.0.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.16.5 cpython/3.11.15 HTTPX/0.28.1

File hashes

Hashes for archetype_py-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5f83d9d5f2881ab58cdc6cb12b1e3a2278599e115a6ad37ce4b539ee47186fb7
MD5 f4e8b9125a2b9fb46e75db35df3cb7fb
BLAKE2b-256 756544b4c73f428c11b4fc99999b3a15ecc7947c50b3f8ae3495ddb68f43b257

See more details on using hashes here.

File details

Details for the file archetype_py-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: archetype_py-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: Hatch/1.16.5 cpython/3.11.15 HTTPX/0.28.1

File hashes

Hashes for archetype_py-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cea01db46c3bda23c5803c9b112d64c6dac1332e7d3539a9286aee3158c2bb6b
MD5 e7a02abcd6f3e68675a775c6bbedbdf3
BLAKE2b-256 3c22d614070c8c74b45e473a4f356c9c4acdc2d922791bb452142da2447eefbf

See more details on using hashes here.

Supported by

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