#!/usr/bin/env python3 """test_last_full_moon.py — run the full moon pipeline for the most recent full moon. Identical to `moon-phase-monthly.sh --phase full --no-upload` except the output is written to test_last_full_moon_out.jpg in the sky-cam directory instead of the normal movies tree. Includes east-frame detection, dark-window filtering, NASA Dial-a-Moon fetch, and render_phase_closeup — the complete production path. Also calls sun_events_in_range() explicitly as a regression check for the sunrise_sunset() bare-topos fix. Run from the sky-cam directory: python3 test_last_full_moon.py """ import sys import pathlib from datetime import datetime, timedelta, timezone HERE = pathlib.Path(__file__).resolve().parent sys.path.insert(0, str(HERE)) OUT_PATH = HERE / 'test_last_full_moon_out.jpg' def main() -> int: import moon_phase as mp import moon_phase_monthly as mpm # ── Regression check: sun_events_in_range() (bare-topos fix) ───────────── now = datetime.now(timezone.utc) candidates = mp.full_moons_in_range(now - timedelta(days=35), now) if not candidates: print("ERROR: no full moon found in the last 35 days", file=sys.stderr) return 1 fm = candidates[-1] day_start = fm.replace(hour=0, minute=0, second=0, microsecond=0) events = mp.sun_events_in_range(day_start, day_start + timedelta(days=1)) print(f"sun events on {day_start.strftime('%Y-%m-%d')} UTC (topos fix check):") for t, is_rise in events: print(f" {'sunrise' if is_rise else 'sunset '} {t.strftime('%H:%M:%S')} UTC") print() # ── Full production pipeline ────────────────────────────────────────────── return mpm.run_phase( phase='full', target_utc=fm, cam=mpm.SUNRISE_CAM, dry_run=False, no_upload=True, out_path=str(OUT_PATH), ) if __name__ == "__main__": sys.exit(main())