From dbbea1a95fb11e5e0187b5bbb1ca05c04abb8f7e Mon Sep 17 00:00:00 2001 From: Kemal Yaylali Date: Sat, 15 Aug 2026 20:45:02 +0100 Subject: [PATCH] chore: enforce ruff config and fix lint findings --- .github/workflows/ci.yml | 5 +++++ ashvale/estimation.py | 1 - ashvale/features.py | 10 ++++++++-- ashvale/led.py | 3 +-- ashvale/models/__init__.py | 8 ++++---- ashvale/models/climatology.py | 4 ++-- ashvale/models/precip.py | 2 +- ashvale/sensors.py | 1 - ashvale/station.py | 3 +-- pyproject.toml | 5 ++++- scripts/evaluate.py | 12 +++++++----- scripts/simulate.py | 14 +++++++++----- 12 files changed, 42 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48fea56..a6f7b20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,11 @@ jobs: pip install -r requirements.txt pip install httpx + - name: Lint + run: | + pip install ruff + ruff check . + - name: Byte-compile every module run: python -m compileall -q ashvale scripts run.py diff --git a/ashvale/estimation.py b/ashvale/estimation.py index 3498509..2a10019 100644 --- a/ashvale/estimation.py +++ b/ashvale/estimation.py @@ -30,7 +30,6 @@ Two jobs here, both familiar from soft-sensor work: from __future__ import annotations -import math from dataclasses import dataclass, field from typing import Dict, Optional diff --git a/ashvale/features.py b/ashvale/features.py index 9ba0769..f1e1cd9 100644 --- a/ashvale/features.py +++ b/ashvale/features.py @@ -32,8 +32,14 @@ from typing import Dict, List, Tuple import numpy as np -from .physics import (absolute_humidity, clear_sky_irradiance, dew_point, - solar_position, vapour_pressure_deficit, wet_bulb) +from .physics import ( + absolute_humidity, + clear_sky_irradiance, + dew_point, + solar_position, + vapour_pressure_deficit, + wet_bulb, +) FEATURE_NAMES: List[str] = [ "bias", diff --git a/ashvale/led.py b/ashvale/led.py index 757500e..fe41083 100644 --- a/ashvale/led.py +++ b/ashvale/led.py @@ -34,8 +34,7 @@ matters. from __future__ import annotations import asyncio -import time -from typing import Dict, List, Sequence, Tuple +from typing import List, Sequence, Tuple OFF = (0, 0, 0) diff --git a/ashvale/models/__init__.py b/ashvale/models/__init__.py index e06fa91..a5f22d3 100644 --- a/ashvale/models/__init__.py +++ b/ashvale/models/__init__.py @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .rls import RecursiveLeastSquares, AdaptiveConformal -from .nowcast import NowcastEnsemble -from .climatology import HarmonicClimatology -from .precip import PrecipitationModel, zambretti from .anomaly import AnomalyMonitor +from .climatology import HarmonicClimatology +from .nowcast import NowcastEnsemble +from .precip import PrecipitationModel, zambretti +from .rls import AdaptiveConformal, RecursiveLeastSquares __all__ = [ "RecursiveLeastSquares", "AdaptiveConformal", "NowcastEnsemble", diff --git a/ashvale/models/climatology.py b/ashvale/models/climatology.py index 76e155b..eca0ed9 100644 --- a/ashvale/models/climatology.py +++ b/ashvale/models/climatology.py @@ -141,9 +141,9 @@ class HarmonicClimatology: sigma0 = self.resid_std.get(target, 1.0) sigma = sigma0 * np.sqrt(1.0 + lead_h / 24.0) return [ - {"ts": float(t), "lead_h": float(l), "mu": float(m), + {"ts": float(t), "lead_h": float(lh), "mu": float(m), "lo": float(m - 1.645 * s), "hi": float(m + 1.645 * s)} - for t, l, m, s in zip(grid, lead_h, mu, sigma) + for t, lh, m, s in zip(grid, lead_h, mu, sigma) ] def anomaly_now(self, target: str, ts: float, observed: float) -> float: diff --git a/ashvale/models/precip.py b/ashvale/models/precip.py index 31bb1b8..6e202be 100644 --- a/ashvale/models/precip.py +++ b/ashvale/models/precip.py @@ -39,7 +39,7 @@ from __future__ import annotations import math import time -from typing import Dict, List, Optional, Tuple +from typing import Dict, List, Optional import numpy as np diff --git a/ashvale/sensors.py b/ashvale/sensors.py index 73971f0..4004574 100644 --- a/ashvale/sensors.py +++ b/ashvale/sensors.py @@ -25,7 +25,6 @@ same code to the Pi unchanged. from __future__ import annotations import math -import random import time from typing import Any, Dict, Optional diff --git a/ashvale/station.py b/ashvale/station.py index 55ea5f5..1431026 100644 --- a/ashvale/station.py +++ b/ashvale/station.py @@ -34,7 +34,6 @@ from __future__ import annotations import asyncio import json -import math import time from pathlib import Path from typing import Any, Dict, List, Optional @@ -44,7 +43,7 @@ import numpy as np from . import physics from .config import Config from .estimation import SignalTracker -from .features import N_FEATURES, build_features +from .features import build_features from .models.anomaly import AnomalyMonitor from .models.climatology import HarmonicClimatology from .models.nowcast import NowcastEnsemble diff --git a/pyproject.toml b/pyproject.toml index 7f118f6..032d565 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,5 +77,8 @@ line-length = 100 target-version = "py39" [tool.ruff.lint] -select = ["E", "F", "W", "I", "UP", "B"] +# UP is deliberately absent. With target-version = "py39" it fights the +# `from __future__ import annotations` style used throughout and generates +# several hundred findings for no behavioural gain. B currently finds nothing. +select = ["E", "F", "W", "I"] ignore = ["E501"] diff --git a/scripts/evaluate.py b/scripts/evaluate.py index 927fcc9..bbdfafc 100644 --- a/scripts/evaluate.py +++ b/scripts/evaluate.py @@ -47,11 +47,11 @@ import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) -from ashvale.config import load_config # noqa: E402 -from ashvale.features import build_features # noqa: E402 +from ashvale.config import load_config # noqa: E402 +from ashvale.features import build_features # noqa: E402 from ashvale.models.climatology import HarmonicClimatology # noqa: E402 -from ashvale.models.nowcast import NowcastEnsemble # noqa: E402 -from ashvale.storage import Store, resample # noqa: E402 +from ashvale.models.nowcast import NowcastEnsemble # noqa: E402 +from ashvale.storage import Store, resample # noqa: E402 def horizon_label(seconds: int) -> str: @@ -163,7 +163,9 @@ def main() -> None: f"{r['bias']:>+8.3f} {r['weights']}{flag}") print() - print(f"units: temperature C, humidity %, pressure hPa") + # Driven off the dict rather than hardcoded, so adding a target cannot leave + # the units line silently describing the wrong columns. + print("units: " + ", ".join(f"{t} {units[t]}" for t in cfg.model.targets if t in units)) print("coverage should sit near 90% if the conformal calibration is honest.") diff --git a/scripts/simulate.py b/scripts/simulate.py index 3a4f33b..ec50e17 100644 --- a/scripts/simulate.py +++ b/scripts/simulate.py @@ -50,11 +50,15 @@ import numpy as np sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) -from ashvale.config import load_config # noqa: E402 -from ashvale.estimation import SignalTracker # noqa: E402 -from ashvale.physics import (dew_point, sea_level_pressure, # noqa: E402 - solar_position, clear_sky_irradiance) -from ashvale.storage import Store # noqa: E402 +from ashvale.config import load_config # noqa: E402 +from ashvale.estimation import SignalTracker # noqa: E402 +from ashvale.physics import ( # noqa: E402 + clear_sky_irradiance, + dew_point, + sea_level_pressure, + solar_position, +) +from ashvale.storage import Store # noqa: E402 def generate(days: float, step_s: int, lat: float, lon: float,