Skip to content

Commit d8ab798

Browse files
authored
Merge pull request #57 from igorbenav/mypy-fixes
fixed for stuff found by mypy
2 parents 10e05f9 + 9a5f6f9 commit d8ab798

File tree

11 files changed

+51
-25
lines changed

11 files changed

+51
-25
lines changed

mypy.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[mypy]
2+
ignore_missing_imports = True
3+
strict_optional = True
4+
warn_redundant_casts = True
5+
warn_unused_ignores = True

src/app/api/dependencies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ async def get_optional_user(
6464
if token_data is None:
6565
return None
6666

67-
return await get_current_user(token_value, is_deleted=False, db=db)
67+
return await get_current_user(token_value, db=db)
6868

6969
except HTTPException as http_exc:
7070
if http_exc.status_code != 401:

src/app/api/paginated.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TypeVar, Generic, List
1+
from typing import TypeVar, Generic, List, Dict, Any
22

33
from pydantic import BaseModel
44

@@ -19,7 +19,7 @@ def paginated_response(
1919
crud_data: ListResponse[SchemaType],
2020
page: int,
2121
items_per_page: int
22-
) -> PaginatedListResponse[SchemaType]:
22+
) -> Dict[str, Any]:
2323
"""
2424
Create a paginated response based on the provided data and pagination parameters.
2525
@@ -34,8 +34,8 @@ def paginated_response(
3434
3535
Returns
3636
-------
37-
PaginatedListResponse[SchemaType]
38-
A structured paginated response containing the list of items, total count, pagination flags, and numbers.
37+
Dict[str, Any]
38+
A structured paginated response dict containing the list of items, total count, pagination flags, and numbers.
3939
4040
Note
4141
----

src/app/core/db/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import uuid as uuid_pkg
22
from datetime import datetime
33
from sqlalchemy import Column, DateTime, Boolean, text
4+
from sqlalchemy.dialects.postgresql import UUID
45

56
class UUIDMixin:
6-
uuid: uuid_pkg.UUID = Column(uuid_pkg.UUID(as_uuid=True), primary_key=True, default=uuid_pkg.uuid4, server_default=text("gen_random_uuid()"))
7+
uuid: uuid_pkg.UUID = Column(UUID, primary_key=True, default=uuid_pkg.uuid4, server_default=text("gen_random_uuid()"))
8+
79

810
class TimestampMixin:
911
created_at: datetime = Column(DateTime, default=datetime.utcnow, server_default=text("current_timestamp(0)"))

src/app/core/exceptions/cache_exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@ class InvalidRequestError(Exception):
88
def __init__(self, message="Type of request not supported."):
99
self.message = message
1010
super().__init__(self.message)
11+
12+
13+
class MissingClientError(Exception):
14+
def __init__(self, message="Client is None."):
15+
self.message = message
16+
super().__init__(self.message)

src/app/core/exceptions/http_exceptions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
from http import HTTPStatus
12
from fastapi import HTTPException, status
23

34
class CustomException(HTTPException):
45
def __init__(self, status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR, detail: str | None = None):
56
if not detail:
6-
detail = status_code.description
7+
detail = HTTPStatus(status_code).description
78
super().__init__(status_code=status_code, detail=detail)
89

910

src/app/core/schemas.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,29 @@ class TimestampSchema(BaseModel):
1818
updated_at: datetime = Field(default=None)
1919

2020
@field_serializer("created_at")
21-
def serialize_dt(self, created_at: datetime | None, _info):
22-
return created_at.isoformat()
21+
def serialize_dt(self, created_at: datetime | None, _info) -> str | None:
22+
if created_at is not None:
23+
return created_at.isoformat()
24+
25+
return None
2326

2427
@field_serializer("updated_at")
25-
def serialize_updated_at(self, updated_at: datetime | None, _info):
28+
def serialize_updated_at(self, updated_at: datetime | None, _info) -> str | None:
2629
if updated_at is not None:
2730
return updated_at.isoformat()
2831

32+
return None
2933

3034
class PersistentDeletion(BaseModel):
3135
deleted_at: datetime | None = Field(default=None)
3236
is_deleted: bool = False
3337

3438
@field_serializer('deleted_at')
35-
def serialize_dates(self, deleted_at: datetime | None, _info):
39+
def serialize_dates(self, deleted_at: datetime | None, _info) -> str | None:
3640
if deleted_at is not None:
3741
return deleted_at.isoformat()
42+
43+
return None
3844

3945

4046
# -------------- token --------------

src/app/core/utils/cache.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Callable, Union, List, Dict, Any
1+
from typing import Callable, Union, Tuple, List, Dict, Any
22
import functools
33
import json
44
import re
@@ -7,21 +7,21 @@
77
from fastapi.encoders import jsonable_encoder
88
from redis.asyncio import Redis, ConnectionPool
99

10-
from app.core.exceptions.cache_exceptions import CacheIdentificationInferenceError, InvalidRequestError
10+
from app.core.exceptions.cache_exceptions import CacheIdentificationInferenceError, InvalidRequestError, MissingClientError
1111

1212
pool: ConnectionPool | None = None
1313
client: Redis | None = None
1414

15-
def _infer_resource_id(kwargs: Dict[str, Any], resource_id_type: Union[type, str]) -> Union[None, int, str]:
15+
def _infer_resource_id(kwargs: Dict[str, Any], resource_id_type: Union[type, Tuple[type, ...]]) -> Union[None, int, str]:
1616
"""
1717
Infer the resource ID from a dictionary of keyword arguments.
1818
1919
Parameters
2020
----------
2121
kwargs: Dict[str, Any]
2222
A dictionary of keyword arguments.
23-
resource_id_type: Union[type, str]
24-
The expected type of the resource ID, which can be an integer (int) or a string (str).
23+
resource_id_type: Union[type, Tuple[type, ...]]
24+
The expected type of the resource ID, which can be integer (int) or a string (str).
2525
2626
Returns
2727
-------
@@ -30,8 +30,8 @@ def _infer_resource_id(kwargs: Dict[str, Any], resource_id_type: Union[type, str
3030
3131
Note
3232
----
33-
- When `resource_id_type` is 'int', the function looks for an argument with the key 'id'.
34-
- When `resource_id_type` is 'str', it attempts to infer the resource ID as a string.
33+
- When `resource_id_type` is `int`, the function looks for an argument with the key 'id'.
34+
- When `resource_id_type` is `str`, it attempts to infer the resource ID as a string.
3535
"""
3636
resource_id = None
3737
for arg_name, arg_value in kwargs.items():
@@ -177,7 +177,10 @@ async def _delete_keys_by_pattern(pattern: str):
177177
- Be cautious with patterns that could match a large number of keys, as deleting
178178
many keys simultaneously may impact the performance of the Redis server.
179179
"""
180-
cursor = "0"
180+
if client is None:
181+
raise MissingClientError
182+
183+
cursor = -1
181184
while cursor != 0:
182185
cursor, keys = await client.scan(cursor, match=pattern, count=100)
183186
if keys:
@@ -188,7 +191,7 @@ def cache(
188191
key_prefix: str,
189192
resource_id_name: Any = None,
190193
expiration: int = 3600,
191-
resource_id_type: Union[type, List[type]] = int,
194+
resource_id_type: Union[type, Tuple[type, ...]] = int,
192195
to_invalidate_extra: Dict[str, Any] | None = None,
193196
pattern_to_invalidate_extra: List[str] | None = None
194197
) -> Callable:
@@ -207,8 +210,8 @@ def cache(
207210
otherwise, the resource ID is inferred from the function's arguments.
208211
expiration: int, optional
209212
The expiration time for the cached data in seconds. Defaults to 3600 seconds (1 hour).
210-
resource_id_type: Union[type, List[type]], optional
211-
The expected type of the resource ID. This can be a single type (e.g., int) or a list of types (e.g., [int, str]).
213+
resource_id_type: Union[type, Tuple[type, ...]], default int
214+
The expected type of the resource ID. This can be a single type (e.g., int) or a tuple of types (e.g., (int, str)).
212215
Defaults to int. This is used only if resource_id_name is not provided.
213216
to_invalidate_extra: Dict[str, Any] | None, optional
214217
A dictionary where keys are cache key prefixes and values are templates for cache key suffixes.
@@ -286,6 +289,9 @@ async def update_item(request: Request, item_id: int, data: dict, user_id: int):
286289
def wrapper(func: Callable) -> Callable:
287290
@functools.wraps(func)
288291
async def inner(request: Request, *args, **kwargs) -> Response:
292+
if client is None:
293+
raise MissingClientError
294+
289295
if resource_id_name:
290296
resource_id = kwargs[resource_id_name]
291297
else:

src/app/crud/crud_base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
_auto_detect_join_condition,
1414
_add_column_with_prefix
1515
)
16+
from app.core.db.database import Base
1617

17-
ModelType = TypeVar("ModelType")
18+
ModelType = TypeVar("ModelType", bound=Base)
1819
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
1920
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel)
2021
UpdateSchemaInternalType = TypeVar("UpdateSchemaInternalType", bound=BaseModel)

src/app/schemas/post.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class PostCreateInternal(PostCreate):
6666
created_by_user_id: int
6767

6868

69-
class PostUpdate(PostBase):
69+
class PostUpdate(BaseModel):
7070
model_config = ConfigDict(extra='forbid')
7171

7272
title: Annotated[

0 commit comments

Comments
 (0)