diff --git a/discord/commands/context.py b/discord/commands/context.py index fc3befe563..cce7b8fe04 100644 --- a/discord/commands/context.py +++ b/discord/commands/context.py @@ -29,6 +29,9 @@ import discord.abc if TYPE_CHECKING: + # https://github.com/PyCQA/pylint/issues/3525 + # pylint: disable=cyclic-import + import discord from discord import Bot from discord.state import ConnectionState diff --git a/discord/errors.py b/discord/errors.py index 6cc549c61d..93bb892fb6 100644 --- a/discord/errors.py +++ b/discord/errors.py @@ -27,6 +27,9 @@ from typing import Dict, List, Optional, TYPE_CHECKING, Any, Tuple, Union if TYPE_CHECKING: + # https://github.com/PyCQA/pylint/issues/3525 + # pylint: disable=cyclic-import + from aiohttp import ClientResponse, ClientWebSocketResponse try: diff --git a/discord/gateway.py b/discord/gateway.py index 253e49825e..9cfd75e941 100644 --- a/discord/gateway.py +++ b/discord/gateway.py @@ -24,15 +24,15 @@ """ import asyncio -from collections import namedtuple, deque import concurrent.futures import logging import struct import sys -import time import threading +import time import traceback import zlib +from collections import namedtuple, deque import aiohttp diff --git a/discord/message.py b/discord/message.py index b0a1cb28a2..ef615b2b7b 100644 --- a/discord/message.py +++ b/discord/message.py @@ -27,27 +27,27 @@ import asyncio import datetime -import re import io +import re from os import PathLike -from typing import Dict, TYPE_CHECKING, Union, List, Optional, Any, Callable, Tuple, ClassVar, Optional, overload, TypeVar, Type +from typing import Dict, TYPE_CHECKING, Union, List, Any, Callable, Tuple, ClassVar, Optional, overload, TypeVar, Type from . import utils -from .reaction import Reaction +from .components import _component_factory +from .embeds import Embed from .emoji import Emoji -from .partial_emoji import PartialEmoji from .enums import MessageType, ChannelType, try_enum from .errors import InvalidArgument, HTTPException -from .components import _component_factory -from .embeds import Embed -from .member import Member -from .flags import MessageFlags from .file import File -from .utils import escape_mentions, MISSING +from .flags import MessageFlags from .guild import Guild +from .member import Member from .mixins import Hashable +from .partial_emoji import PartialEmoji +from .reaction import Reaction from .sticker import StickerItem from .threads import Thread +from .utils import escape_mentions, MISSING if TYPE_CHECKING: from .types.message import ( @@ -998,7 +998,7 @@ def is_system(self) -> bool: ) @utils.cached_slot_property('_cs_system_content') - def system_content(self): + def system_content(self) -> str: r""":class:`str`: A property that returns the content that is rendered regardless of the :attr:`Message.type`. @@ -1007,29 +1007,31 @@ def system_content(self): returns an English message denoting the contents of the system message. """ + return_msg = '' # So that pylint doesn't complain about this being used before it's set + if self.type is MessageType.default: - return self.content + return_msg = self.content if self.type is MessageType.recipient_add: if self.channel.type is ChannelType.group: - return f'{self.author.name} added {self.mentions[0].name} to the group.' + return_msg = f'{self.author.name} added {self.mentions[0].name} to the group.' else: - return f'{self.author.name} added {self.mentions[0].name} to the thread.' + return_msg = f'{self.author.name} added {self.mentions[0].name} to the thread.' if self.type is MessageType.recipient_remove: if self.channel.type is ChannelType.group: - return f'{self.author.name} removed {self.mentions[0].name} from the group.' + return_msg = f'{self.author.name} removed {self.mentions[0].name} from the group.' else: - return f'{self.author.name} removed {self.mentions[0].name} from the thread.' + return_msg = f'{self.author.name} removed {self.mentions[0].name} from the thread.' if self.type is MessageType.channel_name_change: - return f'{self.author.name} changed the channel name: **{self.content}**' + return_msg = f'{self.author.name} changed the channel name: **{self.content}**' if self.type is MessageType.channel_icon_change: - return f'{self.author.name} changed the channel icon.' + return_msg = f'{self.author.name} changed the channel icon.' if self.type is MessageType.pins_add: - return f'{self.author.name} pinned a message to this channel.' + return_msg = f'{self.author.name} pinned a message to this channel.' if self.type is MessageType.new_member: formats = [ @@ -1049,66 +1051,71 @@ def system_content(self): ] created_at_ms = int(self.created_at.timestamp() * 1000) - return formats[created_at_ms % len(formats)].format(self.author.name) + return_msg = formats[created_at_ms % len(formats)].format(self.author.name) if self.type is MessageType.premium_guild_subscription: if not self.content: - return f'{self.author.name} just boosted the server!' + return_msg = f'{self.author.name} just boosted the server!' else: - return f'{self.author.name} just boosted the server **{self.content}** times!' + return_msg = f'{self.author.name} just boosted the server **{self.content}** times!' if self.type is MessageType.premium_guild_tier_1: if not self.content: - return f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 1!**' + return_msg = f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 1!**' else: - return f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 1!**' + return_msg = f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 1!**' if self.type is MessageType.premium_guild_tier_2: if not self.content: - return f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 2!**' + return_msg = f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 2!**' else: - return f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 2!**' + return_msg = f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 2!**' if self.type is MessageType.premium_guild_tier_3: if not self.content: - return f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 3!**' + return_msg = f'{self.author.name} just boosted the server! {self.guild} has achieved **Level 3!**' else: - return f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 3!**' + return_msg = f'{self.author.name} just boosted the server **{self.content}** times! {self.guild} has achieved **Level 3!**' if self.type is MessageType.channel_follow_add: - return f'{self.author.name} has added {self.content} to this channel' + return_msg = f'{self.author.name} has added {self.content} to this channel' if self.type is MessageType.guild_stream: # the author will be a Member - return f'{self.author.name} is live! Now streaming {self.author.activity.name}' # type: ignore + return_msg = f'{self.author.name} is live! Now streaming {self.author.activity.name}' # type: ignore if self.type is MessageType.guild_discovery_disqualified: - return 'This server has been removed from Server Discovery because it no longer passes all the requirements. Check Server Settings for more details.' + return_msg = 'This server has been removed from Server Discovery because it no longer passes all the ' \ + 'requirements. Check Server Settings for more details.' if self.type is MessageType.guild_discovery_requalified: - return 'This server is eligible for Server Discovery again and has been automatically relisted!' + return_msg = 'This server is eligible for Server Discovery again and has been automatically relisted!' if self.type is MessageType.guild_discovery_grace_period_initial_warning: - return 'This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery.' + return_msg = 'This server has failed Discovery activity requirements for 1 week. If this server fails ' \ + 'for 4 weeks in a row, it will be automatically removed from Discovery.' if self.type is MessageType.guild_discovery_grace_period_final_warning: - return 'This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery.' + return_msg = 'This server has failed Discovery activity requirements for 3 weeks in a row. If this ' \ + 'server fails for 1 more week, it will be removed from Discovery.' if self.type is MessageType.thread_created: - return f'{self.author.name} started a thread: **{self.content}**. See all **threads**.' + return_msg = f'{self.author.name} started a thread: **{self.content}**. See all **threads**.' if self.type is MessageType.reply: - return self.content + return_msg = self.content if self.type is MessageType.thread_starter_message: if self.reference is None or self.reference.resolved is None: - return 'Sorry, we couldn\'t load the first message in this thread' + return_msg = 'Sorry, we couldn\'t load the first message in this thread' # the resolved message for the reference will be a Message - return self.reference.resolved.content # type: ignore + return_msg = self.reference.resolved.content # type: ignore # pylint: disable=no-member if self.type is MessageType.guild_invite_reminder: - return 'Wondering who to invite?\nStart by inviting anyone who can help you build the server!' + return_msg = 'Wondering who to invite?\nStart by inviting anyone who can help you build the server!' + + return return_msg async def delete(self, *, delay: Optional[float] = None) -> None: """|coro| @@ -1152,42 +1159,42 @@ async def delete(delay: float): @overload async def edit( - self, - *, - content: Optional[str] = ..., - embed: Optional[Embed] = ..., - attachments: List[Attachment] = ..., - suppress: bool = ..., - delete_after: Optional[float] = ..., - allowed_mentions: Optional[AllowedMentions] = ..., - view: Optional[View] = ..., + self, + *, + content: Optional[str] = ..., + embed: Optional[Embed] = ..., + attachments: List[Attachment] = ..., + suppress: bool = ..., + delete_after: Optional[float] = ..., + allowed_mentions: Optional[AllowedMentions] = ..., + view: Optional[View] = ..., ) -> Message: ... @overload async def edit( - self, - *, - content: Optional[str] = ..., - embeds: List[Embed] = ..., - attachments: List[Attachment] = ..., - suppress: bool = ..., - delete_after: Optional[float] = ..., - allowed_mentions: Optional[AllowedMentions] = ..., - view: Optional[View] = ..., + self, + *, + content: Optional[str] = ..., + embeds: List[Embed] = ..., + attachments: List[Attachment] = ..., + suppress: bool = ..., + delete_after: Optional[float] = ..., + allowed_mentions: Optional[AllowedMentions] = ..., + view: Optional[View] = ..., ) -> Message: ... async def edit( - self, - content: Optional[str] = MISSING, - embed: Optional[Embed] = MISSING, - embeds: List[Embed] = MISSING, - attachments: List[Attachment] = MISSING, - suppress: bool = MISSING, - delete_after: Optional[float] = None, - allowed_mentions: Optional[AllowedMentions] = MISSING, - view: Optional[View] = MISSING, + self, + content: Optional[str] = MISSING, + embed: Optional[Embed] = MISSING, + embeds: List[Embed] = MISSING, + attachments: List[Attachment] = MISSING, + suppress: bool = MISSING, + delete_after: Optional[float] = None, + allowed_mentions: Optional[AllowedMentions] = MISSING, + view: Optional[View] = MISSING, ) -> Message: """|coro| @@ -1266,8 +1273,8 @@ async def edit( payload['embeds'] = [e.to_dict() for e in embeds] if suppress is not MISSING: - flags = MessageFlags._from_value(self.flags.value) - flags.suppress_embeds = suppress + flags = MessageFlags._from_value(self.flags.value) # pylint: disable=protected-access + flags.suppress_embeds = suppress # pylint: disable=assigning-non-slot payload['flags'] = flags.value if allowed_mentions is MISSING: @@ -1789,7 +1796,7 @@ async def edit(self, **fields: Any) -> Optional[Message]: except KeyError: pass else: - flags = MessageFlags._from_value(0) + flags = MessageFlags._from_value(0) # pylint: disable=protected-access flags.suppress_embeds = suppress fields['flags'] = flags.value diff --git a/discord/object.py b/discord/object.py index a9da4fb2f7..8b1a67c471 100644 --- a/discord/object.py +++ b/discord/object.py @@ -25,15 +25,15 @@ from __future__ import annotations -from . import utils -from .mixins import Hashable - from typing import ( SupportsInt, TYPE_CHECKING, Union, ) +from . import utils +from .mixins import Hashable + if TYPE_CHECKING: import datetime SupportsIntCast = Union[SupportsInt, str, bytes, bytearray] @@ -76,9 +76,9 @@ class Object(Hashable): The ID of the object. """ - def __init__(self, id: SupportsIntCast): + def __init__(self, id: SupportsIntCast): # pylint: disable=redefined-builtin try: - id = int(id) + id = int(id) # pylint: disable=redefined-builtin except ValueError: raise TypeError(f'id parameter must be convertible to int not {id.__class__!r}') from None else: diff --git a/discord/permissions.py b/discord/permissions.py index fecea827a1..d3231d7456 100644 --- a/discord/permissions.py +++ b/discord/permissions.py @@ -578,10 +578,10 @@ def _augment_from_permissions(cls): # god bless Python def getter(self, x=key): - return self._values.get(x) + return self._values.get(x) # pylint: disable=protected-access def setter(self, value, x=key): - self._set(x, value) + self._set(x, value) # pylint: disable=protected-access prop = property(getter, setter) setattr(cls, name, prop) diff --git a/discord/state.py b/discord/state.py index b2f25f302d..19831ee763 100644 --- a/discord/state.py +++ b/discord/state.py @@ -147,14 +147,14 @@ class ConnectionState: _parsers: Dict[str, Callable[[Dict[str, Any]], None]] def __init__( - self, - *, - dispatch: Callable, - handlers: Dict[str, Callable], - hooks: Dict[str, Callable], - http: HTTPClient, - loop: asyncio.AbstractEventLoop, - **options: Any, + self, + *, + dispatch: Callable, + handlers: Dict[str, Callable], + hooks: Dict[str, Callable], + http: HTTPClient, + loop: asyncio.AbstractEventLoop, + **options: Any ) -> None: self.loop: asyncio.AbstractEventLoop = loop self.http: HTTPClient = http diff --git a/discord/ui/select.py b/discord/ui/select.py index 0241a3ddde..4c7443ffe8 100644 --- a/discord/ui/select.py +++ b/discord/ui/select.py @@ -45,6 +45,9 @@ ) if TYPE_CHECKING: + # https://github.com/PyCQA/pylint/issues/3525 + # pylint: disable=cyclic-import + from .view import View from ..types.components import SelectMenu as SelectMenuPayload from ..types.interactions import ( diff --git a/discord/utils.py b/discord/utils.py index 088e5f3a79..04032d9574 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -66,7 +66,7 @@ from .errors import InvalidArgument, HTTPException try: - import orjson + import orjson # pylint: disable=import-error except ModuleNotFoundError: HAS_ORJSON = False else: @@ -322,7 +322,7 @@ def oauth_url( return url -def snowflake_time(id: int) -> datetime.datetime: +def snowflake_time(id: int) -> datetime.datetime: # pylint: disable=redefined-builtin """ Parameters ----------- @@ -626,7 +626,10 @@ class SnowflakeList(array.array): if TYPE_CHECKING: - def __init__(self, data: Iterable[int], *, is_sorted: bool = False): + def __init__(self, + data: Iterable[int], # pylint: disable=unused-argument + *, + is_sorted: bool = False): # pylint: disable=super-init-not-called,unused-argument ... def __new__(cls, data: Iterable[int], *, is_sorted: bool = False): @@ -916,8 +919,8 @@ def normalise_optional_params(parameters: Iterable[Any]) -> Tuple[Any, ...]: def evaluate_annotation( tp: Any, - globals: Dict[str, Any], - locals: Dict[str, Any], + globals: Dict[str, Any], # pylint: disable=redefined-builtin + locals: Dict[str, Any], # pylint: disable=redefined-builtin cache: Dict[str, Any], *, implicit_str: bool = True, @@ -930,7 +933,7 @@ def evaluate_annotation( if implicit_str and isinstance(tp, str): if tp in cache: return cache[tp] - evaluated = eval(tp, globals, locals) + evaluated = eval(tp, globals, locals) # pylint: disable=eval-used cache[tp] = evaluated return evaluate_annotation(evaluated, globals, locals, cache) @@ -939,7 +942,7 @@ def evaluate_annotation( is_literal = False args = tp.__args__ if not hasattr(tp, '__origin__'): - if PY_310 and tp.__class__ is types.UnionType: # type: ignore + if PY_310 and tp.__class__ is types.UnionType: # type: ignore # pylint: disable=no-member converted = Union[args] # type: ignore return evaluate_annotation(converted, globals, locals, cache) @@ -983,7 +986,7 @@ def resolve_annotation( if isinstance(annotation, str): annotation = ForwardRef(annotation) - locals = globalns if localns is None else localns + locals = globalns if localns is None else localns # pytype: disable=redefined-builtin if cache is None: cache = {} return evaluate_annotation(annotation, globalns, locals, cache) @@ -1058,8 +1061,9 @@ def generate_snowflake(dt: Optional[datetime.datetime] = None) -> int: def basic_autocomplete(values: Union[Iterable[str], - Callable[[Interaction], Union[Iterable[str], Coroutine[Iterable[str]]]], - Coroutine[Iterable[str]]]) -> Callable[[Interaction, str], Coroutine[List[str]]]: + Callable[[AutocompleteContext], Union[Iterable[str], Coroutine[Iterable[str]]]], + Coroutine[Iterable[str]]]) -> Callable[[AutocompleteContext, str], + Coroutine[List[str]]]: """A helper function to make a basic autocomplete for slash commands. This is a pretty standard autocomplete and will return any options that start with the value from the user, case insensitive. If :param:`values` is callable, it will be called with the interaction. @@ -1075,7 +1079,7 @@ def basic_autocomplete(values: Union[Iterable[str], # or - async def autocomplete(interaction): + async def autocomplete(ctx): return ("foo", "bar", "baz", interaction.user.name) Option(str, "name", autocomplete=basic_autocomplete(autocomplete)) @@ -1098,7 +1102,7 @@ async def autocomplete_callback(ctx: AutocompleteContext) -> List[str]: _values = values # since we reassign later, python considers it local if we don't do this if callable(_values): - _values = _values(interaction) + _values = _values(ctx) if asyncio.iscoroutine(_values): _values = await _values return ([x for x in _values if x.lower().startswith(ctx.value.lower())])[:25] diff --git a/discord/voice_client.py b/discord/voice_client.py index fab2c7e95e..3746a090a7 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -41,16 +41,16 @@ from __future__ import annotations import asyncio -import socket import logging +import socket import struct import threading from typing import Any, Callable, List, Optional, TYPE_CHECKING, Tuple from . import opus, utils from .backoff import ExponentialBackoff -from .gateway import * from .errors import ClientException, ConnectionClosed +from .gateway import * from .player import AudioPlayer, AudioSource from .utils import MISSING diff --git a/discord/webhook/async_.py b/discord/webhook/async_.py index fab5809677..c51ce2faaa 100644 --- a/discord/webhook/async_.py +++ b/discord/webhook/async_.py @@ -48,6 +48,8 @@ from ..channel import PartialMessageable from ..threads import Thread +# See sync.py # pylint: disable=duplicate-code + __all__ = ( 'Webhook', 'WebhookMessage', diff --git a/discord/webhook/sync.py b/discord/webhook/sync.py index 802f692d06..9b727ea8c4 100644 --- a/discord/webhook/sync.py +++ b/discord/webhook/sync.py @@ -28,6 +28,7 @@ # a bit easier to write. It's an unfortunate design. Originally, these types were # merged and an adapter was used to differentiate between the async and sync versions. # However, this proved to be difficult to provide typings for, so here we are. +# pylint: disable=duplicate-code from __future__ import annotations