From c14c8e12c18645df939e3060e6f56d019b68ba5f Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 7 Aug 2026 12:04:49 +0200 Subject: [PATCH 1/3] Declare limits as a direct dependency flexmeasures/utils/validation_utils.py imports `limits` directly (to validate rate limits with limits.parse), but PR #2306 only declared Flask-Limiter. `limits` therefore reached us as a transitive dependency of Flask-Limiter, which works today but is not something we should rely on: nothing stops Flask-Limiter from dropping or renaming that dependency, and it makes `uv sync --no-deps`-style or vendored installs fragile. So declare it explicitly, with Flask-Limiter's own floor (>=3.13), since we only use the long-standing limits.parse. The lock file already contained `limits` (5.8.0) as a transitive entry, so the lock change is just the new edge from flexmeasures to it; no resolved version changes. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JEvWAj45zXaod5WjniF81D Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 1 + pyproject.toml | 4 ++++ uv.lock | 2 ++ 3 files changed, 7 insertions(+) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index d3b8c58963..54f482f7d0 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -53,6 +53,7 @@ New features Infrastructure / Support ---------------------- +* Declare ``limits`` as a direct dependency, as we import it ourselves to validate rate limits, rather than relying on it arriving as a dependency of ``Flask-Limiter`` [see `PR #2404 `_] * The database migration for this release splits each stored flex-context's ``inflexible-device-sensors`` field into ``inflexible-consumption``/``inflexible-production`` sensor references, classifying each sensor by its ``consumption_is_positive`` attribute (behavior-preserving; sensor attributes themselves are kept). Downgrading merges them back into bare sensor IDs, dropping any source filters added in the meantime [see `PR #2358 `_] * Speed up listing assets: eager-load each asset's sensors instead of lazy-loading them one query per asset during serialization, and skip loading sensors entirely for field-filtered responses that do not include them [see `PR #2363 `_] * Speed up scheduling jobs by building the scheduling problem directly with the HiGHS Python API (``highspy``), bypassing Pyomo's model construction and solution-ingestion overhead (roughly a second for a single-device job, and several seconds for multi-device jobs); this direct backend is the new default for the ``FLEXMEASURES_LP_SOLVER`` setting (``"highspy"``), while any Pyomo-based solver (e.g. the previous default ``"appsi_highs"``, or ``"cbc"``) remains available as before [see `PR #2364 `_] diff --git a/pyproject.toml b/pyproject.toml index 61d91045f7..2e80ddb781 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,10 @@ dependencies = [ "flask-swagger-ui>=5.21.0", # Note: the redis extra (used for rate-limit storage) currently pins redis<8 "Flask-Limiter[redis]>=4.0", + # Flask-Limiter's rate-limit parser, which we also import directly (to validate rate limits), + # so we declare it rather than lean on it arriving transitively. + # The floor is Flask-Limiter's own, as we only use the long-standing limits.parse. + "limits>=3.13", "sentry-sdk[flask]>=2.52.0", "marshmallow>=3", # See GH#1450 (failing tests on older Python versions) diff --git a/uv.lock b/uv.lock index a469a3f6e0..b7030d2618 100644 --- a/uv.lock +++ b/uv.lock @@ -1254,6 +1254,7 @@ dependencies = [ { name = "iso8601", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "isodate", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "lightgbm", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, + { name = "limits", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "marshmallow", version = "3.26.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" }, { name = "marshmallow", version = "4.3.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (python_full_version >= '3.11' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, { name = "marshmallow-oneofschema", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" }, @@ -1378,6 +1379,7 @@ requires-dist = [ { name = "iso8601", specifier = ">=2.1.0" }, { name = "isodate", specifier = ">=0.7.2" }, { name = "lightgbm", specifier = ">=4.6.0" }, + { name = "limits", specifier = ">=3.13" }, { name = "marshmallow", specifier = ">=3" }, { name = "marshmallow", marker = "python_full_version < '3.11'", specifier = "~=3.0" }, { name = "marshmallow-oneofschema", specifier = ">=3.2.0" }, From e84886b5c621505c658912bfa474790a7778e2d0 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Fri, 7 Aug 2026 12:05:39 +0200 Subject: [PATCH 2/3] Point the changelog entry at the actual PR number Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01JEvWAj45zXaod5WjniF81D Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 54f482f7d0..00dd6674ef 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -53,7 +53,7 @@ New features Infrastructure / Support ---------------------- -* Declare ``limits`` as a direct dependency, as we import it ourselves to validate rate limits, rather than relying on it arriving as a dependency of ``Flask-Limiter`` [see `PR #2404 `_] +* Declare ``limits`` as a direct dependency, as we import it ourselves to validate rate limits, rather than relying on it arriving as a dependency of ``Flask-Limiter`` [see `PR #2407 `_] * The database migration for this release splits each stored flex-context's ``inflexible-device-sensors`` field into ``inflexible-consumption``/``inflexible-production`` sensor references, classifying each sensor by its ``consumption_is_positive`` attribute (behavior-preserving; sensor attributes themselves are kept). Downgrading merges them back into bare sensor IDs, dropping any source filters added in the meantime [see `PR #2358 `_] * Speed up listing assets: eager-load each asset's sensors instead of lazy-loading them one query per asset during serialization, and skip loading sensors entirely for field-filtered responses that do not include them [see `PR #2363 `_] * Speed up scheduling jobs by building the scheduling problem directly with the HiGHS Python API (``highspy``), bypassing Pyomo's model construction and solution-ingestion overhead (roughly a second for a single-device job, and several seconds for multi-device jobs); this direct backend is the new default for the ``FLEXMEASURES_LP_SOLVER`` setting (``"highspy"``), while any Pyomo-based solver (e.g. the previous default ``"appsi_highs"``, or ``"cbc"``) remains available as before [see `PR #2364 `_] From 53696588c0438484482309aba47b83418ddc09d1 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Thu, 13 Aug 2026 19:29:18 +0200 Subject: [PATCH 3/3] docs: append this PR to the rate limiting changelog entry Context: - Review: no entry of its own; just append the PR reference to the rate limiting entry Change: - Dropped the separate Infrastructure / Support entry and referenced this PR from the entry of #2306, which introduced the rate limiting this dependency serves Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 53f8e4393c..80dc8022c5 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -34,7 +34,7 @@ New features * Support multiple feeders to a shared storage [see `PR #2001 `_, `PR #2321 `_, `PR #2322 `_ and `PR #2325 `_] * Add support for intermediate power constraints on groups of devices, via a new ``group`` field in the storage flex-model [see `PR #2276 `_ and `issue #2092 `_] * In the UI, asset and sensor charts now render with Apache ECharts (canvas) by default, for much faster drawing and interaction on dense time series, while staying visually and functionally equivalent to the previous Vega-Lite charts, which remain available as a fallback via a toggle [see `PR #2234 `_ and `PR #2399 `_] -* The API is now rate-limited, with a generous default limit on all endpoints and a stricter limit on triggering schedules and forecasts (which only counts triggers we accepted). Limits are configurable, and can be set per organisation by putting its account on a plan, which hosts create with ``flexmeasures add plan`` and platform admins assign from the organisation's page in the UI; play servers are exempt, as they run simulations. See :ref:`plans-and-rate-limiting` [see `PR #2306 `_] +* The API is now rate-limited, with a generous default limit on all endpoints and a stricter limit on triggering schedules and forecasts (which only counts triggers we accepted). Limits are configurable, and can be set per organisation by putting its account on a plan, which hosts create with ``flexmeasures add plan`` and platform admins assign from the organisation's page in the UI; play servers are exempt, as they run simulations. See :ref:`plans-and-rate-limiting` [see `PR #2306 `_ and `PR #2407 `_] * New storage flex-model field ``operation-modes`` confines a device's power to one of several power bands, following the S2 standard's operation modes — for example, a device that is either off or running at one fixed power [see `PR #2278 `_] * Extended ``GET /api/v3_0/jobs/`` with a ``result`` field containing ``unresolved`` and ``resolved`` soft state-of-charge constraint analysis (``soc-minima``/``soc-maxima`` violations or satisfied constraints, keyed by asset ID) for scheduling jobs; both arrays are empty when no SoC constraints were defined [see `PR #2072 `_] * Extended the scheduling job ``result`` field with a ``num-beliefs`` field reporting the total number of beliefs (scheduled values) saved to the database [see `PR #2280 `_] @@ -72,6 +72,7 @@ New features Infrastructure / Support ---------------------- + * Support storing encrypted connection secrets on organisations and assets, including utility functions, encryption key configuration, CLI commands to set and delete secrets, and UI tables that show stored secret names and optional expiration times without exposing their values [see `PR #2236 `_] * Standardize job-trigger API responses to return ``202 Accepted`` and a canonical ``job`` field; legacy response fields such as ``schedule`` and ``forecast`` are preserved for backward-compatibility but marked deprecated with migration guidance in :ref:`api_background_jobs` [see `PR #2224 `_]. * Warn on startup when ``TRUSTED_HOSTS`` is unset, as that lets clients poison the URLs FlexMeasures generates, such as password reset links; the setting can now also be given as a comma-separated environment variable, and the ``development`` environment trusts loopback hosts by default (so reaching a development server by its LAN address or through a tunnel now means listing that host) [see `PR #2389 `_]