atomhttp 1.0.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.
Files changed (41) hide show
  1. atomhttp-1.0.0/LICENSE +21 -0
  2. atomhttp-1.0.0/PKG-INFO +165 -0
  3. atomhttp-1.0.0/README.md +116 -0
  4. atomhttp-1.0.0/atomhttp/__init__.py +76 -0
  5. atomhttp-1.0.0/atomhttp/adapters/__init__.py +4 -0
  6. atomhttp-1.0.0/atomhttp/adapters/http_adapter.py +102 -0
  7. atomhttp-1.0.0/atomhttp/adapters/mock_adapter.py +130 -0
  8. atomhttp-1.0.0/atomhttp/auth/__init__.py +4 -0
  9. atomhttp-1.0.0/atomhttp/auth/basic_auth.py +90 -0
  10. atomhttp-1.0.0/atomhttp/auth/bearer_auth.py +83 -0
  11. atomhttp-1.0.0/atomhttp/client.py +577 -0
  12. atomhttp-1.0.0/atomhttp/core/__init__.py +19 -0
  13. atomhttp-1.0.0/atomhttp/core/adapters.py +687 -0
  14. atomhttp-1.0.0/atomhttp/core/config.py +186 -0
  15. atomhttp-1.0.0/atomhttp/core/defaults.py +212 -0
  16. atomhttp-1.0.0/atomhttp/core/form_data.py +282 -0
  17. atomhttp-1.0.0/atomhttp/core/request.py +240 -0
  18. atomhttp-1.0.0/atomhttp/core/response.py +101 -0
  19. atomhttp-1.0.0/atomhttp/errors/__init__.py +13 -0
  20. atomhttp-1.0.0/atomhttp/errors/http_errors.py +142 -0
  21. atomhttp-1.0.0/atomhttp/interceptors/__init__.py +5 -0
  22. atomhttp-1.0.0/atomhttp/interceptors/manager.py +136 -0
  23. atomhttp-1.0.0/atomhttp/interceptors/request_interceptor.py +18 -0
  24. atomhttp-1.0.0/atomhttp/interceptors/response_interceptor.py +18 -0
  25. atomhttp-1.0.0/atomhttp/progress/__init__.py +3 -0
  26. atomhttp-1.0.0/atomhttp/progress/upload_progress.py +89 -0
  27. atomhttp-1.0.0/atomhttp/transforms/__init__.py +5 -0
  28. atomhttp-1.0.0/atomhttp/transforms/data_serializer.py +96 -0
  29. atomhttp-1.0.0/atomhttp/transforms/request_transform.py +96 -0
  30. atomhttp-1.0.0/atomhttp/transforms/response_transform.py +73 -0
  31. atomhttp-1.0.0/atomhttp/utils/__init__.py +5 -0
  32. atomhttp-1.0.0/atomhttp/utils/cookies.py +128 -0
  33. atomhttp-1.0.0/atomhttp/utils/helpers.py +111 -0
  34. atomhttp-1.0.0/atomhttp/utils/redirect.py +107 -0
  35. atomhttp-1.0.0/atomhttp.egg-info/PKG-INFO +165 -0
  36. atomhttp-1.0.0/atomhttp.egg-info/SOURCES.txt +39 -0
  37. atomhttp-1.0.0/atomhttp.egg-info/dependency_links.txt +1 -0
  38. atomhttp-1.0.0/atomhttp.egg-info/requires.txt +21 -0
  39. atomhttp-1.0.0/atomhttp.egg-info/top_level.txt +1 -0
  40. atomhttp-1.0.0/pyproject.toml +250 -0
  41. atomhttp-1.0.0/setup.cfg +4 -0
atomhttp-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abolfazl Hosseini
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,165 @@
1
+ Metadata-Version: 2.4
2
+ Name: atomhttp
3
+ Version: 1.0.0
4
+ Summary: Professional asynchronous HTTP client for Python — interceptors, progress tracking, FormData, Blob, concurrent requests, and full type hints
5
+ Author-email: Abolfazl Hosseini <tryuzr@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/inject3r/atomhttp
8
+ Project-URL: Repository, https://github.com/inject3r/atomhttp.git
9
+ Project-URL: Documentation, https://inject3r.github.io/atomhttp
10
+ Project-URL: Issues, https://github.com/inject3r/atomhttp/issues
11
+ Project-URL: Changelog, https://github.com/inject3r/atomhttp/releases
12
+ Keywords: http,client,async,await,aiohttp,rest,api,interceptor,progress,formdata
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: License :: OSI Approved :: MIT License
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Development Status :: 5 - Production/Stable
23
+ Classifier: Intended Audience :: Developers
24
+ Classifier: Topic :: Internet :: WWW/HTTP
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Framework :: AsyncIO
27
+ Requires-Python: >=3.8
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: aiohttp>=3.8.0
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: black>=22.0.0; extra == "dev"
36
+ Requires-Dist: isort>=5.10.0; extra == "dev"
37
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
38
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
39
+ Provides-Extra: test
40
+ Requires-Dist: pytest>=7.0.0; extra == "test"
41
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
42
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
43
+ Provides-Extra: all
44
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
45
+ Requires-Dist: pytest>=7.0.0; extra == "all"
46
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
47
+ Requires-Dist: pytest-cov>=4.0.0; extra == "all"
48
+ Dynamic: license-file
49
+
50
+ <p align="center">
51
+ <img src="https://inject3r.github.io/atomhttp/logo.jpg" alt="AtomHTTP Logo" width="350">
52
+ </p>
53
+
54
+ # AtomHTTP
55
+
56
+ A professional, feature-rich asynchronous HTTP client for Python — designed for developers who need reliability, flexibility, and performance.
57
+
58
+ **[Full Documentation](https://inject3r.github.io/atomhttp)** — Complete API reference, advanced guides, and examples
59
+
60
+ <br/>
61
+
62
+ ## Features
63
+
64
+ - **Full HTTP Method Support**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS with async/await syntax
65
+ - **Request & Response Interceptors**: Modify requests before sending and responses before returning
66
+ - **Upload & Download Progress Tracking**: Real-time callbacks for monitoring data transfer
67
+ - **FormData Support**: Multipart/form-data and URL-encoded form handling with file uploads
68
+ - **Multiple Response Types**: JSON (auto-parsed), text, blob, arraybuffer, and stream
69
+ - **Concurrent Request Helpers**: Execute multiple requests in parallel with `all()` and `spread()`
70
+ - **Base URL Configuration**: Set a base URL once and use relative paths
71
+ - **Automatic JSON Serialization**: No need to manually encode/decode JSON
72
+ - **Authentication**: Basic Auth and Bearer Token support
73
+ - **Comprehensive Error Handling**: Typed exceptions with standardized error codes
74
+ - **Timeout & Redirect Control**: Configurable timeouts and maximum redirect limits
75
+ - **Keep-Alive & Connection Pooling**: Reuse connections for better performance
76
+ - **Proxy Support**: Route requests through HTTP proxies
77
+ - **Unix Socket Path Support**: Connect via Unix domain sockets
78
+ - **Size Limits**: Configure maximum request body and response content lengths
79
+ - **Status Code Validation**: Custom validation functions for HTTP status codes
80
+ - **CSRF Protection**: Built-in support for XSRF token headers
81
+ - **Automatic Decompression**: Handles gzip and deflate compressed responses
82
+ - **Mock Adapter for Testing**: Simulate responses without network calls
83
+ - **Type Hints**: Full typing support for excellent IDE autocompletion
84
+
85
+ ## Installation
86
+
87
+ ```bash
88
+ pip install atomhttp
89
+ ```
90
+
91
+ With development dependencies:
92
+
93
+ ```bash
94
+ pip install atomhttp[dev]
95
+ ```
96
+
97
+ ## Quick Start
98
+
99
+ ```python
100
+ import asyncio
101
+ from atomhttp import AtomHTTP
102
+
103
+ async def main():
104
+ client = AtomHTTP({'baseURL': 'https://api.example.com'})
105
+ response = await client.get('/users')
106
+ print(response.status, response.data)
107
+ await client.close()
108
+
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ ## Documentation
113
+
114
+ For complete documentation, API reference, and advanced usage examples, visit:
115
+
116
+ **[https://inject3r.github.io/atomhttp](https://inject3r.github.io/atomhttp)**
117
+
118
+ The documentation includes:
119
+
120
+ - Detailed API reference for all classes and methods
121
+ - Advanced usage patterns and best practices
122
+ - Configuration options and their effects
123
+ - Error handling strategies
124
+ - Migration guides from other HTTP clients
125
+
126
+ ## Requirements
127
+
128
+ - Python 3.8+
129
+ - aiohttp 3.8.0+
130
+
131
+ ## Running Tests
132
+
133
+ ```bash
134
+ # Run all tests with coverage
135
+ ./scripts/tests.sh
136
+
137
+ # Clean test output files
138
+ ./scripts/test_clean.sh
139
+ ```
140
+
141
+ ## License
142
+
143
+ This project is licensed under the MIT License.
144
+
145
+ ## Author
146
+
147
+ **Abolfazl Hosseini**
148
+
149
+ - Email: tryuzr@gmail.com
150
+ - GitHub: [@inject3r](https://github.com/inject3r)
151
+
152
+ ## Contributing
153
+
154
+ Contributions are welcome! Please feel free to submit a Pull Request.
155
+
156
+ 1. Fork the repository
157
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
158
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
159
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
160
+ 5. Open a Pull Request
161
+
162
+ ## Acknowledgments
163
+
164
+ - [aiohttp](https://docs.aiohttp.org/) - Async HTTP client/server framework
165
+ - All contributors and users of this project
@@ -0,0 +1,116 @@
1
+ <p align="center">
2
+ <img src="https://inject3r.github.io/atomhttp/logo.jpg" alt="AtomHTTP Logo" width="350">
3
+ </p>
4
+
5
+ # AtomHTTP
6
+
7
+ A professional, feature-rich asynchronous HTTP client for Python — designed for developers who need reliability, flexibility, and performance.
8
+
9
+ **[Full Documentation](https://inject3r.github.io/atomhttp)** — Complete API reference, advanced guides, and examples
10
+
11
+ <br/>
12
+
13
+ ## Features
14
+
15
+ - **Full HTTP Method Support**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS with async/await syntax
16
+ - **Request & Response Interceptors**: Modify requests before sending and responses before returning
17
+ - **Upload & Download Progress Tracking**: Real-time callbacks for monitoring data transfer
18
+ - **FormData Support**: Multipart/form-data and URL-encoded form handling with file uploads
19
+ - **Multiple Response Types**: JSON (auto-parsed), text, blob, arraybuffer, and stream
20
+ - **Concurrent Request Helpers**: Execute multiple requests in parallel with `all()` and `spread()`
21
+ - **Base URL Configuration**: Set a base URL once and use relative paths
22
+ - **Automatic JSON Serialization**: No need to manually encode/decode JSON
23
+ - **Authentication**: Basic Auth and Bearer Token support
24
+ - **Comprehensive Error Handling**: Typed exceptions with standardized error codes
25
+ - **Timeout & Redirect Control**: Configurable timeouts and maximum redirect limits
26
+ - **Keep-Alive & Connection Pooling**: Reuse connections for better performance
27
+ - **Proxy Support**: Route requests through HTTP proxies
28
+ - **Unix Socket Path Support**: Connect via Unix domain sockets
29
+ - **Size Limits**: Configure maximum request body and response content lengths
30
+ - **Status Code Validation**: Custom validation functions for HTTP status codes
31
+ - **CSRF Protection**: Built-in support for XSRF token headers
32
+ - **Automatic Decompression**: Handles gzip and deflate compressed responses
33
+ - **Mock Adapter for Testing**: Simulate responses without network calls
34
+ - **Type Hints**: Full typing support for excellent IDE autocompletion
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install atomhttp
40
+ ```
41
+
42
+ With development dependencies:
43
+
44
+ ```bash
45
+ pip install atomhttp[dev]
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ```python
51
+ import asyncio
52
+ from atomhttp import AtomHTTP
53
+
54
+ async def main():
55
+ client = AtomHTTP({'baseURL': 'https://api.example.com'})
56
+ response = await client.get('/users')
57
+ print(response.status, response.data)
58
+ await client.close()
59
+
60
+ asyncio.run(main())
61
+ ```
62
+
63
+ ## Documentation
64
+
65
+ For complete documentation, API reference, and advanced usage examples, visit:
66
+
67
+ **[https://inject3r.github.io/atomhttp](https://inject3r.github.io/atomhttp)**
68
+
69
+ The documentation includes:
70
+
71
+ - Detailed API reference for all classes and methods
72
+ - Advanced usage patterns and best practices
73
+ - Configuration options and their effects
74
+ - Error handling strategies
75
+ - Migration guides from other HTTP clients
76
+
77
+ ## Requirements
78
+
79
+ - Python 3.8+
80
+ - aiohttp 3.8.0+
81
+
82
+ ## Running Tests
83
+
84
+ ```bash
85
+ # Run all tests with coverage
86
+ ./scripts/tests.sh
87
+
88
+ # Clean test output files
89
+ ./scripts/test_clean.sh
90
+ ```
91
+
92
+ ## License
93
+
94
+ This project is licensed under the MIT License.
95
+
96
+ ## Author
97
+
98
+ **Abolfazl Hosseini**
99
+
100
+ - Email: tryuzr@gmail.com
101
+ - GitHub: [@inject3r](https://github.com/inject3r)
102
+
103
+ ## Contributing
104
+
105
+ Contributions are welcome! Please feel free to submit a Pull Request.
106
+
107
+ 1. Fork the repository
108
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
109
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
110
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
111
+ 5. Open a Pull Request
112
+
113
+ ## Acknowledgments
114
+
115
+ - [aiohttp](https://docs.aiohttp.org/) - Async HTTP client/server framework
116
+ - All contributors and users of this project
@@ -0,0 +1,76 @@
1
+ """
2
+ AtomHTTP - Professional HTTP Client for Python
3
+ ===============================================
4
+
5
+ A comprehensive, asynchronous HTTP client for Python with features including:
6
+ - Full HTTP method support (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
7
+ - Request and response interceptors
8
+ - Upload and download progress tracking
9
+ - FormData (multipart/form-data) with file uploads
10
+ - Blob, ArrayBuffer, and stream response types
11
+ - Concurrent request helpers (all, spread)
12
+ - Base URL configuration
13
+ - Automatic JSON serialization/deserialization
14
+ - Comprehensive error handling with typed exceptions
15
+ - Type hints for better IDE support
16
+ - Mock adapter for testing
17
+ - Keep-alive connection pooling
18
+ - Proxy support
19
+ - Unix socket path support
20
+ - Configurable timeouts and redirect limits
21
+
22
+ This module exports the main AtomHTTP client class along with all necessary
23
+ types, exceptions, and utilities for making HTTP requests.
24
+
25
+ Example:
26
+ >>> import asyncio
27
+ >>> from atomhttp import AtomHTTP
28
+ >>>
29
+ >>> async def main():
30
+ ... client = AtomHTTP({'baseURL': 'https://api.example.com'})
31
+ ... response = await client.get('/users')
32
+ ... print(response.status, response.data)
33
+ ... await client.close()
34
+ >>>
35
+ >>> asyncio.run(main())
36
+ """
37
+
38
+ from .client import AtomHTTP
39
+ from .errors.http_errors import (
40
+ AtomHTTPError,
41
+ AtomHTTPRequestError,
42
+ AtomHTTPNetworkError,
43
+ AtomHTTPTimeoutError
44
+ )
45
+ from .core.response import Response
46
+ from .core.config import RequestConfig
47
+ from .core.form_data import FormData
48
+ from .core.adapters import HTTPAdapter, MockAdapter
49
+ from .interceptors.manager import InterceptorManager
50
+
51
+ __version__ = "2.0.0"
52
+
53
+ __all__ = [
54
+ # Main client
55
+ "AtomHTTP",
56
+
57
+ # Exception classes
58
+ "AtomHTTPError",
59
+ "AtomHTTPRequestError",
60
+ "AtomHTTPNetworkError",
61
+ "AtomHTTPTimeoutError",
62
+
63
+ # Core types
64
+ "Response",
65
+ "RequestConfig",
66
+
67
+ # Interceptor management
68
+ "InterceptorManager",
69
+
70
+ # Data types
71
+ "FormData",
72
+
73
+ # Adapters
74
+ "HTTPAdapter",
75
+ "MockAdapter",
76
+ ]
@@ -0,0 +1,4 @@
1
+ from .http_adapter import HTTPAdapter
2
+ from .mock_adapter import MockAdapter
3
+
4
+ __all__ = ['HTTPAdapter', 'MockAdapter']
@@ -0,0 +1,102 @@
1
+ """
2
+ HTTP Adapter Module
3
+ -------------------
4
+ This module provides the base HTTP adapter for making asynchronous HTTP requests
5
+ using aiohttp. It handles request execution, timeout management, proxy support,
6
+ and response processing.
7
+
8
+ The HTTPAdapter is the default transport layer for the AtomHTTP client,
9
+ responsible for converting RequestConfig objects into actual HTTP requests
10
+ and wrapping responses into AtomHTTP Response objects.
11
+ """
12
+
13
+ import aiohttp
14
+ from typing import Optional
15
+ from ..core.config import RequestConfig
16
+ from ..core.response import Response
17
+
18
+
19
+ class HTTPAdapter:
20
+ """
21
+ HTTP adapter for making asynchronous HTTP requests using aiohttp.
22
+
23
+ This adapter serves as the transport layer for the AtomHTTP client,
24
+ handling the low-level details of HTTP communication including connection
25
+ management, timeout handling, proxy configuration, and response parsing.
26
+
27
+ Attributes:
28
+ proxy (Optional[str]): Proxy server URL to use for requests.
29
+ Format: 'http://proxy.example.com:8080'
30
+ """
31
+
32
+ def __init__(self, proxy: Optional[str] = None):
33
+ """
34
+ Initialize the HTTP adapter with optional proxy configuration.
35
+
36
+ Args:
37
+ proxy (Optional[str]): Proxy server URL. If provided, all requests
38
+ will be routed through this proxy.
39
+ """
40
+ self.proxy = proxy
41
+
42
+ async def send(self, config: RequestConfig) -> Response:
43
+ """
44
+ Execute an HTTP request based on the provided configuration.
45
+
46
+ This method performs the actual HTTP request using aiohttp,
47
+ handling all aspects of the request lifecycle including connection
48
+ establishment, timeout management, request headers and body,
49
+ redirect following, and response parsing.
50
+
51
+ Args:
52
+ config (RequestConfig): Request configuration object containing all
53
+ request parameters such as URL, method,
54
+ headers, data, timeout, etc.
55
+
56
+ Returns:
57
+ Response: A AtomHTTP Response object containing the parsed response
58
+ data, status code, headers, and original configuration.
59
+
60
+ Raises:
61
+ aiohttp.ClientError: If a network-related error occurs
62
+ asyncio.TimeoutError: If the request exceeds the configured timeout
63
+ json.JSONDecodeError: If response_type='json' and response is invalid JSON
64
+ """
65
+ # Configure timeout with total request duration limit
66
+ timeout = aiohttp.ClientTimeout(total=config.timeout)
67
+
68
+ # Create TCP connector if proxy is configured
69
+ connector = None
70
+ if self.proxy:
71
+ connector = aiohttp.TCPConnector()
72
+
73
+ # Create a new client session for this request
74
+ # Using async context manager ensures proper cleanup
75
+ async with aiohttp.ClientSession(connector=connector) as session:
76
+ # Execute the HTTP request with all configured parameters
77
+ async with session.request(
78
+ method=config.method,
79
+ url=config.url,
80
+ headers=config.headers,
81
+ params=config.params,
82
+ data=config.data,
83
+ timeout=timeout,
84
+ max_redirects=config.maxRedirects
85
+ ) as response:
86
+ # Parse response body based on expected response type
87
+ # JSON responses are automatically deserialized to dict/list
88
+ # Non-JSON responses are returned as plain text
89
+ if config.responseType == 'json':
90
+ data = await response.json()
91
+ else:
92
+ data = await response.text()
93
+
94
+ # Wrap the aiohttp response in AtomHTTP's Response object
95
+ return Response(
96
+ data=data,
97
+ status=response.status,
98
+ status_text=response.reason,
99
+ headers=dict(response.headers),
100
+ config=config,
101
+ request=config
102
+ )
@@ -0,0 +1,130 @@
1
+ """
2
+ Mock Adapter Module
3
+ -------------------
4
+ This module provides a mock HTTP adapter for testing purposes.
5
+
6
+ The MockAdapter allows developers to simulate HTTP responses without making
7
+ actual network requests. This is useful for unit testing, integration testing,
8
+ and development scenarios where external APIs are unavailable or undesirable
9
+ to call directly.
10
+ """
11
+
12
+ from typing import Dict, Any, Optional
13
+ from ..core.config import RequestConfig
14
+ from ..core.response import Response
15
+
16
+
17
+ class MockAdapter:
18
+ """
19
+ Mock adapter for testing HTTP requests without actual network calls.
20
+
21
+ This adapter stores predefined responses for specific request patterns
22
+ and returns them when matching requests are made. It enables isolated
23
+ testing of code that depends on HTTP responses without external dependencies.
24
+
25
+ Features:
26
+ - Register mock responses for specific HTTP methods and URLs
27
+ - Customizable response data, status codes, and status texts
28
+ - Automatic 404 response for unregistered endpoints
29
+ - No actual network connections are established
30
+
31
+ Attributes:
32
+ _responses (Dict[str, Dict]): Internal storage mapping request keys
33
+ to their configured mock responses.
34
+
35
+ Example:
36
+ >>> mock = MockAdapter()
37
+ >>> mock.on('GET', 'https://api.test/users', {'users': []}, 200)
38
+ >>> response = await mock.send(config)
39
+ """
40
+
41
+ def __init__(self):
42
+ """
43
+ Initialize an empty mock adapter with no predefined responses.
44
+
45
+ Use the on() method to register mock responses before sending requests.
46
+ """
47
+ self._responses: Dict[str, Dict] = {}
48
+
49
+ def on(self, method: str, url: str, response_data: Any, status: int = 200):
50
+ """
51
+ Register a mock response for a specific HTTP method and URL.
52
+
53
+ When a request with the matching method and URL is sent through this
54
+ adapter, the registered response will be returned instead of making
55
+ an actual network request.
56
+
57
+ Args:
58
+ method (str): HTTP method (GET, POST, PUT, DELETE, etc.)
59
+ url (str): Full URL or path that this mock should respond to
60
+ response_data (Any): Data to be returned as the response body.
61
+ Can be dict, list, string, or any JSON-serializable type.
62
+ status (int): HTTP status code to return. Defaults to 200.
63
+
64
+ Note:
65
+ If multiple responses are registered for the same method and URL,
66
+ the last registration will overwrite previous ones.
67
+
68
+ Example:
69
+ >>> mock = MockAdapter()
70
+ >>> mock.on('GET', 'https://api.test/users', {'users': []}, 200)
71
+ >>> mock.on('POST', 'https://api.test/users', {'id': 1}, 201)
72
+ >>> mock.on('GET', 'https://api.test/users/1', {'name': 'John'}, 200)
73
+ """
74
+ # Create a unique key combining method and URL for lookup
75
+ key = f"{method}:{url}"
76
+
77
+ # Store the mock response configuration
78
+ self._responses[key] = {
79
+ 'data': response_data,
80
+ 'status': status,
81
+ 'status_text': 'OK' if status == 200 else 'Error'
82
+ }
83
+
84
+ async def send(self, config: RequestConfig) -> Response:
85
+ """
86
+ Send a mock request and return a predefined response.
87
+
88
+ This method looks up the request method and URL in the registered
89
+ responses. If a match is found, the corresponding mock response is
90
+ returned. Otherwise, a 404 Not Found response is returned.
91
+
92
+ Args:
93
+ config (RequestConfig): Request configuration containing method and URL.
94
+ Other config fields (headers, data, etc.) are
95
+ ignored in mock mode.
96
+
97
+ Returns:
98
+ Response: A AtomHTTP Response object containing either the registered
99
+ mock data or a 404 error response.
100
+
101
+ Note:
102
+ No actual HTTP request is made. The response is constructed entirely
103
+ from in-memory mock data, making this adapter suitable for tests
104
+ that require deterministic, repeatable responses.
105
+ """
106
+ # Build lookup key from request configuration
107
+ key = f"{config.method}:{config.url}"
108
+
109
+ # Check if a mock response is registered for this request
110
+ if key in self._responses:
111
+ mock = self._responses[key]
112
+ # Return the registered mock response
113
+ return Response(
114
+ data=mock['data'],
115
+ status=mock['status'],
116
+ status_text=mock['status_text'],
117
+ headers={},
118
+ config=config,
119
+ request=config
120
+ )
121
+ else:
122
+ # Return default 404 response for unregistered endpoints
123
+ return Response(
124
+ data={'error': 'No mock found'},
125
+ status=404,
126
+ status_text='Not Found',
127
+ headers={},
128
+ config=config,
129
+ request=config
130
+ )
@@ -0,0 +1,4 @@
1
+ from .basic_auth import BasicAuth
2
+ from .bearer_auth import BearerAuth
3
+
4
+ __all__ = ['BasicAuth', 'BearerAuth']