From 7b9f3248917f76817b1bdd5cac5fa5110e31d0a7 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 19:20:30 +0400 Subject: Clean Up Startup Ping Function The function was missing the self arg, which would lead to an exception at startup for any projects that don't override it. It's also not being awaited despite being an async function. Signed-off-by: Hassan Abouelela --- botcore/_bot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'botcore') diff --git a/botcore/_bot.py b/botcore/_bot.py index e9eba5c5..ed31d624 100644 --- a/botcore/_bot.py +++ b/botcore/_bot.py @@ -197,7 +197,7 @@ class BotBase(commands.Bot): if not guild.roles or not guild.members or not guild.channels: msg = "Guild available event was dispatched but the cache appears to still be empty!" - self.log_to_dev_log(msg) + await self.log_to_dev_log(msg) return self._guild_available.set() @@ -249,7 +249,7 @@ class BotBase(commands.Bot): except Exception as e: raise StartupError(e) - async def ping_services() -> None: + async def ping_services(self) -> None: """Ping all required services on setup to ensure they are up before starting.""" ... -- cgit v1.2.3 From 9d0cf91e237e7716c618014676a90ed4d780495a Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 19:22:38 +0400 Subject: Add Typehints To Typing Patcher Signed-off-by: Hassan Abouelela --- botcore/utils/_monkey_patches.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'botcore') diff --git a/botcore/utils/_monkey_patches.py b/botcore/utils/_monkey_patches.py index f2c6c100..c2f8aa10 100644 --- a/botcore/utils/_monkey_patches.py +++ b/botcore/utils/_monkey_patches.py @@ -1,6 +1,7 @@ """Contains all common monkey patches, used to alter discord to fit our needs.""" import logging +import typing from datetime import datetime, timedelta from functools import partial, partialmethod @@ -46,9 +47,9 @@ def _patch_typing() -> None: log.debug("Patching send_typing, which should fix things breaking when Discord disables typing events. Stay safe!") original = http.HTTPClient.send_typing - last_403 = None + last_403: typing.Optional[datetime] = None - async def honeybadger_type(self, channel_id: int) -> None: # noqa: ANN001 + async def honeybadger_type(self: http.HTTPClient, channel_id: int) -> None: nonlocal last_403 if last_403 and (datetime.utcnow() - last_403) < timedelta(minutes=5): log.warning("Not sending typing event, we got a 403 less than 5 minutes ago.") -- cgit v1.2.3 From a9966239af6edc1cd9b6133de41f03d15ceec285 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 19:23:14 +0400 Subject: Fix Docstring For Role Change Wrapper Util Signed-off-by: Hassan Abouelela --- botcore/utils/members.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'botcore') diff --git a/botcore/utils/members.py b/botcore/utils/members.py index e89b4618..10513953 100644 --- a/botcore/utils/members.py +++ b/botcore/utils/members.py @@ -1,5 +1,4 @@ """Useful helper functions for interactin with :obj:`discord.Member` objects.""" - import typing import discord @@ -30,18 +29,19 @@ async def get_or_fetch_member(guild: discord.Guild, member_id: int) -> typing.Op async def handle_role_change( member: discord.Member, - coro: typing.Callable[..., typing.Coroutine], + coro: typing.Callable[[discord.Role], typing.Coroutine], role: discord.Role ) -> None: """ - Await the given ``coro`` with ``member`` as the sole argument. + Await the given ``coro`` with ``role`` as the sole argument. Handle errors that we expect to be raised from :obj:`discord.Member.add_roles` and :obj:`discord.Member.remove_roles`. Args: - member: The member to pass to ``coro``. + member: The member that is being modified for logging purposes. coro: This is intended to be :obj:`discord.Member.add_roles` or :obj:`discord.Member.remove_roles`. + role: The role to be passed to ``coro``. """ try: await coro(role) -- cgit v1.2.3 From f17f947006ae55f3baca2eeec7ce804dbfdac238 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 19:23:46 +0400 Subject: Fix Incorrect Typehints & Docstrings Signed-off-by: Hassan Abouelela --- botcore/site_api.py | 2 +- botcore/utils/scheduling.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'botcore') diff --git a/botcore/site_api.py b/botcore/site_api.py index dbdf4f3b..d3a58b9c 100644 --- a/botcore/site_api.py +++ b/botcore/site_api.py @@ -26,7 +26,7 @@ class ResponseCodeError(ValueError): Args: response (:obj:`aiohttp.ClientResponse`): The response object from the request. response_json: The JSON response returned from the request, if any. - request_text: The text of the request, if any. + response_text: The text of the request, if any. """ self.status = response.status self.response_json = response_json or {} diff --git a/botcore/utils/scheduling.py b/botcore/utils/scheduling.py index 164f6b10..d9c3937a 100644 --- a/botcore/utils/scheduling.py +++ b/botcore/utils/scheduling.py @@ -209,7 +209,7 @@ class Scheduler: def create_task( - coro: typing.Awaitable, + coro: typing.Coroutine, *, suppressed_exceptions: tuple[typing.Type[Exception]] = (), event_loop: typing.Optional[asyncio.AbstractEventLoop] = None, -- cgit v1.2.3 From cabc6f7182c9b8f7999548d8d561ce6054af66d3 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 19:25:56 +0400 Subject: Declare Static Method The `maybe_raise_for_status` function is declared as a class function, but does not need to be so. Signed-off-by: Hassan Abouelela --- botcore/site_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'botcore') diff --git a/botcore/site_api.py b/botcore/site_api.py index d3a58b9c..44309f9d 100644 --- a/botcore/site_api.py +++ b/botcore/site_api.py @@ -76,7 +76,8 @@ class APIClient: """Close the aiohttp session.""" await self.session.close() - async def maybe_raise_for_status(self, response: aiohttp.ClientResponse, should_raise: bool) -> None: + @staticmethod + async def maybe_raise_for_status(response: aiohttp.ClientResponse, should_raise: bool) -> None: """ Raise :exc:`ResponseCodeError` for non-OK response if an exception should be raised. -- cgit v1.2.3 From ecb9a7e4f6b1ddeecbf0e00af4a149a99b4fa4c9 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 21:18:30 +0400 Subject: Document Create Task Return Type Signed-off-by: Hassan Abouelela --- botcore/utils/scheduling.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'botcore') diff --git a/botcore/utils/scheduling.py b/botcore/utils/scheduling.py index d9c3937a..8d2f875e 100644 --- a/botcore/utils/scheduling.py +++ b/botcore/utils/scheduling.py @@ -208,13 +208,16 @@ class Scheduler: self._log.error(f"Error in task #{task_id} {id(done_task)}!", exc_info=exception) +TASK_RETURN = typing.TypeVar("TASK_RETURN") + + def create_task( - coro: typing.Coroutine, + coro: typing.Coroutine[typing.Any, typing.Any, TASK_RETURN], *, suppressed_exceptions: tuple[typing.Type[Exception]] = (), event_loop: typing.Optional[asyncio.AbstractEventLoop] = None, **kwargs, -) -> asyncio.Task: +) -> asyncio.Task[TASK_RETURN]: """ Wrapper for creating an :obj:`asyncio.Task` which logs exceptions raised in the task. -- cgit v1.2.3 From 5efb69b2070ee972dd58401c06c0313513593a38 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 26 Jun 2022 21:42:07 +0400 Subject: Replace Typing Generics Replaces all typing generics with collection equivalents as per PEP 585. `typing.Callable` was not included in this due to a sphinx-autodoc bug not handling it well. Signed-off-by: Hassan Abouelela --- botcore/utils/members.py | 3 ++- botcore/utils/scheduling.py | 15 ++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'botcore') diff --git a/botcore/utils/members.py b/botcore/utils/members.py index 10513953..1536a8d1 100644 --- a/botcore/utils/members.py +++ b/botcore/utils/members.py @@ -1,5 +1,6 @@ """Useful helper functions for interactin with :obj:`discord.Member` objects.""" import typing +from collections import abc import discord @@ -29,7 +30,7 @@ async def get_or_fetch_member(guild: discord.Guild, member_id: int) -> typing.Op async def handle_role_change( member: discord.Member, - coro: typing.Callable[[discord.Role], typing.Coroutine], + coro: typing.Callable[[discord.Role], abc.Coroutine], role: discord.Role ) -> None: """ diff --git a/botcore/utils/scheduling.py b/botcore/utils/scheduling.py index 8d2f875e..8e30d63b 100644 --- a/botcore/utils/scheduling.py +++ b/botcore/utils/scheduling.py @@ -4,6 +4,7 @@ import asyncio import contextlib import inspect import typing +from collections import abc from datetime import datetime from functools import partial @@ -38,7 +39,7 @@ class Scheduler: self.name = name self._log = logging.get_logger(f"{__name__}.{name}") - self._scheduled_tasks: typing.Dict[typing.Hashable, asyncio.Task] = {} + self._scheduled_tasks: dict[typing.Hashable, asyncio.Task] = {} def __contains__(self, task_id: typing.Hashable) -> bool: """ @@ -52,7 +53,7 @@ class Scheduler: """ return task_id in self._scheduled_tasks - def schedule(self, task_id: typing.Hashable, coroutine: typing.Coroutine) -> None: + def schedule(self, task_id: typing.Hashable, coroutine: abc.Coroutine) -> None: """ Schedule the execution of a ``coroutine``. @@ -79,7 +80,7 @@ class Scheduler: self._scheduled_tasks[task_id] = task self._log.debug(f"Scheduled task #{task_id} {id(task)}.") - def schedule_at(self, time: datetime, task_id: typing.Hashable, coroutine: typing.Coroutine) -> None: + def schedule_at(self, time: datetime, task_id: typing.Hashable, coroutine: abc.Coroutine) -> None: """ Schedule ``coroutine`` to be executed at the given ``time``. @@ -107,7 +108,7 @@ class Scheduler: self, delay: typing.Union[int, float], task_id: typing.Hashable, - coroutine: typing.Coroutine + coroutine: abc.Coroutine ) -> None: """ Schedule ``coroutine`` to be executed after ``delay`` seconds. @@ -151,7 +152,7 @@ class Scheduler: self, delay: typing.Union[int, float], task_id: typing.Hashable, - coroutine: typing.Coroutine + coroutine: abc.Coroutine ) -> None: """Await ``coroutine`` after ``delay`` seconds.""" try: @@ -212,7 +213,7 @@ TASK_RETURN = typing.TypeVar("TASK_RETURN") def create_task( - coro: typing.Coroutine[typing.Any, typing.Any, TASK_RETURN], + coro: abc.Coroutine[typing.Any, typing.Any, TASK_RETURN], *, suppressed_exceptions: tuple[typing.Type[Exception]] = (), event_loop: typing.Optional[asyncio.AbstractEventLoop] = None, @@ -241,7 +242,7 @@ def create_task( return task -def _log_task_exception(task: asyncio.Task, *, suppressed_exceptions: typing.Tuple[typing.Type[Exception]]) -> None: +def _log_task_exception(task: asyncio.Task, *, suppressed_exceptions: tuple[type[Exception]]) -> None: """Retrieve and log the exception raised in ``task`` if one exists.""" with contextlib.suppress(asyncio.CancelledError): exception = task.exception() -- cgit v1.2.3 From 7913afabf954426119fe353485bdaaf4074a7e26 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Wed, 29 Jun 2022 13:38:05 +0400 Subject: Switch `typing.Hashable` With `Collections.abc.Hashable` Switches out the Hashable type from the typing library for the generic from collections. Signed-off-by: Hassan Abouelela --- botcore/utils/scheduling.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'botcore') diff --git a/botcore/utils/scheduling.py b/botcore/utils/scheduling.py index 8e30d63b..ebc42665 100644 --- a/botcore/utils/scheduling.py +++ b/botcore/utils/scheduling.py @@ -39,9 +39,9 @@ class Scheduler: self.name = name self._log = logging.get_logger(f"{__name__}.{name}") - self._scheduled_tasks: dict[typing.Hashable, asyncio.Task] = {} + self._scheduled_tasks: dict[abc.Hashable, asyncio.Task] = {} - def __contains__(self, task_id: typing.Hashable) -> bool: + def __contains__(self, task_id: abc.Hashable) -> bool: """ Return :obj:`True` if a task with the given ``task_id`` is currently scheduled. @@ -53,7 +53,7 @@ class Scheduler: """ return task_id in self._scheduled_tasks - def schedule(self, task_id: typing.Hashable, coroutine: abc.Coroutine) -> None: + def schedule(self, task_id: abc.Hashable, coroutine: abc.Coroutine) -> None: """ Schedule the execution of a ``coroutine``. @@ -80,7 +80,7 @@ class Scheduler: self._scheduled_tasks[task_id] = task self._log.debug(f"Scheduled task #{task_id} {id(task)}.") - def schedule_at(self, time: datetime, task_id: typing.Hashable, coroutine: abc.Coroutine) -> None: + def schedule_at(self, time: datetime, task_id: abc.Hashable, coroutine: abc.Coroutine) -> None: """ Schedule ``coroutine`` to be executed at the given ``time``. @@ -107,7 +107,7 @@ class Scheduler: def schedule_later( self, delay: typing.Union[int, float], - task_id: typing.Hashable, + task_id: abc.Hashable, coroutine: abc.Coroutine ) -> None: """ @@ -123,7 +123,7 @@ class Scheduler: """ self.schedule(task_id, self._await_later(delay, task_id, coroutine)) - def cancel(self, task_id: typing.Hashable) -> None: + def cancel(self, task_id: abc.Hashable) -> None: """ Unschedule the task identified by ``task_id``. Log a warning if the task doesn't exist. @@ -151,7 +151,7 @@ class Scheduler: async def _await_later( self, delay: typing.Union[int, float], - task_id: typing.Hashable, + task_id: abc.Hashable, coroutine: abc.Coroutine ) -> None: """Await ``coroutine`` after ``delay`` seconds.""" @@ -174,7 +174,7 @@ class Scheduler: else: self._log.debug(f"Finally block reached for #{task_id}; {state=}") - def _task_done_callback(self, task_id: typing.Hashable, done_task: asyncio.Task) -> None: + def _task_done_callback(self, task_id: abc.Hashable, done_task: asyncio.Task) -> None: """ Delete the task and raise its exception if one exists. @@ -215,7 +215,7 @@ TASK_RETURN = typing.TypeVar("TASK_RETURN") def create_task( coro: abc.Coroutine[typing.Any, typing.Any, TASK_RETURN], *, - suppressed_exceptions: tuple[typing.Type[Exception]] = (), + suppressed_exceptions: tuple[type[Exception]] = (), event_loop: typing.Optional[asyncio.AbstractEventLoop] = None, **kwargs, ) -> asyncio.Task[TASK_RETURN]: -- cgit v1.2.3