- 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:
+18
-8
@@ -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
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user