Skip to content

Commit 32120d3

Browse files
authored
Merge pull request #16 from im-voracity/release/v1.0.4
docs: expand pagination and retry behavior docs (v1.0.4)
2 parents 253ca76 + f0838be commit 32120d3

File tree

5 files changed

+82
-128
lines changed

5 files changed

+82
-128
lines changed

README.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,27 @@ for sale in client.sales.history_autopaginate(buyer_name="Paula"):
358358

359359
The iterator stops when there are no more pages — no token management, no loop conditions.
360360

361+
### Processing pages individually
362+
363+
If you need to act at the end of each page — flush a batch to a database, save a checkpoint, update a progress bar — use the single-page method and control the loop yourself:
364+
365+
```python
366+
page_token = None
367+
while True:
368+
page = client.sales.history(start_date=1700000000000, page_token=page_token)
369+
370+
for sale in page.items:
371+
process(sale)
372+
373+
save_checkpoint(page_token) # per-page side effect
374+
375+
if not page.page_info or not page.page_info.next_page_token:
376+
break
377+
page_token = page.page_info.next_page_token
378+
```
379+
380+
Use `*_autopaginate` when you only need to iterate all records. Use the manual loop when you need to act between pages.
381+
361382
---
362383

363384
## Sandbox Mode
@@ -418,7 +439,19 @@ Exception hierarchy:
418439
| `APIStatusError` | other | Unexpected HTTP status |
419440
| `HotmartError` || Base class for all SDK errors |
420441

421-
The SDK retries automatically on transient errors (5xx, 429) with exponential backoff (`0.5 × 2^attempt + jitter`, cap 30s). Configure via `max_retries`:
442+
### Retry behavior
443+
444+
Not all errors are equal — the SDK handles them differently before raising:
445+
446+
| Behavior | Exceptions |
447+
|----------|-----------|
448+
| **Retried with exponential backoff** — raised only after all retries are exhausted | `RateLimitError` (429), `InternalServerError` (500, 502, 503) |
449+
| **Triggers token refresh + one automatic retry** — never raised for an expired token | `AuthenticationError` from 401 |
450+
| **Raised immediately, no retry** | `BadRequestError` (400), `AuthenticationError` from 403, `NotFoundError` (404), `APIStatusError` |
451+
452+
In practice: a `RateLimitError` in your `except` block means Hotmart was still returning 429 after all retries. An `AuthenticationError` means your credentials are genuinely invalid, not just that a token expired mid-run.
453+
454+
Backoff formula: `0.5s × 2^attempt + jitter` (jitter 0–0.5s, cap 30s). For 429, the `RateLimit-Reset` header is used directly when present. Configure the number of retries via `max_retries`:
422455

423456
```python
424457
client = Hotmart(..., max_retries=5)

docs/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ O formato segue [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) e o pro
66

77
---
88

9+
## [1.0.4] - 2026-03-28
10+
11+
Versão de manutenção com melhorias de documentação. Nenhuma mudança no código da biblioteca.
12+
13+
### Changed
14+
15+
- Seção "Processing pages individually" adicionada ao README (EN e PT-BR): padrão de loop manual com `page_token` para processamento página a página com efeitos colaterais (checkpoint, batch flush, etc.)
16+
- Seção "Retry behavior" expandida no README (EN e PT-BR): tabela clara de quais erros são reprocessados automaticamente, quais disparam renovação de token e quais são lançados imediatamente
17+
18+
---
19+
920
## [1.0.3] - 2026-03-26
1021

1122
### Fixed

docs/README-ptBR.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,27 @@ for venda in client.sales.history_autopaginate(buyer_name="Paula"):
357357

358358
O iterador para automaticamente quando não há mais páginas — sem gerenciamento de token, sem condições de loop.
359359

360+
### Processamento página a página
361+
362+
Se você precisar agir ao final de cada página — salvar um checkpoint, enviar um batch para o banco, atualizar uma barra de progresso — use o método de página única e controle o loop manualmente:
363+
364+
```python
365+
page_token = None
366+
while True:
367+
pagina = client.sales.history(start_date=1700000000000, page_token=page_token)
368+
369+
for venda in pagina.items:
370+
processar(venda)
371+
372+
salvar_checkpoint(page_token) # efeito colateral por página
373+
374+
if not pagina.page_info or not pagina.page_info.next_page_token:
375+
break
376+
page_token = pagina.page_info.next_page_token
377+
```
378+
379+
Use `*_autopaginate` quando precisar apenas iterar todos os registros. Use o loop manual quando precisar agir entre páginas.
380+
360381
---
361382

362383
## Modo Sandbox
@@ -417,7 +438,19 @@ Hierarquia de exceções:
417438
| `APIStatusError` | outros | Status HTTP inesperado |
418439
| `HotmartError` || Classe base para todos os erros do SDK |
419440

420-
O SDK realiza retentativas automáticas em erros transitórios (5xx, 429) com backoff exponencial (`0.5 × 2^attempt + jitter`, cap 30s). Configure via `max_retries`:
441+
### Comportamento de retentativas
442+
443+
Nem todos os erros são tratados da mesma forma — o SDK age diferente antes de lançar cada um:
444+
445+
| Comportamento | Exceções |
446+
|---------------|---------|
447+
| **Reprocessado com backoff exponencial** — lançado apenas após esgotar todas as tentativas | `RateLimitError` (429), `InternalServerError` (500, 502, 503) |
448+
| **Dispara renovação de token + uma nova tentativa automática** — nunca lançado por token expirado | `AuthenticationError` originado de 401 |
449+
| **Lançado imediatamente, sem retentativa** | `BadRequestError` (400), `AuthenticationError` de 403, `NotFoundError` (404), `APIStatusError` |
450+
451+
Na prática: um `RateLimitError` no seu `except` significa que a Hotmart continuou retornando 429 mesmo após todas as tentativas. Um `AuthenticationError` indica credenciais genuinamente inválidas — não simplesmente um token expirado no meio da execução.
452+
453+
Fórmula do backoff: `0.5s × 2^attempt + jitter` (jitter 0–0.5s, cap 30s). Para 429, o header `RateLimit-Reset` é usado diretamente quando presente. Configure o número de tentativas via `max_retries`:
421454

422455
```python
423456
client = Hotmart(..., max_retries=5)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "hotmart-python"
3-
version = "1.0.3"
3+
version = "1.0.4"
44
description = "Python SDK for the Hotmart API"
55
authors = [{ name = "Matheus Tenório", email = "matheusct16@gmail.com" }]
66
license = { text = "Apache-2.0" }

0 commit comments

Comments
 (0)