Skip to content

Commit 08597ba

Browse files
Modernize packaging and code for Python 3.10+ / Django 4.2+
- Migrate to pyproject.toml (PEP 517/621) with setuptools, remove setup.py - Add rich dependency for terminal colors, replace django.utils.termcolors - Add pytest test suite with Django-agnostic tests - Add GitHub Actions CI for Python 3.10-3.14, Django 4.2/5.2 - Add uv for dependency management with uv.lock - Deprecate legacy RainbowTestSuiteRunner (Django <1.8) - Modernize code: super() without args, remove Python 2 headers - Update README and AGENTS.md for new workflow - Bump version to 0.7.0
1 parent 1d52012 commit 08597ba

File tree

19 files changed

+1185
-118
lines changed

19 files changed

+1185
-118
lines changed

.github/workflows/ci.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
python-version: ["3.10", "3.11", "3.12", "3.13"]
16+
django-version: ["4.2", "5.2"]
17+
include:
18+
# Python 3.14 (prerelease) - only test with Django 5.2+
19+
- python-version: "3.14"
20+
django-version: "5.2"
21+
# Django 6.0 (when available) - test with Python 3.12+
22+
# - python-version: "3.12"
23+
# django-version: "6.0"
24+
# - python-version: "3.13"
25+
# django-version: "6.0"
26+
exclude:
27+
# Django 5.2 requires Python 3.10+
28+
# (all our Python versions meet this requirement)
29+
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Install uv
34+
uses: astral-sh/setup-uv@v4
35+
with:
36+
version: "latest"
37+
38+
- name: Set up Python ${{ matrix.python-version }}
39+
uses: actions/setup-python@v5
40+
with:
41+
python-version: ${{ matrix.python-version }}
42+
allow-prereleases: true
43+
44+
- name: Install dependencies
45+
run: |
46+
uv sync --group test
47+
uv pip install "django~=${{ matrix.django-version }}.0"
48+
49+
- name: Run tests
50+
run: uv run pytest -v
51+
52+
- name: Check code compiles
53+
run: uv run python -m compileall rainbowtests setup.py
54+
55+
lint:
56+
runs-on: ubuntu-latest
57+
steps:
58+
- uses: actions/checkout@v4
59+
60+
- name: Install uv
61+
uses: astral-sh/setup-uv@v4
62+
with:
63+
version: "latest"
64+
65+
- name: Set up Python
66+
uses: actions/setup-python@v5
67+
with:
68+
python-version: "3.12"
69+
70+
- name: Install dependencies
71+
run: uv sync --group dev
72+
73+
- name: Run ruff check
74+
run: uv run ruff check .
75+
76+
build:
77+
runs-on: ubuntu-latest
78+
steps:
79+
- uses: actions/checkout@v4
80+
81+
- name: Install uv
82+
uses: astral-sh/setup-uv@v4
83+
with:
84+
version: "latest"
85+
86+
- name: Set up Python
87+
uses: actions/setup-python@v5
88+
with:
89+
python-version: "3.12"
90+
91+
- name: Install build tools
92+
run: uv pip install build
93+
94+
- name: Build package
95+
run: python -m build
96+
97+
- name: Check package installs
98+
run: uv pip install dist/*.whl

AGENTS.md

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,62 @@ This repository is a small Django test-runner package intended to make test outp
1010

1111
## Local setup
1212

13-
- Use a virtual environment.
14-
- Install in editable mode for development:
13+
This project uses [uv](https://github.com/astral-sh/uv) for dependency management.
1514

1615
```bash
17-
python -m venv .venv
18-
. .venv/bin/activate
19-
python -m pip install -U pip
20-
python -m pip install -e .
21-
```
16+
# Clone the repository
17+
git clone https://github.com/bradmontgomery/django-rainbowtests.git
18+
cd django-rainbowtests
2219

23-
- Install Django appropriate to the change you’re making (this project historically targeted older Django, but modernization work may change that).
20+
# Install all dependencies (dev + test)
21+
uv sync --group dev --group test
22+
```
2423

2524
## How to validate changes
2625

27-
- Run any existing test/lint commands already present in the repo.
28-
- At minimum, ensure the code still imports and compiles:
26+
Run the test suite:
27+
28+
```bash
29+
uv run pytest
30+
```
31+
32+
Run the linter:
2933

3034
```bash
31-
python -m compileall rainbowtests setup.py
35+
uv run ruff check .
3236
```
3337

34-
- If you have a sample Django project handy, validate integration by setting:
38+
Ensure the code compiles:
39+
40+
```bash
41+
uv run python -m compileall rainbowtests
42+
```
43+
44+
If you have a sample Django project handy, validate integration by setting:
3545

3646
```python
3747
TEST_RUNNER = 'rainbowtests.test.runner.RainbowDiscoverRunner'
3848
```
3949

40-
and running `python manage.py test`.
50+
...and running `python manage.py test`.
4151

4252
## Code & style conventions
4353

4454
- Do not do repo-wide reformatting unless explicitly requested.
4555
- Avoid adding new dependencies for minor changes.
4656
- Keep color/output behavior changes isolated to the existing modules (`rainbowtests/colors.py`, `rainbowtests/messages.py`, and `rainbowtests/test/*`) when possible.
57+
- Use `uv run ruff check --fix .` to fix lint issues.
58+
59+
## Python/Django Compatibility
60+
61+
- **Python**: 3.10, 3.11, 3.12, 3.13, 3.14
62+
- **Django**: 4.2, 5.2, 6.0
4763

4864
## Packaging / docs
4965

50-
- Keep packaging metadata consistent with documentation files in the repo root (e.g., `README.md`, `LICENSE.md`).
66+
- Packaging is managed via `pyproject.toml` (PEP 517/621 with setuptools).
67+
- Version is defined in `rainbowtests/__init__.py` and read dynamically by setuptools.
68+
- Keep documentation consistent with packaging metadata.
5169
- Prefer Markdown for documentation.
5270

5371
## Safety & privacy

PLAN.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
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

Comments
 (0)