Refactor code for improved readability and consistency
Test / test (push) Successful in 15s

- Reformatted function signatures in `organization_service.py` and `task_service.py` for better alignment.
- Updated import statements across multiple files for consistency and organization.
- Enhanced test files by improving formatting and ensuring consistent use of async session factories.
- Added type hints and improved type safety in various service and test files.
- Adjusted `pyproject.toml` to include configuration for isort, mypy, and ruff for better code quality checks.
- Cleaned up unused imports and organized existing ones in several test files.
This commit is contained in:
Artem Kashaev
2025-12-01 16:18:03 +05:00
parent eecb74c523
commit 5fcb574aca
62 changed files with 765 additions and 476 deletions
+18 -8
View File
@@ -1,17 +1,18 @@
"""Redis cache utilities and availability tracking."""
from __future__ import annotations
import asyncio
import json
import logging
from typing import Any, Awaitable, Callable, Optional
from collections.abc import Awaitable, Callable
from typing import Any
import redis.asyncio as redis
from app.core.config import settings
from redis.asyncio.client import Redis
from redis.exceptions import RedisError
from app.core.config import settings
logger = logging.getLogger(__name__)
@@ -44,7 +45,9 @@ class RedisCacheManager:
async with self._lock:
if self._client is not None:
return
self._client = redis.from_url(settings.redis_url, encoding="utf-8", decode_responses=False)
self._client = redis.from_url(
settings.redis_url, encoding="utf-8", decode_responses=False
)
await self._refresh_availability()
async def shutdown(self) -> None:
@@ -59,7 +62,9 @@ class RedisCacheManager:
return
async with self._lock:
if self._client is None:
self._client = redis.from_url(settings.redis_url, encoding="utf-8", decode_responses=False)
self._client = redis.from_url(
settings.redis_url, encoding="utf-8", decode_responses=False
)
await self._refresh_availability()
async def _refresh_availability(self) -> None:
@@ -95,7 +100,7 @@ async def shutdown_cache() -> None:
await cache_manager.shutdown()
def get_cache_client() -> Optional[Redis]:
def get_cache_client() -> Redis | None:
"""Expose the active Redis client for dependency injection."""
return cache_manager.get_client()
@@ -113,12 +118,17 @@ async def read_json(client: Redis, key: str) -> Any | None:
cache_manager.mark_available()
try:
return json.loads(raw.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc: # pragma: no cover - malformed payloads
except (
UnicodeDecodeError,
json.JSONDecodeError,
) as exc: # pragma: no cover - malformed payloads
logger.warning("Discarding malformed cache entry %s: %s", key, exc)
return None
async def write_json(client: Redis, key: str, value: Any, ttl_seconds: int, backoff_ms: int) -> None:
async def write_json(
client: Redis, key: str, value: Any, ttl_seconds: int, backoff_ms: int
) -> None:
"""Serialize data to JSON and store it with TTL using retry/backoff."""
payload = json.dumps(value, separators=(",", ":"), ensure_ascii=True).encode("utf-8")
+7 -2
View File
@@ -1,4 +1,5 @@
"""Application settings using Pydantic Settings."""
from pydantic import Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -15,7 +16,9 @@ class Settings(BaseSettings):
db_port: int = Field(default=5432, description="Database port")
db_name: str = Field(default="test_task_crm", description="Database name")
db_user: str = Field(default="postgres", description="Database user")
db_password: SecretStr = Field(default=SecretStr("postgres"), description="Database user password")
db_password: SecretStr = Field(
default=SecretStr("postgres"), description="Database user password"
)
database_url_override: str | None = Field(
default=None,
alias="DATABASE_URL",
@@ -28,7 +31,9 @@ class Settings(BaseSettings):
refresh_token_expire_days: int = 7
redis_enabled: bool = Field(default=False, description="Toggle Redis-backed cache usage")
redis_url: str = Field(default="redis://localhost:6379/0", description="Redis connection URL")
analytics_cache_ttl_seconds: int = Field(default=120, ge=1, description="TTL for cached analytics responses")
analytics_cache_ttl_seconds: int = Field(
default=120, ge=1, description="TTL for cached analytics responses"
)
analytics_cache_backoff_ms: int = Field(
default=200,
ge=0,
+2 -2
View File
@@ -1,11 +1,11 @@
"""Database utilities for async SQLAlchemy engine and sessions."""
from __future__ import annotations
from collections.abc import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from app.core.config import settings
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
engine = create_async_engine(settings.database_url, echo=settings.sqlalchemy_echo)
AsyncSessionMaker = async_sessionmaker(bind=engine, expire_on_commit=False)
+2 -1
View File
@@ -1,11 +1,12 @@
"""Middleware that logs cache availability transitions."""
from __future__ import annotations
import logging
from starlette.types import ASGIApp, Receive, Scope, Send
from app.core.cache import cache_manager
from app.core.config import settings
from starlette.types import ASGIApp, Receive, Scope, Send
logger = logging.getLogger(__name__)
+4 -3
View File
@@ -1,13 +1,14 @@
"""Security helpers for hashing passwords and issuing JWT tokens."""
from __future__ import annotations
from collections.abc import Mapping
from datetime import datetime, timedelta, timezone
from typing import Any, Mapping
from typing import Any
import jwt
from passlib.context import CryptContext # type: ignore
from app.core.config import settings
from passlib.context import CryptContext # type: ignore
class PasswordHasher: