From 35f09a0fbdd71b13451951ed6232ee4a9517c03d Mon Sep 17 00:00:00 2001 From: Noloquideus Date: Tue, 12 May 2026 00:03:51 +0300 Subject: [PATCH] fix: delete keydb --- pyproject.toml | 1 - .../commands/create_kyc_command.py | 16 +- src/application/contracts/__init__.py | 1 - src/application/contracts/i_cache.py | 34 ---- src/infrastructure/cache/__init__.py | 5 - src/infrastructure/cache/client.py | 5 - src/infrastructure/cache/keydb_client.py | 55 ------ src/infrastructure/cache/remote_cache.py | 65 ------- src/infrastructure/config/settings.py | 17 +- src/main.py | 4 - src/presentation/decorators/cache.py | 45 ----- src/presentation/decorators/rate_limit.py | 171 ------------------ src/presentation/dependencies/cache.py | 28 --- src/presentation/dependencies/commands.py | 7 +- uv.lock | 11 -- 15 files changed, 16 insertions(+), 449 deletions(-) delete mode 100644 src/application/contracts/i_cache.py delete mode 100644 src/infrastructure/cache/__init__.py delete mode 100644 src/infrastructure/cache/client.py delete mode 100644 src/infrastructure/cache/keydb_client.py delete mode 100644 src/infrastructure/cache/remote_cache.py delete mode 100644 src/presentation/decorators/cache.py delete mode 100644 src/presentation/decorators/rate_limit.py delete mode 100644 src/presentation/dependencies/cache.py diff --git a/pyproject.toml b/pyproject.toml index 508c1bd..5f84600 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ dependencies = [ "pydantic-settings==2.12.0", "python-jose==3.5.0", "python-ulid==3.1.0", - "redis==7.2.0", "sqlalchemy==2.0.46", "uvloop==0.22.1; platform_system != 'Windows'", ] \ No newline at end of file diff --git a/src/application/commands/create_kyc_command.py b/src/application/commands/create_kyc_command.py index aa96a3f..12a7dc0 100644 --- a/src/application/commands/create_kyc_command.py +++ b/src/application/commands/create_kyc_command.py @@ -1,8 +1,7 @@ from __future__ import annotations from datetime import datetime,timedelta,timezone -import orjson from src.application.abstractions import IUnitOfWork -from src.application.contracts import IBeorgService,ICache,ILogger +from src.application.contracts import IBeorgService,ILogger from src.application.domain.dto import BeorgKycCreateResponse,BeorgKycResultResponse,KycSessionResponse from src.application.domain.exceptions import ApplicationException from src.application.services import ensure_adult,extract_personal_data,parse_birth_date @@ -18,12 +17,10 @@ class PassKycCommand: *, unit_of_work: IUnitOfWork, logger: ILogger, - cache: ICache, beorg_service: IBeorgService, ) -> None: self._unit_of_work = unit_of_work self._logger = logger - self._cache = cache self._beorg_service = beorg_service @@ -40,7 +37,6 @@ class PassKycCommand: expires_at=expires_at, error=result.error, ) - await self._cache.set(f'kyc:session:{user_id}',result.model_dump_json(),ttl=KYC_SESSION_TTL) self._logger.info(f'KYC started for user {user_id}') return result @@ -52,12 +48,10 @@ class CompleteKycCommand: *, unit_of_work: IUnitOfWork, logger: ILogger, - cache: ICache, beorg_service: IBeorgService, ) -> None: self._unit_of_work = unit_of_work self._logger = logger - self._cache = cache self._beorg_service = beorg_service @@ -87,7 +81,7 @@ class CompleteKycCommand: ensure_adult(birth_date) async with self._unit_of_work as unit_of_work: - user = await unit_of_work.user_repository.update_kyc_data( + await unit_of_work.user_repository.update_kyc_data( user_id=user_id, first_name=personal_data.first_name, last_name=personal_data.last_name, @@ -104,17 +98,11 @@ class CompleteKycCommand: result_data=result.data, error=None, ) - await self._cache.set_user(user_id,user,ttl=KYC_SESSION_TTL) - await self._cache.delete(f'kyc:session:{user_id}') self._logger.info(f'KYC completed for user {user_id}') return result async def _get_session(self,user_id: str) -> BeorgKycCreateResponse: - raw = await self._cache.get(f'kyc:session:{user_id}') - if raw is not None: - return BeorgKycCreateResponse.model_validate(orjson.loads(raw)) - now = _utc_now() async with self._unit_of_work as unit_of_work: await unit_of_work.kyc_repository.expire_started_sessions(user_id=user_id,now=now) diff --git a/src/application/contracts/__init__.py b/src/application/contracts/__init__.py index 460f112..1d394a1 100644 --- a/src/application/contracts/__init__.py +++ b/src/application/contracts/__init__.py @@ -1,6 +1,5 @@ from src.application.contracts.i_logger import ILogger from src.application.contracts.i_jwt_service import IJwtService from src.application.contracts.i_csrf_service import ICsrfService -from src.application.contracts.i_cache import ICache from src.application.contracts.i_hash_service import IHashService from src.application.contracts.i_beorg_service import IBeorgService \ No newline at end of file diff --git a/src/application/contracts/i_cache.py b/src/application/contracts/i_cache.py deleted file mode 100644 index 7d59d8f..0000000 --- a/src/application/contracts/i_cache.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations -from abc import ABC, abstractmethod -from src.application.domain.entities.user import UserEntity - - -class ICache(ABC): - - @abstractmethod - async def set(self, key: str, value: str, ttl: int) -> bool: - raise NotImplementedError - - @abstractmethod - async def set_nx(self, key: str, value: str, ttl: int) -> bool: - raise NotImplementedError - - @abstractmethod - async def get(self, key: str) -> str | None: - raise NotImplementedError - - @abstractmethod - async def hget(self, key: str, field: str) -> str | None: - raise NotImplementedError - - @abstractmethod - async def delete(self, key: str) -> bool: - raise NotImplementedError - - @abstractmethod - async def get_user(self, user_id: str) -> dict | None: - raise NotImplementedError - - @abstractmethod - async def set_user(self, user_id: str, user: UserEntity, ttl: int = 300) -> None: - raise NotImplementedError \ No newline at end of file diff --git a/src/infrastructure/cache/__init__.py b/src/infrastructure/cache/__init__.py deleted file mode 100644 index 12bf9af..0000000 --- a/src/infrastructure/cache/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from src.infrastructure.cache.client import create_redis_client -from src.infrastructure.cache.keydb_client import KeydbCache -from src.infrastructure.cache.remote_cache import RemoteCache - -__all__ = ['create_redis_client', 'KeydbCache', 'RemoteCache'] diff --git a/src/infrastructure/cache/client.py b/src/infrastructure/cache/client.py deleted file mode 100644 index a84e66f..0000000 --- a/src/infrastructure/cache/client.py +++ /dev/null @@ -1,5 +0,0 @@ -from redis.asyncio import Redis - - -def create_redis_client(url: str) -> Redis: - return Redis.from_url(url,decode_responses=True) diff --git a/src/infrastructure/cache/keydb_client.py b/src/infrastructure/cache/keydb_client.py deleted file mode 100644 index 494c3e9..0000000 --- a/src/infrastructure/cache/keydb_client.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations -import orjson -from redis.asyncio.client import Redis -from src.application.contracts import ICache -from src.application.domain.entities.user import UserEntity - - -class KeydbCache(ICache): - USER_PREFIX = 'user:me' - - def __init__(self, redis_client: Redis): - self._r = redis_client - - async def set(self, key: str, value: str, ttl: int) -> bool: - return bool(await self._r.set(key, value, ex=ttl)) - - async def set_nx(self, key: str, value: str, ttl: int) -> bool: - return bool(await self._r.set(key, value, ex=ttl, nx=True)) - - async def get(self, key: str) -> str | None: - return await self._r.get(key) - - async def hget(self, key: str, field: str) -> str | None: - return await self._r.hget(key, field) - - async def delete(self, key: str) -> bool: - return (await self._r.delete(key)) > 0 - - async def get_user(self, user_id: str) -> dict | None: - raw = await self._r.get(f'{self.USER_PREFIX}:{user_id}') - if raw is None: - return None - return orjson.loads(raw) - - async def set_user(self, user_id: str, user: UserEntity, ttl: int = 300) -> None: - data = orjson.dumps({ - 'id': user.id, - 'email': user.email, - 'first_name': user.first_name, - 'middle_name': user.middle_name, - 'last_name': user.last_name, - 'birth_date': str(user.birth_date) if user.birth_date else None, - 'crypto_wallet': user.crypto_wallet, - 'phone': user.phone, - 'bik': user.bik, - 'account_number': user.account_number, - 'card_number': user.card_number, - 'inn': user.inn, - 'kyc_verified': user.kyc_verified, - 'is_deleted': user.is_deleted, - 'created_at': user.created_at.isoformat() if user.created_at else None, - 'updated_at': user.updated_at.isoformat() if user.updated_at else None, - 'kyc_verified_at': user.kyc_verified_at.isoformat() if user.kyc_verified_at else None, - }) - await self._r.set(f'{self.USER_PREFIX}:{user_id}', data, ex=ttl) diff --git a/src/infrastructure/cache/remote_cache.py b/src/infrastructure/cache/remote_cache.py deleted file mode 100644 index 173da4a..0000000 --- a/src/infrastructure/cache/remote_cache.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations -import orjson -from redis.asyncio.client import Redis -from src.application.contracts import ICache -from src.application.domain.entities.user import UserEntity - - -class RemoteCache(ICache): - - - USER_PREFIX = 'user:me' - - - def __init__(self,redis_client: Redis) -> None: - self._r = redis_client - - - async def set(self,key: str,value: str,ttl: int) -> bool: - return bool(await self._r.set(key,value,ex=ttl)) - - - async def set_nx(self,key: str,value: str,ttl: int) -> bool: - return bool(await self._r.set(key,value,ex=ttl,nx=True)) - - - async def get(self,key: str) -> str | None: - return await self._r.get(key) - - - async def hget(self,key: str,field: str) -> str | None: - return await self._r.hget(key,field) - - - async def delete(self,key: str) -> bool: - return (await self._r.delete(key)) > 0 - - - async def get_user(self,user_id: str) -> dict | None: - raw = await self._r.get(f'{self.USER_PREFIX}:{user_id}') - if raw is None: - return None - return orjson.loads(raw) - - - async def set_user(self,user_id: str,user: UserEntity,ttl: int = 300) -> None: - data = orjson.dumps({ - 'id': user.id, - 'email': user.email, - 'first_name': user.first_name, - 'middle_name': user.middle_name, - 'last_name': user.last_name, - 'birth_date': str(user.birth_date) if user.birth_date else None, - 'crypto_wallet': user.crypto_wallet, - 'phone': user.phone, - 'bik': user.bik, - 'account_number': user.account_number, - 'card_number': user.card_number, - 'inn': user.inn, - 'kyc_verified': user.kyc_verified, - 'is_deleted': user.is_deleted, - 'created_at': user.created_at.isoformat() if user.created_at else None, - 'updated_at': user.updated_at.isoformat() if user.updated_at else None, - 'kyc_verified_at': user.kyc_verified_at.isoformat() if user.kyc_verified_at else None, - }) - await self._r.set(f'{self.USER_PREFIX}:{user_id}',data,ex=ttl) diff --git a/src/infrastructure/config/settings.py b/src/infrastructure/config/settings.py index d5c87a1..a2e9bca 100644 --- a/src/infrastructure/config/settings.py +++ b/src/infrastructure/config/settings.py @@ -9,10 +9,10 @@ from src.infrastructure.vault import VaultClient class Settings(BaseSettings): model_config = SettingsConfigDict(env_file='.env',extra='ignore') _vault_beorg_secrets: dict[str,Any] = PrivateAttr(default_factory=dict) + _vault_database_secrets: dict[str,Any] = PrivateAttr(default_factory=dict) DOCS_USERNAME: str = 'admin' DOCS_PASSWORD: str = 'admin' - KEYDB_URL: str = 'redis://localhost:6379/0' VAULT_ADDR: str = 'https://corp.vault.elcsa.ru' VAULT_ROLE_ID: str = '' VAULT_SECRET_ID: str = '' @@ -30,7 +30,6 @@ class Settings(BaseSettings): JWT_ALGORITHM: str = 'RS256' JWT_AUDIENCE: str | None = None JWT_ISSUER: str | None = None - DATABASE_URL: str = 'postgresql+asyncpg://postgres:postgres@localhost:5432/kyc' DATABASE_POOL_SIZE: int = 5 DATABASE_MAX_OVERFLOW: int = 10 DATABASE_POOL_TIMEOUT: int = 30 @@ -66,6 +65,11 @@ class Settings(BaseSettings): ]) + @property + def DATABASE_URL(self) -> str: + return self._get_vault_secret(self._vault_database_secrets,'DATABASE_URL','database_url') + + @property def BEORG_PROJECT_ID(self) -> str: return self._get_beorg_secret('project_id','BEORG_PROJECT_ID') @@ -82,8 +86,12 @@ class Settings(BaseSettings): def _get_beorg_secret(self,*keys: str) -> str: + return self._get_vault_secret(self._vault_beorg_secrets,*keys) + + + def _get_vault_secret(self,secrets: dict[str,Any],*keys: str) -> str: for key in keys: - value = self._vault_beorg_secrets.get(key) + value = secrets.get(key) if value is not None: return str(value) return '' @@ -101,6 +109,7 @@ class Settings(BaseSettings): mount_point=self.VAULT_MOUNT_POINT, ) object.__setattr__(self,'_vault_beorg_secrets',client.read_many(self.VAULT_BEORG_SECRET_PATH)) + object.__setattr__(self,'_vault_database_secrets',client.read_many(self.VAULT_DATABASE_SECRET_PATH)) secrets = client.read_many( self.VAULT_BEORG_SECRET_PATH, self.VAULT_DATABASE_SECRET_PATH, @@ -108,7 +117,7 @@ class Settings(BaseSettings): self.VAULT_DOCS_SECRET_PATH, ) for field in type(self).model_fields: - if field.startswith('VAULT_') or field == 'KEYDB_URL': + if field.startswith('VAULT_'): continue value = secrets.get(field,secrets.get(field.lower())) if value is None: diff --git a/src/main.py b/src/main.py index eee16dd..a757e8b 100644 --- a/src/main.py +++ b/src/main.py @@ -8,7 +8,6 @@ from fastapi.responses import HTMLResponse from fastapi.security import HTTPBasic, HTTPBasicCredentials from src.application.domain.enums import LogFormat,LogLevel from src.application.domain.exceptions import ApplicationException -from src.infrastructure.cache import create_redis_client from src.infrastructure.config.settings import get_settings from src.infrastructure.vault import JwtKeyStore, start_jwt_keys_scheduler from src.infrastructure.utils import generate_instance_id @@ -42,8 +41,6 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: logger.set_instance_id(instance_id) logger.info(f'Users service instance started with id {instance_id}') - app.state.redis = create_redis_client(settings.KEYDB_URL) - jwt_store = JwtKeyStore( vault_addr=settings.VAULT_ADDR, vault_role_id=settings.VAULT_ROLE_ID, @@ -61,7 +58,6 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: app.state.jwt_key_store = jwt_store app.state.jwt_keys_scheduler = jwt_scheduler yield - await app.state.redis.aclose() logger.info(f'Users service instance ended with id {instance_id}') diff --git a/src/presentation/decorators/cache.py b/src/presentation/decorators/cache.py deleted file mode 100644 index d267f7f..0000000 --- a/src/presentation/decorators/cache.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations -import functools -from typing import Any,Awaitable,Callable -from fastapi import Request -from fastapi.responses import ORJSONResponse -from src.presentation.dependencies.cache import get_cache_remote -from src.presentation.dependencies.logger import get_logger - - -def cached(*, prefix: str) -> Callable: - - - def decorator(func: Callable[..., Awaitable[Any]]): - @functools.wraps(func) - async def wrapper(*args: Any, **kwargs: Any) -> Any: - logger = get_logger() - - request = kwargs.get('request') - if not isinstance(request, Request): - for a in args: - if isinstance(a, Request): - request = a - break - - auth = kwargs.get('auth') - user_id = getattr(auth, 'user_id', None) if auth else None - - if request is None or user_id is None: - return await func(*args, **kwargs) - - cache_key = f'{prefix}:{user_id}' - - try: - cache = get_cache_remote(request) - hit = await cache.get_user(user_id) - if hit is not None: - logger.debug(f'Cache hit key={cache_key}') - return ORJSONResponse(status_code=200, content=hit) - except Exception as e: - logger.warning(f'Cache read failed key={cache_key} error={e}') - - return await func(*args, **kwargs) - - return wrapper - return decorator diff --git a/src/presentation/decorators/rate_limit.py b/src/presentation/decorators/rate_limit.py deleted file mode 100644 index 6ff0094..0000000 --- a/src/presentation/decorators/rate_limit.py +++ /dev/null @@ -1,171 +0,0 @@ -from __future__ import annotations -import functools -import inspect -import hashlib -from typing import Any, Awaitable, Callable, Literal, Optional, Protocol, runtime_checkable -from fastapi import Request -from redis.asyncio.client import Redis -from src.application.contracts import ILogger -from src.application.domain.exceptions import ApplicationException -from src.infrastructure.logger import get_logger -from src.presentation.dependencies import get_redis - - -def _find_request(args: tuple[Any, ...], kwargs: dict[str, Any]) -> Request: - req = kwargs.get('request') - if isinstance(req, Request): - return req - for a in args: - if isinstance(a, Request): - return a - raise RuntimeError('rate_limit decorator requires fastapi.Request argument') - - -def _client_ip(request: Request) -> str: - xff = request.headers.get('x-forwarded-for') - if xff: - return xff.split(',')[0].strip() - if request.client: - return request.client.host - return 'unknown' - - -_LUA_INCR_EXPIRE_TTL = ''' -local key = KEYS[1] -local window = tonumber(ARGV[1]) - -local current = redis.call('INCR', key) -if current == 1 then - redis.call('EXPIRE', key, window) -end - -local ttl = redis.call('TTL', key) -return { current, ttl } -''' - - -Scope = Literal['ip', 'device', 'user', 'key'] - - -@runtime_checkable -class KeyBuilder1(Protocol): - def __call__(self, request: Request) -> str: ... - - -@runtime_checkable -class KeyBuilder3(Protocol): - def __call__(self, request: Request, args: tuple[Any, ...], kwargs: dict[str, Any]) -> str: ... - - -KeyBuilder = KeyBuilder1 | KeyBuilder3 - - -def _call_key_builder(builder: KeyBuilder, request: Request, args: tuple[Any, ...], kwargs: dict[str, Any]) -> str: - try: - sig = inspect.signature(builder) - if len(sig.parameters) >= 3: - return builder(request, args, kwargs) - return builder(request) - except Exception as e: - try: - return builder(request, args, kwargs) - except Exception: - raise e - -def _email_rl_key(request: Request, args: tuple[Any, ...], kwargs: dict[str, Any]) -> str: - - body = kwargs.get('body') - if body is None and args: - for a in args: - if hasattr(a, 'email'): - body = a - break - - email = (getattr(body, 'email', '') or '').strip().lower() - if not email: - email = _client_ip(request) - - digest = hashlib.sha256(email.encode('utf-8')).hexdigest()[:24] - return f'email:{digest}' - -def rate_limit( - *, - limit: int, - window_seconds: int, - scope: Scope = 'ip', - key_prefix: str = 'rl', - key_builder: Optional[KeyBuilder] = None, - fail_open: bool = True, -) -> Callable[[Callable[..., Awaitable[Any]]], Callable[..., Awaitable[Any]]]: - - if limit <= 0: - raise ValueError('rate_limit: limit must be > 0') - if window_seconds <= 0: - raise ValueError('rate_limit: window_seconds must be > 0') - if scope == 'key' and not key_builder: - raise ValueError('rate_limit: scope="key" requires key_builder') - - def decorator(func: Callable[..., Awaitable[Any]]): - @functools.wraps(func) - async def wrapper(*args: Any, **kwargs: Any): - request = _find_request(args, kwargs) - logger: ILogger = get_logger() - - if scope == 'ip': - ident = _client_ip(request) - elif scope == 'device': - ident = request.cookies.get('device_id') or _client_ip(request) - elif scope == 'user': - user = getattr(request.state, 'user', None) - user_id = getattr(user, 'id', None) if user else None - ident = str(user_id) if user_id else _client_ip(request) - else: - try: - ident = _call_key_builder(key_builder, request, args, kwargs) # type: ignore[arg-type] - except Exception as e: - logger.error(f'RateLimit key_builder failed error={str(e)}') - raise ApplicationException(500, 'Rate limiter key_builder failed') - - route = request.url.path - method = request.method - redis_key = f'{key_prefix}:{scope}:{method}:{route}:{ident}' - - logger.debug(f'RateLimit check key={redis_key} limit={limit} window={window_seconds}') - - try: - redis: Redis = get_redis(request) - - result = await redis.eval( - _LUA_INCR_EXPIRE_TTL, - 1, - redis_key, - str(window_seconds), - ) - - count = int(result[0]) - ttl_raw = int(result[1]) if result and len(result) > 1 else window_seconds - ttl = window_seconds if ttl_raw < 0 else ttl_raw - - except Exception as e: - logger.error(f'RateLimit redis failure key={redis_key} error={str(e)}') - - if fail_open: - logger.warning(f'RateLimit fail-open activated key={redis_key}') - return await func(*args, **kwargs) - - raise ApplicationException(503, 'Rate limiter unavailable') - - if count > limit: - retry_after = max(ttl, 0) - logger.warning(f'RateLimit exceeded key={redis_key} count={count} limit={limit} retry_after={retry_after}') - raise ApplicationException( - status_code=429, - message='Too Many Requests', - headers={'Retry-After': str(retry_after)}, - ) - - logger.debug(f'RateLimit passed key={redis_key} count={count}') - return await func(*args, **kwargs) - - return wrapper - return decorator \ No newline at end of file diff --git a/src/presentation/dependencies/cache.py b/src/presentation/dependencies/cache.py deleted file mode 100644 index e57f250..0000000 --- a/src/presentation/dependencies/cache.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - - -from fastapi import Depends,Request -from redis.asyncio.client import Redis - -from src.application.contracts import ICache -from src.infrastructure.cache import KeydbCache - - -def get_redis_remote(request: Request) -> Redis: - return request.app.state.redis - - -def get_redis(request: Request) -> Redis: - return request.app.state.redis - - -def get_cache_remote(redis_client: Redis = Depends(get_redis_remote)) -> ICache: - return KeydbCache(redis_client) - - -def get_remote_cache(redis_client: Redis = Depends(get_redis_remote)) -> ICache: - return KeydbCache(redis_client) - - -def get_cache(redis_client: Redis = Depends(get_redis)) -> ICache: - return KeydbCache(redis_client) diff --git a/src/presentation/dependencies/commands.py b/src/presentation/dependencies/commands.py index 2734575..8f96aa5 100644 --- a/src/presentation/dependencies/commands.py +++ b/src/presentation/dependencies/commands.py @@ -2,10 +2,9 @@ from __future__ import annotations from fastapi import Depends from src.application.abstractions import IUnitOfWork from src.application.commands import CompleteKycCommand,GetKycSessionCommand,PassKycCommand -from src.application.contracts import IBeorgService,ICache,ILogger +from src.application.contracts import IBeorgService,ILogger from src.infrastructure.config import settings from src.infrastructure.beorg import BeorgService -from src.presentation.dependencies.cache import get_cache from src.presentation.dependencies.logger import get_logger from src.presentation.dependencies.unit_of_work import get_unit_of_work @@ -23,13 +22,11 @@ def get_beorg_service() -> IBeorgService: def get_pass_kyc_command( logger: ILogger = Depends(get_logger), unit_of_work: IUnitOfWork = Depends(get_unit_of_work), - cache: ICache = Depends(get_cache), beorg_service: IBeorgService = Depends(get_beorg_service), ) -> PassKycCommand: return PassKycCommand( unit_of_work=unit_of_work, logger=logger, - cache=cache, beorg_service=beorg_service, ) @@ -45,12 +42,10 @@ def get_kyc_session_command( def get_complete_kyc_command( logger: ILogger = Depends(get_logger), unit_of_work: IUnitOfWork = Depends(get_unit_of_work), - cache: ICache = Depends(get_cache), beorg_service: IBeorgService = Depends(get_beorg_service), ) -> CompleteKycCommand: return CompleteKycCommand( unit_of_work=unit_of_work, logger=logger, - cache=cache, beorg_service=beorg_service, ) \ No newline at end of file diff --git a/uv.lock b/uv.lock index 0cfaa29..7ac1e2d 100644 --- a/uv.lock +++ b/uv.lock @@ -393,7 +393,6 @@ dependencies = [ { name = "pydantic-settings" }, { name = "python-jose" }, { name = "python-ulid" }, - { name = "redis" }, { name = "sqlalchemy" }, { name = "uvloop", marker = "sys_platform != 'win32'" }, ] @@ -414,7 +413,6 @@ requires-dist = [ { name = "pydantic-settings", specifier = "==2.12.0" }, { name = "python-jose", specifier = "==3.5.0" }, { name = "python-ulid", specifier = "==3.1.0" }, - { name = "redis", specifier = "==7.2.0" }, { name = "sqlalchemy", specifier = "==2.0.46" }, { name = "uvloop", marker = "sys_platform != 'win32'", specifier = "==0.22.1" }, ] @@ -593,15 +591,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6c/a0/4ed6632b70a52de845df056654162acdebaf97c20e3212c559ac43e7216e/python_ulid-3.1.0-py3-none-any.whl", hash = "sha256:e2cdc979c8c877029b4b7a38a6fba3bc4578e4f109a308419ff4d3ccf0a46619", size = 11577, upload-time = "2025-08-18T16:09:25.047Z" }, ] -[[package]] -name = "redis" -version = "7.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/32/6fac13a11e73e1bc67a2ae821a72bfe4c2d8c4c48f0267e4a952be0f1bae/redis-7.2.0.tar.gz", hash = "sha256:4dd5bf4bd4ae80510267f14185a15cba2a38666b941aff68cccf0256b51c1f26", size = 4901247, upload-time = "2026-02-16T17:16:22.797Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/cf/f6180b67f99688d83e15c84c5beda831d1d341e95872d224f87ccafafe61/redis-7.2.0-py3-none-any.whl", hash = "sha256:01f591f8598e483f1842d429e8ae3a820804566f1c73dca1b80e23af9fba0497", size = 394898, upload-time = "2026-02-16T17:16:20.693Z" }, -] - [[package]] name = "requests" version = "2.33.1"