From 19c4d0271a7065684a1961f4b1bb90c15a6f5d17 Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 14:09:42 +0800 Subject: [PATCH 1/6] fix latest bug --- fastapi_cache/coder.py | 17 +++-------------- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/fastapi_cache/coder.py b/fastapi_cache/coder.py index 904fc69..178fe26 100644 --- a/fastapi_cache/coder.py +++ b/fastapi_cache/coder.py @@ -15,11 +15,12 @@ from typing import ( import pendulum from fastapi.encoders import jsonable_encoder -from pydantic import BaseConfig, ValidationError, fields from starlette.responses import JSONResponse from starlette.templating import ( _TemplateResponse as TemplateResponse, # pyright: ignore[reportPrivateUsage] ) +class ModelField: + pass _T = TypeVar("_T", bound=type) @@ -69,7 +70,7 @@ class Coder: # decode_as_type method and then stores a different kind of field for a # given type, do make sure that the subclass provides its own class # attribute for this cache. - _type_field_cache: ClassVar[Dict[Any, fields.ModelField]] = {} + _type_field_cache: ClassVar[Dict[Any, ModelField]] = {} @overload @classmethod @@ -89,18 +90,6 @@ class Coder: """ result = cls.decode(value) - if type_ is not None: - try: - field = cls._type_field_cache[type_] - except KeyError: - field = cls._type_field_cache[type_] = fields.ModelField( - name="body", type_=type_, class_validators=None, model_config=BaseConfig - ) - result, errors = field.validate(result, {}, loc=()) - if errors is not None: - if not isinstance(errors, list): - errors = [errors] - raise ValidationError(errors, type_) return result diff --git a/pyproject.toml b/pyproject.toml index c49fd44..003157d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fastapi-cache2" -version = "0.2.1" +version = "0.2.2" description = "Cache for FastAPI" authors = ["long2ice "] license = "Apache-2.0" From e4a0df62dd2f8988187e72b9911cae7c8dd843a4 Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 14:32:02 +0800 Subject: [PATCH 2/6] fix #424, no-cache should store the result to cache --- fastapi_cache/decorator.py | 6 +++--- tests/test_decorator.py | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/fastapi_cache/decorator.py b/fastapi_cache/decorator.py index 4c7cf33..40a1920 100644 --- a/fastapi_cache/decorator.py +++ b/fastapi_cache/decorator.py @@ -72,7 +72,7 @@ def _uncacheable(request: Optional[Request]) -> bool: Returns true if: - Caching has been disabled globally - This is not a GET request - - The request has a Cache-Control header with a value of "no-store" or "no-cache" + - The request has a Cache-Control header with a value of "no-store" """ if not FastAPICache.get_enable(): @@ -81,7 +81,7 @@ def _uncacheable(request: Optional[Request]) -> bool: return False if request.method != "GET": return True - return request.headers.get("Cache-Control") in ("no-store", "no-cache") + return request.headers.get("Cache-Control") == "no-store" def cache( @@ -182,7 +182,7 @@ def cache( ) ttl, cached = 0, None - if cached is None: # cache miss + if cached is None or (request is not None and request.headers.get("Cache-Control") == "no-cache") : # cache miss result = await ensure_async_func(*args, **kwargs) to_cache = coder.encode(result) diff --git a/tests/test_decorator.py b/tests/test_decorator.py index fefa182..f8d2028 100644 --- a/tests/test_decorator.py +++ b/tests/test_decorator.py @@ -112,3 +112,28 @@ def test_alternate_injected_namespace() -> None: response = client.get("/namespaced_injection") assert response.headers.get("X-FastAPI-Cache") == "MISS" assert response.json() == {"__fastapi_cache_request": 42, "__fastapi_cache_response": 17} + +def test_cache_control() -> None: + with TestClient(app) as client: + response = client.get("/uncached_put") + assert "X-FastAPI-Cache" not in response.headers + assert response.json() == {"value": 1} + + # HIT + response = client.get("/uncached_put") + assert response.headers.get("X-FastAPI-Cache") == "HIT" + assert response.json() == {"value": 1} + + # no-cache + response = client.get("/uncached_put", headers={"Cache-Control": "no-cache"}) + assert response.json() == {"value": 2} + + response = client.get("/uncached_put") + assert response.json() == {"value": 2} + + # no-store + response = client.get("/uncached_put", headers={"Cache-Control": "no-store"}) + assert response.json() == {"value": 3} + + response = client.get("/uncached_put") + assert response.json() == {"value": 2} From 120553a36ffa46274875ef4921c929d4577b9c17 Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 14:42:56 +0800 Subject: [PATCH 3/6] version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 003157d..951a2d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fastapi-cache2" -version = "0.2.2" +version = "0.2.3" description = "Cache for FastAPI" authors = ["long2ice "] license = "Apache-2.0" From 6f8994b843fa3000e3fc048c5069b535fa73980a Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 14:43:53 +0800 Subject: [PATCH 4/6] fix test --- tests/test_decorator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_decorator.py b/tests/test_decorator.py index f8d2028..af38d7e 100644 --- a/tests/test_decorator.py +++ b/tests/test_decorator.py @@ -115,25 +115,25 @@ def test_alternate_injected_namespace() -> None: def test_cache_control() -> None: with TestClient(app) as client: - response = client.get("/uncached_put") + response = client.put("/uncached_put") assert "X-FastAPI-Cache" not in response.headers assert response.json() == {"value": 1} # HIT - response = client.get("/uncached_put") + response = client.put("/uncached_put") assert response.headers.get("X-FastAPI-Cache") == "HIT" assert response.json() == {"value": 1} # no-cache - response = client.get("/uncached_put", headers={"Cache-Control": "no-cache"}) + response = client.put("/uncached_put", headers={"Cache-Control": "no-cache"}) assert response.json() == {"value": 2} - response = client.get("/uncached_put") + response = client.put("/uncached_put") assert response.json() == {"value": 2} # no-store - response = client.get("/uncached_put", headers={"Cache-Control": "no-store"}) + response = client.put("/uncached_put", headers={"Cache-Control": "no-store"}) assert response.json() == {"value": 3} - response = client.get("/uncached_put") + response = client.put("/uncached_put") assert response.json() == {"value": 2} From 74e827d3de6cdf9f3138d3b78737604e728122d3 Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 14:51:58 +0800 Subject: [PATCH 5/6] fix tests --- examples/in_memory/main.py | 9 +++++++++ pyproject.toml | 2 +- tests/test_decorator.py | 18 ++++++++---------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/examples/in_memory/main.py b/examples/in_memory/main.py index ac2c5dc..73bdaae 100644 --- a/examples/in_memory/main.py +++ b/examples/in_memory/main.py @@ -107,6 +107,15 @@ async def uncached_put(): put_ret = put_ret + 1 return {"value": put_ret} +put_ret2 = 0 + +@app.get("/cached_put") +@cache(namespace="test", expire=5) +async def cached_put(): + global put_ret2 + put_ret2 = put_ret2 + 1 + return {"value": put_ret2} + @app.get("/namespaced_injection") @cache(namespace="test", expire=5, injected_dependency_namespace="monty_python") diff --git a/pyproject.toml b/pyproject.toml index 951a2d7..c49fd44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fastapi-cache2" -version = "0.2.3" +version = "0.2.1" description = "Cache for FastAPI" authors = ["long2ice "] license = "Apache-2.0" diff --git a/tests/test_decorator.py b/tests/test_decorator.py index af38d7e..b688569 100644 --- a/tests/test_decorator.py +++ b/tests/test_decorator.py @@ -99,10 +99,10 @@ def test_pydantic_model() -> None: def test_non_get() -> None: with TestClient(app) as client: - response = client.put("/uncached_put") + response = client.put("/cached_put") assert "X-FastAPI-Cache" not in response.headers assert response.json() == {"value": 1} - response = client.put("/uncached_put") + response = client.put("/cached_put") assert "X-FastAPI-Cache" not in response.headers assert response.json() == {"value": 2} @@ -115,25 +115,23 @@ def test_alternate_injected_namespace() -> None: def test_cache_control() -> None: with TestClient(app) as client: - response = client.put("/uncached_put") - assert "X-FastAPI-Cache" not in response.headers + response = client.get("/cached_put") assert response.json() == {"value": 1} # HIT - response = client.put("/uncached_put") - assert response.headers.get("X-FastAPI-Cache") == "HIT" + response = client.get("/cached_put") assert response.json() == {"value": 1} # no-cache - response = client.put("/uncached_put", headers={"Cache-Control": "no-cache"}) + response = client.get("/cached_put", headers={"Cache-Control": "no-cache"}) assert response.json() == {"value": 2} - response = client.put("/uncached_put") + response = client.get("/cached_put") assert response.json() == {"value": 2} # no-store - response = client.put("/uncached_put", headers={"Cache-Control": "no-store"}) + response = client.get("/cached_put", headers={"Cache-Control": "no-store"}) assert response.json() == {"value": 3} - response = client.put("/uncached_put") + response = client.get("/cached_put") assert response.json() == {"value": 2} From 2739b2d0feb1690ac94ef7fffa4b39485964e122 Mon Sep 17 00:00:00 2001 From: John Lyu Date: Thu, 9 May 2024 15:01:55 +0800 Subject: [PATCH 6/6] lint --- fastapi_cache/coder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastapi_cache/coder.py b/fastapi_cache/coder.py index 178fe26..4ce9432 100644 --- a/fastapi_cache/coder.py +++ b/fastapi_cache/coder.py @@ -19,6 +19,8 @@ from starlette.responses import JSONResponse from starlette.templating import ( _TemplateResponse as TemplateResponse, # pyright: ignore[reportPrivateUsage] ) + + class ModelField: pass