Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions bcb/odata/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def __init__(self, *, timeout: RequestTimeout = None) -> None:
self._timeout = timeout
self.service = ODataService(self.BASE_URL, timeout=timeout)

def describe(self, endpoint: Optional[str] = None) -> None:
def describe(self, endpoint: Optional[str] = None, *, full: bool = True) -> None:
"""
Mostra a descrição de uma API ou de um *endpoint*
específico.
Expand All @@ -381,7 +381,12 @@ def describe(self, endpoint: Optional[str] = None) -> None:
----------

endpoint : None (padrão) ou str
nome do *endpoint*
Nome do *endpoint*. Quando informado, mostra apenas a descrição
desse *endpoint*.
full : bool, default True
Quando ``endpoint`` não é informado, mostra os detalhes de todos
os *endpoints*. Use ``False`` para imprimir apenas a listagem curta
com os nomes dos *endpoints*.

Returns
-------
Expand All @@ -392,7 +397,7 @@ def describe(self, endpoint: Optional[str] = None) -> None:
if endpoint:
self.service[endpoint].describe()
else:
self.service.describe()
self.service.describe(full=full)

def get_endpoint(self, endpoint: str) -> Endpoint:
"""
Expand Down
40 changes: 28 additions & 12 deletions bcb/odata/framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,20 +578,36 @@ def function_imports(self) -> dict[str, ODataFunctionImport]:
def entity_sets(self) -> dict[str, ODataEntitySet]:
return self.metadata.entity_sets

def describe(self) -> None:
es_names = []
for es in self.entity_sets.keys():
k = f"{self.metadata.namespace}.{es}"
if k not in self.metadata._used_elements:
es_names.append(es)
if len(es_names):
def _standalone_entity_sets(self) -> list[ODataEntitySet]:
return [
entity_set
for name, entity_set in self.entity_sets.items()
if f"{self.metadata.namespace}.{name}" not in self.metadata._used_elements
]

def describe(self, *, full: bool = False) -> None:
entity_sets = self._standalone_entity_sets()
function_imports = list(self.function_imports.values())

if full:
if entity_sets:
print("EntitySets:")
for entity_set in entity_sets:
entity_set.describe()
if function_imports:
print("FunctionImports:")
for function_import in function_imports:
function_import.describe()
return

if entity_sets:
print("EntitySets:")
for es in es_names:
print(" ", es)
if len(self.function_imports):
for entity_set in entity_sets:
print(" ", entity_set.name)
if function_imports:
print("FunctionImports:")
for es in self.function_imports.keys():
print(" ", es)
for function_import in function_imports:
print(" ", function_import.name)

def query(
self, entity_set: Union[ODataEntitySet, ODataFunctionImport]
Expand Down
1 change: 1 addition & 0 deletions docs/currency.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ __ documentacao_

A classe :py:class:`bcb.PTAX` retorna cotações de moedas obtidas a partir da `API de Moedas`__ do BCB.
Esta implementação é mais estável que a do :ref:`Conversor de Moedas`.
O método ``describe`` mostra os *endpoints*, parâmetros e propriedades disponíveis.

.. ipython:: python

Expand Down
11 changes: 6 additions & 5 deletions docs/expectativas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ defasagem de 1 ano.

Ao instanciar a classe :py:class:`bcb.Expectativas` diversas informações
são obtidas e a melhor maneira de interagir com a API é
através do método :py:meth:`bcb.Expectativas.describe`.
através do método :py:meth:`bcb.Expectativas.describe`, que mostra os
*endpoints* e suas propriedades. Para obter apenas a listagem curta dos nomes,
use ``describe(full=False)``.


.. ipython:: python
Expand All @@ -35,10 +37,9 @@ através do método :py:meth:`bcb.Expectativas.describe`.
em = Expectativas()
em.describe()

O método :py:meth:`bcb.Expectativas.describe` também recebe o nomes dos
*endpoints* e apresenta uma descrição do *endpoint* trazendo o seu tipo
`EntityType` e as propriedades retornadas `Properties` e os seus respectivos
tipos.
O método :py:meth:`bcb.Expectativas.describe` também recebe o nome de um
*endpoint* para restringir a saída, apresentando o seu tipo `EntityType` e as
propriedades retornadas `Properties` com os seus respectivos tipos.

.. ipython:: python

Expand Down
4 changes: 2 additions & 2 deletions docs/odata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ Segue um exemplo de como acessar a API do PIX.
pix = SPI()

É necessário importar e criar um objeto da classe que implementa a API, neste caso a classe ``SPI``.
Tendo o objeto, executar o método ``describe`` para visualizar o *endpoints* disponíveis na API.
Tendo o objeto, executar o método ``describe`` para visualizar os *endpoints* disponíveis na API e suas propriedades. Para obter apenas a listagem curta dos nomes, use ``describe(full=False)``.


.. ipython:: python

pix.describe()

Como vemos, a API do PIX tem 4 *endpoints* (``EntitySets``).
Para ver as informações retornadas por cada *endpoint* é só executar o método ``describe`` passando como argumento
Para restringir a saída a um *endpoint*, execute o método ``describe`` passando como argumento
o nome do *endpoint*.

.. ipython:: python
Expand Down
5 changes: 3 additions & 2 deletions docs/taxajuros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ __ documentacao_
Os dados são obtidos a partir da `API de Taxas de Juros`__.


Esta API usa o serviço ``taxaJuros`` versão ``v2`` e tem os ``EntitySets``:
Esta API usa o serviço ``taxaJuros`` versão ``v2``. O método ``describe``
mostra os ``EntitySets`` e suas propriedades:

.. ipython:: python

from bcb import TaxaJuros
em = TaxaJuros()
em.describe()

As características do ``EntitySets`` podem ser visualizadas por:
Para restringir a saída a um ``EntitySet`` específico, informe o seu nome:

.. ipython:: python

Expand Down
52 changes: 51 additions & 1 deletion tests/test_odata.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pandas as pd
import pytest

from bcb.odata.api import Expectativas
from bcb.odata.api import Expectativas, ODataAPI
from bcb.odata.framework import (
ODataParameter,
ODataProperty,
Expand Down Expand Up @@ -120,6 +120,56 @@ def test_invalid_endpoint_raises(httpx_mock):
api.get_endpoint("DoesNotExist")


def test_api_describe_shows_all_endpoint_details_by_default(httpx_mock, capsys):
add_service_mocks(httpx_mock)
api = Expectativas()

api.describe()

output = capsys.readouterr().out
assert "EntitySets:" in output
assert "EntitySet (Endpoint): ExpectativasMercadoAnuais" in output
assert "EntityType: IFBCB_DadosSeries_v2.Expectativa" in output
assert "Properties: Indicador<str>, Data<datetime>, Mediana<float>" in output


def test_api_describe_can_show_summary_only(httpx_mock, capsys):
add_service_mocks(httpx_mock)
api = Expectativas()

api.describe(full=False)

output = capsys.readouterr().out
assert "EntitySets:" in output
assert " ExpectativasMercadoAnuais" in output
assert "Properties:" not in output


def test_api_describe_specific_endpoint_is_preserved(httpx_mock, capsys):
add_service_mocks(httpx_mock)
api = Expectativas()

api.describe("ExpectativasMercadoAnuais")

output = capsys.readouterr().out
assert "EntitySet (Endpoint): ExpectativasMercadoAnuais" in output
assert "Properties: Indicador<str>, Data<datetime>, Mediana<float>" in output


def test_api_describe_shows_function_import_details_by_default(httpx_mock, capsys):
add_function_service_mocks(httpx_mock)
api = ODataAPI(FUNCTION_BASE_URL)

api.describe()

output = capsys.readouterr().out
assert "FunctionImports:" in output
assert "Function: CotacaoMoedaPeriodo" in output
assert "Parameters: moeda <str>, dataInicial <str>, limite <int>" in output
assert "EntitySet: CotacoesMoedaPeriodo" in output
assert "Properties: Moeda <str>, Data <datetime>, CotacaoCompra <float>" in output


def test_service_root_status_error_raises_odata_error(httpx_mock):
httpx_mock.add_response(
url=EXPECTATIVAS_BASE_URL,
Expand Down
Loading