Browse Source

Add enumerators instead of strings.

Changes channel type, status and server region into 3.4 enums.
pull/57/head
Rapptz 9 years ago
parent
commit
79bdf2a721
  1. 89
      discord/channel.py
  2. 13
      discord/client.py
  3. 54
      discord/enums.py
  4. 57
      discord/member.py
  5. 60
      discord/server.py
  6. 5
      discord/state.py
  7. 61
      docs/api.rst

89
discord/channel.py

@ -26,44 +26,37 @@ DEALINGS IN THE SOFTWARE.
from copy import deepcopy from copy import deepcopy
from . import utils from . import utils
from .permissions import Permissions from .permissions import Permissions
from .enums import ChannelType
from collections import namedtuple from collections import namedtuple
Overwrites = namedtuple('Overwrites', 'id allow deny type') Overwrites = namedtuple('Overwrites', 'id allow deny type')
class Channel(object): class Channel:
"""Represents a Discord server channel. """Represents a Discord server channel.
Instance attributes: Attributes
-----------
.. attribute:: name name : str
The channel name. The channel name.
.. attribute:: server server : :class:`Server`
The server the channel belongs to.
The :class:`Server` the channel belongs to. id : str
.. attribute:: id
The channel ID. The channel ID.
.. attribute:: topic topic : Optional[str]
The channel's topic. None if it doesn't exist. The channel's topic. None if it doesn't exist.
.. attribute:: is_private is_private : bool
``True`` if the channel is a private channel (i.e. PM). ``False`` in this case. ``True`` if the channel is a private channel (i.e. PM). ``False`` in this case.
.. attribute:: position position : int
The position in the channel list. The position in the channel list.
.. attribute:: type type : :class:`ChannelType`
The channel type. There is a chance that the type will be ``str`` if
The channel type. Usually ``'voice'`` or ``'text'``. the channel type is not within the ones recognised by the enumerator.
.. attribute:: changed_roles changed_roles
A list of :class:`Roles` that have been overridden from their default A list of :class:`Roles` that have been overridden from their default
values in the :attr:`Server.roles` attribute. values in the :attr:`Server.roles` attribute.
.. attribute:: voice_members voice_members
A list of :class:`Members` that are currently inside this voice channel. A list of :class:`Members` that are currently inside this voice channel.
If :attr:`type` is not ``'voice'`` then this is always an empty array. If :attr:`type` is not :attr:`ChannelType.voice` then this is always an empty array.
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -78,6 +71,11 @@ class Channel(object):
self.is_private = False self.is_private = False
self.position = kwargs.get('position') self.position = kwargs.get('position')
self.type = kwargs.get('type') self.type = kwargs.get('type')
try:
self.type = ChannelType(self.type)
except:
pass
self.changed_roles = [] self.changed_roles = []
self._permission_overwrites = [] self._permission_overwrites = []
for overridden in kwargs.get('permission_overwrites', []): for overridden in kwargs.get('permission_overwrites', []):
@ -98,11 +96,11 @@ class Channel(object):
self.changed_roles.append(override) self.changed_roles.append(override)
def is_default_channel(self): def is_default_channel(self):
"""Checks if this is the default channel for the :class:`Server` it belongs to.""" """bool : Indicates if this is the default channel for the :class:`Server` it belongs to."""
return self.server.id == self.id return self.server.id == self.id
def mention(self): def mention(self):
"""Returns a string that allows you to mention the channel.""" """str : The string that allows you to mention the channel."""
return '<#{0.id}>'.format(self) return '<#{0.id}>'.format(self)
def permissions_for(self, member): def permissions_for(self, member):
@ -116,8 +114,15 @@ class Channel(object):
- Member overrides - Member overrides
- Whether the channel is the default channel. - Whether the channel is the default channel.
:param member: The :class:`Member` to resolve permissions for. Parameters
:return: The resolved :class:`Permissions` for the :class:`Member`. ----------
member : :class:`Member`
The member to resolve permissions for.
Returns
-------
:class:`Permissions`
The resolved permissions for the member.
""" """
# The current cases can be explained as: # The current cases can be explained as:
@ -173,19 +178,16 @@ class Channel(object):
return base return base
class PrivateChannel(object): class PrivateChannel:
"""Represents a Discord private channel. """Represents a Discord private channel.
Instance attributes: Attributes
----------
.. attribute:: user user : :class:`User`
The user you are participating with in the private channel.
The :class:`User` in the private channel. id : str
.. attribute:: id
The private channel ID. The private channel ID.
.. attribute:: is_private is_private : bool
``True`` if the channel is a private channel (i.e. PM). ``True`` in this case. ``True`` if the channel is a private channel (i.e. PM). ``True`` in this case.
""" """
@ -207,8 +209,15 @@ class PrivateChannel(object):
- can_manage_messages: You cannot delete others messages in a PM. - can_manage_messages: You cannot delete others messages in a PM.
- can_mention_everyone: There is no one to mention in a PM. - can_mention_everyone: There is no one to mention in a PM.
:param user: The :class:`User` to check permissions for. Parameters
:return: A :class:`Permission` with the resolved permission value. -----------
user : :class:`User`
The user to check permissions for.
Returns
--------
:class:`Permission`
The resolved permissions for the user.
""" """
base = Permissions.TEXT base = Permissions.TEXT

13
discord/client.py

@ -34,6 +34,7 @@ from .object import Object
from .errors import * from .errors import *
from .state import ConnectionState from .state import ConnectionState
from . import utils from . import utils
from .enums import ChannelType, ServerRegion
import asyncio import asyncio
import aiohttp import aiohttp
@ -1085,7 +1086,7 @@ class Client:
log.debug(request_success_log.format(response=r, json=payload, data=data)) log.debug(request_success_log.format(response=r, json=payload, data=data))
@asyncio.coroutine @asyncio.coroutine
def create_channel(self, server, name, type='text'): def create_channel(self, server, name, type=None):
"""|coro| """|coro|
Creates a :class:`Channel` in the specified :class:`Server`. Creates a :class:`Channel` in the specified :class:`Server`.
@ -1098,8 +1099,8 @@ class Client:
The server to create the channel in. The server to create the channel in.
name : str name : str
The channel's name. The channel's name.
type : str type : :class:`ChannelType`
The type of channel to create. 'text' or 'voice'. The type of channel to create. Defaults to :attr:`ChannelType.text`.
Raises Raises
------- -------
@ -1117,9 +1118,12 @@ class Client:
different than the one that will be added in cache. different than the one that will be added in cache.
""" """
if type is None:
type = ChannelType.text
payload = { payload = {
'name': name, 'name': name,
'type': type 'type': str(type)
} }
url = '{0}/{1.id}/channels'.format(endpoints.SERVERS, server) url = '{0}/{1.id}/channels'.format(endpoints.SERVERS, server)
@ -1160,4 +1164,3 @@ class Client:
response = yield from self.session.delete(url, headers=self.headers) response = yield from self.session.delete(url, headers=self.headers)
log.debug(request_logging_format.format(method='DELETE', response=response)) log.debug(request_logging_format.format(method='DELETE', response=response))
yield from utils._verify_successful_response(response) yield from utils._verify_successful_response(response)

54
discord/enums.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
"""
The MIT License (MIT)
Copyright (c) 2015 Rapptz
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.
"""
from enum import Enum
class ChannelType(Enum):
text = 'text'
voice = 'voice'
def __str__(self):
return self.value
class ServerRegion(Enum):
us_west = 'us-west'
us_east = 'us-east'
singapore = 'singapore'
london = 'london'
sydney = 'sydney'
amsterdam = 'amsterdam'
frankfurt = 'frankfurt'
def __str__(self):
return self.value
class Status(Enum):
online = 'online'
offline = 'offline'
idle = 'idle'
def __str__(self):
return self.value

57
discord/member.py

@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE.
from .user import User from .user import User
from .utils import parse_time from .utils import parse_time
from .enums import Status
class Member(User): class Member(User):
"""Represents a Discord member to a :class:`Server`. """Represents a Discord member to a :class:`Server`.
@ -33,44 +34,34 @@ class Member(User):
This is a subclass of :class:`User` that extends more functionality This is a subclass of :class:`User` that extends more functionality
that server members have such as roles and permissions. that server members have such as roles and permissions.
Instance attributes: Attributes
----------
.. attribute:: deaf deaf : bool
Indicates if the member is currently deafened by the server.
A boolean that specifies if the member is currently deafened by the server. mute : bool
.. attribute:: mute Indicates if the member is currently muted by the server.
self_mute : bool
A boolean that specifies if the member is currently muted by the server. Indicates if the member is currently muted by their own accord.
.. attribute:: self_mute self_deaf : bool
Indicates if the member is currently deafened by their own accord.
A boolean that specifies if the member is currently muted by their own accord. is_afk : bool
.. attribute:: self_deaf Indicates if the member is currently in the AFK channel in the server.
voice_channel : :class:`Channel`
A boolean that specifies if the member is currently deafened by their own accord. The voice channel that the member is currently connected to. None if the member
.. attribute:: is_afk
A boolean that specifies if the member is currently in the AFK channel in the server.
.. attribute:: voice_channel
A voice :class:`Channel` that the member is currently connected to. None if the member
is not currently in a voice channel. is not currently in a voice channel.
.. attribute:: roles roles
A list of :class:`Role` that the member belongs to. Note that the first element of this A list of :class:`Role` that the member belongs to. Note that the first element of this
list is always the default '@everyone' role. list is always the default '@everyone' role.
.. attribute:: joined_at joined_at : `datetime.datetime`
A datetime object that specifies the date and time in UTC that the member joined the server for A datetime object that specifies the date and time in UTC that the member joined the server for
the first time. the first time.
.. attribute:: status status : :class:`Status`
The member's status. There is a chance that the status will be a ``str``
A string that denotes the user's status. Can be 'online', 'offline' or 'idle'. if it is a value that is not recognised by the enumerator.
.. attribute:: game_id game_id : int
The game ID that the user is currently playing. Could be None if no game is being played. The game ID that the user is currently playing. Could be None if no game is being played.
.. attribute:: server server : :class:`Server`
The server that the member belongs to.
The :class:`Server` that the member belongs to.
""" """
def __init__(self, deaf, joined_at, user, roles, mute, **kwargs): def __init__(self, deaf, joined_at, user, roles, mute, **kwargs):
@ -79,7 +70,7 @@ class Member(User):
self.mute = mute self.mute = mute
self.joined_at = parse_time(joined_at) self.joined_at = parse_time(joined_at)
self.roles = roles self.roles = roles
self.status = 'offline' self.status = Status.offline
self.game_id = kwargs.get('game_id', None) self.game_id = kwargs.get('game_id', None)
self.server = kwargs.get('server', None) self.server = kwargs.get('server', None)
self.update_voice_state(mute=mute, deaf=deaf) self.update_voice_state(mute=mute, deaf=deaf)

60
discord/server.py

@ -28,45 +28,36 @@ from . import utils
from .role import Role from .role import Role
from .member import Member from .member import Member
from .channel import Channel from .channel import Channel
from .enums import ServerRegion, Status
class Server(object): class Server:
"""Represents a Discord server. """Represents a Discord server.
Instance attributes: Attributes
----------
.. attribute:: name name : str
The server name. The server name.
.. attribute:: roles roles
A list of :class:`Role` that the server has available. A list of :class:`Role` that the server has available.
.. attribute:: region region : :class:`ServerRegion`
The region the server belongs on. There is a chance that the region
The region the server belongs on. will be a ``str`` if the value is not recognised by the enumerator.
.. attribute:: afk_timeout afk_timeout : int
The timeout to get sent to the AFK channel. The timeout to get sent to the AFK channel.
.. attribute:: afk_channel afk_channel : :class:`Channel`
The channel that denotes the AFK channel. None if it doesn't exist.
The :class:`Channel` that denotes the AFK channel. None if it doesn't exist. members
.. attribute:: members
A list of :class:`Member` that are currently on the server. A list of :class:`Member` that are currently on the server.
.. attribute:: channels channels
A list of :class:`Channel` that are currently on the server. A list of :class:`Channel` that are currently on the server.
.. attribute:: icon icon : str
The server's icon. The server's icon.
.. attribute:: id id : str
The server's ID. The server's ID.
.. attribute:: owner owner : :class:`Member`
The member who owns the server.
The :class:`Member` who owns the server. unavailable : bool
.. attribute:: unavailable Indicates if the server is unavailable. If this is ``True`` then the
A boolean indicating if the server is unavailable. If this is ``True`` then the
reliability of other attributes outside of :meth:`Server.id` is slim and they might reliability of other attributes outside of :meth:`Server.id` is slim and they might
all be None. It is best to not do anything with the server if it is unavailable. all be None. It is best to not do anything with the server if it is unavailable.
@ -88,6 +79,11 @@ class Server(object):
def _from_data(self, guild): def _from_data(self, guild):
self.name = guild.get('name') self.name = guild.get('name')
self.region = guild.get('region') self.region = guild.get('region')
try:
self.region = ServerRegion(self.region)
except:
pass
self.afk_timeout = guild.get('afk_timeout') self.afk_timeout = guild.get('afk_timeout')
self.icon = guild.get('icon') self.icon = guild.get('icon')
self.unavailable = guild.get('unavailable', False) self.unavailable = guild.get('unavailable', False)
@ -119,6 +115,10 @@ class Server(object):
member = utils.find(lambda m: m.id == user_id, self.members) member = utils.find(lambda m: m.id == user_id, self.members)
if member is not None: if member is not None:
member.status = presence['status'] member.status = presence['status']
try:
member.status = Status(member.status)
except:
pass
member.game_id = presence['game_id'] member.game_id = presence['game_id']
self.channels = [Channel(server=self, **c) for c in guild['channels']] self.channels = [Channel(server=self, **c) for c in guild['channels']]
@ -137,7 +137,7 @@ class Server(object):
return utils.find(lambda c: c.is_default_channel(), self.channels) return utils.find(lambda c: c.is_default_channel(), self.channels)
def icon_url(self): def icon_url(self):
"""Returns the URL version of the server's icon. Returns None if it has no icon.""" """Returns the URL version of the server's icon. Returns an empty string if it has no icon."""
if self.icon is None: if self.icon is None:
return '' return ''
return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.jpg'.format(self) return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.jpg'.format(self)

5
discord/state.py

@ -31,6 +31,7 @@ from .channel import Channel, PrivateChannel
from .member import Member from .member import Member
from .role import Role from .role import Role
from . import utils from . import utils
from .enums import Status
from collections import deque from collections import deque
import copy import copy
@ -113,6 +114,10 @@ class ConnectionState:
if member is not None: if member is not None:
old_member = copy.copy(member) old_member = copy.copy(member)
member.status = data.get('status') member.status = data.get('status')
try:
member.status = Status(member.status)
except:
pass
member.game_id = data.get('game_id') member.game_id = data.get('game_id')
member.name = user.get('username', member.name) member.name = user.get('username', member.name)
member.avatar = user.get('avatar', member.avatar) member.avatar = user.get('avatar', member.avatar)

61
docs/api.rst

@ -297,6 +297,67 @@ Utility Functions
.. autofunction:: discord.utils.find .. autofunction:: discord.utils.find
Enumerators
------------
The API provides some enumerators for certain types of strings to avoid the API
from being stringly typed in case the strings change in the future.
All enumerators are subclasses of `enum`_.
.. _enum: https://docs.python.org/3/library/enum.html
.. class:: ChannelType
Specifies the type of :class:`Channel`.
.. attribute:: text
A text channel.
.. attribute:: voice
A voice channel.
.. class:: ServerRegion
Specifies the region a :class:`Server`'s voice server belongs to.
.. attribute:: us_west
The US West region.
.. attribute:: us_east
The US East region.
.. attribute:: singapore
The Singapore region.
.. attribute:: london
The London region.
.. attribute:: sydney
The Sydney region.
.. attribute:: amsterdam
The Amsterdam region.
.. attribute:: frankfurt
The Frankfurt region.
.. class:: Status
Specifies a :class:`Member` 's status.
.. attribute:: online
The member is online.
.. attribute:: offline
The member is offline.
.. attribute:: idle
The member is idle.
Data Classes Data Classes
-------------- --------------

Loading…
Cancel
Save