Drop support for Python 3.4 and make minimum version 3.5.2.
This commit is contained in:
@ -48,7 +48,6 @@ import sys, re
|
||||
import signal
|
||||
from collections import namedtuple
|
||||
|
||||
PY35 = sys.version_info >= (3, 5)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
AppInfo = namedtuple('AppInfo', 'id name description icon owner')
|
||||
@ -139,12 +138,10 @@ class Client:
|
||||
|
||||
# internals
|
||||
|
||||
@asyncio.coroutine
|
||||
def _syncer(self, guilds):
|
||||
yield from self.ws.request_sync(guilds)
|
||||
async def _syncer(self, guilds):
|
||||
await self.ws.request_sync(guilds)
|
||||
|
||||
@asyncio.coroutine
|
||||
def _chunker(self, guild):
|
||||
async def _chunker(self, guild):
|
||||
try:
|
||||
guild_id = guild.id
|
||||
except AttributeError:
|
||||
@ -159,7 +156,7 @@ class Client:
|
||||
}
|
||||
}
|
||||
|
||||
yield from self.ws.send_as_json(payload)
|
||||
await self.ws.send_as_json(payload)
|
||||
|
||||
def handle_ready(self):
|
||||
self._ready.set()
|
||||
@ -218,15 +215,14 @@ class Client:
|
||||
""":obj:`bool`: Specifies if the client's internal cache is ready for use."""
|
||||
return self._ready.is_set()
|
||||
|
||||
@asyncio.coroutine
|
||||
def _run_event(self, coro, event_name, *args, **kwargs):
|
||||
async def _run_event(self, coro, event_name, *args, **kwargs):
|
||||
try:
|
||||
yield from coro(*args, **kwargs)
|
||||
await coro(*args, **kwargs)
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception:
|
||||
try:
|
||||
yield from self.on_error(event_name, *args, **kwargs)
|
||||
await self.on_error(event_name, *args, **kwargs)
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
@ -276,10 +272,9 @@ class Client:
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
compat.create_task(self._run_event(coro, method, *args, **kwargs), loop=self.loop)
|
||||
asyncio.ensure_future(self._run_event(coro, method, *args, **kwargs), loop=self.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_error(self, event_method, *args, **kwargs):
|
||||
async def on_error(self, event_method, *args, **kwargs):
|
||||
"""|coro|
|
||||
|
||||
The default error handler provided by the client.
|
||||
@ -291,8 +286,7 @@ class Client:
|
||||
print('Ignoring exception in {}'.format(event_method), file=sys.stderr)
|
||||
traceback.print_exc()
|
||||
|
||||
@asyncio.coroutine
|
||||
def request_offline_members(self, *guilds):
|
||||
async def request_offline_members(self, *guilds):
|
||||
"""|coro|
|
||||
|
||||
Requests previously offline members from the guild to be filled up
|
||||
@ -318,12 +312,11 @@ class Client:
|
||||
if any(not g.large or g.unavailable for g in guilds):
|
||||
raise InvalidArgument('An unavailable or non-large guild was passed.')
|
||||
|
||||
yield from self._connection.request_offline_members(guilds)
|
||||
await self._connection.request_offline_members(guilds)
|
||||
|
||||
# login state management
|
||||
|
||||
@asyncio.coroutine
|
||||
def login(self, token, *, bot=True):
|
||||
async def login(self, token, *, bot=True):
|
||||
"""|coro|
|
||||
|
||||
Logs in the client with the specified credentials.
|
||||
@ -350,34 +343,31 @@ class Client:
|
||||
"""
|
||||
|
||||
log.info('logging in using static token')
|
||||
yield from self.http.static_login(token, bot=bot)
|
||||
await self.http.static_login(token, bot=bot)
|
||||
self._connection.is_bot = bot
|
||||
|
||||
@asyncio.coroutine
|
||||
def logout(self):
|
||||
async def logout(self):
|
||||
"""|coro|
|
||||
|
||||
Logs out of Discord and closes all connections.
|
||||
"""
|
||||
yield from self.close()
|
||||
await self.close()
|
||||
|
||||
@asyncio.coroutine
|
||||
def _connect(self):
|
||||
async def _connect(self):
|
||||
coro = DiscordWebSocket.from_client(self, shard_id=self.shard_id)
|
||||
self.ws = yield from asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
self.ws = await asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
while True:
|
||||
try:
|
||||
yield from self.ws.poll_event()
|
||||
await self.ws.poll_event()
|
||||
except ResumeWebSocket as e:
|
||||
log.info('Got a request to RESUME the websocket.')
|
||||
coro = DiscordWebSocket.from_client(self, shard_id=self.shard_id,
|
||||
session=self.ws.session_id,
|
||||
sequence=self.ws.sequence,
|
||||
resume=True)
|
||||
self.ws = yield from asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
self.ws = await asyncio.wait_for(coro, timeout=180.0, loop=self.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def connect(self, *, reconnect=True):
|
||||
async def connect(self, *, reconnect=True):
|
||||
"""|coro|
|
||||
|
||||
Creates a websocket connection and lets the websocket listen
|
||||
@ -405,7 +395,7 @@ class Client:
|
||||
backoff = ExponentialBackoff()
|
||||
while not self.is_closed():
|
||||
try:
|
||||
yield from self._connect()
|
||||
await self._connect()
|
||||
except (OSError,
|
||||
HTTPException,
|
||||
GatewayNotFound,
|
||||
@ -416,7 +406,7 @@ class Client:
|
||||
websockets.WebSocketProtocolError) as e:
|
||||
|
||||
if not reconnect:
|
||||
yield from self.close()
|
||||
await self.close()
|
||||
if isinstance(e, ConnectionClosed) and e.code == 1000:
|
||||
# clean close, don't re-raise this
|
||||
return
|
||||
@ -431,15 +421,14 @@ class Client:
|
||||
# regardless and rely on is_closed instead
|
||||
if isinstance(e, ConnectionClosed):
|
||||
if e.code != 1000:
|
||||
yield from self.close()
|
||||
await self.close()
|
||||
raise
|
||||
|
||||
retry = backoff.delay()
|
||||
log.exception("Attempting a reconnect in %.2fs", retry)
|
||||
yield from asyncio.sleep(retry, loop=self.loop)
|
||||
await asyncio.sleep(retry, loop=self.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def close(self):
|
||||
async def close(self):
|
||||
"""|coro|
|
||||
|
||||
Closes the connection to discord.
|
||||
@ -451,16 +440,16 @@ class Client:
|
||||
|
||||
for voice in self.voice_clients:
|
||||
try:
|
||||
yield from voice.disconnect()
|
||||
await voice.disconnect()
|
||||
except:
|
||||
# if an error happens during disconnects, disregard it.
|
||||
pass
|
||||
|
||||
if self.ws is not None and self.ws.open:
|
||||
yield from self.ws.close()
|
||||
await self.ws.close()
|
||||
|
||||
|
||||
yield from self.http.close()
|
||||
await self.http.close()
|
||||
self._ready.clear()
|
||||
|
||||
def clear(self):
|
||||
@ -475,8 +464,7 @@ class Client:
|
||||
self._connection.clear()
|
||||
self.http.recreate()
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, *args, **kwargs):
|
||||
async def start(self, *args, **kwargs):
|
||||
"""|coro|
|
||||
|
||||
A shorthand coroutine for :meth:`login` + :meth:`connect`.
|
||||
@ -484,8 +472,8 @@ class Client:
|
||||
|
||||
bot = kwargs.pop('bot', True)
|
||||
reconnect = kwargs.pop('reconnect', True)
|
||||
yield from self.login(*args, bot=bot)
|
||||
yield from self.connect(reconnect=reconnect)
|
||||
await self.login(*args, bot=bot)
|
||||
await self.connect(reconnect=reconnect)
|
||||
|
||||
def _do_cleanup(self):
|
||||
log.info('Cleaning up event loop.')
|
||||
@ -493,7 +481,7 @@ class Client:
|
||||
if loop.is_closed():
|
||||
return # we're already cleaning up
|
||||
|
||||
task = compat.create_task(self.close(), loop=loop)
|
||||
task = asyncio.ensure_future(self.close(), loop=loop)
|
||||
|
||||
def _silence_gathered(fut):
|
||||
try:
|
||||
@ -558,7 +546,7 @@ class Client:
|
||||
loop.add_signal_handler(signal.SIGINT, self._do_cleanup)
|
||||
loop.add_signal_handler(signal.SIGTERM, self._do_cleanup)
|
||||
|
||||
task = compat.create_task(self.start(*args, **kwargs), loop=loop)
|
||||
task = asyncio.ensure_future(self.start(*args, **kwargs), loop=loop)
|
||||
|
||||
def stop_loop_on_finish(fut):
|
||||
loop.stop()
|
||||
@ -661,13 +649,12 @@ class Client:
|
||||
|
||||
# listeners/waiters
|
||||
|
||||
@asyncio.coroutine
|
||||
def wait_until_ready(self):
|
||||
async def wait_until_ready(self):
|
||||
"""|coro|
|
||||
|
||||
Waits until the client's internal cache is all ready.
|
||||
"""
|
||||
yield from self._ready.wait()
|
||||
await self._ready.wait()
|
||||
|
||||
def wait_for(self, event, *, check=None, timeout=None):
|
||||
"""|coro|
|
||||
@ -751,7 +738,7 @@ class Client:
|
||||
:ref:`event reference <discord-api-events>`.
|
||||
"""
|
||||
|
||||
future = compat.create_future(self.loop)
|
||||
future = self.loop.create_future()
|
||||
if check is None:
|
||||
def _check(*args):
|
||||
return True
|
||||
@ -782,8 +769,7 @@ class Client:
|
||||
Using the basic :meth:`event` decorator: ::
|
||||
|
||||
@client.event
|
||||
@asyncio.coroutine
|
||||
def on_ready():
|
||||
async def on_ready():
|
||||
print('Ready!')
|
||||
|
||||
Saving characters by using the :meth:`async_event` decorator: ::
|
||||
@ -808,8 +794,7 @@ class Client:
|
||||
|
||||
return self.event(coro)
|
||||
|
||||
@asyncio.coroutine
|
||||
def change_presence(self, *, activity=None, status=None, afk=False):
|
||||
async def change_presence(self, *, activity=None, status=None, afk=False):
|
||||
"""|coro|
|
||||
|
||||
Changes the client's presence.
|
||||
@ -851,7 +836,7 @@ class Client:
|
||||
status_enum = status
|
||||
status = str(status)
|
||||
|
||||
yield from self.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
await self.ws.change_presence(activity=activity, status=status, afk=afk)
|
||||
|
||||
for guild in self._connection.guilds:
|
||||
me = guild.me
|
||||
@ -863,8 +848,7 @@ class Client:
|
||||
|
||||
# Guild stuff
|
||||
|
||||
@asyncio.coroutine
|
||||
def create_guild(self, name, region=None, icon=None):
|
||||
async def create_guild(self, name, region=None, icon=None):
|
||||
"""|coro|
|
||||
|
||||
Creates a :class:`Guild`.
|
||||
@ -903,13 +887,12 @@ class Client:
|
||||
else:
|
||||
region = region.value
|
||||
|
||||
data = yield from self.http.create_guild(name, region, icon)
|
||||
data = await self.http.create_guild(name, region, icon)
|
||||
return Guild(data=data, state=self._connection)
|
||||
|
||||
# Invite management
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_invite(self, url):
|
||||
async def get_invite(self, url):
|
||||
"""|coro|
|
||||
|
||||
Gets an :class:`Invite` from a discord.gg URL or ID.
|
||||
@ -939,11 +922,10 @@ class Client:
|
||||
"""
|
||||
|
||||
invite_id = self._resolve_invite(url)
|
||||
data = yield from self.http.get_invite(invite_id)
|
||||
data = await self.http.get_invite(invite_id)
|
||||
return Invite.from_incomplete(state=self._connection, data=data)
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete_invite(self, invite):
|
||||
async def delete_invite(self, invite):
|
||||
"""|coro|
|
||||
|
||||
Revokes an :class:`Invite`, URL, or ID to an invite.
|
||||
@ -967,12 +949,11 @@ class Client:
|
||||
"""
|
||||
|
||||
invite_id = self._resolve_invite(invite)
|
||||
yield from self.http.delete_invite(invite_id)
|
||||
await self.http.delete_invite(invite_id)
|
||||
|
||||
# Miscellaneous stuff
|
||||
|
||||
@asyncio.coroutine
|
||||
def application_info(self):
|
||||
async def application_info(self):
|
||||
"""|coro|
|
||||
|
||||
Retrieve's the bot's application information.
|
||||
@ -987,13 +968,12 @@ class Client:
|
||||
HTTPException
|
||||
Retrieving the information failed somehow.
|
||||
"""
|
||||
data = yield from self.http.application_info()
|
||||
data = await self.http.application_info()
|
||||
return AppInfo(id=int(data['id']), name=data['name'],
|
||||
description=data['description'], icon=data['icon'],
|
||||
owner=User(state=self._connection, data=data['owner']))
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_user_info(self, user_id):
|
||||
async def get_user_info(self, user_id):
|
||||
"""|coro|
|
||||
|
||||
Retrieves a :class:`User` based on their ID. This can only
|
||||
@ -1018,11 +998,10 @@ class Client:
|
||||
HTTPException
|
||||
Fetching the user failed.
|
||||
"""
|
||||
data = yield from self.http.get_user_info(user_id)
|
||||
data = await self.http.get_user_info(user_id)
|
||||
return User(state=self._connection, data=data)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_user_profile(self, user_id):
|
||||
async def get_user_profile(self, user_id):
|
||||
"""|coro|
|
||||
|
||||
Gets an arbitrary user's profile. This can only be used by non-bot accounts.
|
||||
@ -1046,7 +1025,7 @@ class Client:
|
||||
"""
|
||||
|
||||
state = self._connection
|
||||
data = yield from self.http.get_user_profile(user_id)
|
||||
data = await self.http.get_user_profile(user_id)
|
||||
|
||||
def transform(d):
|
||||
return state._get_guild(int(d['id']))
|
||||
@ -1060,8 +1039,7 @@ class Client:
|
||||
user=User(data=user, state=state),
|
||||
connected_accounts=data['connected_accounts'])
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_webhook_info(self, webhook_id):
|
||||
async def get_webhook_info(self, webhook_id):
|
||||
"""|coro|
|
||||
|
||||
Retrieves a :class:`Webhook` with the specified ID.
|
||||
@ -1080,5 +1058,5 @@ class Client:
|
||||
:class:`Webhook`
|
||||
The webhook you requested.
|
||||
"""
|
||||
data = yield from self.http.get_webhook(webhook_id)
|
||||
data = await self.http.get_webhook(webhook_id)
|
||||
return Webhook.from_state(data, state=self._connection)
|
||||
|
Reference in New Issue
Block a user