From 6720846d3bf06c05c5a20c023f2153211ab171d4 Mon Sep 17 00:00:00 2001 From: Paillat Date: Sun, 23 Aug 2026 20:26:30 +0200 Subject: [PATCH] feat: Hard pylint block --- .github/workflows/lib-checks.yml | 7 ++++++- discord/__init__.py | 6 ++++-- discord/client.py | 2 +- discord/cog.py | 2 +- discord/components.py | 4 ++-- discord/flags.py | 4 ++-- discord/guild.py | 2 +- discord/http.py | 2 +- discord/iterators.py | 16 ++++++++++++---- discord/raw_models.py | 2 -- discord/state.py | 6 +++--- discord/user.py | 2 +- discord/voice/client.py | 4 +++- discord/voice/gateway.py | 4 ++-- discord/voice/receive/reader.py | 5 +++-- discord/webhook/sync.py | 4 ++-- pyproject.toml | 3 ++- 17 files changed, 46 insertions(+), 29 deletions(-) diff --git a/.github/workflows/lib-checks.yml b/.github/workflows/lib-checks.yml index 4612442a92..37fc584553 100644 --- a/.github/workflows/lib-checks.yml +++ b/.github/workflows/lib-checks.yml @@ -131,6 +131,7 @@ jobs: with: python-version: "3.14" groups: "dev" + extras: "voice,speed" - name: "Setup cache" id: cache-pylint uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -140,7 +141,11 @@ jobs: restore-keys: | pylint-${{ runner.os }}-py3.14- - name: "Run pylint" - run: pylint discord/ --exit-zero + run: | + pylint discord/ \ + --output-format=github,json:pylint.json \ + --fail-under=0 \ + --fail-on=E,F mypy: needs: [ changes ] if: ${{ needs.changes.outputs.lib == 'true' && github.event_name != 'schedule' }} diff --git a/discord/__init__.py b/discord/__init__.py index 5c9d23f9bd..cf59e6b232 100644 --- a/discord/__init__.py +++ b/discord/__init__.py @@ -92,12 +92,14 @@ @deprecated( "discord.VoiceClient is deprecated in favour of discord.voice.VoiceClient since 2.7 and will be removed in 3.0", ) - class VoiceClient(VoiceClientC): ... + class VoiceClient(VoiceClientC): ... # pylint: disable=function-redefined @deprecated( "discord.VoiceProtocol is deprecated in favour of discord.voice.VoiceProtocol since 2.7 and will be removed in 3.0", ) - class VoiceProtocol(VoiceProtocolC[C], Generic[C]): ... + class VoiceProtocol( # pylint: disable=function-redefined + VoiceProtocolC[C], Generic[C] + ): ... else: from .utils import warn_deprecated diff --git a/discord/client.py b/discord/client.py index de9f17ad70..f80d40ae5b 100644 --- a/discord/client.py +++ b/discord/client.py @@ -133,7 +133,7 @@ def _cleanup_loop(loop: asyncio.AbstractEventLoop) -> None: loop.close() -class Client: +class Client: # pylint: disable=function-redefined r"""Represents a client connection that connects to Discord. This class is used to interact with the Discord WebSocket and API. diff --git a/discord/cog.py b/discord/cog.py index d514e1febf..e044684347 100644 --- a/discord/cog.py +++ b/discord/cog.py @@ -48,8 +48,8 @@ ApplicationCommand, ApplicationContext, SlashCommandGroup, - _BaseCommand, ) +from .commands.core import _BaseCommand if TYPE_CHECKING: from .ext.bridge import BridgeCommand diff --git a/discord/components.py b/discord/components.py index 53aa06de6e..7893114284 100644 --- a/discord/components.py +++ b/discord/components.py @@ -132,9 +132,9 @@ class Component: __slots__: tuple[str, ...] = ("type", "id") - __repr_info__: ClassVar[tuple[str, ...]] + __repr_info__: ClassVar[tuple[str, ...]] # pylint: disable=declare-non-slot type: ComponentType - versions: tuple[int, ...] + versions: tuple[int, ...] # pylint: disable=declare-non-slot def __repr__(self) -> str: attrs = " ".join(f"{key}={getattr(self, key)!r}" for key in self.__repr_info__) diff --git a/discord/flags.py b/discord/flags.py index 524ed3c593..2376d6f8ca 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -97,8 +97,8 @@ def decorator(cls: type[BF]): # n.b. flags must inherit from this and use the decorator above class BaseFlags: - VALID_FLAGS: ClassVar[dict[str, int]] - DEFAULT_VALUE: ClassVar[int] + VALID_FLAGS: ClassVar[dict[str, int]] # pylint: disable=declare-non-slot + DEFAULT_VALUE: ClassVar[int] # pylint: disable=declare-non-slot value: int diff --git a/discord/guild.py b/discord/guild.py index b485123b52..6e66abd58b 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -222,7 +222,7 @@ def __contains__(self, key: int | abc.Snowflake) -> bool: return super().__contains__(key) -class Guild(Hashable): +class Guild(Hashable): # pylint: disable=function-redefined """Represents a Discord guild. This is referred to as a "server" in the official Discord UI. diff --git a/discord/http.py b/discord/http.py index 40ebcd7c1f..3eb5031cc6 100644 --- a/discord/http.py +++ b/discord/http.py @@ -39,7 +39,7 @@ import aiohttp -from . import __version__, utils +from . import __version__, utils # pylint: disable=no-name-in-module from .errors import ( DiscordServerError, Forbidden, diff --git a/discord/iterators.py b/discord/iterators.py index 50fdc6d2a3..1406b4fe31 100644 --- a/discord/iterators.py +++ b/discord/iterators.py @@ -428,7 +428,9 @@ async def fill_messages(self): self.state.create_message(channel=channel, data=element) ) - async def _retrieve_messages(self, retrieve: int) -> list[MessagePayload]: + async def _retrieve_messages( # pylint: disable=method-hidden + self, retrieve: int + ) -> list[MessagePayload]: """Retrieve messages and update next parameters.""" raise NotImplementedError @@ -657,7 +659,9 @@ async def fill_guilds(self): for element in data: await self.guilds.put(self.create_guild(element)) - async def _retrieve_guilds(self, retrieve) -> list[Guild]: + async def _retrieve_guilds( # pylint: disable=method-hidden + self, retrieve + ) -> list[Guild]: """Retrieve guilds and update next parameters.""" raise NotImplementedError @@ -1055,7 +1059,9 @@ async def fill_entitlements(self): for element in data: await self.entitlements.put(self.create_entitlement(element)) - async def _retrieve_entitlements(self, retrieve) -> list[EntitlementPayload]: + async def _retrieve_entitlements( # pylint: disable=method-hidden + self, retrieve + ) -> list[EntitlementPayload]: """Retrieve entitlements and update next parameters.""" raise NotImplementedError @@ -1170,7 +1176,9 @@ async def fill_subscriptions(self): for element in data: await self.subscriptions.put(self.create_subscription(element)) - async def _retrieve_subscriptions(self, retrieve) -> list[SubscriptionPayload]: + async def _retrieve_subscriptions( # pylint: disable=method-hidden + self, retrieve + ) -> list[SubscriptionPayload]: raise NotImplementedError async def _retrieve_subscriptions_before_strategy(self, retrieve): diff --git a/discord/raw_models.py b/discord/raw_models.py index 291a44fadc..efce937520 100644 --- a/discord/raw_models.py +++ b/discord/raw_models.py @@ -103,8 +103,6 @@ class _RawReprMixin: - __slots__: tuple[str, ...] - def __repr__(self) -> str: value = " ".join( f"{attr}={getattr(self, attr)!r}" diff --git a/discord/state.py b/discord/state.py index 83137e94bb..1850343786 100644 --- a/discord/state.py +++ b/discord/state.py @@ -153,7 +153,7 @@ async def logging_coroutine(coroutine: Coroutine[Any, Any, T], *, info: str) -> _log.exception("Exception occurred during %s", info) -class ConnectionState: +class ConnectionState: # pylint: disable=function-redefined if TYPE_CHECKING: _get_websocket: Callable[..., DiscordWebSocket] _get_client: Callable[..., Client] @@ -369,7 +369,7 @@ def _update_references(self, ws: DiscordWebSocket) -> None: for vc in self.voice_clients: vc.main_ws = ws # type: ignore - def store_user(self, data: UserPayload) -> User: + def store_user(self, data: UserPayload) -> User: # pylint: disable=method-hidden user_id = int(data["id"]) try: user = self._users[user_id] @@ -388,7 +388,7 @@ def store_user(self, data: UserPayload) -> User: copied_user._update(data) return copied_user - def deref_user(self, user_id: int) -> None: + def deref_user(self, user_id: int) -> None: # pylint: disable=method-hidden self._users.pop(user_id, None) def create_user(self, data: UserPayload) -> User: diff --git a/discord/user.py b/discord/user.py index 32a0cfe2be..29b20835c0 100644 --- a/discord/user.py +++ b/discord/user.py @@ -609,7 +609,7 @@ def __del__(self) -> None: @classmethod def _copy(cls, user: User): self = super()._copy(user) - self._stored = False + self._stored = False # pylint: disable=assigning-non-slot return self async def _get_channel(self) -> DMChannel: diff --git a/discord/voice/client.py b/discord/voice/client.py index 51431375e6..cb41146545 100644 --- a/discord/voice/client.py +++ b/discord/voice/client.py @@ -430,7 +430,9 @@ def _get_voice_packet(self, data: Any) -> bytes: def _encrypt_xsalsa20_poly1305(self, header: bytes, data: Any) -> bytes: # deprecated - box = nacl.secret.SecretBox(bytes(self.secret_key)) + box = nacl.secret.SecretBox( # pylint: disable=possibly-used-before-assignment + bytes(self.secret_key) + ) nonce = bytearray(24) nonce[:12] = header return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext diff --git a/discord/voice/gateway.py b/discord/voice/gateway.py index 7b2aa3a17d..26434693a8 100644 --- a/discord/voice/gateway.py +++ b/discord/voice/gateway.py @@ -148,7 +148,7 @@ def session_id(self, value: str | None) -> None: def self_id(self) -> int: return self._connection.self_id - async def _hook(self, *args: Any) -> Any: + async def _hook(self, *args: Any) -> Any: # pylint: disable=method-hidden pass async def send_as_bytes(self, op: ConvertibleToInt, data: bytes) -> None: @@ -276,7 +276,7 @@ async def received_binary_message(self, msg: bytes) -> None: op_type = msg[3] result = state.dave_session.process_proposals( ( - davey.ProposalsOperationType.append + davey.ProposalsOperationType.append # pylint: disable=possibly-used-before-assignment if op_type == 0 else davey.ProposalsOperationType.revoke ), diff --git a/discord/voice/receive/reader.py b/discord/voice/receive/reader.py index 2a82c6e1dc..1695f3a2c0 100644 --- a/discord/voice/receive/reader.py +++ b/discord/voice/receive/reader.py @@ -57,6 +57,7 @@ DecryptRTP = Callable[[RTPPacket], bytes] DecryptRTCP = Callable[[bytes], bytes] SpeakingEvent = Literal["member_speaking_start", "member_speaking_stop"] + # pylint: disable-next=possibly-used-before-assignment EncryptionBox = nacl.secret.SecretBox | nacl.secret.Aead _log = logging.getLogger(__name__) @@ -187,7 +188,7 @@ def callback(self, packet_data: bytes) -> None: packet.type, type(packet), ) - except CryptoError as exc: + except CryptoError as exc: # pylint: disable=possibly-used-before-assignment _log.error("CryptoError while decoding a voice packet", exc_info=exc) return except Exception as exc: @@ -303,7 +304,7 @@ def decrypt_rtp(self, packet: RTPPacket) -> bytes: try: decrypted_audio = dave.decrypt( uid, - davey.MediaType.audio, + davey.MediaType.audio, # pylint: disable=possibly-used-before-assignment raw_payload, ) diff --git a/discord/webhook/sync.py b/discord/webhook/sync.py index a33655c868..1bcea331b6 100644 --- a/discord/webhook/sync.py +++ b/discord/webhook/sync.py @@ -689,7 +689,7 @@ def partial( "type": 1, "token": token, } - import requests + import requests # pylint: disable=import-error if session is MISSING: session = requests # type: ignore @@ -736,7 +736,7 @@ def from_url( data: dict[str, Any] = m.groupdict() data["type"] = 1 - import requests + import requests # pylint: disable=import-error if session is MISSING: session = requests # type: ignore diff --git a/pyproject.toml b/pyproject.toml index 3af40cb29b..f52ef89d96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -149,7 +149,8 @@ enable = [ ] disable = [ "protected-access", - "fixme" + "fixme", + "typecheck", ] [tool.pylint.format]