diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 0e87063318..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 `_] diff --git a/pyproject.toml b/pyproject.toml index 2b72e9aa3c..c53fe9f12a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,6 +82,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 154a248c74..dde8b79ff0 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" },