hishel 0.1.5__tar.gz → 1.0.0.dev1__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.
- {hishel-0.1.5 → hishel-1.0.0.dev1}/.gitignore +2 -1
- hishel-1.0.0.dev1/CHANGELOG.md +45 -0
- hishel-1.0.0.dev1/PKG-INFO +298 -0
- hishel-1.0.0.dev1/README.md +214 -0
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/__init__.py +6 -6
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_async_cache.py +3 -3
- hishel-1.0.0.dev1/hishel/_core/__init__.py +59 -0
- hishel-1.0.0.dev1/hishel/_core/_async/_storages/_sqlite.py +457 -0
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_core/_base/_storages/_base.py +1 -1
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_core/_base/_storages/_packing.py +5 -5
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_core/_spec.py +89 -2
- hishel-1.0.0.dev1/hishel/_core/_sync/_storages/_sqlite.py +457 -0
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_core/models.py +1 -1
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_sync_cache.py +3 -3
- hishel-1.0.0.dev1/hishel/_utils.py +218 -0
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/httpx.py +15 -8
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/requests.py +5 -5
- {hishel-0.1.5 → hishel-1.0.0.dev1}/pyproject.toml +16 -23
- hishel-0.1.5/CHANGELOG.md +0 -64
- hishel-0.1.5/PKG-INFO +0 -258
- hishel-0.1.5/README.md +0 -148
- hishel-0.1.5/hishel/__init__.py +0 -57
- hishel-0.1.5/hishel/_async/__init__.py +0 -5
- hishel-0.1.5/hishel/_async/_client.py +0 -30
- hishel-0.1.5/hishel/_async/_mock.py +0 -43
- hishel-0.1.5/hishel/_async/_pool.py +0 -201
- hishel-0.1.5/hishel/_async/_storages.py +0 -768
- hishel-0.1.5/hishel/_async/_transports.py +0 -282
- hishel-0.1.5/hishel/_controller.py +0 -581
- hishel-0.1.5/hishel/_exceptions.py +0 -10
- hishel-0.1.5/hishel/_files.py +0 -54
- hishel-0.1.5/hishel/_headers.py +0 -215
- hishel-0.1.5/hishel/_lfu_cache.py +0 -71
- hishel-0.1.5/hishel/_lmdb_types_.pyi +0 -53
- hishel-0.1.5/hishel/_s3.py +0 -122
- hishel-0.1.5/hishel/_serializers.py +0 -329
- hishel-0.1.5/hishel/_sync/__init__.py +0 -5
- hishel-0.1.5/hishel/_sync/_client.py +0 -30
- hishel-0.1.5/hishel/_sync/_mock.py +0 -43
- hishel-0.1.5/hishel/_sync/_pool.py +0 -201
- hishel-0.1.5/hishel/_sync/_storages.py +0 -768
- hishel-0.1.5/hishel/_sync/_transports.py +0 -282
- hishel-0.1.5/hishel/_synchronization.py +0 -37
- hishel-0.1.5/hishel/_utils.py +0 -458
- hishel-0.1.5/hishel/beta/_core/__init__.py +0 -0
- hishel-0.1.5/hishel/beta/_core/_async/_storages/_sqlite.py +0 -411
- hishel-0.1.5/hishel/beta/_core/_sync/_storages/_sqlite.py +0 -411
- {hishel-0.1.5 → hishel-1.0.0.dev1}/LICENSE +0 -0
- {hishel-0.1.5/hishel/beta → hishel-1.0.0.dev1/hishel}/_core/_headers.py +0 -0
- {hishel-0.1.5 → hishel-1.0.0.dev1}/hishel/py.typed +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 1.0.0dev1 - 2025-10-21
|
|
6
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
7
|
+
- Remove some redundant utils methods
|
|
8
|
+
|
|
9
|
+
## 1.0.0.dev0 - 2025-10-19
|
|
10
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
11
|
+
- Use mike powered versioning
|
|
12
|
+
- Improve docs versioning, deploy dev doc on ci
|
|
13
|
+
|
|
14
|
+
## 0.1.5 - 2025-10-18
|
|
15
|
+
### <!-- 0 -->🚀 Features
|
|
16
|
+
- Set chunk size to 128KB for httpx to reduce SQLite read/writes
|
|
17
|
+
- Better cache-control parsing
|
|
18
|
+
- Add close method to storages API (#384)
|
|
19
|
+
- Increase requests buffer size to 128KB, disable charset detection
|
|
20
|
+
|
|
21
|
+
### <!-- 1 -->🐛 Bug Fixes
|
|
22
|
+
- Fix some line breaks
|
|
23
|
+
|
|
24
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
25
|
+
- Remove some redundant files from repo
|
|
26
|
+
|
|
27
|
+
## 0.1.4 - 2025-10-14
|
|
28
|
+
### <!-- 0 -->🚀 Features
|
|
29
|
+
- Add support for a sans-IO API (#366)
|
|
30
|
+
- Allow already consumed streams with `CacheTransport` (#377)
|
|
31
|
+
- Add sqlite storage for beta storages
|
|
32
|
+
- Get rid of some locks from sqlite storage
|
|
33
|
+
- Better async implemetation for sqlite storage
|
|
34
|
+
|
|
35
|
+
### <!-- 1 -->🐛 Bug Fixes
|
|
36
|
+
- Create an sqlite file in a cache folder
|
|
37
|
+
- Fix beta imports
|
|
38
|
+
|
|
39
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
40
|
+
- Improve CI (#369)
|
|
41
|
+
- Remove src folder (#373)
|
|
42
|
+
- Temporary remove python3.14 from CI
|
|
43
|
+
- Add sqlite tests for new storage
|
|
44
|
+
- Move some tests to beta
|
|
45
|
+
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hishel
|
|
3
|
+
Version: 1.0.0.dev1
|
|
4
|
+
Summary: Elegant HTTP Caching for Python
|
|
5
|
+
Project-URL: Homepage, https://hishel.com
|
|
6
|
+
Project-URL: Source, https://github.com/karpetrosyan/hishel
|
|
7
|
+
Author-email: Kar Petrosyan <kar.petrosyanpy@gmail.com>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Framework :: AsyncIO
|
|
13
|
+
Classifier: Framework :: Trio
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
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: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Requires-Dist: msgpack>=1.1.2
|
|
28
|
+
Requires-Dist: typing-extensions>=4.14.1
|
|
29
|
+
Provides-Extra: async
|
|
30
|
+
Requires-Dist: anyio>=4.9.0; extra == 'async'
|
|
31
|
+
Requires-Dist: anysqlite>=0.0.5; extra == 'async'
|
|
32
|
+
Provides-Extra: httpx
|
|
33
|
+
Requires-Dist: anyio>=4.9.0; extra == 'httpx'
|
|
34
|
+
Requires-Dist: anysqlite>=0.0.5; extra == 'httpx'
|
|
35
|
+
Requires-Dist: httpx>=0.28.1; extra == 'httpx'
|
|
36
|
+
Provides-Extra: requests
|
|
37
|
+
Requires-Dist: requests>=2.32.5; extra == 'requests'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
<p align="center">
|
|
41
|
+
<img alt="Hishel Logo" width="350" src="https://raw.githubusercontent.com/karpetrosyan/hishel/master/docs/static/Shelkopryad_350x250_yellow.png#gh-dark-mode-only">
|
|
42
|
+
<img alt="Hishel Logo" width="350" src="https://raw.githubusercontent.com/karpetrosyan/hishel/master/docs/static/Shelkopryad_350x250_black.png#gh-light-mode-only">
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<h1 align="center">Hishel</h1>
|
|
46
|
+
|
|
47
|
+
<p align="center">
|
|
48
|
+
<strong>Elegant HTTP Caching for Python</strong>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<a href="https://pypi.org/project/hishel">
|
|
53
|
+
<img src="https://img.shields.io/pypi/v/hishel.svg" alt="PyPI version">
|
|
54
|
+
</a>
|
|
55
|
+
<a href="https://pypi.org/project/hishel">
|
|
56
|
+
<img src="https://img.shields.io/pypi/pyversions/hishel.svg" alt="Python versions">
|
|
57
|
+
</a>
|
|
58
|
+
<a href="https://github.com/karpetrosyan/hishel/blob/master/LICENSE">
|
|
59
|
+
<img src="https://img.shields.io/pypi/l/hishel" alt="License">
|
|
60
|
+
</a>
|
|
61
|
+
<a href="https://coveralls.io/github/karpetrosyan/hishel">
|
|
62
|
+
<img src="https://img.shields.io/coverallsCoverage/github/karpetrosyan/hishel" alt="Coverage">
|
|
63
|
+
</a>
|
|
64
|
+
<a href="https://static.pepy.tech/badge/hishel/month">
|
|
65
|
+
<img src="https://static.pepy.tech/badge/hishel/month" alt="Downloads">
|
|
66
|
+
</a>
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
**Hishel** (հիշել, *to remember* in Armenian) is a modern HTTP caching library for Python that implements [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111.html) specifications. It provides seamless caching integration for popular HTTP clients with minimal code changes.
|
|
72
|
+
|
|
73
|
+
## ✨ Features
|
|
74
|
+
|
|
75
|
+
- 🎯 **RFC 9111 Compliant** - Fully compliant with the latest HTTP caching specification
|
|
76
|
+
- 🔌 **Easy Integration** - Drop-in support for HTTPX and Requests
|
|
77
|
+
- 💾 **Flexible Storage** - SQLite backend with more coming soon
|
|
78
|
+
- ⚡ **High Performance** - Efficient caching with minimal overhead
|
|
79
|
+
- 🔄 **Async & Sync** - Full support for both synchronous and asynchronous workflows
|
|
80
|
+
- 🎨 **Type Safe** - Fully typed with comprehensive type hints
|
|
81
|
+
- 🧪 **Well Tested** - Extensive test coverage and battle-tested
|
|
82
|
+
- 🎛️ **Configurable** - Fine-grained control over caching behavior
|
|
83
|
+
- 🌐 **Future Ready** - Designed for easy integration with any HTTP client/server
|
|
84
|
+
|
|
85
|
+
## 📦 Installation
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install hishel
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Optional Dependencies
|
|
92
|
+
|
|
93
|
+
Install with specific HTTP client support:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install hishel[httpx] # For HTTPX support
|
|
97
|
+
pip install hishel[requests] # For Requests support
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Or install both:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install hishel[httpx,requests]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 🚀 Quick Start
|
|
107
|
+
|
|
108
|
+
### With HTTPX
|
|
109
|
+
|
|
110
|
+
**Synchronous:**
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from hishel.httpx import SyncCacheClient
|
|
114
|
+
|
|
115
|
+
client = SyncCacheClient()
|
|
116
|
+
|
|
117
|
+
# First request - fetches from origin
|
|
118
|
+
response = client.get("https://api.example.com/data")
|
|
119
|
+
print(response.extensions["hishel_from_cache"]) # False
|
|
120
|
+
|
|
121
|
+
# Second request - served from cache
|
|
122
|
+
response = client.get("https://api.example.com/data")
|
|
123
|
+
print(response.extensions["hishel_from_cache"]) # True
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Asynchronous:**
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from hishel.httpx import AsyncCacheClient
|
|
130
|
+
|
|
131
|
+
async with AsyncCacheClient() as client:
|
|
132
|
+
# First request - fetches from origin
|
|
133
|
+
response = await client.get("https://api.example.com/data")
|
|
134
|
+
print(response.extensions["hishel_from_cache"]) # False
|
|
135
|
+
|
|
136
|
+
# Second request - served from cache
|
|
137
|
+
response = await client.get("https://api.example.com/data")
|
|
138
|
+
print(response.extensions["hishel_from_cache"]) # True
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### With Requests
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import requests
|
|
145
|
+
from hishel.requests import CacheAdapter
|
|
146
|
+
|
|
147
|
+
session = requests.Session()
|
|
148
|
+
session.mount("https://", CacheAdapter())
|
|
149
|
+
session.mount("http://", CacheAdapter())
|
|
150
|
+
|
|
151
|
+
# First request - fetches from origin
|
|
152
|
+
response = session.get("https://api.example.com/data")
|
|
153
|
+
|
|
154
|
+
# Second request - served from cache
|
|
155
|
+
response = session.get("https://api.example.com/data")
|
|
156
|
+
print(response.headers.get("X-Hishel-From-Cache")) # "True"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 🎛️ Advanced Configuration
|
|
160
|
+
|
|
161
|
+
### Custom Cache Options
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from hishel import CacheOptions
|
|
165
|
+
from hishel.httpx import SyncCacheClient
|
|
166
|
+
|
|
167
|
+
client = SyncCacheClient(
|
|
168
|
+
cache_options=CacheOptions(
|
|
169
|
+
shared=False, # Use as private cache (browser-like)
|
|
170
|
+
supported_methods=["GET", "HEAD", "POST"], # Cache GET, HEAD, and POST
|
|
171
|
+
allow_stale=True # Allow serving stale responses
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Custom Storage Backend
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from hishel import SyncSqliteStorage
|
|
180
|
+
from hishel.httpx import SyncCacheClient
|
|
181
|
+
|
|
182
|
+
storage = SyncSqliteStorage(
|
|
183
|
+
database_path="my_cache.db",
|
|
184
|
+
default_ttl=7200.0, # Cache entries expire after 2 hours
|
|
185
|
+
refresh_ttl_on_access=True # Reset TTL when accessing cached entries
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
client = SyncCacheClient(storage=storage)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## 🏗️ Architecture
|
|
192
|
+
|
|
193
|
+
Hishel uses a **sans-I/O state machine** architecture that separates HTTP caching logic from I/O operations:
|
|
194
|
+
|
|
195
|
+
- ✅ **Correct** - Fully RFC 9111 compliant
|
|
196
|
+
- ✅ **Testable** - Easy to test without network dependencies
|
|
197
|
+
- ✅ **Flexible** - Works with any HTTP client or server
|
|
198
|
+
- ✅ **Type Safe** - Clear state transitions with full type hints
|
|
199
|
+
|
|
200
|
+
## 🔮 Roadmap
|
|
201
|
+
|
|
202
|
+
While Hishel currently supports HTTPX and Requests, we're actively working on:
|
|
203
|
+
|
|
204
|
+
- 🎯 Additional HTTP client integrations
|
|
205
|
+
- 🎯 Server-side caching support
|
|
206
|
+
- 🎯 More storage backends
|
|
207
|
+
- 🎯 Advanced caching strategies
|
|
208
|
+
- 🎯 Performance optimizations
|
|
209
|
+
|
|
210
|
+
## 📚 Documentation
|
|
211
|
+
|
|
212
|
+
Comprehensive documentation is available at [https://hishel.com/dev](https://hishel.com/dev)
|
|
213
|
+
|
|
214
|
+
- [Getting Started](https://hishel.com)
|
|
215
|
+
- [HTTPX Integration](https://hishel.com/dev/integrations/httpx)
|
|
216
|
+
- [Requests Integration](https://hishel.com/dev/integrations/requests)
|
|
217
|
+
- [Storage Backends](https://hishel.com/dev/storages)
|
|
218
|
+
- [RFC 9111 Specification](https://hishel.com/dev/specification)
|
|
219
|
+
|
|
220
|
+
## 🤝 Contributing
|
|
221
|
+
|
|
222
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
223
|
+
|
|
224
|
+
See our [Contributing Guide](https://hishel.com/dev/contributing) for more details.
|
|
225
|
+
|
|
226
|
+
## 📄 License
|
|
227
|
+
|
|
228
|
+
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
|
|
229
|
+
|
|
230
|
+
## 💖 Support
|
|
231
|
+
|
|
232
|
+
If you find Hishel useful, please consider:
|
|
233
|
+
|
|
234
|
+
- ⭐ Starring the repository
|
|
235
|
+
- 🐛 Reporting bugs and issues
|
|
236
|
+
- 💡 Suggesting new features
|
|
237
|
+
- 📖 Improving documentation
|
|
238
|
+
- ☕ [Buying me a coffee](https://buymeacoffee.com/karpetrosyan)
|
|
239
|
+
|
|
240
|
+
## 🙏 Acknowledgments
|
|
241
|
+
|
|
242
|
+
Hishel is inspired by and builds upon the excellent work in the Python HTTP ecosystem, particularly:
|
|
243
|
+
|
|
244
|
+
- [HTTPX](https://github.com/encode/httpx) - A next-generation HTTP client for Python
|
|
245
|
+
- [Requests](https://github.com/psf/requests) - The classic HTTP library for Python
|
|
246
|
+
- [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111.html) - HTTP Caching specification
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
<p align="center">
|
|
251
|
+
<strong>Made with ❤️ by <a href="https://github.com/karpetrosyan">Kar Petrosyan</a></strong>
|
|
252
|
+
</p>
|
|
253
|
+
|
|
254
|
+
# Changelog
|
|
255
|
+
|
|
256
|
+
All notable changes to this project will be documented in this file.
|
|
257
|
+
|
|
258
|
+
## 1.0.0dev1 - 2025-10-21
|
|
259
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
260
|
+
- Remove some redundant utils methods
|
|
261
|
+
|
|
262
|
+
## 1.0.0.dev0 - 2025-10-19
|
|
263
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
264
|
+
- Use mike powered versioning
|
|
265
|
+
- Improve docs versioning, deploy dev doc on ci
|
|
266
|
+
|
|
267
|
+
## 0.1.5 - 2025-10-18
|
|
268
|
+
### <!-- 0 -->🚀 Features
|
|
269
|
+
- Set chunk size to 128KB for httpx to reduce SQLite read/writes
|
|
270
|
+
- Better cache-control parsing
|
|
271
|
+
- Add close method to storages API (#384)
|
|
272
|
+
- Increase requests buffer size to 128KB, disable charset detection
|
|
273
|
+
|
|
274
|
+
### <!-- 1 -->🐛 Bug Fixes
|
|
275
|
+
- Fix some line breaks
|
|
276
|
+
|
|
277
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
278
|
+
- Remove some redundant files from repo
|
|
279
|
+
|
|
280
|
+
## 0.1.4 - 2025-10-14
|
|
281
|
+
### <!-- 0 -->🚀 Features
|
|
282
|
+
- Add support for a sans-IO API (#366)
|
|
283
|
+
- Allow already consumed streams with `CacheTransport` (#377)
|
|
284
|
+
- Add sqlite storage for beta storages
|
|
285
|
+
- Get rid of some locks from sqlite storage
|
|
286
|
+
- Better async implemetation for sqlite storage
|
|
287
|
+
|
|
288
|
+
### <!-- 1 -->🐛 Bug Fixes
|
|
289
|
+
- Create an sqlite file in a cache folder
|
|
290
|
+
- Fix beta imports
|
|
291
|
+
|
|
292
|
+
### <!-- 7 -->⚙️ Miscellaneous Tasks
|
|
293
|
+
- Improve CI (#369)
|
|
294
|
+
- Remove src folder (#373)
|
|
295
|
+
- Temporary remove python3.14 from CI
|
|
296
|
+
- Add sqlite tests for new storage
|
|
297
|
+
- Move some tests to beta
|
|
298
|
+
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="Hishel Logo" width="350" src="https://raw.githubusercontent.com/karpetrosyan/hishel/master/docs/static/Shelkopryad_350x250_yellow.png#gh-dark-mode-only">
|
|
3
|
+
<img alt="Hishel Logo" width="350" src="https://raw.githubusercontent.com/karpetrosyan/hishel/master/docs/static/Shelkopryad_350x250_black.png#gh-light-mode-only">
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<h1 align="center">Hishel</h1>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<strong>Elegant HTTP Caching for Python</strong>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://pypi.org/project/hishel">
|
|
14
|
+
<img src="https://img.shields.io/pypi/v/hishel.svg" alt="PyPI version">
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://pypi.org/project/hishel">
|
|
17
|
+
<img src="https://img.shields.io/pypi/pyversions/hishel.svg" alt="Python versions">
|
|
18
|
+
</a>
|
|
19
|
+
<a href="https://github.com/karpetrosyan/hishel/blob/master/LICENSE">
|
|
20
|
+
<img src="https://img.shields.io/pypi/l/hishel" alt="License">
|
|
21
|
+
</a>
|
|
22
|
+
<a href="https://coveralls.io/github/karpetrosyan/hishel">
|
|
23
|
+
<img src="https://img.shields.io/coverallsCoverage/github/karpetrosyan/hishel" alt="Coverage">
|
|
24
|
+
</a>
|
|
25
|
+
<a href="https://static.pepy.tech/badge/hishel/month">
|
|
26
|
+
<img src="https://static.pepy.tech/badge/hishel/month" alt="Downloads">
|
|
27
|
+
</a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
**Hishel** (հիշել, *to remember* in Armenian) is a modern HTTP caching library for Python that implements [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111.html) specifications. It provides seamless caching integration for popular HTTP clients with minimal code changes.
|
|
33
|
+
|
|
34
|
+
## ✨ Features
|
|
35
|
+
|
|
36
|
+
- 🎯 **RFC 9111 Compliant** - Fully compliant with the latest HTTP caching specification
|
|
37
|
+
- 🔌 **Easy Integration** - Drop-in support for HTTPX and Requests
|
|
38
|
+
- 💾 **Flexible Storage** - SQLite backend with more coming soon
|
|
39
|
+
- ⚡ **High Performance** - Efficient caching with minimal overhead
|
|
40
|
+
- 🔄 **Async & Sync** - Full support for both synchronous and asynchronous workflows
|
|
41
|
+
- 🎨 **Type Safe** - Fully typed with comprehensive type hints
|
|
42
|
+
- 🧪 **Well Tested** - Extensive test coverage and battle-tested
|
|
43
|
+
- 🎛️ **Configurable** - Fine-grained control over caching behavior
|
|
44
|
+
- 🌐 **Future Ready** - Designed for easy integration with any HTTP client/server
|
|
45
|
+
|
|
46
|
+
## 📦 Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install hishel
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Optional Dependencies
|
|
53
|
+
|
|
54
|
+
Install with specific HTTP client support:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install hishel[httpx] # For HTTPX support
|
|
58
|
+
pip install hishel[requests] # For Requests support
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or install both:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install hishel[httpx,requests]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 🚀 Quick Start
|
|
68
|
+
|
|
69
|
+
### With HTTPX
|
|
70
|
+
|
|
71
|
+
**Synchronous:**
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from hishel.httpx import SyncCacheClient
|
|
75
|
+
|
|
76
|
+
client = SyncCacheClient()
|
|
77
|
+
|
|
78
|
+
# First request - fetches from origin
|
|
79
|
+
response = client.get("https://api.example.com/data")
|
|
80
|
+
print(response.extensions["hishel_from_cache"]) # False
|
|
81
|
+
|
|
82
|
+
# Second request - served from cache
|
|
83
|
+
response = client.get("https://api.example.com/data")
|
|
84
|
+
print(response.extensions["hishel_from_cache"]) # True
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Asynchronous:**
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from hishel.httpx import AsyncCacheClient
|
|
91
|
+
|
|
92
|
+
async with AsyncCacheClient() as client:
|
|
93
|
+
# First request - fetches from origin
|
|
94
|
+
response = await client.get("https://api.example.com/data")
|
|
95
|
+
print(response.extensions["hishel_from_cache"]) # False
|
|
96
|
+
|
|
97
|
+
# Second request - served from cache
|
|
98
|
+
response = await client.get("https://api.example.com/data")
|
|
99
|
+
print(response.extensions["hishel_from_cache"]) # True
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### With Requests
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
import requests
|
|
106
|
+
from hishel.requests import CacheAdapter
|
|
107
|
+
|
|
108
|
+
session = requests.Session()
|
|
109
|
+
session.mount("https://", CacheAdapter())
|
|
110
|
+
session.mount("http://", CacheAdapter())
|
|
111
|
+
|
|
112
|
+
# First request - fetches from origin
|
|
113
|
+
response = session.get("https://api.example.com/data")
|
|
114
|
+
|
|
115
|
+
# Second request - served from cache
|
|
116
|
+
response = session.get("https://api.example.com/data")
|
|
117
|
+
print(response.headers.get("X-Hishel-From-Cache")) # "True"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 🎛️ Advanced Configuration
|
|
121
|
+
|
|
122
|
+
### Custom Cache Options
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from hishel import CacheOptions
|
|
126
|
+
from hishel.httpx import SyncCacheClient
|
|
127
|
+
|
|
128
|
+
client = SyncCacheClient(
|
|
129
|
+
cache_options=CacheOptions(
|
|
130
|
+
shared=False, # Use as private cache (browser-like)
|
|
131
|
+
supported_methods=["GET", "HEAD", "POST"], # Cache GET, HEAD, and POST
|
|
132
|
+
allow_stale=True # Allow serving stale responses
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Custom Storage Backend
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from hishel import SyncSqliteStorage
|
|
141
|
+
from hishel.httpx import SyncCacheClient
|
|
142
|
+
|
|
143
|
+
storage = SyncSqliteStorage(
|
|
144
|
+
database_path="my_cache.db",
|
|
145
|
+
default_ttl=7200.0, # Cache entries expire after 2 hours
|
|
146
|
+
refresh_ttl_on_access=True # Reset TTL when accessing cached entries
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
client = SyncCacheClient(storage=storage)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 🏗️ Architecture
|
|
153
|
+
|
|
154
|
+
Hishel uses a **sans-I/O state machine** architecture that separates HTTP caching logic from I/O operations:
|
|
155
|
+
|
|
156
|
+
- ✅ **Correct** - Fully RFC 9111 compliant
|
|
157
|
+
- ✅ **Testable** - Easy to test without network dependencies
|
|
158
|
+
- ✅ **Flexible** - Works with any HTTP client or server
|
|
159
|
+
- ✅ **Type Safe** - Clear state transitions with full type hints
|
|
160
|
+
|
|
161
|
+
## 🔮 Roadmap
|
|
162
|
+
|
|
163
|
+
While Hishel currently supports HTTPX and Requests, we're actively working on:
|
|
164
|
+
|
|
165
|
+
- 🎯 Additional HTTP client integrations
|
|
166
|
+
- 🎯 Server-side caching support
|
|
167
|
+
- 🎯 More storage backends
|
|
168
|
+
- 🎯 Advanced caching strategies
|
|
169
|
+
- 🎯 Performance optimizations
|
|
170
|
+
|
|
171
|
+
## 📚 Documentation
|
|
172
|
+
|
|
173
|
+
Comprehensive documentation is available at [https://hishel.com/dev](https://hishel.com/dev)
|
|
174
|
+
|
|
175
|
+
- [Getting Started](https://hishel.com)
|
|
176
|
+
- [HTTPX Integration](https://hishel.com/dev/integrations/httpx)
|
|
177
|
+
- [Requests Integration](https://hishel.com/dev/integrations/requests)
|
|
178
|
+
- [Storage Backends](https://hishel.com/dev/storages)
|
|
179
|
+
- [RFC 9111 Specification](https://hishel.com/dev/specification)
|
|
180
|
+
|
|
181
|
+
## 🤝 Contributing
|
|
182
|
+
|
|
183
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
184
|
+
|
|
185
|
+
See our [Contributing Guide](https://hishel.com/dev/contributing) for more details.
|
|
186
|
+
|
|
187
|
+
## 📄 License
|
|
188
|
+
|
|
189
|
+
This project is licensed under the BSD-3-Clause License - see the [LICENSE](LICENSE) file for details.
|
|
190
|
+
|
|
191
|
+
## 💖 Support
|
|
192
|
+
|
|
193
|
+
If you find Hishel useful, please consider:
|
|
194
|
+
|
|
195
|
+
- ⭐ Starring the repository
|
|
196
|
+
- 🐛 Reporting bugs and issues
|
|
197
|
+
- 💡 Suggesting new features
|
|
198
|
+
- 📖 Improving documentation
|
|
199
|
+
- ☕ [Buying me a coffee](https://buymeacoffee.com/karpetrosyan)
|
|
200
|
+
|
|
201
|
+
## 🙏 Acknowledgments
|
|
202
|
+
|
|
203
|
+
Hishel is inspired by and builds upon the excellent work in the Python HTTP ecosystem, particularly:
|
|
204
|
+
|
|
205
|
+
- [HTTPX](https://github.com/encode/httpx) - A next-generation HTTP client for Python
|
|
206
|
+
- [Requests](https://github.com/psf/requests) - The classic HTTP library for Python
|
|
207
|
+
- [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111.html) - HTTP Caching specification
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
<p align="center">
|
|
212
|
+
<strong>Made with ❤️ by <a href="https://github.com/karpetrosyan">Kar Petrosyan</a></strong>
|
|
213
|
+
</p>
|
|
214
|
+
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from hishel.
|
|
2
|
-
from hishel.
|
|
1
|
+
from hishel._core._async._storages._sqlite import AsyncSqliteStorage
|
|
2
|
+
from hishel._core._base._storages._base import (
|
|
3
3
|
AsyncBaseStorage as AsyncBaseStorage,
|
|
4
4
|
SyncBaseStorage as SyncBaseStorage,
|
|
5
5
|
)
|
|
6
|
-
from hishel.
|
|
7
|
-
from hishel.
|
|
6
|
+
from hishel._core._headers import Headers as Headers
|
|
7
|
+
from hishel._core._spec import (
|
|
8
8
|
AnyState as AnyState,
|
|
9
9
|
CacheMiss as CacheMiss,
|
|
10
10
|
CacheOptions as CacheOptions,
|
|
@@ -17,8 +17,8 @@ from hishel.beta._core._spec import (
|
|
|
17
17
|
StoreAndUse as StoreAndUse,
|
|
18
18
|
create_idle_state as create_idle_state,
|
|
19
19
|
)
|
|
20
|
-
from hishel.
|
|
21
|
-
from hishel.
|
|
20
|
+
from hishel._core._sync._storages._sqlite import SyncSqliteStorage
|
|
21
|
+
from hishel._core.models import (
|
|
22
22
|
CompletePair as CompletePair,
|
|
23
23
|
IncompletePair as IncompletePair,
|
|
24
24
|
Pair as Pair,
|
|
@@ -8,7 +8,7 @@ from typing import AsyncIterator, Awaitable, Callable
|
|
|
8
8
|
|
|
9
9
|
from typing_extensions import assert_never
|
|
10
10
|
|
|
11
|
-
from hishel
|
|
11
|
+
from hishel import (
|
|
12
12
|
AnyState,
|
|
13
13
|
AsyncBaseStorage,
|
|
14
14
|
AsyncSqliteStorage,
|
|
@@ -24,8 +24,8 @@ from hishel.beta import (
|
|
|
24
24
|
StoreAndUse,
|
|
25
25
|
create_idle_state,
|
|
26
26
|
)
|
|
27
|
-
from hishel.
|
|
28
|
-
from hishel.
|
|
27
|
+
from hishel._core._spec import InvalidatePairs, vary_headers_match
|
|
28
|
+
from hishel._core.models import CompletePair
|
|
29
29
|
|
|
30
30
|
logger = logging.getLogger("hishel.integrations.clients")
|
|
31
31
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from hishel._core._async._storages._sqlite import AsyncSqliteStorage
|
|
2
|
+
from hishel._core._base._storages._base import (
|
|
3
|
+
AsyncBaseStorage as AsyncBaseStorage,
|
|
4
|
+
SyncBaseStorage as SyncBaseStorage,
|
|
5
|
+
)
|
|
6
|
+
from hishel._core._headers import Headers as Headers
|
|
7
|
+
from hishel._core._spec import (
|
|
8
|
+
AnyState as AnyState,
|
|
9
|
+
CacheMiss as CacheMiss,
|
|
10
|
+
CacheOptions as CacheOptions,
|
|
11
|
+
CouldNotBeStored as CouldNotBeStored,
|
|
12
|
+
FromCache as FromCache,
|
|
13
|
+
IdleClient as IdleClient,
|
|
14
|
+
NeedRevalidation as NeedRevalidation,
|
|
15
|
+
NeedToBeUpdated as NeedToBeUpdated,
|
|
16
|
+
State as State,
|
|
17
|
+
StoreAndUse as StoreAndUse,
|
|
18
|
+
create_idle_state as create_idle_state,
|
|
19
|
+
)
|
|
20
|
+
from hishel._core._sync._storages._sqlite import SyncSqliteStorage
|
|
21
|
+
from hishel._core.models import (
|
|
22
|
+
CompletePair as CompletePair,
|
|
23
|
+
IncompletePair as IncompletePair,
|
|
24
|
+
Pair as Pair,
|
|
25
|
+
PairMeta as PairMeta,
|
|
26
|
+
Request as Request,
|
|
27
|
+
Response,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
__all__ = (
|
|
31
|
+
# New API
|
|
32
|
+
## States
|
|
33
|
+
"AnyState",
|
|
34
|
+
"IdleClient",
|
|
35
|
+
"CacheMiss",
|
|
36
|
+
"FromCache",
|
|
37
|
+
"NeedRevalidation",
|
|
38
|
+
"AnyState",
|
|
39
|
+
"CacheOptions",
|
|
40
|
+
"NeedToBeUpdated",
|
|
41
|
+
"State",
|
|
42
|
+
"StoreAndUse",
|
|
43
|
+
"CouldNotBeStored",
|
|
44
|
+
"create_idle_state",
|
|
45
|
+
## Models
|
|
46
|
+
"Request",
|
|
47
|
+
"Response",
|
|
48
|
+
"Pair",
|
|
49
|
+
"IncompletePair",
|
|
50
|
+
"CompletePair",
|
|
51
|
+
"PairMeta",
|
|
52
|
+
## Headers
|
|
53
|
+
"Headers",
|
|
54
|
+
## Storages
|
|
55
|
+
"SyncBaseStorage",
|
|
56
|
+
"AsyncBaseStorage",
|
|
57
|
+
"SyncSqliteStorage",
|
|
58
|
+
"AsyncSqliteStorage",
|
|
59
|
+
)
|