From b8b8301921f5d26a07d42343de9783bad12a2cf5 Mon Sep 17 00:00:00 2001 From: Karl Waldman Date: Sun, 23 Aug 2026 09:36:07 -0400 Subject: [PATCH 1/2] =?UTF-8?q?release:=201.13.0=20=E2=80=94=20get=5Fmulti?= =?UTF-8?q?ple=20batches=20(api#7240)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minor rather than patch, deliberately. The public signature is unchanged, so strict semver would call this a patch — but it materially changes how many HTTP requests a call makes, and a minor keeps it out of tight pins like ~=1.12.8 while staying available to ~=1.12. Anyone on a narrow pin opts in rather than being surprised by a changed request pattern. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01JKAExynd9zoKwt6rYA66EA --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ oilpriceapi/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db8764d..4a68882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ All notable changes to the OilPriceAPI Python SDK will be documented in this file. +## [1.13.0] - 2026-08-23 + +### Fixed + +- **`get_multiple()` now batches — up to 20 codes per request instead of one + request per code.** The REST API accepts 20 commodity codes in a single + request that counts **once** against quota, so the method whose purpose is + fetching several prices previously cost up to **20x more quota than writing + the call by hand**. Through it the free plan was 50 code-reads a day; through + the raw API it is 1,000. +- The same fix is applied to `AsyncPricesResource.get_multiple()`, which was + worse: `asyncio.gather` fanned out one request **per code** concurrently, + which could also trip the 60-per-60-second rate limit on a long list. Chunks + are still gathered concurrently, so 25 codes cost 2 requests rather than 25. + +### Changed + +- **Your quota consumption will drop.** This is in your favour and requires no + code change, but it is a behaviour change: a `get_multiple()` call that + previously consumed N requests now consumes `ceil(N / 20)`. +- The per-code failure contract is unchanged. Because the API rejects the whole + request when any code in it is unknown, a failed batch is retried per code — + for that chunk only — so `return_failures=True` still reports exactly which + code was at fault. + +### Documentation + +- Polling examples now default to an interval that fits the free plan + (30 minutes), with a plan/interval table and the measured update cadence of + the underlying data. Nothing we publish moves faster than about every + 2.5 minutes, so a shorter timer returns the same number. + ## [1.12.8] - 2026-08-12 ### Fixed diff --git a/oilpriceapi/version.py b/oilpriceapi/version.py index 3e3d79c..f5d9dd8 100644 --- a/oilpriceapi/version.py +++ b/oilpriceapi/version.py @@ -5,6 +5,6 @@ Used in __init__.py, client.py, and async_client.py. """ -__version__ = "1.12.8" +__version__ = "1.13.0" SDK_VERSION = __version__ SDK_NAME = "oilpriceapi-python" diff --git a/pyproject.toml b/pyproject.toml index 5e2b118..62fa9cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" [project] name = "oilpriceapi" -version = "1.12.8" +version = "1.13.0" description = "Official Python SDK for source-timestamped OilPriceAPI energy data" authors = [ {name = "OilPriceAPI", email = "support@oilpriceapi.com"} From 926d4045f1f77a4217892d06953aefaa47fddeb4 Mon Sep 17 00:00:00 2001 From: Karl Waldman Date: Sun, 23 Aug 2026 09:37:02 -0400 Subject: [PATCH 2/2] test: version guard reads pyproject instead of a hard-coded literal test_package_version_helper_reads_the_project_version asserted the literal '1.12.8', so it failed on this release for a reason unrelated to what it guards. Its job is 'does the helper report the PROJECT version', not 'is the version 1.12.8'. Now reads the expected value from pyproject.toml, so it keeps testing the helper and stops needing a hand-edit every release. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01JKAExynd9zoKwt6rYA66EA --- tests/test_release_readiness.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_release_readiness.py b/tests/test_release_readiness.py index dd12ef9..e1aa1ba 100644 --- a/tests/test_release_readiness.py +++ b/tests/test_release_readiness.py @@ -170,7 +170,13 @@ def test_package_version_helper_reads_the_project_version() -> None: capture_output=True, text=True, ) - assert result.stdout.strip() == "1.12.8" + # Read the expected value from pyproject rather than hard-coding it. The + # helper's job is "does it report the PROJECT version", not "is the version + # 1.12.8" — pinning the literal made this test fail on every release for a + # reason unrelated to what it guards. + pyproject = (ROOT / "pyproject.toml").read_text() + expected = re.search(r'^version = "([^"]+)"', pyproject, re.M).group(1) + assert result.stdout.strip() == expected def test_every_workflow_pins_actions_and_hardens_each_checkout_step() -> None: