|
| 1 | +# Modernization Plan (Packaging + uv + Django/Python) |
| 2 | + |
| 3 | +## Scope / goals |
| 4 | + |
| 5 | +We will implement a modernization of `django-rainbowtests` to: |
| 6 | + |
| 7 | +1. Migrate packaging to **`pyproject.toml`** (remove/replace `setup.py`). |
| 8 | +2. Manage dependencies and dev workflows using **uv**. |
| 9 | +3. Support **exactly** these Python versions: **3.10, 3.11, 3.12, 3.13, 3.14**. |
| 10 | +4. Target **Django 4.2, 5.2, 6.0**. |
| 11 | +5. Adopt **`rich`** for terminal color output and remove dependency on `django.utils.termcolors`. |
| 12 | +6. Add **django-project-agnostic** tests using **pytest** in a repo-root `tests/` directory. |
| 13 | +7. Add **GitHub Actions** CI to run the test suite across all supported Python/Django versions. |
| 14 | +8. Update docs (`README.md`, `AGENTS.md`, etc.) to match the new reality. |
| 15 | + |
| 16 | +## Current repository state (findings) |
| 17 | + |
| 18 | +### Packaging |
| 19 | + |
| 20 | +- Uses `setup.py` + `MANIFEST.in`. |
| 21 | +- `setup.py` currently: |
| 22 | + - `install_requires=['django']` (unversioned). |
| 23 | + - Classifiers still include Python 2.x and Python 3.4. |
| 24 | + - Reads long description from `README.md`. |
| 25 | +- `MANIFEST.in` includes `README.md` + `LICENSE.md`. |
| 26 | + |
| 27 | +### Code / Django integration |
| 28 | + |
| 29 | +- Primary runner: `rainbowtests/test/runner.py` with `RainbowDiscoverRunner(DiscoverRunner)`. |
| 30 | + - Overrides `run_suite` and sets `runner.resultclass = RainbowTextTestResult`. |
| 31 | + - Uses `settings.RAINBOWTESTS_SHOW_MESSAGES`. |
| 32 | + - Coverage runner uses `coverage.coverage()`. |
| 33 | +- Legacy runner: `rainbowtests/test/simple.py` imports `django.test.simple.DjangoTestSuiteRunner` (removed long ago; incompatible with Django 4.2+). |
| 34 | +- Color styles rely on `django.utils.termcolors.make_style`. |
| 35 | +- There is effectively **no real automated test suite** in-repo (`rainbowtests/tests.py` is empty; no pytest/tox/CI config). |
| 36 | + |
| 37 | +### Docs |
| 38 | + |
| 39 | +- `README.md` still documents Django 1.4–1.8 + Python 2.7 / 3.4. |
| 40 | +- `AGENTS.md` exists but currently describes pip/venv-based dev workflow, not uv. |
| 41 | + |
| 42 | +## Key design decisions to make (before implementation) |
| 43 | + |
| 44 | +1. **Build backend**: Use `setuptools` via PEP 517/621 (simplest migration, minimal behavior change). |
| 45 | +2. **Version source**: Keep `rainbowtests.__version__` as the single source of truth and configure setuptools dynamic version from that attribute. |
| 46 | +3. **Supported Python versions**: We support *exactly* 3.10–3.14; packaging will express this as a bounded range (e.g. `>=3.10,<3.15`) plus explicit trove classifiers, while CI enforces the exact matrix. |
| 47 | +4. **Supported Django versions**: We will explicitly support 4.2 LTS, 5.2 (LTS), and 6.0. |
| 48 | + - Practical note: depending on today’s ecosystem, Django 6.0 may be prerelease/not available on PyPI yet; plan CI to optionally test prereleases. |
| 49 | +5. **Color output implementation**: Adopt `rich` for styling and remove usage of `django.utils.termcolors`. |
| 50 | + - Maintain the existing public API shape in `rainbowtests/colors.py` as much as practical (callables like `green("text")`). |
| 51 | +6. **Legacy runner removal**: `RainbowTestSuiteRunner` (Django <1.8) should be removed (or gated behind a safe import + clear error), because the project will officially support only Django 4.2+. |
| 52 | +7. **Test strategy**: Add django-project-agnostic unit tests (no external Django project) validating: |
| 53 | + - resultclass injection works |
| 54 | + - colored dot output for success/error/failure |
| 55 | + - traceback highlighting behavior |
| 56 | + - `colors.*` functions return styled output (ANSI sequences) via rich |
| 57 | + |
| 58 | +## Implementation plan (phased) |
| 59 | + |
| 60 | +### Phase 0 — Baseline + safety net |
| 61 | + |
| 62 | +- Add a pytest-based test harness in a repo-root `tests/` directory. |
| 63 | + - Keep it **django-project-agnostic**: tests should not require a separate Django project checkout. |
| 64 | + - It is acceptable (and expected) that tests install Django itself; the goal is to avoid needing an app/project scaffold. |
| 65 | + - Use minimal settings configuration inside tests (e.g., `django.conf.settings.configure(...)` when needed). |
| 66 | + - Prefer unit tests around `RainbowTextTestResult` + the runner wiring rather than full integration tests. |
| 67 | + |
| 68 | +- Add GitHub Actions CI to run the test suite across the supported matrix: |
| 69 | + - Python: 3.10, 3.11, 3.12, 3.13, 3.14 |
| 70 | + - Django: 4.2, 5.2, 6.0 |
| 71 | + - If Django 6.0 is not released yet, install with prereleases enabled (e.g. `uv pip install --pre`) and/or split into an “experimental” job until stable. |
| 72 | + - If Python 3.14 is not available on GitHub Actions yet, use the appropriate setup-python prerelease channel and treat it similarly (tracked/optional) until GA. |
| 73 | + |
| 74 | +- Run everything via uv in CI: |
| 75 | + - `uv sync --group test` |
| 76 | + - `uv run pytest` |
| 77 | + |
| 78 | +Acceptance criteria: |
| 79 | +- `uv run pytest` works locally. |
| 80 | +- CI reproduces local runs for all stable versions in the matrix. |
| 81 | + |
| 82 | +### Phase 1 — Migrate packaging to `pyproject.toml` |
| 83 | + |
| 84 | +- Create `pyproject.toml` with: |
| 85 | + - `[build-system]` using `setuptools`. |
| 86 | + - `[project]` metadata (name, description, readme, license, authors, urls). |
| 87 | + - `requires-python` expressing our explicit support window (e.g. `">=3.10,<3.15"`). |
| 88 | + - Dependencies: |
| 89 | + - `Django>=4.2` (and likely `<7` to avoid unknown future breakages). |
| 90 | + - `rich` (for terminal color output) |
| 91 | + - Classifiers updated to Python 3.10–3.14 and supported Django versions. |
| 92 | + - Configure package discovery for `rainbowtests`. |
| 93 | + - Configure version as dynamic from `rainbowtests.__version__`. |
| 94 | +- Remove or greatly simplify `setup.py` (eventually delete once packaging is stable). |
| 95 | +- Ensure sdists/wheels include README/LICENSE as desired (verify with `python -m build` in CI). |
| 96 | + |
| 97 | +Acceptance criteria: |
| 98 | +- `python -m build` produces sdist/wheel. |
| 99 | +- `pip install dist/*.whl` works. |
| 100 | + |
| 101 | +### Phase 2 — Adopt uv for dependency management |
| 102 | + |
| 103 | +- Standardize dev workflow around uv: |
| 104 | + - `uv sync` for dev environment creation. |
| 105 | + - `uv run python -m ...` for commands. |
| 106 | +- Add dependency groups (PEP 735 style) in `pyproject.toml` (uv-supported), e.g.: |
| 107 | + - `dependency-groups.dev`: tooling (ruff, mypy optional) |
| 108 | + - `dependency-groups.test`: pytest, coverage (and any small pytest helpers as needed) |
| 109 | +- Generate and commit `uv.lock`. |
| 110 | +- Document common commands in README/AGENTS. |
| 111 | + |
| 112 | +Acceptance criteria: |
| 113 | +- Fresh checkout: `uv sync` + `uv run pytest` works. |
| 114 | + |
| 115 | +### Phase 3 — Modernize code for Django 4.2+ / Python 3.10–3.14 |
| 116 | + |
| 117 | +Focus areas: |
| 118 | + |
| 119 | +1. **Remove obsolete Django runner**: |
| 120 | + - Delete `rainbowtests/test/simple.py` OR keep it but make it inert on modern Django: |
| 121 | + - wrap import in `try/except ImportError` and raise a clear message if used. |
| 122 | + - Update README to remove all references to `RainbowTestSuiteRunner`. |
| 123 | + |
| 124 | +2. **Audit `DiscoverRunner` integration**: |
| 125 | + - Confirm `run_suite` override still matches Django 4.2/5.2/6.0 expectations. |
| 126 | + - Confirm `unittest.TextTestRunner` usage still works with Django’s runner plumbing. |
| 127 | + - Consider overriding `get_resultclass()` or `get_test_runner_kwargs()` if Django provides cleaner hooks in modern versions. |
| 128 | + |
| 129 | +3. **Coverage support**: |
| 130 | + - Update `RainbowDiscoverCoverageRunner` to use modern `coverage.Coverage()` API. |
| 131 | + - Consider moving coverage integration to docs (recommended modern workflow is `coverage run -m pytest` / `coverage run manage.py test`), and potentially deprecate the custom coverage runner. |
| 132 | + |
| 133 | +4. **Color utilities (switch to rich)**: |
| 134 | + - Replace `django.utils.termcolors` usage with `rich`. |
| 135 | + - Keep `rainbowtests/colors.py` API stable (e.g., `colors.red("text") -> str`) by using rich to generate ANSI-colored strings. |
| 136 | + - Likely approach: render a `rich.text.Text` with a `rich.console.Console(force_terminal=True, file=io.StringIO())` and return the captured string. |
| 137 | + - Ensure behavior remains reasonable when output is not a TTY (either always emit ANSI, or make it configurable; decide and document). |
| 138 | + |
| 139 | +5. **General Python modernization** (optional but recommended once tests exist): |
| 140 | + - Remove Python 2-era comments and encoding headers. |
| 141 | + - Use `super()` without args. |
| 142 | + - Use f-strings where it improves readability. |
| 143 | + |
| 144 | +Acceptance criteria: |
| 145 | +- Tests pass on Django 4.2 + 5.2. |
| 146 | +- Django 6.0 tests pass (or are at least tracked) once available. |
| 147 | + |
| 148 | +### Phase 4 — Documentation updates |
| 149 | + |
| 150 | +- Update `README.md`: |
| 151 | + - Compatibility section to: Python 3.10/3.11/3.12/3.13/3.14; Django 4.2/5.2/6.0. |
| 152 | + - Remove legacy Django <1.8 guidance. |
| 153 | + - Provide modern installation examples (`pip install ...` and optionally `uv add django-rainbowtests`). |
| 154 | + - Document settings: |
| 155 | + - `RAINBOWTESTS_HIGHLIGHT_PATH` |
| 156 | + - `RAINBOWTESTS_SHOW_MESSAGES` |
| 157 | + - Add a “Development” section referencing uv. |
| 158 | + |
| 159 | +- Update `AGENTS.md`: |
| 160 | + - Replace venv/pip steps with uv-first workflow. |
| 161 | + - Add the standard commands to run tests/linters using `uv run`. |
| 162 | + |
| 163 | +Acceptance criteria: |
| 164 | +- Docs do not mention unsupported Python/Django versions. |
| 165 | +- Quickstart is accurate for both consumers and contributors. |
| 166 | + |
| 167 | +## Deliverables (files likely to change) |
| 168 | + |
| 169 | +- Add: `pyproject.toml`, `uv.lock`, `tests/`, CI workflow under `.github/workflows/`. |
| 170 | +- Modify: `README.md`, `AGENTS.md`, `MANIFEST.in` (if needed), package code under `rainbowtests/test/`. |
| 171 | +- Remove: `setup.py` (eventually), `rainbowtests/test/simple.py` (or deprecate/guard it). |
| 172 | + |
| 173 | +## Open questions / risks |
| 174 | + |
| 175 | +- Django 6.0 availability and installation constraints (may require prerelease installs for a while). |
| 176 | +- Python 3.14 availability on GitHub Actions / wheels for dependencies (may require prerelease interpreters initially). |
| 177 | +- Rich/ANSI behavior differences across terminals and non-TTY output (ensure deterministic tests). |
| 178 | +- Whether Django’s internal runner APIs changed enough that overriding `run_suite` is brittle; tests across versions will surface this early. |
| 179 | + - Ideally our pytest test suite would capture this. |
0 commit comments