Passed
Pull Request — main (#235)
by Yohann
01:42
created

pincer.objects.user.user.User.send()   A

Complexity

Conditions 1

Size

Total Lines 11
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 1
nop 2
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
12
13
from ..guild import channel
0 ignored issues
show
Bug introduced by
The name channel does not seem to exist in module pincer.objects.guild.
Loading history...
14
from ...utils.api_object import APIObject
0 ignored issues
show
Bug introduced by
The name api_object does not seem to exist in module pincer.utils.
Loading history...
introduced by
Cannot import 'utils.api_object' due to syntax error 'invalid syntax (<unknown>, line 80)'
Loading history...
15
from ...utils.color import Color
16
from ...utils.conversion import construct_client_dict
17
from ...utils.convert_message import MessageConvertable
18
from ...utils.types import MISSING
19
20
PILLOW_IMPORT = True
21
22
try:
23
    from PIL import Image
24
except (ModuleNotFoundError, ImportError):
25
    PILLOW_IMPORT = False
26
27
28
if TYPE_CHECKING:
29
    from typing import Optional
30
31
    from ...client import Client
0 ignored issues
show
introduced by
Cannot import 'client' due to syntax error 'invalid syntax (<unknown>, line 354)'
Loading history...
32
    from ...objects.message.user_message import UserMessage
33
    from ...utils.types import APINullable
34
    from ...utils.snowflake import Snowflake
35
36
37
class PremiumTypes(IntEnum):
38
    """The type of Discord premium a user has.
39
40
    Attributes
41
    ----------
42
    NONE:
43
        No nitro.
44
    NITRO_CLASSIC:
45
        Nitro classic (no boosts).
46
    NITRO:
47
        Full nitro subscription.
48
    """
49
50
    NONE = 0
51
    NITRO_CLASSIC = 1
52
    NITRO = 2
53
54
55
class VisibilityType(IntEnum):
56
    """The type of a connection visibility.
57
58
    Attributes
59
    ----------
60
    NONE:
61
        Connection is not visible.
62
    EVERYONE:
63
        Connection is visible to everyone.
64
    """
65
66
    NONE = 0
67
    EVERYONE = 1
68
69
70
@dataclass
0 ignored issues
show
best-practice introduced by
Too many instance attributes (16/7)
Loading history...
71
class User(APIObject):
72
    """Represents a Discord user. This can be a bot account or a
73
    human account.
74
75
    Attributes
76
    ----------
77
    avatar: Optional[:class:`str`]
78
        The user's avatar hash
79
    discriminator: :class:`str`
80
        The user's 4-digit discord-tag
81
    id: :class:`~pincer.utils.snowflake.Snowflake`
82
        The user's id
83
    username: :class:`str`
84
        The user's username, not unique across the platform
85
    flags: APINullable[:class:`int`]
86
        The flags on a user's account
87
    accent_color: APINullable[Optional[:class:`int`]]
88
        The user's banner color encoded as an integer representation of
89
        hexadecimal color code
90
    banner: APINullable[Optional[:class:`str`]]
91
        The user's banner, or null if unset
92
    banner_color: APINullable[Optional[:class:`~pincer.utils.color.Color`]]
93
        The color of the user's banner
94
    bot: APINullable[:class:`bool`]
95
        Whether the user belongs to an OAuth2 application
96
    email: APINullable[Optional[:class:`str`]]
97
        The user's email
98
    locale: APINullable[:class:`str`]
99
        The user's chosen language option
100
    mfa_enabled: APINullable[:class:`bool`]
101
        Whether the user has two factor enabled on their account
102
    premium_type: APINullable[:class:`int`]
103
        The type of Nitro subscription on a user's account
104
    public_flags: APINullable[:class:`int`]
105
        The public flags on a user's account
106
    system: APINullable[:class:`bool`]
107
        Whether the user is an Official Discord System user
108
        (part of the urgent message system)
109
    verified: APINullable[:class:`bool`]
110
        Whether the email on this account has been verified
111
    """
112
113
    id: Snowflake
114
    username: APINullable[str] = MISSING
115
    discriminator: APINullable[str] = MISSING
116
117
    avatar: APINullable[str] = MISSING
118
    flags: APINullable[int] = MISSING
119
    accent_color: APINullable[Optional[int]] = MISSING
120
    banner: APINullable[Optional[str]] = MISSING
121
    banner_color: APINullable[Optional[Color]] = MISSING
122
    bot: APINullable[bool] = MISSING
123
    email: APINullable[Optional[str]] = MISSING
124
    locale: APINullable[str] = MISSING
125
    mfa_enabled: APINullable[bool] = MISSING
126
    premium_type: APINullable[int] = MISSING
127
    public_flags: APINullable[int] = MISSING
128
    system: APINullable[bool] = MISSING
129
    verified: APINullable[bool] = MISSING
130
131
    @property
132
    def premium(self) -> APINullable[PremiumTypes]:
133
        """APINullable[:class:`~pincer.objects.user.user.PremiumTypes`]: The
134
        user their premium type in a usable enum.
135
        """
136
        return (
137
            MISSING if self.premium_type is MISSING else PremiumTypes(
138
                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:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
147
        return (
148
            f"https://cdn.discordapp.com/avatars/{self.id}/{self.avatar}.{ext}"
149
            f"?size={size}"
150
        )
151
152
    if PILLOW_IMPORT:
153
154
        async def get_avatar(self, size: int = 512, ext: str = "png") -> Image:
0 ignored issues
show
Unused Code introduced by
The argument size seems to be unused.
Loading history...
Unused Code introduced by
The argument ext seems to be unused.
Loading history...
155
            """Get the user's avatar as a Pillow image.
156
157
            Parameters
158
            ----------
159
            size : :class: int, optional
160
                The size of the image to get. Defaults to 512.
161
            ext : :class: str, optional
162
                The file extension to use. Defaults to 'png'.
163
164
            Returns
165
            -------
166
            :class: Image
167
                The user's avatar as a Pillow image.
168
            """
169
            async with ClientSession().get(url=self.get_avatar_url()) as resp:
170
                avatar = io.BytesIO(await resp.read())
171
                print(Image, dir(Image))
172
                return Image.open(avatar).convert("RGBA")
173
174
    def __str__(self):
175
        return self.username + "#" + self.discriminator
176
177
    @classmethod
178
    async def from_id(cls, client: Client, user_id: int) -> User:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
179
        data = await client.http.get(f"users/{user_id}")
180
        return cls.from_dict(construct_client_dict(client, data))
181
182
    async def get_dm_channel(self) -> channel.Channel:
183
        """
184
        Returns
185
        -------
186
        :class:`~pincer.objects.guild.channel.Channel`
187
            DM channel for this user.
188
        """
189
        return channel.Channel.from_dict(
190
            construct_client_dict(
191
                self._client,
192
                await self._http.post(
193
                    "/users/@me/channels",
194
                    data={"recipient_id": self.id}
195
                )
196
            )
197
        )
198
199
    async def send(self, message: MessageConvertable) -> UserMessage:
200
        """
201
        Sends a message to a user.
202
203
        Parameters
204
        ----------
205
        message : :class:`~pincer.utils.convert_message.MessageConvertable`
206
            Message to be sent to the user.
207
        """
208
        channel = await self.get_dm_channel()
0 ignored issues
show
Comprehensibility Bug introduced by
channel is re-defining a name which is already available in the outer-scope (previously defined on line 13).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
209
        return await channel.send(message)
210