Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
fd8ef2c
Add a golden-master replay harness for the exposure controller
ekstremedia Jul 27, 2026
9216980
Turn src/ into a raspilapse package and delete the dual-import idiom
ekstremedia Jul 27, 2026
794aee0
Make the optional dependencies optional, and shrink the install to th…
ekstremedia Jul 27, 2026
7cbfd08
Make the overlay optional in fact, and fix what turning it off broke
ekstremedia Jul 27, 2026
12b4256
Give the config defaults in code, and cut the example from 681 lines …
ekstremedia Jul 27, 2026
2080066
Break the 287-line capture loop into named steps
ekstremedia Jul 27, 2026
4f65468
Replace day/transition/night with one continuous exposure ladder
ekstremedia Jul 27, 2026
28499f0
Take the metering shot off every frame
ekstremedia Jul 27, 2026
a859818
Address review: one real bug in production diagnostics, and eight sma…
ekstremedia Jul 27, 2026
fcaedde
Document the functions that were missing an explanation, not the ones…
ekstremedia Jul 27, 2026
334c977
Explain the replay fixtures, and delete three that outlived their code
ekstremedia Jul 27, 2026
ec7767b
Review: reject saturated frames, and take Pillow as high as 3.9 allows
ekstremedia Jul 27, 2026
f1e1ad0
Split the aurora and tide widgets out of apply_overlay
ekstremedia Jul 27, 2026
9d23f02
Decompose the rest of apply_overlay, and commit the render check
ekstremedia Jul 27, 2026
2a5e00e
Split _prepare_overlay_data by source, and cover the field groups
ekstremedia Jul 27, 2026
0e5b1c5
Explain that a sequence's stored brightness is not what the controlle…
ekstremedia Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

**BEFORE SUBMITTING, VERIFY:**

- [ ] ✅ **Code formatted with Black** (`make format` or `black src/ tests/ --line-length=100`)
- [ ] ✅ **Code formatted with Black** (`make format` or `black raspilapse/ tests/ --line-length=100`)
- [ ] ✅ **All tests pass** (`make test` or `python3 -m pytest tests/ -v`)
- [ ] ✅ **Black check passes** (`make check` or `black --check src/ tests/`)
- [ ] ✅ **Black check passes** (`make check` or `black --check raspilapse/ tests/`)
- [ ] 📝 Code has docstrings and comments where needed
- [ ] 🧪 Added tests for new features (if applicable)
- [ ] 📖 Updated documentation (if needed)
Expand All @@ -40,5 +40,5 @@
**Did you format your code with Black?** ← Most common CI failure!

```bash
make format # or: black src/ tests/ --line-length=100
make format # or: black raspilapse/ tests/ --line-length=100
```
49 changes: 32 additions & 17 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ jobs:

- name: Lint with ruff
run: |
ruff check src/ scripts/ tests/
ruff check raspilapse/ scripts/ tests/

- name: Check code formatting with black
run: |
black --check src/ scripts/ tests/
black --check raspilapse/ scripts/ tests/

- name: Run tests with pytest
run: |
pytest tests/ -v --cov=src --cov-branch --cov-report=term-missing --cov-report=xml
pytest tests/ -v --cov=raspilapse --cov-branch --cov-report=term-missing --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
Expand Down Expand Up @@ -82,12 +82,16 @@ jobs:
python -m pip install --upgrade pip
pip install -r requirements-dev.txt

# Advisory. The dual-import idiom's `no-redef` suppression is gone, and
# verified to leave no no-redef errors behind, but ~60 pre-existing errors
# remain -- mostly Any leaking out of config.get(). Clearing those is a
# typing pass of its own, not part of the reorganisation.
- name: Type check with mypy
run: |
mypy src/ --ignore-missing-imports --no-strict-optional
mypy raspilapse/ --ignore-missing-imports --no-strict-optional
continue-on-error: true

compatibility-check:
install-check:
runs-on: ubuntu-latest

steps:
Expand All @@ -99,21 +103,32 @@ jobs:
with:
python-version: '3.11'

- name: Install dependencies
# This replaces a job that verified the flat `cd src && import x` half of
# the dual-import idiom, which no longer exists. What matters now is that a
# fresh install works and the console scripts resolve.
- name: Install the package
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -e .

- name: Check for syntax errors
- name: Verify every module imports
run: |
python -m py_compile src/*.py scripts/*.py tests/*.py

- name: Verify modules import the way systemd runs them
python - <<'PY'
import importlib, pkgutil, raspilapse
failed = []
for module in pkgutil.walk_packages(raspilapse.__path__, "raspilapse."):
try:
importlib.import_module(module.name)
except Exception as error:
failed.append(f"{module.name}: {error}")
for line in failed:
print("FAIL", line)
raise SystemExit(1 if failed else 0)
PY

- name: Verify every console script resolves
run: |
# The units run `python3 src/auto_timelapse.py`, so sys.path[0] is src/
# and the flat half of the dual-import idiom is what production uses.
# Importing as `src.x` in CI would never exercise that path.
cd src
for module in logging_config config_utils colors exposure weather database; do
python -c "import $module" && echo "ok $module"
for script in capture status snapshot timelapse daily overlay db retry-uploads; do
command -v "raspilapse-$script" >/dev/null || { echo "missing raspilapse-$script"; exit 1; }
echo "ok raspilapse-$script"
done
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ line length 100 (enforced by black and ruff via `pyproject.toml`).

| Path | Contents |
|------|----------|
| `src/` | Application code. Every module is importable both as `src.x` and as bare `x` — the systemd units run scripts directly, so `sys.path[0]` is `src/`. |
| `raspilapse/` | Application code, grouped by what it talks to: `camera/`, `overlay/`, `video/`, `storage/`, `cli/`. One import path per module — the units run `python3 -m raspilapse.cli.x` from the project directory. |
| `scripts/` | Installer and operator tools (shell + standalone Python) |
| `systemd/` | Unit templates (`*.in`, substituted by `scripts/install.sh`) |
| `config/` | `config.example.yml` is the documented schema; `config.yml` is gitignored |
| `tests/` | pytest suite, one module per `src/` module (`__version__.py` is covered by `test_version.py`) |
| `config/` | `config.example.yml` is a short starter file; `docs/CONFIG-REFERENCE.yml` is the full schema; `config.yml` is gitignored |
| `tests/` | pytest suite, one module per application module (`__version__.py` is covered by `test_version.py`) |
| `tests/replay/` | Recorded sunsets, and what the exposure code decided about them — 3.8 MB of JSON that [its README](tests/replay/README.md) explains. Read that before touching a golden file. |
| `docs/` | User documentation |

Never commit `config/config.yml` — it holds API keys. `.gitignore` covers it,
Expand All @@ -62,7 +63,7 @@ but check `git status` before you push.

Maintainers only.

1. `src/__version__.py` is the single source of truth for the version.
1. `raspilapse/__version__.py` is the single source of truth for the version.
`pyproject.toml` reads it dynamically; update `CITATION.cff` by hand.
2. Add a `CHANGELOG.md` entry under a new `## [x.y.z]` heading.
`tests/test_version.py` asserts these two agree.
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ help:

format:
@echo "🎨 Formatting code with Black..."
black src/ scripts/ tests/
black raspilapse/ scripts/ tests/

check:
@echo "✅ Checking code formatting..."
black --check src/ scripts/ tests/
black --check raspilapse/ scripts/ tests/

test:
@echo "🧪 Running tests..."
python3 -m pytest tests/ -v

test-cov:
@echo "📊 Running tests with coverage..."
python3 -m pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml
python3 -m pytest tests/ -v --cov=raspilapse --cov-report=term-missing --cov-report=xml

lint:
@echo "🔍 Linting code..."
ruff check src/ scripts/ tests/
ruff check raspilapse/ scripts/ tests/

all: format lint check test
@echo "✅ All checks passed! Ready to commit."
Expand Down
Loading
Loading