Skip to content

Base

base

Base class for project rules — dependency-free module.

This module contains the abstract base class for all rules, the @register_rule decorator, and the shared _RULE_REGISTRY. It has no dependencies on concrete rule implementations to avoid circular imports.

LINT_PASS_THRESHOLD = 100 module-attribute

Minimum lint score — zero tolerance for lint issues.

PASS_THRESHOLD = 90 module-attribute

Minimum score (out of 100) for a check to pass.

PERFECT_SCORE = 100 module-attribute

Maximum achievable score.

ProjectRule

Bases: ABC

Base class for project invariants.

Each rule defines a single check that a project must satisfy.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
class ProjectRule(ABC):
    """Base class for project invariants.

    Each rule defines a single check that a project must satisfy.
    """

    @property
    @abstractmethod
    def rule_id(self) -> str:
        """Unique identifier for this rule."""

    @property
    def category(self) -> str:
        """Scoring category, auto-injected by ``@register_rule``.

        Valid values: ``lint``, ``type``, ``complexity``, ``security``,
        ``deps``, ``testing``, ``architecture``, ``practices``,
        ``structure``, ``tooling``.
        """
        return getattr(self, "_registered_category", "")

    @property
    def framework(self) -> Framework:
        """Ecosystem this rule applies to, auto-injected by ``@register_rule``.

        Defaults to :attr:`Framework.PYTHON` for rules registered before the
        framework dimension existed.
        """
        return getattr(self, "_registered_framework", Framework.PYTHON)

    @abstractmethod
    def check(self, project_path: Path) -> CheckResult:
        """Execute the check against a project.

        Args:
            project_path: Root directory of the project to check.

        Returns:
            CheckResult with pass/fail status and message.
        """

    def check_src(self, project_path: Path) -> CheckResult | None:
        """Return an early ``CheckResult`` if ``src/`` does not exist.

        Call this at the top of ``check()`` to eliminate boilerplate::

            early = self.check_src(project_path)
            if early is not None:
                return early

        Returns:
            ``None`` if ``src/`` exists — single-package layout (``src/``)
            or multi-package workspace (``packages/*/src/``). The rule
            should continue.
            A passing ``CheckResult`` if neither layout is present.
        """
        if iter_src_dirs(project_path):
            return None
        return CheckResult(
            rule_id=self.rule_id,
            passed=True,
            message="src/ directory not found",
            severity=Severity.INFO,
            score=100,
        )

    @classmethod
    def get_instances(cls) -> list[ProjectRule]:
        """Instantiate this rule.

        Override in subclasses that require constructor parameters
        (e.g. ``ToolAvailabilityRule``).

        Returns:
            List of rule instances — ``[cls()]`` by default.
        """
        return [cls()]
category property

Scoring category, auto-injected by @register_rule.

Valid values: lint, type, complexity, security, deps, testing, architecture, practices, structure, tooling.

framework property

Ecosystem this rule applies to, auto-injected by @register_rule.

Defaults to :attr:Framework.PYTHON for rules registered before the framework dimension existed.

rule_id abstractmethod property

Unique identifier for this rule.

check(project_path) abstractmethod

Execute the check against a project.

Parameters:

Name Type Description Default
project_path Path

Root directory of the project to check.

required

Returns:

Type Description
CheckResult

CheckResult with pass/fail status and message.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
@abstractmethod
def check(self, project_path: Path) -> CheckResult:
    """Execute the check against a project.

    Args:
        project_path: Root directory of the project to check.

    Returns:
        CheckResult with pass/fail status and message.
    """
check_src(project_path)

Return an early CheckResult if src/ does not exist.

Call this at the top of check() to eliminate boilerplate::

Text Only
early = self.check_src(project_path)
if early is not None:
    return early

Returns:

Type Description
CheckResult | None

None if src/ exists — single-package layout (src/)

CheckResult | None

or multi-package workspace (packages/*/src/). The rule

CheckResult | None

should continue.

CheckResult | None

A passing CheckResult if neither layout is present.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
def check_src(self, project_path: Path) -> CheckResult | None:
    """Return an early ``CheckResult`` if ``src/`` does not exist.

    Call this at the top of ``check()`` to eliminate boilerplate::

        early = self.check_src(project_path)
        if early is not None:
            return early

    Returns:
        ``None`` if ``src/`` exists — single-package layout (``src/``)
        or multi-package workspace (``packages/*/src/``). The rule
        should continue.
        A passing ``CheckResult`` if neither layout is present.
    """
    if iter_src_dirs(project_path):
        return None
    return CheckResult(
        rule_id=self.rule_id,
        passed=True,
        message="src/ directory not found",
        severity=Severity.INFO,
        score=100,
    )
get_instances() classmethod

Instantiate this rule.

Override in subclasses that require constructor parameters (e.g. ToolAvailabilityRule).

Returns:

Type Description
list[ProjectRule]

List of rule instances — [cls()] by default.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
@classmethod
def get_instances(cls) -> list[ProjectRule]:
    """Instantiate this rule.

    Override in subclasses that require constructor parameters
    (e.g. ``ToolAvailabilityRule``).

    Returns:
        List of rule instances — ``[cls()]`` by default.
    """
    return [cls()]

get_registry()

Return the Python rule registry as a category -> classes view.

Backwards-compatible accessor: it exposes only the python framework rules, keyed by category, exactly as before the framework dimension was introduced. New framework-aware callers use :func:get_registry_for.

Callers must ensure that rule modules have been imported before calling this function so that @register_rule decorators have fired.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
def get_registry() -> dict[str, list[type[ProjectRule]]]:
    """Return the Python rule registry as a ``category -> classes`` view.

    Backwards-compatible accessor: it exposes only the ``python`` framework
    rules, keyed by category, exactly as before the framework dimension was
    introduced. New framework-aware callers use :func:`get_registry_for`.

    Callers must ensure that rule modules have been imported before
    calling this function so that ``@register_rule`` decorators have fired.
    """
    return get_registry_for(Framework.PYTHON)

get_registry_for(framework)

Return the rule registry for a single framework, keyed by category.

Parameters:

Name Type Description Default
framework Framework

Ecosystem whose rules to expose.

required

Returns:

Type Description
dict[str, list[type[ProjectRule]]]

Mapping category -> [rule classes] for that framework only.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
def get_registry_for(framework: Framework) -> dict[str, list[type[ProjectRule]]]:
    """Return the rule registry for a single *framework*, keyed by category.

    Args:
        framework: Ecosystem whose rules to expose.

    Returns:
        Mapping ``category -> [rule classes]`` for that framework only.
    """
    view: dict[str, list[type[ProjectRule]]] = {}
    for (category, fw), classes in _RULE_REGISTRY.items():
        if fw is framework:
            view.setdefault(category, []).extend(classes)
    return view

register_rule(category, framework=Framework.PYTHON)

Class decorator that registers a rule in the auto-discovery registry.

Also injects _registered_category and _registered_framework on the class so that ProjectRule.category / ProjectRule.framework resolve automatically.

Parameters:

Name Type Description Default
category str

Unified category (e.g. "lint", "security").

required
framework Framework | str

Ecosystem the rule applies to (default "python" so existing Python rules are unaffected).

PYTHON

Returns:

Type Description
Callable[[type[ProjectRule]], type[ProjectRule]]

The unmodified class — the decorator only appends to the registry

Callable[[type[ProjectRule]], type[ProjectRule]]

and sets the _registered_* attributes.

Source code in packages/axm-audit/src/axm_audit/core/rules/base.py
Python
def register_rule(
    category: str,
    framework: Framework | str = Framework.PYTHON,
) -> Callable[[type[ProjectRule]], type[ProjectRule]]:
    """Class decorator that registers a rule in the auto-discovery registry.

    Also injects ``_registered_category`` and ``_registered_framework`` on the
    class so that ``ProjectRule.category`` / ``ProjectRule.framework`` resolve
    automatically.

    Args:
        category: Unified category (e.g. ``"lint"``, ``"security"``).
        framework: Ecosystem the rule applies to (default ``"python"`` so
            existing Python rules are unaffected).

    Returns:
        The unmodified class — the decorator only appends to the registry
        and sets the ``_registered_*`` attributes.
    """
    fw = Framework(framework)

    def _decorator(cls: type[ProjectRule]) -> type[ProjectRule]:
        cls._registered_category = category  # type: ignore[attr-defined]
        cls._registered_framework = fw  # type: ignore[attr-defined]
        bucket = _RULE_REGISTRY.setdefault((category, fw), [])
        if cls not in bucket:
            bucket.append(cls)
        return cls

    return _decorator