Skip to content

Commit 268495a

Browse files
wilsonfreitasclaude
andcommitted
docs: Add comprehensive async API documentation with sidebar navigation
- Create docs/async.rst with complete async API documentation in Portuguese - Document async_get() for sgs and currency modules - Document async_collect() and async_query() for OData queries - Provide practical examples with asyncio.gather() patterns - Include performance comparison (sync vs async) - Document error handling and resource cleanup - Add semaphore pattern for limiting concurrent requests - Update docs/index.rst to include async page in toctree - Add 'APIs Assíncronas' section to index overview - Configure Furo theme with sidebar navigation on all pages (html_sidebars in conf.py) - Enable navigation_with_keys option in theme config - Build confirms: 0 errors, 0 warnings The 'APIs Assíncronas' menu item now appears in the sidebar on all documentation pages. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent dc1583f commit 268495a

3 files changed

Lines changed: 274 additions & 0 deletions

File tree

docs/async.rst

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
.. _async:
2+
3+
APIs Assíncronas
4+
================
5+
6+
O **python-bcb** oferece suporte completo a programação assíncrona através de métodos ``async_get()`` e ``async_collect()`` em todos os módulos.
7+
Isso permite buscar dados de forma não-bloqueante e executar múltiplas requisições concorrentemente usando ``asyncio``.
8+
9+
Quando Usar APIs Assíncronas
10+
----------------------------
11+
12+
Use as APIs assíncronas quando você precisa:
13+
14+
* **Buscar múltiplas séries** — Reduz o tempo total de execução
15+
* **Integrar com código assíncrono** — Evita bloquear a event loop
16+
* **Processamento em larga escala** — Milhares de requisições sem I/O bloqueante
17+
* **Aplicações web/CLI** — Melhor responsividade e throughput
18+
19+
Exemplo Básico: Múltiplas Séries SGS
20+
------------------------------------
21+
22+
Buscar vários indicadores SGS concorrentemente é muito mais rápido que fazer requisições sequenciais:
23+
24+
.. code-block:: python
25+
26+
import asyncio
27+
from bcb import sgs
28+
29+
async def fetch_economic_indicators():
30+
"""Buscar SELIC, CDI e IPCA concorrentemente."""
31+
# Criar tasks para requisições concorrentes
32+
results = await asyncio.gather(
33+
sgs.async_get(1, start='2024-01-01'), # SELIC
34+
sgs.async_get(12, start='2024-01-01'), # CDI
35+
sgs.async_get(433, start='2024-01-01'), # IPCA
36+
)
37+
38+
selic_df, cdi_df, ipca_df = results
39+
return selic_df, cdi_df, ipca_df
40+
41+
# Executar
42+
selic, cdi, ipca = asyncio.run(fetch_economic_indicators())
43+
print(selic.head())
44+
45+
Módulo SGS: async_get()
46+
-----------------------
47+
48+
A função :py:func:`bcb.sgs.async_get` é a versão assíncrona de :py:func:`bcb.sgs.get`.
49+
Busca dados de múltiplos códigos SGS concorrentemente com a mesma interface que a versão síncrona.
50+
51+
**Exemplo com múltiplos códigos:**
52+
53+
.. code-block:: python
54+
55+
import asyncio
56+
from bcb import sgs
57+
58+
async def main():
59+
# Buscar vários indicadores de uma vez
60+
df = await sgs.async_get(
61+
[1, 11, 12, 433], # SELIC, Taxa Over, CDI, IPCA
62+
start='2023-01-01',
63+
end='2024-12-31'
64+
)
65+
print(df.head())
66+
67+
asyncio.run(main())
68+
69+
Módulo Currency: async_get()
70+
-----------------------------
71+
72+
A função :py:func:`bcb.currency.async_get` é a versão assíncrona de :py:func:`bcb.currency.get`.
73+
Busca taxas de câmbio de forma assíncrona com a mesma interface que a versão síncrona.
74+
75+
**Exemplo:**
76+
77+
.. code-block:: python
78+
79+
import asyncio
80+
from bcb import currency
81+
82+
async def main():
83+
# Buscar taxas de câmbio
84+
usd = await currency.async_get('USD', start='2024-01-01', end='2024-12-31')
85+
print(usd.head())
86+
87+
asyncio.run(main())
88+
89+
OData: async_collect()
90+
----------------------
91+
92+
Todas as queries OData suportam métodos assíncronos para execução não-bloqueante:
93+
94+
* :py:meth:`ODataQuery.async_collect` — versão assíncrona de :py:meth:`ODataQuery.collect`
95+
* :py:meth:`Endpoint.async_get` — versão assíncrona de :py:meth:`Endpoint.get`
96+
* :py:meth:`Endpoint.async_query` — retorna uma query pronta para execução assíncrona
97+
98+
**Exemplo com Expectativas:**
99+
100+
.. code-block:: python
101+
102+
import asyncio
103+
from bcb import Expectativas
104+
105+
async def main():
106+
api = Expectativas()
107+
endpoint = api.get_endpoint('ExpectativasMercadoAnuais')
108+
109+
# Construir query e executar de forma assíncrona
110+
df = await (
111+
endpoint.query()
112+
.filter(endpoint.Indicador == 'IPCA')
113+
.limit(100)
114+
.async_collect()
115+
)
116+
print(df)
117+
118+
asyncio.run(main())
119+
120+
Padrão asyncio.gather() — Operações Paralelas
121+
----------------------------------------------
122+
123+
Use ``asyncio.gather()`` para executar várias operações em paralelo:
124+
125+
.. code-block:: python
126+
127+
import asyncio
128+
from bcb import sgs, currency
129+
from bcb import Expectativas
130+
131+
async def main():
132+
# Executar 3 operações em paralelo
133+
selic_task = sgs.async_get(1, start='2024-01-01')
134+
usd_task = currency.async_get('USD', start='2024-01-01')
135+
136+
api = Expectativas()
137+
endpoint = api.get_endpoint('ExpectativasMercadoAnuais')
138+
expectations_task = endpoint.query().filter(
139+
endpoint.Indicador == 'IPCA'
140+
).limit(10).async_collect()
141+
142+
# Aguardar todas as operações
143+
selic, usd, expectations = await asyncio.gather(
144+
selic_task,
145+
usd_task,
146+
expectations_task
147+
)
148+
149+
return selic, usd, expectations
150+
151+
selic, usd, expectations = asyncio.run(main())
152+
153+
Tratamento de Erros
154+
-------------------
155+
156+
As APIs assíncronas lançam as mesmas exceções que as síncronas:
157+
158+
.. code-block:: python
159+
160+
import asyncio
161+
from bcb import sgs
162+
from bcb.exceptions import SGSError, BCBRateLimitError
163+
164+
async def main():
165+
try:
166+
df = await sgs.async_get(99999) # Código inválido
167+
except SGSError as e:
168+
print(f"Erro de dados SGS: {e}")
169+
except BCBRateLimitError:
170+
print("Limite de requisições excedido - tente novamente mais tarde")
171+
172+
asyncio.run(main())
173+
174+
Performance: Síncrono vs Assíncrono
175+
-----------------------------------
176+
177+
**Requisições Sequenciais (bloqueante):**
178+
179+
.. code-block:: python
180+
181+
# Leva ~5 segundos (1s + 1s + 1s + cada requisição é bloqueante)
182+
df1 = sgs.get(1, start='2024-01-01')
183+
df2 = sgs.get(11, start='2024-01-01')
184+
df3 = sgs.get(12, start='2024-01-01')
185+
186+
**Requisições Concorrentes (assíncrono):**
187+
188+
.. code-block:: python
189+
190+
# Leva ~1 segundo (todas 3 são executadas em paralelo)
191+
import asyncio
192+
193+
async def main():
194+
df1, df2, df3 = await asyncio.gather(
195+
sgs.async_get(1, start='2024-01-01'),
196+
sgs.async_get(11, start='2024-01-01'),
197+
sgs.async_get(12, start='2024-01-01'),
198+
)
199+
200+
asyncio.run(main())
201+
202+
Limpeza de Recursos
203+
-------------------
204+
205+
Para aplicações de longa duração, feche o cliente assíncrono quando terminar:
206+
207+
.. code-block:: python
208+
209+
import asyncio
210+
from bcb import http
211+
212+
async def main():
213+
# ... suas operações assíncronas ...
214+
pass
215+
216+
asyncio.run(main())
217+
218+
# Fechar cliente assíncrono
219+
asyncio.run(http.close_async_client())
220+
221+
Limitações
222+
----------
223+
224+
* **Concorrência sem limite** — Use um ``asyncio.Semaphore()`` para limitar requisições simultâneas
225+
* **Rate limiting** — APIs BCB podem ter limites; implemente backoff exponencial se necessário
226+
* **Ciclos de evento** — APIs assíncronas exigem uma event loop ativa (use ``asyncio.run()``)
227+
228+
**Exemplo com Semaphore:**
229+
230+
.. code-block:: python
231+
232+
import asyncio
233+
from bcb import sgs
234+
235+
async def main():
236+
# Limitar a 3 requisições simultâneas
237+
semaphore = asyncio.Semaphore(3)
238+
239+
async def fetch_with_limit(code):
240+
async with semaphore:
241+
return await sgs.async_get(code, start='2024-01-01')
242+
243+
codes = [1, 11, 12, 433, 189]
244+
results = await asyncio.gather(*[fetch_with_limit(c) for c in codes])
245+
246+
return results
247+
248+
asyncio.run(main())
249+
250+
Veja Também
251+
-----------
252+
253+
* :ref:`SGS` — Documentação completa do módulo SGS
254+
* :ref:`Conversor de Moedas` — Documentação do módulo currency
255+
* :ref:`OData` — Documentação do cliente OData
256+
* `asyncio — asyncpython <https://docs.python.org/3/library/asyncio.html>`_

docs/conf.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@
6565
"source_repository": "https://github.com/wilsonfreitas/python-bcb/",
6666
"source_branch": "main",
6767
"source_directory": "docs/",
68+
"navigation_with_keys": True,
69+
}
70+
71+
# Customize sidebar to show navigation on all pages
72+
html_sidebars = {
73+
"**": [
74+
"sidebar/brand.html",
75+
"sidebar/search.html",
76+
"sidebar/navigation.html",
77+
"sidebar/ethical-ads.html",
78+
]
6879
}
6980
# html_theme = "alabaster"
7081
# html_theme_options = {

docs/index.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ APIs implementadas
8383
é passada para a classe :py:class:`bcb.ODataAPI` e o objeto criado dá
8484
total acesso a API.
8585
Veja a documentação em :ref:`Classe ODataAPI`.
86+
``APIs Assíncronas``
87+
Todos os módulos oferecem versões assíncronas de suas funções principais
88+
para programação não-bloqueante com ``asyncio``.
89+
Use ``sgs.async_get()``, ``currency.async_get()``, e ``ODataQuery.async_collect()``
90+
para buscar múltiplos dados em paralelo e melhorar a performance.
91+
Veja a documentação em :ref:`async`.
8692
Muito mais
8793
Veja todos os *endpoints* implementados na documentação de nossa :ref:`API`.
8894

@@ -104,6 +110,7 @@ Uso
104110
expectativas
105111
taxajuros
106112
odata
113+
async
107114
api
108115

109116
Índices e tabelas

0 commit comments

Comments
 (0)