From edcbdc5d7591b05eee6e4a6e147320b54f64645c Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:22:07 +0300 Subject: [PATCH 01/13] Add `isort` profile to `ruff` --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index c37974a..aca8624 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ packages = ["app"] target-version = "py311" line-length = 100 pydocstyle = { convention = "google" } +extend-select = ["I"] [tool.isort] profile = "black" From 3c1357efb7a7ab90160c3d548afbe849f2be561c Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:23:44 +0300 Subject: [PATCH 02/13] Remove `black` profile and add config for `ruff` --- .pre-commit-config.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf9c86b..7008a51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,10 +4,6 @@ repos: hooks: - id: end-of-file-fixer - id: trailing-whitespace - - repo: https://github.com/psf/black - rev: 23.12.1 - hooks: - - id: black - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: @@ -18,3 +14,5 @@ repos: rev: v0.1.9 hooks: - id: ruff + name: ruff (rust) + args: ["--config", "pyproject.toml"] From d58f838fd0d538b3af79a39e33700d10898da2c4 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:24:22 +0300 Subject: [PATCH 03/13] Remove `black` from CI --- .github/workflows/lint.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1e6e0f6..bb0bbf8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,12 +34,6 @@ jobs: run: | ruff check --config=pyproject.toml --show-fixes --output-format=github ${{ steps.changed-python-files.outputs.all_changed_files }} - - name: Black - id: black - if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() - run: | - black --config=pyproject.toml --check --diff --verbose ${{ steps.changed-python-files.outputs.all_changed_files }} - - name: Isort id: isort if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() From f85ddd9154d97e8623702c8e48ee188458471641 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:30:14 +0300 Subject: [PATCH 04/13] Apply `ruff` and `isort` for `app` dir --- app/__init__.py | 10 +-- app/config/__init__.py | 19 ++++-- app/config/db.py | 8 +-- app/config/karmic_restriction.py | 14 ++-- app/config/karmic_triggers.py | 64 +++++++++++-------- app/config/logging_config.py | 3 +- app/config/main.py | 8 +-- app/config/moderation.py | 1 - app/config/storage.py | 2 +- app/config/webhook.py | 4 +- app/filters/__init__.py | 11 +++- app/filters/reports.py | 4 +- app/filters/tg_permissions.py | 24 ++----- app/handlers/__init__.py | 19 +++--- app/handlers/base.py | 5 +- app/handlers/change_karma.py | 4 +- app/handlers/chat_rules.py | 8 +-- app/handlers/errors.py | 4 +- app/handlers/karma.py | 16 ++--- app/handlers/moderator.py | 58 +++++------------ app/handlers/superuser.py | 4 +- app/infrastructure/database/models/chat.py | 4 +- app/infrastructure/database/models/report.py | 4 +- .../database/models/user_karma.py | 8 +-- app/infrastructure/database/repo/chat.py | 8 +-- .../database/repo/chat_settings.py | 4 +- app/infrastructure/database/repo/report.py | 30 ++++----- app/infrastructure/database/repo/user.py | 4 +- app/middlewares/config_middleware.py | 12 ++-- app/middlewares/fix_target_middleware.py | 4 +- app/models/config/auto_restriction.py | 8 +-- app/models/config/db.py | 19 +++--- app/models/config/storage.py | 3 +- app/services/adaptive_trottle.py | 8 +-- app/services/karma.py | 16 ++--- app/services/moderation.py | 35 +++------- app/services/report.py | 4 +- app/services/settings.py | 8 +-- app/services/user_getter.py | 4 +- app/utils/exceptions.py | 4 +- app/utils/executor.py | 1 - app/utils/log.py | 12 +++- app/utils/timedelta_functions.py | 3 +- 43 files changed, 201 insertions(+), 292 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 027f728..9c76e35 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,6 @@ -__version__ = '1.4' -__application_name__ = 'KarmaBot' -__author__ = __maintainer__ = 'Yuriy Chebyshev' -__copyright__ = 'Copyleft 2019-2021' +__version__ = "1.4" +__application_name__ = "KarmaBot" +__author__ = __maintainer__ = "Yuriy Chebyshev" +__copyright__ = "Copyleft 2019-2021" __license__ = "WTFPL" -__email__ = 'bomzheg@gmail.com' +__email__ = "bomzheg@gmail.com" diff --git a/app/config/__init__.py b/app/config/__init__.py index d814449..1262543 100644 --- a/app/config/__init__.py +++ b/app/config/__init__.py @@ -3,12 +3,23 @@ """ from .karmic_triggers import ( + MINUS, + MINUS_EMOJI, + MINUS_TRIGGERS, PLUS, - PLUS_TRIGGERS, PLUS_EMOJI, + PLUS_TRIGGERS, PLUS_WORDS, - MINUS, - MINUS_TRIGGERS, - MINUS_EMOJI, ) from .main import load_config + +__all__ = [ + "MINUS", + "MINUS_EMOJI", + "MINUS_TRIGGERS", + "PLUS", + "PLUS_EMOJI", + "PLUS_TRIGGERS", + "PLUS_WORDS", + "load_config", +] diff --git a/app/config/db.py b/app/config/db.py index 00a34e9..080bdd3 100644 --- a/app/config/db.py +++ b/app/config/db.py @@ -6,16 +6,16 @@ def load_db_config(app_dir: Path): db_config = DBConfig() - db_config.db_type = os.getenv("DB_TYPE", default='sqlite') + db_config.db_type = os.getenv("DB_TYPE", default="sqlite") db_config.login = os.getenv("DB_LOGIN") db_config.password = os.getenv("DB_PASSWORD") db_config.db_name = os.getenv("DB_NAME") - db_config.db_host = os.getenv("DB_HOST", default='localhost') + db_config.db_host = os.getenv("DB_HOST", default="localhost") port = os.getenv("DB_PORT") if port is None: - if db_config.db_type == 'mysql': + if db_config.db_type == "mysql": db_config.db_port = 3306 - elif db_config.db_type == 'postgres': + elif db_config.db_type == "postgres": db_config.db_port = 5432 else: db_config.db_port = int(port) diff --git a/app/config/karmic_restriction.py b/app/config/karmic_restriction.py index b76ee7e..340eb05 100644 --- a/app/config/karmic_restriction.py +++ b/app/config/karmic_restriction.py @@ -3,17 +3,19 @@ from app.models.common import TypeRestriction from app.models.config import AutoRestrictionConfig + from .moderation import FOREVER_RESTRICT_DURATION from .restriction_plan import RestrictionPlan, RestrictionPlanElem - NEGATIVE_KARMA_TO_RESTRICT = -100 KARMA_AFTER_RESTRICT = -80 -RESTRICTIONS_PLAN = RestrictionPlan([ - RestrictionPlanElem(timedelta(days=7), TypeRestriction.karmic_ro), - RestrictionPlanElem(timedelta(days=30), TypeRestriction.karmic_ro), - RestrictionPlanElem(FOREVER_RESTRICT_DURATION, TypeRestriction.karmic_ban), -]) +RESTRICTIONS_PLAN = RestrictionPlan( + [ + RestrictionPlanElem(timedelta(days=7), TypeRestriction.karmic_ro), + RestrictionPlanElem(timedelta(days=30), TypeRestriction.karmic_ro), + RestrictionPlanElem(FOREVER_RESTRICT_DURATION, TypeRestriction.karmic_ban), + ] +) def load_karmic_restriction_config() -> AutoRestrictionConfig: diff --git a/app/config/karmic_triggers.py b/app/config/karmic_triggers.py index 347e9e8..0ebdd78 100644 --- a/app/config/karmic_triggers.py +++ b/app/config/karmic_triggers.py @@ -1,28 +1,42 @@ PLUS = "+" -PLUS_WORDS = frozenset({ - "спасибо", - "спс", - "спасибочки", - "спасибки", - "благодарю", - "пасиба", - "пасеба", - "посеба", - "благодарочка", - "thx", - "мерси", - "выручил", - "сяп", - "сяб", - "сенк", - "сенкс", - "сяпки", - "сябки", - "сенью", - "благодарствую", -}) +PLUS_WORDS = frozenset( + { + "спасибо", + "спс", + "спасибочки", + "спасибки", + "благодарю", + "пасиба", + "пасеба", + "посеба", + "благодарочка", + "thx", + "мерси", + "выручил", + "сяп", + "сяб", + "сенк", + "сенкс", + "сяпки", + "сябки", + "сенью", + "благодарствую", + } +) PLUS_TRIGGERS = frozenset({PLUS, *PLUS_WORDS}) -PLUS_EMOJI = frozenset({"👍", }) +PLUS_EMOJI = frozenset( + { + "👍", + } +) MINUS = "-" -MINUS_TRIGGERS = frozenset({MINUS, }) -MINUS_EMOJI = frozenset({'👎', }) +MINUS_TRIGGERS = frozenset( + { + MINUS, + } +) +MINUS_EMOJI = frozenset( + { + "👎", + } +) diff --git a/app/config/logging_config.py b/app/config/logging_config.py index 39940ef..aed14a5 100644 --- a/app/config/logging_config.py +++ b/app/config/logging_config.py @@ -7,7 +7,6 @@ from app.models.config import LogConfig from app.utils.log import Logger - logger = Logger(__name__) @@ -17,6 +16,6 @@ def logging_setup(config_path: Path, log_config: LogConfig): with (config_path / "logging.yaml").open("r") as f: logging_config = yaml.safe_load(f) with suppress(KeyError): - logging_config['handlers']['file']['filename'] = log_dir / "app.log" + logging_config["handlers"]["file"]["filename"] = log_dir / "app.log" logging.config.dictConfig(logging_config) logger.info("Logging configured successfully") diff --git a/app/config/main.py b/app/config/main.py index 91069a2..3b1761a 100644 --- a/app/config/main.py +++ b/app/config/main.py @@ -24,9 +24,7 @@ def load_config(config_dir: Path = None) -> Config: with (config_dir / "bot-config.yaml").open("r", encoding="utf-8") as f: config_file_data = yaml.load(f, Loader=yaml.FullLoader) - log_config = load_log_config( - app_dir=app_dir, log_chat_id=config_file_data["log_chat_id"] - ) + log_config = load_log_config(app_dir=app_dir, log_chat_id=config_file_data["log_chat_id"]) logging_setup(config_dir, log_config) load_dotenv(str(config_dir / ".env")) @@ -44,9 +42,7 @@ def load_config(config_dir: Path = None) -> Config: config_file_data["tg_client_config"] | {"bot_token": _bot_token} ), storage=load_storage(config_file_data["storage"]), - report_award_cleanup_delay=config_file_data.get( - "report_award_cleanup_delay", 3600 - ), + report_award_cleanup_delay=config_file_data.get("report_award_cleanup_delay", 3600), callback_query_answer_cache_time=config_file_data.get( "callback_query_answer_cache_time", 3600 ), diff --git a/app/config/moderation.py b/app/config/moderation.py index cce6a0d..928efa6 100644 --- a/app/config/moderation.py +++ b/app/config/moderation.py @@ -6,7 +6,6 @@ from app.models.common import TypeRestriction - DEFAULT_RESTRICT_DURATION = timedelta(hours=1) FOREVER_RESTRICT_DURATION = timedelta(days=666) RO_ACTION = partial(Bot.restrict_chat_member, permissions=ChatPermissions(can_send_messages=False)) diff --git a/app/config/storage.py b/app/config/storage.py index 7f17b78..e7df555 100644 --- a/app/config/storage.py +++ b/app/config/storage.py @@ -1,6 +1,6 @@ from typing import Any -from app.models.config.storage import StorageConfig, StorageType, RedisConfig +from app.models.config.storage import RedisConfig, StorageConfig, StorageType def load_storage(dct: dict[str, Any]) -> StorageConfig: diff --git a/app/config/webhook.py b/app/config/webhook.py index a5db981..e482945 100644 --- a/app/config/webhook.py +++ b/app/config/webhook.py @@ -7,7 +7,7 @@ def load_webhook_config() -> WebhookConfig: return WebhookConfig( host=os.getenv("WEBHOOK_HOST"), port=os.getenv("WEBHOOK_PORT", default=443), - path=os.getenv("WEBHOOK_PATH", default='/karmabot/'), - listen_host=os.getenv("LISTEN_IP", default='localhost'), + path=os.getenv("WEBHOOK_PATH", default="/karmabot/"), + listen_host=os.getenv("LISTEN_IP", default="localhost"), listen_port=int(os.getenv("LISTEN_PORT", default=3000)), ) diff --git a/app/filters/__init__.py b/app/filters/__init__.py index 92baa53..250575f 100644 --- a/app/filters/__init__.py +++ b/app/filters/__init__.py @@ -2,7 +2,14 @@ from .has_target import HasTargetFilter from .karma_change import KarmaFilter -from .tg_permissions import (BotHasPermissions, HasPermissions, - TargetHasPermissions) +from .tg_permissions import BotHasPermissions, HasPermissions, TargetHasPermissions logger = Logger(__name__) + +__all__ = [ + "HasTargetFilter", + "KarmaFilter", + "BotHasPermissions", + "HasPermissions", + "TargetHasPermissions", +] diff --git a/app/filters/reports.py b/app/filters/reports.py index 31cb046..1584413 100644 --- a/app/filters/reports.py +++ b/app/filters/reports.py @@ -8,9 +8,7 @@ class HasResolvedReport(BaseFilter): """Check if reported message already resolved report""" - async def __call__( - self, message: types.Message, chat: Chat, report_repo: ReportRepo - ) -> bool: + async def __call__(self, message: types.Message, chat: Chat, report_repo: ReportRepo) -> bool: if not message.reply_to_message: return False return await report_repo.has_resolved_report( diff --git a/app/filters/tg_permissions.py b/app/filters/tg_permissions.py index 4d46422..b2bb948 100644 --- a/app/filters/tg_permissions.py +++ b/app/filters/tg_permissions.py @@ -45,14 +45,10 @@ def __post_init__(self): arg: True for arg in self.ARGUMENTS.values() if getattr(self, arg) } - def _get_cached_value( - self, user: types.User, chat: Chat - ) -> types.ChatMember | None: + def _get_cached_value(self, user: types.User, chat: Chat) -> types.ChatMember | None: return None # TODO - def _set_cached_value( - self, user: types.User, chat: Chat, _member: types.ChatMember - ): + def _set_cached_value(self, user: types.User, chat: Chat, _member: types.ChatMember): return None # TODO async def _get_chat_member( @@ -66,9 +62,7 @@ async def _get_chat_member( if target_user_id is None: return False try: - chat_member = next( - filter(lambda member: member.user.id == target_user_id, admins) - ) + chat_member = next(filter(lambda member: member.user.id == target_user_id, admins)) except StopIteration: return False self._set_cached_value(user, chat, chat_member) @@ -92,9 +86,7 @@ async def __call__( return {self.PAYLOAD_ARGUMENT_NAME: chat_member} - def get_target_id( - self, update: types.TelegramObject, user: types.User, bot: Bot - ) -> int | None: + def get_target_id(self, update: types.TelegramObject, user: types.User, bot: Bot) -> int | None: return user.id @@ -107,9 +99,7 @@ class TargetHasPermissions(HasPermissions): can_be_same: bool = False can_be_bot: bool = False - def get_target_id( - self, message: types.Message, user: types.User, bot: Bot - ) -> int | None: + def get_target_id(self, message: types.Message, user: types.User, bot: Bot) -> int | None: target_user = get_target_user(message, self.can_be_same, self.can_be_bot) if target_user is None: return None @@ -133,7 +123,5 @@ class BotHasPermissions(HasPermissions): } PAYLOAD_ARGUMENT_NAME = "bot_member" - def get_target_id( - self, message: types.Message, user: types.User, bot: Bot - ) -> int | None: + def get_target_id(self, message: types.Message, user: types.User, bot: Bot) -> int | None: return bot.id diff --git a/app/handlers/__init__.py b/app/handlers/__init__.py index 932e8de..a749109 100644 --- a/app/handlers/__init__.py +++ b/app/handlers/__init__.py @@ -1,13 +1,16 @@ -from aiogram import Dispatcher, Bot +from aiogram import Bot, Dispatcher -from . import base, chat_rules -from . import change_karma -from . import errors -from . import karma -from . import moderator -from . import settings -from . import superuser from ..models.config import Config +from . import ( + base, + change_karma, + chat_rules, + errors, + karma, + moderator, + settings, + superuser, +) def setup(dp: Dispatcher, bot: Bot, config: Config): diff --git a/app/handlers/base.py b/app/handlers/base.py index 5d9b3fd..fb74bba 100644 --- a/app/handlers/base.py +++ b/app/handlers/base.py @@ -117,10 +117,7 @@ async def cmd_about(message: types.Message): @router.message(Command("idchat", prefix="!")) async def get_idchat(message: types.Message): - text = ( - f"id этого чата: {hpre(message.chat.id)}\n" - f"Ваш id: {hpre(message.from_user.id)}" - ) + text = f"id этого чата: {hpre(message.chat.id)}\n" f"Ваш id: {hpre(message.from_user.id)}" if message.reply_to_message: text += ( f"\nid {hbold(message.reply_to_message.from_user.full_name)}: " diff --git a/app/handlers/change_karma.py b/app/handlers/change_karma.py index f408119..c3d2c0d 100644 --- a/app/handlers/change_karma.py +++ b/app/handlers/change_karma.py @@ -133,9 +133,7 @@ async def cancel_karma( return await callback_query.answer("Эта кнопка не для Вас", cache_time=3600) rollback_karma = float(callback_data.rollback_karma) moderator_event_id = ( - None - if callback_data.moderator_event_id == "null" - else callback_data.moderator_event_id + None if callback_data.moderator_event_id == "null" else callback_data.moderator_event_id ) await cancel_karma_change( callback_data.karma_event_id, rollback_karma, moderator_event_id, bot, user_repo diff --git a/app/handlers/chat_rules.py b/app/handlers/chat_rules.py index c42433f..55b683e 100644 --- a/app/handlers/chat_rules.py +++ b/app/handlers/chat_rules.py @@ -58,10 +58,6 @@ def setup() -> Router: router.message.register(lmgify_cmd, Command("go", prefix="!"), F.reply_to_message) router.message.register(paste_cmd, Command("paste", prefix="!"), F.reply_to_message) router.message.register(nometa_cmd, Command("nm", prefix="!"), F.reply_to_message) - router.message.register( - xy_problem_cmd, Command("xy", prefix="!"), F.reply_to_message - ) - router.message.register( - delete_me_cmd, Command("go", "paste", "nm", "xy", prefix="!") - ) + router.message.register(xy_problem_cmd, Command("xy", prefix="!"), F.reply_to_message) + router.message.register(delete_me_cmd, Command("go", "paste", "nm", "xy", prefix="!")) return router diff --git a/app/handlers/errors.py b/app/handlers/errors.py index d46aff8..1a8f9c9 100644 --- a/app/handlers/errors.py +++ b/app/handlers/errors.py @@ -21,9 +21,7 @@ async def errors_handler(error: ErrorEvent, bot: Bot, config: Config): except TelegramBadRequest as e: if "rights" in e.message and "send" in e.message: if error.update.message and error.update.message.chat: - logger.info( - "bot are muted in chat {chat}", chat=error.update.message.chat.id - ) + logger.info("bot are muted in chat {chat}", chat=error.update.message.chat.id) else: logger.info( "bot can't send message (no rights) in update {update}", diff --git a/app/handlers/karma.py b/app/handlers/karma.py index 47bbfef..07af53a 100644 --- a/app/handlers/karma.py +++ b/app/handlers/karma.py @@ -46,9 +46,7 @@ async def get_top_from_private( if error_message: return await message.reply(error_message) - logger.info( - "user {user} ask top karma of chat {chat}", user=user.tg_id, chat=chat.chat_id - ) + logger.info("user {user} ask top karma of chat {chat}", user=user.tg_id, chat=chat.chat_id) text = await get_karma_top(chat, user, chat_repo=chat_repo, user_repo=user_repo) await message.reply(text, link_preview_options=LinkPreviewOptions(is_disabled=True)) @@ -78,21 +76,15 @@ async def get_top( ) ) - logger.info( - "user {user} ask top karma of chat {chat}", user=user.tg_id, chat=chat.chat_id - ) + logger.info("user {user} ask top karma of chat {chat}", user=user.tg_id, chat=chat.chat_id) text = await get_karma_top(chat, user, chat_repo=chat_repo, user_repo=user_repo) await message.reply(text, link_preview_options=LinkPreviewOptions(is_disabled=True)) @router.message(F.chat.type.in_(["group", "supergroup"]), Command("me", prefix="!")) -async def get_me( - message: types.Message, chat: Chat, user: User, config: Config, bot: Bot -): - logger.info( - "user {user} ask his karma in chat {chat}", user=user.tg_id, chat=chat.chat_id - ) +async def get_me(message: types.Message, chat: Chat, user: User, config: Config, bot: Bot): + logger.info("user {user} ask his karma in chat {chat}", user=user.tg_id, chat=chat.chat_id) uk, number_in_top = await get_me_chat_info(chat=chat, user=user) bot_reply = await message.reply( f"Ваша карма в данном чате: {uk.karma:.2f} ({number_in_top})", diff --git a/app/handlers/moderator.py b/app/handlers/moderator.py index a0e4e3f..18e8724 100644 --- a/app/handlers/moderator.py +++ b/app/handlers/moderator.py @@ -110,9 +110,7 @@ async def report_already_reported(message: types.Message, config: Config, bot: B Command("report", "admin", "spam", prefix="/!@"), ) async def report_private(message: types.Message): - await message.reply( - "Вы можете жаловаться на сообщения пользователей только в группах." - ) + await message.reply("Вы можете жаловаться на сообщения пользователей только в группах.") @router.message( @@ -123,9 +121,7 @@ async def report_private(message: types.Message): ~TargetHasPermissions(), BotHasPermissions(can_restrict_members=True), ) -async def cmd_ro( - message: types.Message, user: User, target: User, chat: Chat, bot: Bot -): +async def cmd_ro(message: types.Message, user: User, target: User, chat: Chat, bot: Bot): try: duration, comment = get_duration(message.text) except TimedeltaParseError as e: @@ -167,9 +163,7 @@ async def cmd_ro_private(message: types.Message): ~TargetHasPermissions(), BotHasPermissions(can_restrict_members=True), ) -async def cmd_ban( - message: types.Message, user: User, target: User, chat: Chat, bot: Bot -): +async def cmd_ban(message: types.Message, user: User, target: User, chat: Chat, bot: Bot): try: duration, comment = get_duration(message.text) except TimedeltaParseError as e: @@ -223,10 +217,8 @@ async def cmd_warn( moderator=user, target_user=target, chat=chat, comment=comment ) - text = ( - "Пользователь {user} получил официальное предупреждение от модератора".format( - user=target.mention_link, - ) + text = "Пользователь {user} получил официальное предупреждение от модератора".format( + user=target.mention_link, ) msg = await message.reply( text, @@ -241,9 +233,7 @@ async def cmd_warn( Command(commands=["w", "warn"], prefix="!"), ) async def cmd_warn_private(message: types.Message): - await message.reply( - "Вы можете выдавать предупреждения пользователям только в группах." - ) + await message.reply("Вы можете выдавать предупреждения пользователям только в группах.") @router.message( @@ -251,9 +241,7 @@ async def cmd_warn_private(message: types.Message): Command("info", prefix="!"), ) async def get_info_about_user_private(message: types.Message): - await message.reply( - "Вы можете запрашивать информацию о пользователях только в группах." - ) + await message.reply("Вы можете запрашивать информацию о пользователях только в группах.") @router.message( @@ -316,9 +304,7 @@ async def cmd_unhandled(message: types.Message): await delete_message(message) -@router.callback_query( - kb.WarnCancelCb.filter(), MagicData(F.user.tg_id == F.callback_data.user_id) -) +@router.callback_query(kb.WarnCancelCb.filter(), MagicData(F.user.tg_id == F.callback_data.user_id)) async def cancel_warn( callback_query: types.CallbackQuery, callback_data: kb.WarnCancelCb, bot: Bot ): @@ -326,9 +312,7 @@ async def cancel_warn( await delete_moderator_event(callback_data.moderator_event_id, moderator=from_user) await callback_query.answer("Вы отменили предупреждение", show_alert=True) - await cleanup_command_dialog( - bot, bot_message=callback_query.message, delete_bot_reply=True - ) + await cleanup_command_dialog(bot, bot_message=callback_query.message, delete_bot_reply=True) @router.callback_query( @@ -393,9 +377,7 @@ async def approve_report_handler( ) -@router.callback_query( - kb.DeclineReportCb.filter(), HasPermissions(can_restrict_members=True) -) +@router.callback_query(kb.DeclineReportCb.filter(), HasPermissions(can_restrict_members=True)) async def decline_report_handler( callback_query: types.CallbackQuery, callback_data: kb.DeclineReportCb, @@ -415,9 +397,7 @@ async def decline_report_handler( report_repo=report_repo, ) await callback_query.answer("Вы отклонили репорт", show_alert=True) - await cleanup_reports_dialog( - first_report, linked_reports, delete_first_reply=True, bot=bot - ) + await cleanup_reports_dialog(first_report, linked_reports, delete_first_reply=True, bot=bot) @router.callback_query( @@ -441,9 +421,7 @@ async def cancel_report_handler( report_repo=report_repo, ) await callback_query.answer("Вы отменили репорт", show_alert=True) - await cleanup_command_dialog( - bot, bot_message=callback_query.message, delete_bot_reply=True - ) + await cleanup_command_dialog(bot, bot_message=callback_query.message, delete_bot_reply=True) @router.callback_query( @@ -453,15 +431,9 @@ async def cancel_report_handler( @router.callback_query( kb.CancelReportCb.filter(), MagicData(F.user.id != F.callback_data.reporter_id) ) -@router.callback_query( - kb.ApproveReportCb.filter(), ~HasPermissions(can_restrict_members=True) -) -@router.callback_query( - kb.DeclineReportCb.filter(), ~HasPermissions(can_restrict_members=True) -) -async def unauthorized_button_action( - callback_query: types.CallbackQuery, config: Config -): +@router.callback_query(kb.ApproveReportCb.filter(), ~HasPermissions(can_restrict_members=True)) +@router.callback_query(kb.DeclineReportCb.filter(), ~HasPermissions(can_restrict_members=True)) +async def unauthorized_button_action(callback_query: types.CallbackQuery, config: Config): await callback_query.answer( "Эта кнопка не для Вас", cache_time=config.callback_query_answer_cache_time ) diff --git a/app/handlers/superuser.py b/app/handlers/superuser.py index e84df21..1cd0ee7 100644 --- a/app/handlers/superuser.py +++ b/app/handlers/superuser.py @@ -37,8 +37,6 @@ def setup_superuser(bot_config: Config) -> Router: router.message.register(exception, Command(commands="exception")) router.message.register(leave_chat, Command(commands="get_out")) - router.message.register( - show_tagged_users, Command(commands="entities", prefix="!/") - ) + router.message.register(show_tagged_users, Command(commands="entities", prefix="!/")) return router diff --git a/app/infrastructure/database/models/chat.py b/app/infrastructure/database/models/chat.py index 36ed4b7..a9c3384 100644 --- a/app/infrastructure/database/models/chat.py +++ b/app/infrastructure/database/models/chat.py @@ -36,9 +36,7 @@ def mention(self): ) def __str__(self): - rez = ( - f"Chat with type: {self.type_} with ID {self.chat_id}, title: {self.title}" - ) + rez = f"Chat with type: {self.type_} with ID {self.chat_id}, title: {self.title}" if self.username: rez += f" Username @{self.username}" if self.description: diff --git a/app/infrastructure/database/models/report.py b/app/infrastructure/database/models/report.py index 77b9895..916335e 100644 --- a/app/infrastructure/database/models/report.py +++ b/app/infrastructure/database/models/report.py @@ -32,9 +32,7 @@ class Report(Model): command_message_id = fields.BigIntField(generated=False, null=False) bot_reply_message_id = fields.BigIntField(generated=False, null=True) reported_message_id = fields.BigIntField(generated=False, null=False) - reported_message_content = fields.CharField( - null=False, max_length=TG_MESSAGE_MAX_LEN - ) + reported_message_content = fields.CharField(null=False, max_length=TG_MESSAGE_MAX_LEN) resolved_by: fields.ForeignKeyRelation[User] = fields.ForeignKeyField( "models.User", related_name="resolved_reports", null=True ) diff --git a/app/infrastructure/database/models/user_karma.py b/app/infrastructure/database/models/user_karma.py index ef8ebf0..ad11283 100644 --- a/app/infrastructure/database/models/user_karma.py +++ b/app/infrastructure/database/models/user_karma.py @@ -55,9 +55,7 @@ async def change( (how_change) must be from -inf to +inf """ if how_change == 0: - raise ValueError( - f"how_change must be float and not 0 but it is {how_change}" - ) + raise ValueError(f"how_change must be float and not 0 but it is {how_change}") await self.fetch_related("chat", using_db=using_db) if skip_power_check: @@ -132,9 +130,7 @@ async def number_in_top(self) -> int: async def all_to_json(cls, chat_id: int = None) -> dict: if chat_id is not None: uks = ( - await cls.filter(chat_id=chat_id) - .prefetch_related("user") - .order_by(*karma_filters) + await cls.filter(chat_id=chat_id).prefetch_related("user").order_by(*karma_filters) ) return {chat_id: [{**uk.user.to_json(), "karma": uk.karma} for uk in uks]} else: diff --git a/app/infrastructure/database/repo/chat.py b/app/infrastructure/database/repo/chat.py index 9c8bd6a..d8aceb2 100644 --- a/app/infrastructure/database/repo/chat.py +++ b/app/infrastructure/database/repo/chat.py @@ -40,9 +40,7 @@ async def get_or_create_from_tg_chat(self, chat) -> Chat: chat = await self.create_from_tg_chat(chat=chat) return chat - async def get_top_karma_list( - self, chat: Chat, limit: int = 15 - ) -> list[TopResultEntry]: + async def get_top_karma_list(self, chat: Chat, limit: int = 15) -> list[TopResultEntry]: await chat.fetch_related("user_karma", using_db=self.session) users_karmas = ( await chat.user_karma.order_by(*karma_filters) @@ -69,9 +67,7 @@ async def get_neighbours( .all() ) - user_uk = ( - await chat.user_karma.filter(user=user).prefetch_related("user").first() - ) + user_uk = await chat.user_karma.filter(user=user).prefetch_related("user").first() return uk[0], user_uk, uk[1] async def get_neighbours_id(self, chat_id, user_id) -> Neighbours: diff --git a/app/infrastructure/database/repo/chat_settings.py b/app/infrastructure/database/repo/chat_settings.py index 839a82e..2514b9a 100644 --- a/app/infrastructure/database/repo/chat_settings.py +++ b/app/infrastructure/database/repo/chat_settings.py @@ -8,9 +8,7 @@ def __init__(self, session: BaseDBAsyncClient | None = None): self.session = session async def get_or_create(self, chat: Chat) -> ChatSettings: - chat_settings, _ = await ChatSettings.get_or_create( - chat=chat, using_db=self.session - ) + chat_settings, _ = await ChatSettings.get_or_create(chat=chat, using_db=self.session) return chat_settings async def update_karma_counting(self, chat_settings: ChatSettings, value: bool): diff --git a/app/infrastructure/database/repo/report.py b/app/infrastructure/database/repo/report.py index 804d94b..5207f3a 100644 --- a/app/infrastructure/database/repo/report.py +++ b/app/infrastructure/database/repo/report.py @@ -39,24 +39,20 @@ async def get_report_by_id(self, report_id: int) -> Report: return await Report.get(id=report_id, using_db=self.session) async def get_linked_pending_reports(self, report_id: int) -> Iterable[Report]: - report = await Report.get(id=report_id, using_db=self.session).prefetch_related( - "chat" - ) - return ( - await ( - Report.filter( - chat=report.chat, - reported_message_id=report.reported_message_id, - status=ReportStatus.PENDING, - ) - .prefetch_related("chat", "reporter") - # Sort by `created_time` and command_message_id to get the first report - # If `created_time` is the same, - # the first report is the one with the lowest `command_message_id` - .order_by("created_time", "command_message_id") - .using_db(self.session) - .all() + report = await Report.get(id=report_id, using_db=self.session).prefetch_related("chat") + return await ( + Report.filter( + chat=report.chat, + reported_message_id=report.reported_message_id, + status=ReportStatus.PENDING, ) + .prefetch_related("chat", "reporter") + # Sort by `created_time` and command_message_id to get the first report + # If `created_time` is the same, + # the first report is the one with the lowest `command_message_id` + .order_by("created_time", "command_message_id") + .using_db(self.session) + .all() ) async def has_resolved_report(self, chat_id: int, message_id: int) -> bool: diff --git a/app/infrastructure/database/repo/user.py b/app/infrastructure/database/repo/user.py index f1010d7..65b19b0 100644 --- a/app/infrastructure/database/repo/user.py +++ b/app/infrastructure/database/repo/user.py @@ -55,9 +55,7 @@ async def update_user_data(self, user: User, tg_user: types.User): if changed: await self.save(user) - async def get_or_create_from_tg_user( - self, tg_user: types.User | dto.TargetUser - ) -> User: + async def get_or_create_from_tg_user(self, tg_user: types.User | dto.TargetUser) -> User: if tg_user.id is None: try: return await User.get(username__iexact=tg_user.username) diff --git a/app/middlewares/config_middleware.py b/app/middlewares/config_middleware.py index 2bbded1..9168ed0 100644 --- a/app/middlewares/config_middleware.py +++ b/app/middlewares/config_middleware.py @@ -1,4 +1,4 @@ -from typing import Callable, Dict, Any, Awaitable +from typing import Any, Awaitable, Callable, Dict from aiogram import BaseMiddleware from aiogram.types.base import TelegramObject @@ -6,7 +6,6 @@ from app.models.config import Config from app.utils.log import Logger - logger = Logger(__name__) @@ -15,8 +14,11 @@ def __init__(self, config: Config): super(ConfigMiddleware, self).__init__() self.config = config - async def __call__(self, handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], event: TelegramObject, - data: Dict[str, Any]) -> Any: + async def __call__( + self, + handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], + event: TelegramObject, + data: Dict[str, Any], + ) -> Any: data["config"]: Config = self.config return await handler(event, data) - diff --git a/app/middlewares/fix_target_middleware.py b/app/middlewares/fix_target_middleware.py index 93c8feb..54296e0 100644 --- a/app/middlewares/fix_target_middleware.py +++ b/app/middlewares/fix_target_middleware.py @@ -23,9 +23,7 @@ async def __call__( ) -> Any: if target := data.get("target", None): logger.debug("Starting target lookup either in db or by pyrogram") - target = await get_db_user_by_tg_user( - target, self.user_getter, data["user_repo"] - ) + target = await get_db_user_by_tg_user(target, self.user_getter, data["user_repo"]) data["target"] = target logger.debug("Target resolved") return await handler(event, data) diff --git a/app/models/config/auto_restriction.py b/app/models/config/auto_restriction.py index e9238da..c5a2038 100644 --- a/app/models/config/auto_restriction.py +++ b/app/models/config/auto_restriction.py @@ -59,9 +59,7 @@ def render_auto_restriction(self, user: "User", count_auto_restrict: int): ) return text - def render_negative_karma_notification( - self, user: "User", count_auto_restrict: int - ): + def render_negative_karma_notification(self, user: "User", count_auto_restrict: int): if self.next_will_be_last_restriction(count_auto_restrict): template = ( "Внимание {username}!\nУ Вас отрицательная карма. " @@ -80,7 +78,5 @@ def render_negative_karma_notification( return template.format( username=user.mention_link, threshold=self.threshold, - duration=self.plan.get_next_restriction_printable_duration( - count_auto_restrict - ), + duration=self.plan.get_next_restriction_printable_duration(count_auto_restrict), ) diff --git a/app/models/config/db.py b/app/models/config/db.py index 3de7346..2890d53 100644 --- a/app/models/config/db.py +++ b/app/models/config/db.py @@ -2,7 +2,6 @@ from app.utils.log import Logger - logger = Logger(__name__) @@ -17,20 +16,18 @@ class DBConfig: db_path: str = None def create_url_config(self): - if self.db_type == 'mysql': - db_url = ( - f'{self.db_type}://{self.login}:{self.password}' - f'@{self.db_host}:{self.db_port}/{self.db_name}' - ) - elif self.db_type == 'postgres': + if self.db_type == "mysql": db_url = ( - f'{self.db_type}://{self.login}:{self.password}' - f'@{self.db_host}:{self.db_port}/{self.db_name}' + f"{self.db_type}://{self.login}:{self.password}" + f"@{self.db_host}:{self.db_port}/{self.db_name}" ) - elif self.db_type == 'sqlite': + elif self.db_type == "postgres": db_url = ( - f'{self.db_type}://{self.db_path}' + f"{self.db_type}://{self.login}:{self.password}" + f"@{self.db_host}:{self.db_port}/{self.db_name}" ) + elif self.db_type == "sqlite": + db_url = f"{self.db_type}://{self.db_path}" else: raise ValueError("DB_TYPE not mysql, sqlite or postgres") logger.debug(db_url) diff --git a/app/models/config/storage.py b/app/models/config/storage.py index 5931df9..a9f63dc 100644 --- a/app/models/config/storage.py +++ b/app/models/config/storage.py @@ -1,6 +1,6 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass from enum import Enum from aiogram.fsm.storage.base import BaseStorage @@ -43,4 +43,3 @@ class RedisConfig: def create_redis_storage(self) -> RedisStorage: logger.info("created storage for {self}", self=self) return RedisStorage(Redis(host=self.url, port=self.port, db=self.db)) - diff --git a/app/services/adaptive_trottle.py b/app/services/adaptive_trottle.py index 9d61e6e..04db461 100644 --- a/app/services/adaptive_trottle.py +++ b/app/services/adaptive_trottle.py @@ -45,9 +45,7 @@ async def wrapped(*args, **kwargs): ): return await func(*args, **kwargs) else: - await process_on_throttled( - on_throttled, current_key, rate, *args, **kwargs - ) + await process_on_throttled(on_throttled, current_key, rate, *args, **kwargs) return wrapped @@ -95,9 +93,7 @@ def get_bucket(self, chat_id: int, user_id: int, target_user_id: int): ) def set_bucket(self, chat_id: int, user_id: int, target_user_id: int, bucket: dict): - self.last_calls.setdefault(chat_id, {}).setdefault(user_id, {})[ - target_user_id - ] = bucket + self.last_calls.setdefault(chat_id, {}).setdefault(user_id, {})[target_user_id] = bucket async def process_on_throttled( diff --git a/app/services/karma.py b/app/services/karma.py index 8a0f629..07a0efd 100644 --- a/app/services/karma.py +++ b/app/services/karma.py @@ -22,9 +22,7 @@ async def get_top( chat: Chat, user: User, user_repo: UserRepo, chat_repo: ChatRepo, limit: int = 15 ): top_karmas = await chat_repo.get_top_karma_list(chat, limit) - text_list = format_output( - [(i, user, karma) for i, (user, karma) in enumerate(top_karmas, 1)] - ) + text_list = format_output([(i, user, karma) for i, (user, karma) in enumerate(top_karmas, 1)]) text = add_caption(text_list) try: prev_uk, user_uk, next_uk = await chat_repo.get_neighbours(user, chat) @@ -36,17 +34,11 @@ async def get_top( neighbours_karmas = [] if prev_uk.user.id not in user_ids: text = add_separator(text) - neighbours_karmas.append( - (number_user_in_top - 1, prev_uk.user, prev_uk.karma_round) - ) + neighbours_karmas.append((number_user_in_top - 1, prev_uk.user, prev_uk.karma_round)) if user_uk.user.id not in user_ids: - neighbours_karmas.append( - (number_user_in_top, user_uk.user, user_uk.karma_round) - ) + neighbours_karmas.append((number_user_in_top, user_uk.user, user_uk.karma_round)) if next_uk.user.id not in user_ids: - neighbours_karmas.append( - (number_user_in_top + 1, next_uk.user, next_uk.karma_round) - ) + neighbours_karmas.append((number_user_in_top + 1, next_uk.user, next_uk.karma_round)) additional_users = format_output(neighbours_karmas) return text + "\n" + additional_users diff --git a/app/services/moderation.py b/app/services/moderation.py index 1db1f77..e97ebf2 100644 --- a/app/services/moderation.py +++ b/app/services/moderation.py @@ -21,9 +21,7 @@ config = load_config() -async def warn_user( - moderator: User, target_user: User, chat: Chat, comment: str -) -> ModeratorEvent: +async def warn_user(moderator: User, target_user: User, chat: Chat, comment: str) -> ModeratorEvent: return await ModeratorEvent.save_new_action( moderator=moderator, user=target_user, @@ -45,13 +43,9 @@ async def ban_user( comment=comment, type_restriction=TypeRestriction.ban, ) - text = "Пользователь {user} попал в бан этого чата.".format( - user=target.mention_link - ) + text = "Пользователь {user} попал в бан этого чата.".format(user=target.mention_link) if duration < moderation.FOREVER_RESTRICT_DURATION: - text += " Он сможет вернуться через {duration}".format( - duration=format_timedelta(duration) - ) + text += " Он сможет вернуться через {duration}".format(duration=format_timedelta(duration)) return text @@ -68,8 +62,7 @@ async def ro_user( type_restriction=TypeRestriction.ro, ) return ( - "Пользователь {user} сможет только читать " - "сообщения на протяжении {duration}" + "Пользователь {user} сможет только читать " "сообщения на протяжении {duration}" ).format( user=target.mention_link, duration=format_timedelta(duration), @@ -146,9 +139,7 @@ def get_duration(text: str) -> tuple[timedelta, str]: async def user_has_now_ro(user: User, chat: Chat, bot: Bot) -> bool: try: - chat_member = await bot.get_chat_member( - chat_id=chat.chat_id, user_id=user.tg_id - ) + chat_member = await bot.get_chat_member(chat_id=chat.chat_id, user_id=user.tg_id) except TelegramBadRequest as e: # TODO #102 probably we need to disable karmic ro for chats with hidden members? if "user not found" in e.message: @@ -183,9 +174,7 @@ async def auto_restrict( count=count_auto_restrict, ) - current_restriction = config.auto_restriction.get_next_restriction( - count_auto_restrict - ) + current_restriction = config.auto_restriction.get_next_restriction(count_auto_restrict) moderator_event = await restrict( bot=bot, @@ -207,9 +196,7 @@ async def get_count_auto_restrict( bot_user: User | None = None, bot: Bot | None = None, ) -> int: - assert ( - bot is not None or bot_user is not None - ), "One of bot and bot_user must be not None" + assert bot is not None or bot_user is not None, "One of bot and bot_user must be not None" if bot_user is None: bot_user = await user_repo.get_or_create_from_tg_user(await bot.me()) return await ModeratorEvent.filter( @@ -223,9 +210,7 @@ async def get_count_auto_restrict( ).count() -async def delete_moderator_event( - moderator_event_id: int, moderator: User | None = None -): +async def delete_moderator_event(moderator_event_id: int, moderator: User | None = None): moderator_event = await ModeratorEvent.get(id_=moderator_event_id) logger.info( @@ -245,9 +230,7 @@ async def get_mentions_admins( admins = await bot.get_chat_administrators(chat.id) random.shuffle(admins) # чтобы попадались разные админы admins_mention = "" - notifiable_admins = [ - admin for admin in admins if need_notify_admin(admin, ignore_anonymous) - ] + notifiable_admins = [admin for admin in admins if need_notify_admin(admin, ignore_anonymous)] random_five_admins = notifiable_admins[:5] for admin in random_five_admins: admins_mention += hidden_link(admin.user.url) diff --git a/app/services/report.py b/app/services/report.py index 1375165..c0f8dfe 100644 --- a/app/services/report.py +++ b/app/services/report.py @@ -42,9 +42,7 @@ async def resolve_report( Returns all linked reports. """ resolution_time = datetime.utcnow() - first_report, *linked_reports = await report_repo.get_linked_pending_reports( - report_id - ) + first_report, *linked_reports = await report_repo.get_linked_pending_reports(report_id) first_report.resolved_by = resolved_by first_report.status = resolution diff --git a/app/services/settings.py b/app/services/settings.py index ec3a48c..7222fcc 100644 --- a/app/services/settings.py +++ b/app/services/settings.py @@ -16,15 +16,11 @@ async def enable_karmic_restriction( await chat_settings_repo.update_karmic_restriction(chat_settings, True) -async def disable_karma_counting( - chat_settings: ChatSettings, chat_settings_repo: ChatSettingsRepo -): +async def disable_karma_counting(chat_settings: ChatSettings, chat_settings_repo: ChatSettingsRepo): await chat_settings_repo.update_karma_counting(chat_settings, False) -async def enable_karma_counting( - chat_settings: ChatSettings, chat_settings_repo: ChatSettingsRepo -): +async def enable_karma_counting(chat_settings: ChatSettings, chat_settings_repo: ChatSettingsRepo): await chat_settings_repo.update_karma_counting(chat_settings, True) diff --git a/app/services/user_getter.py b/app/services/user_getter.py index 1c9ac38..ccaa86f 100644 --- a/app/services/user_getter.py +++ b/app/services/user_getter.py @@ -41,9 +41,7 @@ async def get_user_by_username(self, username: str) -> User: except FloodWait as e: logger.error("Flood Wait {e}", e=e) await asyncio.sleep(e.value) - raise Exception( - "Username resolver encountered flood error. Waited for %s", e.value - ) + raise Exception("Username resolver encountered flood error. Waited for %s", e.value) return self.get_aiogram_user_by_pyrogram(user) diff --git a/app/utils/exceptions.py b/app/utils/exceptions.py index 4123043..11b7975 100644 --- a/app/utils/exceptions.py +++ b/app/utils/exceptions.py @@ -1,7 +1,5 @@ class KarmaError(Exception): - def __init__( - self, text: str = None, user_id: int = None, chat_id: int = None, *args - ): + def __init__(self, text: str = None, user_id: int = None, chat_id: int = None, *args): super(KarmaError, self).__init__(text, args) self.text = text self.user_id = user_id diff --git a/app/utils/executor.py b/app/utils/executor.py index b67e9d0..70a1c88 100644 --- a/app/utils/executor.py +++ b/app/utils/executor.py @@ -7,7 +7,6 @@ from app.models.config import Config, WebhookConfig from app.utils.log import Logger - logger = Logger(__name__) diff --git a/app/utils/log.py b/app/utils/log.py index 932083e..7648891 100644 --- a/app/utils/log.py +++ b/app/utils/log.py @@ -5,7 +5,17 @@ class Logger(logging.LoggerAdapter): def __init__(self, name: str, extra=None): super().__init__(logging.getLogger(name), extra or {}) - def log(self, level, msg: str, *args, exc_info=None, extra=None, stack_info=False, stacklevel=1, **kwargs): + def log( + self, + level, + msg: str, + *args, + exc_info=None, + extra=None, + stack_info=False, + stacklevel=1, + **kwargs, + ): if self.isEnabledFor(level): # noinspection PyProtectedMember self.logger._log( diff --git a/app/utils/timedelta_functions.py b/app/utils/timedelta_functions.py index 2611f53..d17ca63 100644 --- a/app/utils/timedelta_functions.py +++ b/app/utils/timedelta_functions.py @@ -2,8 +2,7 @@ import re import typing -from app.utils.exceptions import ToLongDuration, InvalidFormatDuration - +from app.utils.exceptions import InvalidFormatDuration, ToLongDuration MODIFIERS = { "y": datetime.timedelta(days=365), # простим один день если кому-то попадётся високосный From 51933bb331d5737c1ae5bc13cf4fd1b5dde3f1a2 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:31:20 +0300 Subject: [PATCH 05/13] Apply `ruff` and `isort` for `tests` dir --- tests/__init__.py | 1 - tests/karma/common.py | 27 +++++++++-- tests/karma/fixtures/__init__.py | 10 +++- tests/karma/fixtures/fixtures_karma.py | 18 +++---- tests/karma/test_correct_karma_filter.py | 6 +-- tests/karma/test_not_one_word.py | 9 ++-- tests/target/common.py | 1 - tests/target/correct_targets.py | 15 ++++-- tests/target/fixtures/__init__.py | 17 ++++++- tests/target/fixtures/targets.py | 48 +++++++++---------- tests/target/test_auto_target.py | 35 +++++++++----- .../timedelta/fixtures/fixterus_timedelta.py | 4 +- tests/timedelta/test_timedelta_parser.py | 1 + 13 files changed, 124 insertions(+), 68 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 911265c..deabe5e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,5 +2,4 @@ from app.config import load_config - load_config(Path(__file__).parent.parent / "config_dist") diff --git a/tests/karma/common.py b/tests/karma/common.py index e213fb1..3993636 100644 --- a/tests/karma/common.py +++ b/tests/karma/common.py @@ -3,11 +3,17 @@ from aiogram import types from app.filters.karma_change import ( - KarmaFilter, PUNCTUATIONS, PLUS_TRIGGERS, PLUS_EMOJI, MINUS_TRIGGERS, - MINUS_EMOJI, PLUS, INF, check, + INF, + MINUS_EMOJI, + MINUS_TRIGGERS, + PLUS, + PLUS_EMOJI, + PLUS_TRIGGERS, + PUNCTUATIONS, + KarmaFilter, + check, ) - plus_texts = (*PLUS_TRIGGERS, *PLUS_EMOJI, PLUS * 2, PLUS * 3, PLUS * 4) minus_texts = (*MINUS_TRIGGERS, *MINUS_EMOJI) punctuations = [*PUNCTUATIONS, ""] @@ -19,6 +25,17 @@ def filter_check(message: types.Message): __all__ = [ - KarmaFilter, PUNCTUATIONS, PLUS_TRIGGERS, PLUS_EMOJI, MINUS_TRIGGERS, MINUS_EMOJI, PLUS, INF, - plus_texts, minus_texts, punctuations, SPACES, filter_check + KarmaFilter, + PUNCTUATIONS, + PLUS_TRIGGERS, + PLUS_EMOJI, + MINUS_TRIGGERS, + MINUS_EMOJI, + PLUS, + INF, + plus_texts, + minus_texts, + punctuations, + SPACES, + filter_check, ] diff --git a/tests/karma/fixtures/__init__.py b/tests/karma/fixtures/__init__.py index 94da0bf..75f43ba 100644 --- a/tests/karma/fixtures/__init__.py +++ b/tests/karma/fixtures/__init__.py @@ -2,6 +2,14 @@ generate_phrases_next_word, get_message_with_text, get_next_word_parts, - wrong_generate_phrases_next_word, get_wrong_next_word_parts, + wrong_generate_phrases_next_word, ) + +__all__ = [ + "generate_phrases_next_word", + "get_message_with_text", + "get_next_word_parts", + "get_wrong_next_word_parts", + "wrong_generate_phrases_next_word", +] diff --git a/tests/karma/fixtures/fixtures_karma.py b/tests/karma/fixtures/fixtures_karma.py index 9f350aa..c4f02d6 100644 --- a/tests/karma/fixtures/fixtures_karma.py +++ b/tests/karma/fixtures/fixtures_karma.py @@ -7,9 +7,7 @@ def get_next_word_parts( - first_word: str, - punctuations: typing.Iterable[str], - spaces: typing.Iterable[str] + first_word: str, punctuations: typing.Iterable[str], spaces: typing.Iterable[str] ) -> typing.List[typing.List[str]]: """ собрать список из списков [first_word, знак препинания, пробельный символ, сгенерированные следующее слово] @@ -23,9 +21,7 @@ def get_next_word_parts( def generate_phrases_next_word( - first_word: str, - punctuations: typing.Iterable[str], - spaces: typing.Iterable[str] + first_word: str, punctuations: typing.Iterable[str], spaces: typing.Iterable[str] ) -> typing.List[str]: """ get string like %karma_trigger%%punctuation%%space%%next_words% @@ -34,7 +30,9 @@ def generate_phrases_next_word( return ["".join(precursors_list) for precursors_list in precursors_lists] -def get_wrong_next_word_parts(first_word: str, punctuations: typing.Iterable[str]) -> typing.List[typing.List[str]]: +def get_wrong_next_word_parts( + first_word: str, punctuations: typing.Iterable[str] +) -> typing.List[typing.List[str]]: """ собрать список из списков [first_word, знак препинания, "", сгенерированные следующее слово] """ @@ -45,14 +43,16 @@ def get_wrong_next_word_parts(first_word: str, punctuations: typing.Iterable[str return rez -def wrong_generate_phrases_next_word(first_word: str, punctuations: typing.Iterable[str]) -> typing.List[str]: +def wrong_generate_phrases_next_word( + first_word: str, punctuations: typing.Iterable[str] +) -> typing.List[str]: """get string like %karma_trigger%%punctuation%%next_words% without spaces""" precursors_lists = get_wrong_next_word_parts(first_word, punctuations) return ["".join(precursors_list) for precursors_list in precursors_lists] def get_next_words(count_symbols: int = 10) -> str: - return ''.join(choice(ascii_letters) for _ in range(count_symbols)) + return "".join(choice(ascii_letters) for _ in range(count_symbols)) def get_message_with_text(text: str) -> types.Message: diff --git a/tests/karma/test_correct_karma_filter.py b/tests/karma/test_correct_karma_filter.py index 8410f3e..db004f9 100644 --- a/tests/karma/test_correct_karma_filter.py +++ b/tests/karma/test_correct_karma_filter.py @@ -1,6 +1,6 @@ import pytest -from .common import plus_texts, minus_texts, punctuations, filter_check, SPACES, INF +from .common import INF, SPACES, filter_check, minus_texts, plus_texts, punctuations from .fixtures import generate_phrases_next_word, get_message_with_text @@ -13,7 +13,7 @@ def test_correct_plus(text: str): def check_plus(text_with_plus_trigger: str): msg = get_message_with_text(text_with_plus_trigger) filter_rez = filter_check(msg) - assert filter_rez['karma']['karma_change'] == INF, str(msg) + assert filter_rez["karma"]["karma_change"] == INF, str(msg) @pytest.mark.parametrize("text", minus_texts) @@ -25,4 +25,4 @@ def test_correct_minus(text: str): def check_minus_reply(text_with_minus_trigger: str): msg = get_message_with_text(text_with_minus_trigger) filter_rez = filter_check(msg) - assert filter_rez['karma']['karma_change'] == -INF, str(msg) + assert filter_rez["karma"]["karma_change"] == -INF, str(msg) diff --git a/tests/karma/test_not_one_word.py b/tests/karma/test_not_one_word.py index d980db3..d2e5233 100644 --- a/tests/karma/test_not_one_word.py +++ b/tests/karma/test_not_one_word.py @@ -1,6 +1,9 @@ -from .common import PLUS_TRIGGERS, MINUS_TRIGGERS, punctuations, filter_check -from .fixtures import (wrong_generate_phrases_next_word, get_message_with_text, - generate_phrases_next_word) +from .common import MINUS_TRIGGERS, PLUS_TRIGGERS, filter_check, punctuations +from .fixtures import ( + generate_phrases_next_word, + get_message_with_text, + wrong_generate_phrases_next_word, +) def test_plus(): diff --git a/tests/target/common.py b/tests/target/common.py index b0c37f2..356d097 100644 --- a/tests/target/common.py +++ b/tests/target/common.py @@ -5,7 +5,6 @@ from app.filters.has_target import HasTargetFilter - CONF_CAN_BE_SAME = dict(can_be_same=True) CONF_CANT_BE_SAME = dict(can_be_same=False) diff --git a/tests/target/correct_targets.py b/tests/target/correct_targets.py index 269c315..ad53d04 100644 --- a/tests/target/correct_targets.py +++ b/tests/target/correct_targets.py @@ -1,9 +1,14 @@ import pytest from aiogram import types -from .common import filter_check, CONF_CANT_BE_SAME -from .fixtures import (get_from_user, get_message_with_reply, - get_message_with_text_mention, get_message_with_mention, get_parts) +from .common import CONF_CANT_BE_SAME, filter_check +from .fixtures import ( + get_from_user, + get_message_with_mention, + get_message_with_reply, + get_message_with_text_mention, + get_parts, +) def test_reply_target(): @@ -35,6 +40,8 @@ def check_target(target_user: dict, msg: types.Message): target_user = types.User(**target_user) founded_user = filter_rez["target"] if founded_user.id is None: - assert founded_user.username == target_user.username, f"msg text {{{msg.text}}} user: {{{target_user}}}" + assert ( + founded_user.username == target_user.username + ), f"msg text {{{msg.text}}} user: {{{target_user}}}" else: assert founded_user == target_user, f"msg text {{{msg.text}}} user: {{{target_user}}}" diff --git a/tests/target/fixtures/__init__.py b/tests/target/fixtures/__init__.py index 4f7ec16..50a31ec 100644 --- a/tests/target/fixtures/__init__.py +++ b/tests/target/fixtures/__init__.py @@ -1,2 +1,15 @@ -from .targets import get_from_user, get_message_with_reply, \ - get_message_with_text_mention, get_message_with_mention, get_parts +from .targets import ( + get_from_user, + get_message_with_mention, + get_message_with_reply, + get_message_with_text_mention, + get_parts, +) + +__all__ = [ + "get_from_user", + "get_message_with_mention", + "get_message_with_reply", + "get_message_with_text_mention", + "get_parts", +] diff --git a/tests/target/fixtures/targets.py b/tests/target/fixtures/targets.py index c92130a..2089301 100644 --- a/tests/target/fixtures/targets.py +++ b/tests/target/fixtures/targets.py @@ -18,7 +18,7 @@ def get_parts() -> typing.List[typing.List[str]]: def get_words(count_symbols: int = 10) -> str: - return ''.join(choice(ascii_letters) for _ in range(count_symbols)) + return "".join(choice(ascii_letters) for _ in range(count_symbols)) def get_message_with_reply(author_user: dict, target_user: dict, text: str) -> types.Message: @@ -32,7 +32,9 @@ def get_message_with_reply(author_user: dict, target_user: dict, text: str) -> t ) -def get_message_with_mention(author_user: dict, target_user: dict, text_precursors: typing.List[str]) -> types.Message: +def get_message_with_mention( + author_user: dict, target_user: dict, text_precursors: typing.List[str] +) -> types.Message: username = get_user_username(target_user) text_precursors[1] = username msg_text = " ".join(text_precursors) @@ -45,46 +47,40 @@ def get_message_with_mention(author_user: dict, target_user: dict, text_precurso ], message_id=1, date=datetime.now(), - chat=types.Chat(id=1, type="group") + chat=types.Chat(id=1, type="group"), ) def get_entity_mention(offset, length) -> types.MessageEntity: - return types.MessageEntity(**{ - "offset": offset, - "length": length, - "type": "mention" - }) + return types.MessageEntity(**{"offset": offset, "length": length, "type": "mention"}) def get_message_with_text_mention( - author_user: dict, - target_user: dict, - text_precursors: typing.List[str] + author_user: dict, target_user: dict, text_precursors: typing.List[str] ) -> types.Message: - first_name = target_user['first_name'] + first_name = target_user["first_name"] text_precursors[1] = first_name msg_text = " ".join(text_precursors) start_entity_pos = len(text_precursors[0]) + 1 # добавляем длину пробела return types.Message( from_user=types.User(**author_user), text=msg_text, - entities=[ - get_entity_text_mention(start_entity_pos, target_user) - ], + entities=[get_entity_text_mention(start_entity_pos, target_user)], message_id=1, date=datetime.now(), - chat=types.Chat(id=1, type="group") + chat=types.Chat(id=1, type="group"), ) def get_entity_text_mention(offset, user: dict) -> types.MessageEntity: - return types.MessageEntity(**{ - "offset": offset, - "length": len(user["first_name"]), - "type": "text_mention", - "user": user - }) + return types.MessageEntity( + **{ + "offset": offset, + "length": len(user["first_name"]), + "type": "text_mention", + "user": user, + } + ) def get_user_username(user: dict) -> str: @@ -102,8 +98,8 @@ def get_reply_message(user_dict): def get_from_user(id_=777, username=None, first_name="Bob"): return { - 'id': id_, - 'username': username, - 'first_name': first_name, - 'is_bot': False, + "id": id_, + "username": username, + "first_name": first_name, + "is_bot": False, } diff --git a/tests/target/test_auto_target.py b/tests/target/test_auto_target.py index b92fd96..1bd5786 100644 --- a/tests/target/test_auto_target.py +++ b/tests/target/test_auto_target.py @@ -1,9 +1,14 @@ import pytest from aiogram import types -from .common import filter_check, CONF_CAN_BE_SAME, CONF_CANT_BE_SAME -from .fixtures import (get_from_user, get_message_with_reply, - get_message_with_text_mention, get_message_with_mention, get_parts) +from .common import CONF_CAN_BE_SAME, CONF_CANT_BE_SAME, filter_check +from .fixtures import ( + get_from_user, + get_message_with_mention, + get_message_with_reply, + get_message_with_text_mention, + get_parts, +) @pytest.mark.parametrize("phrase", get_parts()) @@ -35,16 +40,22 @@ def check_msg_auto_target(user: dict, msg: types.Message): target_user = types.User(**user) founded_user = filter_rez["target"] if founded_user.id is None: - assert founded_user.username == target_user.username, f"msg text {{{msg.text}}} user: {{{user}}}" + assert ( + founded_user.username == target_user.username + ), f"msg text {{{msg.text}}} user: {{{user}}}" else: - assert are_users_equals(founded_user, target_user), f"msg text {{{msg.text}}} user: {{{user}}}" + assert are_users_equals( + founded_user, target_user + ), f"msg text {{{msg.text}}} user: {{{user}}}" def are_users_equals(expected: types.User, actual: types.User) -> bool: - return all([ - expected.id == actual.id, - expected.is_bot == actual.is_bot, - expected.username == actual.username, - expected.first_name == actual.first_name, - expected.last_name == actual.last_name, - ]) + return all( + [ + expected.id == actual.id, + expected.is_bot == actual.is_bot, + expected.username == actual.username, + expected.first_name == actual.first_name, + expected.last_name == actual.last_name, + ] + ) diff --git a/tests/timedelta/fixtures/fixterus_timedelta.py b/tests/timedelta/fixtures/fixterus_timedelta.py index 1e43200..521dc15 100644 --- a/tests/timedelta/fixtures/fixterus_timedelta.py +++ b/tests/timedelta/fixtures/fixterus_timedelta.py @@ -13,7 +13,9 @@ CORRECT_TUPLE_TYPE = typing.Tuple[str, timedelta] -def get_difficult_correct(count: int = 10, count_in_one_up_to: int = 3) -> typing.List[CORRECT_TUPLE_TYPE]: +def get_difficult_correct( + count: int = 10, count_in_one_up_to: int = 3 +) -> typing.List[CORRECT_TUPLE_TYPE]: return [get_many_correct(i) for _ in range(count) for i in range(2, count_in_one_up_to)] diff --git a/tests/timedelta/test_timedelta_parser.py b/tests/timedelta/test_timedelta_parser.py index 370a53b..5641a22 100644 --- a/tests/timedelta/test_timedelta_parser.py +++ b/tests/timedelta/test_timedelta_parser.py @@ -1,4 +1,5 @@ from app.utils.timedelta_functions import parse_timedelta + from .fixtures import CORRECT_SIMPLE, get_difficult_correct From f809b2610f4e4480cbc09a1c71797df834f37c11 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 13 Feb 2024 18:34:07 +0300 Subject: [PATCH 06/13] Remove `black` from dependencies --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index aca8624..5b44be7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ test = [ ] lint = [ "ruff~=0.1.9", - "black~=23.12.1", "isort~=5.13.2", ] From a150808eb554eb851d29dff7967fe5776ae24792 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 14:30:28 +0300 Subject: [PATCH 07/13] Add ruff format check instead of ruff check --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bb0bbf8..b075ff5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -32,7 +32,7 @@ jobs: id: ruff if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() run: | - ruff check --config=pyproject.toml --show-fixes --output-format=github ${{ steps.changed-python-files.outputs.all_changed_files }} + ruff format --check --config=pyproject.toml -- --show-fixes --output-format=github ${{ steps.changed-python-files.outputs.all_changed_files }} - name: Isort id: isort From 94f1b5421054ca342072278234692e2b9d527bd0 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 14:36:37 +0300 Subject: [PATCH 08/13] Update ruff hooks to format and lint with fix --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7008a51..828fbae 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,6 +13,11 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.9 hooks: + # Run the linter - id: ruff name: ruff (rust) + args: ["--config", "pyproject.toml", "--fix"] + # Run the formatter + - id: ruff-format + name: ruff-format (rust) args: ["--config", "pyproject.toml"] From 6824c8d99248e684a0711937f2640cc8008b8633 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 14:44:58 +0300 Subject: [PATCH 09/13] Remove unused flags --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b075ff5..cb6d2b3 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -32,7 +32,7 @@ jobs: id: ruff if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() run: | - ruff format --check --config=pyproject.toml -- --show-fixes --output-format=github ${{ steps.changed-python-files.outputs.all_changed_files }} + ruff format --check --config=pyproject.toml ${{ steps.changed-python-files.outputs.all_changed_files }} - name: Isort id: isort From 70f44f65e3b96b1a0c6314df40968f24404d763c Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 14:47:34 +0300 Subject: [PATCH 10/13] Remove etxra `f` --- app/handlers/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/handlers/base.py b/app/handlers/base.py index fb74bba..b223942 100644 --- a/app/handlers/base.py +++ b/app/handlers/base.py @@ -117,7 +117,7 @@ async def cmd_about(message: types.Message): @router.message(Command("idchat", prefix="!")) async def get_idchat(message: types.Message): - text = f"id этого чата: {hpre(message.chat.id)}\n" f"Ваш id: {hpre(message.from_user.id)}" + text = f"id этого чата: {hpre(message.chat.id)}\nВаш id: {hpre(message.from_user.id)}" if message.reply_to_message: text += ( f"\nid {hbold(message.reply_to_message.from_user.full_name)}: " From 64ab68878bfe56950afdc0cd9c3152b76a878512 Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 15:15:13 +0300 Subject: [PATCH 11/13] Use linters for `tests` and `migrations` --- migrations/02_pump_karma_puls49.py | 9 +++++---- tests/timedelta/fixtures/__init__.py | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/migrations/02_pump_karma_puls49.py b/migrations/02_pump_karma_puls49.py index c01ecbf..10fb03c 100644 --- a/migrations/02_pump_karma_puls49.py +++ b/migrations/02_pump_karma_puls49.py @@ -2,13 +2,14 @@ from app.config import load_config - db_config = load_config().db with sqlite3.connect(db_config.db_path) as conn: cur = conn.cursor() - cur.execute(""" - UPDATE user_karma + cur.execute( + """ + UPDATE user_karma SET karma = karma + 49; - """) + """ + ) diff --git a/tests/timedelta/fixtures/__init__.py b/tests/timedelta/fixtures/__init__.py index f22da76..f5e4510 100644 --- a/tests/timedelta/fixtures/__init__.py +++ b/tests/timedelta/fixtures/__init__.py @@ -1 +1,6 @@ from .fixterus_timedelta import CORRECT_SIMPLE, get_difficult_correct + +__all__ = [ + "CORRECT_SIMPLE", + "get_difficult_correct", +] From 8d0910670301ed0aee93d2d2ceae5d6234b4caec Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 15:15:57 +0300 Subject: [PATCH 12/13] Use `.` instead of lint only changed files --- .github/workflows/lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cb6d2b3..59c5048 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -32,10 +32,10 @@ jobs: id: ruff if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() run: | - ruff format --check --config=pyproject.toml ${{ steps.changed-python-files.outputs.all_changed_files }} + ruff format --check --config=pyproject.toml . - name: Isort id: isort if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() run: | - isort --check --diff --profile=black ${{ steps.changed-python-files.outputs.all_changed_files }} + isort --check --diff --profile=black . From 72ece67844b131c5304c44e3985720a2616c265f Mon Sep 17 00:00:00 2001 From: Desiders Date: Tue, 20 Feb 2024 21:57:29 +0300 Subject: [PATCH 13/13] Add ruff check --- .github/workflows/lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 59c5048..c64294b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -32,6 +32,7 @@ jobs: id: ruff if: steps.changed-python-files.outputs.all_changed_files != '' && !cancelled() run: | + ruff check --config=pyproject.toml . ruff format --check --config=pyproject.toml . - name: Isort