From 25d58068030604f4bc455f5723c68a945a114c59 Mon Sep 17 00:00:00 2001 From: Nekokatt Date: Tue, 8 Sep 2020 15:19:32 +0100 Subject: [PATCH 1/3] Removed constants module mess. --- hikari/api/cache.py | 1 - hikari/api/voice.py | 1 - hikari/applications.py | 8 +- hikari/channels.py | 4 +- hikari/config.py | 10 ++- hikari/embeds.py | 1 - hikari/emojis.py | 8 +- hikari/events/base_events.py | 1 - hikari/events/channel_events.py | 3 + hikari/events/guild_events.py | 3 + hikari/events/message_events.py | 6 ++ hikari/events/reaction_events.py | 1 + hikari/events/typing_events.py | 1 + hikari/files.py | 2 - hikari/guilds.py | 14 ++-- hikari/impl/bot.py | 15 ++-- hikari/impl/buckets.py | 1 - hikari/impl/entity_factory.py | 5 +- hikari/impl/event_manager_base.py | 1 - hikari/impl/rest.py | 98 ++++++++++++------------ hikari/impl/shard.py | 41 ++++++---- hikari/impl/stateful_cache.py | 1 - hikari/impl/stateful_guild_chunker.py | 1 - hikari/impl/voice.py | 2 - hikari/invites.py | 6 +- hikari/messages.py | 7 +- hikari/traits.py | 1 - hikari/undefined.py | 2 - hikari/urls.py | 33 ++++++++ hikari/users.py | 6 +- hikari/utilities/constants.py | 87 --------------------- hikari/utilities/event_stream.py | 1 - hikari/utilities/routes.py | 1 - hikari/webhooks.py | 6 +- tests/hikari/__init__.py | 1 - tests/hikari/impl/skipped_test_shard.py | 19 +++-- tests/hikari/impl/test_entity_factory.py | 3 +- tests/hikari/impl/test_rest.py | 46 +++++------ tests/hikari/test_applications.py | 8 +- tests/hikari/test_config.py | 9 +-- tests/hikari/test_guilds.py | 18 ++--- tests/hikari/test_users.py | 10 +-- 42 files changed, 221 insertions(+), 272 deletions(-) create mode 100644 hikari/urls.py delete mode 100644 hikari/utilities/constants.py diff --git a/hikari/api/cache.py b/hikari/api/cache.py index b7d812d07a..efa6518388 100644 --- a/hikari/api/cache.py +++ b/hikari/api/cache.py @@ -39,7 +39,6 @@ from hikari import users from hikari import voices - _KeyT = typing.TypeVar("_KeyT", bound=typing.Hashable) _ValueT = typing.TypeVar("_ValueT") diff --git a/hikari/api/voice.py b/hikari/api/voice.py index 963310581a..e0c7b421b4 100644 --- a/hikari/api/voice.py +++ b/hikari/api/voice.py @@ -34,7 +34,6 @@ from hikari import guilds from hikari import snowflakes - _VoiceConnectionT = typing.TypeVar("_VoiceConnectionT", bound="VoiceConnection") diff --git a/hikari/applications.py b/hikari/applications.py index c24f28dcdf..432af76edf 100644 --- a/hikari/applications.py +++ b/hikari/applications.py @@ -42,8 +42,8 @@ from hikari import files from hikari import guilds from hikari import snowflakes +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import routes if typing.TYPE_CHECKING: @@ -360,7 +360,7 @@ def format_icon(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[ return None return routes.CDN_TEAM_ICON.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, team_id=self.id, hash=self.icon_hash, size=size, @@ -486,7 +486,7 @@ def format_icon(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[ return None return routes.CDN_APPLICATION_ICON.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, application_id=self.id, hash=self.icon_hash, size=size, @@ -531,7 +531,7 @@ def format_cover_image(self, *, ext: str = "png", size: int = 4096) -> typing.Op return None return routes.CDN_APPLICATION_COVER.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, application_id=self.id, hash=self.cover_image_hash, size=size, diff --git a/hikari/channels.py b/hikari/channels.py index a5ed62a47b..a3601ac6bc 100644 --- a/hikari/channels.py +++ b/hikari/channels.py @@ -50,9 +50,9 @@ from hikari import permissions from hikari import snowflakes from hikari import undefined +from hikari import urls from hikari import users from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import routes if typing.TYPE_CHECKING: @@ -488,7 +488,7 @@ def format_icon(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[ return None return routes.CDN_CHANNEL_ICON.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, channel_id=self.id, hash=self.icon_hash, size=size, diff --git a/hikari/config.py b/hikari/config.py index 0717f1b2b6..220e4e5839 100644 --- a/hikari/config.py +++ b/hikari/config.py @@ -36,9 +36,11 @@ import attr from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import data_binding +_BASICAUTH_TOKEN_PREFIX: typing.Final[str] = "Basic" # nosec +_PROXY_AUTHENTICATION_HEADER: typing.Final[str] = "Proxy-Authentication" + @attr_extensions.with_copy @attr.s(slots=True, kw_only=True, repr=False, weakref_slot=False) @@ -56,7 +58,7 @@ def header(self) -> str: """Generate the header value and return it.""" raw_token = f"{self.username}:{self.password}".encode("ascii") token_part = base64.b64encode(raw_token).decode("ascii") - return f"{constants.BASICAUTH_TOKEN_PREFIX} {token_part}" + return f"{_BASICAUTH_TOKEN_PREFIX} {token_part}" def __str__(self) -> str: return self.header @@ -101,11 +103,11 @@ def all_headers(self) -> typing.Optional[data_binding.Headers]: if self.headers is None: if self.auth is None: return None - return {constants.PROXY_AUTHENTICATION_HEADER: self.auth} + return {_PROXY_AUTHENTICATION_HEADER: self.auth} if self.auth is None: return self.headers - return {**self.headers, constants.PROXY_AUTHENTICATION_HEADER: self.auth} + return {**self.headers, _PROXY_AUTHENTICATION_HEADER: self.auth} @attr_extensions.with_copy diff --git a/hikari/embeds.py b/hikari/embeds.py index 64ed91a605..5f7437e04e 100644 --- a/hikari/embeds.py +++ b/hikari/embeds.py @@ -51,7 +51,6 @@ if typing.TYPE_CHECKING: import concurrent.futures - AsyncReaderT = typing.TypeVar("AsyncReaderT", bound=files.AsyncReader) diff --git a/hikari/emojis.py b/hikari/emojis.py index 09e72c2b9c..3fb9cad3cc 100644 --- a/hikari/emojis.py +++ b/hikari/emojis.py @@ -33,14 +33,16 @@ from hikari import files from hikari import snowflakes +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import routes if typing.TYPE_CHECKING: from hikari import traits from hikari import users +_TWEMOJI_PNG_BASE_URL: typing.Final[str] = "https://github.com/twitter/twemoji/raw/master/assets/72x72/" + @attr.s(eq=True, hash=True, init=True, kw_only=True, slots=True, weakref_slot=False) class Emoji(files.WebResource, abc.ABC): @@ -161,7 +163,7 @@ def url(self) -> str: ------- https://github.com/twitter/twemoji/raw/master/assets/72x72/1f004.png """ - return constants.TWEMOJI_PNG_BASE_URL + self.filename + return _TWEMOJI_PNG_BASE_URL + self.filename @property @typing.final @@ -269,7 +271,7 @@ def is_mentionable(self) -> bool: def url(self) -> str: ext = "gif" if self.is_animated else "png" - return routes.CDN_CUSTOM_EMOJI.compile(constants.CDN_URL, emoji_id=self.id, file_format=ext) + return routes.CDN_CUSTOM_EMOJI.compile(urls.CDN_URL, emoji_id=self.id, file_format=ext) @attr.s(eq=True, hash=True, init=True, kw_only=True, slots=True, weakref_slot=False) diff --git a/hikari/events/base_events.py b/hikari/events/base_events.py index 3dfdef9543..3258cb54f0 100644 --- a/hikari/events/base_events.py +++ b/hikari/events/base_events.py @@ -45,7 +45,6 @@ if typing.TYPE_CHECKING: import types - T = typing.TypeVar("T") REQUIRED_INTENTS_ATTR: typing.Final[str] = "___requiresintents___" NO_RECURSIVE_THROW_ATTR: typing.Final[str] = "___norecursivethrow___" diff --git a/hikari/events/channel_events.py b/hikari/events/channel_events.py index d7542e2bbb..361ded3c3e 100644 --- a/hikari/events/channel_events.py +++ b/hikari/events/channel_events.py @@ -536,6 +536,7 @@ class GuildPinsUpdateEvent(PinsUpdateEvent, GuildChannelEvent): # <>. last_pin_timestamp: typing.Optional[datetime.datetime] = attr.ib(repr=True) + # <>. @property @@ -585,6 +586,7 @@ class PrivatePinsUpdateEvent(PinsUpdateEvent, PrivateChannelEvent): # <>. last_pin_timestamp: typing.Optional[datetime.datetime] = attr.ib(repr=True) + # <>. @property @@ -732,6 +734,7 @@ class WebhookUpdateEvent(GuildChannelEvent): # <>. guild_id: snowflakes.Snowflake = attr.ib() + # <>. async def fetch_channel_webhooks(self) -> typing.Sequence[webhooks.Webhook]: diff --git a/hikari/events/guild_events.py b/hikari/events/guild_events.py index 7e700097f0..2cd6b3dfc4 100644 --- a/hikari/events/guild_events.py +++ b/hikari/events/guild_events.py @@ -341,6 +341,7 @@ class BanCreateEvent(BanEvent): # <>. user: users.User = attr.ib() + # <>. async def fetch_ban(self) -> guilds.GuildMemberBan: @@ -383,6 +384,7 @@ class BanDeleteEvent(BanEvent): # <>. user: users.User = attr.ib() + # <>. # Sure, I could allow delete_message_days here, but... is there any point? @@ -461,6 +463,7 @@ class IntegrationsUpdateEvent(GuildEvent): # <>. guild_id: snowflakes.Snowflake = attr.ib() + # <>. async def fetch_integrations(self) -> typing.Sequence[guilds.Integration]: diff --git a/hikari/events/message_events.py b/hikari/events/message_events.py index b51efe16d1..3cf205605d 100644 --- a/hikari/events/message_events.py +++ b/hikari/events/message_events.py @@ -292,6 +292,7 @@ class GuildMessageCreateEvent(GuildMessageEvent, MessageCreateEvent): # <>. message: messages.Message = attr.ib() + # <>. @property @@ -314,6 +315,7 @@ class PrivateMessageCreateEvent(PrivateMessageEvent, MessageCreateEvent): # <>. message: messages.Message = attr.ib() + # <>. @property @@ -335,6 +337,7 @@ class GuildMessageUpdateEvent(GuildMessageEvent, MessageUpdateEvent): # <>. message: messages.PartialMessage = attr.ib() + # <>. @property @@ -359,6 +362,7 @@ class PrivateMessageUpdateEvent(PrivateMessageEvent, MessageUpdateEvent): # <>. message: messages.PartialMessage = attr.ib() + # <>. @property @@ -380,6 +384,7 @@ class GuildMessageDeleteEvent(GuildMessageEvent, MessageDeleteEvent): # <>. message: messages.PartialMessage = attr.ib() + # <>. @property @@ -402,6 +407,7 @@ class PrivateMessageDeleteEvent(PrivateMessageEvent, MessageDeleteEvent): # <>. message: messages.PartialMessage = attr.ib() + # <>. @property diff --git a/hikari/events/reaction_events.py b/hikari/events/reaction_events.py index 57eae4a9f5..7a20ec01bd 100644 --- a/hikari/events/reaction_events.py +++ b/hikari/events/reaction_events.py @@ -222,6 +222,7 @@ class GuildReactionAddEvent(GuildReactionEvent, ReactionAddEvent): # <>. emoji: emojis.Emoji = attr.ib() + # <>. @property diff --git a/hikari/events/typing_events.py b/hikari/events/typing_events.py index cb5678fd45..e21b5feb94 100644 --- a/hikari/events/typing_events.py +++ b/hikari/events/typing_events.py @@ -224,6 +224,7 @@ class PrivateTypingEvent(TypingEvent): # <>. timestamp: datetime.datetime = attr.ib(repr=False) + # <>. @property diff --git a/hikari/files.py b/hikari/files.py index d46f5a5732..ba5cb13909 100644 --- a/hikari/files.py +++ b/hikari/files.py @@ -68,11 +68,9 @@ _MAGIC: typing.Final[int] = 50 * 1024 - ReaderImplT = typing.TypeVar("ReaderImplT", bound="AsyncReader") ReaderImplT_co = typing.TypeVar("ReaderImplT_co", bound="AsyncReader", covariant=True) - Pathish = typing.Union["os.PathLike[str]", str] """Type hint representing a literal file or path. diff --git a/hikari/guilds.py b/hikari/guilds.py index cc39950d60..913d915fb3 100644 --- a/hikari/guilds.py +++ b/hikari/guilds.py @@ -57,9 +57,9 @@ from hikari import files from hikari import snowflakes +from hikari import urls from hikari import users from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import flag from hikari.utilities import routes @@ -684,7 +684,7 @@ def format_icon(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> ext = "png" return routes.CDN_GUILD_ICON.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.icon_hash, size=size, @@ -745,7 +745,7 @@ def format_splash(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona return None return routes.CDN_GUILD_SPLASH.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.splash_hash, size=size, @@ -783,7 +783,7 @@ def format_discovery_splash(self, *, ext: str = "png", size: int = 4096) -> typi return None return routes.CDN_GUILD_DISCOVERY_SPLASH.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.discovery_splash_hash, size=size, @@ -981,7 +981,7 @@ def format_splash(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona return None return routes.CDN_GUILD_SPLASH.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.splash_hash, size=size, @@ -1019,7 +1019,7 @@ def format_discovery_splash(self, *, ext: str = "png", size: int = 4096) -> typi return None return routes.CDN_GUILD_DISCOVERY_SPLASH.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.discovery_splash_hash, size=size, @@ -1057,7 +1057,7 @@ def format_banner(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona return None return routes.CDN_GUILD_BANNER.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.banner_hash, size=size, diff --git a/hikari/impl/bot.py b/hikari/impl/bot.py index 7e275b879a..92a6530f7d 100644 --- a/hikari/impl/bot.py +++ b/hikari/impl/bot.py @@ -55,7 +55,6 @@ from hikari.impl import shard as shard_impl from hikari.impl import voice as voice_impl from hikari.utilities import aio -from hikari.utilities import constants from hikari.utilities import date from hikari.utilities import event_stream from hikari.utilities import ux @@ -173,11 +172,11 @@ class BotApp(traits.BotAware, event_dispatcher.EventDispatcher): proxy_settings : typing.Optional[config.ProxySettings] If specified, custom proxy settings to use with network-layer logic in your application to get through an HTTP-proxy. - rest_url : builtins.str - Defaults to the Discord REST API URL. Can be overridden if you are - attempting to point to an unofficial endpoint, or if you are attempting - to mock/stub the Discord API for any reason. Generally you do not want - to change this. + rest_url : typing.Optional[builtins.str] + Defaults to the Discord REST API URL if `builtins.None`. Can be + overridden if you are attempting to point to an unofficial endpoint, or + if you are attempting to mock/stub the Discord API for any reason. + Generally you do not want to change this. !!! note `force_color` will always take precedence over `allow_color`. @@ -225,7 +224,7 @@ def __init__( intents: intents_.Intents = intents_.Intents.ALL_UNPRIVILEGED, logs: typing.Union[None, LoggerLevelT, typing.Dict[str, typing.Any]] = "INFO", proxy_settings: typing.Optional[config.ProxySettings] = None, - rest_url: str = constants.REST_API_URL, + rest_url: typing.Optional[str] = None, ) -> None: # Beautification and logging ux.init_logging(logs, allow_color, force_color) @@ -291,8 +290,6 @@ def __init__( proxy_settings=self._proxy_settings, rest_url=rest_url, token=token, - token_type=constants.BOT_TOKEN_PREFIX, - version=6, ) # We populate these on startup instead, as we need to possibly make some diff --git a/hikari/impl/buckets.py b/hikari/impl/buckets.py index 98dc55047f..a4546b0957 100644 --- a/hikari/impl/buckets.py +++ b/hikari/impl/buckets.py @@ -222,7 +222,6 @@ if typing.TYPE_CHECKING: import types - UNKNOWN_HASH: typing.Final[str] = "UNKNOWN" """The hash used for an unknown bucket that has not yet been resolved.""" diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py index 5db41382fb..774c43c5ad 100644 --- a/hikari/impl/entity_factory.py +++ b/hikari/impl/entity_factory.py @@ -51,10 +51,11 @@ from hikari import webhooks as webhook_models from hikari.api import entity_factory from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import data_binding from hikari.utilities import date +_DEFAULT_MAX_PRESENCES: typing.Final[int] = 25000 + def _deserialize_seconds_timedelta(seconds: typing.Union[str, int]) -> datetime.timedelta: return datetime.timedelta(seconds=int(seconds)) @@ -1174,7 +1175,7 @@ def deserialize_rest_guild(self, payload: data_binding.JSONObject) -> guild_mode raw_max_presences = payload["max_presences"] if raw_max_presences is None: - max_presences = constants.DEFAULT_MAX_PRESENCES + max_presences = _DEFAULT_MAX_PRESENCES else: max_presences = int(raw_max_presences) diff --git a/hikari/impl/event_manager_base.py b/hikari/impl/event_manager_base.py index a63fb47bf4..910b37e1a4 100644 --- a/hikari/impl/event_manager_base.py +++ b/hikari/impl/event_manager_base.py @@ -44,7 +44,6 @@ if typing.TYPE_CHECKING: from hikari.api import shard as gateway_shard - _LOGGER: typing.Final[logging.Logger] = logging.getLogger("hikari") if typing.TYPE_CHECKING: diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py index b0c44de19e..973afae1b2 100644 --- a/hikari/impl/rest.py +++ b/hikari/impl/rest.py @@ -41,12 +41,15 @@ import logging import math import os +import platform import re +import sys import typing import aiohttp import attr +from hikari import _about as about from hikari import channels from hikari import config from hikari import embeds as embeds_ @@ -58,13 +61,13 @@ from hikari import snowflakes from hikari import traits from hikari import undefined +from hikari import urls from hikari import users from hikari.api import rest as rest_api from hikari.impl import buckets from hikari.impl import entity_factory as entity_factory_impl from hikari.impl import rate_limits from hikari.impl import special_endpoints -from hikari.utilities import constants from hikari.utilities import data_binding from hikari.utilities import date from hikari.utilities import net @@ -87,6 +90,27 @@ _LOGGER: typing.Final[logging.Logger] = logging.getLogger("hikari.rest") +_APPLICATION_JSON: typing.Final[str] = "application/json" +_APPLICATION_OCTET_STREAM: typing.Final[str] = "application/octet-stream" +_AUTHORIZATION_HEADER: typing.Final[str] = sys.intern("Authorization") +_BEARER_TOKEN_PREFIX: typing.Final[str] = "Bearer" # nosec +_BOT_TOKEN_PREFIX: typing.Final[str] = "Bot" # nosec +_DATE_HEADER: typing.Final[str] = sys.intern("Date") +_HTTP_USER_AGENT: typing.Final[str] = ( + f"DiscordBot ({about.__url__}, {about.__version__}) {about.__author__} " + f"AIOHTTP/{aiohttp.__version__} " + f"{platform.python_implementation()}/{platform.python_version()} {platform.system()} {platform.architecture()[0]}" +) +_MILLISECOND_PRECISION: typing.Final[str] = "millisecond" +_USER_AGENT_HEADER: typing.Final[str] = sys.intern("User-Agent") +_X_AUDIT_LOG_REASON_HEADER: typing.Final[str] = sys.intern("X-Audit-Log-Reason") +_X_RATELIMIT_BUCKET_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Bucket") +_X_RATELIMIT_LIMIT_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Limit") +_X_RATELIMIT_PRECISION_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Precision") +_X_RATELIMIT_REMAINING_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Remaining") +_X_RATELIMIT_RESET_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Reset") +_X_RATELIMIT_RESET_AFTER_HEADER: typing.Final[str] = sys.intern("X-RateLimit-Reset-After") + @typing.final class BasicLazyCachedTCPConnectorFactory(rest_api.ConnectorFactory): @@ -238,7 +262,7 @@ def is_debug_enabled(self) -> bool: def proxy_settings(self) -> config.ProxySettings: return self._proxy_settings - def acquire(self, token: str, token_type: str = constants.BEARER_TOKEN_PREFIX) -> rest_api.RESTClient: + def acquire(self, token: str, token_type: str = _BEARER_TOKEN_PREFIX) -> rest_api.RESTClient: loop = asyncio.get_running_loop() if self._event_loop is None: @@ -263,7 +287,6 @@ def acquire(self, token: str, token_type: str = constants.BEARER_TOKEN_PREFIX) - token=token, token_type=token_type, rest_url=self._url, - version=self._version, ) return rest_client @@ -328,20 +351,11 @@ class RESTClientImpl(rest_api.RESTClient): rest_url : builtins.str The HTTP API base URL. This can contain format-string specifiers to interpolate information such as API version in use. - version : builtins.int - The API version to use. Currently only supports `6` and `7`. - - !!! warning - The V7 API at the time of writing is considered to be experimental and - is undocumented. While currently almost identical in most places to the - V6 API, it should not be used unless you are sure you understand the - risk that it might break without warning. """ __slots__: typing.Sequence[str] = ( "buckets", "global_rate_limit", - "version", "_client_session", "_closed_event", "_connector_factory", @@ -361,9 +375,6 @@ class RESTClientImpl(rest_api.RESTClient): global_rate_limit: rate_limits.ManualRateLimiter """Global ratelimiter.""" - version: int - """API version in-use.""" - @attr.s(auto_exc=True, slots=True, repr=False, weakref_slot=False) class _RetryRequest(RuntimeError): ... @@ -379,14 +390,12 @@ def __init__( http_settings: config.HTTPSettings, proxy_settings: config.ProxySettings, token: typing.Optional[str], - token_type: typing.Optional[str], + token_type: typing.Optional[str] = None, rest_url: typing.Optional[str], - version: int, ) -> None: self.buckets = buckets.RESTBucketManager() # We've been told in DAPI that this is per token. self.global_rate_limit = rate_limits.ManualRateLimiter() - self.version = version self._client_session: typing.Optional[aiohttp.ClientSession] = None self._closed_event = asyncio.Event() @@ -402,16 +411,13 @@ def __init__( full_token = None else: if token_type is None: - token_type = constants.BOT_TOKEN_PREFIX + token_type = _BOT_TOKEN_PREFIX full_token = f"{token_type.title()} {token}" self._token: typing.Optional[str] = full_token - if rest_url is None: - rest_url = constants.REST_API_URL - - self._rest_url = rest_url.format(self) + self._rest_url = rest_url if rest_url is not None else urls.REST_API_URL @property def http_settings(self) -> config.HTTPSettings: @@ -490,13 +496,13 @@ async def _request( self.buckets.start() headers = data_binding.StringMapBuilder() - headers.setdefault(constants.USER_AGENT_HEADER, constants.HTTP_USER_AGENT) - headers.put(constants.X_RATELIMIT_PRECISION_HEADER, constants.MILLISECOND_PRECISION) + headers.setdefault(_USER_AGENT_HEADER, _HTTP_USER_AGENT) + headers.put(_X_RATELIMIT_PRECISION_HEADER, _MILLISECOND_PRECISION) if self._token is not None and not no_auth: - headers[constants.AUTHORIZATION_HEADER] = self._token + headers[_AUTHORIZATION_HEADER] = self._token - headers.put(constants.X_AUDIT_LOG_REASON_HEADER, reason) + headers.put(_X_AUDIT_LOG_REASON_HEADER, reason) while True: try: @@ -554,7 +560,7 @@ async def _request( # Handle the response. if 200 <= response.status < 300: - if response.content_type == constants.APPLICATION_JSON: + if response.content_type == _APPLICATION_JSON: # Only deserializing here stops Cloudflare shenanigans messing us around. return data_binding.load_json(await response.read()) @@ -569,7 +575,7 @@ async def _request( @typing.final def _stringify_http_message(self, headers: data_binding.Headers, body: typing.Any) -> str: string = "\n".join( - f" {name}: {value}" if name != constants.AUTHORIZATION_HEADER else f" {name}: **REDACTED TOKEN**" + f" {name}: {value}" if name != _AUTHORIZATION_HEADER else f" {name}: **REDACTED TOKEN**" for name, value in headers.items() ) @@ -591,13 +597,13 @@ async def _parse_ratelimits(self, compiled_route: routes.CompiledRoute, response # Handle rate limiting. resp_headers = response.headers - limit = int(resp_headers.get(constants.X_RATELIMIT_LIMIT_HEADER, "1")) - remaining = int(resp_headers.get(constants.X_RATELIMIT_REMAINING_HEADER, "1")) - bucket = resp_headers.get(constants.X_RATELIMIT_BUCKET_HEADER, "None") - reset_at = float(resp_headers.get(constants.X_RATELIMIT_RESET_HEADER, "0")) - reset_after = float(resp_headers.get(constants.X_RATELIMIT_RESET_AFTER_HEADER, "0")) + limit = int(resp_headers.get(_X_RATELIMIT_LIMIT_HEADER, "1")) + remaining = int(resp_headers.get(_X_RATELIMIT_REMAINING_HEADER, "1")) + bucket = resp_headers.get(_X_RATELIMIT_BUCKET_HEADER, "None") + reset_at = float(resp_headers.get(_X_RATELIMIT_RESET_HEADER, "0")) + reset_after = float(resp_headers.get(_X_RATELIMIT_RESET_AFTER_HEADER, "0")) reset_date = datetime.datetime.fromtimestamp(reset_at, tz=datetime.timezone.utc) - now_date = date.rfc7231_datetime_string_to_datetime(resp_headers[constants.DATE_HEADER]) + now_date = date.rfc7231_datetime_string_to_datetime(resp_headers[_DATE_HEADER]) is_rate_limited = response.status == http.HTTPStatus.TOO_MANY_REQUESTS @@ -613,7 +619,7 @@ async def _parse_ratelimits(self, compiled_route: routes.CompiledRoute, response if not is_rate_limited: return - if response.content_type != constants.APPLICATION_JSON: + if response.content_type != _APPLICATION_JSON: # We don't know exactly what this could imply. It is likely Cloudflare interfering # but I'd rather we just give up than do something resulting in multiple failed # requests repeatedly. @@ -700,15 +706,15 @@ def _generate_allowed_mentions( parsed_mentions.append("users") elif isinstance(user_mentions, typing.Collection): # Duplicates will cause discord to error. - snowflakes = {str(int(u)) for u in user_mentions} - allowed_mentions["users"] = list(snowflakes) + ids = {str(int(u)) for u in user_mentions} + allowed_mentions["users"] = list(ids) if role_mentions is True: parsed_mentions.append("roles") elif isinstance(role_mentions, typing.Collection): # Duplicates will cause discord to error. - snowflakes = {str(int(r)) for r in role_mentions} - allowed_mentions["roles"] = list(snowflakes) + ids = {str(int(r)) for r in role_mentions} + allowed_mentions["roles"] = list(ids) return allowed_mentions @@ -985,16 +991,14 @@ async def create_message( if final_attachments: form = data_binding.URLEncodedForm() - form.add_field("payload_json", data_binding.dump_json(body), content_type=constants.APPLICATION_JSON) + form.add_field("payload_json", data_binding.dump_json(body), content_type=_APPLICATION_JSON) stack = contextlib.AsyncExitStack() try: for i, attachment in enumerate(final_attachments): stream = await stack.enter_async_context(attachment.stream(executor=self._executor)) - form.add_field( - f"file{i}", stream, filename=stream.filename, content_type=constants.APPLICATION_OCTET_STREAM - ) + form.add_field(f"file{i}", stream, filename=stream.filename, content_type=_APPLICATION_OCTET_STREAM) raw_response = await self._request(route, form=form) finally: @@ -1380,16 +1384,14 @@ async def execute_webhook( if final_attachments: form = data_binding.URLEncodedForm() - form.add_field("payload_json", data_binding.dump_json(body), content_type=constants.APPLICATION_JSON) + form.add_field("payload_json", data_binding.dump_json(body), content_type=_APPLICATION_JSON) stack = contextlib.AsyncExitStack() try: for i, attachment in enumerate(final_attachments): stream = await stack.enter_async_context(attachment.stream(executor=self._executor)) - form.add_field( - f"file{i}", stream, filename=stream.filename, content_type=constants.APPLICATION_OCTET_STREAM - ) + form.add_field(f"file{i}", stream, filename=stream.filename, content_type=_APPLICATION_OCTET_STREAM) raw_response = await self._request(route, query=query, form=form, no_auth=True) finally: diff --git a/hikari/impl/shard.py b/hikari/impl/shard.py index 8aee252067..4264bba21e 100644 --- a/hikari/impl/shard.py +++ b/hikari/impl/shard.py @@ -30,12 +30,14 @@ import http import json import logging +import platform import typing import urllib.parse import zlib import aiohttp +from hikari import _about as about from hikari import errors from hikari import intents as intents_ from hikari import presences @@ -43,7 +45,6 @@ from hikari import undefined from hikari.api import shard from hikari.impl import rate_limits -from hikari.utilities import constants from hikari.utilities import data_binding from hikari.utilities import date @@ -87,6 +88,20 @@ # Rate-limit for chunking requests (used to prevent saturating the entire # ratelimit window). _CHUNKING_RATELIMIT: typing.Final[typing.Tuple[float, int]] = (60.0, 60) +# Supported gateway version +_VERSION: int = 6 + + +def _log_filterer(token: str) -> typing.Callable[[str], str]: + def filterer(entry: str) -> str: + return entry.replace(token, "**REDACTED TOKEN**") + + return filterer + + +if typing.TYPE_CHECKING: + # noinspection PyProtectedMember,PyUnresolvedReferences + _ZlibDecompressor = zlib._Decompress @typing.final @@ -100,13 +115,13 @@ class _V6GatewayTransport(aiohttp.ClientWebSocketResponse): Payload logging is also performed here. """ - __slots__: typing.Sequence[str] = ("_zlib", "_logger", "_debug", "_token") + __slots__: typing.Sequence[str] = ("_zlib", "_logger", "_debug", "_log_filterer") # Initialized from `connect' - _zlib: zlib._Decompress + _zlib: _ZlibDecompressor _logger: logging.Logger _debug: bool - _token: str + _log_filterer: typing.Callable[[str], str] def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: super().__init__(*args, **kwargs) @@ -191,7 +206,8 @@ def _log_debug_payload(self, payload: str, message: str, /) -> None: "%s payload with size %s\n %s", message, len(payload), - payload.replace(self._token, "**REDACTED TOKEN**"), + # False positive, MyPy expects a method. + self._log_filterer(payload), # type: ignore ) else: self._logger.debug("%s payload with size %s", message, len(payload)) @@ -205,7 +221,7 @@ async def connect( http_config: config.HTTPSettings, logger: logging.Logger, proxy_config: config.ProxySettings, - token: str, + log_filterer: typing.Callable[[str], str], url: str, ) -> typing.AsyncGenerator[_V6GatewayTransport, None]: """Generate a single-use websocket connection. @@ -251,7 +267,8 @@ async def connect( ws._debug = debug # We store this so we can remove it from debug logs # which enables people to send me logs in issues safely. - ws._token = token + # Also MyPy raises a false positive about this... + ws._log_filterer = log_filterer # type: ignore yield ws except errors.GatewayError: @@ -355,8 +372,6 @@ class GatewayShardImpl(shard.GatewayShard): url : builtins.str The gateway URL to use. This should not contain a query-string or fragments. - version : builtins.int - Gateway API version to use. !!! note If all four of `initial_activity`, `initial_idle_since`, @@ -646,9 +661,9 @@ async def _identify(self) -> None: "compress": False, "large_threshold": self._large_threshold, "properties": { - "$os": constants.SYSTEM_TYPE, - "$browser": constants.AIOHTTP_VERSION, - "$device": constants.LIBRARY_VERSION, + "$os": f"{platform.system()} {platform.architecture()[0]}", + "$browser": f"aiohttp {aiohttp.__version__}", + "$device": f"hikari {about.__version__}", }, "shard": [self._shard_id, self._shard_count], }, @@ -750,9 +765,9 @@ async def _run_once(self) -> bool: async with _V6GatewayTransport.connect( debug=self._debug, http_config=self._http_settings, + log_filterer=_log_filterer(self._token), logger=self._logger, proxy_config=self._proxy_settings, - token=self._token, url=self._url, ) as self._ws: # Dispatch CONNECTED synthetic event. diff --git a/hikari/impl/stateful_cache.py b/hikari/impl/stateful_cache.py index 6dc5fa1a00..451561e5b5 100644 --- a/hikari/impl/stateful_cache.py +++ b/hikari/impl/stateful_cache.py @@ -48,7 +48,6 @@ if typing.TYPE_CHECKING: from hikari import traits - _KeyT = typing.TypeVar("_KeyT", bound=typing.Hashable) _LOGGER: typing.Final[logging.Logger] = logging.getLogger("hikari.cache") _ValueT = typing.TypeVar("_ValueT") diff --git a/hikari/impl/stateful_guild_chunker.py b/hikari/impl/stateful_guild_chunker.py index 1f826192a0..07e829bfab 100644 --- a/hikari/impl/stateful_guild_chunker.py +++ b/hikari/impl/stateful_guild_chunker.py @@ -52,7 +52,6 @@ from hikari import users as users_ from hikari.api import shard as gateway_shard - EXPIRY_TIME: typing.Final[int] = 5000 """How long a chunk event should wait until it's considered expired in miliseconds.""" diff --git a/hikari/impl/voice.py b/hikari/impl/voice.py index fbb0f3e66c..a154104995 100644 --- a/hikari/impl/voice.py +++ b/hikari/impl/voice.py @@ -41,10 +41,8 @@ if typing.TYPE_CHECKING: _VoiceEventCallbackT = typing.Callable[[voice_events.VoiceEvent], typing.Coroutine[None, typing.Any, None]] - _LOGGER: typing.Final[logging.Logger] = logging.getLogger("hikari.voice.management") - _VoiceConnectionT = typing.TypeVar("_VoiceConnectionT", bound="voice.VoiceConnection") diff --git a/hikari/invites.py b/hikari/invites.py index a0c52d4d78..02744d7417 100644 --- a/hikari/invites.py +++ b/hikari/invites.py @@ -41,8 +41,8 @@ from hikari import files from hikari import guilds from hikari import snowflakes +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import routes if typing.TYPE_CHECKING: @@ -162,7 +162,7 @@ def format_splash(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona return None return routes.CDN_GUILD_SPLASH.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.splash_hash, size=size, @@ -200,7 +200,7 @@ def format_banner(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona return None return routes.CDN_GUILD_BANNER.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, guild_id=self.id, hash=self.banner_hash, size=size, diff --git a/hikari/messages.py b/hikari/messages.py index ca933805fd..ca067dccf9 100644 --- a/hikari/messages.py +++ b/hikari/messages.py @@ -43,8 +43,8 @@ from hikari import files from hikari import snowflakes from hikari import undefined +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import flag if typing.TYPE_CHECKING: @@ -361,9 +361,8 @@ def link(self) -> str: builtins.str The jump link to the message. """ - if self.guild_id is None: - return f"{constants.BASE_URL}/channels/@me/{self.channel_id}/{self.id}" - return f"{constants.BASE_URL}/channels/{self.guild_id}/{self.channel_id}/{self.id}" + guild_id_str = "@me" if self.guild_id is None else str(self.guild_id) + return f"{urls.BASE_URL}/channels/{guild_id_str}/{self.channel_id}/{self.id}" async def fetch_channel(self) -> channels.PartialChannel: """Fetch the channel this message was created in. diff --git a/hikari/traits.py b/hikari/traits.py index 1fb5e4d9a1..fe046517a4 100644 --- a/hikari/traits.py +++ b/hikari/traits.py @@ -58,7 +58,6 @@ from hikari.api import voice as voice_ from hikari.events import base_events # noqa F401 - Unused (False positive) - EventT_co = typing.TypeVar("EventT_co", bound="base_events.Event", covariant=True) """Type-hint for a covariant event implementation instance. diff --git a/hikari/undefined.py b/hikari/undefined.py index e6e608af94..1aba319d1e 100644 --- a/hikari/undefined.py +++ b/hikari/undefined.py @@ -92,14 +92,12 @@ class UndefinedType(_UndefinedSentinel, enum.Enum): setattr(_UndefinedSentinel, "__new__", lambda _: UNDEFINED) del _UndefinedSentinel - UNDEFINED: typing.Final[typing.Literal[UndefinedType.UNDEFINED_VALUE]] = UndefinedType.UNDEFINED_VALUE """Undefined sentinel value. This will behave as a false value in conditions. """ - T = typing.TypeVar("T", covariant=True) UndefinedOr = typing.Union[T, UndefinedType] """Type hint to mark a type as being semantically optional. diff --git a/hikari/urls.py b/hikari/urls.py new file mode 100644 index 0000000000..97df4318d5 --- /dev/null +++ b/hikari/urls.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# cython: language_level=3 +# Copyright (c) 2020 Nekokatt +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""API-wide URLs.""" + +from __future__ import annotations + +__all__: typing.Final[typing.List[str]] = ["BASE_URL", "REST_API_URL", "OAUTH2_API_URL", "CDN_URL"] + +import typing + +BASE_URL: typing.Final[str] = "https://discord.com" +REST_API_URL: typing.Final[str] = f"{BASE_URL}/api/v6" +OAUTH2_API_URL: typing.Final[str] = f"{REST_API_URL}/oauth2" +CDN_URL: typing.Final[str] = "https://cdn.discordapp.com" diff --git a/hikari/users.py b/hikari/users.py index c796b154ae..4d697d6468 100644 --- a/hikari/users.py +++ b/hikari/users.py @@ -34,8 +34,8 @@ from hikari import files from hikari import snowflakes from hikari import undefined +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import flag from hikari.utilities import routes @@ -285,7 +285,7 @@ def format_avatar(self, *, ext: typing.Optional[str] = None, size: int = 4096) - ext = "png" return routes.CDN_USER_AVATAR.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, user_id=self.id, hash=self.avatar_hash, size=size, @@ -296,7 +296,7 @@ def format_avatar(self, *, ext: typing.Optional[str] = None, size: int = 4096) - def default_avatar(self) -> files.URL: # noqa: D401 imperative mood check """Placeholder default avatar for the user if no avatar is set.""" return routes.CDN_DEFAULT_USER_AVATAR.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, discriminator=int(self.discriminator) % 5, file_format="png", ) diff --git a/hikari/utilities/constants.py b/hikari/utilities/constants.py deleted file mode 100644 index abb416eafe..0000000000 --- a/hikari/utilities/constants.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -# cython: language_level=3 -# Copyright (c) 2020 Nekokatt -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -"""Various strings used in multiple places.""" - -from __future__ import annotations - -import platform -import typing - -import aiohttp - -from hikari import _about - -# Headers. -ACCEPT_HEADER: typing.Final[str] = "Accept" -AUTHORIZATION_HEADER: typing.Final[str] = "Authorization" -CF_RAY_HEADER: typing.Final[str] = "CF-Ray" -CF_REQUEST_ID_HEADER: typing.Final[str] = "CF-Request-ID" -CONTENT_LENGTH_HEADER: typing.Final[str] = "Content-Length" -CONTENT_TYPE_HEADER: typing.Final[str] = "Content-Type" -DATE_HEADER: typing.Final[str] = "Date" -PROXY_AUTHENTICATION_HEADER: typing.Final[str] = "Proxy-Authentication" -USER_AGENT_HEADER: typing.Final[str] = "User-Agent" -X_AUDIT_LOG_REASON_HEADER: typing.Final[str] = "X-Audit-Log-Reason" -X_RATELIMIT_BUCKET_HEADER: typing.Final[str] = "X-RateLimit-Bucket" -X_RATELIMIT_LIMIT_HEADER: typing.Final[str] = "X-RateLimit-Limit" -X_RATELIMIT_PRECISION_HEADER: typing.Final[str] = "X-RateLimit-Precision" -X_RATELIMIT_REMAINING_HEADER: typing.Final[str] = "X-RateLimit-Remaining" -X_RATELIMIT_RESET_HEADER: typing.Final[str] = "X-RateLimit-Reset" -X_RATELIMIT_RESET_AFTER_HEADER: typing.Final[str] = "X-RateLimit-Reset-After" - -# Mimetypes. -APPLICATION_JSON: typing.Final[str] = "application/json" -APPLICATION_XML: typing.Final[str] = "application/xml" -APPLICATION_OCTET_STREAM: typing.Final[str] = "application/octet-stream" - -# Bits of text. -BASICAUTH_TOKEN_PREFIX: typing.Final[str] = "Basic" # nosec -BEARER_TOKEN_PREFIX: typing.Final[str] = "Bearer" # nosec -BOT_TOKEN_PREFIX: typing.Final[str] = "Bot" # nosec -MILLISECOND_PRECISION: typing.Final[str] = "millisecond" - -# User-agent info. -AIOHTTP_VERSION: typing.Final[str] = f"aiohttp {aiohttp.__version__}" -LIBRARY_VERSION: typing.Final[str] = f"hikari {_about.__version__}" -SYSTEM_TYPE: typing.Final[str] = f"{platform.system()} {platform.architecture()[0]}" -HTTP_USER_AGENT: typing.Final[str] = ( - f"DiscordBot ({_about.__url__}, {_about.__version__}) {_about.__author__} " - f"AIOHTTP/{aiohttp.__version__} " - f"{platform.python_implementation()}/{platform.python_version()} {SYSTEM_TYPE}" -) -PYTHON_PLATFORM_VERSION: typing.Final[str] = ( - f"{platform.python_implementation()} {platform.python_version()} " - f"{platform.python_branch()} {platform.python_compiler()}" -).replace(" " * 2, " ") - -# URLs -BASE_URL: typing.Final[str] = "https://discord.com" -REST_API_URL: typing.Final[str] = BASE_URL + "/api/v{0.version}" # noqa: FS003 fstring missing prefix -OAUTH2_API_URL: typing.Final[str] = f"{REST_API_URL}/oauth2" -CDN_URL: typing.Final[str] = "https://cdn.discordapp.com" -TWEMOJI_PNG_BASE_URL: typing.Final[str] = "https://github.com/twitter/twemoji/raw/master/assets/72x72/" -TWEMOJI_SVG_BASE_URL: typing.Final[str] = "https://github.com/twitter/twemoji/raw/master/assets/svg/" - -# Miscellaneous -DEFAULT_MAX_PRESENCES: typing.Final[int] = 25000 - -__all__: typing.Final[typing.List[str]] = [attr for attr in globals() if not any(c.islower() for c in attr)] diff --git a/hikari/utilities/event_stream.py b/hikari/utilities/event_stream.py index 2502039821..167fff9542 100644 --- a/hikari/utilities/event_stream.py +++ b/hikari/utilities/event_stream.py @@ -39,7 +39,6 @@ from hikari import traits from hikari.events import base_events # noqa F401 - Unused (False positive) - EventT = typing.TypeVar("EventT", bound="base_events.Event") _LOGGER: typing.Final[logging.Logger] = logging.getLogger("hikari") diff --git a/hikari/utilities/routes.py b/hikari/utilities/routes.py index 901c2f7707..0406839823 100644 --- a/hikari/utilities/routes.py +++ b/hikari/utilities/routes.py @@ -431,7 +431,6 @@ def compile_to_file( GET_GATEWAY: typing.Final[Route] = Route(GET, "/gateway") GET_GATEWAY_BOT: typing.Final[Route] = Route(GET, "/gateway/bot") - PNG: typing.Final[str] = "png".casefold() JPEG: typing.Final[str] = "jpeg".casefold() WEBP: typing.Final[str] = "webp".casefold() diff --git a/hikari/webhooks.py b/hikari/webhooks.py index 3451ec9cf8..9337b277be 100644 --- a/hikari/webhooks.py +++ b/hikari/webhooks.py @@ -33,8 +33,8 @@ from hikari import files as files_ from hikari import snowflakes from hikari import undefined +from hikari import urls from hikari.utilities import attr_extensions -from hikari.utilities import constants from hikari.utilities import routes if typing.TYPE_CHECKING: @@ -420,7 +420,7 @@ def default_avatar(self) -> files_.URL: This is used if no avatar is set. """ return routes.CDN_DEFAULT_USER_AVATAR.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, discriminator=0, file_format="png", ) @@ -457,7 +457,7 @@ def format_avatar(self, ext: str = "png", size: int = 4096) -> typing.Optional[f return None return routes.CDN_USER_AVATAR.compile_to_file( - constants.CDN_URL, + urls.CDN_URL, user_id=self.id, hash=self.avatar_hash, size=size, diff --git a/tests/hikari/__init__.py b/tests/hikari/__init__.py index edc91ff0f3..6f0b9377a8 100644 --- a/tests/hikari/__init__.py +++ b/tests/hikari/__init__.py @@ -34,7 +34,6 @@ def set_event_loop(self, loop) -> None: asyncio.set_event_loop_policy(TestingPolicy()) - _pytest_parametrize = pytest.mark.parametrize diff --git a/tests/hikari/impl/skipped_test_shard.py b/tests/hikari/impl/skipped_test_shard.py index e40baf4ee3..67d1a33d35 100644 --- a/tests/hikari/impl/skipped_test_shard.py +++ b/tests/hikari/impl/skipped_test_shard.py @@ -34,7 +34,6 @@ from hikari import snowflakes from hikari import undefined from hikari.impl import shard -from hikari.utilities import constants from hikari.utilities import date as hikari_date from tests.hikari import client_session_stub from tests.hikari import hikari_test_helpers @@ -955,9 +954,9 @@ async def test__handshake_when__session_id_is_None_and_no_intents(self, client): "compress": False, "large_threshold": 123, "properties": { - "$os": constants.SYSTEM_TYPE, - "$browser": constants.AIOHTTP_VERSION, - "$device": constants.LIBRARY_VERSION, + "$os": "constants.SYSTEM_TYPE", + "$browser": "constants.AIOHTTP_VERSION", + "$device": "constants.LIBRARY_VERSION", }, "shard": [0, 1], "presence": {"since": None, "afk": False, "status": presences.Status.ONLINE, "game": None}, @@ -984,9 +983,9 @@ async def test__handshake_when__session_id_is_None_and_intents(self, client): "compress": False, "large_threshold": 123, "properties": { - "$os": constants.SYSTEM_TYPE, - "$browser": constants.AIOHTTP_VERSION, - "$device": constants.LIBRARY_VERSION, + "$os": "constants.SYSTEM_TYPE", + "$browser": "constants.AIOHTTP_VERSION", + "$device": "constants.LIBRARY_VERSION", }, "shard": [0, 1], "intents": intents.Intents.ALL_UNPRIVILEGED, @@ -1034,9 +1033,9 @@ async def test__handshake_when__session_id_is_None_and_activity(self, client, id "compress": False, "large_threshold": 123, "properties": { - "$os": constants.SYSTEM_TYPE, - "$browser": constants.AIOHTTP_VERSION, - "$device": constants.LIBRARY_VERSION, + "$os": "constants.SYSTEM_TYPE", + "$browser": "constants.AIOHTTP_VERSION", + "$device": "constants.LIBRARY_VERSION", }, "shard": [0, 1], "presence": { diff --git a/tests/hikari/impl/test_entity_factory.py b/tests/hikari/impl/test_entity_factory.py index f42ce8cdd0..7964d4f9ca 100644 --- a/tests/hikari/impl/test_entity_factory.py +++ b/tests/hikari/impl/test_entity_factory.py @@ -43,7 +43,6 @@ from hikari import voices as voice_models from hikari import webhooks as webhook_models from hikari.impl import entity_factory -from hikari.utilities import constants def test__deserialize_seconds_timedelta(): @@ -1837,7 +1836,7 @@ def test_deserialize_rest_guild_with_null_fields(self, entity_factory_impl): assert guild.widget_channel_id is None assert guild.system_channel_id is None assert guild.rules_channel_id is None - assert guild.max_presences is constants.DEFAULT_MAX_PRESENCES + assert guild.max_presences is entity_factory._DEFAULT_MAX_PRESENCES assert guild.vanity_url_code is None assert guild.description is None assert guild.banner_hash is None diff --git a/tests/hikari/impl/test_rest.py b/tests/hikari/impl/test_rest.py index f651f4070a..25c9cf1e4e 100644 --- a/tests/hikari/impl/test_rest.py +++ b/tests/hikari/impl/test_rest.py @@ -43,7 +43,6 @@ from hikari.impl import entity_factory from hikari.impl import rest from hikari.impl import special_endpoints -from hikari.utilities import constants from hikari.utilities import net from hikari.utilities import routes from tests.hikari import client_session_stub @@ -181,7 +180,6 @@ def test_acquire(self, rest_app): token="token", token_type="Type", rest_url=rest_app._url, - version=rest_app._version, ) def test_acquire_when__event_loop_and_loop_do_not_equal(self, rest_app): @@ -237,8 +235,7 @@ def rest_client(rest_client_class): proxy_settings=mock.Mock(spec=config.ProxySettings), token="some_token", token_type="tYpe", - rest_url="https://some.where/api/v{0.version}", - version=3, + rest_url="https://some.where/api/v3", executor=mock.Mock(), entity_factory=mock.Mock(), ) @@ -305,7 +302,6 @@ def test__init__when_token_is_None_sets_token_to_None(self): token=None, token_type=None, rest_url=None, - version=1, executor=None, entity_factory=None, ) @@ -321,7 +317,6 @@ def test__init__when_token_is_not_None_and_token_type_is_None_generates_token_wi token="some_token", token_type=None, rest_url=None, - version=1, executor=None, entity_factory=None, ) @@ -337,7 +332,6 @@ def test__init__when_token_and_token_type_is_not_None_generates_token_with_type( token="some_token", token_type="tYpe", rest_url=None, - version=1, executor=None, entity_factory=None, ) @@ -353,11 +347,10 @@ def test__init__when_rest_url_is_None_generates_url_using_default_url(self): token=None, token_type=None, rest_url=None, - version=1, executor=None, entity_factory=None, ) - assert obj._rest_url == "https://discord.com/api/v1" + assert obj._rest_url == "https://discord.com/api/v6" def test__init__when_rest_url_is_not_None_generates_url_using_given_url(self): obj = rest.RESTClientImpl( @@ -368,8 +361,7 @@ def test__init__when_rest_url_is_not_None_generates_url_using_given_url(self): proxy_settings=mock.Mock(), token=None, token_type=None, - rest_url="https://some.where/api/v{0.version}", - version=2, + rest_url="https://some.where/api/v2", executor=None, entity_factory=None, ) @@ -759,7 +751,7 @@ async def test__request_when__token_is_None(self, rest_client, exit_exception): await rest_client._request(route) _, kwargs = mock_session.request.call_args_list[0] - assert constants.AUTHORIZATION_HEADER not in kwargs["headers"] + assert rest._AUTHORIZATION_HEADER not in kwargs["headers"] @hikari_test_helpers.timeout() async def test__request_when__token_is_not_None(self, rest_client, exit_exception): @@ -773,7 +765,7 @@ async def test__request_when__token_is_not_None(self, rest_client, exit_exceptio await rest_client._request(route) _, kwargs = mock_session.request.call_args_list[0] - assert kwargs["headers"][constants.AUTHORIZATION_HEADER] == "token" + assert kwargs["headers"][rest._AUTHORIZATION_HEADER] == "token" @hikari_test_helpers.timeout() async def test__request_when_no_auth_passed(self, rest_client, exit_exception): @@ -787,7 +779,7 @@ async def test__request_when_no_auth_passed(self, rest_client, exit_exception): await rest_client._request(route, no_auth=True) _, kwargs = mock_session.request.call_args_list[0] - assert constants.AUTHORIZATION_HEADER not in kwargs["headers"] + assert rest._AUTHORIZATION_HEADER not in kwargs["headers"] @hikari_test_helpers.timeout() async def test__request_when_response_is_NO_CONTENT(self, rest_client): @@ -808,7 +800,7 @@ class StubResponse: async def test__request_when_response_is_APPLICATION_JSON(self, rest_client): class StubResponse: status = http.HTTPStatus.OK - content_type = constants.APPLICATION_JSON + content_type = rest._APPLICATION_JSON reason = "cause why not" headers = {"HEADER": "value", "HEADER": "value"} @@ -887,7 +879,7 @@ async def test__handle_error_response(self, rest_client, exit_exception): async def test__parse_ratelimits_when_not_ratelimited(self, rest_client): class StubResponse: status = http.HTTPStatus.OK - headers = {constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} + headers = {rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} json = mock.AsyncMock() @@ -899,8 +891,8 @@ class StubResponse: async def test__parse_ratelimits_when_ratelimited(self, rest_client, exit_exception): class StubResponse: status = http.HTTPStatus.TOO_MANY_REQUESTS - content_type = constants.APPLICATION_JSON - headers = {constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} + content_type = rest._APPLICATION_JSON + headers = {rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} async def json(self): raise exit_exception @@ -913,7 +905,7 @@ async def test__parse_ratelimits_when_unexpected_content_type(self, rest_client) class StubResponse: status = http.HTTPStatus.TOO_MANY_REQUESTS content_type = "text/html" - headers = {constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} + headers = {rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} real_url = "https://some.url" async def read(self): @@ -926,8 +918,8 @@ async def read(self): async def test__parse_ratelimits_when_global_ratelimit(self, rest_client): class StubResponse: status = http.HTTPStatus.TOO_MANY_REQUESTS - content_type = constants.APPLICATION_JSON - headers = {constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} + content_type = rest._APPLICATION_JSON + headers = {rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT"} real_url = "https://some.url" async def json(self): @@ -942,10 +934,10 @@ async def json(self): async def test__parse_ratelimits_when_remaining_under_or_equal_to_0(self, rest_client): class StubResponse: status = http.HTTPStatus.TOO_MANY_REQUESTS - content_type = constants.APPLICATION_JSON + content_type = rest._APPLICATION_JSON headers = { - constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT", - constants.X_RATELIMIT_REMAINING_HEADER: "0", + rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT", + rest._X_RATELIMIT_REMAINING_HEADER: "0", } real_url = "https://some.url" @@ -959,10 +951,10 @@ async def json(self): async def test__parse_ratelimits_when_retry_after_is_close_enough(self, rest_client): class StubResponse: status = http.HTTPStatus.TOO_MANY_REQUESTS - content_type = constants.APPLICATION_JSON + content_type = rest._APPLICATION_JSON headers = { - constants.DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT", - constants.X_RATELIMIT_RESET_AFTER_HEADER: "0.002", + rest._DATE_HEADER: "Thu, 02 Jul 2020 20:55:08 GMT", + rest._X_RATELIMIT_RESET_AFTER_HEADER: "0.002", } real_url = "https://some.url" diff --git a/tests/hikari/test_applications.py b/tests/hikari/test_applications.py index cc93054a2e..10c42fab42 100644 --- a/tests/hikari/test_applications.py +++ b/tests/hikari/test_applications.py @@ -22,8 +22,8 @@ import pytest from hikari import applications +from hikari import urls from hikari import users -from hikari.utilities import constants from hikari.utilities import routes from tests.hikari import hikari_test_helpers @@ -91,7 +91,7 @@ def test_format_icon_when_hash_is_not_None(self, model): assert model.format_icon(ext="jpeg", size=1) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, team_id=123, hash="ahashicon", size=1, file_format="jpeg" + urls.CDN_URL, team_id=123, hash="ahashicon", size=1, file_format="jpeg" ) @@ -125,7 +125,7 @@ def test_format_icon_when_hash_is_not_None(self, model): assert model.format_icon(ext="jpeg", size=1) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, application_id=123, hash="ahashicon", size=1, file_format="jpeg" + urls.CDN_URL, application_id=123, hash="ahashicon", size=1, file_format="jpeg" ) def test_cover_image_url_property(self, model): @@ -152,5 +152,5 @@ def test_format_cover_image_when_hash_is_not_None(self, model): assert model.format_cover_image(ext="jpeg", size=1) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, application_id=123, hash="ahashcover", size=1, file_format="jpeg" + urls.CDN_URL, application_id=123, hash="ahashcover", size=1, file_format="jpeg" ) diff --git a/tests/hikari/test_config.py b/tests/hikari/test_config.py index 085d4a8fb4..050a934217 100644 --- a/tests/hikari/test_config.py +++ b/tests/hikari/test_config.py @@ -22,7 +22,6 @@ import pytest from hikari import config as config_ -from hikari.utilities import constants class TestBasicAuthHeader: @@ -31,10 +30,10 @@ def config(self): return config_.BasicAuthHeader(username="davfsa", password="securepassword123") def test_header_property(self, config): - assert config.header == f"{constants.BASICAUTH_TOKEN_PREFIX} ZGF2ZnNhOnNlY3VyZXBhc3N3b3JkMTIz" + assert config.header == f"{config_._BASICAUTH_TOKEN_PREFIX} ZGF2ZnNhOnNlY3VyZXBhc3N3b3JkMTIz" def test_str(self, config): - assert str(config) == f"{constants.BASICAUTH_TOKEN_PREFIX} ZGF2ZnNhOnNlY3VyZXBhc3N3b3JkMTIz" + assert str(config) == f"{config_._BASICAUTH_TOKEN_PREFIX} ZGF2ZnNhOnNlY3VyZXBhc3N3b3JkMTIz" class TestProxySettings: @@ -44,7 +43,7 @@ def test_all_headers_when_headers_and_auth_are_None(self): def test_all_headers_when_headers_is_None_and_auth_is_not_None(self): config = config_.ProxySettings(headers=None, auth="some auth") - assert config.all_headers == {constants.PROXY_AUTHENTICATION_HEADER: "some auth"} + assert config.all_headers == {config_._PROXY_AUTHENTICATION_HEADER: "some auth"} def test_all_headers_when_headers_is_not_None_and_auth_is_None(self): config = config_.ProxySettings(headers={"header1": "header1 info"}, auth=None) @@ -52,4 +51,4 @@ def test_all_headers_when_headers_is_not_None_and_auth_is_None(self): def test_all_headers_when_headers_and_auth_are_not_None(self): config = config_.ProxySettings(headers={"header1": "header1 info"}, auth="some auth") - assert config.all_headers == {"header1": "header1 info", constants.PROXY_AUTHENTICATION_HEADER: "some auth"} + assert config.all_headers == {"header1": "header1 info", config_._PROXY_AUTHENTICATION_HEADER: "some auth"} diff --git a/tests/hikari/test_guilds.py b/tests/hikari/test_guilds.py index c1d46c713c..d0118afc02 100644 --- a/tests/hikari/test_guilds.py +++ b/tests/hikari/test_guilds.py @@ -22,8 +22,8 @@ import pytest from hikari import guilds +from hikari import urls from hikari import users -from hikari.utilities import constants from hikari.utilities import routes from tests.hikari import hikari_test_helpers @@ -201,7 +201,7 @@ def test_format_icon_when_format_is_None_and_avatar_hash_is_for_gif(self, obj): assert obj.format_icon(ext=None, size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=1234567890, hash="a_18dnf8dfbakfdh", size=2, @@ -217,7 +217,7 @@ def test_format_icon_when_format_is_None_and_avatar_hash_is_not_for_gif(self, ob assert obj.format_icon(ext=None, size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=1234567890, hash="18dnf8dfbakfdh", size=2, @@ -233,7 +233,7 @@ def test_format_icon_with_all_args(self, obj): assert obj.format_icon(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=1234567890, hash="18dnf8dfbakfdh", size=2, @@ -261,7 +261,7 @@ def test_format_splash_when_hash(self, obj): assert obj.format_splash(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=123, hash="18dnf8dfbakfdh", size=2, @@ -286,7 +286,7 @@ def test_format_discovery_splash_when_hash(self, obj): assert obj.format_discovery_splash(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=123, hash="18dnf8dfbakfdh", size=2, @@ -325,7 +325,7 @@ def test_format_splash_when_hash(self, obj): assert obj.format_splash(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=123, hash="18dnf8dfbakfdh", size=2, @@ -350,7 +350,7 @@ def test_format_discovery_splash_when_hash(self, obj): assert obj.format_discovery_splash(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=123, hash="18dnf8dfbakfdh", size=2, @@ -375,7 +375,7 @@ def test_format_banner_when_hash(self, obj): assert obj.format_banner(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, guild_id=123, hash="18dnf8dfbakfdh", size=2, diff --git a/tests/hikari/test_users.py b/tests/hikari/test_users.py index 91a2f7e5c7..ea2855836c 100644 --- a/tests/hikari/test_users.py +++ b/tests/hikari/test_users.py @@ -22,8 +22,8 @@ import pytest from hikari import undefined +from hikari import urls from hikari import users -from hikari.utilities import constants from hikari.utilities import routes from tests.hikari import hikari_test_helpers @@ -82,7 +82,7 @@ def test_format_avatar_when_format_is_None_and_avatar_hash_is_for_gif(self, obj) assert obj.format_avatar(ext=None, size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, user_id=123, hash="a_18dnf8dfbakfdh", size=2, @@ -98,7 +98,7 @@ def test_format_avatar_when_format_is_None_and_avatar_hash_is_not_for_gif(self, assert obj.format_avatar(ext=None, size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, user_id=123, hash="18dnf8dfbakfdh", size=2, @@ -114,7 +114,7 @@ def test_format_avatar_with_all_args(self, obj): assert obj.format_avatar(ext="url", size=2) == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, user_id=123, hash="18dnf8dfbakfdh", size=2, @@ -130,7 +130,7 @@ def test_default_avatar(self, obj): assert obj.default_avatar == "file" route.compile_to_file.assert_called_once_with( - constants.CDN_URL, + urls.CDN_URL, discriminator=1, file_format="png", ) From eeee4b3446a2933ad77dba11652066c17f156fd7 Mon Sep 17 00:00:00 2001 From: Nekokatt Date: Tue, 8 Sep 2020 15:30:11 +0100 Subject: [PATCH 2/3] Interned payload flags on shard. --- hikari/impl/shard.py | 47 ++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/hikari/impl/shard.py b/hikari/impl/shard.py index 4264bba21e..733ab1e904 100644 --- a/hikari/impl/shard.py +++ b/hikari/impl/shard.py @@ -31,6 +31,7 @@ import json import logging import platform +import sys import typing import urllib.parse import zlib @@ -59,6 +60,12 @@ from hikari import guilds from hikari import users as users_ +# Important attributes +_D: typing.Final[str] = sys.intern("d") +_T: typing.Final[str] = sys.intern("t") +_S: typing.Final[str] = sys.intern("s") +_OP: typing.Final[str] = sys.intern("op") + # Opcodes. _DISPATCH: typing.Final[int] = 0 _HEARTBEAT: typing.Final[int] = 1 @@ -570,7 +577,7 @@ async def request_guild_members( payload.put_snowflake_array("user_ids", users) payload.put("nonce", nonce) - await self._ws.send_json({"op": _REQUEST_GUILD_MEMBERS, "d": payload}) # type: ignore[union-attr] + await self._ws.send_json({_OP: _REQUEST_GUILD_MEMBERS, _D: payload}) # type: ignore[union-attr] async def start(self) -> None: if self._run_task is not None: @@ -604,7 +611,7 @@ async def update_presence( activity=activity, status=status, ) - payload: data_binding.JSONObject = {"op": _PRESENCE_UPDATE, "d": presence_payload} + payload: data_binding.JSONObject = {_OP: _PRESENCE_UPDATE, _D: presence_payload} await self._ws.send_json(payload) # type: ignore[union-attr] async def update_voice_state( @@ -617,8 +624,8 @@ async def update_voice_state( ) -> None: await self._ws.send_json( # type: ignore[union-attr] { - "op": _VOICE_STATE_UPDATE, - "d": { + _OP: _VOICE_STATE_UPDATE, + _D: { "guild_id": str(int(guild)), "channel_id": str(int(channel)) if channel is not None else None, "mute": self_mute, @@ -655,8 +662,8 @@ def _dispatch(self, name: str, seq: int, data: data_binding.JSONObject) -> None: async def _identify(self) -> None: payload: data_binding.JSONObject = { - "op": _IDENTIFY, - "d": { + _OP: _IDENTIFY, + _D: { "token": self._token, "compress": False, "large_threshold": self._large_threshold, @@ -670,9 +677,9 @@ async def _identify(self) -> None: } if self._intents is not None: - payload["d"]["intents"] = self._intents + payload[_D]["intents"] = self._intents - payload["d"]["presence"] = self._serialize_and_store_presence_payload() + payload[_D]["presence"] = self._serialize_and_store_presence_payload() await self._ws.send_json(payload) # type: ignore[union-attr] @@ -703,8 +710,8 @@ async def _heartbeat(self, heartbeat_interval: float) -> bool: async def _resume(self) -> None: await self._ws.send_json( # type: ignore[union-attr] { - "op": _RESUME, - "d": {"token": self._token, "seq": self._seq, "session_id": self._session_id}, + _OP: _RESUME, + _D: {"token": self._token, "seq": self._seq, "session_id": self._session_id}, } ) @@ -776,11 +783,11 @@ async def _run_once(self) -> bool: # Expect HELLO. payload = await self._ws.receive_json() - if payload["op"] != _HELLO: + if payload[_OP] != _HELLO: await self._ws.close(code=errors.ShardCloseCode.PROTOCOL_ERROR, message=b"Expected HELLO op") - raise errors.GatewayError(f"Expected opcode {_HELLO}, but received {payload['op']}") + raise errors.GatewayError(f"Expected opcode {_HELLO}, but received {payload[_OP]}") - heartbeat_latency = float(payload["d"]["heartbeat_interval"]) / 1_000.0 + heartbeat_latency = float(payload[_D]["heartbeat_interval"]) / 1_000.0 heartbeat_task = asyncio.create_task(self._heartbeat(heartbeat_latency)) if self._closing.is_set(): @@ -799,12 +806,14 @@ async def _run_once(self) -> bool: # Event polling. while not self._closing.is_set() and not heartbeat_task.done() and not heartbeat_task.cancelled(): payload = await self._ws.receive_json() - op = payload["op"] - d = payload["d"] + op = payload[_OP] # opcode int + d = payload[_D] # data/payload. Usually a dict or a bool for INVALID_SESSION if op == _DISPATCH: - self._logger.debug("dispatching %s", payload["t"]) - self._dispatch(payload["t"], payload["s"], d) + t = payload[_T] # event name str + s = payload[_S] # seq int + self._logger.debug("dispatching %s with seq %s", t, s) + self._dispatch(t, s, d) elif op == _HEARTBEAT: await self._send_heartbeat_ack() self._logger.debug("sent HEARTBEAT") @@ -852,11 +861,11 @@ async def _run_once(self) -> bool: self._event_consumer(self, "DISCONNECTED", {}) async def _send_heartbeat(self) -> None: - await self._ws.send_json({"op": _HEARTBEAT, "d": self._seq}) # type: ignore[union-attr] + await self._ws.send_json({_OP: _HEARTBEAT, _D: self._seq}) # type: ignore[union-attr] self._last_heartbeat_sent = date.monotonic() async def _send_heartbeat_ack(self) -> None: - await self._ws.send_json({"op": _HEARTBEAT_ACK, "d": None}) # type: ignore[union-attr] + await self._ws.send_json({_OP: _HEARTBEAT_ACK, _D: None}) # type: ignore[union-attr] @staticmethod def _serialize_activity(activity: typing.Optional[presences.Activity]) -> data_binding.JSONish: From c907544cfe4cae4a57f78cc9d20d7f6ff0834454 Mon Sep 17 00:00:00 2001 From: Nekokatt Date: Tue, 8 Sep 2020 15:32:53 +0100 Subject: [PATCH 3/3] Fixed unused version in shard. --- hikari/impl/shard.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hikari/impl/shard.py b/hikari/impl/shard.py index 733ab1e904..46bbb616e4 100644 --- a/hikari/impl/shard.py +++ b/hikari/impl/shard.py @@ -442,13 +442,12 @@ def __init__( shard_count: int = 1, token: str, url: str, - version: int = 6, ) -> None: if data_format != shard.GatewayDataFormat.JSON: raise NotImplementedError(f"Unsupported gateway data format: {data_format}") - query = {"v": version, "encoding": data_format} + query = {"v": _VERSION, "encoding": data_format} if compression is not None: if compression == shard.GatewayCompression.PAYLOAD_ZLIB_STREAM: