Browse Source

Create ClientStatus type to improve Member memory usage

pull/7523/head
Lilly Rose Berner 3 years ago
committed by GitHub
parent
commit
85b6175137
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 68
      discord/member.py
  2. 6
      discord/types/activity.py

68
discord/member.py

@ -55,7 +55,10 @@ if TYPE_CHECKING:
from .channel import DMChannel, VoiceChannel, StageChannel
from .flags import PublicUserFlags
from .guild import Guild
from .types.activity import PartialPresenceUpdate
from .types.activity import (
ClientStatus as ClientStatusPayload,
PartialPresenceUpdate,
)
from .types.member import (
MemberWithUser as MemberWithUserPayload,
Member as MemberPayload,
@ -163,6 +166,46 @@ class VoiceState:
return f'<{self.__class__.__name__} {inner}>'
class _ClientStatus:
__slots__ = ('_status', 'desktop', 'mobile', 'web')
def __init__(self):
self._status: str = 'offline'
self.desktop: Optional[str] = None
self.mobile: Optional[str] = None
self.web: Optional[str] = None
def __repr__(self) -> str:
attrs = [
('_status', self._status),
('desktop', self.desktop),
('mobile', self.mobile),
('web', self.web),
]
inner = ' '.join('%s=%r' % t for t in attrs)
return f'<{self.__class__.__name__} {inner}>'
def _update(self, status: str, data: ClientStatusPayload, /) -> None:
self._status = status
self.desktop = data.get('desktop')
self.mobile = data.get('mobile')
self.web = data.get('web')
@classmethod
def _copy(cls, client_status: Self, /) -> Self:
self = cls.__new__(cls) # bypass __init__
self._status = client_status._status
self.desktop = client_status.desktop
self.mobile = client_status.mobile
self.web = client_status.web
return self
def flatten_user(cls):
for attr, value in itertools.chain(BaseUser.__dict__.items(), User.__dict__.items()):
# ignore private/special methods
@ -303,7 +346,7 @@ class Member(discord.abc.Messageable, _UserTag):
self.joined_at: Optional[datetime.datetime] = utils.parse_time(data.get('joined_at'))
self.premium_since: Optional[datetime.datetime] = utils.parse_time(data.get('premium_since'))
self._roles: utils.SnowflakeList = utils.SnowflakeList(map(int, data['roles']))
self._client_status: Dict[Optional[str], str] = {None: 'offline'}
self._client_status: _ClientStatus = _ClientStatus()
self.activities: Tuple[ActivityTypes, ...] = tuple()
self.nick: Optional[str] = data.get('nick', None)
self.pending: bool = data.get('pending', False)
@ -366,7 +409,7 @@ class Member(discord.abc.Messageable, _UserTag):
self._roles = utils.SnowflakeList(member._roles, is_sorted=True)
self.joined_at = member.joined_at
self.premium_since = member.premium_since
self._client_status = member._client_status.copy()
self._client_status = _ClientStatus._copy(member._client_status)
self.guild = member.guild
self.nick = member.nick
self.pending = member.pending
@ -405,10 +448,7 @@ class Member(discord.abc.Messageable, _UserTag):
def _presence_update(self, data: PartialPresenceUpdate, user: UserPayload) -> Optional[Tuple[User, User]]:
self.activities = tuple(map(create_activity, data['activities']))
self._client_status = {
sys.intern(key): sys.intern(value) for key, value in data.get('client_status', {}).items() # type: ignore
}
self._client_status[None] = sys.intern(data['status'])
self._client_status._update(data['status'], data['client_status'])
if len(user) > 1:
return self._update_inner_user(user)
@ -428,7 +468,7 @@ class Member(discord.abc.Messageable, _UserTag):
@property
def status(self) -> Status:
""":class:`Status`: The member's overall status. If the value is unknown, then it will be a :class:`str` instead."""
return try_enum(Status, self._client_status[None])
return try_enum(Status, self._client_status._status)
@property
def raw_status(self) -> str:
@ -436,31 +476,31 @@ class Member(discord.abc.Messageable, _UserTag):
.. versionadded:: 1.5
"""
return self._client_status[None]
return self._client_status._status
@status.setter
def status(self, value: Status) -> None:
# internal use only
self._client_status[None] = str(value)
self._client_status._status = str(value)
@property
def mobile_status(self) -> Status:
""":class:`Status`: The member's status on a mobile device, if applicable."""
return try_enum(Status, self._client_status.get('mobile', 'offline'))
return try_enum(Status, self._client_status.mobile or 'offline')
@property
def desktop_status(self) -> Status:
""":class:`Status`: The member's status on the desktop client, if applicable."""
return try_enum(Status, self._client_status.get('desktop', 'offline'))
return try_enum(Status, self._client_status.desktop or 'offline')
@property
def web_status(self) -> Status:
""":class:`Status`: The member's status on the web client, if applicable."""
return try_enum(Status, self._client_status.get('web', 'offline'))
return try_enum(Status, self._client_status.web or 'offline')
def is_on_mobile(self) -> bool:
""":class:`bool`: A helper function that determines if a member is active on a mobile device."""
return 'mobile' in self._client_status
return self._client_status.mobile is not None
@property
def colour(self) -> Colour:

6
discord/types/activity.py

@ -41,9 +41,9 @@ class PartialPresenceUpdate(TypedDict):
class ClientStatus(TypedDict, total=False):
desktop: str
mobile: str
web: str
desktop: StatusType
mobile: StatusType
web: StatusType
class ActivityTimestamps(TypedDict, total=False):

Loading…
Cancel
Save