bsdd: retry on HTTP 429 rate-limit responses in Client.get()

The bSDD API rate-limits aggressively; without retry logic the client
silently returns the 429 JSON dict, causing KeyError when callers
access expected response keys. Client.get() now retries up to 5 times,
sleeping for the Retry-After header value (defaulting to 5s).

Remove the manual time.sleep() calls from the test module now that the
client handles rate limiting automatically.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Bruno Postle
2026-04-10 00:03:07 +01:00
parent 9cca7c2b88
commit 7aca51f063
2 changed files with 8 additions and 9 deletions
+7 -1
View File
@@ -521,7 +521,13 @@ class Client:
headers = {"User-Agent": "IfcOpenShell.bSDD.py/0.8.0"}
if is_auth_required:
headers["Authorization"] = "Bearer " + self.get_access_token()
return requests.get(f"{self.baseurl}{endpoint}", timeout=10, headers=headers, params=params or None).json()
for _ in range(5):
response = requests.get(f"{self.baseurl}{endpoint}", timeout=10, headers=headers, params=params or None)
if response.status_code != 429:
return response.json()
retry_after = int(response.headers.get("Retry-After", 5))
time.sleep(retry_after)
return response.json()
def _get_deprecated(self, endpoint, params=None, is_auth_required=False):
headers = {"User-Agent": "IfcOpenShell.bSDD.py/0.8.0"}
+1 -8
View File
@@ -1,26 +1,19 @@
import time
from bsdd import Client
client = Client()
# Fetch shared data at module level to avoid repeated API calls during tests.
# Sleeps are required: the bSDD API rate-limits to roughly one request per second.
# The Client.get() method handles 429 rate-limit responses with automatic retry.
_dictionaries = client.get_dictionary()["dictionaries"]
ifc4x3_uri = next(l["uri"] for l in _dictionaries if "4.3" in l["uri"])
nbs_uri = next(l["uri"] for l in _dictionaries if "Uniclass 2015" == l["name"])
time.sleep(2)
_ifc4x3_classes = client.get_classes(ifc4x3_uri, use_nested_classes=False, class_type="Class")
time.sleep(2)
_nbs_classes = client.get_classes(nbs_uri, use_nested_classes=False, class_type="Class", offset=0, limit=5)
_uri_light_fixture = next(l for l in _ifc4x3_classes["classes"] if "IfcLightFixture" == l["code"])["uri"]
time.sleep(2)
_light_fixture = client.get_class(_uri_light_fixture)
time.sleep(2)
_light_fixture_relations = client.get_class_relations(_uri_light_fixture)
time.sleep(2)
_light_fixture_properties = client.get_class_properties(_uri_light_fixture)