diff --git a/docs/usage/getting-started/configuration.md b/docs/usage/getting-started/configuration.md index 548376ffc..62d87efd3 100644 --- a/docs/usage/getting-started/configuration.md +++ b/docs/usage/getting-started/configuration.md @@ -245,6 +245,15 @@ Controls how githubkit caches **tokens** (e.g., GitHub App installation tokens) You can provide any built-in strategy or implement a custom one by subclassing `BaseCacheStrategy`. +!!! note "Migrating to Hishel 2.0" + + githubkit now depends on Hishel `>=2.0`. If you implement a custom `BaseCacheStrategy` or use githubkit's cache clients directly, note these breaking changes: + + - `get_hishel_policy()` has been replaced by `get_hishel_options()`, which returns a `hishel.CacheOptions` instead of a `CachePolicy`. Hishel 2.0 removed `CachePolicy` and `SpecificationPolicy`. + - `get_hishel_storage()` must return a `hishel.BaseStorage` (formerly `SyncBaseStorage`). `SyncSqliteStorage` is now `SqliteStorage`. + - The `policy` argument of `SyncCacheClient` / `AsyncCacheClient` has been renamed to `rfc` to align with Hishel 2.0. It accepts `CacheOptions | bool` and defaults to `True` (RFC 9111 caching, same behavior as before). + - `SyncMemoryStorage` / `AsyncMemoryStorage` no longer accept `refresh_ttl_on_access`. + #### Built-in Cache Strategies **`MemCacheStrategy`** — In-memory cache (default) diff --git a/githubkit/_httpx.py b/githubkit/_httpx.py index 7f9f01942..175b8769b 100644 --- a/githubkit/_httpx.py +++ b/githubkit/_httpx.py @@ -6,13 +6,13 @@ if TYPE_CHECKING: from hishel.httpx2 import AsyncCacheTransport as AsyncCacheTransport - from hishel.httpx2 import SyncCacheTransport as SyncCacheTransport + from hishel.httpx2 import CacheTransport as CacheTransport import httpx2 as httpx else: httpx = None if not os.getenv(GITHUBKIT_HTTPX2_DISABLE_FLAG): try: - from hishel.httpx2 import AsyncCacheTransport, SyncCacheTransport + from hishel.httpx2 import AsyncCacheTransport, CacheTransport import httpx2 as httpx except ImportError: # Hishel wraps a missing HTTP client in ImportError. @@ -21,7 +21,7 @@ if httpx is None: try: from hishel.httpx import AsyncCacheTransport as AsyncCacheTransport - from hishel.httpx import SyncCacheTransport as SyncCacheTransport + from hishel.httpx import CacheTransport as CacheTransport import httpx as httpx except ImportError: raise RuntimeError( diff --git a/githubkit/cache/base.py b/githubkit/cache/base.py index 50f05827a..c8c4a251f 100644 --- a/githubkit/cache/base.py +++ b/githubkit/cache/base.py @@ -1,13 +1,7 @@ import abc from datetime import timedelta -from hishel import ( - AsyncBaseStorage, - CacheOptions, - CachePolicy, - SpecificationPolicy, - SyncBaseStorage, -) +from hishel import AsyncBaseStorage, BaseStorage, CacheOptions class BaseCache(abc.ABC): @@ -47,12 +41,12 @@ async def get_async_cache_storage(self) -> AsyncBaseCache: """ raise NotImplementedError - def get_hishel_policy(self) -> CachePolicy: - """Get the hishel cache policy instance""" - return SpecificationPolicy(cache_options=CacheOptions(shared=False)) + def get_hishel_options(self) -> CacheOptions: + """Get the hishel cache options instance""" + return CacheOptions(shared=False) @abc.abstractmethod - def get_hishel_storage(self) -> SyncBaseStorage: + def get_hishel_storage(self) -> BaseStorage: """Get the hishel storage instance used in sync context""" raise NotImplementedError diff --git a/githubkit/core.py b/githubkit/core.py index 047b75a5a..e27a8334d 100644 --- a/githubkit/core.py +++ b/githubkit/core.py @@ -275,7 +275,7 @@ def _create_sync_client(self) -> httpx.Client: transport=self.config.transport, event_hooks=self.config.event_hooks, storage=self.config.cache_strategy.get_hishel_storage(), - policy=self.config.cache_strategy.get_hishel_policy(), + rfc=self.config.cache_strategy.get_hishel_options(), ) return httpx.Client( @@ -303,7 +303,7 @@ async def _create_async_client(self) -> httpx.AsyncClient: transport=self.config.async_transport, event_hooks=self.config.async_event_hooks, storage=await self.config.cache_strategy.get_async_hishel_storage(), - policy=self.config.cache_strategy.get_hishel_policy(), + rfc=self.config.cache_strategy.get_hishel_options(), ) return httpx.AsyncClient( diff --git a/githubkit/hishel.py b/githubkit/hishel.py index 5f506fa1d..c1ce2502c 100644 --- a/githubkit/hishel.py +++ b/githubkit/hishel.py @@ -6,63 +6,60 @@ from hishel import ( AsyncBaseStorage, AsyncSqliteStorage, - CachePolicy, - SyncBaseStorage, - SyncSqliteStorage, + BaseStorage, + CacheOptions, + SqliteStorage, ) -from ._httpx import AsyncCacheTransport, SyncCacheTransport, httpx +from ._httpx import AsyncCacheTransport, CacheTransport, httpx class SyncCacheClient(httpx.Client): def __init__(self, *args: Any, **kwargs: Any): - self.storage: SyncBaseStorage | None = kwargs.pop("storage", None) - self.policy: CachePolicy | None = kwargs.pop("policy", None) + self.storage: BaseStorage | None = kwargs.pop("storage", None) + self.rfc: CacheOptions | bool = kwargs.pop("rfc", True) super().__init__(*args, **kwargs) def _init_transport(self, *args, **kwargs) -> httpx.BaseTransport: _transport = super()._init_transport(*args, **kwargs) - return SyncCacheTransport( - next_transport=_transport, storage=self.storage, policy=self.policy + return CacheTransport( + next_transport=_transport, storage=self.storage, rfc=self.rfc ) def _init_proxy_transport(self, *args, **kwargs) -> httpx.BaseTransport: _transport = super()._init_proxy_transport(*args, **kwargs) - return SyncCacheTransport( - next_transport=_transport, storage=self.storage, policy=self.policy + return CacheTransport( + next_transport=_transport, storage=self.storage, rfc=self.rfc ) class AsyncCacheClient(httpx.AsyncClient): def __init__(self, *args: Any, **kwargs: Any): self.storage: AsyncBaseStorage | None = kwargs.pop("storage", None) - self.policy: CachePolicy | None = kwargs.pop("policy", None) + self.rfc: CacheOptions | bool = kwargs.pop("rfc", True) super().__init__(*args, **kwargs) def _init_transport(self, *args, **kwargs) -> httpx.AsyncBaseTransport: _transport = super()._init_transport(*args, **kwargs) return AsyncCacheTransport( - next_transport=_transport, storage=self.storage, policy=self.policy + next_transport=_transport, storage=self.storage, rfc=self.rfc ) def _init_proxy_transport(self, *args, **kwargs) -> httpx.AsyncBaseTransport: _transport = super()._init_proxy_transport(*args, **kwargs) return AsyncCacheTransport( - next_transport=_transport, storage=self.storage, policy=self.policy + next_transport=_transport, storage=self.storage, rfc=self.rfc ) -class SyncMemoryStorage(SyncSqliteStorage): +class SyncMemoryStorage(SqliteStorage): def __init__( self, *, default_ttl: float | None = None, - refresh_ttl_on_access: bool | None = None, keep_unclosed: bool = False, ) -> None: - super().__init__( - default_ttl=default_ttl, refresh_ttl_on_access=refresh_ttl_on_access - ) + super().__init__(default_ttl=default_ttl) # NOTE: hishel close the storage when the client transport is closed. # but for in-memory sqlite, # we may want to keep it unclosed to preserve the data for the next client. @@ -91,12 +88,9 @@ def __init__( self, *, default_ttl: float | None = None, - refresh_ttl_on_access: bool | None = None, keep_unclosed: bool = False, ) -> None: - super().__init__( - default_ttl=default_ttl, refresh_ttl_on_access=refresh_ttl_on_access - ) + super().__init__(default_ttl=default_ttl) # NOTE: hishel close the storage when the client transport is closed. # but for in-memory sqlite, # we may want to keep it unclosed to preserve the data for the next client. @@ -117,7 +111,7 @@ async def _ensure_connection(self) -> anysqlite.Connection: async def close(self) -> None: if self.keep_unclosed: # Do not close the connection, but drain all pending writes - async with self._write_lock: + async with self._init_lock: return return await super().close() diff --git a/pyproject.toml b/pyproject.toml index d0c0a40aa..0b179023d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ requires-python = ">=3.10, <4.0" dependencies = [ "anyio >=3.6.1, <5.0.0", "httpx >=0.23.0, <1.0.0", - "hishel[async,httpx] >=1.4.0, <2.0.0", + "hishel[async,httpx] >=2.0.0, <3.0.0", "typing-extensions >=4.13.0, <5.0.0", "pydantic >=1.9.1, <3.0.0, !=2.5.0, !=2.5.1", "githubkit-schemas >=26.5.7", diff --git a/uv.lock b/uv.lock index 6681540dc..8498b4bee 100644 --- a/uv.lock +++ b/uv.lock @@ -944,7 +944,7 @@ requires-dist = [ { name = "githubkit-schemas", editable = "packages/githubkit-schemas" }, { name = "githubkit-schemas", extras = ["all"], marker = "extra == 'all'", editable = "packages/githubkit-schemas" }, { name = "githubkit-schemas", extras = ["all"], marker = "extra == 'all-schemas'", editable = "packages/githubkit-schemas" }, - { name = "hishel", extras = ["async", "httpx"], specifier = ">=1.4.0,<2.0.0" }, + { name = "hishel", extras = ["async", "httpx"], specifier = ">=2.0.0,<3.0.0" }, { name = "httpx", specifier = ">=0.23.0,<1.0.0" }, { name = "pydantic", specifier = ">=1.9.1,!=2.5.0,!=2.5.1,<3.0.0" }, { name = "pyjwt", extras = ["crypto"], marker = "extra == 'all'", specifier = ">=2.4.0,<3.0.0" }, @@ -1129,15 +1129,15 @@ wheels = [ [[package]] name = "hishel" -version = "1.4.0" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "msgpack" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/ff/efba29288e1d304359491fa3aab83174c3ef24a63819e6acad6873d8c0a9/hishel-1.4.0.tar.gz", hash = "sha256:e406b052c658ce28629fc31423b9914b637d47d7c923f5fe9e288ec47e4823d1", size = 813499, upload-time = "2026-09-16T15:38:54.085Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/83/e8c4e482b6f5e9c2f9d1c7a1503137eed81b689d358ae0df6ac50d79f172/hishel-2.0.0.tar.gz", hash = "sha256:f043c88acf9b476fdbf203986253cd4e27e2468a3319b43c3946a641e1cb7696", size = 902409, upload-time = "2026-11-05T14:10:42.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/c5/2cf7b80da9833de6ae5099111b64cf541830ccb4ef26605ae86f23ed5604/hishel-1.4.0-py3-none-any.whl", hash = "sha256:38cb62d7d38fb437dc086f789c26d0cab41310d12497ec3f56dcead4b08571f0", size = 80795, upload-time = "2026-09-16T15:38:52.545Z" }, + { url = "https://files.pythonhosted.org/packages/01/9e/3657bc96268326f911952e2b6d67494344ef0c49220db342f1d625cb2cf3/hishel-2.0.0-py3-none-any.whl", hash = "sha256:3e96613d05a13d08d4ee22621dff3aebcdffbe41472efc2b5d4d01d6bd254983", size = 81878, upload-time = "2026-11-05T14:10:40.115Z" }, ] [package.optional-dependencies]