fix: delte unused

This commit is contained in:
2026-05-11 20:05:07 +03:00
parent f00551b2d1
commit 8be49b039f
13 changed files with 7 additions and 272 deletions

View File

@@ -11,7 +11,6 @@ dependencies = [
"dotenv==0.9.9", "dotenv==0.9.9",
"email-validator==2.3.0", "email-validator==2.3.0",
"fastapi==0.128.7", "fastapi==0.128.7",
"faststream[rabbit]==0.6.6",
"granian==2.6.1", "granian==2.6.1",
"hvac==2.4.0", "hvac==2.4.0",
"itsdangerous==2.2.0", "itsdangerous==2.2.0",

View File

@@ -1,9 +1,8 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime,timedelta,timezone from datetime import datetime,timedelta,timezone
import orjson import orjson
from ulid import ULID
from src.application.abstractions import IUnitOfWork from src.application.abstractions import IUnitOfWork
from src.application.contracts import IBeorgService,ICache,ILogger,IQueueMessanger from src.application.contracts import IBeorgService,ICache,ILogger
from src.application.domain.dto import BeorgKycCreateResponse,BeorgKycResultResponse,KycSessionResponse from src.application.domain.dto import BeorgKycCreateResponse,BeorgKycResultResponse,KycSessionResponse
from src.application.domain.exceptions import ApplicationException from src.application.domain.exceptions import ApplicationException
from src.application.services import ensure_adult,extract_personal_data,parse_birth_date from src.application.services import ensure_adult,extract_personal_data,parse_birth_date
@@ -55,15 +54,11 @@ class CompleteKycCommand:
logger: ILogger, logger: ILogger,
cache: ICache, cache: ICache,
beorg_service: IBeorgService, beorg_service: IBeorgService,
queue_messanger: IQueueMessanger,
verified_queue: str,
) -> None: ) -> None:
self._unit_of_work = unit_of_work self._unit_of_work = unit_of_work
self._logger = logger self._logger = logger
self._cache = cache self._cache = cache
self._beorg_service = beorg_service self._beorg_service = beorg_service
self._queue_messanger = queue_messanger
self._verified_queue = verified_queue
async def __call__(self,user_id: str) -> BeorgKycResultResponse: async def __call__(self,user_id: str) -> BeorgKycResultResponse:
@@ -111,21 +106,6 @@ class CompleteKycCommand:
) )
await self._cache.set_user(user_id,user,ttl=KYC_SESSION_TTL) await self._cache.set_user(user_id,user,ttl=KYC_SESSION_TTL)
await self._cache.delete(f'kyc:session:{user_id}') await self._cache.delete(f'kyc:session:{user_id}')
await self._queue_messanger.publish_to_queue(
self._verified_queue,
{
'user_id': user_id,
'kyc_verified': True,
'first_name': user.first_name,
'last_name': user.last_name,
'middle_name': user.middle_name,
'birth_date': str(user.birth_date) if user.birth_date else None,
'inn': user.inn,
'kyc_verified_at': user.kyc_verified_at.isoformat() if user.kyc_verified_at else None,
},
message_id=str(ULID()),
correlation_id=user_id,
)
self._logger.info(f'KYC completed for user {user_id}') self._logger.info(f'KYC completed for user {user_id}')
return result return result

View File

@@ -3,5 +3,4 @@ from src.application.contracts.i_jwt_service import IJwtService
from src.application.contracts.i_csrf_service import ICsrfService from src.application.contracts.i_csrf_service import ICsrfService
from src.application.contracts.i_cache import ICache from src.application.contracts.i_cache import ICache
from src.application.contracts.i_hash_service import IHashService from src.application.contracts.i_hash_service import IHashService
from src.application.contracts.i_queue_messanger import IQueueMessanger
from src.application.contracts.i_beorg_service import IBeorgService from src.application.contracts.i_beorg_service import IBeorgService

View File

@@ -1,40 +0,0 @@
from abc import ABC, abstractmethod
from typing import Mapping, Any
class IQueueMessanger(ABC):
@abstractmethod
async def connect(self) -> None:
raise NotImplementedError
@abstractmethod
async def close(self) -> None:
raise NotImplementedError
@abstractmethod
async def publish_to_queue(
self,
queue: str,
message: Any,
*,
persist: bool = True,
headers: Mapping[str, Any] | None = None,
correlation_id: str | None = None,
message_id: str | None = None,
) -> None:
raise NotImplementedError
@abstractmethod
async def publish(
self,
message: Any,
*,
exchange: str,
routing_key: str,
persist: bool = True,
headers: Mapping[str, Any] | None = None,
correlation_id: str | None = None,
message_id: str | None = None,
) -> None:
raise NotImplementedError

View File

@@ -22,18 +22,15 @@ class Settings(BaseSettings):
VAULT_BEORG_SECRET_PATH: str = 'beorg' VAULT_BEORG_SECRET_PATH: str = 'beorg'
VAULT_DATABASE_SECRET_PATH: str = 'database' VAULT_DATABASE_SECRET_PATH: str = 'database'
VAULT_JWT_SECRET_PATH: str = 'jwt' VAULT_JWT_SECRET_PATH: str = 'jwt'
VAULT_RABBIT_SECRET_PATH: str = 'rabbitmq'
VAULT_DOCS_SECRET_PATH: str = 'docs' VAULT_DOCS_SECRET_PATH: str = 'docs'
VAULT_JWT_KID_PATH: str = 'jwt/kid' VAULT_JWT_KID_PATH: str = 'jwt/kid'
VAULT_JWT_KIDS_PREFIX: str = 'jwt/kids' VAULT_JWT_KIDS_PREFIX: str = 'jwt/kids'
LOG_FORMAT: str = 'json'
LOG_LEVEL: str = 'INFO'
JWT_KEYS_REFRESH_SECONDS: int = 300 JWT_KEYS_REFRESH_SECONDS: int = 300
JWT_ALGORITHM: str = 'RS256' JWT_ALGORITHM: str = 'RS256'
JWT_AUDIENCE: str | None = None JWT_AUDIENCE: str | None = None
JWT_ISSUER: str | None = None JWT_ISSUER: str | None = None
RABBIT_URL: str = 'amqp://guest:guest@localhost:5672/'
RABBIT_CRYPTO_TRANSFER_COMPLETED_QUEUE: str = 'crypto_transfer_completed'
RABBIT_KYC_VERIFIED_QUEUE: str = 'kyc_verified'
RABBIT_PUBLISH_PERSIST: bool = True
DATABASE_URL: str = 'postgresql+asyncpg://postgres:postgres@localhost:5432/kyc' DATABASE_URL: str = 'postgresql+asyncpg://postgres:postgres@localhost:5432/kyc'
DATABASE_POOL_SIZE: int = 5 DATABASE_POOL_SIZE: int = 5
DATABASE_MAX_OVERFLOW: int = 10 DATABASE_MAX_OVERFLOW: int = 10
@@ -110,7 +107,6 @@ class Settings(BaseSettings):
self.VAULT_BEORG_SECRET_PATH, self.VAULT_BEORG_SECRET_PATH,
self.VAULT_DATABASE_SECRET_PATH, self.VAULT_DATABASE_SECRET_PATH,
self.VAULT_JWT_SECRET_PATH, self.VAULT_JWT_SECRET_PATH,
self.VAULT_RABBIT_SECRET_PATH,
self.VAULT_DOCS_SECRET_PATH, self.VAULT_DOCS_SECRET_PATH,
) )
for field in type(self).model_fields: for field in type(self).model_fields:

View File

@@ -1 +0,0 @@
from src.infrastructure.messanger.rabbit_client import RabbitClient

View File

@@ -1,72 +0,0 @@
from typing import Any, Mapping
from faststream.rabbit import RabbitBroker
from src.application.contracts import IQueueMessanger
from src.infrastructure.config import settings
class RabbitClient(IQueueMessanger):
def __init__(self) -> None:
self._broker = RabbitBroker(
settings.RABBIT_URL,
)
self._connected = False
async def connect(self) -> None:
if self._connected:
return
await self._broker.connect()
self._connected = True
async def close(self) -> None:
if not self._connected:
return
await self._broker.close()
self._connected = False
async def _ensure_connected(self) -> None:
if not self._connected:
await self.connect()
async def publish_to_queue(
self,
queue: str,
message: Any,
*,
persist: bool | None = None,
headers: Mapping[str, Any] | None = None,
correlation_id: str | None = None,
message_id: str | None = None,
) -> None:
await self._ensure_connected()
await self._broker.publish(
message,
queue=queue,
persist=settings.RABBIT_PUBLISH_PERSIST if persist is None else persist,
headers=headers,
correlation_id=correlation_id,
message_id=message_id,
)
async def publish(
self,
message: Any,
*,
exchange: str,
routing_key: str,
persist: bool | None = None,
headers: Mapping[str, Any] | None = None,
correlation_id: str | None = None,
message_id: str | None = None,
) -> None:
await self._ensure_connected()
await self._broker.publish(
message,
exchange=exchange,
routing_key=routing_key,
persist=settings.RABBIT_PUBLISH_PERSIST if persist is None else persist,
headers=headers,
correlation_id=correlation_id,
message_id=message_id,
)

View File

@@ -6,6 +6,7 @@ from fastapi import Depends, FastAPI, status
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from fastapi.security import HTTPBasic, HTTPBasicCredentials from fastapi.security import HTTPBasic, HTTPBasicCredentials
from src.application.domain.enums import LogFormat,LogLevel
from src.application.domain.exceptions import ApplicationException from src.application.domain.exceptions import ApplicationException
from src.infrastructure.cache import create_redis_client from src.infrastructure.cache import create_redis_client
from src.infrastructure.config.settings import get_settings from src.infrastructure.config.settings import get_settings
@@ -14,7 +15,6 @@ from src.infrastructure.utils import generate_instance_id
from src.infrastructure.logger import logger from src.infrastructure.logger import logger
from src.infrastructure.config import settings from src.infrastructure.config import settings
from src.presentation.handlers import application_exception_handler, unhandled_exception_handler from src.presentation.handlers import application_exception_handler, unhandled_exception_handler
from src.presentation.messaging import crypto_transfer_router
from src.presentation.middleware import TraceIDMiddleware, SecurityHeadersMiddleware from src.presentation.middleware import TraceIDMiddleware, SecurityHeadersMiddleware
from src.presentation.routing import kyc_router from src.presentation.routing import kyc_router
@@ -37,6 +37,8 @@ async def verify_credentials(credentials: HTTPBasicCredentials = Depends(securit
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
instance_id = generate_instance_id() instance_id = generate_instance_id()
logger.set_format(LogFormat(settings.LOG_FORMAT.lower()))
logger.set_min_level(LogLevel[settings.LOG_LEVEL.upper()])
logger.set_instance_id(instance_id) logger.set_instance_id(instance_id)
logger.info(f'Users service instance started with id {instance_id}') logger.info(f'Users service instance started with id {instance_id}')
@@ -74,10 +76,8 @@ app.add_exception_handler(ApplicationException, application_exception_handler)
app.add_exception_handler(Exception, unhandled_exception_handler) app.add_exception_handler(Exception, unhandled_exception_handler)
app.include_router(kyc_router) app.include_router(kyc_router)
app.include_router(crypto_transfer_router)
# Added middleware
app.add_middleware(TraceIDMiddleware, logger=logger) app.add_middleware(TraceIDMiddleware, logger=logger)
app.add_middleware( app.add_middleware(
SecurityHeadersMiddleware, SecurityHeadersMiddleware,

View File

@@ -2,12 +2,11 @@ from __future__ import annotations
from fastapi import Depends from fastapi import Depends
from src.application.abstractions import IUnitOfWork from src.application.abstractions import IUnitOfWork
from src.application.commands import CompleteKycCommand,GetKycSessionCommand,PassKycCommand from src.application.commands import CompleteKycCommand,GetKycSessionCommand,PassKycCommand
from src.application.contracts import IBeorgService,ICache,ILogger,IQueueMessanger from src.application.contracts import IBeorgService,ICache,ILogger
from src.infrastructure.config import settings from src.infrastructure.config import settings
from src.infrastructure.beorg import BeorgService from src.infrastructure.beorg import BeorgService
from src.presentation.dependencies.cache import get_cache from src.presentation.dependencies.cache import get_cache
from src.presentation.dependencies.logger import get_logger from src.presentation.dependencies.logger import get_logger
from src.presentation.dependencies.queue_messanger import get_rabbit
from src.presentation.dependencies.unit_of_work import get_unit_of_work from src.presentation.dependencies.unit_of_work import get_unit_of_work
@@ -48,13 +47,10 @@ def get_complete_kyc_command(
unit_of_work: IUnitOfWork = Depends(get_unit_of_work), unit_of_work: IUnitOfWork = Depends(get_unit_of_work),
cache: ICache = Depends(get_cache), cache: ICache = Depends(get_cache),
beorg_service: IBeorgService = Depends(get_beorg_service), beorg_service: IBeorgService = Depends(get_beorg_service),
queue_messanger: IQueueMessanger = Depends(get_rabbit),
) -> CompleteKycCommand: ) -> CompleteKycCommand:
return CompleteKycCommand( return CompleteKycCommand(
unit_of_work=unit_of_work, unit_of_work=unit_of_work,
logger=logger, logger=logger,
cache=cache, cache=cache,
beorg_service=beorg_service, beorg_service=beorg_service,
queue_messanger=queue_messanger,
verified_queue=settings.RABBIT_KYC_VERIFIED_QUEUE,
) )

View File

@@ -1,8 +0,0 @@
from functools import lru_cache
from src.application.contracts import IQueueMessanger
from src.infrastructure.messanger import RabbitClient
@lru_cache(maxsize=1)
def get_rabbit() -> IQueueMessanger:
return RabbitClient()

View File

@@ -1 +0,0 @@
from src.presentation.messaging.crypto_transfer import crypto_transfer_router

View File

@@ -1,39 +0,0 @@
from fastapi import Depends
import orjson
from faststream.rabbit.fastapi import RabbitMessage,RabbitRouter
from pydantic import BaseModel
from src.application.contracts import ILogger
from src.infrastructure.config import settings
from src.infrastructure.context_vars import trace_id_var
from src.presentation.dependencies.logger import get_logger
crypto_transfer_router=RabbitRouter(settings.RABBIT_URL)
class CryptoTransferCompletedMessage(BaseModel):
user_id: str
order_id: str
trace_id: str
message_id: str
@crypto_transfer_router.subscriber(settings.RABBIT_CRYPTO_TRANSFER_COMPLETED_QUEUE)
async def crypto_transfer_completed_handler(
msg_body: CryptoTransferCompletedMessage,
message: RabbitMessage,
logger: ILogger = Depends(get_logger),
) -> None:
trace_id=msg_body.trace_id
token=trace_id_var.set(trace_id)
try:
payload=msg_body.model_dump(mode='json')
logger.info(orjson.dumps({
'event':'crypto_transfer_completed_received',
'payload':payload,
'rabbit_message_id':message.message_id,
'rabbit_correlation_id':message.correlation_id,
},default=str).decode())
finally:
trace_id_var.reset(token)

74
uv.lock generated
View File

@@ -2,19 +2,6 @@ version = 1
revision = 3 revision = 3
requires-python = "==3.12.*" requires-python = "==3.12.*"
[[package]]
name = "aio-pika"
version = "9.6.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiormq" },
{ name = "yarl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/96/63/56354526f2e6e915c93bee6e4dedb35888fe82d6bc1a19f35f5a77e795ff/aio_pika-9.6.2.tar.gz", hash = "sha256:c49e9246080dc8ffa1bb0e4aca407bf3d8ad78c3ee3a93df88b68fe65d7a49b9", size = 70851, upload-time = "2026-03-22T19:03:20.878Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/25/05/256fa313f48bed075056d13593b92ce804be05d75f4f312be24edb82860a/aio_pika-9.6.2-py3-none-any.whl", hash = "sha256:2a5478af920d169795071c9c09c7542cd8cdece60438cf7804533dcbcce93b7f", size = 56269, upload-time = "2026-03-22T19:03:19.558Z" },
]
[[package]] [[package]]
name = "aiohappyeyeballs" name = "aiohappyeyeballs"
version = "2.6.1" version = "2.6.1"
@@ -58,19 +45,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" }, { url = "https://files.pythonhosted.org/packages/aa/ca/eadf6f9c8fa5e31d40993e3db153fb5ed0b11008ad5d9de98a95045bed84/aiohttp-3.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:110e448e02c729bcebb18c60b9214a87ba33bac4a9fa5e9a5f139938b56c6cb1", size = 460446, upload-time = "2026-03-31T21:58:10.945Z" },
] ]
[[package]]
name = "aiormq"
version = "6.9.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pamqp" },
{ name = "yarl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6c/0e/db90154d52d399108903fe603e5110a533c42065180265dd003788264080/aiormq-6.9.4.tar.gz", hash = "sha256:0e7c01b662804e1cc7ace9a17794e8c1192a27fc2afa96162362a6e61ae8e8ef", size = 49232, upload-time = "2026-03-23T09:18:19.493Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/6c/48/1ce3773f392f02ceda37aee168fade9d725483a9592c202d06044cd093ff/aiormq-6.9.4-py3-none-any.whl", hash = "sha256:726a8586695e863fba68cf88842065ab12348c9438dcebdfc9d0bddaf6083277", size = 32166, upload-time = "2026-03-23T09:18:17.523Z" },
]
[[package]] [[package]]
name = "aiosignal" name = "aiosignal"
version = "1.4.0" version = "1.4.0"
@@ -290,24 +264,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" },
] ]
[[package]]
name = "fast-depends"
version = "3.0.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f8/6d/787a21ca8043a8fdb737cf28f645e94a46fc30b44a31de54573299156bad/fast_depends-3.0.8.tar.gz", hash = "sha256:896b16f79a512b6ea1df721b0aa1708a192a06f964be6597e01fcf5412559101", size = 18382, upload-time = "2026-03-02T19:54:28.649Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1d/1d/e4843e4eeb65f51447b8c22d200d12d8f94f27c97e77bb7162515cc8d61f/fast_depends-3.0.8-py3-none-any.whl", hash = "sha256:4c52c8a3907bca46d43e70e4364d6d016872d9a3aae4bc0c1c85e72e0a6a21c7", size = 25507, upload-time = "2026-03-02T19:54:27.594Z" },
]
[package.optional-dependencies]
pydantic = [
{ name = "pydantic" },
]
[[package]] [[package]]
name = "fastapi" name = "fastapi"
version = "0.128.7" version = "0.128.7"
@@ -324,25 +280,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/af/1a/f983b45661c79c31be575c570d46c437a5409b67a939c1b3d8d6b3ed7a7f/fastapi-0.128.7-py3-none-any.whl", hash = "sha256:6bd9bd31cb7047465f2d3fa3ba3f33b0870b17d4eaf7cdb36d1576ab060ad662", size = 103630, upload-time = "2026-02-10T12:26:39.414Z" }, { url = "https://files.pythonhosted.org/packages/af/1a/f983b45661c79c31be575c570d46c437a5409b67a939c1b3d8d6b3ed7a7f/fastapi-0.128.7-py3-none-any.whl", hash = "sha256:6bd9bd31cb7047465f2d3fa3ba3f33b0870b17d4eaf7cdb36d1576ab060ad662", size = 103630, upload-time = "2026-02-10T12:26:39.414Z" },
] ]
[[package]]
name = "faststream"
version = "0.6.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
{ name = "fast-depends", extra = ["pydantic"] },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a6/cc/26deefd97a3d51205554d4fe69ffc2a9144515cda20cb7185be27e11166e/faststream-0.6.6.tar.gz", hash = "sha256:de87502e22db0372131165221728c6993b29d42ba29aaaa0a27d1249803f2ddd", size = 302712, upload-time = "2026-02-03T18:08:35.747Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ff/17/169728098799d4f5c4978f9b83d2dc41541eee02ec8547149a085acf11dd/faststream-0.6.6-py3-none-any.whl", hash = "sha256:4aca70628b526d8e27771f1f8edf9cd0a80a62f335a2721ddbbc863e6098f269", size = 507654, upload-time = "2026-02-03T18:08:34.347Z" },
]
[package.optional-dependencies]
rabbit = [
{ name = "aio-pika" },
]
[[package]] [[package]]
name = "frozenlist" name = "frozenlist"
version = "1.8.0" version = "1.8.0"
@@ -449,7 +386,6 @@ dependencies = [
{ name = "dotenv" }, { name = "dotenv" },
{ name = "email-validator" }, { name = "email-validator" },
{ name = "fastapi" }, { name = "fastapi" },
{ name = "faststream", extra = ["rabbit"] },
{ name = "granian" }, { name = "granian" },
{ name = "hvac" }, { name = "hvac" },
{ name = "itsdangerous" }, { name = "itsdangerous" },
@@ -471,7 +407,6 @@ requires-dist = [
{ name = "dotenv", specifier = "==0.9.9" }, { name = "dotenv", specifier = "==0.9.9" },
{ name = "email-validator", specifier = "==2.3.0" }, { name = "email-validator", specifier = "==2.3.0" },
{ name = "fastapi", specifier = "==0.128.7" }, { name = "fastapi", specifier = "==0.128.7" },
{ name = "faststream", extras = ["rabbit"], specifier = "==0.6.6" },
{ name = "granian", specifier = "==2.6.1" }, { name = "granian", specifier = "==2.6.1" },
{ name = "hvac", specifier = "==2.4.0" }, { name = "hvac", specifier = "==2.4.0" },
{ name = "itsdangerous", specifier = "==2.2.0" }, { name = "itsdangerous", specifier = "==2.2.0" },
@@ -534,15 +469,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" }, { url = "https://files.pythonhosted.org/packages/68/40/c2051bd19fc467610fed469dc29e43ac65891571138f476834ca192bc290/orjson-3.11.7-cp312-cp312-win_arm64.whl", hash = "sha256:26c3b9132f783b7d7903bf1efb095fed8d4a3a85ec0d334ee8beff3d7a4749d5", size = 126089, upload-time = "2026-02-02T15:38:05.297Z" },
] ]
[[package]]
name = "pamqp"
version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/fb/62/35bbd3d3021e008606cd0a9532db7850c65741bbf69ac8a3a0d8cfeb7934/pamqp-3.3.0.tar.gz", hash = "sha256:40b8795bd4efcf2b0f8821c1de83d12ca16d5760f4507836267fd7a02b06763b", size = 30993, upload-time = "2024-01-12T20:37:25.085Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ac/8d/c1e93296e109a320e508e38118cf7d1fc2a4d1c2ec64de78565b3c445eb5/pamqp-3.3.0-py2.py3-none-any.whl", hash = "sha256:c901a684794157ae39b52cbf700db8c9aae7a470f13528b9d7b4e5f7202f8eb0", size = 33848, upload-time = "2024-01-12T20:37:21.359Z" },
]
[[package]] [[package]]
name = "propcache" name = "propcache"
version = "0.4.1" version = "0.4.1"