data-retrieval-module 1.0.1__tar.gz → 1.0.2__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.
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/PKG-INFO +1 -1
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/__init__.py +8 -4
- data_retrieval_module-1.0.2/data_retrieval/data_provider/__init__.py +5 -0
- data_retrieval_module-1.0.2/data_retrieval/data_provider/database/__init__.py +4 -0
- data_retrieval_module-1.0.2/data_retrieval/data_provider/database/database_data_provider.py +121 -0
- data_retrieval_module-1.0.2/data_retrieval/data_provider/database/sqlite3_data_provider.py +388 -0
- data_retrieval_module-1.0.2/data_retrieval/data_provider/rest_api/__init__.py +12 -0
- data_retrieval_module-1.0.2/data_retrieval/data_provider/rest_api/rest_api_data_provider.py +265 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/PKG-INFO +1 -1
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/SOURCES.txt +6 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/pyproject.toml +2 -2
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/tests/test_basic.py +1 -1
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/CHANGELOG.md +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/LICENSE +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/MANIFEST.in +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/Makefile +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/README.md +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/foreign_exchange/__init__.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/foreign_exchange/forex_data_provider_base.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/foreign_exchange/forex_data_provider_wrapper.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/foreign_exchange/forex_python_data_provider.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/__init__.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/data_module.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/data_provider.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/data_provider_wrapper.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/exceptions.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/py.typed +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/utils/__init__.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/utils/date_utils.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/dependency_links.txt +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/requires.txt +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/top_level.txt +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/requirements-test.txt +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/setup.cfg +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/setup.py +0 -0
- {data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-retrieval-module
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A standardized interface for data providers with sync and async support
|
|
5
5
|
Author-email: AbigailWilliams1692 <abigail.williams@example.com>
|
|
6
6
|
Maintainer-email: AbigailWilliams1692 <abigail.williams@example.com>
|
|
@@ -28,13 +28,16 @@ from data_retrieval.model.exceptions import (
|
|
|
28
28
|
from data_retrieval.data_provider.rest_api import RestAPI_DataProvider
|
|
29
29
|
|
|
30
30
|
# Database providers
|
|
31
|
-
from data_retrieval.data_provider.database import
|
|
31
|
+
from data_retrieval.data_provider.database import (
|
|
32
|
+
Database_DataProvider,
|
|
33
|
+
SQLite3_DataProvider,
|
|
34
|
+
)
|
|
32
35
|
|
|
33
36
|
# Foreign Exchange providers
|
|
34
37
|
from data_retrieval.foreign_exchange import (
|
|
35
38
|
Forex_DataProvider_Base,
|
|
36
39
|
ForexPython_DataProvider,
|
|
37
|
-
Forex_DataProvider_Wrapper
|
|
40
|
+
Forex_DataProvider_Wrapper,
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
#######################################################################
|
|
@@ -58,6 +61,7 @@ __all__ = [
|
|
|
58
61
|
|
|
59
62
|
# Database providers
|
|
60
63
|
"Database_DataProvider",
|
|
64
|
+
"SQLite3_DataProvider",
|
|
61
65
|
|
|
62
66
|
# Foreign Exchange providers
|
|
63
67
|
"Forex_DataProvider_Base",
|
|
@@ -68,6 +72,6 @@ __all__ = [
|
|
|
68
72
|
#######################################################################
|
|
69
73
|
# Version Information
|
|
70
74
|
#######################################################################
|
|
71
|
-
__version__ = "1.0.
|
|
75
|
+
__version__ = "1.0.2"
|
|
72
76
|
__author__ = "AbigailWilliams1692"
|
|
73
|
-
__email__ = "
|
|
77
|
+
__email__ = "alfred.xy1020@gmail.com"
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#######################################################################
|
|
2
|
+
# Project: Data Retrieval Module
|
|
3
|
+
# File: db_provider.py
|
|
4
|
+
# Description: Database data provider implementations
|
|
5
|
+
# Author: AbigailWilliams1692
|
|
6
|
+
# Created: 2026-01-14
|
|
7
|
+
# Updated: 2026-01-19
|
|
8
|
+
#######################################################################
|
|
9
|
+
|
|
10
|
+
#######################################################################
|
|
11
|
+
# Import Packages
|
|
12
|
+
#######################################################################
|
|
13
|
+
# Standard Packages
|
|
14
|
+
import datetime
|
|
15
|
+
import logging
|
|
16
|
+
from abc import ABC, abstractmethod
|
|
17
|
+
from typing import Any, Dict, List, Optional
|
|
18
|
+
|
|
19
|
+
# Third-party Packages
|
|
20
|
+
|
|
21
|
+
# Local Packages
|
|
22
|
+
from data_retrieval.model.data_provider import DataProvider
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
#######################################################################
|
|
26
|
+
# Database Data Provider (Synchronous)
|
|
27
|
+
#######################################################################
|
|
28
|
+
class Database_DataProvider(DataProvider, ABC):
|
|
29
|
+
"""
|
|
30
|
+
Base class for database data providers.
|
|
31
|
+
|
|
32
|
+
This class extends the DataProvider base class to provide database-specific
|
|
33
|
+
functionality for synchronous data retrieval operations. It serves as a
|
|
34
|
+
foundation for implementing various database connection types and query
|
|
35
|
+
operations.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
###################################################################
|
|
39
|
+
# Class Attributes
|
|
40
|
+
###################################################################
|
|
41
|
+
__name = "Database_DataProvider"
|
|
42
|
+
__type = "Database_DataProvider"
|
|
43
|
+
|
|
44
|
+
###################################################################
|
|
45
|
+
# Constructor Method
|
|
46
|
+
###################################################################
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
instance_id: Optional[int] = None,
|
|
50
|
+
logger: Optional[logging.Logger] = None,
|
|
51
|
+
log_level: Optional[int] = logging.INFO,
|
|
52
|
+
**config,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Initialize the Database_DataProvider with the given parameters.
|
|
56
|
+
|
|
57
|
+
:param instance_id: Unique identifier for this provider instance.
|
|
58
|
+
:param logger: Logger instance for logging operations.
|
|
59
|
+
:param log_level: Logging level for the provider.
|
|
60
|
+
:param config: Additional configuration parameters for the database connection.
|
|
61
|
+
"""
|
|
62
|
+
# Super Initialize
|
|
63
|
+
super().__init__(
|
|
64
|
+
instance_id=instance_id,
|
|
65
|
+
logger=logger,
|
|
66
|
+
log_level=log_level,
|
|
67
|
+
**config
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
###################################################################
|
|
71
|
+
# Utility Methods
|
|
72
|
+
###################################################################
|
|
73
|
+
def format_sql_query(self, sql: str, params: Dict[str, Any]) -> str:
|
|
74
|
+
"""
|
|
75
|
+
Format the SQL query string with the given key-value pairs.
|
|
76
|
+
|
|
77
|
+
:param sql: the SQL query template string with placeholders.
|
|
78
|
+
:param params: Dict[str, Any]: a Dictionary of key-value pairs used to parametrize the SQL query.
|
|
79
|
+
:return: the formatted SQL query string.
|
|
80
|
+
"""
|
|
81
|
+
for key, value in params.items():
|
|
82
|
+
placeholder = ":" + key
|
|
83
|
+
|
|
84
|
+
# Covert the value to string based on its type
|
|
85
|
+
if isinstance(value, str):
|
|
86
|
+
value_to_replace = "'" + str(value) + "'"
|
|
87
|
+
elif isinstance(value, (int, float)):
|
|
88
|
+
value_to_replace = str(value)
|
|
89
|
+
elif isinstance(value, datetime.date):
|
|
90
|
+
value_to_replace = "'" + value.strftime("%Y-%m-%d") + "'"
|
|
91
|
+
elif isinstance(value, List):
|
|
92
|
+
value_to_replace = "'" + self.stringify_a_list_of_items_with_apostrophe(item_list=value) + "'"
|
|
93
|
+
else:
|
|
94
|
+
raise TypeError(f"Unsupported value type: {type(value)} for parameter '{key}'")
|
|
95
|
+
|
|
96
|
+
# Replace all the placeholders in the SQL string
|
|
97
|
+
sql = sql.replace(placeholder, value_to_replace, count=-1)
|
|
98
|
+
|
|
99
|
+
return sql
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def stringify_a_list_of_items_with_apostrophe(item_list: List[Any]) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Convert a list of items into a comma-separated string with each item wrapped in apostrophes.
|
|
105
|
+
|
|
106
|
+
:param item_list: List of items to convert.
|
|
107
|
+
:return: String representation of items wrapped in apostrophes and separated by commas.
|
|
108
|
+
"""
|
|
109
|
+
item_str_list = [f"'{str(item)}'" for item in item_list]
|
|
110
|
+
return ",".join(item_str_list)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def generate_markers(size: int, marker: str = "?") -> str:
|
|
114
|
+
"""
|
|
115
|
+
Generate placeholder markers joined by ','.
|
|
116
|
+
|
|
117
|
+
:param size: Number of markers to generate.
|
|
118
|
+
:param marker: Marker string to use (default is "?").
|
|
119
|
+
:return: String of markers joined by commas.
|
|
120
|
+
"""
|
|
121
|
+
return ",".join([marker] * size)
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
########################################################################
|
|
3
|
+
# File: database_service.py
|
|
4
|
+
# Description: SQLite3 database data provider
|
|
5
|
+
# Author: AbigailWilliams1692
|
|
6
|
+
# Creation Date: 2026-01-29
|
|
7
|
+
# Version: 1.0.0
|
|
8
|
+
# License: MIT License
|
|
9
|
+
########################################################################
|
|
10
|
+
|
|
11
|
+
########################################################################
|
|
12
|
+
# Import Libraries
|
|
13
|
+
########################################################################
|
|
14
|
+
# Standard Packages
|
|
15
|
+
import logging
|
|
16
|
+
import sqlite3
|
|
17
|
+
from enum import Enum
|
|
18
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
19
|
+
|
|
20
|
+
# Third-party Packages
|
|
21
|
+
from data_retrieval.data_provider.database.database_data_provider import (
|
|
22
|
+
Database_DataProvider,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
########################################################################
|
|
27
|
+
# SQLite3 Data Provider Class
|
|
28
|
+
########################################################################
|
|
29
|
+
class SQLite3FetchMode(str, Enum):
|
|
30
|
+
"""
|
|
31
|
+
Enum for fetch modes.
|
|
32
|
+
"""
|
|
33
|
+
ALL = "all"
|
|
34
|
+
ONE = "one"
|
|
35
|
+
MANY = "many"
|
|
36
|
+
LAST_ID = "last_id"
|
|
37
|
+
NONE = "none"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class SQLite3_DataProvider(Database_DataProvider):
|
|
41
|
+
"""
|
|
42
|
+
SQLite3 data provider class.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
###################################################################
|
|
46
|
+
# Class Attributes
|
|
47
|
+
###################################################################
|
|
48
|
+
__name = "SQLite3_DataProvider"
|
|
49
|
+
|
|
50
|
+
###################################################################
|
|
51
|
+
# Constructor Method
|
|
52
|
+
###################################################################
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
db_file_path: str,
|
|
56
|
+
instance_id: Optional[int] = None,
|
|
57
|
+
logger: Optional[logging.Logger] = None,
|
|
58
|
+
log_level: Optional[int] = logging.INFO,
|
|
59
|
+
**config,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Initialize the DatabaseService with the given parameters.
|
|
63
|
+
|
|
64
|
+
:param db_file_path: Path to the SQLite database file (.db).
|
|
65
|
+
:param instance_id: Unique identifier for this provider instance.
|
|
66
|
+
:param logger: Logger instance for logging operations.
|
|
67
|
+
:param log_level: Logging level for the provider.
|
|
68
|
+
:param config: Additional configuration parameters.
|
|
69
|
+
"""
|
|
70
|
+
# Super Initialize
|
|
71
|
+
super().__init__(
|
|
72
|
+
instance_id=instance_id,
|
|
73
|
+
logger=logger,
|
|
74
|
+
log_level=log_level,
|
|
75
|
+
**config,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Initialize the DatabaseService attributes
|
|
79
|
+
## Store the database path
|
|
80
|
+
self._db_file_path = db_file_path
|
|
81
|
+
## Initialize the cursor
|
|
82
|
+
self._cursor: Optional[sqlite3.Cursor] = None
|
|
83
|
+
## Connect to the datbase file
|
|
84
|
+
self.connect()
|
|
85
|
+
|
|
86
|
+
# Update data methods
|
|
87
|
+
self.update_data_methods(
|
|
88
|
+
new_methods={
|
|
89
|
+
"execute": self.execute,
|
|
90
|
+
"execute_many": self.execute_many,
|
|
91
|
+
"fetch_one": self.fetch_one,
|
|
92
|
+
"fetch_many": self.fetch_many,
|
|
93
|
+
"fetch_all": self.fetch_all,
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
###################################################################
|
|
98
|
+
# Getter & Setter Methods
|
|
99
|
+
###################################################################
|
|
100
|
+
def get_db_file_path(self) -> str:
|
|
101
|
+
"""
|
|
102
|
+
Get the database file path.
|
|
103
|
+
|
|
104
|
+
:return: The path to the SQLite database file.
|
|
105
|
+
"""
|
|
106
|
+
return self._db_file_path
|
|
107
|
+
|
|
108
|
+
def set_db_file_path(self, db_file_path: str) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Set the database file path.
|
|
111
|
+
|
|
112
|
+
:param db_file_path: The path to the SQLite database file.
|
|
113
|
+
:return: None.
|
|
114
|
+
"""
|
|
115
|
+
self._db_file_path = db_file_path
|
|
116
|
+
|
|
117
|
+
def get_cursor(self) -> Optional[sqlite3.Cursor]:
|
|
118
|
+
"""
|
|
119
|
+
Get the database cursor.
|
|
120
|
+
|
|
121
|
+
:return: The SQLite cursor object.
|
|
122
|
+
"""
|
|
123
|
+
return self._cursor
|
|
124
|
+
|
|
125
|
+
def set_cursor(self, cursor: sqlite3.Cursor) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Set the database cursor.
|
|
128
|
+
|
|
129
|
+
:param cursor: The SQLite cursor object.
|
|
130
|
+
:return: None.
|
|
131
|
+
"""
|
|
132
|
+
self._cursor = cursor
|
|
133
|
+
|
|
134
|
+
###################################################################
|
|
135
|
+
# Connection Methods
|
|
136
|
+
###################################################################
|
|
137
|
+
def _connect(self, *args, **kwargs) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Connect to the SQLite database.
|
|
140
|
+
|
|
141
|
+
Creates a connection to the SQLite database file specified by db_file_path.
|
|
142
|
+
If the file does not exist, SQLite will create it.
|
|
143
|
+
|
|
144
|
+
:param args: Positional arguments (unused).
|
|
145
|
+
:param kwargs: Keyword arguments (unused).
|
|
146
|
+
:return: None.
|
|
147
|
+
:raises sqlite3.Error: If connection fails.
|
|
148
|
+
"""
|
|
149
|
+
# Connect to the database
|
|
150
|
+
conn = sqlite3.connect(self.get_db_file_path())
|
|
151
|
+
|
|
152
|
+
# Set row factory to return rows as sqlite3.Row objects
|
|
153
|
+
conn.row_factory = sqlite3.Row
|
|
154
|
+
|
|
155
|
+
# Set connection and cursor
|
|
156
|
+
self.set_connection(connection=conn)
|
|
157
|
+
self.set_cursor(conn.cursor())
|
|
158
|
+
|
|
159
|
+
def _disconnect(self) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Disconnect from the SQLite database.
|
|
162
|
+
|
|
163
|
+
Closes the cursor and connection to the database.
|
|
164
|
+
|
|
165
|
+
:param args: Positional arguments (unused).
|
|
166
|
+
:param kwargs: Keyword arguments (unused).
|
|
167
|
+
:return: None.
|
|
168
|
+
:raises sqlite3.Error: If disconnection fails.
|
|
169
|
+
"""
|
|
170
|
+
if self._cursor is not None:
|
|
171
|
+
self._cursor.close()
|
|
172
|
+
self._cursor = None
|
|
173
|
+
|
|
174
|
+
conn = self.get_connection()
|
|
175
|
+
if conn is not None:
|
|
176
|
+
conn.close()
|
|
177
|
+
self.set_connection(connection=None)
|
|
178
|
+
|
|
179
|
+
###################################################################
|
|
180
|
+
# Core Instance Method: Execute
|
|
181
|
+
###################################################################
|
|
182
|
+
def execute(
|
|
183
|
+
self,
|
|
184
|
+
sql: str,
|
|
185
|
+
params: Optional[Union[Tuple, Dict[str, Any]]] = None,
|
|
186
|
+
fetch_mode: str = SQLite3FetchMode.ALL,
|
|
187
|
+
commit: bool = True,
|
|
188
|
+
**kwargs,
|
|
189
|
+
) -> Any:
|
|
190
|
+
"""
|
|
191
|
+
Execute a SQL query on the SQLite database.
|
|
192
|
+
|
|
193
|
+
:param sql: The SQL query string to execute.
|
|
194
|
+
:param params: Optional parameters for parameterized queries.
|
|
195
|
+
Can be a tuple for positional params or dict for named params.
|
|
196
|
+
:param fetch: Fetch mode - "all", "one", "many", or "none".
|
|
197
|
+
- "all": Fetch all results (fetchall).
|
|
198
|
+
- "one": Fetch single result (fetchone).
|
|
199
|
+
- "many": Fetch specified number of results (fetchmany).
|
|
200
|
+
- "none": Don't fetch results (for INSERT/UPDATE/DELETE).
|
|
201
|
+
:param commit: Whether to commit the transaction after execution.
|
|
202
|
+
:param kwargs: Additional keyword arguments.
|
|
203
|
+
- fetch_size: Number of rows to fetch when fetch="many".
|
|
204
|
+
:return: Query results based on fetch mode, or lastrowid for INSERT operations.
|
|
205
|
+
:raises sqlite3.Error: If query execution fails.
|
|
206
|
+
:raises ValueError: If invalid fetch mode is specified.
|
|
207
|
+
"""
|
|
208
|
+
# Check if the database is connected
|
|
209
|
+
self.check_db_connection()
|
|
210
|
+
|
|
211
|
+
# Get the connection and the cursor
|
|
212
|
+
conn = self.get_connection()
|
|
213
|
+
cursor = self.get_cursor()
|
|
214
|
+
|
|
215
|
+
# Execute the query with or without parameters
|
|
216
|
+
if params is not None:
|
|
217
|
+
cursor.execute(sql, params)
|
|
218
|
+
else:
|
|
219
|
+
cursor.execute(sql)
|
|
220
|
+
|
|
221
|
+
# Commit if requested
|
|
222
|
+
if commit:
|
|
223
|
+
conn.commit()
|
|
224
|
+
|
|
225
|
+
# Fetch results based on mode
|
|
226
|
+
if fetch_mode == "all":
|
|
227
|
+
return cursor.fetchall()
|
|
228
|
+
elif fetch_mode == "one":
|
|
229
|
+
return cursor.fetchone()
|
|
230
|
+
elif fetch_mode == "many":
|
|
231
|
+
fetch_size = kwargs.get("fetch_size", 100)
|
|
232
|
+
return cursor.fetchmany(fetch_size)
|
|
233
|
+
elif fetch_mode == "last_id":
|
|
234
|
+
return cursor.lastrowid
|
|
235
|
+
elif fetch_mode == "none":
|
|
236
|
+
return None
|
|
237
|
+
else:
|
|
238
|
+
raise ValueError(f"Invalid fetch mode: {fetch_mode}. Must be 'all', 'one', 'many', or 'none'.")
|
|
239
|
+
|
|
240
|
+
def execute_many(
|
|
241
|
+
self,
|
|
242
|
+
sql: str,
|
|
243
|
+
params_list: List[Union[Tuple, Dict[str, Any]]],
|
|
244
|
+
fetch_mode: str = "all",
|
|
245
|
+
commit: bool = True,
|
|
246
|
+
) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Execute a SQL statement on the SQLite database multiple times with different parameters.
|
|
249
|
+
|
|
250
|
+
:param sql: The SQL statement to execute.
|
|
251
|
+
:param params_list: List of parameter tuples or dicts.
|
|
252
|
+
:param commit: Whether to commit the transaction (default: True).
|
|
253
|
+
:return: None.
|
|
254
|
+
"""
|
|
255
|
+
# Check if the database is connected
|
|
256
|
+
self.check_db_connection()
|
|
257
|
+
|
|
258
|
+
# Get the connection and the cursor
|
|
259
|
+
conn = self.get_connection()
|
|
260
|
+
cursor = self.get_cursor()
|
|
261
|
+
|
|
262
|
+
# Execute the query with multiple parameter groups
|
|
263
|
+
cursor.executemany(sql, params_list)
|
|
264
|
+
|
|
265
|
+
# Commit if requested
|
|
266
|
+
if commit:
|
|
267
|
+
conn.commit()
|
|
268
|
+
|
|
269
|
+
# Fetch results based on mode
|
|
270
|
+
if fetch_mode == "all":
|
|
271
|
+
return cursor.fetchall()
|
|
272
|
+
elif fetch_mode == "one":
|
|
273
|
+
return cursor.fetchone()
|
|
274
|
+
elif fetch_mode == "many":
|
|
275
|
+
fetch_size = kwargs.get("fetch_size", 100)
|
|
276
|
+
return cursor.fetchmany(fetch_size)
|
|
277
|
+
elif fetch_mode == "last_id":
|
|
278
|
+
return cursor.lastrowid
|
|
279
|
+
elif fetch_mode == "none":
|
|
280
|
+
return None
|
|
281
|
+
else:
|
|
282
|
+
raise ValueError(f"Invalid fetch mode: {fetch_mode}. Must be 'all', 'one', 'many', or 'none'.")
|
|
283
|
+
|
|
284
|
+
###################################################################
|
|
285
|
+
# Core Instance Methods: Fetch One/Many/All
|
|
286
|
+
###################################################################
|
|
287
|
+
def fetch_one(
|
|
288
|
+
self,
|
|
289
|
+
sql: str,
|
|
290
|
+
params: Optional[Union[Tuple, Dict[str, Any]]] = None,
|
|
291
|
+
) -> Optional[sqlite3.Row]:
|
|
292
|
+
"""
|
|
293
|
+
Execute a SELECT query and fetch a single result.
|
|
294
|
+
|
|
295
|
+
:param sql: The SQL SELECT query.
|
|
296
|
+
:param params: Optional parameters for parameterized queries.
|
|
297
|
+
:return: Single result row or None.
|
|
298
|
+
"""
|
|
299
|
+
return self.execute(sql=sql, params=params, fetch="one")
|
|
300
|
+
|
|
301
|
+
def fetch_many(
|
|
302
|
+
self,
|
|
303
|
+
sql: str,
|
|
304
|
+
params: Optional[Union[Tuple, Dict[str, Any]]] = None,
|
|
305
|
+
fetch_size: int = 100,
|
|
306
|
+
) -> List[sqlite3.Row]:
|
|
307
|
+
"""
|
|
308
|
+
Execute a SELECT query and fetch multiple results.
|
|
309
|
+
|
|
310
|
+
:param sql: The SQL SELECT query.
|
|
311
|
+
:param params: Optional parameters for parameterized queries.
|
|
312
|
+
:param fetch_size: Number of rows to fetch (default: 100).
|
|
313
|
+
:return: List of result rows.
|
|
314
|
+
"""
|
|
315
|
+
return self.execute(sql=sql, params=params, fetch="many", fetch_size=fetch_size)
|
|
316
|
+
|
|
317
|
+
def fetch_all(
|
|
318
|
+
self,
|
|
319
|
+
sql: str,
|
|
320
|
+
params: Optional[Union[Tuple, Dict[str, Any]]] = None,
|
|
321
|
+
) -> List[sqlite3.Row]:
|
|
322
|
+
"""
|
|
323
|
+
Execute a SELECT query and fetch all results.
|
|
324
|
+
|
|
325
|
+
:param sql: The SQL SELECT query.
|
|
326
|
+
:param params: Optional parameters for parameterized queries.
|
|
327
|
+
:return: List of all result rows.
|
|
328
|
+
"""
|
|
329
|
+
return self.execute(sql=sql, params=params, fetch="all")
|
|
330
|
+
|
|
331
|
+
###################################################################
|
|
332
|
+
# Core Instance Method: Commit
|
|
333
|
+
###################################################################
|
|
334
|
+
def commit(self) -> None:
|
|
335
|
+
"""
|
|
336
|
+
Commit the current transaction.
|
|
337
|
+
"""
|
|
338
|
+
self.check_db_connection()
|
|
339
|
+
self.get_connection().commit()
|
|
340
|
+
|
|
341
|
+
###################################################################
|
|
342
|
+
# Core Instance Method: Rollback
|
|
343
|
+
###################################################################
|
|
344
|
+
def rollback(self) -> None:
|
|
345
|
+
"""
|
|
346
|
+
Rollback the current transaction.
|
|
347
|
+
|
|
348
|
+
:return: None.
|
|
349
|
+
"""
|
|
350
|
+
self.check_db_connection()
|
|
351
|
+
self.get_connection().rollback()
|
|
352
|
+
|
|
353
|
+
###################################################################
|
|
354
|
+
# Utility Methods
|
|
355
|
+
###################################################################
|
|
356
|
+
def check_db_connection(self) -> None:
|
|
357
|
+
"""
|
|
358
|
+
Check connection and raise sqlite3.OperationalError if not connected.
|
|
359
|
+
"""
|
|
360
|
+
if not self.is_connected():
|
|
361
|
+
raise sqlite3.OperationalError("Database is not connected. Call connect() first.")
|
|
362
|
+
|
|
363
|
+
def table_exists(self, table_name: str) -> bool:
|
|
364
|
+
"""
|
|
365
|
+
Check if a table exists in the database.
|
|
366
|
+
|
|
367
|
+
:param table_name: Name of the table to check.
|
|
368
|
+
:return: True if table exists, False otherwise.
|
|
369
|
+
"""
|
|
370
|
+
sql = """
|
|
371
|
+
SELECT name
|
|
372
|
+
FROM sqlite_master
|
|
373
|
+
WHERE type='table'
|
|
374
|
+
AND name=?
|
|
375
|
+
"""
|
|
376
|
+
result = self.fetch_one(sql=sql, params=(table_name,))
|
|
377
|
+
return result is not None
|
|
378
|
+
|
|
379
|
+
def get_table_info(self, table_name: str) -> List[sqlite3.Row]:
|
|
380
|
+
"""
|
|
381
|
+
Get column information for a table.
|
|
382
|
+
|
|
383
|
+
:param table_name: Name of the table.
|
|
384
|
+
:return: List of column information rows.
|
|
385
|
+
"""
|
|
386
|
+
self.check_db_connection()
|
|
387
|
+
sql = f"PRAGMA table_info({table_name})"
|
|
388
|
+
return self.fetch_all(sql=sql)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#######################################################################
|
|
2
|
+
# Project: Data Retrieval Module
|
|
3
|
+
# File: __init__.py
|
|
4
|
+
# Description: REST API data provider package initialization
|
|
5
|
+
# Author: AbigailWilliams1692
|
|
6
|
+
# Created: 2026-01-14
|
|
7
|
+
# Updated: 2026-01-18
|
|
8
|
+
#######################################################################
|
|
9
|
+
|
|
10
|
+
from .rest_api_data_provider import RestAPI_DataProvider
|
|
11
|
+
|
|
12
|
+
__all__ = ["RestAPI_DataProvider"]
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#######################################################################
|
|
2
|
+
# Project: Data Retrieval Module
|
|
3
|
+
# File: rest_api_provider.py
|
|
4
|
+
# Description: REST API data provider implementations
|
|
5
|
+
# Author: AbigailWilliams1692
|
|
6
|
+
# Created: 2026-01-14
|
|
7
|
+
# Updated: 2026-01-19
|
|
8
|
+
#######################################################################
|
|
9
|
+
|
|
10
|
+
#######################################################################
|
|
11
|
+
# Import Packages
|
|
12
|
+
#######################################################################
|
|
13
|
+
# Standard Packages
|
|
14
|
+
import logging
|
|
15
|
+
from abc import ABC
|
|
16
|
+
from collections.abc import Generator
|
|
17
|
+
from typing import Any, Dict, List, Optional
|
|
18
|
+
|
|
19
|
+
# Third-party Packages
|
|
20
|
+
import requests
|
|
21
|
+
from requests import Response
|
|
22
|
+
from requests.adapters import HTTPAdapter
|
|
23
|
+
from requests.auth import HTTPBasicAuth
|
|
24
|
+
from urllib3.util import Retry
|
|
25
|
+
|
|
26
|
+
# Local Packages
|
|
27
|
+
from data_retrieval.model.data_provider import DataProvider
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#######################################################################
|
|
31
|
+
# REST API Data Provider (Synchronous)
|
|
32
|
+
#######################################################################
|
|
33
|
+
class RestAPI_DataProvider(DataProvider, ABC):
|
|
34
|
+
"""
|
|
35
|
+
Synchronous REST API data provider.
|
|
36
|
+
|
|
37
|
+
Provides standardized interface for interacting with REST APIs.
|
|
38
|
+
Supports authentication, pagination, error handling, and retry logic.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
###################################################################
|
|
42
|
+
# Class Attributes
|
|
43
|
+
###################################################################
|
|
44
|
+
__name = "RestAPI_DataProvider"
|
|
45
|
+
__type = "RestAPI_DataProvider"
|
|
46
|
+
__base_url: str = ""
|
|
47
|
+
|
|
48
|
+
###################################################################
|
|
49
|
+
# Constructor Method
|
|
50
|
+
###################################################################
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
instance_id: Optional[int] = None,
|
|
54
|
+
logger: Optional[logging.Logger] = None,
|
|
55
|
+
log_level: Optional[int] = logging.INFO,
|
|
56
|
+
base_url: Optional[str] = None,
|
|
57
|
+
timeout: int = 30,
|
|
58
|
+
max_retries: int = 3,
|
|
59
|
+
retry_backoff_factor: float = 0.3,
|
|
60
|
+
**config
|
|
61
|
+
) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Initialize the REST API data provider.
|
|
64
|
+
|
|
65
|
+
:param instance_id: Unique identifier for this provider instance.
|
|
66
|
+
:param logger: Logger instance for logging operations.
|
|
67
|
+
:param log_level: Logging level for the data provider.
|
|
68
|
+
:param data_methods: Dictionary of data retrieval methods.
|
|
69
|
+
:param base_url: Base URL for the REST API.
|
|
70
|
+
:param timeout: Request timeout in seconds.
|
|
71
|
+
:param max_retries: Maximum number of retry attempts.
|
|
72
|
+
:param retry_backoff_factor: Backoff factor for retry delays.
|
|
73
|
+
:param config: Additional configuration parameters.
|
|
74
|
+
"""
|
|
75
|
+
# Initialize the base DataProvider
|
|
76
|
+
super().__init__(
|
|
77
|
+
instance_id=instance_id,
|
|
78
|
+
logger=logger,
|
|
79
|
+
log_level=log_level,
|
|
80
|
+
**config
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Prepare the data methods
|
|
84
|
+
self.update_data_methods(
|
|
85
|
+
{
|
|
86
|
+
"http_request": self._make_request,
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Initialize REST API specific attributes
|
|
91
|
+
self._base_url = base_url or self.__base_url
|
|
92
|
+
self._timeout = timeout
|
|
93
|
+
self._max_retries = max_retries
|
|
94
|
+
self._retry_backoff_factor = retry_backoff_factor
|
|
95
|
+
|
|
96
|
+
# Connect to the Session
|
|
97
|
+
self.connect()
|
|
98
|
+
|
|
99
|
+
# Initialize session with retry strategy
|
|
100
|
+
retry_strategy = Retry(
|
|
101
|
+
total=max_retries,
|
|
102
|
+
backoff_factor=retry_backoff_factor,
|
|
103
|
+
status_forcelist=[429, 500, 502, 503, 504],
|
|
104
|
+
allowed_methods=["HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
|
105
|
+
)
|
|
106
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
107
|
+
self.get_connection().mount("http://", adapter)
|
|
108
|
+
self.get_connection().mount("https://", adapter)
|
|
109
|
+
|
|
110
|
+
###################################################################
|
|
111
|
+
# Getter & Setter Methods
|
|
112
|
+
###################################################################
|
|
113
|
+
def get_base_url(self) -> str:
|
|
114
|
+
"""
|
|
115
|
+
Get the base URL of the API server.
|
|
116
|
+
|
|
117
|
+
:return: The base URL of the API server.
|
|
118
|
+
"""
|
|
119
|
+
return self.__base_url
|
|
120
|
+
|
|
121
|
+
def set_base_url(self, base_url: str) -> None:
|
|
122
|
+
"""
|
|
123
|
+
Set the base URL of the API server.
|
|
124
|
+
|
|
125
|
+
:param base_url: The base URL of the API server.
|
|
126
|
+
"""
|
|
127
|
+
self.__base_url = base_url.rstrip("/")
|
|
128
|
+
|
|
129
|
+
###################################################################
|
|
130
|
+
# Core Instance Method: Make Request to REST API Server
|
|
131
|
+
###################################################################
|
|
132
|
+
def _make_request(
|
|
133
|
+
self,
|
|
134
|
+
url: str,
|
|
135
|
+
method: str,
|
|
136
|
+
params: Optional[Dict] = None,
|
|
137
|
+
data: Optional[Dict] = None,
|
|
138
|
+
json: Optional[Dict] = None,
|
|
139
|
+
headers: Optional[Dict] = None,
|
|
140
|
+
authentication: Optional[Any] = None,
|
|
141
|
+
) -> Dict:
|
|
142
|
+
"""
|
|
143
|
+
Make HTTP request to REST API endpoint.
|
|
144
|
+
|
|
145
|
+
:param url: Endpoint URL (relative to base_url)
|
|
146
|
+
:param method: HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
147
|
+
:param params: Query parameters
|
|
148
|
+
:param data: Form data to send
|
|
149
|
+
:param json: JSON data to send
|
|
150
|
+
:param headers: Additional headers
|
|
151
|
+
:param authentication: Override default authentication
|
|
152
|
+
|
|
153
|
+
:return: Response data as dictionary.
|
|
154
|
+
:raises: HTTPError if request fails.
|
|
155
|
+
"""
|
|
156
|
+
# Logging the Request
|
|
157
|
+
self.get_logger().debug(f"Making {method.upper()} request to {url}")
|
|
158
|
+
|
|
159
|
+
# Make the request
|
|
160
|
+
try:
|
|
161
|
+
response: Response = self.get_connection().request(
|
|
162
|
+
method=method.upper(),
|
|
163
|
+
url=url,
|
|
164
|
+
params=params,
|
|
165
|
+
data=data,
|
|
166
|
+
json=json,
|
|
167
|
+
headers=headers,
|
|
168
|
+
auth=authentication,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
## Raise an error for bad response (4xx and 5xx)
|
|
172
|
+
response.raise_for_status()
|
|
173
|
+
|
|
174
|
+
## If the response is successful, return the JSON content
|
|
175
|
+
self.get_logger().debug(f"Request succeeded: {response.status_code}.")
|
|
176
|
+
return response.json()
|
|
177
|
+
|
|
178
|
+
except requests.exceptions.RequestException as e:
|
|
179
|
+
self.get_logger().error(f"Request failed: {e}")
|
|
180
|
+
return {}
|
|
181
|
+
|
|
182
|
+
###################################################################
|
|
183
|
+
# Core Instance Method: Fetch Data
|
|
184
|
+
##################################################################
|
|
185
|
+
def fetch_data(self, data_point: str, return_data_type: type, *args, **kwargs) -> Any:
|
|
186
|
+
"""
|
|
187
|
+
Base method to fetch data based on the data point and return type.
|
|
188
|
+
|
|
189
|
+
:param data_point: str: The data point to fetch.
|
|
190
|
+
:param return_data_type: type: The type of data to return.
|
|
191
|
+
:param args: Tuple: Positional arguments for fetching data.
|
|
192
|
+
:param kwargs: Dict: Keyword arguments for fetching data.
|
|
193
|
+
:return: The fetched data.
|
|
194
|
+
"""
|
|
195
|
+
return super().fetch_data(data_point=data_point, return_data_type=return_data_type, *args, **kwargs)
|
|
196
|
+
|
|
197
|
+
###################################################################
|
|
198
|
+
# Connection Methods
|
|
199
|
+
###################################################################
|
|
200
|
+
def _connect(self) -> None:
|
|
201
|
+
"""
|
|
202
|
+
Connect to Aladdin API server.
|
|
203
|
+
"""
|
|
204
|
+
self.set_connection(connection=requests.Session())
|
|
205
|
+
|
|
206
|
+
def _disconnect(self, *args, **kwargs):
|
|
207
|
+
if self.get_connection() is not None:
|
|
208
|
+
self.get_connection().close()
|
|
209
|
+
self.set_connection(connection=None)
|
|
210
|
+
|
|
211
|
+
###################################################################
|
|
212
|
+
# Utility Methods
|
|
213
|
+
###################################################################
|
|
214
|
+
@staticmethod
|
|
215
|
+
def generate_headers(*args, **kwargs) -> Dict:
|
|
216
|
+
"""
|
|
217
|
+
Generate default HTTP headers for API requests.
|
|
218
|
+
|
|
219
|
+
:param args: Additional positional arguments (unused).
|
|
220
|
+
:param kwargs: Additional keyword arguments (unused).
|
|
221
|
+
:return: Dictionary containing default HTTP headers.
|
|
222
|
+
"""
|
|
223
|
+
headers = {
|
|
224
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
225
|
+
"Accept": "application/json, text/plain, */*",
|
|
226
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
227
|
+
"Content-Type": "application/json",
|
|
228
|
+
"Connection": "keep-alive",
|
|
229
|
+
}
|
|
230
|
+
return headers
|
|
231
|
+
|
|
232
|
+
def generate_authentication(self, authentication_type: str, *args, **kwargs) -> Any:
|
|
233
|
+
"""
|
|
234
|
+
Generate the authentication for the request.
|
|
235
|
+
|
|
236
|
+
:param args: Additional positional arguments (unused).
|
|
237
|
+
:param kwargs: Additional keyword arguments (unused).
|
|
238
|
+
:return: the Authentication.
|
|
239
|
+
"""
|
|
240
|
+
if authentication_type == "HTTPBasicAuth":
|
|
241
|
+
return self.generate_http_authentication(*args, **kwargs)
|
|
242
|
+
else:
|
|
243
|
+
return None
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def generate_http_authentication(username: str, password: str) -> Any:
|
|
247
|
+
"""
|
|
248
|
+
Generate HTTP authentication for the request.
|
|
249
|
+
|
|
250
|
+
:param username: The username for authentication.
|
|
251
|
+
:param password: The password for authentication.
|
|
252
|
+
:return: The HTTP authentication.
|
|
253
|
+
"""
|
|
254
|
+
return HTTPBasicAuth(username=username, password=password)
|
|
255
|
+
|
|
256
|
+
@staticmethod
|
|
257
|
+
def partition_list_into_chunks(item_list: List[Any], chunk_length: int = 100) -> Generator[List[Any], None, None]:
|
|
258
|
+
"""
|
|
259
|
+
Return a generator that yields successive n-size chunks of list of items.
|
|
260
|
+
|
|
261
|
+
:param item_list: a list of items.
|
|
262
|
+
:param chunk_length: the length of each chunk.
|
|
263
|
+
"""
|
|
264
|
+
for i in range(0, len(item_list), chunk_length):
|
|
265
|
+
yield item_list[i:i + chunk_length]
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval_module.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: data-retrieval-module
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A standardized interface for data providers with sync and async support
|
|
5
5
|
Author-email: AbigailWilliams1692 <abigail.williams@example.com>
|
|
6
6
|
Maintainer-email: AbigailWilliams1692 <abigail.williams@example.com>
|
|
@@ -8,6 +8,12 @@ requirements-test.txt
|
|
|
8
8
|
setup.py
|
|
9
9
|
data_retrieval/__init__.py
|
|
10
10
|
data_retrieval/py.typed
|
|
11
|
+
data_retrieval/data_provider/__init__.py
|
|
12
|
+
data_retrieval/data_provider/database/__init__.py
|
|
13
|
+
data_retrieval/data_provider/database/database_data_provider.py
|
|
14
|
+
data_retrieval/data_provider/database/sqlite3_data_provider.py
|
|
15
|
+
data_retrieval/data_provider/rest_api/__init__.py
|
|
16
|
+
data_retrieval/data_provider/rest_api/rest_api_data_provider.py
|
|
11
17
|
data_retrieval/foreign_exchange/__init__.py
|
|
12
18
|
data_retrieval/foreign_exchange/forex_data_provider_base.py
|
|
13
19
|
data_retrieval/foreign_exchange/forex_data_provider_wrapper.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "data-retrieval-module"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.2"
|
|
8
8
|
description = "A standardized interface for data providers with sync and async support"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -80,7 +80,7 @@ Repository = "https://github.com/AbigailWilliams1692/data-retrieval-module"
|
|
|
80
80
|
Changelog = "https://github.com/AbigailWilliams1692/data-retrieval-module/blob/main/CHANGELOG.md"
|
|
81
81
|
|
|
82
82
|
[tool.setuptools]
|
|
83
|
-
packages = ["data_retrieval", "data_retrieval.model", "data_retrieval.foreign_exchange", "data_retrieval.utils"]
|
|
83
|
+
packages = ["data_retrieval", "data_retrieval.model", "data_retrieval.foreign_exchange", "data_retrieval.utils", "data_retrieval.data_provider", "data_retrieval.data_provider.database", "data_retrieval.data_provider.rest_api"]
|
|
84
84
|
|
|
85
85
|
[tool.setuptools.package-data]
|
|
86
86
|
data_retrieval = ["py.typed"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/__init__.py
RENAMED
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/data_module.py
RENAMED
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/data_provider.py
RENAMED
|
File without changes
|
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/model/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/utils/__init__.py
RENAMED
|
File without changes
|
{data_retrieval_module-1.0.1 → data_retrieval_module-1.0.2}/data_retrieval/utils/date_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|