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.
- atomhttp-1.0.0/LICENSE +21 -0
- atomhttp-1.0.0/PKG-INFO +165 -0
- atomhttp-1.0.0/README.md +116 -0
- atomhttp-1.0.0/atomhttp/__init__.py +76 -0
- atomhttp-1.0.0/atomhttp/adapters/__init__.py +4 -0
- atomhttp-1.0.0/atomhttp/adapters/http_adapter.py +102 -0
- atomhttp-1.0.0/atomhttp/adapters/mock_adapter.py +130 -0
- atomhttp-1.0.0/atomhttp/auth/__init__.py +4 -0
- atomhttp-1.0.0/atomhttp/auth/basic_auth.py +90 -0
- atomhttp-1.0.0/atomhttp/auth/bearer_auth.py +83 -0
- atomhttp-1.0.0/atomhttp/client.py +577 -0
- atomhttp-1.0.0/atomhttp/core/__init__.py +19 -0
- atomhttp-1.0.0/atomhttp/core/adapters.py +687 -0
- atomhttp-1.0.0/atomhttp/core/config.py +186 -0
- atomhttp-1.0.0/atomhttp/core/defaults.py +212 -0
- atomhttp-1.0.0/atomhttp/core/form_data.py +282 -0
- atomhttp-1.0.0/atomhttp/core/request.py +240 -0
- atomhttp-1.0.0/atomhttp/core/response.py +101 -0
- atomhttp-1.0.0/atomhttp/errors/__init__.py +13 -0
- atomhttp-1.0.0/atomhttp/errors/http_errors.py +142 -0
- atomhttp-1.0.0/atomhttp/interceptors/__init__.py +5 -0
- atomhttp-1.0.0/atomhttp/interceptors/manager.py +136 -0
- atomhttp-1.0.0/atomhttp/interceptors/request_interceptor.py +18 -0
- atomhttp-1.0.0/atomhttp/interceptors/response_interceptor.py +18 -0
- atomhttp-1.0.0/atomhttp/progress/__init__.py +3 -0
- atomhttp-1.0.0/atomhttp/progress/upload_progress.py +89 -0
- atomhttp-1.0.0/atomhttp/transforms/__init__.py +5 -0
- atomhttp-1.0.0/atomhttp/transforms/data_serializer.py +96 -0
- atomhttp-1.0.0/atomhttp/transforms/request_transform.py +96 -0
- atomhttp-1.0.0/atomhttp/transforms/response_transform.py +73 -0
- atomhttp-1.0.0/atomhttp/utils/__init__.py +5 -0
- atomhttp-1.0.0/atomhttp/utils/cookies.py +128 -0
- atomhttp-1.0.0/atomhttp/utils/helpers.py +111 -0
- atomhttp-1.0.0/atomhttp/utils/redirect.py +107 -0
- atomhttp-1.0.0/atomhttp.egg-info/PKG-INFO +165 -0
- atomhttp-1.0.0/atomhttp.egg-info/SOURCES.txt +39 -0
- atomhttp-1.0.0/atomhttp.egg-info/dependency_links.txt +1 -0
- atomhttp-1.0.0/atomhttp.egg-info/requires.txt +21 -0
- atomhttp-1.0.0/atomhttp.egg-info/top_level.txt +1 -0
- atomhttp-1.0.0/pyproject.toml +250 -0
- 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.
|
atomhttp-1.0.0/PKG-INFO
ADDED
|
@@ -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
|
atomhttp-1.0.0/README.md
ADDED
|
@@ -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,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
|
+
)
|