Skip to content

Proposed: import-linter contract to lock in the current cycle-free layering #284

Description

@Polichinel

Status: proposed only. Nothing in this repo has been changed. Ready to paste.

Why this repo

Across the platform, 4 of 7 packages carry import cycles: views-pipeline-core (7), views-hydranet (2), views-faoapi (1), views-crafdapi (1). views-postprocessing has none — along with views-frames and views-reporting. A contract here passes on day one and costs nothing.

Worth noting: this is also the only register on the platform that fully converges (78 concerns arrived, 78 resolved, open count flat at 22 over four months). Locking in the structure seems worth the two lines.

The measured structure

crafd    -> contract, delivery
unfao    -> contract, delivery
contract -> delivery
delivery -> (nothing)

Proposed contract

[tool.importlinter]
root_package = "views_postprocessing"

[[tool.importlinter.contracts]]
name = "Postprocessing layering"
type = "layers"
layers = [
    "views_postprocessing.crafd | views_postprocessing.unfao",
    "views_postprocessing.contract",
    "views_postprocessing.delivery",
]

Plus import-linter = ">=2.0" in [tool.poetry.group.dev.dependencies], and one line after the Lint step in .github/workflows/run_pytest.yml (~line 118):

    - name: Imports
      run: poetry run lint-imports

| means the siblings are independentcrafd and unfao may not import each other, which is what prevents a cycle. Neither does today.

A concern that was raised and then disproved

views_postprocessing/ has no __init__.py, so it is an implicit namespace package, and I expected that to block import-linter — its graph builder has to import the root package. Tested in an isolated environment against this source tree, and it works: grimp built the graph successfully, finding 37 modules and all four top-level packages (contract, crafd, delivery, unfao).

So there is no packaging change needed and no __init__.py should be added on the linter's account. Recording it here because it looked like a blocker and is not.

To apply

  1. Paste the block into pyproject.toml, add the dev dep and the CI step.
  2. poetry install && poetry run lint-imports → expect Contracts: 1 kept, 0 broken.
  3. Mutation-test it — add from views_postprocessing.crafd import ... to something under delivery/, confirm it breaks and names the chain, revert. A contract nobody has seen fail is not yet known to work.
  4. poetry run pytest.

Precedent

Applied and mutation-tested in views-frames (views-platform/views-frames#238), where both contracts caught injected violations and named the exact offending import line.

Filed by Claude Opus 5 at Simon's request. Not applied here — this repo was deliberately left untouched.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions