initialize Redis integration, logging enhancements, and Telegram bot setup

This commit is contained in:
ruslangilfanov 2025-08-10 13:30:28 +03:00
parent f153a9825f
commit 9747c9e9b0
No known key found for this signature in database
19 changed files with 888 additions and 12 deletions

View File

@ -8,18 +8,27 @@ authors = [
] ]
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"aiogram>=3.21.0",
"aiogram-dialog>=2.4.0",
"aiogtts>=1.1.1", "aiogtts>=1.1.1",
"alembic>=1.16.1", "alembic>=1.16.1",
"asyncpg>=0.30.0", "asyncpg>=0.30.0",
"click>=8.2.1", "click>=8.2.1",
"dependency-injector>=4.47.1", "dependency-injector>=4.47.1",
"greenlet>=3.2.3", "greenlet>=3.2.3",
"legacy-cgi>=2.6.3",
"openai>=1.84.0", "openai>=1.84.0",
"orjson>=3.11.1",
"pendulum>=3.1.0", "pendulum>=3.1.0",
"psycopg2-binary>=2.9.10", "psycopg2-binary>=2.9.10",
"pydantic>=2.11.5", "pydantic>=2.11.5",
"pydantic-settings>=2.9.1", "pydantic-settings>=2.9.1",
"python-json-logger>=3.3.0",
"redis>=6.4.0",
"requests>=2.32.4",
"sentry-sdk>=2.34.1",
"sqlalchemy>=2.0.41", "sqlalchemy>=2.0.41",
"telebot>=0.0.5",
] ]
[project.scripts] [project.scripts]

View File

@ -3,6 +3,7 @@ from dependency_injector import containers, providers
from .db_config import PostgresConfig from .db_config import PostgresConfig
from .log_config import LoggerConfig from .log_config import LoggerConfig
from .openai_config import OpenAiConfig from .openai_config import OpenAiConfig
from .redis_conn import RedisConfig
from .tg_bot_config import TgBotConfig from .tg_bot_config import TgBotConfig
@ -11,5 +12,6 @@ class ConfigContainer(containers.DeclarativeContainer):
postgres_config: providers.Provider[PostgresConfig] = providers.Singleton( postgres_config: providers.Provider[PostgresConfig] = providers.Singleton(
PostgresConfig PostgresConfig
) )
redis_config: providers.Provider[RedisConfig] = providers.Singleton(RedisConfig)
tg_bot_config: providers.Provider[TgBotConfig] = providers.Singleton(TgBotConfig) tg_bot_config: providers.Provider[TgBotConfig] = providers.Singleton(TgBotConfig)
openai_config: providers.Provider[OpenAiConfig] = providers.Singleton(OpenAiConfig) openai_config: providers.Provider[OpenAiConfig] = providers.Singleton(OpenAiConfig)

View File

@ -1,4 +1,5 @@
import pydantic import pydantic
from pydantic_settings import SettingsConfigDict
from . import EnvConfig from . import EnvConfig
@ -6,3 +7,7 @@ from . import EnvConfig
class LoggerConfig(EnvConfig): class LoggerConfig(EnvConfig):
telegram_bot_token: pydantic.SecretStr | None = None telegram_bot_token: pydantic.SecretStr | None = None
telegram_chat_id: int | None = None telegram_chat_id: int | None = None
model_config = SettingsConfigDict(
env_prefix="LOG_",
)

View File

@ -0,0 +1,17 @@
import pydantic
from pydantic_settings import SettingsConfigDict
from . import EnvConfig
class RedisConfig(EnvConfig):
host: str = pydantic.Field(default="127.0.0.1")
port: int = pydantic.Field(default=6379)
db: int = pydantic.Field(default=0)
username: str | None = pydantic.Field(default=None)
password: pydantic.SecretStr | None = pydantic.Field(default=None)
pool_size: int = pydantic.Field(default=100)
model_config = SettingsConfigDict(
env_prefix="REDIS_",
)

View File

@ -1,7 +1,12 @@
import pydantic import pydantic
from pydantic_settings import SettingsConfigDict
from . import EnvConfig from . import EnvConfig
class TgBotConfig(EnvConfig): class TgBotConfig(EnvConfig):
model_config = SettingsConfigDict(
env_prefix="TG_",
)
token: pydantic.SecretStr token: pydantic.SecretStr

View File

@ -6,6 +6,7 @@ from dependency_injector import containers, providers
from .configs.container import ConfigContainer from .configs.container import ConfigContainer
from .database.container import DatabaseContainer from .database.container import DatabaseContainer
from .openai_manager.container import OpenAiContainer from .openai_manager.container import OpenAiContainer
from .redis_db.container import RedisContainer
class MainContainer(containers.DeclarativeContainer): class MainContainer(containers.DeclarativeContainer):
@ -18,6 +19,9 @@ class MainContainer(containers.DeclarativeContainer):
openai_container = providers.Container( openai_container = providers.Container(
OpenAiContainer, config_container=config_container OpenAiContainer, config_container=config_container
) )
redis_container = providers.Container(
RedisContainer, config_container=config_container
)
@contextlib.asynccontextmanager @contextlib.asynccontextmanager

View File

@ -5,6 +5,7 @@ Revises: 78357f437f61
Create Date: 2025-07-16 10:13:26.574794 Create Date: 2025-07-16 10:13:26.574794
""" """
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op from alembic import op
@ -12,8 +13,8 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = '6b43c7ed8c78' revision: str = "6b43c7ed8c78"
down_revision: Union[str, None] = '78357f437f61' down_revision: Union[str, None] = "78357f437f61"
branch_labels: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None
@ -21,16 +22,22 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
"""Upgrade schema.""" """Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.alter_column('openai_token_usage', 'response_fingerprint', op.alter_column(
existing_type=sa.TEXT(), "openai_token_usage",
nullable=True) "response_fingerprint",
existing_type=sa.TEXT(),
nullable=True,
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
"""Downgrade schema.""" """Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.alter_column('openai_token_usage', 'response_fingerprint', op.alter_column(
existing_type=sa.TEXT(), "openai_token_usage",
nullable=False) "response_fingerprint",
existing_type=sa.TEXT(),
nullable=False,
)
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@ -5,14 +5,15 @@ Revises: 6b43c7ed8c78
Create Date: 2025-08-10 12:40:24.118166 Create Date: 2025-08-10 12:40:24.118166
""" """
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op from alembic import op
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = 'd30d80dee5a3' revision: str = "d30d80dee5a3"
down_revision: Union[str, None] = '6b43c7ed8c78' down_revision: Union[str, None] = "6b43c7ed8c78"
branch_labels: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None
@ -20,12 +21,14 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
"""Upgrade schema.""" """Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint(op.f('uq_glossary_word_term'), 'glossary_word', ['term']) op.create_unique_constraint(
op.f("uq_glossary_word_term"), "glossary_word", ["term"]
)
# ### end Alembic commands ### # ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
"""Downgrade schema.""" """Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(op.f('uq_glossary_word_term'), 'glossary_word', type_='unique') op.drop_constraint(op.f("uq_glossary_word_term"), "glossary_word", type_="unique")
# ### end Alembic commands ### # ### end Alembic commands ###

255
src/greek_lang/logger.py Normal file
View File

@ -0,0 +1,255 @@
import base64
import contextlib
import contextvars
import datetime
import logging
import socket
import sys
import typing
from collections.abc import Iterator
from logging.config import dictConfig
from types import TracebackType
import orjson
import sentry_sdk
from .configs.log_config import LoggerConfig
extra_log_context: contextvars.ContextVar[dict[str, str]] = contextvars.ContextVar(
"extra_log_context"
)
@contextlib.contextmanager
def extra_log_context_manager(new_context: dict[str, str]) -> Iterator[None]:
extra_log_context_data = {}
with contextlib.suppress(LookupError):
extra_log_context_data = extra_log_context.get()
extra_log_context_data.update(new_context)
token = extra_log_context.set(extra_log_context_data)
try:
yield
finally:
extra_log_context.reset(token)
class NonLoggableExceptionsFilter(logging.Filter):
exclude_exception_types: typing.Sequence[type[Exception]]
def __init__(
self,
*,
exclude_exception_types: typing.Sequence[type[Exception]] = (),
name: str = "",
):
self.exclude_exception_types = exclude_exception_types
super().__init__(name=name)
def filter(self, record: logging.LogRecord) -> bool:
if record.exc_info is None:
return True
try:
exception_type = record.exc_info[0]
except TypeError:
return True
return exception_type not in self.exclude_exception_types
def default_json_serializer(obj: object) -> str:
match obj:
case bytes() as b:
try:
return b.decode("utf-8")
except UnicodeDecodeError:
return base64.b64encode(b).decode("ascii")
case datetime.timedelta() as td:
return str(td.total_seconds())
case datetime.datetime() as dt:
return dt.isoformat()
case datetime.date() as d:
return d.isoformat()
case _:
raise TypeError(f"Type {type(obj)} not serializable")
def json_serializer(data: dict[str, typing.Any], **_: typing.Any) -> str:
extra_log_context_data = {}
with contextlib.suppress(LookupError):
extra_log_context_data = extra_log_context.get()
data.update({"extra_log_context": extra_log_context_data})
return orjson.dumps(
data,
default=default_json_serializer,
).decode()
def get_dict_config(
*,
sentry_dsn: str | None = None,
tg_token: str | None = None,
tg_chat: int | None = None,
exclude_exception_types: typing.Sequence[type[Exception]] = (),
formatters_extension_dict: dict[str, typing.Any] | None = None,
filters_extension_dict: dict[str, typing.Any] | None = None,
handlers_extension_dict: dict[str, typing.Any] | None = None,
loggers_extension_dict: dict[str, typing.Any] | None = None,
) -> dict[str, typing.Any]:
hostname: str = socket.gethostname()
null_handler: dict[str, str] = {
"class": "logging.NullHandler",
}
formatters = {
"verbose": {
"format": f"%(asctime)s [%(levelname)s] [{hostname} %(name)s:%(lineno)s] %(message)s"
},
"json": {
"()": "pythonjsonlogger.jsonlogger.JsonFormatter",
"json_serializer": json_serializer,
"format": "%(asctime)s %(levelname)s %(name)s %(filename)s %(lineno)s %(message)s",
},
} | (formatters_extension_dict or {})
filters = {
"non_loggable_exceptions": {
"()": NonLoggableExceptionsFilter,
"exclude_exception_types": exclude_exception_types,
},
} | (filters_extension_dict or {})
handlers = {
"console_handler": {
"class": "logging.StreamHandler",
"formatter": "verbose",
"filters": [],
},
"telegram_handler": {
"class": "greek_lang.utils.telegram_log.handler.TelegramHandler",
"token": tg_token,
"chat_id": tg_chat,
"logger_name": "console_handler",
"level": "ERROR",
"formatter": "verbose",
"filters": ["non_loggable_exceptions"],
}
if tg_token and tg_token
else null_handler,
"sentry_handler": {
"class": "sentry_sdk.integrations.logging.EventHandler",
"level": "ERROR",
"formatter": "verbose",
"filters": ["non_loggable_exceptions"],
}
if sentry_dsn is not None
else null_handler,
} | (handlers_extension_dict or {})
loggers = {
"root": {
"level": "DEBUG",
"handlers": ["console_handler", "telegram_handler", "sentry_handler"],
},
"console": {
"level": "DEBUG",
"handlers": ["console_handler"],
"propagate": False,
},
"telegram.bot": {
"propagate": False,
},
"httpx": {
"level": "DEBUG",
"propagate": True,
},
} | (loggers_extension_dict or {})
return {
"version": 1,
"disable_existing_loggers": False,
"formatters": formatters,
"filters": filters,
"handlers": handlers,
"loggers": loggers,
}
def create_tg_info_logger(
*,
tg_token: str,
tg_chat: str,
) -> logging.Logger:
logger_name = "tg_info"
dict_config = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"telegram_handler": {
"class": "petuh_bot.utils.telegram_log.handler.TelegramHandler",
"logger_name": "console",
"token": tg_token,
"chat_id": tg_chat,
"level": "INFO",
}
},
"loggers": {
logger_name: {
"handlers": ["telegram_handler"],
"propagate": False,
},
},
}
logging.config.dictConfig(dict_config)
return logging.getLogger(logger_name)
def init_root_logger(
sentry_dsn: str | None = None,
tg_token: str | None = None,
tg_chat: int | None = None,
exclude_exception_types: typing.Sequence[type[Exception]] = (),
formatters_extension_dict: dict[str, typing.Any] | None = None,
filters_extension_dict: dict[str, typing.Any] | None = None,
handlers_extension_dict: dict[str, typing.Any] | None = None,
loggers_extension_dict: dict[str, typing.Any] | None = None,
) -> logging.Logger:
if sentry_dsn is not None:
sentry_sdk.init(
dsn=sentry_dsn,
traces_sample_rate=1.0,
default_integrations=True,
)
dict_config = get_dict_config(
sentry_dsn=sentry_dsn,
tg_token=tg_token,
tg_chat=tg_chat,
exclude_exception_types=exclude_exception_types,
formatters_extension_dict=formatters_extension_dict,
filters_extension_dict=filters_extension_dict,
handlers_extension_dict=handlers_extension_dict,
loggers_extension_dict=loggers_extension_dict,
)
dictConfig(dict_config)
return logging.getLogger()
loggers_ext: dict[str, typing.Any] = {}
def _exc_hook_patched(
exc_type: type[BaseException],
exc_val: BaseException,
exc_tb: TracebackType,
) -> None:
if isinstance(exc_val, KeyboardInterrupt):
return
logging.critical(
f"Uncaught exception: {exc_type}", exc_info=(exc_type, exc_val, exc_tb)
)
def setup() -> None:
config = LoggerConfig()
init_root_logger(
tg_token=config.telegram_bot_token.get_secret_value()
if config.telegram_bot_token
else None,
tg_chat=config.telegram_chat_id,
loggers_extension_dict=loggers_ext,
)
sys.excepthook = _exc_hook_patched # type: ignore[assignment]

View File

View File

@ -0,0 +1,24 @@
from collections.abc import AsyncIterator
from dependency_injector import containers, providers
from ..configs.redis_conn import RedisConfig
from .redis_conn import create_redis_pool, RedisPool
async def create_redis_pool_resource(
redis_config: RedisConfig,
) -> AsyncIterator[RedisPool]:
redis_pool = await create_redis_pool(redis_config)
try:
yield redis_pool
finally:
await redis_pool.aclose()
class RedisContainer(containers.DeclarativeContainer):
config_container = providers.DependenciesContainer()
redis_pool: providers.Resource[RedisPool] = providers.Resource(
create_redis_pool_resource,
redis_config=config_container.redis_config,
)

View File

@ -0,0 +1,51 @@
import dataclasses
from typing import TypeAlias
import redis
from ..configs.redis_conn import RedisConfig
RedisPool: TypeAlias = redis.asyncio.Redis
@dataclasses.dataclass(frozen=True)
class RedisConnectionParams:
host: str = "127.0.0.1"
port: int = 6379
db: int = 0
username: str | None = None
password: str | None = None
max_connections: int = 2**31
socket_timeout: float = 5.0
def create_redis_single_pool(
redis_conn_params: RedisConnectionParams,
) -> redis.asyncio.Redis:
redis_url = f"redis://{redis_conn_params.host}:{redis_conn_params.port}/{redis_conn_params.db}"
connection: redis.asyncio.Redis = redis.asyncio.from_url( # type: ignore[no-untyped-call]
redis_url,
username=redis_conn_params.username,
password=redis_conn_params.password,
decode_responses=False,
socket_connect_timeout=redis_conn_params.socket_timeout,
max_connections=redis_conn_params.max_connections,
)
return connection
def create_redis_pool(
redis_config: RedisConfig,
) -> RedisPool:
redis_conn_params = RedisConnectionParams(
host=redis_config.host,
port=redis_config.port,
db=redis_config.db,
username=redis_config.username,
password=(
redis_config.password.get_secret_value() if redis_config.password else None
),
max_connections=redis_config.pool_size,
)
return create_redis_single_pool(redis_conn_params)

View File

View File

@ -0,0 +1,17 @@
import asyncio
from greek_lang import logger
from greek_lang.container import init_main_container
from greek_lang.tg_bot import app
async def main() -> None:
logger.setup()
async with init_main_container():
bot = app.create_bot()
dispatcher = await app.create_dispatcher()
await app.run_bot(bot=bot, dispatcher=dispatcher)
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,77 @@
import pydantic
from aiogram import Bot, Dispatcher, BaseMiddleware
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart
from aiogram.fsm.storage.base import BaseStorage, DefaultKeyBuilder
from aiogram.fsm.storage.redis import RedisStorage
from aiogram.types import BotCommandScopeAllPrivateChats, Message
from aiogram_dialog import DialogManager, setup_dialogs
from dependency_injector.wiring import Provide, inject
from ..configs.container import ConfigContainer
from ..redis_db.container import RedisContainer
from ..redis_db.redis_conn import RedisPool
@inject
def create_bot(
bot_token: pydantic.SecretStr = Provide[
ConfigContainer.tg_bot_config.provided.token
],
) -> Bot:
bot = Bot(
token=bot_token.get_secret_value(),
)
return bot
async def create_dispatcher() -> Dispatcher:
async def start(message: Message, dialog_manager: DialogManager) -> None:
user = message.from_user
if user is None:
return
await message.answer(
text="TEST",
parse_mode=ParseMode.HTML,
)
fsm_storage = await create_fsm_storage()
dp = Dispatcher(
storage=fsm_storage,
)
middlewares: list[BaseMiddleware] = []
for middleware in middlewares:
dp.update.middleware(middleware)
dp.message.register(start, CommandStart())
dp.business_message.register(start, CommandStart())
setup_dialogs(dp)
return dp
@inject
async def create_fsm_storage(
redis_pool: RedisPool = Provide[RedisContainer.redis_pool],
) -> BaseStorage:
storage = RedisStorage(
redis=redis_pool,
key_builder=DefaultKeyBuilder(
prefix="fsm",
with_destiny=True,
),
)
return storage
async def run_bot(
bot: Bot,
dispatcher: Dispatcher,
) -> None:
await bot.delete_webhook(drop_pending_updates=True)
await bot.delete_my_commands(scope=BotCommandScopeAllPrivateChats())
await dispatcher.start_polling(
bot, allowed_updates=dispatcher.resolve_used_update_types()
)

View File

View File

@ -0,0 +1,103 @@
import contextlib
import copy
import datetime
import io
import logging
import logging.config
import types
import cgitb
import telebot
from requests import ReadTimeout
ExcInfoType = tuple[type[BaseException], BaseException, types.TracebackType]
class TelegramHandler(logging.Handler):
bot: telebot.TeleBot
chat_id: int
logger_name: logging.Logger | None
def __init__(self, *, token: str, chat_id: int, logger_name: str | None = None):
logging.Handler.__init__(self)
self.bot = telebot.TeleBot(token)
self.chat_id = chat_id
self.logger = logging.getLogger(logger_name) if logger_name else None
@staticmethod
def get_tb_data(exc_info: ExcInfoType, output_format: str = "html") -> io.BytesIO:
string_io_buffer = io.StringIO()
context_width = 11
cgitb.Hook(
context=context_width,
file=string_io_buffer,
format=output_format,
).handle(info=exc_info)
string_io_buffer.seek(0)
encoding = "utf-8"
bytes_io_buffer = io.BytesIO(string_io_buffer.read().encode(encoding))
bytes_io_buffer.seek(0)
return bytes_io_buffer
@staticmethod
def prepare(log_data: str, length: int) -> str:
message = log_data[:length]
return message
def emit(self, record: logging.LogRecord) -> None:
try:
if record.exc_info is None:
self.send_plain_text(record)
else:
self.send_traceback(record)
except ReadTimeout:
if self.logger:
self.logger.error("Telegram request timed out")
except BaseException as exc:
if self.logger:
self.logger.exception(
f"Telegram Log Handler Unexpected Exception Occurred: {exc}"
)
def send_traceback(self, record: logging.LogRecord) -> None:
tb_data_html = self.get_tb_data(record.exc_info, output_format="html") # type: ignore
tb_data_plain = self.get_tb_data(record.exc_info, output_format="plain") # type: ignore
with contextlib.closing(tb_data_html), contextlib.closing(tb_data_plain):
filename = datetime.datetime.now().strftime("python_tb_%Y-%m-%d_%H_%M_%S")
caption = self.get_exc_caption_text(record)
self.bot.send_media_group(
chat_id=self.chat_id,
media=[
telebot.types.InputMediaDocument(
telebot.types.InputFile(
tb_data_html, file_name=filename + ".html"
),
caption=caption,
),
telebot.types.InputMediaDocument(
telebot.types.InputFile(
tb_data_plain, file_name=filename + ".txt"
)
),
],
timeout=5,
)
def get_exc_caption_text(self, record: logging.LogRecord) -> str:
caption_length = 200
no_exc_record = self.get_no_exc_record_copy(record)
caption = self.prepare(self.format(no_exc_record), caption_length)
return caption
@staticmethod
def get_no_exc_record_copy(record: logging.LogRecord) -> logging.LogRecord:
no_exc_record = copy.copy(record)
no_exc_record.exc_info = None
no_exc_record.exc_text = None
return no_exc_record
def send_plain_text(self, record: logging.LogRecord) -> None:
message_length = 4096
text = self.prepare(self.format(record), message_length)
self.bot.send_message(self.chat_id, text, timeout=5)

297
uv.lock
View File

@ -2,6 +2,46 @@ version = 1
revision = 2 revision = 2
requires-python = ">=3.13" requires-python = ">=3.13"
[[package]]
name = "aiofiles"
version = "24.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" },
]
[[package]]
name = "aiogram"
version = "3.21.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiofiles" },
{ name = "aiohttp" },
{ name = "certifi" },
{ name = "magic-filter" },
{ name = "pydantic" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/70/11/414c49e31ac353b12dba4f89e66141e4504d359c453dfdd5d259cefb97a4/aiogram-3.21.0.tar.gz", hash = "sha256:24cd0015ed73471fa3028b47788e57b43a475c66d176a857de2b6b67bd37e1dd", size = 1500486, upload-time = "2025-07-05T00:20:03.203Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/0b/606c9cdff82f5a5e004d72a14368d46ed00298c94a8d83b6faf8fb70499f/aiogram-3.21.0-py3-none-any.whl", hash = "sha256:0995e11be66bba46c0aab4ac8a41587fb2749b72399aff46a20e6610ccebe3ae", size = 677316, upload-time = "2025-07-05T00:20:01.322Z" },
]
[[package]]
name = "aiogram-dialog"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiogram" },
{ name = "cachetools" },
{ name = "jinja2" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f2/b9/cfadb823578f9aff44f10928f8020dc4abda82078fba62295aae8869e894/aiogram_dialog-2.4.0.tar.gz", hash = "sha256:e8f0a811be3a58d1e48dfb9dd79108fd0e25c8ab7f8067c31c49f2f583ba4ecc", size = 80359, upload-time = "2025-07-08T22:41:41.078Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/50/d0/1c6511eb6840d06efbfba12cf6e59f688f9e314ab90af34027fa8069af75/aiogram_dialog-2.4.0-py3-none-any.whl", hash = "sha256:4e5fd8f7db66b6d252983c4025968b379069f4a2022db60bde36e5b91268b6ad", size = 112911, upload-time = "2025-07-08T22:41:47.61Z" },
]
[[package]] [[package]]
name = "aiogtts" name = "aiogtts"
version = "1.1.1" version = "1.1.1"
@ -159,6 +199,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" },
] ]
[[package]]
name = "cachetools"
version = "5.5.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" },
]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2025.8.3" version = "2025.8.3"
@ -177,6 +226,37 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" },
] ]
[[package]]
name = "charset-normalizer"
version = "3.4.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" },
{ url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" },
{ url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" },
{ url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" },
{ url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" },
{ url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" },
{ url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" },
{ url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" },
{ url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" },
{ url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" },
{ url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" },
{ url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" },
{ url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" },
{ url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" },
{ url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" },
{ url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" },
{ url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" },
{ url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" },
{ url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" },
{ url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" },
{ url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" },
{ url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" },
{ url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" },
]
[[package]] [[package]]
name = "click" name = "click"
version = "8.2.1" version = "8.2.1"
@ -306,18 +386,27 @@ name = "greek-lang"
version = "0.1.0" version = "0.1.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "aiogram" },
{ name = "aiogram-dialog" },
{ name = "aiogtts" }, { name = "aiogtts" },
{ name = "alembic" }, { name = "alembic" },
{ name = "asyncpg" }, { name = "asyncpg" },
{ name = "click" }, { name = "click" },
{ name = "dependency-injector" }, { name = "dependency-injector" },
{ name = "greenlet" }, { name = "greenlet" },
{ name = "legacy-cgi" },
{ name = "openai" }, { name = "openai" },
{ name = "orjson" },
{ name = "pendulum" }, { name = "pendulum" },
{ name = "psycopg2-binary" }, { name = "psycopg2-binary" },
{ name = "pydantic" }, { name = "pydantic" },
{ name = "pydantic-settings" }, { name = "pydantic-settings" },
{ name = "python-json-logger" },
{ name = "redis" },
{ name = "requests" },
{ name = "sentry-sdk" },
{ name = "sqlalchemy" }, { name = "sqlalchemy" },
{ name = "telebot" },
] ]
[package.dev-dependencies] [package.dev-dependencies]
@ -332,18 +421,27 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "aiogram", specifier = ">=3.21.0" },
{ name = "aiogram-dialog", specifier = ">=2.4.0" },
{ name = "aiogtts", specifier = ">=1.1.1" }, { name = "aiogtts", specifier = ">=1.1.1" },
{ name = "alembic", specifier = ">=1.16.1" }, { name = "alembic", specifier = ">=1.16.1" },
{ name = "asyncpg", specifier = ">=0.30.0" }, { name = "asyncpg", specifier = ">=0.30.0" },
{ name = "click", specifier = ">=8.2.1" }, { name = "click", specifier = ">=8.2.1" },
{ name = "dependency-injector", specifier = ">=4.47.1" }, { name = "dependency-injector", specifier = ">=4.47.1" },
{ name = "greenlet", specifier = ">=3.2.3" }, { name = "greenlet", specifier = ">=3.2.3" },
{ name = "legacy-cgi", specifier = ">=2.6.3" },
{ name = "openai", specifier = ">=1.84.0" }, { name = "openai", specifier = ">=1.84.0" },
{ name = "orjson", specifier = ">=3.11.1" },
{ name = "pendulum", specifier = ">=3.1.0" }, { name = "pendulum", specifier = ">=3.1.0" },
{ name = "psycopg2-binary", specifier = ">=2.9.10" }, { name = "psycopg2-binary", specifier = ">=2.9.10" },
{ name = "pydantic", specifier = ">=2.11.5" }, { name = "pydantic", specifier = ">=2.11.5" },
{ name = "pydantic-settings", specifier = ">=2.9.1" }, { name = "pydantic-settings", specifier = ">=2.9.1" },
{ name = "python-json-logger", specifier = ">=3.3.0" },
{ name = "redis", specifier = ">=6.4.0" },
{ name = "requests", specifier = ">=2.32.4" },
{ name = "sentry-sdk", specifier = ">=2.34.1" },
{ name = "sqlalchemy", specifier = ">=2.0.41" }, { name = "sqlalchemy", specifier = ">=2.0.41" },
{ name = "telebot", specifier = ">=0.0.5" },
] ]
[package.metadata.requires-dev] [package.metadata.requires-dev]
@ -435,6 +533,27 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
] ]
[[package]]
name = "iniconfig"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" },
]
[[package]]
name = "jinja2"
version = "3.1.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
]
[[package]] [[package]]
name = "jiter" name = "jiter"
version = "0.10.0" version = "0.10.0"
@ -471,6 +590,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/4a/4175a563579e884192ba6e81725fc0448b042024419be8d83aa8a80a3f44/jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5", size = 354213, upload-time = "2025-05-18T19:04:41.894Z" }, { url = "https://files.pythonhosted.org/packages/b3/4a/4175a563579e884192ba6e81725fc0448b042024419be8d83aa8a80a3f44/jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5", size = 354213, upload-time = "2025-05-18T19:04:41.894Z" },
] ]
[[package]]
name = "legacy-cgi"
version = "2.6.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a6/ed/300cabc9693209d5a03e2ebc5eb5c4171b51607c08ed84a2b71c9015e0f3/legacy_cgi-2.6.3.tar.gz", hash = "sha256:4c119d6cb8e9d8b6ad7cc0ddad880552c62df4029622835d06dfd18f438a8154", size = 24401, upload-time = "2025-03-27T00:48:56.957Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/33/68c6c38193684537757e0d50a7ccb4f4656e5c2f7cd2be737a9d4a1bff71/legacy_cgi-2.6.3-py3-none-any.whl", hash = "sha256:6df2ea5ae14c71ef6f097f8b6372b44f6685283dc018535a75c924564183cdab", size = 19851, upload-time = "2025-03-27T00:48:55.366Z" },
]
[[package]]
name = "magic-filter"
version = "1.0.12"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e6/08/da7c2cc7398cc0376e8da599d6330a437c01d3eace2f2365f300e0f3f758/magic_filter-1.0.12.tar.gz", hash = "sha256:4751d0b579a5045d1dc250625c4c508c18c3def5ea6afaf3957cb4530d03f7f9", size = 11071, upload-time = "2023-10-01T12:33:19.006Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/75/f620449f0056eff0ec7c1b1e088f71068eb4e47a46eb54f6c065c6ad7675/magic_filter-1.0.12-py3-none-any.whl", hash = "sha256:e5929e544f310c2b1f154318db8c5cdf544dd658efa998172acd2e4ba0f6c6a6", size = 11335, upload-time = "2023-10-01T12:33:17.711Z" },
]
[[package]] [[package]]
name = "mako" name = "mako"
version = "1.3.10" version = "1.3.10"
@ -640,6 +777,49 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d6/dd/9aa956485c2856346b3181542fbb0aea4e5b457fa7a523944726746da8da/openai-1.99.6-py3-none-any.whl", hash = "sha256:e40d44b2989588c45ce13819598788b77b8fb80ba2f7ae95ce90d14e46f1bd26", size = 786296, upload-time = "2025-08-09T15:20:51.95Z" }, { url = "https://files.pythonhosted.org/packages/d6/dd/9aa956485c2856346b3181542fbb0aea4e5b457fa7a523944726746da8da/openai-1.99.6-py3-none-any.whl", hash = "sha256:e40d44b2989588c45ce13819598788b77b8fb80ba2f7ae95ce90d14e46f1bd26", size = 786296, upload-time = "2025-08-09T15:20:51.95Z" },
] ]
[[package]]
name = "orjson"
version = "3.11.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/3b/fd9ff8ff64ae3900f11554d5cfc835fb73e501e043c420ad32ec574fe27f/orjson-3.11.1.tar.gz", hash = "sha256:48d82770a5fd88778063604c566f9c7c71820270c9cc9338d25147cbf34afd96", size = 5393373, upload-time = "2025-07-25T14:33:52.898Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/e9/880ef869e6f66279ce3a381a32afa0f34e29a94250146911eee029e56efc/orjson-3.11.1-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53cfefe4af059e65aabe9683f76b9c88bf34b4341a77d329227c2424e0e59b0e", size = 240835, upload-time = "2025-07-25T14:32:54.507Z" },
{ url = "https://files.pythonhosted.org/packages/f0/1f/52039ef3d03eeea21763b46bc99ebe11d9de8510c72b7b5569433084a17e/orjson-3.11.1-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:93d5abed5a6f9e1b6f9b5bf6ed4423c11932b5447c2f7281d3b64e0f26c6d064", size = 129226, upload-time = "2025-07-25T14:32:55.908Z" },
{ url = "https://files.pythonhosted.org/packages/ee/da/59fdffc9465a760be2cd3764ef9cd5535eec8f095419f972fddb123b6d0e/orjson-3.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf06642f3db2966df504944cdd0eb68ca2717f0353bb20b20acd78109374a6", size = 132261, upload-time = "2025-07-25T14:32:57.538Z" },
{ url = "https://files.pythonhosted.org/packages/bb/5c/8610911c7e969db7cf928c8baac4b2f1e68d314bc3057acf5ca64f758435/orjson-3.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dddf4e78747fa7f2188273f84562017a3c4f0824485b78372513c1681ea7a894", size = 128614, upload-time = "2025-07-25T14:32:58.808Z" },
{ url = "https://files.pythonhosted.org/packages/f7/a1/a1db9d4310d014c90f3b7e9b72c6fb162cba82c5f46d0b345669eaebdd3a/orjson-3.11.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa3fe8653c9f57f0e16f008e43626485b6723b84b2f741f54d1258095b655912", size = 130968, upload-time = "2025-07-25T14:33:00.038Z" },
{ url = "https://files.pythonhosted.org/packages/56/ff/11acd1fd7c38ea7a1b5d6bf582ae3da05931bee64620995eb08fd63c77fe/orjson-3.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6334d2382aff975a61f6f4d1c3daf39368b887c7de08f7c16c58f485dcf7adb2", size = 132439, upload-time = "2025-07-25T14:33:01.354Z" },
{ url = "https://files.pythonhosted.org/packages/70/f9/bb564dd9450bf8725e034a8ad7f4ae9d4710a34caf63b85ce1c0c6d40af0/orjson-3.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3d0855b643f259ee0cb76fe3df4c04483354409a520a902b067c674842eb6b8", size = 135299, upload-time = "2025-07-25T14:33:03.079Z" },
{ url = "https://files.pythonhosted.org/packages/94/bb/c8eafe6051405e241dda3691db4d9132d3c3462d1d10a17f50837dd130b4/orjson-3.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eacdfeefd0a79987926476eb16e0245546bedeb8febbbbcf4b653e79257a8e4", size = 131004, upload-time = "2025-07-25T14:33:04.416Z" },
{ url = "https://files.pythonhosted.org/packages/a2/40/bed8d7dcf1bd2df8813bf010a25f645863a2f75e8e0ebdb2b55784cf1a62/orjson-3.11.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ed07faf9e4873518c60480325dcbc16d17c59a165532cccfb409b4cdbaeff24", size = 130583, upload-time = "2025-07-25T14:33:05.768Z" },
{ url = "https://files.pythonhosted.org/packages/57/e7/cfa2eb803ad52d74fbb5424a429b5be164e51d23f1d853e5e037173a5c48/orjson-3.11.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d6d308dd578ae3658f62bb9eba54801533225823cd3248c902be1ebc79b5e014", size = 404218, upload-time = "2025-07-25T14:33:07.117Z" },
{ url = "https://files.pythonhosted.org/packages/d5/21/bc703af5bc6e9c7e18dcf4404dcc4ec305ab9bb6c82d3aee5952c0c56abf/orjson-3.11.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c4aa13ca959ba6b15c0a98d3d204b850f9dc36c08c9ce422ffb024eb30d6e058", size = 146605, upload-time = "2025-07-25T14:33:08.55Z" },
{ url = "https://files.pythonhosted.org/packages/8f/fe/d26a0150534c4965a06f556aa68bf3c3b82999d5d7b0facd3af7b390c4af/orjson-3.11.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:be3d0653322abc9b68e5bcdaee6cfd58fcbe9973740ab222b87f4d687232ab1f", size = 135434, upload-time = "2025-07-25T14:33:09.967Z" },
{ url = "https://files.pythonhosted.org/packages/89/b6/1cb28365f08cbcffc464f8512320c6eb6db6a653f03d66de47ea3c19385f/orjson-3.11.1-cp313-cp313-win32.whl", hash = "sha256:4dd34e7e2518de8d7834268846f8cab7204364f427c56fb2251e098da86f5092", size = 136596, upload-time = "2025-07-25T14:33:11.333Z" },
{ url = "https://files.pythonhosted.org/packages/f9/35/7870d0d3ed843652676d84d8a6038791113eacc85237b673b925802826b8/orjson-3.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:d6895d32032b6362540e6d0694b19130bb4f2ad04694002dce7d8af588ca5f77", size = 131319, upload-time = "2025-07-25T14:33:12.614Z" },
{ url = "https://files.pythonhosted.org/packages/b7/3e/5bcd50fd865eb664d4edfdaaaff51e333593ceb5695a22c0d0a0d2b187ba/orjson-3.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:bb7c36d5d3570fcbb01d24fa447a21a7fe5a41141fd88e78f7994053cc4e28f4", size = 126613, upload-time = "2025-07-25T14:33:13.927Z" },
{ url = "https://files.pythonhosted.org/packages/61/d8/0a5cd31ed100b4e569e143cb0cddefc21f0bcb8ce284f44bca0bb0e10f3d/orjson-3.11.1-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7b71ef394327b3d0b39f6ea7ade2ecda2731a56c6a7cbf0d6a7301203b92a89b", size = 240819, upload-time = "2025-07-25T14:33:15.223Z" },
{ url = "https://files.pythonhosted.org/packages/b9/95/7eb2c76c92192ceca16bc81845ff100bbb93f568b4b94d914b6a4da47d61/orjson-3.11.1-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:77c0fe28ed659b62273995244ae2aa430e432c71f86e4573ab16caa2f2e3ca5e", size = 129218, upload-time = "2025-07-25T14:33:16.637Z" },
{ url = "https://files.pythonhosted.org/packages/da/84/e6b67f301b18adbbc346882f456bea44daebbd032ba725dbd7b741e3a7f1/orjson-3.11.1-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:1495692f1f1ba2467df429343388a0ed259382835922e124c0cfdd56b3d1f727", size = 132238, upload-time = "2025-07-25T14:33:17.934Z" },
{ url = "https://files.pythonhosted.org/packages/84/78/a45a86e29d9b2f391f9d00b22da51bc4b46b86b788fd42df2c5fcf3e8005/orjson-3.11.1-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:08c6a762fca63ca4dc04f66c48ea5d2428db55839fec996890e1bfaf057b658c", size = 130998, upload-time = "2025-07-25T14:33:19.282Z" },
{ url = "https://files.pythonhosted.org/packages/ea/8f/6eb3ee6760d93b2ce996a8529164ee1f5bafbdf64b74c7314b68db622b32/orjson-3.11.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e26794fe3976810b2c01fda29bd9ac7c91a3c1284b29cc9a383989f7b614037", size = 130559, upload-time = "2025-07-25T14:33:20.589Z" },
{ url = "https://files.pythonhosted.org/packages/1b/78/9572ae94bdba6813917c9387e7834224c011ea6b4530ade07d718fd31598/orjson-3.11.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4b4b4f8f0b1d3ef8dc73e55363a0ffe012a42f4e2f1a140bf559698dca39b3fa", size = 404231, upload-time = "2025-07-25T14:33:22.019Z" },
{ url = "https://files.pythonhosted.org/packages/1f/a3/68381ad0757e084927c5ee6cfdeab1c6c89405949ee493db557e60871c4c/orjson-3.11.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:848be553ea35aa89bfefbed2e27c8a41244c862956ab8ba00dc0b27e84fd58de", size = 146658, upload-time = "2025-07-25T14:33:23.675Z" },
{ url = "https://files.pythonhosted.org/packages/00/db/fac56acf77aab778296c3f541a3eec643266f28ecd71d6c0cba251e47655/orjson-3.11.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c964c29711a4b1df52f8d9966f015402a6cf87753a406c1c4405c407dd66fd45", size = 135443, upload-time = "2025-07-25T14:33:25.04Z" },
{ url = "https://files.pythonhosted.org/packages/76/b1/326fa4b87426197ead61c1eec2eeb3babc9eb33b480ac1f93894e40c8c08/orjson-3.11.1-cp314-cp314-win32.whl", hash = "sha256:33aada2e6b6bc9c540d396528b91e666cedb383740fee6e6a917f561b390ecb1", size = 136643, upload-time = "2025-07-25T14:33:26.449Z" },
{ url = "https://files.pythonhosted.org/packages/0f/8e/2987ae2109f3bfd39680f8a187d1bc09ad7f8fb019dcdc719b08c7242ade/orjson-3.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:68e10fd804e44e36188b9952543e3fa22f5aa8394da1b5283ca2b423735c06e8", size = 131324, upload-time = "2025-07-25T14:33:27.896Z" },
{ url = "https://files.pythonhosted.org/packages/21/5f/253e08e6974752b124fbf3a4de3ad53baa766b0cb4a333d47706d307e396/orjson-3.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:f3cf6c07f8b32127d836be8e1c55d4f34843f7df346536da768e9f73f22078a1", size = 126605, upload-time = "2025-07-25T14:33:29.244Z" },
]
[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
]
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.12.1" version = "0.12.1"
@ -693,6 +873,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" },
] ]
[[package]]
name = "pluggy"
version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
]
[[package]] [[package]]
name = "pre-commit" name = "pre-commit"
version = "4.3.0" version = "4.3.0"
@ -835,6 +1024,37 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
] ]
[[package]]
name = "pytelegrambotapi"
version = "4.28.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
{ name = "pytest" },
{ name = "requests" },
{ name = "wheel" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/81/57590c3c481ff3e848b5ae17371a01d903fd21ec1cfa0e7aeaf75e2db3d2/pytelegrambotapi-4.28.0.tar.gz", hash = "sha256:54efd71efb3b48b27301a6cec9ac27bfbd3feb1b5ec1fa23ab26ab4d2df7d376", size = 1358887, upload-time = "2025-07-26T07:29:05.464Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/80/c5ed58a0a75200814ba0238103f713edeb4c1039d4deb9a255b7d79c5a9d/pytelegrambotapi-4.28.0-py3-none-any.whl", hash = "sha256:dc9156a781ebf67cb87ce5cca963a827b871578fafac40eb4e072535cdcb9696", size = 290699, upload-time = "2025-07-26T07:29:03.581Z" },
]
[[package]]
name = "pytest"
version = "8.4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" },
]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.9.0.post0" version = "2.9.0.post0"
@ -856,6 +1076,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" },
] ]
[[package]]
name = "python-json-logger"
version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9e/de/d3144a0bceede957f961e975f3752760fbe390d57fbe194baf709d8f1f7b/python_json_logger-3.3.0.tar.gz", hash = "sha256:12b7e74b17775e7d565129296105bbe3910842d9d0eb083fc83a6a617aa8df84", size = 16642, upload-time = "2025-03-07T07:08:27.301Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/08/20/0f2523b9e50a8052bc6a8b732dfc8568abbdc42010aef03a2d750bdab3b2/python_json_logger-3.3.0-py3-none-any.whl", hash = "sha256:dd980fae8cffb24c13caf6e158d3d61c0d6d22342f932cb6e9deedab3d35eec7", size = 15163, upload-time = "2025-03-07T07:08:25.627Z" },
]
[[package]] [[package]]
name = "pyupgrade" name = "pyupgrade"
version = "3.20.0" version = "3.20.0"
@ -885,6 +1114,30 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" },
] ]
[[package]]
name = "redis"
version = "6.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" },
]
[[package]]
name = "requests"
version = "2.32.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" },
]
[[package]] [[package]]
name = "rich" name = "rich"
version = "14.1.0" version = "14.1.0"
@ -923,6 +1176,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/5c/799a1efb8b5abab56e8a9f2a0b72d12bd64bb55815e9476c7d0a2887d2f7/ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749", size = 11884718, upload-time = "2025-08-07T19:05:42.866Z" }, { url = "https://files.pythonhosted.org/packages/cb/5c/799a1efb8b5abab56e8a9f2a0b72d12bd64bb55815e9476c7d0a2887d2f7/ruff-0.12.8-py3-none-win_arm64.whl", hash = "sha256:c90e1a334683ce41b0e7a04f41790c429bf5073b62c1ae701c9dc5b3d14f0749", size = 11884718, upload-time = "2025-08-07T19:05:42.866Z" },
] ]
[[package]]
name = "sentry-sdk"
version = "2.34.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3a/38/10d6bfe23df1bfc65ac2262ed10b45823f47f810b0057d3feeea1ca5c7ed/sentry_sdk-2.34.1.tar.gz", hash = "sha256:69274eb8c5c38562a544c3e9f68b5be0a43be4b697f5fd385bf98e4fbe672687", size = 336969, upload-time = "2025-07-30T11:13:37.93Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2d/3e/bb34de65a5787f76848a533afbb6610e01fbcdd59e76d8679c254e02255c/sentry_sdk-2.34.1-py2.py3-none-any.whl", hash = "sha256:b7a072e1cdc5abc48101d5146e1ae680fa81fe886d8d95aaa25a0b450c818d32", size = 357743, upload-time = "2025-07-30T11:13:36.145Z" },
]
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "80.9.0" version = "80.9.0"
@ -992,6 +1258,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/45/8c4ebc0c460e6ec38e62ab245ad3c7fc10b210116cea7c16d61602aa9558/stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe", size = 49533, upload-time = "2025-02-20T14:03:55.849Z" }, { url = "https://files.pythonhosted.org/packages/f7/45/8c4ebc0c460e6ec38e62ab245ad3c7fc10b210116cea7c16d61602aa9558/stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe", size = 49533, upload-time = "2025-02-20T14:03:55.849Z" },
] ]
[[package]]
name = "telebot"
version = "0.0.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytelegrambotapi" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1f/3b/e4188cffaf370f432f15d518cbb53a438200ee7ef68c6db1acab337634e1/telebot-0.0.5.tar.gz", hash = "sha256:848a5885b57247b65edd0e92647b4372ebd8d41611dca3f344788c11deac2571", size = 4752, upload-time = "2023-02-14T15:13:44.409Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ad/2f/d8d669be86c42dd2075d7b25bb6de73a3181661a79ef6a3c53dc811f17a1/telebot-0.0.5-py3-none-any.whl", hash = "sha256:50327c240243480d40ade4ea5bea4f464bf57d4ff000ea669fcd705396074863", size = 4840, upload-time = "2023-02-14T15:13:42.698Z" },
]
[[package]] [[package]]
name = "tokenize-rt" name = "tokenize-rt"
version = "6.2.0" version = "6.2.0"
@ -1043,6 +1322,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
] ]
[[package]]
name = "urllib3"
version = "2.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" },
]
[[package]] [[package]]
name = "virtualenv" name = "virtualenv"
version = "20.33.1" version = "20.33.1"
@ -1057,6 +1345,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/ff/ded57ac5ff40a09e6e198550bab075d780941e0b0f83cbeabd087c59383a/virtualenv-20.33.1-py3-none-any.whl", hash = "sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67", size = 6060362, upload-time = "2025-08-05T16:10:52.81Z" }, { url = "https://files.pythonhosted.org/packages/ca/ff/ded57ac5ff40a09e6e198550bab075d780941e0b0f83cbeabd087c59383a/virtualenv-20.33.1-py3-none-any.whl", hash = "sha256:07c19bc66c11acab6a5958b815cbcee30891cd1c2ccf53785a28651a0d8d8a67", size = 6060362, upload-time = "2025-08-05T16:10:52.81Z" },
] ]
[[package]]
name = "wheel"
version = "0.45.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" },
]
[[package]] [[package]]
name = "yarl" name = "yarl"
version = "1.20.1" version = "1.20.1"