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
committed by Ryan Schultz
parent a61bb485c6
commit 7c7943bb0a
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)