initialize Redis integration, logging enhancements, and Telegram bot setup
This commit is contained in:
parent
f153a9825f
commit
9747c9e9b0
@ -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]
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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_",
|
||||||
|
)
|
||||||
|
|||||||
17
src/greek_lang/configs/redis_conn.py
Normal file
17
src/greek_lang/configs/redis_conn.py
Normal 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_",
|
||||||
|
)
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 ###
|
||||||
|
|||||||
@ -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
255
src/greek_lang/logger.py
Normal 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]
|
||||||
0
src/greek_lang/redis_db/__init__.py
Normal file
0
src/greek_lang/redis_db/__init__.py
Normal file
24
src/greek_lang/redis_db/container.py
Normal file
24
src/greek_lang/redis_db/container.py
Normal 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,
|
||||||
|
)
|
||||||
51
src/greek_lang/redis_db/redis_conn.py
Normal file
51
src/greek_lang/redis_db/redis_conn.py
Normal 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)
|
||||||
0
src/greek_lang/tg_bot/__init__.py
Normal file
0
src/greek_lang/tg_bot/__init__.py
Normal file
17
src/greek_lang/tg_bot/__main__.py
Normal file
17
src/greek_lang/tg_bot/__main__.py
Normal 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())
|
||||||
77
src/greek_lang/tg_bot/app.py
Normal file
77
src/greek_lang/tg_bot/app.py
Normal 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()
|
||||||
|
)
|
||||||
0
src/greek_lang/utils/__init__.py
Normal file
0
src/greek_lang/utils/__init__.py
Normal file
0
src/greek_lang/utils/telegram_log/__init__.py
Normal file
0
src/greek_lang/utils/telegram_log/__init__.py
Normal file
103
src/greek_lang/utils/telegram_log/handler.py
Normal file
103
src/greek_lang/utils/telegram_log/handler.py
Normal 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
297
uv.lock
@ -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"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user