Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e78dc8c
feat: Initial development of Retry Stratefies
IvanildoBarauna Jun 19, 2024
9b66936
feat: Added new necessary params for setup retry strategy
IvanildoBarauna Jun 20, 2024
af8462b
feat: added functional tests on jupyter notebook
IvanildoBarauna Jun 20, 2024
9f796fe
feat: added raise_for_status for get raises on Retainer
IvanildoBarauna Jun 20, 2024
f11ae21
feat: increase minor version
IvanildoBarauna Jun 20, 2024
7082d9d
tests: added new import for Enum Strategies
IvanildoBarauna Jun 20, 2024
ed5f48b
feat: RetryStrategy development
IvanildoBarauna Jun 20, 2024
dfc448e
chore: JetBrains Configs
IvanildoBarauna Jun 20, 2024
d6702a2
chore: adjust import from new retainer component
IvanildoBarauna Jun 20, 2024
de5c463
tests: added LinearStrategy tests for retainer
IvanildoBarauna Jun 20, 2024
18cd496
chore: change default value parameters
IvanildoBarauna Jun 20, 2024
f3520b6
tests: development tests for retainer
IvanildoBarauna Jun 20, 2024
a41c3c3
tests: Added extreme scenarios for raises on ClientBuilder
IvanildoBarauna Jun 20, 2024
1addea2
chore: change reserved name of var
IvanildoBarauna Jun 20, 2024
8edd975
chore: return json in main lib function
IvanildoBarauna Jun 20, 2024
b1c1b32
feat: change default retry for 1
IvanildoBarauna Jun 21, 2024
b0f50ad
feat: up raise for NoRetryStrategy
IvanildoBarauna Jun 21, 2024
0be8cb4
tests: increase codeCov to 100%
IvanildoBarauna Jun 21, 2024
291b47a
chore: Update Documentation + set quantity of retry to 3
IvanildoBarauna Jun 21, 2024
7011b6d
Update notebooks and evoluted project for Alpha phase
IvanildoBarauna Jun 21, 2024
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
2 changes: 1 addition & 1 deletion .idea/api-to-dataframe.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,37 @@ To install the package using poetry, use the following command:
poetry add api-to-dataframe
```

## How to use it
## User Guide

``` python
## Importing library
from api_to_dataframe import ClientBuilder, RetryStrategies

# Create a client for simple ingest data from API (timeout 5 seconds)
# Create a client for simple ingest data from API (timeout 1 second)
client = ClientBuilder(endpoint="https://api.example.com")

# if you can define timeout, use: (default is 5 seconds), with LinearStrategy (In development, actually don't nothing) and set headers:
# if you can define timeout with LinearStrategy and set headers:
headers = {
"application_name": "api_to_dataframe"
}
client = ClientBuilder(endpoint="https://api.example.com"
,retry_strategy=RetryStrategies.LinearStrategy
,timeout=10
,connection_timeout=2
,headers=headers)

"""
NOTE: by default the quantity of retries is 3 and the time between retries is 1 second, but you can define manually, like this:

"""

client = ClientBuilder(endpoint="https://api.example.com"
,retry_strategy=RetryStrategies.LinearStrategy
,connection_timeout=10
,headers=headers
,retries=5
,delay=10)


### timeout, retry_strategy and headers are opcionals parameters

# Get data from the API
Expand Down
193 changes: 115 additions & 78 deletions notebooks/example.ipynb
Original file line number Diff line number Diff line change
@@ -1,98 +1,135 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Defaulting to user installation because normal site-packages is not writeable\n",
"Collecting api-to-dataframe\n",
" Downloading api_to_dataframe-0.0.3-py3-none-any.whl (4.0 kB)\n",
"Collecting coverage<8.0.0,>=7.5.3\n",
" Using cached coverage-7.5.3-cp39-cp39-macosx_10_9_x86_64.whl (204 kB)\n",
"Collecting pytest<9.0.0,>=8.2.2\n",
" Downloading pytest-8.2.2-py3-none-any.whl (339 kB)\n",
"\u001b[K |████████████████████████████████| 339 kB 7.5 MB/s eta 0:00:01\n",
"\u001b[?25hCollecting tomli>=1\n",
" Using cached tomli-2.0.1-py3-none-any.whl (12 kB)\n",
"Requirement already satisfied: exceptiongroup>=1.0.0rc8 in /Users/ivsouza/Library/Python/3.9/lib/python/site-packages (from pytest<9.0.0,>=8.2.2->api-to-dataframe) (1.2.0)\n",
"Requirement already satisfied: packaging in /Users/ivsouza/Library/Python/3.9/lib/python/site-packages (from pytest<9.0.0,>=8.2.2->api-to-dataframe) (23.2)\n",
"Collecting iniconfig\n",
" Using cached iniconfig-2.0.0-py3-none-any.whl (5.9 kB)\n",
"Collecting pluggy<2.0,>=1.5\n",
" Using cached pluggy-1.5.0-py3-none-any.whl (20 kB)\n",
"Installing collected packages: tomli, pluggy, iniconfig, pytest, coverage, api-to-dataframe\n",
"Successfully installed api-to-dataframe-0.0.3 coverage-7.5.3 iniconfig-2.0.0 pluggy-1.5.0 pytest-8.2.2 tomli-2.0.1\n",
"\u001b[33mWARNING: You are using pip version 21.2.4; however, version 24.0 is available.\n",
"You should consider upgrading via the '/Library/Developer/CommandLineTools/usr/bin/python3 -m pip install --upgrade pip' command.\u001b[0m\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"cell_type": "markdown",
"source": [
"pip install api-to-dataframe"
"## Case use - Using Linear Strategy\n",
"For more examples see [User Guide on README](https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/README.md#how-to-use-it)\n",
"\n",
"NOTE: Before ensure that api-to-dataframe is installed as a dependency, see how to do this [here](https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/README.md#installation)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Defaulting to user installation because normal site-packages is not writeable\n",
"\u001b[31mERROR: You must give at least one requirement to install (see \"pip help install\")\u001b[0m\n",
"\u001b[33mWARNING: You are using pip version 21.2.4; however, version 24.0 is available.\n",
"You should consider upgrading via the '/Library/Developer/CommandLineTools/usr/bin/python3 -m pip install --upgrade pip' command.\u001b[0m\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"pip install --upgrade "
]
"cell_type": "markdown",
"source": ""
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"ename": "AttributeError",
"evalue": "'ApiToDataframe' object has no attribute 'name'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[10], line 5\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mapi_to_dataframe\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m ApiToDataframe\n\u001b[1;32m 3\u001b[0m new \u001b[38;5;241m=\u001b[39m ApiToDataframe\u001b[38;5;241m.\u001b[39mApiToDataframe(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIvanildo\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 5\u001b[0m \u001b[43mnew\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msay_hello\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Library/Python/3.9/lib/python/site-packages/api_to_dataframe/run.py:6\u001b[0m, in \u001b[0;36mApiToDataframe.say_hello\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msay_hello\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHello \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
"\u001b[0;31mAttributeError\u001b[0m: 'ApiToDataframe' object has no attribute 'name'"
]
"metadata": {
"ExecuteTime": {
"end_time": "2024-06-21T04:14:54.199749Z",
"start_time": "2024-06-21T04:14:54.124358Z"
}
],
},
"cell_type": "code",
"source": [
"from api_to_dataframe import ApiToDataframe\n",
"from api_to_dataframe import ClientBuilder, RetryStrategies\n",
"\n",
"new = ApiToDataframe.ApiToDataframe(\"Ivanildo\")\n",
"client = ClientBuilder(\n",
" endpoint=\"https://brasilapi.com.br/api/banks/v1\",\n",
" retry_strategy=RetryStrategies.LinearRetryStrategy,\n",
" retries=3,\n",
" connection_timeout=1,\n",
" delay=1)\n",
"\n",
"new.say_hello()\n",
"## Get response.json\n",
"api_data = client.get_api_data()\n",
"\n",
"df = client.api_to_dataframe(api_data)\n",
"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
"df.head()"
],
"outputs": [
{
"data": {
"text/plain": [
" ispb name code \\\n",
"0 00000000 BCO DO BRASIL S.A. 1.0 \n",
"1 00000208 BRB - BCO DE BRASILIA S.A. 70.0 \n",
"2 00038121 Selic NaN \n",
"3 00038166 Bacen NaN \n",
"4 00122327 SANTINVEST S.A. - CFI 539.0 \n",
"\n",
" fullName \n",
"0 Banco do Brasil S.A. \n",
"1 BRB - BANCO DE BRASILIA S.A. \n",
"2 Banco Central do Brasil - Selic \n",
"3 Banco Central do Brasil \n",
"4 SANTINVEST S.A. - CREDITO, FINANCIAMENTO E INV... "
],
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>ispb</th>\n",
" <th>name</th>\n",
" <th>code</th>\n",
" <th>fullName</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>00000000</td>\n",
" <td>BCO DO BRASIL S.A.</td>\n",
" <td>1.0</td>\n",
" <td>Banco do Brasil S.A.</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>00000208</td>\n",
" <td>BRB - BCO DE BRASILIA S.A.</td>\n",
" <td>70.0</td>\n",
" <td>BRB - BANCO DE BRASILIA S.A.</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>00038121</td>\n",
" <td>Selic</td>\n",
" <td>NaN</td>\n",
" <td>Banco Central do Brasil - Selic</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>00038166</td>\n",
" <td>Bacen</td>\n",
" <td>NaN</td>\n",
" <td>Banco Central do Brasil</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>00122327</td>\n",
" <td>SANTINVEST S.A. - CFI</td>\n",
" <td>539.0</td>\n",
" <td>SANTINVEST S.A. - CREDITO, FINANCIAMENTO E INV...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 21
}
],
"metadata": {
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[tool.poetry]
name = "api-to-dataframe"
version = "1.1.0"
version = "1.2.0"
description = "A package to convert API responses to pandas dataframe"
authors = ["IvanildoBarauna <ivanildo.jnr@outlook.com>"]
readme = "README.md"
license = "MIT"
classifiers=[
"Development Status :: 2 - Pre-Alpha",
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
Expand Down
2 changes: 1 addition & 1 deletion src/api_to_dataframe/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .controller.client_builder import ClientBuilder
from .common.utils.retry_strategies import RetryStrategies
from .models.retainer import Strategies as RetryStrategies
9 changes: 0 additions & 9 deletions src/api_to_dataframe/common/utils/retry_strategies.py

This file was deleted.

77 changes: 51 additions & 26 deletions src/api_to_dataframe/controller/client_builder.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,77 @@
from api_to_dataframe.common.utils.retry_strategies import RetryStrategies
from api_to_dataframe.models.retainer import RetryStrategies
from api_to_dataframe.models.retainer import Strategies
from api_to_dataframe.models.get_data import GetData


class ClientBuilder:
def __init__(self,
endpoint: str,
headers: dict = {},
retry_strategy: RetryStrategies = RetryStrategies.NoRetryStrategy,
timeout: int = 5):
headers: dict = None,
retry_strategy: Strategies = Strategies.NoRetryStrategy,
retries: int = 3,
delay: int = 1,
connection_timeout: int = 1):

"""
Initializes an instance of ClientBuilder.
Initializes the ClientBuilder object.

Args:
endpoint (str): The API endpoint to be accessed.
retry_strategy (RetryStrategies, optional): The retry strategy for the request. Default is NoRetryStrategy.
timeout (int, optional): The timeout for the request. Default is 5 seconds.
Args:
endpoint (str): The API endpoint to connect to.
headers (dict, optional): The headers to use for the API request. Defaults to None.
retry_strategy (Strategies, optional): The strategy to use for retrying failed requests. Defaults to Strategies.NoRetryStrategy.
retries (int, optional): The number of times to retry a failed request. Defaults to 3.
delay (int, optional): The delay between retries in seconds. Defaults to 1.
connection_timeout (int, optional): The timeout for the connection in seconds. Defaults to 2.

Raises:
ValueError: If the endpoint is empty.
Raises:
ValueError: If endpoint is an empty string.
ValueError: If retries is not a non-negative integer.
ValueError: If delay is not a non-negative integer.
ValueError: If connection_timeout is not a non-negative integer.
"""

if headers is None:
headers = {}
if endpoint == "":
raise ValueError("::: endpoint param is mandatory :::")
else:
self.endpoint = endpoint
self.retry_strategy = retry_strategy
self.timeout = timeout
self.headers = headers
if not isinstance(retries, int) or retries < 0:
raise ValueError("retries must be a non-negative integer")
if not isinstance(delay, int) or delay < 0:
raise ValueError("delay must be a non-negative integer")
if not isinstance(connection_timeout, int) or connection_timeout < 0:
raise ValueError("connection_timeout must be a non-negative integer")

self.endpoint = endpoint
self.retry_strategy = retry_strategy
self.connection_timeout = connection_timeout
self.headers = headers
self.retries = retries
self.delay = delay

@RetryStrategies
def get_api_data(self):
"""
Retrieves data from the API using the defined endpoint and retry strategy.

Returns:
dict: The response from the API.
"""
response = GetData.get_response(self.endpoint, self.headers, self.retry_strategy, self.timeout)
response = GetData.get_response(
endpoint=self.endpoint,
headers=self.headers,
connection_timeout=self.connection_timeout
)
return response.json()

def _get_raw_api_data(self):
response = GetData.get_response(
endpoint=self.endpoint,
headers=self.headers,
connection_timeout=self.connection_timeout
)
return response

@staticmethod
def api_to_dataframe(response: dict):
"""
Converts the API response into a DataFrame.

Args:
response (dict): The response from the API.

Returns:
DataFrame: The data converted into a DataFrame.
"""
df = GetData.to_dataframe(response)
return df
Loading