From 53fa23e8d929f6e5f41b3e960964b6d0119ab281 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Wed, 20 Mar 2024 11:53:48 +0000 Subject: [PATCH 1/4] add more types and rewrite logic to avoid too many return statements Signed-off-by: Grant Ramsay --- fastapi_redis_cache/util.py | 42 +++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/fastapi_redis_cache/util.py b/fastapi_redis_cache/util.py index a49b22c..5e2ae30 100644 --- a/fastapi_redis_cache/util.py +++ b/fastapi_redis_cache/util.py @@ -3,9 +3,12 @@ import json from datetime import date, datetime from decimal import Decimal +from enum import Enum from typing import Any, Union +from uuid import UUID from dateutil import parser +from pydantic import BaseModel DATETIME_AWARE = "%m/%d/%Y %I:%M:%S %p %z" DATE_ONLY = "%m/%d/%Y" @@ -27,16 +30,47 @@ class BetterJsonEncoder(json.JSONEncoder): """Subclass the JSONEncoder to handle more types.""" def default(self, obj: Any) -> Union[dict[str, str], Any]: # noqa: ANN401 - """Return a serializable object for the JSONEncoder to use.""" - if isinstance(obj, datetime): + """Return a serializable object for the JSONEncoder to use. + + This is re-written from the original code to handle more types, and not + end up with a mass of if-else and return statements. + """ + + def handle_datetime() -> dict[str, str]: return { "val": obj.strftime(DATETIME_AWARE), "_spec_type": str(datetime), } - if isinstance(obj, date): + + def handle_date() -> dict[str, str]: return {"val": obj.strftime(DATE_ONLY), "_spec_type": str(date)} - if isinstance(obj, Decimal): + + def handle_decimal() -> dict[str, str]: return {"val": str(obj), "_spec_type": str(Decimal)} + + def handle_basemodel() -> Any: # noqa: ANN401 + """Handle a Pydantic BaseModel object.""" + return obj.model_dump() + + def handle_uuid() -> str: + return str(obj) + + def handle_enum() -> str: + return str(obj.value) + + type_mapping = { + datetime: handle_datetime, + date: handle_date, + Decimal: handle_decimal, + BaseModel: handle_basemodel, + UUID: handle_uuid, + Enum: handle_enum, + } + + for obj_type, handler in type_mapping.items(): + if isinstance(obj, obj_type): + return handler() + return super().default(obj) From 8a14cbb8f2907b19c6b2ab2bbf44659f6426cb0a Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Wed, 20 Mar 2024 13:20:17 +0000 Subject: [PATCH 2/4] simplify BetterJsonEncoder mapping Signed-off-by: Grant Ramsay --- fastapi_redis_cache/util.py | 47 +++++++++++++------------------------ requirements-dev.txt | 2 +- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/fastapi_redis_cache/util.py b/fastapi_redis_cache/util.py index 5e2ae30..3dc47fa 100644 --- a/fastapi_redis_cache/util.py +++ b/fastapi_redis_cache/util.py @@ -4,7 +4,7 @@ from datetime import date, datetime from decimal import Decimal from enum import Enum -from typing import Any, Union +from typing import Any, Callable, Union from uuid import UUID from dateutil import parser @@ -25,6 +25,8 @@ str(Decimal): Decimal, } +HandlerType = Callable[[Any], Union[dict[str, str], str]] + class BetterJsonEncoder(json.JSONEncoder): """Subclass the JSONEncoder to handle more types.""" @@ -35,41 +37,24 @@ def default(self, obj: Any) -> Union[dict[str, str], Any]: # noqa: ANN401 This is re-written from the original code to handle more types, and not end up with a mass of if-else and return statements. """ - - def handle_datetime() -> dict[str, str]: - return { - "val": obj.strftime(DATETIME_AWARE), + type_mapping: dict[type, HandlerType] = { + datetime: lambda o: { + "val": o.strftime(DATETIME_AWARE), "_spec_type": str(datetime), - } - - def handle_date() -> dict[str, str]: - return {"val": obj.strftime(DATE_ONLY), "_spec_type": str(date)} - - def handle_decimal() -> dict[str, str]: - return {"val": str(obj), "_spec_type": str(Decimal)} - - def handle_basemodel() -> Any: # noqa: ANN401 - """Handle a Pydantic BaseModel object.""" - return obj.model_dump() - - def handle_uuid() -> str: - return str(obj) - - def handle_enum() -> str: - return str(obj.value) - - type_mapping = { - datetime: handle_datetime, - date: handle_date, - Decimal: handle_decimal, - BaseModel: handle_basemodel, - UUID: handle_uuid, - Enum: handle_enum, + }, + date: lambda o: { + "val": o.strftime(DATE_ONLY), + "_spec_type": str(date), + }, + Decimal: lambda o: {"val": str(o), "_spec_type": str(Decimal)}, + BaseModel: lambda o: o.model_dump(), + UUID: lambda o: str(o), + Enum: lambda o: str(o.value), } for obj_type, handler in type_mapping.items(): if isinstance(obj, obj_type): - return handler() + return handler(obj) return super().default(obj) diff --git a/requirements-dev.txt b/requirements-dev.txt index fbf04d7..c45c992 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -47,7 +47,7 @@ pydantic-extra-types==2.6.0 ; python_version >= "3.9" and python_version < "4.0" pydantic-settings==2.2.1 ; python_version >= "3.9" and python_version < "4.0" pydantic==2.6.4 ; python_version >= "3.9" and python_version < "4.0" pyfakefs==5.3.5 ; python_version >= "3.9" and python_version < "4.0" -pymarkdownlnt==0.9.17 ; python_version >= "3.9" and python_version < "4.0" +pymarkdownlnt==0.9.18 ; python_version >= "3.9" and python_version < "4.0" pytest-asyncio==0.21.1 ; python_version >= "3.9" and python_version < "4.0" pytest-cov==4.1.0 ; python_version >= "3.9" and python_version < "4.0" pytest-env==1.1.3 ; python_version >= "3.9" and python_version < "4.0" From baec87a39d87dd1d9cab4cd4607bc478393fb410 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Wed, 20 Mar 2024 13:42:30 +0000 Subject: [PATCH 3/4] add a TODO file Signed-off-by: Grant Ramsay --- TODO.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..8459b7c --- /dev/null +++ b/TODO.md @@ -0,0 +1,10 @@ +# TODO List + +These below are from Issues or PRs in the original repository. + +- Add ability to manually expire a cache entry + () +- Add support for caching non-FastAPI functions + () +- Take a look at other issues in the original repository to see if any need to be +added here. From 51d759c8de1b08c8f2d6ddd2e5350cebc4ac4e00 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Wed, 20 Mar 2024 13:43:14 +0000 Subject: [PATCH 4/4] remove version.py as not needed with Poetry Signed-off-by: Grant Ramsay --- fastapi_redis_cache/version.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 fastapi_redis_cache/version.py diff --git a/fastapi_redis_cache/version.py b/fastapi_redis_cache/version.py deleted file mode 100644 index 24b8e3e..0000000 --- a/fastapi_redis_cache/version.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Define Version information for the package.""" - -__version_info__ = ("0", "2", "5") -__version__ = ".".join(__version_info__)