Implement discord.MessageFlags

Refactor flags placement and use it for suppression.
This commit is contained in:
NCPlayz
2019-11-20 19:57:34 +00:00
committed by Rapptz
parent fe1ebb3144
commit 9c6a121644
6 changed files with 284 additions and 125 deletions

View File

@ -45,124 +45,11 @@ from .iterators import AuditLogIterator, MemberIterator
from .webhook import Webhook
from .widget import Widget
from .asset import Asset
from .flags import SystemChannelFlags
BanEntry = namedtuple('BanEntry', 'reason user')
_GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize')
class _flag_descriptor:
def __init__(self, func):
self.flag = func(None)
self.__doc__ = func.__doc__
def __get__(self, instance, owner):
return instance._has_flag(self.flag)
def __set__(self, instance, value):
instance._set_flag(self.flag, value)
def fill_with_flags(cls):
cls.VALID_FLAGS = {
name: value.flag
for name, value in cls.__dict__.items()
if isinstance(value, _flag_descriptor)
}
max_bits = max(cls.VALID_FLAGS.values()).bit_length()
cls.ALL_OFF_VALUE = -1 + (2 ** max_bits)
return cls
@fill_with_flags
class SystemChannelFlags:
r"""Wraps up a Discord system channel flag value.
Similar to :class:`Permissions`\, the properties provided are two way.
You can set and retrieve individual bits using the properties as if they
were regular bools. This allows you to edit the system flags easily.
To construct an object you can pass keyword arguments denoting the flags
to enable or disable.
.. container:: operations
.. describe:: x == y
Checks if two flags are equal.
.. describe:: x != y
Checks if two flags are not equal.
.. describe:: hash(x)
Return the flag's hash.
.. describe:: iter(x)
Returns an iterator of ``(name, value)`` pairs. This allows it
to be, for example, constructed as a dict or a list of pairs.
Attributes
-----------
value: :class:`int`
The raw value. This value is a bit array field of a 53-bit integer
representing the currently available flags. You should query
flags via the properties rather than using this raw value.
"""
__slots__ = ('value',)
def __init__(self, **kwargs):
self.value = self.ALL_OFF_VALUE
for key, value in kwargs.items():
if key not in self.VALID_FLAGS:
raise TypeError('%r is not a valid flag name.' % key)
setattr(self, key, value)
@classmethod
def _from_value(cls, value):
self = cls.__new__(cls)
self.value = value
return self
def __eq__(self, other):
return isinstance(other, SystemChannelFlags) and self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash(self.value)
def __repr__(self):
return '<SystemChannelFlags value=%s>' % self.value
def __iter__(self):
for name, value in self.__class__.__dict__.items():
if isinstance(value, _flag_descriptor):
yield (name, self._has_flag(value.flag))
# For some reason the flags in the Discord API are "inverted"
# ergo, if they're set then it means "suppress" (off in the GUI toggle)
# Since this is counter-intuitive from an API perspective and annoying
# these will be inverted automatically
def _has_flag(self, o):
return (self.value & o) != o
def _set_flag(self, o, toggle):
if toggle is True:
self.value &= ~o
elif toggle is False:
self.value |= o
else:
raise TypeError('Value to set for SystemChannelFlags must be a bool.')
@_flag_descriptor
def join_notifications(self):
""":class:`bool`: Returns True if the system channel is used for member join notifications."""
return 1
@_flag_descriptor
def premium_subscriptions(self):
""":class:`bool`: Returns True if the system channel is used for Nitro boosting notifications."""
return 2
class Guild(Hashable):
"""Represents a Discord guild.