data-retrieval-module 1.0.0__py3-none-any.whl

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.
@@ -0,0 +1,61 @@
1
+ #######################################################################
2
+ # Project: Data Retrieval Module
3
+ # File: __init__.py
4
+ # Description: Data Retrieval Module package initialization
5
+ # Author: AbigailWilliams1692
6
+ # Created: 2026-01-14
7
+ # Updated: 2026-01-18
8
+ #######################################################################
9
+
10
+ #######################################################################
11
+ # Import Core Classes
12
+ #######################################################################
13
+ from data_retrieval.model.data_provider import DataProvider
14
+ from data_retrieval.model.data_module import DataModule
15
+ from data_retrieval.model.exceptions import (
16
+ DataProviderError,
17
+ DataProviderConnectionError,
18
+ DataFetchError,
19
+ DataMethodNotFoundError,
20
+ ReturnDataTypeNotMatchedError,
21
+ ValidationError
22
+ )
23
+
24
+ #######################################################################
25
+ # Import Data Provider Implementations
26
+ #######################################################################
27
+ # REST API providers
28
+ from data_retrieval.data_provider.rest_api import RestAPI_DataProvider
29
+
30
+ # Database providers
31
+ from data_retrieval.data_provider.database import Database_DataProvider
32
+
33
+ #######################################################################
34
+ # Public API
35
+ #######################################################################
36
+ __all__ = [
37
+ # Core classes
38
+ "DataProvider",
39
+ "DataModule",
40
+
41
+ # Exceptions
42
+ "DataProviderError",
43
+ "DataProviderConnectionError",
44
+ "DataFetchError",
45
+ "DataMethodNotFoundError",
46
+ "ReturnDataTypeNotMatchedError",
47
+ "ValidationError",
48
+
49
+ # REST API providers
50
+ "RestAPI_DataProvider",
51
+
52
+ # Database providers
53
+ "Database_DataProvider",
54
+ ]
55
+
56
+ #######################################################################
57
+ # Version Information
58
+ #######################################################################
59
+ __version__ = "1.0.0"
60
+ __author__ = "AbigailWilliams1692"
61
+ __email__ = "abigail.williams@example.com"
@@ -0,0 +1,11 @@
1
+ #######################################################################
2
+ # Project: Data Retrieval Module
3
+ # File: __init__.py
4
+ # Description: Model Package Initialization
5
+ # Author: AbigailWilliams1692
6
+ # Created: 2026-01-14
7
+ # Updated: 2026-01-18
8
+ #######################################################################
9
+
10
+ from data_retrieval.model.data_module import DataModule
11
+ from data_retrieval.model.data_provider import DataProvider
@@ -0,0 +1,150 @@
1
+ #######################################################################
2
+ # Project: Data Retrieval Module
3
+ # File: data_module.py
4
+ # Description: Abstract base class for aall data modules
5
+ # Author: AbigailWilliams1692
6
+ # Created: 2025-11-13
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 typing import Any, Optional
17
+
18
+ # Local Packages
19
+
20
+
21
+ #################################################
22
+ # Class Definition
23
+ #################################################
24
+ class DataModule(ABC):
25
+ """
26
+ Data Module Abstract Base Class. Provides the interface for all data modules.
27
+ """
28
+
29
+ #################################################
30
+ # Class Attributes
31
+ #################################################
32
+ __name: str = "BaseDataModule"
33
+ __type: str = "DataModule"
34
+
35
+ #################################################
36
+ # Constructor
37
+ #################################################
38
+ def __init__(
39
+ self,
40
+ instance_id: Optional[int] = None,
41
+ logger: Optional[logging.Logger] = None,
42
+ log_level: Optional[int] = logging.INFO,
43
+ ) -> None:
44
+ """
45
+ Constructor method.
46
+
47
+ :param instance_id: str: Unique identifier for the data module instance.
48
+ :param logger: logging.Logger: Logger instance for logging.
49
+ """
50
+ # DataProvider ID
51
+ self._instance_id = instance_id or id(self)
52
+
53
+ # Log Level
54
+ self._log_level = log_level
55
+
56
+ # Logger
57
+ self._logger = logger or self.refresh_logger()
58
+
59
+ # Status
60
+ self._status = None
61
+
62
+ #################################################
63
+ # Getter & Setter Methods
64
+ #################################################
65
+ def get_name(self) -> str:
66
+ """
67
+ Get the name of the data module.
68
+
69
+ :return: str: Name of the data module.
70
+ """
71
+ return self.__name
72
+
73
+ def get_type(self) -> str:
74
+ """
75
+ Get the type of the data module.
76
+
77
+ :return: str: Type of the data module.
78
+ """
79
+ return self.__type
80
+
81
+ def get_instance_id(self) -> str:
82
+ """
83
+ Get the unique identifier of the data module instance.
84
+
85
+ :return: str: Unique identifier of the data module instance.
86
+ """
87
+ return self._instance_id
88
+
89
+ def set_instance_id(self, instance_id: str) -> None:
90
+ """
91
+ Set the unique identifier of the data module instance.
92
+
93
+ :param instance_id: str: Unique identifier of the data module instance.
94
+ """
95
+ self._instance_id = instance_id
96
+
97
+ def get_logger(self) -> logging.Logger:
98
+ """
99
+ Get the logger instance.
100
+
101
+ :return: logging.Logger: Logger instance.
102
+ """
103
+ return self._logger
104
+
105
+ def set_logger(self, logger: logging.Logger) -> None:
106
+ """
107
+ Set the logger instance.
108
+
109
+ :param logger: logging.Logger: Logger instance.
110
+ """
111
+ self._logger = logger
112
+
113
+ def refresh_logger(self) -> logging.Logger:
114
+ """
115
+ Refresh the logger instance.
116
+ """
117
+ logger = logging.getLogger(name=self.__class__.__name__)
118
+ logger.setLevel(self._log_level)
119
+ return logger
120
+
121
+ def get_log_level(self) -> int:
122
+ """
123
+ Get the log level of the logger instance.
124
+
125
+ :return: int: Log level of the logger instance.
126
+ """
127
+ return self._log_level
128
+
129
+ def set_log_level(self, log_level: int) -> None:
130
+ """
131
+ Set the log level of the logger instance.
132
+
133
+ :param log_level: int: Log level of the logger instance.
134
+ """
135
+ self._logger.setLevel(level=log_level)
136
+
137
+ def get_status(self) -> Any:
138
+ """Get the preoccupation status of the data module.
139
+
140
+ :return: Any: Preoccupation status of the data module.
141
+ """
142
+ return self._status
143
+
144
+ def set_status(self, status: Any) -> None:
145
+ """
146
+ Set the preoccupation status of the data module.
147
+
148
+ :param status: Any: Preoccupation status of the data module.
149
+ """
150
+ self._status = status
@@ -0,0 +1,313 @@
1
+ #######################################################################
2
+ # Project: Data Retrieval Module
3
+ # File: data_provider.py
4
+ # Description: Abstract base class for data providers
5
+ # Author: AbigailWilliams1692
6
+ # Created: 2025-11-13
7
+ # Updated: 2026-01-18
8
+ #######################################################################
9
+
10
+ #######################################################################
11
+ # Import Packages
12
+ #######################################################################
13
+ # Standard Packages
14
+ import logging
15
+ from abc import abstractmethod
16
+ from collections.abc import Callable
17
+ from enum import Enum
18
+ from typing import (
19
+ Any,
20
+ Optional,
21
+ Dict,
22
+ Callable,
23
+ )
24
+
25
+ # Local Packages
26
+ from data_retrieval.model.data_module import DataModule
27
+ from data_retrieval.model.exceptions import (
28
+ DataProviderConnectionError,
29
+ DataMethodNotFoundError,
30
+ ReturnDataTypeNotMatchedError,
31
+ )
32
+
33
+
34
+ #######################################################################
35
+ # Enums & Data Classes
36
+ #######################################################################
37
+ class DataProviderConnectionStatus(Enum):
38
+ """
39
+ Enumeration of provider connection states.
40
+ """
41
+ DISCONNECTED = "disconnected"
42
+ CONNECTED = "connected"
43
+ ERROR = "error"
44
+
45
+
46
+ #######################################################################
47
+ # Data Provider Class
48
+ #######################################################################
49
+ class DataProvider(DataModule):
50
+ """
51
+ Abstract base class for data providers with standardized synchronous API interface.
52
+
53
+ This class provides a unified interface for retrieving data from various sources
54
+ (APIs, databases, files, etc.). Subclasses must implement the abstract methods
55
+ to provide source-specific data retrieval logic.
56
+ """
57
+
58
+ #################################################
59
+ # Class Attributes
60
+ #################################################
61
+ __name: str = "DataProvider"
62
+ __type: str = "DataProvider"
63
+
64
+ #################################################
65
+ # Constructor
66
+ #################################################
67
+ def __init__(
68
+ self,
69
+ instance_id: Optional[int] = None,
70
+ logger: Optional[logging.Logger] = None,
71
+ log_level: Optional[int] = logging.INFO,
72
+ **config,
73
+ ) -> None:
74
+ """
75
+ Initialize the data provider.
76
+
77
+ :param instance_id: Unique identifier for this provider instance.
78
+ :param logger: Logger instance for logging operations.
79
+ :param log_level: Logging level for the provider.
80
+ :param data_methods: Dictionary of data retrieval methods.
81
+ :param config: Additional configuration parameters.
82
+ """
83
+ # Initialize the base DataModule
84
+ super().__init__(
85
+ instance_id=instance_id,
86
+ logger=logger,
87
+ log_level=log_level,
88
+ )
89
+
90
+ # Intialize DataProvider attributes
91
+ self._config = config or {}
92
+ self._connection = None
93
+ self._data_methods = {}
94
+
95
+ # Set initial status for the DataProvider instance
96
+ self.set_status(DataProviderConnectionStatus.DISCONNECTED)
97
+
98
+ #################################################
99
+ # Getter & Setter Methods
100
+ #################################################
101
+ def get_config(self) -> Dict[str, Any]:
102
+ """
103
+ Get the configuration dictionary.
104
+
105
+ :return: The configuration dictionary.
106
+ """
107
+ return self._config
108
+
109
+ def set_config(self, config: Dict[str, Any]) -> None:
110
+ """
111
+ Set the configuration dictionary.
112
+
113
+ :param config: The configuration dictionary.
114
+ :return: None.
115
+ """
116
+ self._config = config
117
+
118
+ def update_config(self, key: str, value: Any) -> None:
119
+ """
120
+ Update a specific configuration key-value pair.
121
+
122
+ :param key: The configuration key to update.
123
+ :param value: The new value for the configuration key.
124
+ :return: None.
125
+ """
126
+ self._config.update({key: value})
127
+
128
+ def get_connection(self) -> Any:
129
+ """
130
+ Get the connection object.
131
+
132
+ :return: The connection object.
133
+ """
134
+ return self._connection
135
+
136
+ def set_connection(self, connection: Any) -> None:
137
+ """
138
+ Set the connection object.
139
+
140
+ :param connection: The connection object.
141
+ :return: None.
142
+ """
143
+ self._connection = connection
144
+
145
+ def get_data_methods(self) -> Dict[str, Any]:
146
+ """
147
+ Get the data methods dictionary.
148
+
149
+ :return: The data methods dictionary.
150
+ """
151
+ return self._data_methods
152
+
153
+ def get_data_method(self, data_point: str) -> Optional[Callable]:
154
+ """
155
+ Get a data method from the data methods dictionary.
156
+
157
+ :param data_point: The name of the data method.
158
+ :return: The data method.
159
+ """
160
+ return self._data_methods.get(data_point)
161
+
162
+ def update_data_methods(self, new_methods: Dict[str, Callable]) -> None:
163
+ """
164
+ Update the data methods with new methods, merging with existing ones.
165
+
166
+ :param new_methods: Dictionary of new data methods to add/update.
167
+ :return: None.
168
+ """
169
+ self._data_methods.update(new_methods)
170
+
171
+ def set_data_methods(self, data_methods: Dict[str, Any]) -> None:
172
+ """
173
+ Set the data methods dictionary.
174
+
175
+ :param data_methods: The data methods dictionary.
176
+ :return: None.
177
+ """
178
+ self._data_methods = data_methods
179
+
180
+ def add_data_method(self, data_point: str, method: Any) -> None:
181
+ """
182
+ Add a data method to the data methods dictionary.
183
+
184
+ :param data_point: The name of the data method.
185
+ :param method: The data method.
186
+ :return: None.
187
+ """
188
+ self._data_methods.update(
189
+ {
190
+ data_point: method,
191
+ }
192
+ )
193
+
194
+ def delete_data_method(self, data_point: str) -> None:
195
+ """
196
+ Delete a data method from the data methods dictionary.
197
+
198
+ :param data_point: The name of the data method to delete.
199
+ :return: None.
200
+ """
201
+ if data_point in self._data_methods:
202
+ del self._data_methods[data_point]
203
+
204
+ #################################################
205
+ # Connection Methods
206
+ #################################################
207
+ def is_connected(self) -> bool:
208
+ """
209
+ Check if the data provider is connected to the data source.
210
+
211
+ :return: True if connected, False otherwise.
212
+ """
213
+ return self._connection is not None
214
+
215
+ def connect(self, *args, **kwargs) -> None:
216
+ """
217
+ Safely Connect to the data source.
218
+
219
+ :param args: Positional arguments for connection.
220
+ :param kwargs: Keyword arguments for connection.
221
+ :return: None.
222
+ :raise ConnectionError: If connection fails.
223
+ """
224
+ try:
225
+ self._connect(*args, **kwargs)
226
+ self.set_status(status=DataProviderConnectionStatus.CONNECTED)
227
+ except Exception as e:
228
+ raise DataProviderConnectionError(f"Failed to connect to data source: {e}")
229
+
230
+ @abstractmethod
231
+ def _connect(self, *args, **kwargs):
232
+ """
233
+ Abstract method to connect to the data source.
234
+ """
235
+ raise NotImplementedError("Subclasses must implement this method")
236
+
237
+ def disconnect(self, *args, **kwargs) -> None:
238
+ """
239
+ Safely disconnect from the data source.
240
+
241
+ :param args: Positional arguments for connection.
242
+ :param kwargs: Keyword arguments for connection.
243
+ :return: None.
244
+ :raise ConnectionError: If connection fails.
245
+ """
246
+ try:
247
+ self._disconnect(*args, **kwargs)
248
+ self.set_status(status=DataProviderConnectionStatus.DISCONNECTED)
249
+ except Exception as e:
250
+ raise DataProviderConnectionError(f"Failed to disconnect from data source: {e}")
251
+
252
+ @abstractmethod
253
+ def _disconnect(self, *args, **kwargs):
254
+ """
255
+ Abstract method to disconnect from the data source.
256
+ """
257
+ raise NotImplementedError("Subclasses must implement this method")
258
+
259
+ def refresh_connection(self, *args, **kwargs) -> None:
260
+ """
261
+ Refresh the connection.
262
+
263
+ :param args: Positional arguments for connection.
264
+ :param kwargs: Keyword arguments for connection.
265
+ :return: None.
266
+ :raise ConnectionError: If connection fails.
267
+ """
268
+ self.disconnect(*args, **kwargs)
269
+ self.connect(*args, **kwargs)
270
+
271
+
272
+ #################################################
273
+ # Context Management
274
+ #################################################
275
+ def __enter__(self) -> "DataProvider":
276
+ """
277
+ Enter the runtime context related to this object. Automatically connects to the data source.
278
+ """
279
+ return self
280
+
281
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
282
+ """
283
+ Exit the runtime context related to this object. Automatically disconnects from the data source.
284
+ """
285
+ self.disconnect()
286
+
287
+ #################################################
288
+ # Core Instance Method: Fetch Data
289
+ #################################################
290
+ def fetch_data(self, data_point: str, return_data_type: type, *args, **kwargs) -> Any:
291
+ """
292
+ Base method to fetch data based on the data point and return type.
293
+
294
+ :param data_point: str: The data point to fetch.
295
+ :param return_data_type: type: The type of data to return.
296
+ :param args: Tuple: Positional arguments for fetching data.
297
+ :param kwargs: Dict: Keyword arguments for fetching data.
298
+ :return: The fetched data.
299
+ """
300
+ # Extract the corresponding data method
301
+ data_method = self.get_data_method(data_point=data_point)
302
+ if data_method is None:
303
+ raise DataMethodNotFoundError(f"Data method for data point '{data_point}' not found.")
304
+
305
+ # Retrieve the data
306
+ data = data_method(*args, **kwargs)
307
+
308
+ # Check the return data type
309
+ if not isinstance(data, return_data_type):
310
+ raise ReturnDataTypeNotMatchedError(f"Data type mismatch. Expected {return_data_type}, got {type(data)}.")
311
+
312
+ return data
313
+
@@ -0,0 +1,38 @@
1
+ #######################################################################
2
+ # Project: Data Retrieval Module
3
+ # File: exceptions.py
4
+ # Description: Exception classes for data providers
5
+ # Author: AbigailWilliams1692
6
+ # Created: 2026-01-14
7
+ # Updated: 2026-01-19
8
+ #######################################################################
9
+
10
+ #######################################################################
11
+ # Exception Classes
12
+ #######################################################################
13
+ class DataProviderError(Exception):
14
+ """Base exception for data provider errors."""
15
+ pass
16
+
17
+
18
+ class DataProviderConnectionError(DataProviderError):
19
+ """Raised when connection to data source fails."""
20
+ pass
21
+
22
+
23
+ class DataFetchError(DataProviderError):
24
+ """Raised when a query operation fails."""
25
+ pass
26
+
27
+ class DataMethodNotFoundError(DataProviderError):
28
+ """Raised when a requested data method is not found."""
29
+ pass
30
+
31
+ class ReturnDataTypeNotMatchedError(DataProviderError):
32
+ """Raised when the retrieved data type does not match the expected type."""
33
+ pass
34
+
35
+
36
+ class ValidationError(DataProviderError):
37
+ """Raised when data validation fails."""
38
+ pass
@@ -0,0 +1,2 @@
1
+ # This file indicates that the data_retrieval package is a typed package
2
+ # It enables type checkers to understand that this package contains type annotations
@@ -0,0 +1,350 @@
1
+ Metadata-Version: 2.4
2
+ Name: data-retrieval-module
3
+ Version: 1.0.0
4
+ Summary: A standardized interface for data providers with sync and async support
5
+ Author-email: AbigailWilliams1692 <abigail.williams@example.com>
6
+ Maintainer-email: AbigailWilliams1692 <abigail.williams@example.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/AbigailWilliams1692/data-retrieval-module
9
+ Project-URL: Documentation, https://github.com/AbigailWilliams1692/data-retrieval-module/wiki
10
+ Project-URL: Repository, https://github.com/AbigailWilliams1692/data-retrieval-module
11
+ Project-URL: Bug Tracker, https://github.com/AbigailWilliams1692/data-retrieval-module/issues
12
+ Project-URL: Changelog, https://github.com/AbigailWilliams1692/data-retrieval-module/blob/main/CHANGELOG.md
13
+ Keywords: data,retrieval,provider,async,sync,database,api
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Internet :: WWW/HTTP
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: typing-extensions>=4.0.0; python_version < "3.10"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
34
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
35
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
36
+ Requires-Dist: black>=23.0.0; extra == "dev"
37
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
38
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
39
+ Requires-Dist: isort>=5.12.0; extra == "dev"
40
+ Provides-Extra: async
41
+ Requires-Dist: aiohttp>=3.8.0; extra == "async"
42
+ Requires-Dist: aiosqlite>=0.19.0; extra == "async"
43
+ Requires-Dist: asyncpg>=0.28.0; extra == "async"
44
+ Provides-Extra: database
45
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "database"
46
+ Requires-Dist: PyMySQL>=1.0.0; extra == "database"
47
+ Provides-Extra: all
48
+ Requires-Dist: pytest>=7.0.0; extra == "all"
49
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
50
+ Requires-Dist: pytest-cov>=4.0.0; extra == "all"
51
+ Requires-Dist: pytest-mock>=3.10.0; extra == "all"
52
+ Requires-Dist: black>=23.0.0; extra == "all"
53
+ Requires-Dist: flake8>=6.0.0; extra == "all"
54
+ Requires-Dist: mypy>=1.0.0; extra == "all"
55
+ Requires-Dist: isort>=5.12.0; extra == "all"
56
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
57
+ Requires-Dist: aiosqlite>=0.19.0; extra == "all"
58
+ Requires-Dist: asyncpg>=0.28.0; extra == "all"
59
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == "all"
60
+ Requires-Dist: PyMySQL>=1.0.0; extra == "all"
61
+ Dynamic: license-file
62
+
63
+ # Data Retrieval Module
64
+
65
+ A standardized interface for data providers with both synchronous and asynchronous support. This module provides abstract base classes that enable consistent data retrieval patterns across different data sources (APIs, databases, files, etc.).
66
+
67
+ ## Features
68
+
69
+ - 🔄 **Dual API Support**: Both sync and async interfaces
70
+ - 🏗️ **Abstract Base Classes**: Standardized patterns for data providers
71
+ - 🔌 **Connection Management**: Built-in connection handling with context managers
72
+ - 🔄 **Retry Logic**: Automatic retry with configurable parameters
73
+ - 📊 **Pagination Support**: Standardized pagination with QueryResult
74
+ - 🎣 **Hook Methods**: Customizable validation and transformation
75
+ - 🧪 **Type Safety**: Full type hints and generic support
76
+ - ✅ **Well Tested**: Comprehensive unit test coverage
77
+
78
+ ## Installation
79
+
80
+ ### Basic Installation
81
+ ```bash
82
+ pip install data-retrieval-module
83
+ ```
84
+
85
+ ### With Async Support
86
+ ```bash
87
+ pip install data-retrieval-module[async]
88
+ ```
89
+
90
+ ### Development Installation
91
+ ```bash
92
+ pip install data-retrieval-module[dev]
93
+ ```
94
+
95
+ ### All Features
96
+ ```bash
97
+ pip install data-retrieval-module[all]
98
+ ```
99
+
100
+ ## Quick Start
101
+
102
+ ### Synchronous Data Provider
103
+
104
+ ```python
105
+ from data_retrieval import DataProvider, QueryResult
106
+ from data_retrieval.model import ProviderStatus
107
+
108
+ class UserProvider(DataProvider[User]):
109
+ def _connect(self) -> None:
110
+ self._db = Database.connect(...)
111
+
112
+ def _disconnect(self) -> None:
113
+ self._db.close()
114
+
115
+ def fetch(self, *args, **kwargs) -> QueryResult[User]:
116
+ filters = kwargs.get("filters", {})
117
+ users = self._db.users.find(filters)
118
+ return QueryResult(
119
+ data=users,
120
+ total_count=len(users),
121
+ metadata={"source": "database"}
122
+ )
123
+
124
+ # Usage
125
+ provider = UserProvider()
126
+ with provider.connection(host="localhost", port=5432):
127
+ result = provider.fetch(filters={"active": True})
128
+ for user in result.data:
129
+ print(user.name)
130
+ ```
131
+
132
+ ### Asynchronous Data Provider
133
+
134
+ ```python
135
+ from data_retrieval import AsyncDataProvider
136
+
137
+ class AsyncUserProvider(AsyncDataProvider[User]):
138
+ async def _connect(self) -> None:
139
+ self._db = await Database.connect(...)
140
+
141
+ async def _disconnect(self) -> None:
142
+ await self._db.close()
143
+
144
+ async def fetch(self, *args, **kwargs) -> QueryResult[User]:
145
+ filters = kwargs.get("filters", {})
146
+ users = await self._db.users.find(filters)
147
+ return QueryResult(
148
+ data=users,
149
+ total_count=len(users),
150
+ metadata={"source": "database"}
151
+ )
152
+
153
+ # Usage
154
+ async def main():
155
+ provider = AsyncUserProvider()
156
+ async with provider.async_connection(host="localhost", port=5432) as p:
157
+ result = await p.fetch(filters={"active": True})
158
+ for user in result.data:
159
+ print(user.name)
160
+ ```
161
+
162
+ ## Core Classes
163
+
164
+ ### DataProvider (Synchronous)
165
+
166
+ Abstract base class for synchronous data providers.
167
+
168
+ **Key Methods:**
169
+ - `connect(**config)` - Establish connection
170
+ - `disconnect()` - Close connection
171
+ - `fetch(*args, **kwargs)` - Retrieve data
172
+ - `fetch_or_raise(*args, **kwargs)` - Fetch with error handling
173
+ - `with_retry(operation, max_retries, retry_delay)` - Retry logic
174
+
175
+ **Hook Methods:**
176
+ - `validate(data)` - Validate data
177
+ - `transform(data)` - Transform data
178
+ - `health_check()` - Health status
179
+
180
+ ### AsyncDataProvider (Asynchronous)
181
+
182
+ Abstract base class for asynchronous data providers.
183
+
184
+ **Key Methods:**
185
+ - `async connect(**config)` - Establish connection
186
+ - `async disconnect()` - Close connection
187
+ - `async fetch(*args, **kwargs)` - Retrieve data
188
+ - `async fetch_or_raise(*args, **kwargs)` - Fetch with error handling
189
+ - `async with_retry(operation, max_retries, retry_delay)` - Retry logic
190
+
191
+ ### QueryResult
192
+
193
+ Standardized container for query results.
194
+
195
+ ```python
196
+ @dataclass
197
+ class QueryResult[T]:
198
+ data: List[T]
199
+ total_count: int
200
+ metadata: Dict[str, Any]
201
+
202
+ def is_empty(self) -> bool:
203
+ return self.total_count == 0
204
+ ```
205
+
206
+ ## Advanced Usage
207
+
208
+ ### Custom Validation
209
+
210
+ ```python
211
+ class ValidatedProvider(DataProvider[User]):
212
+ def validate(self, data: User) -> bool:
213
+ # Custom validation logic
214
+ return data.email and "@" in data.email
215
+ ```
216
+
217
+ ### Data Transformation
218
+
219
+ ```python
220
+ class TransformingProvider(DataProvider[User]):
221
+ def transform(self, data: dict) -> User:
222
+ # Convert raw data to User object
223
+ return User(**data)
224
+ ```
225
+
226
+ ### Retry Logic
227
+
228
+ ```python
229
+ provider = MyProvider()
230
+
231
+ # Retry with custom parameters
232
+ result = provider.with_retry(
233
+ operation=lambda: provider.fetch(filters={"id": "123"}),
234
+ max_retries=5,
235
+ retry_delay=2.0,
236
+ parameters={}
237
+ )
238
+ ```
239
+
240
+ ### Context Managers
241
+
242
+ ```python
243
+ # Automatic connection management
244
+ with provider.connection(host="localhost") as p:
245
+ data = p.fetch()
246
+
247
+ # Async version
248
+ async with provider.async_connection(host="localhost") as p:
249
+ data = await p.fetch()
250
+ ```
251
+
252
+ ## Error Handling
253
+
254
+ The module provides specific exception types:
255
+
256
+ ```python
257
+ from data_retrieval.model.exceptions import (
258
+ DataProviderError,
259
+ ConnectionError,
260
+ QueryError,
261
+ ValidationError
262
+ )
263
+
264
+ try:
265
+ result = provider.fetch(filters={"invalid": "field"})
266
+ except ConnectionError as e:
267
+ print(f"Connection failed: {e}")
268
+ except QueryError as e:
269
+ print(f"Query failed: {e}")
270
+ except DataProviderError as e:
271
+ print(f"General error: {e}")
272
+ ```
273
+
274
+ ## Development
275
+
276
+ ### Setup Development Environment
277
+
278
+ ```bash
279
+ # Clone repository
280
+ git clone https://github.com/AbigailWilliams1692/data-retrieval-module.git
281
+ cd data-retrieval-module
282
+
283
+ # Create virtual environment
284
+ python -m venv venv
285
+ source venv/bin/activate # On Windows: venv\Scripts\activate
286
+
287
+ # Install development dependencies
288
+ pip install -e .[dev]
289
+ ```
290
+
291
+ ### Running Tests
292
+
293
+ ```bash
294
+ # Run all tests
295
+ pytest
296
+
297
+ # Run with coverage
298
+ pytest --cov=data_retrieval --cov-report=html
299
+
300
+ # Run specific test file
301
+ pytest tests/test_data_provider.py
302
+ ```
303
+
304
+ ### Code Quality
305
+
306
+ ```bash
307
+ # Format code
308
+ black data_retrieval/ tests/
309
+
310
+ # Sort imports
311
+ isort data_retrieval/ tests/
312
+
313
+ # Type checking
314
+ mypy data_retrieval/
315
+
316
+ # Linting
317
+ flake8 data_retrieval/ tests/
318
+ ```
319
+
320
+ ## Contributing
321
+
322
+ 1. Fork the repository
323
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
324
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
325
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
326
+ 5. Open a Pull Request
327
+
328
+ ## License
329
+
330
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
331
+
332
+ ## Changelog
333
+
334
+ See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.
335
+
336
+ ## Support
337
+
338
+ - 📖 [Documentation](https://github.com/AbigailWilliams1692/data-retrieval-module/wiki)
339
+ - 🐛 [Bug Reports](https://github.com/AbigailWilliams1692/data-retrieval-module/issues)
340
+ - 💬 [Discussions](https://github.com/AbigailWilliams1692/data-retrieval-module/discussions)
341
+
342
+ ## Related Projects
343
+
344
+ - [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) - SQL toolkit and ORM
345
+ - [Django ORM](https://github.com/django/django) - Django's database ORM
346
+ - [Tortoise ORM](https://github.com/tortoise/tortoise-orm) - Async ORM for Python
347
+
348
+ ---
349
+
350
+ **Made with ❤️ by [AbigailWilliams1692](https://github.com/AbigailWilliams1692)**
@@ -0,0 +1,11 @@
1
+ data_retrieval/__init__.py,sha256=uJboXyByW_UUD1UF7Si1APOxUGmGPAZMSBcVO2m2wuo,2000
2
+ data_retrieval/py.typed,sha256=-NTLJWHpx_8vs__Ouvm4nvtZ1-l6FqRKyJ2iqfxmutE,158
3
+ data_retrieval/model/__init__.py,sha256=ZVqtFkRxqTCiqyOfKEeJ7XVNBreQLsN5GRnf-bOOJNk,432
4
+ data_retrieval/model/data_module.py,sha256=CWBRh35_4UV7PQ0pz0bl2xgi45Otd_z5rgi1rBlIlYI,4281
5
+ data_retrieval/model/data_provider.py,sha256=i5D12nwYOVGopVemBlAoX6BhC0wrw3ftNQyifESQjII,10315
6
+ data_retrieval/model/exceptions.py,sha256=ySs--qJ9fJV-cprAb69peZhQx1ppv5RbzK5nbjDQjUc,1169
7
+ data_retrieval_module-1.0.0.dist-info/licenses/LICENSE,sha256=Mcf9NKkIfu5xuYsMLyvzhYXnm9OwZ8jko8scfkocBBU,1073
8
+ data_retrieval_module-1.0.0.dist-info/METADATA,sha256=uAY7libj5VgumIrLjGVYc797MbFcXUCJqgLr4PxKjzo,10150
9
+ data_retrieval_module-1.0.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
10
+ data_retrieval_module-1.0.0.dist-info/top_level.txt,sha256=02EwIYUSaidyp_6eSOKa1TTYSE71RmhFlpkgI5OQ6nk,15
11
+ data_retrieval_module-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Abigail Williams
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ data_retrieval