pincer.objects.user.user   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 11
eloc 82
dl 0
loc 243
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A User.mention() 0 4 1
A User.get_avatar_url() 0 15 1
A User.send() 0 11 1
A User.premium() 0 9 2
A User.get_avatar() 0 27 3
A User.from_id() 0 16 1
A User.get_dm_channel() 0 10 1
A User.__str__() 0 9 1
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from __future__ import annotations
5
6
import io
7
from dataclasses import dataclass
8
from enum import IntEnum
9
from typing import TYPE_CHECKING
10
11
from aiohttp import ClientSession
0 ignored issues
show
introduced by
Unable to import 'aiohttp'
Loading history...
12
13
from ..guild import channel
14
from ...utils.api_object import APIObject
15
from ...utils.color import Color
16
from ...utils.convert_message import MessageConvertable
17
from ...utils.types import MISSING
18
19
PILLOW_IMPORT = True
20
21
try:
22
    from PIL import Image
23
except (ModuleNotFoundError, ImportError):
24
    PILLOW_IMPORT = False
25
26
27
if TYPE_CHECKING:
28
    from typing import Optional
29
30
    from ...client import Client
31
    from ...objects.message.user_message import UserMessage
32
    from ...utils.types import APINullable
33
    from ...utils.snowflake import Snowflake
34
35
36
class PremiumTypes(IntEnum):
37
    """The type of Discord premium a user has.
38
39
    Attributes
40
    ----------
41
    NONE:
42
        No nitro.
43
    NITRO_CLASSIC:
44
        Nitro classic (no boosts).
45
    NITRO:
46
        Full nitro subscription.
47
    """
48
49
    NONE = 0
50
    NITRO_CLASSIC = 1
51
    NITRO = 2
52
53
54
class VisibilityType(IntEnum):
55
    """The type of connection visibility.
56
57
    Attributes
58
    ----------
59
    NONE:
60
        Connection is not visible.
61
    EVERYONE:
62
        Connection is visible to everyone.
63
    """
64
65
    NONE = 0
66
    EVERYONE = 1
67
68
69
@dataclass(repr=False)
70
class User(APIObject):
0 ignored issues
show
best-practice introduced by
Too many instance attributes (16/7)
Loading history...
71
    """Represents a Discord user. This can be a bot account or a
72
    human account.
73
74
    Attributes
75
    ----------
76
    avatar: Optional[:class:`str`]
77
        The user's avatar hash
78
    discriminator: :class:`str`
79
        The user's 4-digit discord-tag
80
    id: :class:`~pincer.utils.snowflake.Snowflake`
81
        The user's id
82
    username: :class:`str`
83
        The user's username, not unique across the platform
84
    flags: APINullable[:class:`int`]
85
        The flags on a user's account
86
    accent_color: APINullable[Optional[:class:`int`]]
87
        The user's banner color encoded as an integer representation of
88
        hexadecimal color code
89
    banner: APINullable[Optional[:class:`str`]]
90
        The user's banner, or null if unset
91
    banner_color: APINullable[Optional[:class:`~pincer.utils.color.Color`]]
92
        The color of the user's banner
93
    bot: APINullable[:class:`bool`]
94
        Whether the user belongs to an OAuth2 application
95
    email: APINullable[Optional[:class:`str`]]
96
        The user's email
97
    locale: APINullable[:class:`str`]
98
        The user's chosen language option
99
    mfa_enabled: APINullable[:class:`bool`]
100
        Whether the user has two factor enabled on their account
101
    premium_type: APINullable[:class:`int`]
102
        The type of Nitro subscription on a user's account
103
    public_flags: APINullable[:class:`int`]
104
        The public flags on a user's account
105
    system: APINullable[:class:`bool`]
106
        Whether the user is an Official Discord System user
107
        (part of the urgent message system)
108
    verified: APINullable[:class:`bool`]
109
        Whether the email on this account has been verified
110
    """
111
112
    id: APINullable[Snowflake] = MISSING
113
    username: APINullable[str] = MISSING
114
    discriminator: APINullable[str] = MISSING
115
116
    avatar: APINullable[str] = MISSING
117
    flags: APINullable[int] = MISSING
118
    accent_color: APINullable[Optional[int]] = MISSING
119
    banner: APINullable[Optional[str]] = MISSING
120
    banner_color: APINullable[Optional[Color]] = MISSING
121
    bot: APINullable[bool] = MISSING
122
    email: APINullable[Optional[str]] = MISSING
123
    locale: APINullable[str] = MISSING
124
    mfa_enabled: APINullable[bool] = MISSING
125
    premium_type: APINullable[int] = MISSING
126
    public_flags: APINullable[int] = MISSING
127
    system: APINullable[bool] = MISSING
128
    verified: APINullable[bool] = MISSING
129
130
    @property
131
    def premium(self) -> APINullable[PremiumTypes]:
132
        """APINullable[:class:`~pincer.objects.user.user.PremiumTypes`]: The
133
        user their premium type in a usable enum.
134
        """
135
        return (
136
            MISSING
137
            if self.premium_type is MISSING
138
            else PremiumTypes(self.premium_type)
139
        )
140
141
    @property
142
    def mention(self) -> str:
143
        """:class:`str`: The user's mention string."""
144
        return f"<@!{self.id}>"
145
146
    def get_avatar_url(self, size: int = 512, ext: str = "png") -> str:
147
        """
148
        Returns the url of the user's avatar.
149
150
        Parameters
151
        ----------
152
        size: :class:`int`: Avatar width & height in pixels
153
        ext: :class:`str`: Image extension
154
155
        Returns
156
        -------
157
        :class:`str`: Returns the url of the user's avatar.
158
        """
159
        return (
160
            f"https://cdn.discordapp.com/avatars/{self.id}/{self.avatar}.{ext}"
161
            f"?size={size}"
162
        )
163
164
    async def get_avatar(self, size: int = 512, ext: str = "png") -> Image:
165
        """|Coro|
166
        Get the user's avatar as a Pillow image.
167
168
        Parameters
169
        ----------
170
        size : :class: int, optional
171
            The size of the image to get. Defaults to 512.
172
        ext : :class: str, optional
173
            The file extension to use. Defaults to 'png'.
174
175
        Returns
176
        -------
177
        :class: Image
178
            The user's avatar as a Pillow image.
179
        """
180
        if not PILLOW_IMPORT:
181
            raise ModuleNotFoundError(
182
                "The `Pillow` library is required for sending and converting "
183
                "pillow images,"
184
            )
185
186
        async with ClientSession().get(
187
            url=self.get_avatar_url(size, ext)
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
188
        ) as resp:
189
            avatar = io.BytesIO(await resp.read())
190
            return Image.open(avatar).convert("RGBA")
191
192
    def __str__(self):
193
        # TODO: fix docs
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
194
        """
195
196
        Returns
197
        -------
198
199
        """
200
        return self.username + "#" + self.discriminator
201
202
    @classmethod
203
    async def from_id(cls, client: Client, user_id: int) -> User:
204
        # TODO: fix docs
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
205
        """
206
207
        Parameters
208
        ----------
209
        client
210
        user_id
211
212
        Returns
213
        -------
214
215
        """
216
        data = await client.http.get(f"users/{user_id}")
217
        return cls.from_dict(data)
218
219
    async def get_dm_channel(self) -> channel.Channel:
220
        """
221
        Returns
222
        -------
223
        :class:`~pincer.objects.guild.channel.Channel`
224
            DM channel for this user.
225
        """
226
        return channel.Channel.from_dict(
227
            await self._http.post(
228
                "/users/@me/channels", data={"recipient_id": self.id}
229
            )
230
        )
231
232
    async def send(self, message: MessageConvertable) -> UserMessage:
233
        """
234
        Sends a message to a user.
235
236
        Parameters
237
        ----------
238
        message : :class:`~pincer.utils.convert_message.MessageConvertable`
239
            Message to be sent to the user.
240
        """
241
        _channel = await self.get_dm_channel()
242
        return await _channel.send(message)
243