An extract job reads every item from a paginated API. client.get_page(cursor) returns {"items": [...], "next_cursor": str | None}; the first page is cursor=None, and next_cursor=None means it was the last page. The call can raise:
- •
TransientError — worth retrying (a timeout, a 429 or 503); - •
PermanentError — never worth retrying (a bad cursor, a 401): raise it at once.
Write fetch_all(client, sleep, rand, max_attempts=5, base_delay=0.5, cap=8.0) that returns all items, in page order:
- •each page gets at most
max_attempts calls; the count starts again for the next page; - •after the
k-th failed call for a page (k = 0 for the first failure), call sleep(rand() * min(cap, base_delay * 2**k)) and try that same page again. Call rand() once per sleep; it returns a float in [0, 1); - •if the last allowed call also fails, re-raise that
TransientError; don't sleep after it.
Use the sleep and rand you're given (the tests record them). Keep the two exception classes in the starter; the client raises them.
Python 3.13 in your browser — the standard library plus pandas and numpy; no pip installs.