From 237f307382bad4046e603718e7254b08a790a613 Mon Sep 17 00:00:00 2001 From: Kirill Pinchuk Date: Mon, 20 Feb 2023 22:34:51 +0300 Subject: [PATCH] decorators.cache: use Generic type. drop py38 --- fan_tools/__init__.py | 2 +- fan_tools/python/decorators.py | 14 +++++++------- pyproject.toml | 3 ++- tests/test_decorators.py | 2 +- tox.ini | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/fan_tools/__init__.py b/fan_tools/__init__.py index 8576e6e..d6497a8 100644 --- a/fan_tools/__init__.py +++ b/fan_tools/__init__.py @@ -1 +1 @@ -__version__ = '3.13.0' +__version__ = '4.0.0' diff --git a/fan_tools/python/decorators.py b/fan_tools/python/decorators.py index 2f29a38..bb92132 100644 --- a/fan_tools/python/decorators.py +++ b/fan_tools/python/decorators.py @@ -3,7 +3,7 @@ import functools import logging from pathlib import Path -from typing import Awaitable, Callable, Protocol, Type, TypeVar, Union +from typing import Awaitable, Callable, Generic, Protocol, Type, TypeVar, Union try: @@ -77,16 +77,16 @@ def json(self) -> str: ... -FuncType = Callable[P, Awaitable[PydanticBaseModel]] +ModelType = TypeVar('ModelType', bound=PydanticBaseModel) -class cache_async: +class cache_async(Generic[ModelType]): """ file cache for async functions that returns pydantic models NB: it doesn't use parameters to generate the cache file name """ - def __init__(self, fname: Path, model: PydanticBaseModel, default: PydanticBaseModel): + def __init__(self, fname: Path, model: ModelType, default: ModelType): self.fname = fname self._default = default self.cache = default @@ -94,9 +94,9 @@ def __init__(self, fname: Path, model: PydanticBaseModel, default: PydanticBaseM if self.fname.exists(): self.cache = model.parse_file(self.fname) - def __call__(self, func: FuncType[P]) -> FuncType[P]: + def __call__(self, func: Callable[P, Awaitable[ModelType]]): @functools.wraps(func) - async def wrapper(*args: P.args, **kwargs: P.kwargs) -> PydanticBaseModel: + async def wrapper(*args: P.args, **kwargs: P.kwargs) -> ModelType: if self.cache: return self.cache value = await func(*args, **kwargs) @@ -104,7 +104,7 @@ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> PydanticBaseModel: self.fname.write_text(self.cache.json()) return value - wrapper.reset_cache = self.reset_cache + wrapper.reset_cache = self.reset_cache # type: ignore return wrapper diff --git a/pyproject.toml b/pyproject.toml index ddc8e09..a534ef5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,8 +21,9 @@ classifiers = [ 'Operating System :: POSIX :: Linux', 'Operating System :: Unix', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: Implementation', 'Programming Language :: Python :: Implementation :: CPython', 'Topic :: Software Development', diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 8ef4649..7413828 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -10,7 +10,7 @@ async def test_01_simplest(self, tmp_path): model.json.return_value = '{"a": "b"}' - @cache_async(fname, model, {}) + @cache_async[type(dict)](fname, model, {}) async def func(): return model diff --git a/tox.ini b/tox.ini index c681300..35a36f7 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] min_version = 4.3 isolated_build = True -envlist = py{38,39,310}-django{32,40} #,mypy +envlist = py{39,310,311}-django{32,40} #,mypy [testenv] extras = @@ -26,7 +26,7 @@ deps = six starlette==0.14.2 uvicorn[standart]==0.15.0 - uvloop==0.16.0 + uvloop django32: djangorestframework==3.12.* django32: Django==3.2.* django40: Django==4.0.*