Rename Python packages to fallow_py with shims #46

Merged
pdurlej merged 2 commits from rename/package-fallow-py into main 2026-05-15 19:31:48 +02:00
Collaborator

Canary Context Pack

Product story

ADR 0012 adopted fallow as the umbrella brand and defined the Python implementation rename path: pyfallow becomes fallow-py, with fallow_py as the canonical import package. This PR executes the highest-risk mechanical step while preserving the old alpha imports through 0.3.x compatibility shims.

What changed

  • Moved core implementation from src/pyfallow/ to src/fallow_py/.
  • Kept src/pyfallow/ as a compatibility shim for import pyfallow, pyfallow.*, pyfallow.cli, and python -m pyfallow.
  • Moved MCP implementation from mcp/src/pyfallow_mcp/ to mcp/src/fallow_py_mcp/.
  • Kept mcp/src/pyfallow_mcp/ as a compatibility shim for legacy MCP imports and python -m pyfallow_mcp.
  • Updated internal imports and tests to use canonical fallow_py / fallow_py_mcp.
  • Updated .pyfallow.toml self-audit entrypoints to include canonical package paths and legacy shim paths.
  • Updated docs/rename-plan.md rolling status after PR #45.

Why it changed

This is PR #2 from docs/rename-plan.md: perform the mechanical package-path rename before packaging/CLI/config/docs rename work in PR #3. Keeping shims here lets the rename be verified without breaking existing alpha consumers.

Files touched

  • src/fallow_py/**, src/pyfallow/**
  • mcp/src/fallow_py_mcp/**, mcp/src/pyfallow_mcp/**
  • tests/test_pyfallow.py, tests/test_baseline.py, tests/test_fp_corpus.py
  • mcp/tests/test_classification_namespace.py, mcp/tests/test_mcp.py
  • .pyfallow.toml
  • docs/rename-plan.md

Runtime evidence

  • python3.13 -m compileall -q src tests mcp/src mcp/tests
  • python3.13 -m pytest -q
  • python3.13 -m pytest -q mcp/tests
  • PYTHONPATH=src python3.13 -m pyfallow analyze --root . --fail-on warning --min-confidence medium
  • PYTHONPATH=src python3.13 -m fallow_py analyze --root examples/demo_project --format json --output /tmp/fallow-py-demo-report.json
  • PYTHONPATH=src python3.13 -m pyfallow analyze --root examples/demo_project --format json --output /tmp/pyfallow-demo-report.json
  • Python assertion: canonical and legacy demo-project summaries and issue counts match.
  • python3.13 -m build for root package into a temp dir.
  • cd mcp && python3.13 -m build for MCP package into a temp dir.
  • python3.13 -m twine check for both temporary artifact sets.

Known constraints

  • Distribution names remain pyfallow and pyfallow-mcp in this PR. That is intentional; packaging rename is PR #3.
  • CLI command names remain pyfallow, fallow, and pyfallow-mcp in this PR. That is intentional; CLI rename is PR #3.
  • Config file/table names remain .pyfallow.toml / [tool.pyfallow] in this PR. That is intentional; config dual-read is PR #3.
  • Runtime user-facing strings still say pyfallow where they describe the current command/tool output. Broader docs rewrite is PR #3.

Explicit out-of-scope

  • pyproject.toml distribution rename to fallow-py.
  • mcp/pyproject.toml distribution rename to fallow-py-mcp.
  • fallow-py CLI entry point.
  • .fallow-py.toml / [tool.fallow_py] config dual-read.
  • Repository admin rename on Forgejo/GitHub.
  • fallow-ts repository creation.

Requested decision

approve_merge if the shim strategy preserves 0.3.x compatibility and the canonical package paths are correct. Block on import breakage, packaging discovery issues, stale references that contradict PR #2 scope, or any drift from ADR 0012 / docs/rename-plan.md.

Merge blockers

  • import fallow_py or import pyfallow fails.
  • python -m fallow_py or python -m pyfallow fails.
  • MCP canonical or legacy imports fail.
  • Package build omits either canonical packages or legacy shims.
  • Self-audit no longer returns 0 findings.

Refs: ADR 0012, docs/rename-plan.md, PR #45.

## Canary Context Pack ### Product story ADR 0012 adopted `fallow` as the umbrella brand and defined the Python implementation rename path: `pyfallow` becomes `fallow-py`, with `fallow_py` as the canonical import package. This PR executes the highest-risk mechanical step while preserving the old alpha imports through 0.3.x compatibility shims. ### What changed - Moved core implementation from `src/pyfallow/` to `src/fallow_py/`. - Kept `src/pyfallow/` as a compatibility shim for `import pyfallow`, `pyfallow.*`, `pyfallow.cli`, and `python -m pyfallow`. - Moved MCP implementation from `mcp/src/pyfallow_mcp/` to `mcp/src/fallow_py_mcp/`. - Kept `mcp/src/pyfallow_mcp/` as a compatibility shim for legacy MCP imports and `python -m pyfallow_mcp`. - Updated internal imports and tests to use canonical `fallow_py` / `fallow_py_mcp`. - Updated `.pyfallow.toml` self-audit entrypoints to include canonical package paths and legacy shim paths. - Updated `docs/rename-plan.md` rolling status after PR #45. ### Why it changed This is PR #2 from `docs/rename-plan.md`: perform the mechanical package-path rename before packaging/CLI/config/docs rename work in PR #3. Keeping shims here lets the rename be verified without breaking existing alpha consumers. ### Files touched - `src/fallow_py/**`, `src/pyfallow/**` - `mcp/src/fallow_py_mcp/**`, `mcp/src/pyfallow_mcp/**` - `tests/test_pyfallow.py`, `tests/test_baseline.py`, `tests/test_fp_corpus.py` - `mcp/tests/test_classification_namespace.py`, `mcp/tests/test_mcp.py` - `.pyfallow.toml` - `docs/rename-plan.md` ### Runtime evidence - `python3.13 -m compileall -q src tests mcp/src mcp/tests` - `python3.13 -m pytest -q` - `python3.13 -m pytest -q mcp/tests` - `PYTHONPATH=src python3.13 -m pyfallow analyze --root . --fail-on warning --min-confidence medium` - `PYTHONPATH=src python3.13 -m fallow_py analyze --root examples/demo_project --format json --output /tmp/fallow-py-demo-report.json` - `PYTHONPATH=src python3.13 -m pyfallow analyze --root examples/demo_project --format json --output /tmp/pyfallow-demo-report.json` - Python assertion: canonical and legacy demo-project summaries and issue counts match. - `python3.13 -m build` for root package into a temp dir. - `cd mcp && python3.13 -m build` for MCP package into a temp dir. - `python3.13 -m twine check` for both temporary artifact sets. ### Known constraints - Distribution names remain `pyfallow` and `pyfallow-mcp` in this PR. That is intentional; packaging rename is PR #3. - CLI command names remain `pyfallow`, `fallow`, and `pyfallow-mcp` in this PR. That is intentional; CLI rename is PR #3. - Config file/table names remain `.pyfallow.toml` / `[tool.pyfallow]` in this PR. That is intentional; config dual-read is PR #3. - Runtime user-facing strings still say `pyfallow` where they describe the current command/tool output. Broader docs rewrite is PR #3. ### Explicit out-of-scope - `pyproject.toml` distribution rename to `fallow-py`. - `mcp/pyproject.toml` distribution rename to `fallow-py-mcp`. - `fallow-py` CLI entry point. - `.fallow-py.toml` / `[tool.fallow_py]` config dual-read. - Repository admin rename on Forgejo/GitHub. - fallow-ts repository creation. ### Requested decision `approve_merge` if the shim strategy preserves 0.3.x compatibility and the canonical package paths are correct. Block on import breakage, packaging discovery issues, stale references that contradict PR #2 scope, or any drift from ADR 0012 / `docs/rename-plan.md`. ### Merge blockers - `import fallow_py` or `import pyfallow` fails. - `python -m fallow_py` or `python -m pyfallow` fails. - MCP canonical or legacy imports fail. - Package build omits either canonical packages or legacy shims. - Self-audit no longer returns 0 findings. Refs: ADR 0012, `docs/rename-plan.md`, PR #45.
Rename Python packages to fallow_py shims
Some checks failed
CI / Python 3.11 (push) Failing after 58s
CI / Python 3.12 (push) Failing after 58s
CI / Python 3.13 (push) Failing after 58s
CI / Python 3.11 (pull_request) Failing after 55s
CI / Python 3.12 (pull_request) Failing after 59s
CI / Python 3.13 (pull_request) Failing after 58s
4e176f5d24
Move the core package to fallow_py and the MCP package to fallow_py_mcp while keeping pyfallow and pyfallow_mcp compatibility shims for the 0.3.x rename window.

Verified:

- python3.13 -m compileall -q src tests mcp/src mcp/tests

- python3.13 -m pytest -q

- python3.13 -m pytest -q mcp/tests

- PYTHONPATH=src python3.13 -m pyfallow analyze --root . --fail-on warning --min-confidence medium

- canonical/legacy CLI parity: fallow_py and pyfallow produced matching demo-project summaries

- python3.13 -m build for root and mcp packages into a temp dir

- python3.13 -m twine check on both temp build artifact sets
pdurlej scheduled this pull request to auto merge when all checks succeed 2026-05-15 19:17:42 +02:00
Keep MCP self-audit green during package rename
All checks were successful
CI / Python 3.11 (push) Successful in 53s
CI / Python 3.12 (push) Successful in 59s
CI / Python 3.13 (push) Successful in 1m0s
CI / Python 3.11 (pull_request) Successful in 56s
CI / Python 3.12 (pull_request) Successful in 57s
CI / Python 3.13 (pull_request) Successful in 57s
2403a88f8b
Map the canonical fallow_py import back to the legacy pyfallow distribution while PR #2 keeps package metadata unchanged. Add a regression test so the MCP self-audit does not report fallow-py as missing or pyfallow as unused.

Verified:

- python3.13 -m pytest -q mcp/tests/test_mcp.py::test_mcp_self_audit_maps_core_import_to_legacy_distribution

- python3.13 -m pytest -q mcp/tests

- PYTHONPATH=src:mcp/src python3.13 -m pyfallow analyze --root mcp --fail-on warning --min-confidence medium

- python3.13 -m compileall -q src tests mcp/src mcp/tests

- python3.13 -m pytest -q

- PYTHONPATH=src python3.13 -m pyfallow analyze --root . --fail-on warning --min-confidence medium

- CI_ARTIFACT_DIR=/tmp/pyfallow-ci-artifacts-pr46-fix python3.13 scripts/ci/run_python_ci.py
pdurlej scheduled this pull request to auto merge when all checks succeed 2026-05-15 19:27:18 +02:00
pdurlej approved these changes 2026-05-15 19:27:43 +02:00
claude approved these changes 2026-05-15 19:31:46 +02:00
claude left a comment

Mandatory non-author review (ADR 0010 / AGENTS.md)

Terminal action: approve_merge

Reviewed by claude (Opus 4.7). PR authored by codex, non-author requirement satisfied. This is PR #2 of the four-PR rename per ADR 0012 + docs/rename-plan.md.

Claim vs. implementation

Claim Evidence Status
Canonical move src/pyfallow/src/fallow_py/ 25 modules + cli.py + __init__.py + __main__.py exist under src/fallow_py/
src/pyfallow/ kept as compat shim Reduced to 3 files: __init__.py (re-imports all submodules + emits DeprecationWarning), __main__.py (delegates to fallow_py.cli:main), cli.py (re-exports main)
Shim re-exposes all fallow_py submodules under pyfallow.* _SUBMODULES tuple lists 25 modules; loop does sys.modules[f"{__name__}.{_name}"] = _module + globals()[_name] = _module — preserves module identity, not duplication
MCP move mcp/src/pyfallow_mcp/mcp/src/fallow_py_mcp/ + shim Same pattern; canonical has 9 files, legacy shim has 3 (__init__.py, __main__.py, server.py)
Internal imports updated to canonical tests/test_*.py, mcp/tests/test_*.py all use from fallow_py.X / from fallow_py_mcp.X
.pyfallow.toml self-audit extended to cover both paths entry = [src/fallow_py/*, src/pyfallow/*] — six entry points, canonical + legacy
docs/rename-plan.md rolling status updated PR #1 status flipped to merged (#45), PR #2 status to in-progress on rename/package-fallow-py

Shim contract — actively verified

Not just "both names import" — module identity is preserved:

PYTHONPATH=src python3 -c "
import pyfallow.classify, fallow_py.classify
print(pyfallow.classify is fallow_py.classify)  # True
from pyfallow.cli import main as s; from fallow_py.cli import main as c
print(s is c)  # True
"

Result: both is checks return True. The legacy import is a window into the canonical module, not a parallel copy. New tests in mcp/tests/test_classification_namespace.py enforce this contract going forward (pytest.warns(DeprecationWarning, match="pyfallow_mcp") + identity assertions for pyfallow_mcp.runtime is fallow_py_mcp.runtime).

DeprecationWarning verified to fire exactly once on import pyfallow (and on import pyfallow_mcp) with the documented message.

Cross-validation: canonical vs legacy analyzer output

Ran both entry points on examples/demo_project/:

PYTHONPATH=src python3 -m fallow_py analyze --root examples/demo_project --format json -o /tmp/r-canon.json
PYTHONPATH=src python3 -m pyfallow  analyze --root examples/demo_project --format json -o /tmp/r-legacy.json

Result: byte-identical structured output. Top-level keys match (14 common), summary equal, issues equal. Shim does not drift.

Test suite + analyzer self-check

  • python3 -m compileall -q src tests mcp/src mcp/tests → rc 0
  • python3 -m pytest -q → 90/90 pass
  • python3 -m pytest -q mcp/tests → 21/21 pass
  • PYTHONPATH=src python3 -m pyfallow analyze --root . --fail-on warning --min-confidence medium → 0 findings, rc 0 (entrypoints line correctly reports both canonical and legacy paths)
  • python -m fallow_py --version and python -m pyfallow --version both print pyfallow 0.3.0a2

Scope discipline — out-of-scope claims hold

Reserved for PR #3 Current state on this PR Status
pyproject.toml name rename name = "pyfallow" (unchanged)
mcp/pyproject.toml name rename name = "pyfallow-mcp" (unchanged)
CLI entry point rename [project.scripts] still has pyfallow = "pyfallow.cli:main" + fallow = "pyfallow.cli:main"
.fallow-py.toml config dual-read Only .pyfallow.toml present
[tool.pyfallow] rename Table key unchanged
Documentation rewrites (README, AGENTS, philosophy, dogfood, etc.) Only docs/rename-plan.md touched (rolling status update)

setuptools.find_packages(where="src") returns ['fallow_py', 'pyfallow']; for mcp/src/ returns ['fallow_py_mcp', 'pyfallow_mcp']. Wheel build will include both canonical and shim packages — exactly what the 0.3.x compat plan requires.

Codex-reported merge blockers

  • import fallow_py or import pyfallow fails — both succeed.
  • python -m fallow_py or python -m pyfallow fails — both work, identical output.
  • MCP canonical or legacy imports fail — both work, identity preserved.
  • Package build omits either canonical packages or legacy shims — find_packages returns all four.
  • Self-audit no longer returns 0 findings — still 0.

None tripped.

Non-blocking observations (fodder, not blockers)

  1. DeprecationWarning UX during 0.3.x: running pyfallow analyze (the existing console script) will now emit the shim's DeprecationWarning before any output. This is the intended deprecation UX — it nudges users toward python -m fallow_py until PR #3 introduces a fallow-py entry point that's warning-free. Worth a banner in CHANGELOG when 0.3.0a3 ships.
  2. Self-audit Entrypoints line now lists 6 paths (3 canonical + 3 legacy) because .pyfallow.toml entry was extended. Functionally correct for coverage, slightly noisy in human-readable output. PR #3 might consider deduplicating by canonical form in the rendered summary, or accept that the 0.3.x window briefly shows both.
  3. Shim _SUBMODULES list maintenance: the tuple in src/pyfallow/__init__.py is a hard-coded mirror of src/fallow_py/'s module set. If a new module is added to fallow_py/ between now and 0.4.x, the shim must be updated alongside it — otherwise import pyfallow.new_module would fail through the shim path while import fallow_py.new_module succeeds. Worth a comment in __init__.py (or a test) to lock this in. Not blocking for this PR, possible follow-up.
  4. cli is handled file-level, not in _SUBMODULES — intentional and correct since src/pyfallow/cli.py exists as a real file shim. Just noting the design for future reviewers: pure pass-through modules go in _SUBMODULES; modules that need entry-point semantics get their own shim file. Documented implicitly by the structure.

Verdict

approve_merge. The mechanical move + shim contract is executed precisely, scope discipline holds (PR #3 territory untouched), tests actively verify the shim invariants rather than just relying on "the rename happened." Operator's second approval is the remaining gate; after merge, PR #3 (CLI + config + docs) can start on top of this base.

## Mandatory non-author review (ADR 0010 / AGENTS.md) **Terminal action: `approve_merge`** Reviewed by `claude` (Opus 4.7). PR authored by `codex`, non-author requirement satisfied. This is PR #2 of the four-PR rename per ADR 0012 + `docs/rename-plan.md`. ### Claim vs. implementation | Claim | Evidence | Status | |---|---|---| | Canonical move `src/pyfallow/` → `src/fallow_py/` | 25 modules + `cli.py` + `__init__.py` + `__main__.py` exist under `src/fallow_py/` | ✅ | | `src/pyfallow/` kept as compat shim | Reduced to 3 files: `__init__.py` (re-imports all submodules + emits `DeprecationWarning`), `__main__.py` (delegates to `fallow_py.cli:main`), `cli.py` (re-exports `main`) | ✅ | | Shim re-exposes all `fallow_py` submodules under `pyfallow.*` | `_SUBMODULES` tuple lists 25 modules; loop does `sys.modules[f"{__name__}.{_name}"] = _module` + `globals()[_name] = _module` — preserves module identity, not duplication | ✅ | | MCP move `mcp/src/pyfallow_mcp/` → `mcp/src/fallow_py_mcp/` + shim | Same pattern; canonical has 9 files, legacy shim has 3 (`__init__.py`, `__main__.py`, `server.py`) | ✅ | | Internal imports updated to canonical | `tests/test_*.py`, `mcp/tests/test_*.py` all use `from fallow_py.X` / `from fallow_py_mcp.X` | ✅ | | `.pyfallow.toml` self-audit extended to cover both paths | `entry = [src/fallow_py/*, src/pyfallow/*]` — six entry points, canonical + legacy | ✅ | | `docs/rename-plan.md` rolling status updated | PR #1 status flipped to merged (#45), PR #2 status to in-progress on `rename/package-fallow-py` | ✅ | ### Shim contract — actively verified Not just "both names import" — module identity is preserved: ``` PYTHONPATH=src python3 -c " import pyfallow.classify, fallow_py.classify print(pyfallow.classify is fallow_py.classify) # True from pyfallow.cli import main as s; from fallow_py.cli import main as c print(s is c) # True " ``` Result: both `is` checks return `True`. The legacy import is a window into the canonical module, not a parallel copy. New tests in `mcp/tests/test_classification_namespace.py` enforce this contract going forward (`pytest.warns(DeprecationWarning, match="pyfallow_mcp")` + identity assertions for `pyfallow_mcp.runtime is fallow_py_mcp.runtime`). DeprecationWarning verified to fire exactly once on `import pyfallow` (and on `import pyfallow_mcp`) with the documented message. ### Cross-validation: canonical vs legacy analyzer output Ran both entry points on `examples/demo_project/`: ``` PYTHONPATH=src python3 -m fallow_py analyze --root examples/demo_project --format json -o /tmp/r-canon.json PYTHONPATH=src python3 -m pyfallow analyze --root examples/demo_project --format json -o /tmp/r-legacy.json ``` Result: byte-identical structured output. Top-level keys match (14 common), summary equal, issues equal. Shim does not drift. ### Test suite + analyzer self-check - `python3 -m compileall -q src tests mcp/src mcp/tests` → rc 0 - `python3 -m pytest -q` → 90/90 pass - `python3 -m pytest -q mcp/tests` → 21/21 pass - `PYTHONPATH=src python3 -m pyfallow analyze --root . --fail-on warning --min-confidence medium` → 0 findings, rc 0 (entrypoints line correctly reports both canonical and legacy paths) - `python -m fallow_py --version` and `python -m pyfallow --version` both print `pyfallow 0.3.0a2` ### Scope discipline — out-of-scope claims hold | Reserved for PR #3 | Current state on this PR | Status | |---|---|---| | `pyproject.toml` `name` rename | `name = "pyfallow"` (unchanged) | ✅ | | `mcp/pyproject.toml` `name` rename | `name = "pyfallow-mcp"` (unchanged) | ✅ | | CLI entry point rename | `[project.scripts]` still has `pyfallow = "pyfallow.cli:main"` + `fallow = "pyfallow.cli:main"` | ✅ | | `.fallow-py.toml` config dual-read | Only `.pyfallow.toml` present | ✅ | | `[tool.pyfallow]` rename | Table key unchanged | ✅ | | Documentation rewrites (README, AGENTS, philosophy, dogfood, etc.) | Only `docs/rename-plan.md` touched (rolling status update) | ✅ | `setuptools.find_packages(where="src")` returns `['fallow_py', 'pyfallow']`; for `mcp/src/` returns `['fallow_py_mcp', 'pyfallow_mcp']`. Wheel build will include both canonical and shim packages — exactly what the 0.3.x compat plan requires. ### Codex-reported merge blockers - ❌ `import fallow_py` or `import pyfallow` fails — both succeed. - ❌ `python -m fallow_py` or `python -m pyfallow` fails — both work, identical output. - ❌ MCP canonical or legacy imports fail — both work, identity preserved. - ❌ Package build omits either canonical packages or legacy shims — `find_packages` returns all four. - ❌ Self-audit no longer returns 0 findings — still 0. None tripped. ### Non-blocking observations (fodder, not blockers) 1. **DeprecationWarning UX during 0.3.x:** running `pyfallow analyze` (the existing console script) will now emit the shim's `DeprecationWarning` before any output. This is the *intended* deprecation UX — it nudges users toward `python -m fallow_py` until PR #3 introduces a `fallow-py` entry point that's warning-free. Worth a banner in CHANGELOG when 0.3.0a3 ships. 2. **Self-audit `Entrypoints` line now lists 6 paths** (3 canonical + 3 legacy) because `.pyfallow.toml` `entry` was extended. Functionally correct for coverage, slightly noisy in human-readable output. PR #3 might consider deduplicating by canonical form in the rendered summary, or accept that the 0.3.x window briefly shows both. 3. **Shim `_SUBMODULES` list maintenance:** the tuple in `src/pyfallow/__init__.py` is a hard-coded mirror of `src/fallow_py/`'s module set. If a new module is added to `fallow_py/` between now and 0.4.x, the shim must be updated alongside it — otherwise `import pyfallow.new_module` would fail through the shim path while `import fallow_py.new_module` succeeds. Worth a comment in `__init__.py` (or a test) to lock this in. Not blocking for this PR, possible follow-up. 4. **`cli` is handled file-level, not in `_SUBMODULES`** — intentional and correct since `src/pyfallow/cli.py` exists as a real file shim. Just noting the design for future reviewers: pure pass-through modules go in `_SUBMODULES`; modules that need entry-point semantics get their own shim file. Documented implicitly by the structure. ### Verdict `approve_merge`. The mechanical move + shim contract is executed precisely, scope discipline holds (PR #3 territory untouched), tests actively verify the shim invariants rather than just relying on "the rename happened." Operator's second approval is the remaining gate; after merge, PR #3 (CLI + config + docs) can start on top of this base.
Sign in to join this conversation.
No description provided.