hishel 1.1.5__tar.gz → 1.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {hishel-1.1.5 → hishel-1.1.6}/CHANGELOG.md +13 -0
  2. {hishel-1.1.5 → hishel-1.1.6}/PKG-INFO +14 -1
  3. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_spec.py +38 -1
  4. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_storages/_async_sqlite.py +2 -2
  5. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_storages/_sync_sqlite.py +2 -2
  6. {hishel-1.1.5 → hishel-1.1.6}/pyproject.toml +1 -1
  7. {hishel-1.1.5 → hishel-1.1.6}/.gitignore +0 -0
  8. {hishel-1.1.5 → hishel-1.1.6}/LICENSE +0 -0
  9. {hishel-1.1.5 → hishel-1.1.6}/README.md +0 -0
  10. {hishel-1.1.5 → hishel-1.1.6}/hishel/__init__.py +0 -0
  11. {hishel-1.1.5 → hishel-1.1.6}/hishel/_async_cache.py +0 -0
  12. {hishel-1.1.5 → hishel-1.1.6}/hishel/_async_httpx.py +0 -0
  13. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_headers.py +0 -0
  14. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_storages/_async_base.py +0 -0
  15. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_storages/_packing.py +0 -0
  16. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/_storages/_sync_base.py +0 -0
  17. {hishel-1.1.5 → hishel-1.1.6}/hishel/_core/models.py +0 -0
  18. {hishel-1.1.5 → hishel-1.1.6}/hishel/_policies.py +0 -0
  19. {hishel-1.1.5 → hishel-1.1.6}/hishel/_sync_cache.py +0 -0
  20. {hishel-1.1.5 → hishel-1.1.6}/hishel/_sync_httpx.py +0 -0
  21. {hishel-1.1.5 → hishel-1.1.6}/hishel/_utils.py +0 -0
  22. {hishel-1.1.5 → hishel-1.1.6}/hishel/asgi.py +0 -0
  23. {hishel-1.1.5 → hishel-1.1.6}/hishel/fastapi.py +0 -0
  24. {hishel-1.1.5 → hishel-1.1.6}/hishel/httpx.py +0 -0
  25. {hishel-1.1.5 → hishel-1.1.6}/hishel/py.typed +0 -0
  26. {hishel-1.1.5 → hishel-1.1.6}/hishel/requests.py +0 -0
@@ -1,3 +1,16 @@
1
+ ## What's Changed in 1.1.6
2
+ ### 📚 Documentation
3
+
4
+ * remove some stale httpx configs by @karpetrosyan
5
+ ### 🚀 Features
6
+
7
+ * Add support for request no-cache directive by @karpetrosyan in [#416](https://github.com/karpetrosyan/hishel/pull/416)
8
+
9
+ ### Contributors
10
+ * @karpetrosyan
11
+
12
+ **Full Changelog**: https://github.com/karpetrosyan/hishel/compare/1.1.5...1.1.6
13
+
1
14
  ## What's Changed in 1.1.5
2
15
  ### 🐛 Bug Fixes
3
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hishel
3
- Version: 1.1.5
3
+ Version: 1.1.6
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,19 @@ 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.6
410
+ ### 📚 Documentation
411
+
412
+ * remove some stale httpx configs by @karpetrosyan
413
+ ### 🚀 Features
414
+
415
+ * Add support for request no-cache directive by @karpetrosyan in [#416](https://github.com/karpetrosyan/hishel/pull/416)
416
+
417
+ ### Contributors
418
+ * @karpetrosyan
419
+
420
+ **Full Changelog**: https://github.com/karpetrosyan/hishel/compare/1.1.5...1.1.6
421
+
409
422
  ## What's Changed in 1.1.5
410
423
  ### 🐛 Bug Fixes
411
424
 
@@ -1207,6 +1207,7 @@ class IdleClient(State):
1207
1207
  - Unsafe methods (POST, PUT, DELETE, etc.) are written through to origin
1208
1208
  - Multiple matching responses are sorted by Date header (most recent first)
1209
1209
  - Age header is updated when serving from cache
1210
+ - Request no-cache directive forces revalidation of cached responses
1210
1211
 
1211
1212
  Examples:
1212
1213
  --------
@@ -1229,6 +1230,18 @@ class IdleClient(State):
1229
1230
  >>> next_state = idle.next(get_request, [cached_pair])
1230
1231
  >>> isinstance(next_state, NeedRevalidation)
1231
1232
  True
1233
+
1234
+ >>> # Need revalidation - request no-cache forces validation of fresh response
1235
+ >>> idle = IdleClient(options=default_options)
1236
+ >>> no_cache_request = Request(
1237
+ ... method="GET",
1238
+ ... url="https://example.com",
1239
+ ... headers=Headers({"cache-control": "no-cache"})
1240
+ ... )
1241
+ >>> cached_pair = CompletePair(no_cache_request, fresh_response)
1242
+ >>> next_state = idle.next(no_cache_request, [cached_pair])
1243
+ >>> isinstance(next_state, NeedRevalidation)
1244
+ True
1232
1245
  """
1233
1246
 
1234
1247
  # ============================================================================
@@ -1388,7 +1401,31 @@ class IdleClient(State):
1388
1401
  ready_to_use, need_revalidation = partition(filtered_pairs, fresh_or_allowed_stale)
1389
1402
 
1390
1403
  # ============================================================================
1391
- # STEP 7: Determine Next State Based on Available Responses
1404
+ # STEP 7: Handle Request no-cache Directive
1405
+ # ============================================================================
1406
+ # RFC 9111 Section 5.2.1.4: no-cache Request Directive
1407
+ # https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.1.4
1408
+ #
1409
+ # "The no-cache request directive indicates that a cache MUST NOT use a
1410
+ # stored response to satisfy the request without successful validation on
1411
+ # the origin server."
1412
+ #
1413
+ # When a client sends Cache-Control: no-cache in the request, it's explicitly
1414
+ # requesting that the cache not use any stored response without first validating
1415
+ # it with the origin server. This is different from the response no-cache directive,
1416
+ # which applies to how responses should be cached.
1417
+ request_cache_control = parse_cache_control(request.headers.get("cache-control"))
1418
+
1419
+ if request_cache_control.no_cache is True:
1420
+ # Move all fresh responses to the revalidation queue
1421
+ # This ensures that even fresh cached responses will be validated
1422
+ # with the origin server via conditional requests (If-None-Match,
1423
+ # If-Modified-Since) before being served to the client.
1424
+ need_revalidation.extend(ready_to_use)
1425
+ ready_to_use = []
1426
+
1427
+ # ============================================================================
1428
+ # STEP 8: Determine Next State Based on Available Responses
1392
1429
  # ============================================================================
1393
1430
 
1394
1431
  if ready_to_use:
@@ -340,8 +340,8 @@ try:
340
340
  await connection.commit()
341
341
 
342
342
  async def _is_corrupted(self, pair: Entry, cursor: anysqlite.Cursor) -> bool:
343
- # if entry was created more than 1 hour ago and still has no response (incomplete)
344
- if pair.meta.created_at + 3600 < time.time() and not self._is_stream_complete(pair.id, cursor):
343
+ # if entry was created more than 1 hour ago and still has no full response data
344
+ if pair.meta.created_at + 3600 < time.time() and not (await self._is_stream_complete(pair.id, cursor)):
345
345
  return True
346
346
  return False
347
347
 
@@ -340,8 +340,8 @@ try:
340
340
  connection.commit()
341
341
 
342
342
  def _is_corrupted(self, pair: Entry, cursor: sqlite3.Cursor) -> bool:
343
- # if entry was created more than 1 hour ago and still has no response (incomplete)
344
- if pair.meta.created_at + 3600 < time.time() and not self._is_stream_complete(pair.id, cursor):
343
+ # if entry was created more than 1 hour ago and still has no full response data
344
+ if pair.meta.created_at + 3600 < time.time() and not (self._is_stream_complete(pair.id, cursor)):
345
345
  return True
346
346
  return False
347
347
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hishel"
7
- version = "1.1.5"
7
+ version = "1.1.6"
8
8
  dynamic = ["readme"]
9
9
  description = " Elegant HTTP Caching for Python"
10
10
  license = "BSD-3-Clause"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes