diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 73c5fdff4..e8c16ce06 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -77,7 +77,7 @@ repos: - --diff - --check - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: 'v0.0.270' + rev: 'v0.0.275' hooks: - id: ruff name: ruff diff --git a/pyproject.toml b/pyproject.toml index c9b968f59..0f3585b79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,10 @@ target-version = "py37" show-fixes = true ignore = ["PLR2004", "PLR0911", "PLR0912", "PLR0913", "PLR0915"] select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE", - "G", "ISC", "PT"] + "G", "ISC", "PT", "ASYNC", "TCH", "CPY", "SLOT", "PERF",] [tool.ruff.per-file-ignores] "tests/*.py" = ["B018"] +"**/__init__.py" = ["CPY001"] +"examples/**.py" = ["CPY001"] +"tests/**.py" = ["RUF012"] diff --git a/telegram/_files/inputsticker.py b/telegram/_files/inputsticker.py index da78bb00f..c0ee2d5aa 100644 --- a/telegram/_files/inputsticker.py +++ b/telegram/_files/inputsticker.py @@ -18,15 +18,17 @@ # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains an object that represents a Telegram InputSticker.""" -from typing import Optional, Sequence, Tuple, Union +from typing import TYPE_CHECKING, Optional, Sequence, Tuple, Union -from telegram._files.inputfile import InputFile from telegram._files.sticker import MaskPosition from telegram._telegramobject import TelegramObject from telegram._utils.argumentparsing import parse_sequence_arg from telegram._utils.files import parse_file_input from telegram._utils.types import FileInput, JSONDict +if TYPE_CHECKING: + from telegram._files.inputfile import InputFile + class InputSticker(TelegramObject): """ diff --git a/telegram/_telegramobject.py b/telegram/_telegramobject.py index 96fd4f8e9..fbc3a2840 100644 --- a/telegram/_telegramobject.py +++ b/telegram/_telegramobject.py @@ -28,6 +28,7 @@ from types import MappingProxyType from typing import ( TYPE_CHECKING, Any, + ClassVar, Dict, Iterator, List, @@ -92,7 +93,7 @@ class TelegramObject: # Used to cache the names of the parameters of the __init__ method of the class # Must be a private attribute to avoid name clashes between subclasses - __INIT_PARAMS: Set[str] = set() + __INIT_PARAMS: ClassVar[Set[str]] = set() # Used to check if __INIT_PARAMS has been set for the current class. Unfortunately, we can't # just check if `__INIT_PARAMS is None`, since subclasses use the parent class' __INIT_PARAMS # unless it's overridden diff --git a/telegram/ext/_aioratelimiter.py b/telegram/ext/_aioratelimiter.py index 8a647353d..6138a53b7 100644 --- a/telegram/ext/_aioratelimiter.py +++ b/telegram/ext/_aioratelimiter.py @@ -196,12 +196,11 @@ class AIORateLimiter(BaseRateLimiter[int]): self._get_group_limiter(group) if group and self._group_max_rate else null_context() ) - async with group_context: # skipcq: PTC-W0062 - async with base_context: - # In case a retry_after was hit, we wait with processing the request - await self._retry_after_event.wait() + async with group_context, base_context: + # In case a retry_after was hit, we wait with processing the request + await self._retry_after_event.wait() - return await callback(*args, **kwargs) + return await callback(*args, **kwargs) # mypy doesn't understand that the last run of the for loop raises an exception async def process_request( diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index 31c037ca9..a051536c3 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -58,7 +58,6 @@ from telegram._utils.warnings import warn from telegram.error import TelegramError from telegram.ext._basehandler import BaseHandler from telegram.ext._basepersistence import BasePersistence -from telegram.ext._baseupdateprocessor import BaseUpdateProcessor from telegram.ext._contexttypes import ContextTypes from telegram.ext._extbot import ExtBot from telegram.ext._updater import Updater @@ -70,6 +69,7 @@ if TYPE_CHECKING: from telegram import Message from telegram.ext import ConversationHandler, JobQueue from telegram.ext._applicationbuilder import InitApplicationBuilder + from telegram.ext._baseupdateprocessor import BaseUpdateProcessor from telegram.ext._jobqueue import Job DEFAULT_GROUP: int = 0 diff --git a/telegram/ext/_dictpersistence.py b/telegram/ext/_dictpersistence.py index d6f35f554..384ba8df2 100644 --- a/telegram/ext/_dictpersistence.py +++ b/telegram/ext/_dictpersistence.py @@ -19,12 +19,14 @@ """This module contains the DictPersistence class.""" import json from copy import deepcopy -from typing import Any, Dict, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, Optional, cast -from telegram._utils.types import JSONDict from telegram.ext import BasePersistence, PersistenceInput from telegram.ext._utils.types import CDCData, ConversationDict, ConversationKey +if TYPE_CHECKING: + from telegram._utils.types import JSONDict + class DictPersistence(BasePersistence[Dict[Any, Any], Dict[Any, Any], Dict[Any, Any]]): """Using Python's :obj:`dict` and :mod:`json` for making your bot persistent. diff --git a/telegram/ext/_jobqueue.py b/telegram/ext/_jobqueue.py index a645d4acc..3ff17d244 100644 --- a/telegram/ext/_jobqueue.py +++ b/telegram/ext/_jobqueue.py @@ -25,7 +25,6 @@ from typing import TYPE_CHECKING, Any, Generic, Optional, Tuple, Union, cast, ov try: import pytz from apscheduler.executors.asyncio import AsyncIOExecutor - from apscheduler.job import Job as APSJob from apscheduler.schedulers.asyncio import AsyncIOScheduler APS_AVAILABLE = True @@ -38,6 +37,9 @@ from telegram.ext._extbot import ExtBot from telegram.ext._utils.types import CCT, JobCallback if TYPE_CHECKING: + if APS_AVAILABLE: + from apscheduler.job import Job as APSJob + from telegram.ext import Application diff --git a/tests/auxil/deprecations.py b/tests/auxil/deprecations.py index 224ecdc40..00f5aa9c8 100644 --- a/tests/auxil/deprecations.py +++ b/tests/auxil/deprecations.py @@ -60,13 +60,13 @@ def check_thumb_deprecation_warnings_for_args_and_attrs( for i in range(expected_recwarn_length): assert issubclass(recwarn[i].category, PTBDeprecationWarning) assert f"{names[i]} '{deprecated_name}' to '{new_name}'" in str(recwarn[i].message), ( - f'Warning issued by file {recwarn[i].filename} ("{str(recwarn[i].message)}") ' + f'Warning issued by file {recwarn[i].filename} ("{recwarn[i].message}") ' "does not contain expected phrase: " f"\"{names[i]} '{deprecated_name}' to '{new_name}'\"" ) assert recwarn[i].filename == calling_file, ( - f'Warning for {names[i]} ("{str(recwarn[i].message)}") was issued by file ' + f'Warning for {names[i]} ("{recwarn[i].message}") was issued by file ' f"{recwarn[i].filename}, expected {calling_file}" ) diff --git a/tests/ext/test_jobqueue.py b/tests/ext/test_jobqueue.py index e95feaf32..db3af0da7 100644 --- a/tests/ext/test_jobqueue.py +++ b/tests/ext/test_jobqueue.py @@ -492,7 +492,7 @@ class TestJobQueue: job_2 = job_queue.run_repeating(self.job_run_once, 0.2) job_3 = Job(self.job_run_once, 0.2) job_3._job = job.job - assert job == job + assert job == job # noqa: PLR0124 assert job != job_queue assert job != job_2 assert job == job_3 diff --git a/tests/test_chatpermissions.py b/tests/test_chatpermissions.py index 9585710c1..e5b9563c2 100644 --- a/tests/test_chatpermissions.py +++ b/tests/test_chatpermissions.py @@ -206,7 +206,7 @@ class TestChatPermissionsWithoutRequest(TestChatPermissionsBase): def test_equality_warning(self, recwarn, chat_permissions): recwarn.clear() - assert chat_permissions == chat_permissions + assert chat_permissions == ChatPermissions.all_permissions() assert str(recwarn[0].message) == ( "In v21, granular media settings will be considered as well when comparing" diff --git a/tests/test_keyboardbutton.py b/tests/test_keyboardbutton.py index 84319acf0..a1f2f7466 100644 --- a/tests/test_keyboardbutton.py +++ b/tests/test_keyboardbutton.py @@ -136,7 +136,7 @@ class TestKeyboardButtonWithoutRequest(TestKeyboardButtonBase): def test_equality_warning(self, recwarn, keyboard_button): recwarn.clear() - assert keyboard_button == keyboard_button + assert keyboard_button == keyboard_button # noqa: PLR0124 assert str(recwarn[0].message) == ( "In v21, `request_user` and `request_chat` will be considered as well when comparing" diff --git a/tests/test_slots.py b/tests/test_slots.py index fdd8619bc..cf257c748 100644 --- a/tests/test_slots.py +++ b/tests/test_slots.py @@ -37,7 +37,7 @@ def test_class_has_slots_and_no_dict(): for name, cls in inspect.getmembers(module, inspect.isclass): if cls.__module__ != module.__name__ or any( # exclude 'imported' modules - x in name for x in {"__class__", "__init__", "Queue", "Webhook"} + x in name for x in ("__class__", "__init__", "Queue", "Webhook") ): continue @@ -46,7 +46,7 @@ def test_class_has_slots_and_no_dict(): assert not isinstance(cls.__slots__, str), f"{name!r}s slots shouldn't be strings" # specify if a certain module/class/base class should have dict- - if any(i in included for i in {cls.__module__, name, cls.__base__.__name__}): + if any(i in included for i in (cls.__module__, name, cls.__base__.__name__)): assert "__dict__" in get_slots(cls), f"class {name!r} ({path}) has no __dict__" continue