hishel 1.1.3__py3-none-any.whl → 1.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hishel/_async_httpx.py +14 -2
- hishel/_core/_storages/_async_sqlite.py +18 -10
- hishel/_core/_storages/_sync_sqlite.py +18 -10
- hishel/_sync_httpx.py +14 -2
- hishel/requests.py +7 -2
- {hishel-1.1.3.dist-info → hishel-1.1.5.dist-info}/METADATA +23 -2
- {hishel-1.1.3.dist-info → hishel-1.1.5.dist-info}/RECORD +9 -9
- {hishel-1.1.3.dist-info → hishel-1.1.5.dist-info}/WHEEL +0 -0
- {hishel-1.1.3.dist-info → hishel-1.1.5.dist-info}/licenses/LICENSE +0 -0
hishel/_async_httpx.py
CHANGED
|
@@ -118,12 +118,24 @@ def _httpx_to_internal(
|
|
|
118
118
|
metadata=headers_metadata,
|
|
119
119
|
)
|
|
120
120
|
elif isinstance(value, httpx.Response):
|
|
121
|
-
if value.is_stream_consumed and "content-encoding" in value.headers:
|
|
122
|
-
raise RuntimeError("Can't get the raw stream of a response with `Content-Encoding` header.")
|
|
123
121
|
stream = (
|
|
124
122
|
make_async_iterator([value.content]) if value.is_stream_consumed else value.aiter_raw(chunk_size=CHUNK_SIZE)
|
|
125
123
|
)
|
|
126
124
|
|
|
125
|
+
if value.is_stream_consumed and "content-encoding" in value.headers:
|
|
126
|
+
# If the stream was consumed and we don't know about
|
|
127
|
+
# the original data and its size, fix the Content-Length
|
|
128
|
+
# header and remove Content-Encoding so we can recreate it later properly.
|
|
129
|
+
headers = Headers(
|
|
130
|
+
{
|
|
131
|
+
**filter_mapping(
|
|
132
|
+
headers,
|
|
133
|
+
["content-encoding"],
|
|
134
|
+
),
|
|
135
|
+
"content-length": str(len(value.content)),
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
|
|
127
139
|
return Response(
|
|
128
140
|
status_code=value.status_code,
|
|
129
141
|
headers=headers,
|
|
@@ -161,8 +161,19 @@ try:
|
|
|
161
161
|
for row in await cursor.fetchall():
|
|
162
162
|
pair_data = unpack(row[1], kind="pair")
|
|
163
163
|
|
|
164
|
+
if pair_data is None:
|
|
165
|
+
continue
|
|
166
|
+
|
|
164
167
|
# Skip entries without a response (incomplete)
|
|
165
|
-
if not
|
|
168
|
+
if not await self._is_stream_complete(pair_data.id, cursor=cursor):
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
# Skip expired entries
|
|
172
|
+
if await self._is_pair_expired(pair_data, cursor=cursor):
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
# Skip soft-deleted entries
|
|
176
|
+
if self.is_soft_deleted(pair_data):
|
|
166
177
|
continue
|
|
167
178
|
|
|
168
179
|
final_pairs.append(pair_data)
|
|
@@ -237,6 +248,11 @@ try:
|
|
|
237
248
|
await self._soft_delete_pair(pair, cursor)
|
|
238
249
|
await connection.commit()
|
|
239
250
|
|
|
251
|
+
async def close(self) -> None:
|
|
252
|
+
if self.connection is not None:
|
|
253
|
+
await self.connection.close()
|
|
254
|
+
self.connection = None
|
|
255
|
+
|
|
240
256
|
async def _is_stream_complete(self, pair_id: uuid.UUID, cursor: anysqlite.Cursor) -> bool:
|
|
241
257
|
# Check if there's a completion marker (chunk_number = -1) for response stream
|
|
242
258
|
await cursor.execute(
|
|
@@ -325,15 +341,7 @@ try:
|
|
|
325
341
|
|
|
326
342
|
async def _is_corrupted(self, pair: Entry, cursor: anysqlite.Cursor) -> bool:
|
|
327
343
|
# if entry was created more than 1 hour ago and still has no response (incomplete)
|
|
328
|
-
if pair.meta.created_at + 3600 < time.time() and pair.
|
|
329
|
-
return True
|
|
330
|
-
|
|
331
|
-
# Check if response stream is complete for Entry with response
|
|
332
|
-
if (
|
|
333
|
-
isinstance(pair, Entry)
|
|
334
|
-
and pair.response is not None
|
|
335
|
-
and not await self._is_stream_complete(pair.id, cursor)
|
|
336
|
-
):
|
|
344
|
+
if pair.meta.created_at + 3600 < time.time() and not self._is_stream_complete(pair.id, cursor):
|
|
337
345
|
return True
|
|
338
346
|
return False
|
|
339
347
|
|
|
@@ -161,8 +161,19 @@ try:
|
|
|
161
161
|
for row in cursor.fetchall():
|
|
162
162
|
pair_data = unpack(row[1], kind="pair")
|
|
163
163
|
|
|
164
|
+
if pair_data is None:
|
|
165
|
+
continue
|
|
166
|
+
|
|
164
167
|
# Skip entries without a response (incomplete)
|
|
165
|
-
if not
|
|
168
|
+
if not self._is_stream_complete(pair_data.id, cursor=cursor):
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
# Skip expired entries
|
|
172
|
+
if self._is_pair_expired(pair_data, cursor=cursor):
|
|
173
|
+
continue
|
|
174
|
+
|
|
175
|
+
# Skip soft-deleted entries
|
|
176
|
+
if self.is_soft_deleted(pair_data):
|
|
166
177
|
continue
|
|
167
178
|
|
|
168
179
|
final_pairs.append(pair_data)
|
|
@@ -237,6 +248,11 @@ try:
|
|
|
237
248
|
self._soft_delete_pair(pair, cursor)
|
|
238
249
|
connection.commit()
|
|
239
250
|
|
|
251
|
+
def close(self) -> None:
|
|
252
|
+
if self.connection is not None:
|
|
253
|
+
self.connection.close()
|
|
254
|
+
self.connection = None
|
|
255
|
+
|
|
240
256
|
def _is_stream_complete(self, pair_id: uuid.UUID, cursor: sqlite3.Cursor) -> bool:
|
|
241
257
|
# Check if there's a completion marker (chunk_number = -1) for response stream
|
|
242
258
|
cursor.execute(
|
|
@@ -325,15 +341,7 @@ try:
|
|
|
325
341
|
|
|
326
342
|
def _is_corrupted(self, pair: Entry, cursor: sqlite3.Cursor) -> bool:
|
|
327
343
|
# if entry was created more than 1 hour ago and still has no response (incomplete)
|
|
328
|
-
if pair.meta.created_at + 3600 < time.time() and pair.
|
|
329
|
-
return True
|
|
330
|
-
|
|
331
|
-
# Check if response stream is complete for Entry with response
|
|
332
|
-
if (
|
|
333
|
-
isinstance(pair, Entry)
|
|
334
|
-
and pair.response is not None
|
|
335
|
-
and not self._is_stream_complete(pair.id, cursor)
|
|
336
|
-
):
|
|
344
|
+
if pair.meta.created_at + 3600 < time.time() and not self._is_stream_complete(pair.id, cursor):
|
|
337
345
|
return True
|
|
338
346
|
return False
|
|
339
347
|
|
hishel/_sync_httpx.py
CHANGED
|
@@ -118,12 +118,24 @@ def _httpx_to_internal(
|
|
|
118
118
|
metadata=headers_metadata,
|
|
119
119
|
)
|
|
120
120
|
elif isinstance(value, httpx.Response):
|
|
121
|
-
if value.is_stream_consumed and "content-encoding" in value.headers:
|
|
122
|
-
raise RuntimeError("Can't get the raw stream of a response with `Content-Encoding` header.")
|
|
123
121
|
stream = (
|
|
124
122
|
make_sync_iterator([value.content]) if value.is_stream_consumed else value.iter_raw(chunk_size=CHUNK_SIZE)
|
|
125
123
|
)
|
|
126
124
|
|
|
125
|
+
if value.is_stream_consumed and "content-encoding" in value.headers:
|
|
126
|
+
# If the stream was consumed and we don't know about
|
|
127
|
+
# the original data and its size, fix the Content-Length
|
|
128
|
+
# header and remove Content-Encoding so we can recreate it later properly.
|
|
129
|
+
headers = Headers(
|
|
130
|
+
{
|
|
131
|
+
**filter_mapping(
|
|
132
|
+
headers,
|
|
133
|
+
["content-encoding"],
|
|
134
|
+
),
|
|
135
|
+
"content-length": str(len(value.content)),
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
|
|
127
139
|
return Response(
|
|
128
140
|
status_code=value.status_code,
|
|
129
141
|
headers=headers,
|
hishel/requests.py
CHANGED
|
@@ -10,7 +10,7 @@ from hishel._core._storages._sync_base import SyncBaseStorage
|
|
|
10
10
|
from hishel._core.models import extract_metadata_from_headers
|
|
11
11
|
from hishel._policies import CachePolicy
|
|
12
12
|
from hishel._sync_cache import SyncCacheProxy
|
|
13
|
-
from hishel._utils import snake_to_header
|
|
13
|
+
from hishel._utils import filter_mapping, snake_to_header
|
|
14
14
|
|
|
15
15
|
try:
|
|
16
16
|
import requests
|
|
@@ -94,12 +94,17 @@ def _requests_to_internal(
|
|
|
94
94
|
elif isinstance(model, requests.models.Response):
|
|
95
95
|
try:
|
|
96
96
|
stream = model.raw.stream(amt=CHUNK_SIZE, decode_content=None)
|
|
97
|
+
headers = Headers(filter_mapping(model.headers, ["transfer-encoding"]))
|
|
97
98
|
except requests.exceptions.StreamConsumedError:
|
|
98
99
|
stream = iter([model.content])
|
|
100
|
+
# If the stream was consumed and we don't know about the original
|
|
101
|
+
# data and its size, fix the Content-Length header and remove
|
|
102
|
+
# Content-Encoding so we can recreate it later properly.
|
|
103
|
+
headers = Headers(filter_mapping(model.headers, ["content-encoding", "transfer-encoding"]))
|
|
99
104
|
|
|
100
105
|
return Response(
|
|
101
106
|
status_code=model.status_code,
|
|
102
|
-
headers=
|
|
107
|
+
headers=headers,
|
|
103
108
|
stream=stream,
|
|
104
109
|
)
|
|
105
110
|
else:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hishel
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.5
|
|
4
4
|
Summary: Elegant HTTP Caching for Python
|
|
5
5
|
Project-URL: Homepage, https://hishel.com
|
|
6
6
|
Project-URL: Source, https://github.com/karpetrosyan/hishel
|
|
@@ -406,6 +406,27 @@ Hishel is inspired by and builds upon the excellent work in the Python HTTP ecos
|
|
|
406
406
|
<strong>Made with ❤️ by <a href="https://github.com/karpetrosyan">Kar Petrosyan</a></strong>
|
|
407
407
|
</p>
|
|
408
408
|
|
|
409
|
+
## What's Changed in 1.1.5
|
|
410
|
+
### 🐛 Bug Fixes
|
|
411
|
+
|
|
412
|
+
* filter out soft-deleted, expired and incomplete entries in `get_entries` by @karpetrosyan
|
|
413
|
+
|
|
414
|
+
### Contributors
|
|
415
|
+
* @karpetrosyan
|
|
416
|
+
|
|
417
|
+
**Full Changelog**: https://github.com/karpetrosyan/hishel/compare/1.1.4...1.1.5
|
|
418
|
+
|
|
419
|
+
## What's Changed in 1.1.4
|
|
420
|
+
### 🐛 Bug Fixes
|
|
421
|
+
|
|
422
|
+
* don't raise an error on consumed streams that were read into memory by @karpetrosyan
|
|
423
|
+
* close sqlite connections properly by @karpetrosyan
|
|
424
|
+
|
|
425
|
+
### Contributors
|
|
426
|
+
* @karpetrosyan
|
|
427
|
+
|
|
428
|
+
**Full Changelog**: https://github.com/karpetrosyan/hishel/compare/1.1.3...1.1.4
|
|
429
|
+
|
|
409
430
|
## What's Changed in 1.1.3
|
|
410
431
|
### ⚙️ Miscellaneous Tasks
|
|
411
432
|
|
|
@@ -416,9 +437,9 @@ Hishel is inspired by and builds upon the excellent work in the Python HTTP ecos
|
|
|
416
437
|
* fix: set `after_revalidation=True` for `NeedsToBeUpdated` -> `FromCache` transition by @jlopex in [#402](https://github.com/karpetrosyan/hishel/pull/402)
|
|
417
438
|
|
|
418
439
|
### Contributors
|
|
440
|
+
* @karpetrosyan
|
|
419
441
|
* @martinblech
|
|
420
442
|
* @jlopex
|
|
421
|
-
* @karpetrosyan
|
|
422
443
|
|
|
423
444
|
**Full Changelog**: https://github.com/karpetrosyan/hishel/compare/1.1.2...1.1.3
|
|
424
445
|
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
hishel/__init__.py,sha256=1EdAEXWx41gmxUzG1Fchd_B4gQDtqlxlqQw0WkCBaUE,1826
|
|
2
2
|
hishel/_async_cache.py,sha256=4wm6YBL9ClNOg4WbEkALTJVCIXuzQU80MVem2C3hHrQ,8785
|
|
3
|
-
hishel/_async_httpx.py,sha256=
|
|
3
|
+
hishel/_async_httpx.py,sha256=89i92f2SlvgWrav_TDNU1iUzMxdR607apauxXA3pE3U,8127
|
|
4
4
|
hishel/_policies.py,sha256=1ae_rmDF7oaG91-lQyOGVaTrRX8uI2GImmu5gN6WJa4,1135
|
|
5
5
|
hishel/_sync_cache.py,sha256=k0AN0M--yR4Jc6SiAreaxPUFiwEt5Dx7wi9jqW9sy50,8510
|
|
6
|
-
hishel/_sync_httpx.py,sha256=
|
|
6
|
+
hishel/_sync_httpx.py,sha256=z1pwVUQfRf72Q48PXXZ4FKwXGevll0X5iHcVRANiP38,7952
|
|
7
7
|
hishel/_utils.py,sha256=kR7RnhFqLzFRmB-YNnZteQVP0iDPUouCscA0_FHHFls,3837
|
|
8
8
|
hishel/asgi.py,sha256=ocXzqrrYGazeJxlKFcz1waoKvKGOqJ7YBEAmly4Towk,14998
|
|
9
9
|
hishel/fastapi.py,sha256=CVWCyXTxBPwG_XALo-Oldekv4lqMgH2-W-PPZ9rZjXg,10826
|
|
10
10
|
hishel/httpx.py,sha256=99a8X9COPiPHSgGW61O2uMWMZB7dY93Ty9DTCJ9C18Q,467
|
|
11
11
|
hishel/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
hishel/requests.py,sha256=
|
|
12
|
+
hishel/requests.py,sha256=F3BntFGeesm19NmWFgGoBg-rfkcIs9OTpXDass73t6w,6819
|
|
13
13
|
hishel/_core/_headers.py,sha256=hGaT6o1F-gs1pm5RpdGb0IMQL3uJYDH1xpwJLy28Cys,17514
|
|
14
14
|
hishel/_core/_spec.py,sha256=5VLwyT-eSdbez87A6xJG8T_Z3ySVcEEQp8WyTY_mhCo,102988
|
|
15
15
|
hishel/_core/models.py,sha256=EabP2qnjYVzhPWhQer3QFmdDE6TDbqEBEqPHzv25VnA,7978
|
|
16
16
|
hishel/_core/_storages/_async_base.py,sha256=iZ6Mb30P0ho5h4UU5bgOrcsSMZ1427j9tht-tupZs68,2106
|
|
17
|
-
hishel/_core/_storages/_async_sqlite.py,sha256=
|
|
17
|
+
hishel/_core/_storages/_async_sqlite.py,sha256=L1772hba8Onpu7zyEVx74ouFEgQFILuo4xY73BHg8SI,15911
|
|
18
18
|
hishel/_core/_storages/_packing.py,sha256=mC8LMFQ5uPfFOgingKm2WKFO_DwcZ1OjTgI6xc0hfJI,3708
|
|
19
19
|
hishel/_core/_storages/_sync_base.py,sha256=qfOvcFY5qvrzSh4ztV2Trlxft-BF7An5SFsLlEb8EeE,2075
|
|
20
|
-
hishel/_core/_storages/_sync_sqlite.py,sha256=
|
|
21
|
-
hishel-1.1.
|
|
22
|
-
hishel-1.1.
|
|
23
|
-
hishel-1.1.
|
|
24
|
-
hishel-1.1.
|
|
20
|
+
hishel/_core/_storages/_sync_sqlite.py,sha256=_d5d4ApZ-CTFY_frs4iehBbn0buQ0zcdRL5RF40MPo4,15386
|
|
21
|
+
hishel-1.1.5.dist-info/METADATA,sha256=dWg7HdttEhW6yjA1Em9ye-wy9bmOa_uXMgyoB_MZngc,20444
|
|
22
|
+
hishel-1.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
+
hishel-1.1.5.dist-info/licenses/LICENSE,sha256=1qQj7pE0V2O9OIedvyOgLGLvZLaPd3nFEup3IBEOZjQ,1493
|
|
24
|
+
hishel-1.1.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|