From 233e6c6064dc8132cc9d00542d90a90393ce2a03 Mon Sep 17 00:00:00 2001 From: nc9 Date: Tue, 26 May 2026 10:15:44 +1000 Subject: [PATCH] fix(client): add network_region to async get_market + signature-parity test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OEClient.get_market accepts network_region and threads it through to _async_get_market, but AsyncOEClient.get_market never did, so async users could not apply the same region filter sync users can. Same shape of bug as the unit_code parity gap PR #27 fixed for get_facility_data. Also adds tests/test_sync_async_parity.py — a parameterised inspect.signature check across the shared public surface (__init__, get_facilities, get_network_data, get_facility_data, get_market, get_current_user) so future sync/async kwargs cannot drift again without CI catching it. --- openelectricity/client.py | 5 +++- tests/test_sync_async_parity.py | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/test_sync_async_parity.py diff --git a/openelectricity/client.py b/openelectricity/client.py index 192c03e..8bd0675 100644 --- a/openelectricity/client.py +++ b/openelectricity/client.py @@ -701,13 +701,15 @@ async def get_market( date_start: datetime | None = None, date_end: datetime | None = None, primary_grouping: DataPrimaryGrouping | None = None, + network_region: str | None = None, ) -> TimeSeriesResponse: """Get market data for specified metrics.""" logger.debug( - "Getting market data for %s (metrics: %s, interval: %s)", + "Getting market data for %s (metrics: %s, interval: %s, region: %s)", network_code, metrics, interval, + network_region, ) await self._ensure_client() params = { @@ -716,6 +718,7 @@ async def get_market( "date_start": date_start.isoformat() if date_start else None, "date_end": date_end.isoformat() if date_end else None, "primary_grouping": primary_grouping, + "network_region": network_region, } # Remove None values params = {k: v for k, v in params.items() if v is not None} diff --git a/tests/test_sync_async_parity.py b/tests/test_sync_async_parity.py new file mode 100644 index 0000000..5ebc9ac --- /dev/null +++ b/tests/test_sync_async_parity.py @@ -0,0 +1,44 @@ +""" +Signature-parity tests for the sync and async clients. + +Public methods shared between :class:`OEClient` and :class:`AsyncOEClient` +should accept the same parameters. Drift like the missing ``unit_code`` on +``get_facility_data`` (issue #27) or the missing ``network_region`` on +``get_market`` should fail here next time it happens. +""" + +import inspect + +import pytest + +from openelectricity import AsyncOEClient, OEClient + +_SHARED_METHODS = [ + "__init__", + "get_facilities", + "get_network_data", + "get_facility_data", + "get_market", + "get_current_user", +] + + +@pytest.mark.parametrize("method_name", _SHARED_METHODS) +def test_sync_async_signature_parity(method_name: str) -> None: + sync_sig = inspect.signature(getattr(OEClient, method_name)) + async_sig = inspect.signature(getattr(AsyncOEClient, method_name)) + + def normalise(sig: inspect.Signature) -> dict[str, tuple[object, inspect._ParameterKind]]: + return {name: (p.default, p.kind) for name, p in sig.parameters.items() if name != "self"} + + sync_params = normalise(sync_sig) + async_params = normalise(async_sig) + + if sync_params != async_params: + sync_only = set(sync_params) - set(async_params) + async_only = set(async_params) - set(sync_params) + kind_or_default = {n for n in sync_params.keys() & async_params.keys() if sync_params[n] != async_params[n]} + pytest.fail( + f"signature drift on {method_name}: sync-only={sync_only or '{}'}, " + f"async-only={async_only or '{}'}, differs={kind_or_default or '{}'}" + )