api-to-dataframe 1.2.2__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/PKG-INFO +15 -18
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/README.md +8 -14
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/pyproject.toml +18 -7
- api_to_dataframe-1.3.0/src/api_to_dataframe/controller/client_builder.py +84 -0
- api_to_dataframe-1.3.0/src/api_to_dataframe/models/get_data.py +29 -0
- api_to_dataframe-1.3.0/src/api_to_dataframe/models/retainer.py +41 -0
- api_to_dataframe-1.3.0/src/api_to_dataframe/utils/logger.py +27 -0
- api_to_dataframe-1.2.2/src/api_to_dataframe/controller/client_builder.py +0 -76
- api_to_dataframe-1.2.2/src/api_to_dataframe/models/get_data.py +0 -30
- api_to_dataframe-1.2.2/src/api_to_dataframe/models/retainer.py +0 -30
- api_to_dataframe-1.2.2/src/api_to_dataframe/views/dataframe_metrics.py +0 -0
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/LICENSE +0 -0
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/src/api_to_dataframe/__init__.py +0 -0
- {api_to_dataframe-1.2.2 → api_to_dataframe-1.3.0}/src/api_to_dataframe/config/config.py +0 -0
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: api-to-dataframe
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A package to convert API responses to pandas dataframe
|
|
5
|
-
Home-page: https://github.com/IvanildoBarauna/api-to-dataframe
|
|
6
5
|
License: MIT
|
|
7
6
|
Author: IvanildoBarauna
|
|
8
7
|
Author-email: ivanildo.jnr@outlook.com
|
|
9
8
|
Requires-Python: >=3.9,<4.0
|
|
10
|
-
Classifier: Development Status ::
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
10
|
Classifier: Intended Audience :: Developers
|
|
12
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -16,15 +15,19 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Requires-Dist: logging (>=0.4.9.6,<0.5.0.0)
|
|
19
19
|
Requires-Dist: pandas (>=2.2.2,<3.0.0)
|
|
20
20
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
21
|
-
Project-URL: Documentation, https://github.com/IvanildoBarauna/api-to-dataframe
|
|
21
|
+
Project-URL: Documentation, https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/README.md
|
|
22
|
+
Project-URL: Homepage, https://pypi.org/project/api-to-dataframe
|
|
23
|
+
Project-URL: ImplementationCase, https://github.com/IvanildoBarauna/ETL-awesome-api
|
|
22
24
|
Project-URL: Issues, https://github.com/IvanildoBarauna/api-to-dataframe/issues
|
|
25
|
+
Project-URL: Notebook, https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/notebooks/example.ipynb
|
|
23
26
|
Project-URL: Repository, https://github.com/IvanildoBarauna/api-to-dataframe
|
|
24
27
|
Description-Content-Type: text/markdown
|
|
25
28
|
|
|
26
29
|
# API to DataFrame
|
|
27
|
-
|
|
30
|
+
Python library that simplifies obtaining data from API endpoints by converting them directly into Pandas DataFrames. This library offers robust features, including retry strategies for failed requests.
|
|
28
31
|
|
|
29
32
|
[](https://github.com/IvanildoBarauna/api-to-dataframe)
|
|
30
33
|
|
|
@@ -44,18 +47,13 @@ Your solution to convert API responses to Pandas DataFrames with retry strategie
|
|
|
44
47
|

|
|
45
48
|

|
|
46
49
|

|
|
47
|
-

|
|
50
|
+

|
|
48
51
|

|
|
49
52
|

|
|
50
53
|

|
|
51
54
|

|
|
52
55
|
|
|
53
56
|
|
|
54
|
-
|
|
55
|
-
## Library Description
|
|
56
|
-
|
|
57
|
-
Python library that simplifies obtaining data from API endpoints by converting them directly into Pandas DataFrames. This library offers robust features, including retry strategies for failed requests and automatic generation of detailed reports on the received data.
|
|
58
|
-
|
|
59
57
|
## Installation
|
|
60
58
|
|
|
61
59
|
To install the package using pip, use the following command:
|
|
@@ -79,29 +77,28 @@ from api_to_dataframe import ClientBuilder, RetryStrategies
|
|
|
79
77
|
# Create a client for simple ingest data from API (timeout 1 second)
|
|
80
78
|
client = ClientBuilder(endpoint="https://api.example.com")
|
|
81
79
|
|
|
82
|
-
# if you can define timeout with
|
|
80
|
+
# if you can define timeout with LINEAR_RETRY_STRATEGY and set headers:
|
|
83
81
|
headers = {
|
|
84
82
|
"application_name": "api_to_dataframe"
|
|
85
83
|
}
|
|
86
84
|
client = ClientBuilder(endpoint="https://api.example.com"
|
|
87
|
-
,retry_strategy=RetryStrategies.
|
|
85
|
+
,retry_strategy=RetryStrategies.LINEAR_RETRY_STRATEGY
|
|
88
86
|
,connection_timeout=2
|
|
89
87
|
,headers=headers)
|
|
90
88
|
|
|
91
89
|
"""
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
NOTE: by default the quantity of retries is 3 and the time between retries is 1 second, but you can define manually.
|
|
94
91
|
"""
|
|
95
92
|
|
|
96
93
|
client = ClientBuilder(endpoint="https://api.example.com"
|
|
97
|
-
,retry_strategy=RetryStrategies.
|
|
94
|
+
,retry_strategy=RetryStrategies.LINEAR_RETRY_STRATEGY
|
|
98
95
|
,connection_timeout=10
|
|
99
96
|
,headers=headers
|
|
100
97
|
,retries=5
|
|
101
98
|
,initial_delay=10)
|
|
102
|
-
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
|
|
101
|
+
### timeout, retry_strategy and headers are opcionals parameters
|
|
105
102
|
|
|
106
103
|
# Get data from the API
|
|
107
104
|
data = client.get_api_data()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# API to DataFrame
|
|
2
|
-
|
|
2
|
+
Python library that simplifies obtaining data from API endpoints by converting them directly into Pandas DataFrames. This library offers robust features, including retry strategies for failed requests.
|
|
3
3
|
|
|
4
4
|
[](https://github.com/IvanildoBarauna/api-to-dataframe)
|
|
5
5
|
|
|
@@ -19,18 +19,13 @@ Your solution to convert API responses to Pandas DataFrames with retry strategie
|
|
|
19
19
|

|
|
20
20
|

|
|
21
21
|

|
|
22
|
-

|
|
22
|
+

|
|
23
23
|

|
|
24
24
|

|
|
25
25
|

|
|
26
26
|

|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
## Library Description
|
|
31
|
-
|
|
32
|
-
Python library that simplifies obtaining data from API endpoints by converting them directly into Pandas DataFrames. This library offers robust features, including retry strategies for failed requests and automatic generation of detailed reports on the received data.
|
|
33
|
-
|
|
34
29
|
## Installation
|
|
35
30
|
|
|
36
31
|
To install the package using pip, use the following command:
|
|
@@ -54,29 +49,28 @@ from api_to_dataframe import ClientBuilder, RetryStrategies
|
|
|
54
49
|
# Create a client for simple ingest data from API (timeout 1 second)
|
|
55
50
|
client = ClientBuilder(endpoint="https://api.example.com")
|
|
56
51
|
|
|
57
|
-
# if you can define timeout with
|
|
52
|
+
# if you can define timeout with LINEAR_RETRY_STRATEGY and set headers:
|
|
58
53
|
headers = {
|
|
59
54
|
"application_name": "api_to_dataframe"
|
|
60
55
|
}
|
|
61
56
|
client = ClientBuilder(endpoint="https://api.example.com"
|
|
62
|
-
,retry_strategy=RetryStrategies.
|
|
57
|
+
,retry_strategy=RetryStrategies.LINEAR_RETRY_STRATEGY
|
|
63
58
|
,connection_timeout=2
|
|
64
59
|
,headers=headers)
|
|
65
60
|
|
|
66
61
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
NOTE: by default the quantity of retries is 3 and the time between retries is 1 second, but you can define manually.
|
|
69
63
|
"""
|
|
70
64
|
|
|
71
65
|
client = ClientBuilder(endpoint="https://api.example.com"
|
|
72
|
-
,retry_strategy=RetryStrategies.
|
|
66
|
+
,retry_strategy=RetryStrategies.LINEAR_RETRY_STRATEGY
|
|
73
67
|
,connection_timeout=10
|
|
74
68
|
,headers=headers
|
|
75
69
|
,retries=5
|
|
76
70
|
,initial_delay=10)
|
|
77
|
-
|
|
78
71
|
|
|
79
|
-
|
|
72
|
+
|
|
73
|
+
### timeout, retry_strategy and headers are opcionals parameters
|
|
80
74
|
|
|
81
75
|
# Get data from the API
|
|
82
76
|
data = client.get_api_data()
|
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "api-to-dataframe"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.3.0"
|
|
4
4
|
description = "A package to convert API responses to pandas dataframe"
|
|
5
5
|
authors = ["IvanildoBarauna <ivanildo.jnr@outlook.com>"]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
classifiers=[
|
|
9
|
-
"Development Status ::
|
|
9
|
+
"Development Status :: 5 - Production/Stable",
|
|
10
10
|
"Intended Audience :: Developers",
|
|
11
11
|
"License :: OSI Approved :: MIT License",
|
|
12
12
|
"Programming Language :: Python :: 3",
|
|
13
13
|
"Programming Language :: Python :: 3.8",
|
|
14
14
|
]
|
|
15
15
|
|
|
16
|
-
homepage = "https://github.com/IvanildoBarauna/api-to-dataframe"
|
|
17
|
-
repository = "https://github.com/IvanildoBarauna/api-to-dataframe"
|
|
18
|
-
documentation = "https://github.com/IvanildoBarauna/api-to-dataframe#readme"
|
|
19
16
|
|
|
20
17
|
[tool.poetry.urls]
|
|
21
|
-
Homepage = "https://
|
|
22
|
-
Documentation = "https://github.com/IvanildoBarauna/api-to-dataframe
|
|
18
|
+
Homepage = "https://pypi.org/project/api-to-dataframe"
|
|
19
|
+
Documentation = "https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/README.md"
|
|
20
|
+
Notebook = 'https://github.com/IvanildoBarauna/api-to-dataframe/blob/main/notebooks/example.ipynb'
|
|
21
|
+
ImplementationCase = 'https://github.com/IvanildoBarauna/ETL-awesome-api'
|
|
23
22
|
Issues = "https://github.com/IvanildoBarauna/api-to-dataframe/issues"
|
|
23
|
+
Repository = "https://github.com/IvanildoBarauna/api-to-dataframe"
|
|
24
24
|
|
|
25
25
|
[tool.poetry.dependencies]
|
|
26
26
|
python = "^3.9"
|
|
27
27
|
pandas = "^2.2.2"
|
|
28
28
|
requests = "^2.32.3"
|
|
29
|
+
logging = "^0.4.9.6"
|
|
29
30
|
|
|
30
31
|
[tool.poetry.group.dev.dependencies]
|
|
31
32
|
poetry-dynamic-versioning = "^1.3.0"
|
|
32
33
|
pytest = "^8.2.2"
|
|
33
34
|
coverage = "^7.5.3"
|
|
34
35
|
responses = "^0.25.3"
|
|
36
|
+
pylint = "^3.2.5"
|
|
37
|
+
black = "^24.4.2"
|
|
35
38
|
|
|
36
39
|
|
|
37
40
|
[build-system]
|
|
@@ -46,3 +49,11 @@ include = ["api_to_dataframe*"]
|
|
|
46
49
|
[tool.poetry-dynamic-versioning]
|
|
47
50
|
enable = true
|
|
48
51
|
versioning = "semantic"
|
|
52
|
+
|
|
53
|
+
[tool.pylint.'MESSAGES CONTROL']
|
|
54
|
+
disable = [
|
|
55
|
+
"C0114", # missing-module-docstring
|
|
56
|
+
"C0116", # missing-function-docstring
|
|
57
|
+
"C0115", # missing-class-docstring
|
|
58
|
+
"R0903", # too-few-public-methods
|
|
59
|
+
]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from api_to_dataframe.models.retainer import retry_strategies, Strategies
|
|
2
|
+
from api_to_dataframe.models.get_data import GetData
|
|
3
|
+
from api_to_dataframe.utils.logger import log, LogLevel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ClientBuilder:
|
|
7
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
8
|
+
self,
|
|
9
|
+
endpoint: str,
|
|
10
|
+
headers: dict = None,
|
|
11
|
+
retry_strategy: Strategies = Strategies.NO_RETRY_STRATEGY,
|
|
12
|
+
retries: int = 3,
|
|
13
|
+
initial_delay: int = 1,
|
|
14
|
+
connection_timeout: int = 1,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Initializes the ClientBuilder object.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
endpoint (str): The API endpoint to connect to.
|
|
21
|
+
headers (dict, optional): The headers to use for the API request. Defaults to None.
|
|
22
|
+
retry_strategy (Strategies, optional): Defaults to Strategies.NoRetryStrategy.
|
|
23
|
+
retries (int): The number of times to retry a failed request. Defaults to 3.
|
|
24
|
+
initial_delay (int): The delay between retries in seconds. Defaults to 1.
|
|
25
|
+
connection_timeout (int): The timeout for the connection in seconds. Defaults to 2.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
ValueError: If endpoint is an empty string.
|
|
29
|
+
ValueError: If retries is not a non-negative integer.
|
|
30
|
+
ValueError: If delay is not a non-negative integer.
|
|
31
|
+
ValueError: If connection_timeout is not a non-negative integer.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
if headers is None:
|
|
35
|
+
headers = {}
|
|
36
|
+
if endpoint == "":
|
|
37
|
+
log("endpoint param is mandatory", LogLevel.ERROR)
|
|
38
|
+
raise ValueError
|
|
39
|
+
if not isinstance(retries, int) or retries < 0:
|
|
40
|
+
log("retries must be a non-negative integer", LogLevel.ERROR)
|
|
41
|
+
raise ValueError
|
|
42
|
+
if not isinstance(initial_delay, int) or initial_delay < 0:
|
|
43
|
+
log("delay must be a non-negative integer", LogLevel.ERROR)
|
|
44
|
+
raise ValueError
|
|
45
|
+
if not isinstance(connection_timeout, int) or connection_timeout < 0:
|
|
46
|
+
log("connection_timeout must be a non-negative integer", LogLevel.ERROR)
|
|
47
|
+
raise ValueError
|
|
48
|
+
|
|
49
|
+
self.endpoint = endpoint
|
|
50
|
+
self.retry_strategy = retry_strategy
|
|
51
|
+
self.connection_timeout = connection_timeout
|
|
52
|
+
self.headers = headers
|
|
53
|
+
self.retries = retries
|
|
54
|
+
self.delay = initial_delay
|
|
55
|
+
|
|
56
|
+
@retry_strategies
|
|
57
|
+
def get_api_data(self):
|
|
58
|
+
"""
|
|
59
|
+
Retrieves data from the API using the defined endpoint and retry strategy.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
dict: The response from the API.
|
|
63
|
+
"""
|
|
64
|
+
response = GetData.get_response(
|
|
65
|
+
endpoint=self.endpoint,
|
|
66
|
+
headers=self.headers,
|
|
67
|
+
connection_timeout=self.connection_timeout,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return response.json()
|
|
71
|
+
|
|
72
|
+
def _get_raw_api_data(self):
|
|
73
|
+
response = GetData.get_response(
|
|
74
|
+
endpoint=self.endpoint,
|
|
75
|
+
headers=self.headers,
|
|
76
|
+
connection_timeout=self.connection_timeout,
|
|
77
|
+
)
|
|
78
|
+
return response
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def api_to_dataframe(response: dict):
|
|
82
|
+
df = GetData.to_dataframe(response)
|
|
83
|
+
log("serialized to dataframe: OK", LogLevel.INFO)
|
|
84
|
+
return df
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from api_to_dataframe.utils.logger import log, LogLevel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class GetData:
|
|
8
|
+
@staticmethod
|
|
9
|
+
def get_response(endpoint: str, headers: dict, connection_timeout: int):
|
|
10
|
+
response = requests.get(endpoint, timeout=connection_timeout, headers=headers)
|
|
11
|
+
response.raise_for_status()
|
|
12
|
+
log("get_response: ok", LogLevel.INFO)
|
|
13
|
+
return response
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def to_dataframe(response):
|
|
17
|
+
try:
|
|
18
|
+
df = pd.DataFrame(response)
|
|
19
|
+
except Exception as err:
|
|
20
|
+
log(f"Error serializing to dataframe: {err}", LogLevel.ERROR)
|
|
21
|
+
raise TypeError(
|
|
22
|
+
f"Invalid response for transform in dataframe: {err}"
|
|
23
|
+
) from err
|
|
24
|
+
|
|
25
|
+
if df.empty:
|
|
26
|
+
log("DataFrame is empty", LogLevel.ERROR)
|
|
27
|
+
raise ValueError("::: DataFrame is empty :::")
|
|
28
|
+
|
|
29
|
+
return df
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from requests.exceptions import RequestException
|
|
4
|
+
from api_to_dataframe.utils.logger import log, LogLevel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Strategies(Enum):
|
|
8
|
+
NO_RETRY_STRATEGY = 0
|
|
9
|
+
LINEAR_RETRY_STRATEGY = 1
|
|
10
|
+
EXPONENTIAL_RETRY_STRATEGY = 2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def retry_strategies(func):
|
|
14
|
+
def wrapper(*args, **kwargs): # pylint: disable=inconsistent-return-statements
|
|
15
|
+
retry_number = 0
|
|
16
|
+
while retry_number < args[0].retries:
|
|
17
|
+
try:
|
|
18
|
+
log(
|
|
19
|
+
f"Trying for the {retry_number + 1} of {args[0].retries} retries. "
|
|
20
|
+
f"Using {args[0].retry_strategy}",
|
|
21
|
+
LogLevel.INFO,
|
|
22
|
+
)
|
|
23
|
+
return func(*args, **kwargs)
|
|
24
|
+
except RequestException as e:
|
|
25
|
+
retry_number += 1
|
|
26
|
+
|
|
27
|
+
if args[0].retry_strategy == Strategies.NO_RETRY_STRATEGY:
|
|
28
|
+
raise e
|
|
29
|
+
if args[0].retry_strategy == Strategies.LINEAR_RETRY_STRATEGY:
|
|
30
|
+
time.sleep(args[0].delay)
|
|
31
|
+
elif args[0].retry_strategy == Strategies.EXPONENTIAL_RETRY_STRATEGY:
|
|
32
|
+
time.sleep(args[0].delay * 2**retry_number)
|
|
33
|
+
|
|
34
|
+
if retry_number == args[0].retries:
|
|
35
|
+
log(
|
|
36
|
+
f"Failed after {retry_number} retries using {args[0].retry_strategy}",
|
|
37
|
+
LogLevel.ERROR,
|
|
38
|
+
)
|
|
39
|
+
raise e
|
|
40
|
+
|
|
41
|
+
return wrapper
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LogLevel(Enum):
|
|
6
|
+
INFO = logging.INFO
|
|
7
|
+
WARNING = logging.WARNING
|
|
8
|
+
ERROR = logging.ERROR
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Configure logging once at the start of your program
|
|
12
|
+
logging.basicConfig(
|
|
13
|
+
encoding="utf-8",
|
|
14
|
+
format="%(asctime)s :: %(levelname)s :: %(message)s",
|
|
15
|
+
datefmt="%Y-%m-%d %H:%M:%S %Z",
|
|
16
|
+
level=logging.DEBUG,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def log(message: str, level: LogLevel):
|
|
21
|
+
logger = logging.getLogger("api-to-dataframe")
|
|
22
|
+
logger.log(level.value, message)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
log("This is an info message", LogLevel.INFO)
|
|
26
|
+
log("This is a warning message", LogLevel.WARNING)
|
|
27
|
+
log("This is an error message", LogLevel.ERROR)
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
from api_to_dataframe.models.retainer import RetryStrategies, Strategies
|
|
2
|
-
from api_to_dataframe.models.get_data import GetData
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class ClientBuilder:
|
|
6
|
-
def __init__(self,
|
|
7
|
-
endpoint: str,
|
|
8
|
-
headers: dict = None,
|
|
9
|
-
retry_strategy: Strategies = Strategies.NoRetryStrategy,
|
|
10
|
-
retries: int = 3,
|
|
11
|
-
initial_delay: int = 1,
|
|
12
|
-
connection_timeout: int = 1):
|
|
13
|
-
|
|
14
|
-
"""
|
|
15
|
-
Initializes the ClientBuilder object.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
endpoint (str): The API endpoint to connect to.
|
|
19
|
-
headers (dict, optional): The headers to use for the API request. Defaults to None.
|
|
20
|
-
retry_strategy (Strategies, optional): The strategy to use for retrying failed requests. Defaults to Strategies.NoRetryStrategy.
|
|
21
|
-
retries (int, optional): The number of times to retry a failed request. Defaults to 3.
|
|
22
|
-
delay (int, optional): The delay between retries in seconds. Defaults to 1.
|
|
23
|
-
connection_timeout (int, optional): The timeout for the connection in seconds. Defaults to 2.
|
|
24
|
-
|
|
25
|
-
Raises:
|
|
26
|
-
ValueError: If endpoint is an empty string.
|
|
27
|
-
ValueError: If retries is not a non-negative integer.
|
|
28
|
-
ValueError: If delay is not a non-negative integer.
|
|
29
|
-
ValueError: If connection_timeout is not a non-negative integer.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
if headers is None:
|
|
33
|
-
headers = {}
|
|
34
|
-
if endpoint == "":
|
|
35
|
-
raise ValueError("::: endpoint param is mandatory :::")
|
|
36
|
-
if not isinstance(retries, int) or retries < 0:
|
|
37
|
-
raise ValueError("retries must be a non-negative integer")
|
|
38
|
-
if not isinstance(initial_delay, int) or initial_delay < 0:
|
|
39
|
-
raise ValueError("delay must be a non-negative integer")
|
|
40
|
-
if not isinstance(connection_timeout, int) or connection_timeout < 0:
|
|
41
|
-
raise ValueError("connection_timeout must be a non-negative integer")
|
|
42
|
-
|
|
43
|
-
self.endpoint = endpoint
|
|
44
|
-
self.retry_strategy = retry_strategy
|
|
45
|
-
self.connection_timeout = connection_timeout
|
|
46
|
-
self.headers = headers
|
|
47
|
-
self.retries = retries
|
|
48
|
-
self.delay = initial_delay
|
|
49
|
-
|
|
50
|
-
@RetryStrategies
|
|
51
|
-
def get_api_data(self):
|
|
52
|
-
"""
|
|
53
|
-
Retrieves data from the API using the defined endpoint and retry strategy.
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
dict: The response from the API.
|
|
57
|
-
"""
|
|
58
|
-
response = GetData.get_response(
|
|
59
|
-
endpoint=self.endpoint,
|
|
60
|
-
headers=self.headers,
|
|
61
|
-
connection_timeout=self.connection_timeout
|
|
62
|
-
)
|
|
63
|
-
return response.json()
|
|
64
|
-
|
|
65
|
-
def _get_raw_api_data(self):
|
|
66
|
-
response = GetData.get_response(
|
|
67
|
-
endpoint=self.endpoint,
|
|
68
|
-
headers=self.headers,
|
|
69
|
-
connection_timeout=self.connection_timeout
|
|
70
|
-
)
|
|
71
|
-
return response
|
|
72
|
-
|
|
73
|
-
@staticmethod
|
|
74
|
-
def api_to_dataframe(response: dict):
|
|
75
|
-
df = GetData.to_dataframe(response)
|
|
76
|
-
return df
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
from requests.exceptions import HTTPError, Timeout
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
# from api_to_dataframe.common.utils.retry_strategies import RetryStrategies
|
|
6
|
-
from api_to_dataframe.models.retainer import RetryStrategies
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class GetData:
|
|
10
|
-
@staticmethod
|
|
11
|
-
def get_response(endpoint: str,
|
|
12
|
-
headers: dict,
|
|
13
|
-
connection_timeout: int):
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
response = requests.get(endpoint, timeout=connection_timeout, headers=headers)
|
|
18
|
-
response.raise_for_status()
|
|
19
|
-
return response
|
|
20
|
-
@staticmethod
|
|
21
|
-
def to_dataframe(response):
|
|
22
|
-
try:
|
|
23
|
-
df = pd.DataFrame(response)
|
|
24
|
-
except Exception as err:
|
|
25
|
-
raise TypeError(f"Invalid response for transform in dataframe: {err}")
|
|
26
|
-
|
|
27
|
-
if df.empty:
|
|
28
|
-
raise ValueError("::: DataFrame is empty :::")
|
|
29
|
-
else:
|
|
30
|
-
return df
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Strategies(Enum):
|
|
6
|
-
NoRetryStrategy = 0
|
|
7
|
-
LinearRetryStrategy = 1
|
|
8
|
-
ExponentialRetryStrategy = 2
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def RetryStrategies(func):
|
|
12
|
-
def wrapper(*args, **kwargs):
|
|
13
|
-
retry_number = 0
|
|
14
|
-
while retry_number < args[0].retries:
|
|
15
|
-
try:
|
|
16
|
-
return func(*args, **kwargs)
|
|
17
|
-
except Exception as e:
|
|
18
|
-
retry_number += 1
|
|
19
|
-
|
|
20
|
-
if args[0].retry_strategy == Strategies.NoRetryStrategy:
|
|
21
|
-
raise e
|
|
22
|
-
elif args[0].retry_strategy == Strategies.LinearRetryStrategy:
|
|
23
|
-
time.sleep(args[0].delay)
|
|
24
|
-
elif args[0].retry_strategy == Strategies.ExponentialRetryStrategy:
|
|
25
|
-
time.sleep(args[0].delay * 2 ** retry_number)
|
|
26
|
-
|
|
27
|
-
if retry_number == args[0].retries:
|
|
28
|
-
print(f"Failed after {retry_number} retries using {args[0].retry_strategy}")
|
|
29
|
-
raise e
|
|
30
|
-
return wrapper
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|