1 Commits

Author SHA1 Message Date
dependabot[bot]
fcc18e619e Bump ruff from 0.1.1 to 0.11.6
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.1.1 to 0.11.6.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/v0.1.1...0.11.6)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.11.6
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 08:47:31 +00:00
11 changed files with 788 additions and 662 deletions

View File

@@ -3,7 +3,6 @@ on:
push: push:
branches: branches:
- main - main
- 'release-*'
tags: tags:
- 'v*' - 'v*'
pull_request: pull_request:
@@ -15,7 +14,7 @@ jobs:
name: Linter name: Linter
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install Poetry - name: Install Poetry
run: pipx install poetry run: pipx install poetry
- name: Setup Python - name: Setup Python
@@ -25,7 +24,7 @@ jobs:
python-version: '3.x' python-version: '3.x'
cache: poetry cache: poetry
- name: Cache mypy cache - name: Cache mypy cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: .mypy_cache path: .mypy_cache
key: ${{ runner.os }}-mypy-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }} key: ${{ runner.os }}-mypy-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
@@ -49,7 +48,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install Poetry - name: Install Poetry
run: pipx install poetry run: pipx install poetry
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
@@ -76,12 +75,11 @@ jobs:
build: build:
name: Build distributions name: Build distributions
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [test-summary] needs: [test-summary]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install Poetry - name: Install Poetry
run: pipx install poetry run: pipx install poetry
- name: Setup Python - name: Setup Python
@@ -93,7 +91,7 @@ jobs:
run: run:
make build make build
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: dist name: dist
path: dist path: dist
@@ -112,7 +110,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v2
with: with:
name: dist name: dist
path: dist path: dist

View File

@@ -20,15 +20,15 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v2
with: with:
languages: python languages: python
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v2
with: with:
category: "/language:python" category: "/language:python"

View File

@@ -12,9 +12,9 @@ jobs:
steps: steps:
- name: Dependabot metadata - name: Dependabot metadata
id: dependabot-metadata id: dependabot-metadata
uses: dependabot/fetch-metadata@v2 uses: dependabot/fetch-metadata@v1
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Approve PR - name: Approve PR
# only auto-approve direct deps that are minor or patch updates # only auto-approve direct deps that are minor or patch updates
# dependency type is indirect, direct:development or direct:production # dependency type is indirect, direct:development or direct:production

View File

@@ -23,7 +23,7 @@ jobs:
|| contains(github.event.pull_request.labels.*.name, 'skip-changelog') || contains(github.event.pull_request.labels.*.name, 'skip-changelog')
) )
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- name: Install Poetry - name: Install Poetry
run: pipx install poetry run: pipx install poetry
- name: Setup Python - name: Setup Python

View File

@@ -8,27 +8,6 @@ This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the chang
<!-- towncrier release notes start --> <!-- towncrier release notes start -->
## [0.2.2](https://github.com/long2ice/fastapi-cache/tree/0.2.2) - 2025-01-18
### Bug Fixes
- Fix failing tests (#459) [#459](https://github.com/long2ice/fastapi-cache/issues/459)
### Build Changes
- Use `importlib.metadata` to include project version string as `fastapi_cache.__version__`. [#172](https://github.com/long2ice/fastapi-cache/issues/172)
- (dependabot) Bump actions/checkout from 2 to 4 [#293](https://github.com/long2ice/fastapi-cache/issues/293)
- (dependabot) Bump actions/download-artifact from 2 to 4 (#359) [#359](https://github.com/long2ice/fastapi-cache/issues/359)
- (dependabot) Bump actions/upload-artifact from 3 to 4 (#360) [#360](https://github.com/long2ice/fastapi-cache/issues/360)
- (dependabot) Bump actions/cache from 3 to 4 (#378) [#378](https://github.com/long2ice/fastapi-cache/issues/378)
- (dependabot) Bump dependabot/fetch-metadata from 1 to 2 (#464) [#464](https://github.com/long2ice/fastapi-cache/issues/464)
- (dependabot) Bump tox from 4.20.0 to 4.23.2 (#466) [#466](https://github.com/long2ice/fastapi-cache/issues/466)
- (dependabot) Bump fastapi from 0.115.0 to 0.115.6 (#486) [#486](https://github.com/long2ice/fastapi-cache/issues/486)
- (dependabot) Bump redis from 5.0.8 to 5.2.1 (#490) [#490](https://github.com/long2ice/fastapi-cache/issues/490)
- (dependabot) Bump uvicorn from 0.30.6 to 0.33.0 (#493) [#493](https://github.com/long2ice/fastapi-cache/issues/493)
- (dependabot) Bump pyright from 1.1.381 to 1.1.392.post0 (#507) [#507](https://github.com/long2ice/fastapi-cache/issues/507)
- (dependabot) Bump towncrier from 22.12.0 to 24.8.0 (#509) [#509](https://github.com/long2ice/fastapi-cache/issues/509)
## 0.2 ## 0.2
### 0.2.1 ### 0.2.1

View File

@@ -0,0 +1 @@
Use `importlib.metadata` to include project version string as `fastapi_cache.__version__`.

View File

@@ -1,5 +1,5 @@
import datetime import datetime
from typing import TYPE_CHECKING, Optional, Tuple, Union from typing import TYPE_CHECKING, Optional, Tuple
from aiobotocore.client import AioBaseClient from aiobotocore.client import AioBaseClient
from aiobotocore.session import AioSession, get_session from aiobotocore.session import AioSession, get_session
@@ -30,7 +30,7 @@ class DynamoBackend(Backend):
>> FastAPICache.init(dynamodb) >> FastAPICache.init(dynamodb)
""" """
client: Union[DynamoDBClient, None] client: DynamoDBClient
session: AioSession session: AioSession
table_name: str table_name: str
region: Optional[str] region: Optional[str]
@@ -46,63 +46,58 @@ class DynamoBackend(Backend):
).__aenter__() ).__aenter__()
async def close(self) -> None: async def close(self) -> None:
if self.client: self.client = await self.client.__aexit__(None, None, None)
await self.client.__aexit__(None, None, None)
self.client = None
async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]: async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]:
if self.client: response = await self.client.get_item(TableName=self.table_name, Key={"key": {"S": key}})
response = await self.client.get_item(TableName=self.table_name, Key={"key": {"S": key}})
if "Item" in response: if "Item" in response:
value = response["Item"].get("value", {}).get("B") value = response["Item"].get("value", {}).get("B")
ttl = response["Item"].get("ttl", {}).get("N") ttl = response["Item"].get("ttl", {}).get("N")
if not ttl: if not ttl:
return -1, value return -1, value
# It's only eventually consistent so we need to check ourselves # It's only eventually consistent so we need to check ourselves
expire = int(ttl) - int(datetime.datetime.now().timestamp()) expire = int(ttl) - int(datetime.datetime.now().timestamp())
if expire > 0: if expire > 0:
return expire, value return expire, value
return 0, None return 0, None
async def get(self, key: str) -> Optional[bytes]: async def get(self, key: str) -> Optional[bytes]:
if self.client: response = await self.client.get_item(TableName=self.table_name, Key={"key": {"S": key}})
response = await self.client.get_item(TableName=self.table_name, Key={"key": {"S": key}}) if "Item" in response:
if "Item" in response: return response["Item"].get("value", {}).get("B")
return response["Item"].get("value", {}).get("B")
return None return None
async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None: async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None:
if self.client: ttl = (
ttl = ( {
{ "ttl": {
"ttl": { "N": str(
"N": str( int(
int( (
( datetime.datetime.now() + datetime.timedelta(seconds=expire)
datetime.datetime.now() + datetime.timedelta(seconds=expire) ).timestamp()
).timestamp()
)
) )
} )
} }
if expire }
else {} if expire
) else {}
)
await self.client.put_item( await self.client.put_item(
TableName=self.table_name, TableName=self.table_name,
Item={ Item={
**{ **{
"key": {"S": key}, "key": {"S": key},
"value": {"B": value}, "value": {"B": value},
},
**ttl,
}, },
) **ttl,
},
)
async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int: async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int:
raise NotImplementedError raise NotImplementedError

1244
poetry.lock generated

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "fastapi-cache2" name = "fastapi-cache2"
version = "0.2.3" version = "0.2.2"
description = "Cache for FastAPI" description = "Cache for FastAPI"
authors = ["long2ice <long2ice@gmail.com>"] authors = ["long2ice <long2ice@gmail.com>"]
license = "Apache-2.0" license = "Apache-2.0"
@@ -33,7 +33,7 @@ mypy = { version = "^1.2.0", python = "^3.10" }
pyright = { version = "^1.1.373", python = "^3.10" } pyright = { version = "^1.1.373", python = "^3.10" }
types-aiobotocore = { extras = ["dynamodb"], version = "^2.5.0.post2", python = "^3.10" } types-aiobotocore = { extras = ["dynamodb"], version = "^2.5.0.post2", python = "^3.10" }
types-redis = { version = "^4.5.4.2", python = "^3.10" } types-redis = { version = "^4.5.4.2", python = "^3.10" }
ruff = { version = ">=0.0.267,<0.1.2", python = "^3.10" } ruff = { version = ">=0.0.267,<0.11.7", python = "^3.10" }
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = "*" pytest = "*"
@@ -41,7 +41,7 @@ requests = "*"
coverage = ">=6.5,<8.0" coverage = ">=6.5,<8.0"
httpx = "*" httpx = "*"
tox = "^4.5.1" tox = "^4.5.1"
towncrier = "24.8.0" towncrier = "^22.12.0"
[tool.poetry.group.distributing] [tool.poetry.group.distributing]
optional = true optional = true
@@ -88,36 +88,6 @@ template = "changelog.d/changelog_template.jinja"
title_format = "## [{version}](https://github.com/long2ice/fastapi-cache/tree/{version}) - {project_date}" title_format = "## [{version}](https://github.com/long2ice/fastapi-cache/tree/{version}) - {project_date}"
issue_format = "[#{issue}](https://github.com/long2ice/fastapi-cache/issues/{issue})" issue_format = "[#{issue}](https://github.com/long2ice/fastapi-cache/issues/{issue})"
[[tool.towncrier.type]]
directory = 'feature'
name = 'New Features'
showcontent = true
[[tool.towncrier.type]]
directory = 'removed'
name = 'Deprecated/Removed Features'
showcontent = true
[[tool.towncrier.type]]
directory = 'fix'
name = 'Bug Fixes'
showcontent = true
[[tool.towncrier.type]]
directory = 'build'
name = 'Build Changes'
showcontent = true
[[tool.towncrier.type]]
directory = 'doc'
name = 'Documentation'
showcontent = true
[[tool.towncrier.type]]
directory = 'misc'
name = 'Everything Else'
showcontent = true
[tool.pyright] [tool.pyright]
strict = ["fastapi_cache", "tests"] strict = ["fastapi_cache", "tests"]
pythonVersion = "3.8" pythonVersion = "3.8"

View File

@@ -1,8 +1,8 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, Optional, Type from typing import Any, Optional, Tuple, Type
import pytest import pytest
from pydantic import BaseModel from pydantic import BaseModel, ValidationError
from fastapi_cache.coder import JsonCoder, PickleCoder from fastapi_cache.coder import JsonCoder, PickleCoder
@@ -41,22 +41,16 @@ def test_pickle_coder(value: Any) -> None:
assert decoded_value == value assert decoded_value == value
# vicchi: 2025/01/17
# test values and tests commented out until #460 is resolved due to removal
# of support for decoding JSON to a custom type
@pytest.mark.parametrize( @pytest.mark.parametrize(
("value", "return_type"), ("value", "return_type"),
[ [
(1, int),
(1, None), (1, None),
("some_string", str),
("some_string", None), ("some_string", None),
# ((1, 2), Tuple[int, int]), ((1, 2), Tuple[int, int]),
([1, 2, 3], None), ([1, 2, 3], None),
# ({"some_key": 1, "other_key": 2}, None),
({"some_key": 1, "other_key": 2}, None), ({"some_key": 1, "other_key": 2}, None),
# (DCItem(name="foo", price=42.0, description="some dataclass item", tax=0.2), DCItem), (DCItem(name="foo", price=42.0, description="some dataclass item", tax=0.2), DCItem),
# (PDItem(name="foo", price=42.0, description="some pydantic item", tax=0.2), PDItem), (PDItem(name="foo", price=42.0, description="some pydantic item", tax=0.2), PDItem),
], ],
) )
def test_json_coder(value: Any, return_type: Type[Any]) -> None: def test_json_coder(value: Any, return_type: Type[Any]) -> None:
@@ -66,7 +60,7 @@ def test_json_coder(value: Any, return_type: Type[Any]) -> None:
assert decoded_value == value assert decoded_value == value
# def test_json_coder_validation_error() -> None: def test_json_coder_validation_error() -> None:
# invalid = b'{"name": "incomplete"}' invalid = b'{"name": "incomplete"}'
# with pytest.raises(ValidationError): with pytest.raises(ValidationError):
# JsonCoder.decode_as_type(invalid, type_=PDItem) JsonCoder.decode_as_type(invalid, type_=PDItem)

View File

@@ -1,5 +1,4 @@
import time import time
from http import HTTPStatus
from typing import Any, Generator from typing import Any, Generator
import pendulum import pendulum
@@ -23,21 +22,19 @@ def test_datetime() -> None:
response = client.get("/datetime") response = client.get("/datetime")
assert response.headers.get("X-FastAPI-Cache") == "MISS" assert response.headers.get("X-FastAPI-Cache") == "MISS"
now = response.json().get("now") now = response.json().get("now")
# now_ = pendulum.now() now_ = pendulum.now()
# assert pendulum.parse(now) == now_ assert pendulum.parse(now) == now_
now_ = pendulum.parse(now)
response = client.get("/datetime") response = client.get("/datetime")
assert response.headers.get("X-FastAPI-Cache") == "HIT" assert response.headers.get("X-FastAPI-Cache") == "HIT"
now = response.json().get("now") now = response.json().get("now")
assert pendulum.parse(now) == now_ assert pendulum.parse(now) == now_
time.sleep(3) time.sleep(3)
response = client.get("/datetime") response = client.get("/datetime")
# now = response.json().get("now")
assert response.headers.get("X-FastAPI-Cache") == "MISS"
now = response.json().get("now") now = response.json().get("now")
assert response.headers.get("X-FastAPI-Cache") == "MISS"
now = pendulum.parse(now) now = pendulum.parse(now)
assert now != now_ assert now != now_
# assert now == pendulum.now() assert now == pendulum.now()
def test_date() -> None: def test_date() -> None:
@@ -103,13 +100,11 @@ def test_pydantic_model() -> None:
def test_non_get() -> None: def test_non_get() -> None:
with TestClient(app) as client: with TestClient(app) as client:
response = client.put("/cached_put") response = client.put("/cached_put")
assert response.status_code == HTTPStatus.METHOD_NOT_ALLOWED
assert "X-FastAPI-Cache" not in response.headers assert "X-FastAPI-Cache" not in response.headers
assert response.json() != {"value": 1} assert response.json() == {"value": 1}
response = client.put("/cached_put") response = client.put("/cached_put")
assert response.status_code == HTTPStatus.METHOD_NOT_ALLOWED
assert "X-FastAPI-Cache" not in response.headers assert "X-FastAPI-Cache" not in response.headers
assert response.json() != {"value": 2} assert response.json() == {"value": 2}
def test_alternate_injected_namespace() -> None: def test_alternate_injected_namespace() -> None: