add lints

This commit is contained in:
ivankirpichnikov
2025-10-16 23:11:04 +03:00
parent 2ae3323b1e
commit 31d06fc0b4
25 changed files with 56 additions and 52 deletions
@@ -6,7 +6,6 @@ from cryptography.fernet import Fernet
from template_project.application.access_token.cryptographer import AccessTokenCryptographer
from template_project.application.access_token.entity import AccessTokenId
type RawAccessToken = str
@@ -1,4 +1,5 @@
from typing import override
from template_project.application.access_token.entity import AccessToken
from template_project.application.access_token.entity_factory import AccessTokenFactory
from template_project.application.user.entity import UserId
@@ -2,6 +2,7 @@ from typing import override
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from template_project.adapters.data_gateways.tables import access_token_table
from template_project.application.access_token.data_gateway import AccessTokenDataGateway
from template_project.application.access_token.entity import AccessToken, AccessTokenId
@@ -14,7 +15,7 @@ class DefaultAccessTokenDataGateway(AccessTokenDataGateway):
@override
async def load_with_id(self, access_token_id: AccessTokenId) -> AccessToken | None:
statement = select(AccessToken).where(
access_token_table.c.id==access_token_id,
access_token_table.c.id == access_token_id,
)
result = await self._session.execute(statement)
return result.scalar_one_or_none()
@@ -10,7 +10,6 @@ from sqlalchemy.orm import registry
from template_project.application.access_token.entity import AccessToken
from template_project.application.user.entity import User
meta_data = MetaData()
user_table = Table(
@@ -1,4 +1,5 @@
from typing import override
from typing import cast, override
from sqlalchemy import exists, select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -13,7 +14,7 @@ class DefaultUserDataGateway(UserDataGateway):
@override
async def load_with_id(self, id_: UserId) -> User | None:
statement = select(User).where(user_table.c.id==id_)
statement = select(User).where(user_table.c.id == id_)
result = await self._session.execute(statement)
return result.scalar_one_or_none()
@@ -24,4 +25,4 @@ class DefaultUserDataGateway(UserDataGateway):
result_fetchone = result.fetchone()
if result_fetchone is None:
return False
return result_fetchone[0]
return cast(bool, result_fetchone[0])
@@ -1,4 +1,3 @@
from abc import abstractmethod
from typing import override
import argon2
@@ -27,7 +26,7 @@ class ArgonPasswordVerifying(PasswordVerifying):
) -> None:
self._password_hasher = password_hasher
@abstractmethod
@override
def verify(
self,
verifiable_password: SecretString,
@@ -35,6 +34,5 @@ class ArgonPasswordVerifying(PasswordVerifying):
) -> bool:
try:
return self._password_hasher.verify(hashed_password, verifiable_password.get_value())
except Argon2Error as e:
except Argon2Error:
return False
@@ -3,7 +3,6 @@ from typing import Protocol
from template_project.application.access_token.entity import AccessTokenId
type RawAccessToken = str
@@ -10,6 +10,7 @@ from template_project.application.user.entity import UserId
AccessTokenId = NewType("AccessTokenId", UUID)
@to_entity
class AccessToken(Entity[AccessTokenId]):
user_id: UserId
@@ -32,17 +33,12 @@ class AccessToken(Entity[AccessTokenId]):
revoked=False,
)
def ensure_expired(self) -> None:
if self.expired_predicate():
raise AccessTokenExpiredError(id_=self.id)
def expired_predicate(self) -> bool:
return (
(self.expires_in < datetime.now(tz=UTC))
or self.revoked
or self.deleted_at is not None
)
return (self.expires_in < datetime.now(tz=UTC)) or self.revoked or self.deleted_at is not None
def revoke(self) -> None:
self.revoked = True
@@ -7,7 +7,7 @@ from typing import dataclass_transform
eq_default=False,
kw_only_default=True,
)
def to_data_structure[_InteractorClsT](interactor_cls: type[_InteractorClsT]) -> type[_InteractorClsT]:
def to_data_structure[InteractorClsT](interactor_cls: type[InteractorClsT]) -> type[InteractorClsT]:
return dataclass(
kw_only=True,
eq=False,
@@ -1,20 +1,20 @@
from collections.abc import Hashable
from dataclasses import dataclass
from datetime import datetime
from typing import dataclass_transform, override
from typing import cast, dataclass_transform, override
from uuid import UUID
from template_project.application.common.errors import EntityAlreadyDeletedError
@dataclass_transform(kw_only_default=True)
def to_entity[_EntityCLsT](entity_cls: type[_EntityCLsT]) -> type[_EntityCLsT]:
def to_entity[EntityCLsT](entity_cls: type[EntityCLsT]) -> type[EntityCLsT]:
return dataclass(kw_only=True)(entity_cls)
@to_entity
class Entity[_EntityId: UUID](Hashable):
id: _EntityId
class Entity[EntityId: UUID](Hashable):
id: EntityId
created_at: datetime
deleted_at: datetime | None = None
@@ -25,7 +25,7 @@ class Entity[_EntityId: UUID](Hashable):
@override
def __eq__(self, other: object) -> bool:
if isinstance(other, Entity):
return self.id == other.id
return cast(bool, self.id == other.id)
return NotImplemented
@override
@@ -7,7 +7,7 @@ from typing import dataclass_transform
eq_default=False,
kw_only_default=True,
)
def to_interactor[_InteractorClsT](interactor_cls: type[_InteractorClsT]) -> type[_InteractorClsT]:
def to_interactor[InteractorClsT](interactor_cls: type[InteractorClsT]) -> type[InteractorClsT]:
return dataclass(
kw_only=True,
eq=False,
@@ -10,8 +10,5 @@ class UserDataGateway(Protocol):
raise NotImplementedError
@abstractmethod
async def exists_by_email(
self,
email: str
) -> bool:
async def exists_by_email(self, email: str) -> bool:
raise NotImplementedError
@@ -8,6 +8,7 @@ from template_project.application.common.entity import Entity, to_entity
UserId = NewType("UserId", UUID)
@to_entity
class User(Entity[UserId]):
email: str
@@ -1,4 +1,5 @@
from typing import override
from template_project.application.common.errors import ApplicationError, to_error
@@ -10,6 +11,7 @@ class UserWithEmailAlreadyExistsError(ApplicationError):
def __str__(self) -> str:
return f"User with the email={self.email!r} already exists"
@to_error
class UserUnauthorizedError(ApplicationError):
pass
@@ -11,6 +11,7 @@ class GetMeResponse:
id: UserId
email: str
response_converter = get_converter(User, GetMeResponse)
@@ -3,6 +3,7 @@ from datetime import timedelta
from pathlib import Path
from tomllib import loads
from typing import dataclass_transform
from adaptix import P, Retort, loader
from template_project.application.common.containers import SecretString
+8 -3
View File
@@ -1,16 +1,16 @@
import argparse
import asyncio
import sys
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
import sys
from typing import Final
import uvicorn
from dishka import AsyncContainer
from dishka.integrations.fastapi import setup_dishka
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from template_project.web_api.configuration import load_configuration
from template_project.web_api.ioc.make import make_ioc
@@ -35,11 +35,13 @@ LOG_CONFIG: Final = {
},
}
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
yield
await app.state.dishka_container.close()
def make_asgi_application(
ioc: AsyncContainer,
) -> FastAPI:
@@ -65,6 +67,7 @@ def make_asgi_application(
return app
def _main(
configuration_path: Path,
) -> None:
@@ -83,7 +86,8 @@ def _main(
def main() -> None:
if sys.platform == "win32":
from asyncio import WindowsSelectorEventLoopPolicy
from asyncio import WindowsSelectorEventLoopPolicy # noqa: PLC0415
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
arg_parser = argparse.ArgumentParser()
@@ -95,5 +99,6 @@ def main() -> None:
args = arg_parser.parse_args()
_main(args.configuration)
if __name__ == "__main__":
main()
@@ -1,4 +1,4 @@
from abc import abstractmethod
from typing import override
from fastapi import Request
@@ -11,8 +11,7 @@ from template_project.application.user.data_gateway import UserDataGateway
from template_project.application.user.entity import User
from template_project.application.user.errors import UserUnauthorizedError
TOKEN_TYPE = "Bearer"
TOKEN_TYPE = "Bearer" # noqa: S105
BEARER_SECTIONS = 2
AUTH_HEADER = "Authorization"
@@ -31,7 +30,7 @@ class WebApiIdentityProvider(IdentityProvider):
self._access_token_data_gateway = access_token_data_gateway
self._access_token_cryptographer = access_token_cryptographer
@abstractmethod
@override
async def get_current_user(self) -> User:
auth_tokn = self._request.headers[AUTH_HEADER]
@@ -1,4 +1,5 @@
from typing import AsyncIterable
from collections.abc import AsyncIterable
from dishka import Provider, Scope, provide
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, create_async_engine
@@ -1,6 +1,6 @@
import argon2
from cryptography.fernet import Fernet
from dishka import Provider, Scope, WithParents, provide, provide_all
from dishka import BaseScope, Provider, Scope, WithParents, provide, provide_all
from template_project.adapters.access_token.cryptographer import FernetAccessTokenCryptographer
from template_project.adapters.password_utils import ArgonPasswordHasher, ArgonPasswordVerifying
@@ -8,7 +8,7 @@ from template_project.web_api.configuration import AccessTokenConfiguration
class CryptographerProvider(Provider):
scope = Scope.APP
scope: BaseScope | None = Scope.APP
@provide
def argon_password_hasher(self) -> argon2.PasswordHasher:
@@ -1,4 +1,4 @@
from dishka import Provider, Scope, WithParents, provide, provide_all
from dishka import BaseScope, Provider, Scope, WithParents, provide, provide_all
from template_project.adapters.data_gateways.access_token import DefaultAccessTokenDataGateway
from template_project.adapters.data_gateways.user import DefaultUserDataGateway
@@ -6,7 +6,7 @@ from template_project.adapters.unit_of_work import DefaultUnitOfWork
class DataGatewayProvider(Provider):
scope = Scope.REQUEST
scope: BaseScope | None = Scope.REQUEST
unit_of_work = provide(WithParents[DefaultUnitOfWork])
data_gateways = provide_all(
+2 -2
View File
@@ -1,10 +1,10 @@
from dishka import Provider, Scope, WithParents, provide_all
from dishka import BaseScope, Provider, Scope, WithParents, provide_all
from template_project.adapters.access_token.factory import DefaultAccessTokenFactory
class FactoryProvider(Provider):
scope = Scope.APP
scope: BaseScope | None = Scope.APP
provides = provide_all(
WithParents[DefaultAccessTokenFactory],
@@ -1,10 +1,10 @@
from dishka import Provider, Scope, provide_all
from dishka import BaseScope, Provider, Scope, provide_all
from template_project.application.user.interactors.sign_up import UserSignUpInteractor
class InteractorProvider(Provider):
scope = Scope.REQUEST
scope: BaseScope | None = Scope.REQUEST
interactors = provide_all(
UserSignUpInteractor,
+7 -2
View File
@@ -1,11 +1,16 @@
from dishka import AsyncContainer, make_async_container
from dishka.integrations.fastapi import FastapiProvider
from template_project.web_api.configuration import AccessTokenConfiguration, Configuration, DatabaseConfiguration, ServerConfiguration
from template_project.web_api.configuration import (
AccessTokenConfiguration,
Configuration,
DatabaseConfiguration,
ServerConfiguration,
)
from template_project.web_api.ioc.cryptographer import CryptographerProvider
from template_project.web_api.ioc.data_gateway import DataGatewayProvider
from template_project.web_api.ioc.factory import FactoryProvider
from template_project.web_api.ioc.interactor import InteractorProvider
from template_project.web_api.ioc.cryptographer import CryptographerProvider
def make_ioc(configuration: Configuration) -> AsyncContainer:
+1 -3
View File
@@ -6,7 +6,6 @@ from pydantic import BaseModel, SecretStr
from template_project.application.common.containers import SecretString
from template_project.application.user.interactors.sign_up import UserSignUpInteractor
router = APIRouter(route_class=DishkaRoute)
@@ -25,8 +24,7 @@ async def sign_up(
interactor: FromDishka[UserSignUpInteractor],
) -> UserSignUpResponse:
response_interactor = await interactor.execute(
email=request.email,
password=SecretString(request.password.get_secret_value())
email=request.email, password=SecretString(request.password.get_secret_value())
)
return UserSignUpResponse(
access_token=response_interactor.access_token,