From ca99bfa64954b68a29139c5123f4ecdfc2c60d65 Mon Sep 17 00:00:00 2001 From: Ian Duffy Date: Mon, 2 Nov 2026 01:29:42 +0000 Subject: [PATCH] fix(ENG-15482): show rate limits when the API leaves out a value The SDK sets each field that the API leaves out to None, so the "key in data" checks were always true. float(None) then stopped `cloudsmith check rates` with TypeError. Fixes CLOUDSMITH-CLI-1V Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + cloudsmith_cli/core/ratelimits.py | 10 +++++----- cloudsmith_cli/core/tests/test_ratelimits.py | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 cloudsmith_cli/core/tests/test_ratelimits.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ea81a12..3d2fc4735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - When the API or a proxy answers the SAML IdP request with an HTML page or a JSON value that is not an object, `cloudsmith auth` now shows "Failed to authenticate via SAML!" with the reason. Before this fix, the CLI stopped with a `JSONDecodeError` or an `AttributeError`. The 2FA code exchange and the SAML token refresh now also reject a response that is not a JSON object. The 2FA code exchange also rejects a response without an access token. - List commands that return no results now print `Results: 0 `, not `Results: 1-0 (0) of 0 (page: 1/1, ...)`. When the API response has no pagination headers, list commands print only the result count, not `of None`. - An API request no longer waits without a limit when the API host accepts the connection but does not reply. A request now fails when it cannot connect in 30 seconds, or when it gets no data for 90 seconds. The API CDN waits 60 seconds for the API, so the CLI does not stop a slow request before the CDN does. If a request fails, the CLI retries it up to 6 times by default (`--error-retry-max`). A POST request has only the 30-second connection timeout, because a retry after a read timeout can create a second entry. File uploads and downloads do not change. +- `cloudsmith check rates` no longer stops with `TypeError` when the API does not give a value for an interval, limit, remaining count, reset time or throttled status. The command now shows `None` for that value. ## [1.30.0] - 2026-10-22 diff --git a/cloudsmith_cli/core/ratelimits.py b/cloudsmith_cli/core/ratelimits.py index 78ac9722a..38a5b892b 100644 --- a/cloudsmith_cli/core/ratelimits.py +++ b/cloudsmith_cli/core/ratelimits.py @@ -26,17 +26,17 @@ def from_dict(cls, data): """Create RateLimitsInfo from a dictionary.""" info = RateLimitsInfo() - if "interval" in data: + if data.get("interval") is not None: info.interval = float(data["interval"]) - if "limit" in data: + if data.get("limit") is not None: info.limit = int(data["limit"]) - if "remaining" in data: + if data.get("remaining") is not None: info.remaining = int(data["remaining"]) - if "reset" in data: + if data.get("reset") is not None: info.reset = datetime.datetime.fromtimestamp( int(data["reset"]), tz=datetime.UTC ) - if "throttled" in data: + if data.get("throttled") is not None: info.throttled = bool(data["throttled"]) else: info.throttled = info.remaining == 0 diff --git a/cloudsmith_cli/core/tests/test_ratelimits.py b/cloudsmith_cli/core/tests/test_ratelimits.py new file mode 100644 index 000000000..ec62a9dc3 --- /dev/null +++ b/cloudsmith_cli/core/tests/test_ratelimits.py @@ -0,0 +1,19 @@ +from ..ratelimits import RateLimitsInfo + + +def test_from_dict_treats_null_values_as_missing(): + info = RateLimitsInfo.from_dict( + { + "interval": None, + "limit": None, + "remaining": None, + "reset": None, + "throttled": None, + } + ) + + assert info.interval is None + assert info.limit is None + assert info.remaining is None + assert info.reset is None + assert info.throttled is False