Skip to content

Commit f966f44

Browse files
authored
Merge pull request #19 from erseco/copilot/improve-ci-coverage-python-moodle
Restore Python 3.8/3.9 compatibility for unit-test collection
2 parents 0697bb2 + 3ede811 commit f966f44

11 files changed

Lines changed: 195 additions & 50 deletions

File tree

.github/workflows/ci.yml

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
- main
1313

1414
jobs:
15-
test:
15+
lint:
1616
runs-on: ubuntu-latest
1717

1818
steps:
@@ -23,40 +23,98 @@ jobs:
2323
uses: actions/setup-python@v6
2424
with:
2525
python-version: '3.13'
26-
cache: 'pip' # caching pip dependencies
26+
cache: 'pip'
2727

2828
- name: Install dependencies
29-
run: |
30-
pip install -r requirements.txt
31-
pip install -e .
29+
run: python -m pip install -e ".[dev]"
3230

3331
- name: Lint
3432
run: make lint
3533

34+
unit:
35+
runs-on: ubuntu-latest
36+
strategy:
37+
fail-fast: false
38+
matrix:
39+
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
40+
41+
steps:
42+
- name: Checkout code
43+
uses: actions/checkout@v4
44+
45+
- name: Set up Python
46+
uses: actions/setup-python@v5
47+
with:
48+
python-version: ${{ matrix.python-version }}
49+
cache: 'pip'
50+
51+
- name: Install dependencies
52+
run: python -m pip install -e ".[dev]"
53+
54+
- name: Run smoke tests
55+
run: make test-unit
56+
57+
integration:
58+
runs-on: ubuntu-latest
59+
needs:
60+
- lint
61+
- unit
62+
strategy:
63+
fail-fast: false
64+
matrix:
65+
include:
66+
- python-version: '3.8'
67+
moodle-image: erseco/alpine-moodle:v4.5.5
68+
moodle-label: Moodle 4.5.5
69+
moodle-cache-key: moodle-4-5-5
70+
run-examples: false
71+
- python-version: '3.13'
72+
moodle-image: erseco/alpine-moodle:v5.0.1
73+
moodle-label: Moodle 5.0.1
74+
moodle-cache-key: moodle-5-0-1
75+
run-examples: true
76+
77+
steps:
78+
- name: Checkout code
79+
uses: actions/checkout@v4
80+
81+
- name: Set up Python
82+
uses: actions/setup-python@v5
83+
with:
84+
python-version: ${{ matrix.python-version }}
85+
cache: 'pip'
86+
87+
- name: Install dependencies
88+
run: python -m pip install -e ".[dev]"
89+
3690
- name: Cache Docker images
3791
uses: actions/cache@v5
3892
with:
39-
path: /tmp/docker-cache
40-
key: ${{ runner.os }}-docker-${{ hashFiles('docker-compose.yml') }}
93+
path: /tmp/docker-cache/${{ matrix.moodle-cache-key }}
94+
key: ${{ runner.os }}-docker-${{ matrix.moodle-cache-key }}-${{ hashFiles('docker-compose.yml') }}
4195

4296
- name: Load cached Docker images
4397
run: |
44-
if [ -f /tmp/docker-cache/postgres.tar ]; then docker load -i /tmp/docker-cache/postgres.tar; fi
45-
if [ -f /tmp/docker-cache/moodle.tar ]; then docker load -i /tmp/docker-cache/moodle.tar; fi
98+
if [ -f /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar ]; then
99+
docker load -i /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar
100+
fi
101+
if [ -f /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar ]; then
102+
docker load -i /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar
103+
fi
46104
47-
- name: Start Moodle with Docker Compose (in backgroud)
48-
run: make upd
105+
- name: Start ${{ matrix.moodle-label }} with Docker Compose
106+
run: MOODLE_DOCKER_IMAGE="${{ matrix.moodle-image }}" make upd
49107

50108
- name: Run tests
51-
run: make test
109+
run: make test-local
52110

53111
- name: Run example_script.py
112+
if: matrix.run-examples
54113
run: python example_script.py
55114

56115
- name: Save Docker images to cache
57116
if: always()
58117
run: |
59-
mkdir -p /tmp/docker-cache
60-
docker save postgres:alpine -o /tmp/docker-cache/postgres.tar
61-
docker save erseco/alpine-moodle:v4.5.5 -o /tmp/docker-cache/moodle.tar
62-
118+
mkdir -p /tmp/docker-cache/${{ matrix.moodle-cache-key }}
119+
docker save postgres:16-alpine -o /tmp/docker-cache/${{ matrix.moodle-cache-key }}/postgres.tar
120+
docker save "${{ matrix.moodle-image }}" -o /tmp/docker-cache/${{ matrix.moodle-cache-key }}/moodle.tar

Makefile

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ENV_FILE=.env
22

3-
.PHONY: ensure-env check-docker up format lint docs docs-generate test test-local test-staging
3+
.PHONY: ensure-env check-docker up format lint docs docs-generate test test-unit test-local test-staging
44

55
ensure-env:
66
@if [ ! -f $(ENV_FILE) ]; then cp .env.example $(ENV_FILE); fi
@@ -15,13 +15,19 @@ up: check-docker ensure-env
1515
upd: check-docker ensure-env
1616
docker compose up -d
1717
@echo "Waiting for Moodle to be ready..."
18-
@for i in $$(seq 1 60); do \
19-
if curl -s --head http://localhost | grep "200 OK" > /dev/null; then \
18+
@ready=0; \
19+
for i in $$(seq 1 60); do \
20+
if curl -fsSL http://localhost/login/index.php > /dev/null; then \
2021
echo "Moodle is up!"; \
22+
ready=1; \
2123
break; \
2224
fi; \
2325
sleep 5; \
24-
done
26+
done; \
27+
if [ $$ready -ne 1 ]; then \
28+
echo "Moodle did not become ready in time."; \
29+
exit 1; \
30+
fi
2531

2632
format:
2733
black .
@@ -36,11 +42,14 @@ docs:
3642
python -m typer py_moodle.cli.app utils docs --output docs/cli.md --name py-moodle
3743
mkdocs build --strict
3844

45+
test-unit:
46+
pytest tests/unit
47+
3948
test-local: ensure-env
40-
pytest --moodle-env local -n auto
49+
pytest --integration --moodle-env local -m integration -n auto
4150

4251
test-staging: ensure-env
43-
pytest --moodle-env staging -n auto
52+
pytest --integration --moodle-env staging -m integration -n auto
4453

4554
test: upd test-local
4655

@@ -63,6 +72,7 @@ help:
6372
@echo " docs - Build documentation with mkdocs"
6473
@echo ""
6574
@echo "Testing:"
75+
@echo " test-unit - Run fast smoke tests that do not require Moodle"
6676
@echo " test-local - Run local tests (in parallel) using pytest with moodle-env=local"
6777
@echo " test-staging - Run tests (in parallel) using moodle-env=staging"
6878
@echo " test - Start containers (detached) and run local tests"

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/erseco/python-moodle/blob/main/LICENSE)
88
[![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
9+
[![CI](https://github.com/erseco/python-moodle/actions/workflows/ci.yml/badge.svg)](https://github.com/erseco/python-moodle/actions/workflows/ci.yml)
910
[![PyPI downloads](https://img.shields.io/pypi/dm/python-moodle)](https://pypi.org/project/python-moodle/)
1011
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
1112
[![GitHub repository](https://img.shields.io/badge/github-repository-blue)](https://github.com/erseco/python-moodle)
@@ -191,7 +192,13 @@ This script is the best starting point for understanding how to use the library'
191192

192193
The project uses `pytest` and provides a `Makefile` with convenient targets.
193194

194-
Run the default test suite against the local environment:
195+
Run the fast smoke test suite (no Moodle service required):
196+
197+
```bash
198+
make test-unit
199+
```
200+
201+
Run the Docker-backed integration suite against the local environment:
195202

196203
```bash
197204
make test-local
@@ -209,6 +216,14 @@ Run all configured environments:
209216
make test
210217
```
211218

219+
GitHub Actions automatically runs:
220+
221+
- linting on Python 3.13
222+
- smoke tests on Python 3.8 through 3.13
223+
- Docker-backed integration tests on representative Python/Moodle combinations:
224+
- Python 3.8 with Moodle 4.5.5
225+
- Python 3.13 with Moodle 5.0.1
226+
212227
## Development
213228

214229
Use the Makefile to format code, run linters, or build the documentation:

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
services:
33

44
postgres:
5-
image: postgres:alpine
5+
image: postgres:16-alpine
66
restart: unless-stopped
77
environment:
88
- POSTGRES_PASSWORD=moodle
@@ -12,7 +12,7 @@ services:
1212
- postgres:/var/lib/postgresql/data
1313

1414
moodle:
15-
image: erseco/alpine-moodle:v4.5.5
15+
image: ${MOODLE_DOCKER_IMAGE:-erseco/alpine-moodle:v4.5.5}
1616
restart: unless-stopped
1717
environment:
1818
DEBUG: true

pytest.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ addopts = -ra -q
44
testpaths = tests
55
python_files = test_*.py
66
pythonpath = src
7+
markers =
8+
integration: tests that require a live Moodle instance

src/py_moodle/course.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
# src/moodle/course.py
21
"""
32
Course management module for Moodle.
43
54
Provides functions to list courses, retrieve course details,
65
and enumerate course sections using AJAX endpoints.
76
"""
87

8+
from __future__ import annotations
9+
910
import json
1011
import time
1112
import urllib.parse

src/py_moodle/folder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# src/moodle/folder.py
21
"""
32
Folder module management for Moodle CLI.
43
@@ -9,6 +8,8 @@
98
All code and comments are in English.
109
"""
1110

11+
from __future__ import annotations
12+
1213
import json
1314
import re
1415
import time

src/py_moodle/module.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
# src/moodle/module.py
21
"""
32
Generic Moodle module management helpers.
43
All code and comments are in English.
54
"""
65

6+
from __future__ import annotations
7+
78
import json
89
import re
910
import time

src/py_moodle/session.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
# src/moodle/session.py
21
"""Reusable, thread-safe Moodle session.
32
43
Lazy login on first access and cache sessions per environment.
54
"""
65

6+
from __future__ import annotations
7+
78
import threading
89
from typing import TYPE_CHECKING
910

0 commit comments

Comments
 (0)