hishel 0.1.3__tar.gz → 0.1.5__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.3 → hishel-0.1.5}/.gitignore +3 -1
- hishel-0.1.5/CHANGELOG.md +64 -0
- {hishel-0.1.3 → hishel-0.1.5}/PKG-INFO +58 -167
- {hishel-0.1.3 → hishel-0.1.5}/README.md +6 -2
- hishel-0.1.5/hishel/__init__.py +57 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/_client.py +1 -1
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/_storages.py +10 -14
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/_transports.py +9 -4
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_controller.py +2 -3
- hishel-0.1.5/hishel/_lmdb_types_.pyi +53 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_serializers.py +2 -2
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/_client.py +1 -1
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/_storages.py +10 -14
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/_transports.py +9 -4
- hishel-0.1.5/hishel/_utils.py +458 -0
- hishel-0.1.5/hishel/beta/__init__.py +59 -0
- hishel-0.1.5/hishel/beta/_async_cache.py +167 -0
- hishel-0.1.5/hishel/beta/_core/_async/_storages/_sqlite.py +411 -0
- hishel-0.1.5/hishel/beta/_core/_base/_storages/_base.py +272 -0
- hishel-0.1.5/hishel/beta/_core/_base/_storages/_packing.py +165 -0
- hishel-0.1.5/hishel/beta/_core/_headers.py +636 -0
- hishel-0.1.5/hishel/beta/_core/_spec.py +2291 -0
- hishel-0.1.5/hishel/beta/_core/_sync/_storages/_sqlite.py +411 -0
- hishel-0.1.5/hishel/beta/_core/models.py +176 -0
- hishel-0.1.5/hishel/beta/_sync_cache.py +167 -0
- hishel-0.1.5/hishel/beta/httpx.py +328 -0
- hishel-0.1.5/hishel/beta/requests.py +198 -0
- hishel-0.1.5/hishel/py.typed +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/pyproject.toml +44 -44
- hishel-0.1.3/CHANGELOG.md +0 -186
- hishel-0.1.3/hishel/__init__.py +0 -17
- hishel-0.1.3/hishel/_utils.py +0 -118
- {hishel-0.1.3 → hishel-0.1.5}/LICENSE +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/__init__.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/_mock.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_async/_pool.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_exceptions.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_files.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_headers.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_lfu_cache.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_s3.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/__init__.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/_mock.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_sync/_pool.py +0 -0
- {hishel-0.1.3 → hishel-0.1.5}/hishel/_synchronization.py +0 -0
- /hishel-0.1.3/hishel/py.typed → /hishel-0.1.5/hishel/beta/_core/__init__.py +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
## [0.1.5] - 2025-10-18
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- *(perf)* Set chunk size to 128KB for httpx to reduce SQLite read/writes
|
|
6
|
+
- Better cache-control parsing
|
|
7
|
+
- Add close method to storages API (#384)
|
|
8
|
+
- *(perf)* Increase requests buffer size to 128KB, disable charset detection
|
|
9
|
+
|
|
10
|
+
### 🐛 Bug Fixes
|
|
11
|
+
|
|
12
|
+
- *(docs)* Fix some line breaks
|
|
13
|
+
|
|
14
|
+
### ⚙️ Miscellaneous Tasks
|
|
15
|
+
|
|
16
|
+
- Remove some redundant files from repo
|
|
17
|
+
## [0.1.4] - 2025-10-14
|
|
18
|
+
|
|
19
|
+
### 🚀 Features
|
|
20
|
+
|
|
21
|
+
- Add support for a sans-IO API (#366)
|
|
22
|
+
- Allow already consumed streams with `CacheTransport` (#377)
|
|
23
|
+
- Add sqlite storage for beta storages
|
|
24
|
+
- Get rid of some locks from sqlite storage
|
|
25
|
+
- Better async implemetation for sqlite storage
|
|
26
|
+
|
|
27
|
+
### 🐛 Bug Fixes
|
|
28
|
+
|
|
29
|
+
- Create an sqlite file in a cache folder
|
|
30
|
+
- Fix beta imports
|
|
31
|
+
|
|
32
|
+
### ⚙️ Miscellaneous Tasks
|
|
33
|
+
|
|
34
|
+
- Improve CI (#369)
|
|
35
|
+
- *(internal)* Remove src folder (#373)
|
|
36
|
+
- *(internal)* Temporary remove python3.14 from CI
|
|
37
|
+
- *(tests)* Add sqlite tests for new storage
|
|
38
|
+
- *(tests)* Move some tests to beta
|
|
39
|
+
## [0.1.3] - 2025-07-06
|
|
40
|
+
|
|
41
|
+
### 🚀 Features
|
|
42
|
+
|
|
43
|
+
- Support providing a path prefix to S3 storage (#342)
|
|
44
|
+
|
|
45
|
+
### 📚 Documentation
|
|
46
|
+
|
|
47
|
+
- Update link to httpx transports page (#337)
|
|
48
|
+
## [0.1.2] - 2025-04-04
|
|
49
|
+
|
|
50
|
+
### 🐛 Bug Fixes
|
|
51
|
+
|
|
52
|
+
- Requirements.txt to reduce vulnerabilities (#263)
|
|
53
|
+
## [0.0.30] - 2024-07-12
|
|
54
|
+
|
|
55
|
+
### 🐛 Bug Fixes
|
|
56
|
+
|
|
57
|
+
- Requirements.txt to reduce vulnerabilities (#245)
|
|
58
|
+
- Requirements.txt to reduce vulnerabilities (#255)
|
|
59
|
+
## [0.0.27] - 2024-05-31
|
|
60
|
+
|
|
61
|
+
### 🐛 Bug Fixes
|
|
62
|
+
|
|
63
|
+
- *(redis)* Do not update metadata with negative ttl (#231)
|
|
64
|
+
## [0.0.1] - 2023-07-22
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hishel
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Persistent cache implementation for httpx and httpcore
|
|
5
5
|
Project-URL: Homepage, https://hishel.com
|
|
6
6
|
Project-URL: Source, https://github.com/karpetrosyan/hishel
|
|
@@ -21,11 +21,20 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
25
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
25
26
|
Requires-Python: >=3.9
|
|
27
|
+
Requires-Dist: anyio>=4.9.0
|
|
28
|
+
Requires-Dist: anysqlite>=0.0.5
|
|
26
29
|
Requires-Dist: httpx>=0.28.0
|
|
30
|
+
Requires-Dist: msgpack>=1.1.2
|
|
31
|
+
Requires-Dist: typing-extensions>=4.14.1
|
|
32
|
+
Provides-Extra: httpx
|
|
33
|
+
Requires-Dist: httpx>=0.28.1; extra == 'httpx'
|
|
27
34
|
Provides-Extra: redis
|
|
28
35
|
Requires-Dist: redis==6.2.0; extra == 'redis'
|
|
36
|
+
Provides-Extra: requests
|
|
37
|
+
Requires-Dist: requests>=2.32.5; extra == 'requests'
|
|
29
38
|
Provides-Extra: s3
|
|
30
39
|
Requires-Dist: boto3<=1.15.3,>=1.15.0; (python_version < '3.12') and extra == 's3'
|
|
31
40
|
Requires-Dist: boto3>=1.15.3; (python_version >= '3.12') and extra == 's3'
|
|
@@ -59,8 +68,8 @@ Description-Content-Type: text/markdown
|
|
|
59
68
|
<img src="https://img.shields.io/pypi/l/hishel" alt="license">
|
|
60
69
|
</a>
|
|
61
70
|
|
|
62
|
-
<a href="https://
|
|
63
|
-
<img src="https://img.shields.io/
|
|
71
|
+
<a href="https://coveralls.io/github/karpetrosyan/hishel">
|
|
72
|
+
<img src="https://img.shields.io/coverallsCoverage/github/karpetrosyan/hishel" alt="license">
|
|
64
73
|
</a>
|
|
65
74
|
|
|
66
75
|
<a href="https://github.com/karpetrosyan/hishel">
|
|
@@ -68,6 +77,10 @@ Description-Content-Type: text/markdown
|
|
|
68
77
|
</a>
|
|
69
78
|
</p>
|
|
70
79
|
|
|
80
|
+
<p align="center">
|
|
81
|
+
<a href="https://buymeacoffee.com/karpetrosyan" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
|
|
82
|
+
</p>
|
|
83
|
+
|
|
71
84
|
-----
|
|
72
85
|
|
|
73
86
|
**Hishel (հիշել, remember)** is a library that implements HTTP Caching for [HTTPX](https://github.com/encode/httpx) and [HTTP Core](https://github.com/encode/httpcore) libraries in accordance with [**RFC 9111**](https://www.rfc-editor.org/rfc/rfc9111.html), the most recent caching specification.
|
|
@@ -179,189 +192,67 @@ You have complete control over them; you can change storage or even write your o
|
|
|
179
192
|
You can support the project by simply leaving a GitHub star ⭐ or by [contributing](https://hishel.com/contributing/).
|
|
180
193
|
Help us grow and continue developing good software for you ❤️
|
|
181
194
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
## 0.1.3 (1st July, 2025)
|
|
185
|
-
|
|
186
|
-
- Remove `types-redis` from dev dependencies (#336)
|
|
187
|
-
- Bump redis to 6.0.0 and address async `.close()` deprecation warning (#336)
|
|
188
|
-
- Avoid race condition when unlinking files in `FileStorage`. (#334)
|
|
189
|
-
- Allow prodiving a `path_prefix` in `S3Storage` and `AsyncS3Storage`. (#342)
|
|
190
|
-
|
|
191
|
-
## 0.1.2 (5th April, 2025)
|
|
192
|
-
|
|
193
|
-
- Add check for fips compliant python. (#325)
|
|
194
|
-
- Fix compatibility with httpx. (#291)
|
|
195
|
-
- Use `SyncByteStream` instead of `ByteStream`. (#298)
|
|
196
|
-
- Don't raise exceptions if date-containing headers are invalid. (#318)
|
|
197
|
-
- Fix for S3 Storage missing metadata in API request. (#320)
|
|
198
|
-
|
|
199
|
-
## 0.1.1 (2nd Nov, 2024)
|
|
200
|
-
|
|
201
|
-
- Fix typing extensions not found. (#290)
|
|
202
|
-
|
|
203
|
-
## 0.1.0 (2nd Nov, 2024)
|
|
204
|
-
|
|
205
|
-
- Add support for Python 3.12 / drop Python 3.8. (#286)
|
|
206
|
-
- Specify usedforsecurity=False in blake2b. (#285)
|
|
207
|
-
|
|
208
|
-
## 0.0.33 (4th Oct, 2024)
|
|
209
|
-
|
|
210
|
-
- Added a [Logging](https://hishel.com/advanced/logging/) section to the documentation.
|
|
211
|
-
|
|
212
|
-
## 0.0.32 (27th Sep, 2024)
|
|
213
|
-
|
|
214
|
-
- Don't raise an exception if the `Date` header is not present. (#273)
|
|
215
|
-
|
|
216
|
-
## 0.0.31 (22nd Sep, 2024)
|
|
217
|
-
|
|
218
|
-
- Ignore file not found error when cleaning up a file storage. (#264)
|
|
219
|
-
- Fix `AssertionError` on `client.close()` when use SQLiteStorage. (#269)
|
|
220
|
-
- Fix ignored flags when use `force_cache`. (#271)
|
|
221
|
-
|
|
222
|
-
## 0.0.30 (12th July, 2024)
|
|
223
|
-
|
|
224
|
-
- Fix cache update on revalidation response with content (rfc9111 section 4.3.3) (#239)
|
|
225
|
-
- Fix request extensions that were not passed into revalidation request for transport-based implementation (but were
|
|
226
|
-
passed for the pool-based impl) (#247).
|
|
227
|
-
- Add `cache_private` property to the controller to support acting as shared cache. (#224)
|
|
228
|
-
- Improve efficiency of scanning cached responses in `FileStorage` by reducing number of syscalls. (#252)
|
|
229
|
-
- Add `remove` support for storages (#241)
|
|
230
|
-
|
|
231
|
-
## 0.0.29 (23th June, 2024)
|
|
232
|
-
|
|
233
|
-
- Documentation hotfix. (#244)
|
|
234
|
-
|
|
235
|
-
## 0.0.28 (23th June, 2024)
|
|
236
|
-
|
|
237
|
-
- Add `revalidated` response extension. (#242)
|
|
238
|
-
|
|
239
|
-
## 0.0.27 (31th May, 2024)
|
|
240
|
-
|
|
241
|
-
- Fix `RedisStorage` when using without ttl. (#231)
|
|
242
|
-
|
|
243
|
-
## 0.0.26 (12th April, 2024)
|
|
244
|
-
|
|
245
|
-
- Expose `AsyncBaseStorage` and `BaseStorage`. (#220)
|
|
246
|
-
- Prevent cache hits from resetting the ttl. (#215)
|
|
247
|
-
|
|
248
|
-
## 0.0.25 (26th March, 2024)
|
|
249
|
-
|
|
250
|
-
- Add `force_cache` property to the controller, allowing RFC9111 rules to be completely disabled. (#204)
|
|
251
|
-
- Add `.gitignore` to cache directory created by `FIleStorage`. (#197)
|
|
252
|
-
- Remove `stale_*` headers from the `CacheControl` class. (#199)
|
|
253
|
-
|
|
254
|
-
## 0.0.24 (14th February, 2024)
|
|
255
|
-
|
|
256
|
-
- Fix `botocore is not installed` exception when using any kind of storage. (#186)
|
|
257
|
-
|
|
258
|
-
## 0.0.23 (14th February, 2024)
|
|
259
|
-
|
|
260
|
-
- Make `S3Storage` to check staleness of all cache files with set interval. (#182)
|
|
261
|
-
- Fix an issue where an empty file in `FileCache` could cause a parsing error. (#181)
|
|
262
|
-
- Support caching for `POST` and other HTTP methods. (#183)
|
|
263
|
-
|
|
264
|
-
## 0.0.22 (31th January, 2024)
|
|
265
|
-
|
|
266
|
-
- Make `FileStorage` to check staleness of all cache files with set interval. (#169)
|
|
267
|
-
- Support AWS S3 storages. (#164)
|
|
268
|
-
- Move `typing_extensions` from requirements.txt to pyproject.toml. (#161)
|
|
269
|
-
|
|
270
|
-
## 0.0.21 (29th December, 2023)
|
|
271
|
-
|
|
272
|
-
- Fix inner transport and connection pool instances closing. (#147)
|
|
273
|
-
- Improved error message when the storage type is incorrect. (#138)
|
|
274
|
-
|
|
275
|
-
## 0.0.20 (12th December, 2023)
|
|
276
|
-
|
|
277
|
-
- Add in-memory storage. (#133)
|
|
278
|
-
- Allow customization of cache key generation. (#130)
|
|
279
|
-
|
|
280
|
-
## 0.0.19 (30th November, 2023)
|
|
281
|
-
|
|
282
|
-
- Add `force_cache` extension to enforce the request to be cached, ignoring the HTTP headers. (#117)
|
|
283
|
-
- Fix issue where sqlite storage cache get deleted immediately. (#119)
|
|
284
|
-
- Support float numbers for storage ttl. (#107)
|
|
285
|
-
|
|
286
|
-
## 0.0.18 (23rd November, 2023)
|
|
287
|
-
|
|
288
|
-
- Fix issue where freshness cannot be calculated to re-send request. (#104)
|
|
289
|
-
- Add `cache_disabled` extension to temporarily disable the cache (#109)
|
|
290
|
-
- Update `datetime.datetime.utcnow()` to `datetime.datetime.now(datetime.timezone.utc)` since `datetime.datetime.utcnow()` has been deprecated. (#111)
|
|
291
|
-
|
|
292
|
-
## 0.0.17 (6th November, 2023)
|
|
293
|
-
|
|
294
|
-
- Fix `Last-Modified` validation.
|
|
295
|
-
|
|
296
|
-
## 0.0.16 (25th October, 2023)
|
|
297
|
-
|
|
298
|
-
- Add `install_cache` function. (#95)
|
|
299
|
-
- Add sqlite support. (#92)
|
|
300
|
-
- Move `ttl` argument to `BaseStorage` class. (#94)
|
|
301
|
-
|
|
302
|
-
## 0.0.14 (23rd October, 2023)
|
|
303
|
-
|
|
304
|
-
- Replace `AsyncResponseStream` with `AsyncCacheStream`. (#86)
|
|
305
|
-
- Add `must-understand` response directive support. (#90)
|
|
306
|
-
|
|
307
|
-
## 0.0.13 (5th October, 2023)
|
|
308
|
-
|
|
309
|
-
- Add support for Python 3.12. (#71)
|
|
310
|
-
- Fix connections releasing from the connection pool. (#83)
|
|
195
|
+
## [0.1.5] - 2025-10-18
|
|
311
196
|
|
|
312
|
-
|
|
197
|
+
### 🚀 Features
|
|
313
198
|
|
|
314
|
-
-
|
|
199
|
+
- *(perf)* Set chunk size to 128KB for httpx to reduce SQLite read/writes
|
|
200
|
+
- Better cache-control parsing
|
|
201
|
+
- Add close method to storages API (#384)
|
|
202
|
+
- *(perf)* Increase requests buffer size to 128KB, disable charset detection
|
|
315
203
|
|
|
316
|
-
|
|
204
|
+
### 🐛 Bug Fixes
|
|
317
205
|
|
|
318
|
-
-
|
|
319
|
-
- Drop httpcore dependency. (#40)
|
|
320
|
-
- Support HTTP methods only if they are defined as cacheable. (#37)
|
|
206
|
+
- *(docs)* Fix some line breaks
|
|
321
207
|
|
|
322
|
-
|
|
208
|
+
### ⚙️ Miscellaneous Tasks
|
|
323
209
|
|
|
324
|
-
-
|
|
325
|
-
|
|
326
|
-
- Use stale responses only if the client is disconnected. (#28)
|
|
210
|
+
- Remove some redundant files from repo
|
|
211
|
+
## [0.1.4] - 2025-10-14
|
|
327
212
|
|
|
328
|
-
|
|
213
|
+
### 🚀 Features
|
|
329
214
|
|
|
330
|
-
-
|
|
215
|
+
- Add support for a sans-IO API (#366)
|
|
216
|
+
- Allow already consumed streams with `CacheTransport` (#377)
|
|
217
|
+
- Add sqlite storage for beta storages
|
|
218
|
+
- Get rid of some locks from sqlite storage
|
|
219
|
+
- Better async implemetation for sqlite storage
|
|
331
220
|
|
|
332
|
-
|
|
221
|
+
### 🐛 Bug Fixes
|
|
333
222
|
|
|
334
|
-
-
|
|
335
|
-
-
|
|
336
|
-
- Fail coverage under 100. (#19)
|
|
223
|
+
- Create an sqlite file in a cache folder
|
|
224
|
+
- Fix beta imports
|
|
337
225
|
|
|
338
|
-
|
|
226
|
+
### ⚙️ Miscellaneous Tasks
|
|
339
227
|
|
|
340
|
-
-
|
|
341
|
-
-
|
|
342
|
-
-
|
|
228
|
+
- Improve CI (#369)
|
|
229
|
+
- *(internal)* Remove src folder (#373)
|
|
230
|
+
- *(internal)* Temporary remove python3.14 from CI
|
|
231
|
+
- *(tests)* Add sqlite tests for new storage
|
|
232
|
+
- *(tests)* Move some tests to beta
|
|
233
|
+
## [0.1.3] - 2025-07-06
|
|
343
234
|
|
|
344
|
-
|
|
235
|
+
### 🚀 Features
|
|
345
236
|
|
|
346
|
-
-
|
|
347
|
-
- Dump original requests with the responses. (#7)
|
|
237
|
+
- Support providing a path prefix to S3 storage (#342)
|
|
348
238
|
|
|
349
|
-
|
|
239
|
+
### 📚 Documentation
|
|
350
240
|
|
|
351
|
-
-
|
|
241
|
+
- Update link to httpx transports page (#337)
|
|
242
|
+
## [0.1.2] - 2025-04-04
|
|
352
243
|
|
|
353
|
-
|
|
244
|
+
### 🐛 Bug Fixes
|
|
354
245
|
|
|
355
|
-
-
|
|
246
|
+
- Requirements.txt to reduce vulnerabilities (#263)
|
|
247
|
+
## [0.0.30] - 2024-07-12
|
|
356
248
|
|
|
357
|
-
|
|
249
|
+
### 🐛 Bug Fixes
|
|
358
250
|
|
|
359
|
-
-
|
|
360
|
-
-
|
|
251
|
+
- Requirements.txt to reduce vulnerabilities (#245)
|
|
252
|
+
- Requirements.txt to reduce vulnerabilities (#255)
|
|
253
|
+
## [0.0.27] - 2024-05-31
|
|
361
254
|
|
|
362
|
-
|
|
255
|
+
### 🐛 Bug Fixes
|
|
363
256
|
|
|
364
|
-
-
|
|
365
|
-
|
|
366
|
-
- Add black as a new linter.
|
|
367
|
-
- Add an expire time for cached responses.
|
|
257
|
+
- *(redis)* Do not update metadata with negative ttl (#231)
|
|
258
|
+
## [0.0.1] - 2023-07-22
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<img src="https://img.shields.io/pypi/l/hishel" alt="license">
|
|
23
23
|
</a>
|
|
24
24
|
|
|
25
|
-
<a href="https://
|
|
26
|
-
<img src="https://img.shields.io/
|
|
25
|
+
<a href="https://coveralls.io/github/karpetrosyan/hishel">
|
|
26
|
+
<img src="https://img.shields.io/coverallsCoverage/github/karpetrosyan/hishel" alt="license">
|
|
27
27
|
</a>
|
|
28
28
|
|
|
29
29
|
<a href="https://github.com/karpetrosyan/hishel">
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
</a>
|
|
32
32
|
</p>
|
|
33
33
|
|
|
34
|
+
<p align="center">
|
|
35
|
+
<a href="https://buymeacoffee.com/karpetrosyan" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
34
38
|
-----
|
|
35
39
|
|
|
36
40
|
**Hishel (հիշել, remember)** is a library that implements HTTP Caching for [HTTPX](https://github.com/encode/httpx) and [HTTP Core](https://github.com/encode/httpcore) libraries in accordance with [**RFC 9111**](https://www.rfc-editor.org/rfc/rfc9111.html), the most recent caching specification.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
3
|
+
from ._async import *
|
|
4
|
+
from ._controller import *
|
|
5
|
+
from ._exceptions import *
|
|
6
|
+
from ._headers import *
|
|
7
|
+
from ._serializers import *
|
|
8
|
+
from ._sync import *
|
|
9
|
+
from ._lfu_cache import *
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
# Old API
|
|
13
|
+
"AsyncCacheClient",
|
|
14
|
+
"MockAsyncConnectionPool",
|
|
15
|
+
"MockAsyncTransport",
|
|
16
|
+
"AsyncCacheConnectionPool",
|
|
17
|
+
"AsyncBaseStorage",
|
|
18
|
+
"AsyncFileStorage",
|
|
19
|
+
"AsyncInMemoryStorage",
|
|
20
|
+
"AsyncRedisStorage",
|
|
21
|
+
"AsyncS3Storage",
|
|
22
|
+
"AsyncSQLiteStorage",
|
|
23
|
+
"AsyncCacheTransport",
|
|
24
|
+
"HEURISTICALLY_CACHEABLE_STATUS_CODES",
|
|
25
|
+
"Controller",
|
|
26
|
+
"CacheControlError",
|
|
27
|
+
"ParseError",
|
|
28
|
+
"ValidationError",
|
|
29
|
+
"CacheControl",
|
|
30
|
+
"Vary",
|
|
31
|
+
"BaseSerializer",
|
|
32
|
+
"JSONSerializer",
|
|
33
|
+
"Metadata",
|
|
34
|
+
"PickleSerializer",
|
|
35
|
+
"YAMLSerializer",
|
|
36
|
+
"clone_model",
|
|
37
|
+
"CacheClient",
|
|
38
|
+
"MockConnectionPool",
|
|
39
|
+
"MockTransport",
|
|
40
|
+
"CacheConnectionPool",
|
|
41
|
+
"BaseStorage",
|
|
42
|
+
"FileStorage",
|
|
43
|
+
"InMemoryStorage",
|
|
44
|
+
"RedisStorage",
|
|
45
|
+
"S3Storage",
|
|
46
|
+
"SQLiteStorage",
|
|
47
|
+
"CacheTransport",
|
|
48
|
+
"LFUCache",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def install_cache() -> None: # pragma: no cover
|
|
52
|
+
httpx.AsyncClient = AsyncCacheClient # type: ignore
|
|
53
|
+
httpx.Client = CacheClient # type: ignore
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
__version__ = "0.1.5"
|
|
57
|
+
|
|
@@ -4,7 +4,6 @@ import datetime
|
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
6
|
import time
|
|
7
|
-
import typing as t
|
|
8
7
|
import typing as tp
|
|
9
8
|
import warnings
|
|
10
9
|
from copy import deepcopy
|
|
@@ -24,13 +23,11 @@ except ImportError: # pragma: no cover
|
|
|
24
23
|
|
|
25
24
|
from httpcore import Request, Response
|
|
26
25
|
|
|
27
|
-
if
|
|
26
|
+
if tp.TYPE_CHECKING: # pragma: no cover
|
|
28
27
|
from typing_extensions import TypeAlias
|
|
29
28
|
|
|
30
|
-
from hishel._serializers import BaseSerializer, clone_model
|
|
31
|
-
|
|
32
29
|
from .._files import AsyncFileManager
|
|
33
|
-
from .._serializers import JSONSerializer, Metadata
|
|
30
|
+
from .._serializers import BaseSerializer, JSONSerializer, Metadata, clone_model
|
|
34
31
|
from .._synchronization import AsyncLock
|
|
35
32
|
from .._utils import float_seconds_to_int_milliseconds
|
|
36
33
|
|
|
@@ -39,10 +36,10 @@ logger = logging.getLogger("hishel.storages")
|
|
|
39
36
|
__all__ = (
|
|
40
37
|
"AsyncBaseStorage",
|
|
41
38
|
"AsyncFileStorage",
|
|
42
|
-
"AsyncRedisStorage",
|
|
43
|
-
"AsyncSQLiteStorage",
|
|
44
39
|
"AsyncInMemoryStorage",
|
|
40
|
+
"AsyncRedisStorage",
|
|
45
41
|
"AsyncS3Storage",
|
|
42
|
+
"AsyncSQLiteStorage",
|
|
46
43
|
)
|
|
47
44
|
|
|
48
45
|
StoredResponse: TypeAlias = tp.Tuple[Response, Request, Metadata]
|
|
@@ -106,8 +103,7 @@ class AsyncFileStorage(AsyncBaseStorage):
|
|
|
106
103
|
self._base_path = Path(base_path) if base_path is not None else Path(".cache/hishel")
|
|
107
104
|
self._gitignore_file = self._base_path / ".gitignore"
|
|
108
105
|
|
|
109
|
-
|
|
110
|
-
self._base_path.mkdir(parents=True)
|
|
106
|
+
self._base_path.mkdir(parents=True, exist_ok=True)
|
|
111
107
|
|
|
112
108
|
if not self._gitignore_file.is_file():
|
|
113
109
|
with open(self._gitignore_file, "w", encoding="utf-8") as f:
|
|
@@ -153,7 +149,7 @@ class AsyncFileStorage(AsyncBaseStorage):
|
|
|
153
149
|
"""
|
|
154
150
|
|
|
155
151
|
if isinstance(key, Response): # pragma: no cover
|
|
156
|
-
key =
|
|
152
|
+
key = tp.cast(str, key.extensions["cache_metadata"]["cache_key"])
|
|
157
153
|
|
|
158
154
|
response_path = self._base_path / key
|
|
159
155
|
|
|
@@ -322,7 +318,7 @@ class AsyncSQLiteStorage(AsyncBaseStorage):
|
|
|
322
318
|
assert self._connection
|
|
323
319
|
|
|
324
320
|
if isinstance(key, Response): # pragma: no cover
|
|
325
|
-
key =
|
|
321
|
+
key = tp.cast(str, key.extensions["cache_metadata"]["cache_key"])
|
|
326
322
|
|
|
327
323
|
async with self._lock:
|
|
328
324
|
await self._connection.execute("DELETE FROM cache WHERE key = ?", [key])
|
|
@@ -459,7 +455,7 @@ class AsyncRedisStorage(AsyncBaseStorage):
|
|
|
459
455
|
"""
|
|
460
456
|
|
|
461
457
|
if isinstance(key, Response): # pragma: no cover
|
|
462
|
-
key =
|
|
458
|
+
key = tp.cast(str, key.extensions["cache_metadata"]["cache_key"])
|
|
463
459
|
|
|
464
460
|
await self._client.delete(key)
|
|
465
461
|
|
|
@@ -572,7 +568,7 @@ class AsyncInMemoryStorage(AsyncBaseStorage):
|
|
|
572
568
|
"""
|
|
573
569
|
|
|
574
570
|
if isinstance(key, Response): # pragma: no cover
|
|
575
|
-
key =
|
|
571
|
+
key = tp.cast(str, key.extensions["cache_metadata"]["cache_key"])
|
|
576
572
|
|
|
577
573
|
async with self._lock:
|
|
578
574
|
self._cache.remove_key(key)
|
|
@@ -720,7 +716,7 @@ class AsyncS3Storage(AsyncBaseStorage): # pragma: no cover
|
|
|
720
716
|
"""
|
|
721
717
|
|
|
722
718
|
if isinstance(key, Response): # pragma: no cover
|
|
723
|
-
key =
|
|
719
|
+
key = tp.cast(str, key.extensions["cache_metadata"]["cache_key"])
|
|
724
720
|
|
|
725
721
|
async with self._lock:
|
|
726
722
|
await self._s3_manager.remove_entry(key)
|
|
@@ -8,11 +8,10 @@ import httpx
|
|
|
8
8
|
from httpx import AsyncByteStream, Request, Response
|
|
9
9
|
from httpx._exceptions import ConnectError
|
|
10
10
|
|
|
11
|
-
from hishel._utils import extract_header_values_decoded, normalized_url
|
|
12
|
-
|
|
13
11
|
from .._controller import Controller, allowed_stale
|
|
14
12
|
from .._headers import parse_cache_control
|
|
15
13
|
from .._serializers import JSONSerializer, Metadata
|
|
14
|
+
from .._utils import extract_header_values_decoded, normalized_url
|
|
16
15
|
from ._storages import AsyncBaseStorage, AsyncFileStorage
|
|
17
16
|
|
|
18
17
|
if tp.TYPE_CHECKING: # pragma: no cover
|
|
@@ -211,11 +210,17 @@ class AsyncCacheTransport(httpx.AsyncBaseTransport):
|
|
|
211
210
|
)
|
|
212
211
|
|
|
213
212
|
regular_response = await self._transport.handle_async_request(request)
|
|
214
|
-
|
|
213
|
+
try:
|
|
214
|
+
# Prefer already-read content, if available
|
|
215
|
+
stream = fake_stream(regular_response.content)
|
|
216
|
+
except httpx.ResponseNotRead:
|
|
217
|
+
# Fall back to stream if not yet read
|
|
218
|
+
assert isinstance(regular_response.stream, tp.AsyncIterable)
|
|
219
|
+
stream = regular_response.stream
|
|
215
220
|
httpcore_regular_response = httpcore.Response(
|
|
216
221
|
status=regular_response.status_code,
|
|
217
222
|
headers=regular_response.headers.raw,
|
|
218
|
-
content=AsyncCacheStream(
|
|
223
|
+
content=AsyncCacheStream(stream),
|
|
219
224
|
extensions=regular_response.extensions,
|
|
220
225
|
)
|
|
221
226
|
await httpcore_regular_response.aread()
|
|
@@ -3,8 +3,7 @@ import typing as tp
|
|
|
3
3
|
|
|
4
4
|
from httpcore import Request, Response
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
|
|
6
|
+
from ._headers import Vary, parse_cache_control
|
|
8
7
|
from ._utils import (
|
|
9
8
|
BaseClock,
|
|
10
9
|
Clock,
|
|
@@ -21,7 +20,7 @@ logger = logging.getLogger("hishel.controller")
|
|
|
21
20
|
HEURISTICALLY_CACHEABLE_STATUS_CODES = (200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501)
|
|
22
21
|
HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"]
|
|
23
22
|
|
|
24
|
-
__all__ = ("
|
|
23
|
+
__all__ = ("HEURISTICALLY_CACHEABLE_STATUS_CODES", "Controller")
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
def get_updated_headers(
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from typing import Any, Iterator
|
|
3
|
+
|
|
4
|
+
class Database: ...
|
|
5
|
+
|
|
6
|
+
class Transaction:
|
|
7
|
+
def get(self, key: bytes, *, db: Database | None = None) -> bytes | None:
|
|
8
|
+
"""
|
|
9
|
+
Get the value associated with the given key.
|
|
10
|
+
"""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def put(self, key: bytes, value: bytes, *, db: Database | None = None, dupdata: bool = False) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Put a key-value pair into the database.
|
|
16
|
+
"""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def delete(self, key: bytes, *, db: Database | None = None) -> bool:
|
|
20
|
+
"""
|
|
21
|
+
Delete the key from the database.
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def cursor(self, db: Database) -> Any:
|
|
26
|
+
"""
|
|
27
|
+
Create a cursor for iterating over key-value pairs in the database.
|
|
28
|
+
"""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
class Environment:
|
|
32
|
+
@contextmanager
|
|
33
|
+
def begin(self, *, db: Database | None = None, write: bool = False) -> Iterator[Transaction]:
|
|
34
|
+
"""
|
|
35
|
+
Begin a transaction in the environment.
|
|
36
|
+
"""
|
|
37
|
+
raise NotImplementedError("It's only for type hinting purposes")
|
|
38
|
+
|
|
39
|
+
def open_db(self, key: bytes, dupsort: bool = False) -> Database:
|
|
40
|
+
"""
|
|
41
|
+
Open a database within the environment.
|
|
42
|
+
"""
|
|
43
|
+
raise NotImplementedError("It's only for type hinting purposes")
|
|
44
|
+
|
|
45
|
+
def open(
|
|
46
|
+
path: str,
|
|
47
|
+
*,
|
|
48
|
+
max_dbs: int = 0,
|
|
49
|
+
) -> Environment:
|
|
50
|
+
"""
|
|
51
|
+
Open an LMDB environment at the specified path.
|
|
52
|
+
"""
|
|
53
|
+
raise NotImplementedError("It's only for type hinting purposes")
|
|
@@ -6,7 +6,7 @@ from datetime import datetime
|
|
|
6
6
|
|
|
7
7
|
from httpcore import Request, Response
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ._utils import normalized_url
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
12
|
import yaml
|
|
@@ -17,7 +17,7 @@ HEADERS_ENCODING = "iso-8859-1"
|
|
|
17
17
|
KNOWN_RESPONSE_EXTENSIONS = ("http_version", "reason_phrase")
|
|
18
18
|
KNOWN_REQUEST_EXTENSIONS = ("timeout", "sni_hostname")
|
|
19
19
|
|
|
20
|
-
__all__ = ("
|
|
20
|
+
__all__ = ("BaseSerializer", "JSONSerializer", "Metadata", "PickleSerializer", "YAMLSerializer", "clone_model")
|
|
21
21
|
|
|
22
22
|
T = tp.TypeVar("T", Request, Response)
|
|
23
23
|
|