Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 0 additions & 3 deletions .flake8

This file was deleted.

32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ jobs:
ruff check src/ tests/
continue-on-error: true

- name: Type check with ty (non-blocking)
run: |
ty check src/
continue-on-error: true

security:
name: Security Scan
runs-on: ubuntu-latest
Expand Down Expand Up @@ -148,3 +153,30 @@ jobs:
sarif_file: bandit-report.sarif
category: bandit
continue-on-error: true

docs-reference-sync:
name: API Reference In Sync
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0

- name: Set up uv
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5.2.2

- name: Regenerate the quartodoc API reference
run: |
uv run python docs/quartodoc_build.py
uv run quartodoc interlinks

- name: Fail if committed docs/reference is stale
run: |
if ! git diff --exit-code -- docs/reference/; then
echo "::error::docs/reference is out of sync with quartodoc. Run 'uv run python docs/quartodoc_build.py && uv run quartodoc interlinks' locally and commit the result."
exit 1
fi
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [6.1.0-rc.1](https://github.com/sequential-parameter-optimization/spotforecast2/compare/v6.0.0...v6.1.0-rc.1) (2026-06-08)

### Features

* **deps:** support spotforecast2-safe 20.x ([40654f4](https://github.com/sequential-parameter-optimization/spotforecast2/commit/40654f4b19df647441b7822f21c8d967353d2c1e))

## [6.0.0](https://github.com/sequential-parameter-optimization/spotforecast2/compare/v5.2.0...v6.0.0) (2026-06-07)

### ⚠ BREAKING CHANGES
Expand Down
2 changes: 1 addition & 1 deletion REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ SPDX-PackageSupplier = "bartzbeielstein <32470350+bartzbeielstein@users.noreply.
SPDX-PackageDownloadLocation = "https://github.com/sequential-parameter-optimization/spotforecast2"

[[annotations]]
path = [".flake8", ".gitignore", ".python-version", ".releaserc.json", ".semantic-release-init", "mkdocs.yml", "package-lock.json", "package.json", "pyproject.toml", "uv.lock"]
path = [".gitignore", ".python-version", ".releaserc.json", ".semantic-release-init", "mkdocs.yml", "package-lock.json", "package.json", "pyproject.toml", "uv.lock"]
precedence = "aggregate"
SPDX-FileCopyrightText = "2026 bartzbeielstein"
SPDX-License-Identifier = "AGPL-3.0-or-later"
Expand Down
22 changes: 19 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "spotforecast2"
version = "6.0.0"
version = "6.1.0-rc.1"
description = "Forecasting with spot"
readme = "README.md"
license = { text = "AGPL-3.0-or-later" }
Expand All @@ -15,7 +15,6 @@ dependencies = [
"astral>=3.2",
"entsoe-py>=0.7.10",
"feature-engine>=1.9.3",
"flake8>=7.3.0",
"holidays>=0.90",
"ipykernel>=7.1.0",
"jinja2>=3.1",
Expand All @@ -32,7 +31,7 @@ dependencies = [
"ruff>=0.15.6",
"scikit-learn>=1.8.0",
"shap>=0.49.1",
"spotforecast2-safe>=19.0.0,<20",
"spotforecast2-safe>=19.0.0,<21",
"spotoptim>=0.12.9",
"tqdm>=4.67.2",
]
Expand All @@ -47,6 +46,7 @@ dev = [
"quartodoc>=0.7.2",
"pytest>=9.0.2",
"pytest-anyio>=0.0.0",
"ty>=0.0.29",
]

[project.optional-dependencies]
Expand All @@ -59,6 +59,7 @@ dev = [
"quartodoc>=0.7.2",
"safety>=3.0.0",
"bandit[sarif]>=1.8.0",
"ty>=0.0.29",
]

[project.scripts]
Expand Down Expand Up @@ -97,6 +98,21 @@ profile = "black"
line-length = 88
target-version = "py313"

[tool.coverage.run]
branch = true
source = ["src/spotforecast2"]

[tool.coverage.report]
# Ratchet: lock in the current ~65% coverage (measured locally) so it cannot
# regress; 60 leaves margin for platform variance on CI. Raise deliberately as
# coverage improves. CI runs pytest with --cov, enforcing this.
fail_under = 60

# Astral `ty` type checker. Run non-blocking in CI (continue-on-error) so it
# surfaces type debt without failing the build; tighten to a gate later.
[tool.ty.environment]
python-version = "3.13"

# [tool.uv.sources]
# Local editable installs — use the sibling checkouts instead of PyPI:
# spotforecast2-safe = { path = "../spotforecast2-safe", editable = true }
Expand Down
33 changes: 27 additions & 6 deletions tests/test_cv_block_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,27 @@ def _skl_cv(
)


class _HideAttr:
"""Proxy delegating to a wrapped object but hiding one attribute.

Recreates the "config never declared this field" path. Since
spotforecast2-safe >= 19.1 ConfigMulti is a dataclass, every field default
is also a *class* attribute, so deleting the instance attribute is no longer
enough to make ``hasattr`` / the ``getattr(..., default)`` fallback see it as
absent. This proxy makes the chosen attribute genuinely raise
``AttributeError``, mirroring an older or third-party ``PipelineConfig``.
"""

def __init__(self, wrapped: object, hidden: str) -> None:
self._wrapped = wrapped
self._hidden = hidden

def __getattr__(self, name: str) -> object:
if name == self._hidden:
raise AttributeError(name)
return getattr(self._wrapped, name)


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -126,12 +147,12 @@ class TestCvBlockSizeFallback:
def test_steps_equal_predict_size_when_attr_absent(self, tmp_path, y_train):
task = _make_task(tmp_path, predict_size=32)
# Exercise the getattr-absent fallback in cv_ts: a config that does not
# declare cv_block_size at all must fall back to predict_size. Newer
# spotforecast2-safe ConfigMulti declares the field (default None), so
# delete it from the instance to recreate the "attribute absent" path
# the getattr fallback is written for.
if hasattr(task.config, "cv_block_size"):
delattr(task.config, "cv_block_size")
# declare cv_block_size at all must fall back to predict_size. The
# dataclass ConfigMulti (spotforecast2-safe >= 19.1) always exposes the
# field as a class attribute (default None), so deleting the instance
# attribute is not enough — wrap the config so the attribute is genuinely
# absent, mirroring an older / third-party PipelineConfig.
task.config = _HideAttr(task.config, "cv_block_size")
assert not hasattr(task.config, "cv_block_size")
assert task.cv_ts(y_train).steps == task.config.predict_size == 32

Expand Down
17 changes: 9 additions & 8 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.