diff --git a/.github/DEVELOPER_CERTIFICATE_OF_ORIGIN.md b/.github/DEVELOPER_CERTIFICATE_OF_ORIGIN.md index 9c09291abc..3679a30804 100644 --- a/.github/DEVELOPER_CERTIFICATE_OF_ORIGIN.md +++ b/.github/DEVELOPER_CERTIFICATE_OF_ORIGIN.md @@ -1,4 +1,4 @@ -# Developer Certificate of Origin (DCO) +# Developer Certificate of Origin (DCO) ``` Version 1.1 @@ -33,4 +33,4 @@ By making a contribution to this project, I certify that: personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. -``` \ No newline at end of file +``` diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1d4b854740..b38df29f46 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,6 +1,6 @@ version: 2 updates: - package-ecosystem: "pip" - directory: "/" + directory: "/" schedule: interval: "daily" diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000000..3927f0bd2a --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,25 @@ +name: Lint + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.9] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install --upgrade pre-commit + - name: Lint + run: pre-commit run --all-files --show-diff-on-failure diff --git a/.gitignore b/.gitignore index 4a28a54c4a..0204b5926e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ build/ test.py build/ node_modules/* -test.py \ No newline at end of file +test.py diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000000..f238bf7ea1 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile = black diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..ff5e39bb5d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: check-yaml +- repo: https://github.com/psf/black + rev: 22.1.0 + hooks: + - id: black +- repo: https://github.com/ikamensh/flynt/ + rev: '0.76' + hooks: + - id: flynt +- repo: https://github.com/pycqa/isort + rev: 5.10.1 + hooks: + - id: isort + name: isort (python) diff --git a/.pylintrc b/.pylintrc index 985fb7f6ae..19a44b15f3 100644 --- a/.pylintrc +++ b/.pylintrc @@ -9,4 +9,4 @@ enable=bad-indentation,line-too-long indent-string=' ' -max-line-length=120 \ No newline at end of file +max-line-length=88 diff --git a/README.rst b/README.rst index d6f2feb859..0cf601d5ac 100644 --- a/README.rst +++ b/README.rst @@ -95,16 +95,16 @@ Quick Example import discord bot = discord.Bot() - + @bot.slash_command() async def hello(ctx, name: str = None): name = name or ctx.author.name await ctx.respond(f"Hello {name}!") - + @bot.user_command(name="Say Hello") async def hi(ctx, user): await ctx.respond(f"{ctx.author.mention} says hello to {user.name}!") - + bot.run("token") Traditional Commands Example diff --git a/discord/abc.py b/discord/abc.py index e46ba7445c..013319d356 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -1013,24 +1013,20 @@ async def move(self, **kwargs) -> None: bucket = self._sorting_bucket parent_id = kwargs.get("category", MISSING) - # fmt: off channels: List[GuildChannel] if parent_id not in (MISSING, None): parent_id = parent_id.id channels = [ ch for ch in self.guild.channels - if ch._sorting_bucket == bucket - and ch.category_id == parent_id + if ch._sorting_bucket == bucket and ch.category_id == parent_id ] else: channels = [ ch for ch in self.guild.channels - if ch._sorting_bucket == bucket - and ch.category_id == self.category_id + if ch._sorting_bucket == bucket and ch.category_id == self.category_id ] - # fmt: on channels.sort(key=lambda c: (c.position, c.id)) diff --git a/discord/activity.py b/discord/activity.py index 092e0a6263..c7e1b55bb8 100644 --- a/discord/activity.py +++ b/discord/activity.py @@ -421,13 +421,11 @@ def to_dict(self) -> Dict[str, Any]: if self._end: timestamps["end"] = self._end - # fmt: off return { - 'type': ActivityType.playing.value, - 'name': str(self.name), - 'timestamps': timestamps + "type": ActivityType.playing.value, + "name": str(self.name), + "timestamps": timestamps, } - # fmt: on def __eq__(self, other: Any) -> bool: return isinstance(other, Game) and other.name == self.name @@ -525,14 +523,12 @@ def twitch_name(self): return name[7:] if name[:7] == "twitch:" else None def to_dict(self) -> Dict[str, Any]: - # fmt: off ret: Dict[str, Any] = { - 'type': ActivityType.streaming.value, - 'name': str(self.name), - 'url': str(self.url), - 'assets': self.assets + "type": ActivityType.streaming.value, + "name": str(self.name), + "url": str(self.url), + "assets": self.assets, } - # fmt: on if self.details: ret["details"] = self.details return ret diff --git a/discord/audit_logs.py b/discord/audit_logs.py index d557bafeaa..323257c635 100644 --- a/discord/audit_logs.py +++ b/discord/audit_logs.py @@ -203,43 +203,50 @@ def __setattr__(self, key: str, value: Any) -> Any: class AuditLogChanges: - # fmt: off TRANSFORMERS: ClassVar[Dict[str, Tuple[Optional[str], Optional[Transformer]]]] = { - 'verification_level': (None, _enum_transformer(enums.VerificationLevel)), - 'explicit_content_filter': (None, _enum_transformer(enums.ContentFilter)), - 'allow': (None, _transform_permissions), - 'deny': (None, _transform_permissions), - 'permissions': (None, _transform_permissions), - 'id': (None, _transform_snowflake), - 'color': ('colour', _transform_color), - 'owner_id': ('owner', _transform_member_id), - 'inviter_id': ('inviter', _transform_member_id), - 'channel_id': ('channel', _transform_channel), - 'afk_channel_id': ('afk_channel', _transform_channel), - 'system_channel_id': ('system_channel', _transform_channel), - 'widget_channel_id': ('widget_channel', _transform_channel), - 'rules_channel_id': ('rules_channel', _transform_channel), - 'public_updates_channel_id': ('public_updates_channel', _transform_channel), - 'permission_overwrites': ('overwrites', _transform_overwrites), - 'splash_hash': ('splash', _guild_hash_transformer('splashes')), - 'banner_hash': ('banner', _guild_hash_transformer('banners')), - 'discovery_splash_hash': ('discovery_splash', _guild_hash_transformer('discovery-splashes')), - 'icon_hash': ('icon', _transform_icon), - 'avatar_hash': ('avatar', _transform_avatar), - 'rate_limit_per_user': ('slowmode_delay', None), - 'guild_id': ('guild', _transform_guild_id), - 'tags': ('emoji', None), - 'default_message_notifications': ('default_notifications', _enum_transformer(enums.NotificationLevel)), - 'region': (None, _enum_transformer(enums.VoiceRegion)), - 'rtc_region': (None, _enum_transformer(enums.VoiceRegion)), - 'video_quality_mode': (None, _enum_transformer(enums.VideoQualityMode)), - 'privacy_level': (None, _enum_transformer(enums.StagePrivacyLevel)), - 'format_type': (None, _enum_transformer(enums.StickerFormatType)), - 'type': (None, _transform_type), - 'status': (None, _enum_transformer(enums.ScheduledEventStatus)), - 'entity_type': ('location_type', _enum_transformer(enums.ScheduledEventLocationType)), + "verification_level": (None, _enum_transformer(enums.VerificationLevel)), + "explicit_content_filter": (None, _enum_transformer(enums.ContentFilter)), + "allow": (None, _transform_permissions), + "deny": (None, _transform_permissions), + "permissions": (None, _transform_permissions), + "id": (None, _transform_snowflake), + "color": ("colour", _transform_color), + "owner_id": ("owner", _transform_member_id), + "inviter_id": ("inviter", _transform_member_id), + "channel_id": ("channel", _transform_channel), + "afk_channel_id": ("afk_channel", _transform_channel), + "system_channel_id": ("system_channel", _transform_channel), + "widget_channel_id": ("widget_channel", _transform_channel), + "rules_channel_id": ("rules_channel", _transform_channel), + "public_updates_channel_id": ("public_updates_channel", _transform_channel), + "permission_overwrites": ("overwrites", _transform_overwrites), + "splash_hash": ("splash", _guild_hash_transformer("splashes")), + "banner_hash": ("banner", _guild_hash_transformer("banners")), + "discovery_splash_hash": ( + "discovery_splash", + _guild_hash_transformer("discovery-splashes"), + ), + "icon_hash": ("icon", _transform_icon), + "avatar_hash": ("avatar", _transform_avatar), + "rate_limit_per_user": ("slowmode_delay", None), + "guild_id": ("guild", _transform_guild_id), + "tags": ("emoji", None), + "default_message_notifications": ( + "default_notifications", + _enum_transformer(enums.NotificationLevel), + ), + "region": (None, _enum_transformer(enums.VoiceRegion)), + "rtc_region": (None, _enum_transformer(enums.VoiceRegion)), + "video_quality_mode": (None, _enum_transformer(enums.VideoQualityMode)), + "privacy_level": (None, _enum_transformer(enums.StagePrivacyLevel)), + "format_type": (None, _enum_transformer(enums.StickerFormatType)), + "type": (None, _transform_type), + "status": (None, _enum_transformer(enums.ScheduledEventStatus)), + "entity_type": ( + "location_type", + _enum_transformer(enums.ScheduledEventLocationType), + ), } - # fmt: on def __init__( self, @@ -497,17 +504,17 @@ def _from_data(self, data: AuditLogEntryPayload) -> None: "_AuditLogProxy", (), elems )() - # fmt: off self.extra: Union[ _AuditLogProxyMemberPrune, _AuditLogProxyMemberMoveOrMessageDelete, _AuditLogProxyMemberDisconnect, _AuditLogProxyPinAction, _AuditLogProxyStageInstanceAction, - Member, User, None, + Member, + User, + None, Role, ] - # fmt: on # this key is not present when the above is present, typically. # It's a list of { new_value: a, old_value: b, key: c } diff --git a/discord/channel.py b/discord/channel.py index 21f12da26a..a3fe0ea58b 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -926,13 +926,11 @@ def voice_states(self) -> Dict[int, VoiceState]: Mapping[:class:`int`, :class:`VoiceState`] The mapping of member ID to a voice state. """ - # fmt: off return { key: value for key, value in self.guild._voice_states.items() if value.channel and value.channel.id == self.id } - # fmt: on @utils.copy_doc(discord.abc.GuildChannel.permissions_for) def permissions_for(self, obj: Union[Member, Role], /) -> Permissions: diff --git a/discord/embeds.py b/discord/embeds.py index 1cddd17eb2..fc69805c56 100644 --- a/discord/embeds.py +++ b/discord/embeds.py @@ -752,13 +752,11 @@ def to_dict(self) -> EmbedData: """Converts this embed object into a dict.""" # add in the raw data into the dict - # fmt: off result = { key[1:]: getattr(self, key) for key in self.__slots__ - if key[0] == '_' and hasattr(self, key) + if key[0] == "_" and hasattr(self, key) } - # fmt: on # deal with basic convenience wrappers diff --git a/discord/enums.py b/discord/enums.py index 616f612920..18665bbf70 100644 --- a/discord/enums.py +++ b/discord/enums.py @@ -340,109 +340,105 @@ class AuditLogActionCategory(Enum): class AuditLogAction(Enum): - # fmt: off - guild_update = 1 - channel_create = 10 - channel_update = 11 - channel_delete = 12 - overwrite_create = 13 - overwrite_update = 14 - overwrite_delete = 15 - kick = 20 - member_prune = 21 - ban = 22 - unban = 23 - member_update = 24 - member_role_update = 25 - member_move = 26 - member_disconnect = 27 - bot_add = 28 - role_create = 30 - role_update = 31 - role_delete = 32 - invite_create = 40 - invite_update = 41 - invite_delete = 42 - webhook_create = 50 - webhook_update = 51 - webhook_delete = 52 - emoji_create = 60 - emoji_update = 61 - emoji_delete = 62 - message_delete = 72 - message_bulk_delete = 73 - message_pin = 74 - message_unpin = 75 - integration_create = 80 - integration_update = 81 - integration_delete = 82 - stage_instance_create = 83 - stage_instance_update = 84 - stage_instance_delete = 85 - sticker_create = 90 - sticker_update = 91 - sticker_delete = 92 - scheduled_event_create = 100 - scheduled_event_update = 101 - scheduled_event_delete = 102 - thread_create = 110 - thread_update = 111 - thread_delete = 112 - # fmt: on + guild_update = 1 + channel_create = 10 + channel_update = 11 + channel_delete = 12 + overwrite_create = 13 + overwrite_update = 14 + overwrite_delete = 15 + kick = 20 + member_prune = 21 + ban = 22 + unban = 23 + member_update = 24 + member_role_update = 25 + member_move = 26 + member_disconnect = 27 + bot_add = 28 + role_create = 30 + role_update = 31 + role_delete = 32 + invite_create = 40 + invite_update = 41 + invite_delete = 42 + webhook_create = 50 + webhook_update = 51 + webhook_delete = 52 + emoji_create = 60 + emoji_update = 61 + emoji_delete = 62 + message_delete = 72 + message_bulk_delete = 73 + message_pin = 74 + message_unpin = 75 + integration_create = 80 + integration_update = 81 + integration_delete = 82 + stage_instance_create = 83 + stage_instance_update = 84 + stage_instance_delete = 85 + sticker_create = 90 + sticker_update = 91 + sticker_delete = 92 + scheduled_event_create = 100 + scheduled_event_update = 101 + scheduled_event_delete = 102 + thread_create = 110 + thread_update = 111 + thread_delete = 112 @property def category(self) -> Optional[AuditLogActionCategory]: - # fmt: off lookup: Dict[AuditLogAction, Optional[AuditLogActionCategory]] = { - AuditLogAction.guild_update: AuditLogActionCategory.update, - AuditLogAction.channel_create: AuditLogActionCategory.create, - AuditLogAction.channel_update: AuditLogActionCategory.update, - AuditLogAction.channel_delete: AuditLogActionCategory.delete, - AuditLogAction.overwrite_create: AuditLogActionCategory.create, - AuditLogAction.overwrite_update: AuditLogActionCategory.update, - AuditLogAction.overwrite_delete: AuditLogActionCategory.delete, - AuditLogAction.kick: None, - AuditLogAction.member_prune: None, - AuditLogAction.ban: None, - AuditLogAction.unban: None, - AuditLogAction.member_update: AuditLogActionCategory.update, - AuditLogAction.member_role_update: AuditLogActionCategory.update, - AuditLogAction.member_move: None, - AuditLogAction.member_disconnect: None, - AuditLogAction.bot_add: None, - AuditLogAction.role_create: AuditLogActionCategory.create, - AuditLogAction.role_update: AuditLogActionCategory.update, - AuditLogAction.role_delete: AuditLogActionCategory.delete, - AuditLogAction.invite_create: AuditLogActionCategory.create, - AuditLogAction.invite_update: AuditLogActionCategory.update, - AuditLogAction.invite_delete: AuditLogActionCategory.delete, - AuditLogAction.webhook_create: AuditLogActionCategory.create, - AuditLogAction.webhook_update: AuditLogActionCategory.update, - AuditLogAction.webhook_delete: AuditLogActionCategory.delete, - AuditLogAction.emoji_create: AuditLogActionCategory.create, - AuditLogAction.emoji_update: AuditLogActionCategory.update, - AuditLogAction.emoji_delete: AuditLogActionCategory.delete, - AuditLogAction.message_delete: AuditLogActionCategory.delete, - AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete, - AuditLogAction.message_pin: None, - AuditLogAction.message_unpin: None, - AuditLogAction.integration_create: AuditLogActionCategory.create, - AuditLogAction.integration_update: AuditLogActionCategory.update, - AuditLogAction.integration_delete: AuditLogActionCategory.delete, - AuditLogAction.stage_instance_create: AuditLogActionCategory.create, - AuditLogAction.stage_instance_update: AuditLogActionCategory.update, - AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete, - AuditLogAction.sticker_create: AuditLogActionCategory.create, - AuditLogAction.sticker_update: AuditLogActionCategory.update, - AuditLogAction.sticker_delete: AuditLogActionCategory.delete, + AuditLogAction.guild_update: AuditLogActionCategory.update, + AuditLogAction.channel_create: AuditLogActionCategory.create, + AuditLogAction.channel_update: AuditLogActionCategory.update, + AuditLogAction.channel_delete: AuditLogActionCategory.delete, + AuditLogAction.overwrite_create: AuditLogActionCategory.create, + AuditLogAction.overwrite_update: AuditLogActionCategory.update, + AuditLogAction.overwrite_delete: AuditLogActionCategory.delete, + AuditLogAction.kick: None, + AuditLogAction.member_prune: None, + AuditLogAction.ban: None, + AuditLogAction.unban: None, + AuditLogAction.member_update: AuditLogActionCategory.update, + AuditLogAction.member_role_update: AuditLogActionCategory.update, + AuditLogAction.member_move: None, + AuditLogAction.member_disconnect: None, + AuditLogAction.bot_add: None, + AuditLogAction.role_create: AuditLogActionCategory.create, + AuditLogAction.role_update: AuditLogActionCategory.update, + AuditLogAction.role_delete: AuditLogActionCategory.delete, + AuditLogAction.invite_create: AuditLogActionCategory.create, + AuditLogAction.invite_update: AuditLogActionCategory.update, + AuditLogAction.invite_delete: AuditLogActionCategory.delete, + AuditLogAction.webhook_create: AuditLogActionCategory.create, + AuditLogAction.webhook_update: AuditLogActionCategory.update, + AuditLogAction.webhook_delete: AuditLogActionCategory.delete, + AuditLogAction.emoji_create: AuditLogActionCategory.create, + AuditLogAction.emoji_update: AuditLogActionCategory.update, + AuditLogAction.emoji_delete: AuditLogActionCategory.delete, + AuditLogAction.message_delete: AuditLogActionCategory.delete, + AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete, + AuditLogAction.message_pin: None, + AuditLogAction.message_unpin: None, + AuditLogAction.integration_create: AuditLogActionCategory.create, + AuditLogAction.integration_update: AuditLogActionCategory.update, + AuditLogAction.integration_delete: AuditLogActionCategory.delete, + AuditLogAction.stage_instance_create: AuditLogActionCategory.create, + AuditLogAction.stage_instance_update: AuditLogActionCategory.update, + AuditLogAction.stage_instance_delete: AuditLogActionCategory.delete, + AuditLogAction.sticker_create: AuditLogActionCategory.create, + AuditLogAction.sticker_update: AuditLogActionCategory.update, + AuditLogAction.sticker_delete: AuditLogActionCategory.delete, AuditLogAction.scheduled_event_create: AuditLogActionCategory.create, AuditLogAction.scheduled_event_update: AuditLogActionCategory.update, AuditLogAction.scheduled_event_delete: AuditLogActionCategory.delete, - AuditLogAction.thread_create: AuditLogActionCategory.create, - AuditLogAction.thread_update: AuditLogActionCategory.update, - AuditLogAction.thread_delete: AuditLogActionCategory.delete, + AuditLogAction.thread_create: AuditLogActionCategory.create, + AuditLogAction.thread_update: AuditLogActionCategory.update, + AuditLogAction.thread_delete: AuditLogActionCategory.delete, } - # fmt: on return lookup[self] @property @@ -548,13 +544,11 @@ class StickerFormatType(Enum): @property def file_extension(self) -> str: - # fmt: off lookup: Dict[StickerFormatType, str] = { - StickerFormatType.png: 'png', - StickerFormatType.apng: 'png', - StickerFormatType.lottie: 'json', + StickerFormatType.png: "png", + StickerFormatType.apng: "png", + StickerFormatType.lottie: "json", } - # fmt: on return lookup[self] diff --git a/discord/flags.py b/discord/flags.py index cd429bf0b5..5bfb20a333 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -85,17 +85,15 @@ class alias_flag_value(flag_value): def fill_with_flags(*, inverted: bool = False): def decorator(cls: Type[BF]): - # fmt: off cls.VALID_FLAGS = { name: value.flag for name, value in cls.__dict__.items() if isinstance(value, flag_value) } - # fmt: on if inverted: max_bits = max(cls.VALID_FLAGS.values()).bit_length() - cls.DEFAULT_VALUE = -1 + (2 ** max_bits) + cls.DEFAULT_VALUE = -1 + (2**max_bits) else: cls.DEFAULT_VALUE = 0 diff --git a/discord/message.py b/discord/message.py index 0ef0f61acf..ac3602f932 100644 --- a/discord/message.py +++ b/discord/message.py @@ -1012,20 +1012,19 @@ def clean_content(self) -> str: respectively, along with this function. """ - # fmt: off transformations = { - re.escape(f'<#{channel.id}>'): f"#{channel.name}" + re.escape(f"<#{channel.id}>"): f"#{channel.name}" for channel in self.channel_mentions } mention_transforms = { - re.escape(f'<@{member.id}>'): f"@{member.display_name}" + re.escape(f"<@{member.id}>"): f"@{member.display_name}" for member in self.mentions } # add the <@!user_id> cases as well.. second_mention_transforms = { - re.escape(f'<@!{member.id}>'): f"@{member.display_name}" + re.escape(f"<@!{member.id}>"): f"@{member.display_name}" for member in self.mentions } @@ -1034,13 +1033,11 @@ def clean_content(self) -> str: if self.guild is not None: role_transforms = { - re.escape(f'<@&{role.id}>'): f"@{role.name}" + re.escape(f"<@&{role.id}>"): f"@{role.name}" for role in self.role_mentions } transformations.update(role_transforms) - # fmt: on - def repl(obj): return transformations.get(re.escape(obj.group(0)), "") diff --git a/discord/ui/view.py b/discord/ui/view.py index e8241eb464..9e1451fc93 100644 --- a/discord/ui/view.py +++ b/discord/ui/view.py @@ -414,13 +414,11 @@ def _dispatch_item(self, item: Item, interaction: Interaction): def refresh(self, components: List[Component]): # This is pretty hacky at the moment - # fmt: off old_state: Dict[Tuple[int, str], Item] = { (item.type.value, item.custom_id): item # type: ignore for item in self.children if item.is_dispatchable() } - # fmt: on children: List[Item] = [ item for item in self.children if not item.is_dispatchable() ] @@ -498,13 +496,11 @@ def __init__(self, state: ConnectionState): @property def persistent_views(self) -> Sequence[View]: - # fmt: off views = { view.id: view for (_, (view, _)) in self._views.items() if view.is_persistent() } - # fmt: on return list(views.values()) def __verify_integrity(self): diff --git a/discord/utils.py b/discord/utils.py index 08d1f52644..3646d2f470 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -379,7 +379,7 @@ def time_snowflake(dt: datetime.datetime, high: bool = False) -> int: The snowflake representing the time given. """ discord_millis = int(dt.timestamp() * 1000 - DISCORD_EPOCH) - return (discord_millis << 22) + (2 ** 22 - 1 if high else 0) + return (discord_millis << 22) + (2**22 - 1 if high else 0) def find(predicate: Callable[[T], Any], seq: Iterable[T]) -> Optional[T]: @@ -749,22 +749,22 @@ def resolve_template(code: Union[Template, str]) -> str: # this page provides a good reference: http://blog.michaelperrin.fr/2019/02/04/advanced-regular-expressions/ _MARKDOWN_ESCAPE_LINKS = r""" \[ # matches link text - [^\[\]]* # link text can contain anything but brackets + [^\[\]]* # link text can contain anything but brackets \] \( # matches link destination [^\(\)]+ # link destination cannot contain parentheses \)""" # note 2: make sure this regex is consumed in re.X (extended mode) since it has whitespace and comments -_MARKDOWN_ESCAPE_COMMON = fr"^>(?:>>)?\s|{_MARKDOWN_ESCAPE_LINKS}" +_MARKDOWN_ESCAPE_COMMON = rf"^>(?:>>)?\s|{_MARKDOWN_ESCAPE_LINKS}" _MARKDOWN_ESCAPE_REGEX = re.compile( - fr"(?P{_MARKDOWN_ESCAPE_SUBREGEX}|{_MARKDOWN_ESCAPE_COMMON})", + rf"(?P{_MARKDOWN_ESCAPE_SUBREGEX}|{_MARKDOWN_ESCAPE_COMMON})", re.MULTILINE | re.X, ) _URL_REGEX = r"(?P<[^: >]+:\/[^ >]+>|(?:https?|steam):\/\/[^\s<]+[^<.,:;\"\'\]\s])" -_MARKDOWN_STOCK_REGEX = fr"(?P[_\\~|\*`]|{_MARKDOWN_ESCAPE_COMMON})" +_MARKDOWN_STOCK_REGEX = rf"(?P[_\\~|\*`]|{_MARKDOWN_ESCAPE_COMMON})" def remove_markdown(text: str, *, ignore_links: bool = True) -> str: diff --git a/docs/_static/custom.js b/docs/_static/custom.js index f3cfa461fb..e995275951 100644 --- a/docs/_static/custom.js +++ b/docs/_static/custom.js @@ -60,7 +60,7 @@ document.addEventListener('DOMContentLoaded', () => { bottomHeightThreshold = document.documentElement.scrollHeight - 30; sections = document.querySelectorAll('section'); hamburgerToggle = document.getElementById('hamburger-toggle'); - + toTop = document.getElementById('to-top'); toTop.hidden = !(window.scrollY > 0); diff --git a/docs/api.rst b/docs/api.rst index 78f856ad61..cc22de8672 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -475,7 +475,7 @@ to handle it, which defaults to print a traceback and ignoring the exception. .. function:: on_raw_typing(payload) - Called when someone begins typing a message. Unlike :func:`on_typing`, this is + Called when someone begins typing a message. Unlike :func:`on_typing`, this is called regardless if the user can be found in the bot's cache or not. If the typing event is occurring in a guild, @@ -835,7 +835,7 @@ to handle it, which defaults to print a traceback and ignoring the exception. .. function:: on_thread_delete(thread) - Called whenever a thread is deleted. If the deleted thread isn't found in internal cache + Called whenever a thread is deleted. If the deleted thread isn't found in internal cache then this will not be called. Archived threads are not in the cache. Consider using :func:`on_raw_thread_delete` @@ -849,7 +849,7 @@ to handle it, which defaults to print a traceback and ignoring the exception. :type thread: :class:`Thread` .. function:: on_raw_thread_delete(payload) - + Called whenever a thread is deleted. Unlike :func:`on_thread_delete` this is called regardless of the state of the internal cache. @@ -2634,7 +2634,7 @@ of :class:`enum.Enum`. - :attr:`~AuditLogDiff.location_type` .. versionadded:: 2.0 - + .. attribute:: scheduled_event_update A scheduled event was updated. @@ -2654,7 +2654,7 @@ of :class:`enum.Enum`. - :attr:`~AuditLogDiff.location_type` .. versionadded:: 2.0 - + .. attribute:: scheduled_event_delete A scheduled event was deleted. @@ -2959,7 +2959,7 @@ of :class:`enum.Enum`. Some might be boost-only or gated. .. warning:: - + Discord said that they won't verify bots who gives access to embedded activities. Read more here: https://discord.com/channels/613425648685547541/697236247739105340/901153332075315321. @@ -2967,29 +2967,29 @@ of :class:`enum.Enum`. .. versionadded:: 2.0 .. attribute:: awkword - + Represents the embedded application Awkword. .. attribute:: betrayal Represents the embedded application Betrayal.io - + .. attribute:: checkers_in_the_park Represents the embedded application Checkers in the Park Prod. - + .. attribute:: checkers_in_the_park_dev Represents the embedded application Checkers in the Park Development. - + .. attribute:: checkers_in_the_park_staging - + Represents the embedded application Checkers in the Park Staging. - + .. attribute:: checkers_in_the_park_qa - + Represents the embedded application Checkers in the Park QA. - + .. attribute:: chess_in_the_park Represents the embedded application Chess in the Park. @@ -2999,13 +2999,13 @@ of :class:`enum.Enum`. Represents the embedded application Chess in the Park Development. .. attribute:: chest_in_the_park_staging - + Represents the embedded application Chess in the Park Staging. .. attribute:: chest_in_the_park_qa - + Represents the embedded application Chess in the Park QA. - + .. attribute:: doodle_crew Represents the embedded application Doodle Crew. @@ -3017,9 +3017,9 @@ of :class:`enum.Enum`. .. attribute:: letter_tile Represents the embedded application Letter Tile. - + .. attribute:: ocho - + Represents the embedded application Ocho. .. attribute:: ocho_dev @@ -3027,13 +3027,13 @@ of :class:`enum.Enum`. Represents the embedded application Ocho Development. .. attribute:: ocho_staging - + Represents the embedded application Ocho Staging. - + .. attribute:: ocho_qa - + Represents the embedded application Ocho QA. - + .. attribute:: poker_night_staging Represents the embedded application Poker Night Staging. @@ -3041,23 +3041,23 @@ of :class:`enum.Enum`. .. attribute:: poker_night Represents the embedded application Poker Night. - + .. attribute:: poker_night_qa Represents the embedded application Poker QA. - + .. attribute:: putts - + Represents the embedded application Putts. - .. attribute:: sketchy_artist - + .. attribute:: sketchy_artist + Represents the embedded application Sketchy Artist. - + .. attribute:: sketchy_artist_dev - + Represents the embedded application Sketchy Artist development version. - + .. attribute:: spell_cast Represents the embedded application Spell Cast. @@ -3065,19 +3065,19 @@ of :class:`enum.Enum`. .. attribute:: watch_together Same as :attr:`~EmbeddedActivity.youtube_together` with remote feature which allows guild admins to limit the playlist access. - + .. attribute:: watch_together_dev Development version of :attr:`.watch_together`. .. attribute:: word_snacks - + Represents the embedded application word snacks. - + .. attribute:: word_snacks_dev - + Represents the embedded application word snacks. This is development version of :attr:`.word_snacks` - + .. attribute:: youtube_together Represents the embedded application Youtube Together. @@ -4346,7 +4346,7 @@ Template .. autoclass:: Template() :members: - + WelcomeScreen ~~~~~~~~~~~~~~~ diff --git a/docs/application_commands.rst b/docs/application_commands.rst index 5a1723602d..7a5a615546 100644 --- a/docs/application_commands.rst +++ b/docs/application_commands.rst @@ -120,7 +120,7 @@ Slash Command Groups Slash command groups allows grouping multiple subcommands under the same parent. .. code-block:: python3 - + my_group = bot.create_group("name", "description") To create a subcommand, use the :meth:`.SlashCommandGroup.command` decorator. @@ -152,4 +152,4 @@ Slash command groups can also be created by subclassing :class:`.SlashCommandGro ... Using Cogs ----------- \ No newline at end of file +---------- diff --git a/docs/conf.py b/docs/conf.py index bf8bd4ea42..740c0cf99f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,9 +11,9 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys import os import re +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -72,8 +72,8 @@ # The suffix of source filenames. source_suffix = { - '.rst': 'restructuredtext', # Used For The Other Docs - '.md': 'markdown', # Used ONLY In the Guide For Faster Making Time + ".rst": "restructuredtext", # Used For The Other Docs + ".md": "markdown", # Used ONLY In the Guide For Faster Making Time } # The encoding of source files. @@ -163,12 +163,12 @@ html_theme = "basic" html_context = { - 'discord_invite': 'https://pycord.dev/discord', - 'discord_extensions': [ - ('discord.ext.commands', 'ext/commands'), - ('discord.ext.tasks', 'ext/tasks'), - ('discord.ext.pages', 'ext/pages'), - ], + "discord_invite": "https://pycord.dev/discord", + "discord_extensions": [ + ("discord.ext.commands", "ext/commands"), + ("discord.ext.tasks", "ext/tasks"), + ("discord.ext.pages", "ext/pages"), + ], } resource_links = { @@ -271,7 +271,7 @@ html_js_files = ["custom.js", "settings.js", "copy.js", "sidebar.js"] # Output file base name for HTML help builder. -htmlhelp_basename = 'pycorddoc' +htmlhelp_basename = "pycorddoc" # -- Options for LaTeX output --------------------------------------------- diff --git a/docs/discord.rst b/docs/discord.rst index 736925c298..4784806bec 100644 --- a/docs/discord.rst +++ b/docs/discord.rst @@ -93,4 +93,4 @@ If you want to invite your bot you must create an invite URL for it. The person adding the bot needs "Manage Server" permissions to do so. If you want to generate this URL dynamically at run-time inside your bot and using the -:class:`discord.Permissions` interface, you can use :func:`discord.utils.oauth_url`. \ No newline at end of file +:class:`discord.Permissions` interface, you can use :func:`discord.utils.oauth_url`. diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst index 1e26302df8..73f11fdcac 100644 --- a/docs/ext/commands/api.rst +++ b/docs/ext/commands/api.rst @@ -34,7 +34,7 @@ Bot .. automethod:: Bot.command(*args, **kwargs) :decorator: - + .. automethod:: Bot.event() :decorator: diff --git a/docs/ext/commands/cogs.rst b/docs/ext/commands/cogs.rst index 25bb1a0b81..09903a49c4 100644 --- a/docs/ext/commands/cogs.rst +++ b/docs/ext/commands/cogs.rst @@ -156,4 +156,3 @@ To do the same with listeners, we can query them with :meth:`.Cog.get_listeners` >>> for name, func in cog.get_listeners(): ... print(name, '->', func) - diff --git a/docs/extensions/attributetable.py b/docs/extensions/attributetable.py index ea9ebebdd8..eb7b0c387e 100644 --- a/docs/extensions/attributetable.py +++ b/docs/extensions/attributetable.py @@ -1,13 +1,13 @@ -from sphinx.util.docutils import SphinxDirective -from sphinx.locale import _ -from docutils import nodes -from sphinx import addnodes - -from collections import OrderedDict, namedtuple import importlib import inspect import os import re +from collections import OrderedDict, namedtuple + +from docutils import nodes +from sphinx import addnodes +from sphinx.locale import _ +from sphinx.util.docutils import SphinxDirective class attributetable(nodes.General, nodes.Element): @@ -99,7 +99,7 @@ def parse_name(self, content): modulename = self.env.ref_context.get("py:module") if modulename is None: raise RuntimeError( - "modulename somehow None for %s in %s." % (content, self.env.docname) + f"modulename somehow None for {content} in {self.env.docname}." ) return modulename, name diff --git a/docs/extensions/details.py b/docs/extensions/details.py index 7c4d7d6a5c..97e89b4f65 100644 --- a/docs/extensions/details.py +++ b/docs/extensions/details.py @@ -1,7 +1,6 @@ -from docutils.parsers.rst import Directive -from docutils.parsers.rst import states, directives -from docutils.parsers.rst.roles import set_classes from docutils import nodes +from docutils.parsers.rst import Directive, directives, states +from docutils.parsers.rst.roles import set_classes class details(nodes.General, nodes.Element): diff --git a/docs/extensions/exception_hierarchy.py b/docs/extensions/exception_hierarchy.py index 1e80acb92c..11a7bdd65c 100644 --- a/docs/extensions/exception_hierarchy.py +++ b/docs/extensions/exception_hierarchy.py @@ -1,7 +1,6 @@ -from docutils.parsers.rst import Directive -from docutils.parsers.rst import states, directives -from docutils.parsers.rst.roles import set_classes from docutils import nodes +from docutils.parsers.rst import Directive, directives, states +from docutils.parsers.rst.roles import set_classes from sphinx.locale import _ diff --git a/docs/extensions/resourcelinks.py b/docs/extensions/resourcelinks.py index 5abc454a95..d37af4c903 100644 --- a/docs/extensions/resourcelinks.py +++ b/docs/extensions/resourcelinks.py @@ -4,11 +4,10 @@ from typing import Any, Dict, List, Tuple +import sphinx from docutils import nodes, utils from docutils.nodes import Node, system_message from docutils.parsers.rst.states import Inliner - -import sphinx from sphinx.application import Sphinx from sphinx.util.nodes import split_explicit_title from sphinx.util.typing import RoleFunction diff --git a/docs/images/snake.svg b/docs/images/snake.svg index aa741440ef..1f2e0afc94 100644 --- a/docs/images/snake.svg +++ b/docs/images/snake.svg @@ -1,4 +1,4 @@ - diff --git a/docs/installing.rst b/docs/installing.rst index d2a48f3e04..75a88e1046 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -22,12 +22,12 @@ is not provided. Python 2.7 or lower is not supported. Python 3.7 or lower is no Installing ----------- -**!!! IMPORTANT !!!** +**!!! IMPORTANT !!!** For new features like options, buttons, and threads, you need to install from git until our v2.0 release on Jan 28th, 2022. :: python3 -m pip install -U git+https://github.com/Pycord-Development/pycord - + For Windows users, this command should be used to install from git: :: py -3 -m pip install -U git+https://github.com/Pycord-Development/pycord @@ -47,7 +47,7 @@ To install additional packages for speedup, you should use ``py-cord[speed]`` i # Linux/macOS python3 -m pip install -U "py-cord[speed]" - + # Windows py -3 -m pip install -U py-cord[speed] @@ -130,4 +130,4 @@ A quick example to showcase how events work: print(f'Message from {message.author}: {message.content}') client = MyClient() - client.run('my token goes here') \ No newline at end of file + client.run('my token goes here') diff --git a/docs/intents.rst b/docs/intents.rst index 19560df0b9..f0e8ab79b4 100644 --- a/docs/intents.rst +++ b/docs/intents.rst @@ -202,4 +202,4 @@ Under the original system this would result in 2 requests to fetch the member li Unfortunately due to this change being required from Discord there is nothing that the library can do to mitigate this. -If you truly dislike the direction Discord is going with their API, you can contact them via `support `_. \ No newline at end of file +If you truly dislike the direction Discord is going with their API, you can contact them via `support `_. diff --git a/docs/logging.rst b/docs/logging.rst index 596a845cad..dfb95dd644 100644 --- a/docs/logging.rst +++ b/docs/logging.rst @@ -43,4 +43,4 @@ stdout of your program. For more information, check the documentation and tutorial of the -:mod:`logging` module. \ No newline at end of file +:mod:`logging` module. diff --git a/docs/quickstart.rst b/docs/quickstart.rst index ca4edbae9e..bcd72c9485 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -55,7 +55,7 @@ There's a lot going on here, so let's walk you through it step by step: sure that we ignore messages from ourselves. We do this by checking if the :attr:`Message.author` is the same as the :attr:`Client.user`. 5. Afterwards, we check if the :class:`Message.content` starts with ``'$hello'``. If it does, - then we send a message in the channel it was used in with ``'Hello!'``. This is a basic way of + then we send a message in the channel it was used in with ``'Hello!'``. This is a basic way of handling commands, which can be later automated with the :doc:`./ext/commands/index` framework. 6. Finally, we run the bot with our login token. If you need help getting your token or creating a bot, look in the :ref:`discord-intro` section. @@ -106,8 +106,8 @@ Let's look at the differences compared to the previous example, step-by-step: 1. The first line remains unchanged. 2. Next, we create an instance of :class:`.Bot`. This is different from :class:`.Client`, as it supports slash command creation and other features, while inheriting all the features of :class:`.Client`. -3. We then use the :meth:`.Bot.slash_command` decorator to register a new slash command. - The ``guild_ids`` attribute contains a list of guilds where this command will be active. +3. We then use the :meth:`.Bot.slash_command` decorator to register a new slash command. + The ``guild_ids`` attribute contains a list of guilds where this command will be active. If you omit it, the command will be globally available, and may take up to an hour to register. 4. Afterwards, we trigger a response to the slash command in the form of a text reply. Please note that all slash commands must have some form of response, otherwise they will fail. diff --git a/docs/version_guarantees.rst b/docs/version_guarantees.rst index 076d8f26eb..b4d5a9ad18 100644 --- a/docs/version_guarantees.rst +++ b/docs/version_guarantees.rst @@ -26,4 +26,4 @@ Examples of Non-Breaking Changes - Changing the behaviour of a function to fix a bug. - Changes in the documentation. - Modifying the internal HTTP handling. -- Upgrading the dependencies to a new version, major or otherwise. \ No newline at end of file +- Upgrading the dependencies to a new version, major or otherwise. diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 210cb535d2..e9de578906 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -1182,4 +1182,4 @@ Bug Fixes - Mentions are now triggered normally. This was changed due to the way discord handles it internally. - Fix issue when a :class:`Message` would attempt to upgrade a :attr:`Message.server` when the channel is a :class:`Object`. -- Unavailable servers were not being added into cache, this has been corrected. \ No newline at end of file +- Unavailable servers were not being added into cache, this has been corrected. diff --git a/requirements.txt b/requirements.txt index 9ad0580346..473db5b253 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -aiohttp>=3.6.0,<3.9.0 \ No newline at end of file +aiohttp>=3.6.0,<3.9.0 +pre-commit diff --git a/setup.py b/setup.py index 2abfd2fbd8..e7010eaf54 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,9 @@ version = "" with open("discord/__init__.py") as f: - search = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE) + search = re.search( + r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE + ) if search is not None: version = search.group(1) @@ -27,11 +29,19 @@ try: import subprocess - p = subprocess.Popen(["git", "rev-list", "--count", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen( + ["git", "rev-list", "--count", "HEAD"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) out, err = p.communicate() if out: version += out.decode("utf-8").strip() - p = subprocess.Popen(["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen( + ["git", "rev-parse", "--short", "HEAD"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) out, err = p.communicate() if out: version += "+g" + out.decode("utf-8").strip() @@ -43,7 +53,7 @@ with open("README.rst") as f: readme = f.read() -# Extra Requirements +# Extra Requirements # Ex: pip install py-cord[voice] or [speed] extras_require = { "voice": ["PyNaCl>=1.3.0,<1.6"], @@ -109,5 +119,5 @@ "Topic :: Utilities", "Typing :: Typed", ], - test_suite="tests", # Test Folder For Workflows + test_suite="tests", # Test Folder For Workflows )