Passed
Pull Request — main (#235)
by
unknown
01:41
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.conversion import construct_client_dict
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
0 ignored issues
show
introduced by
Cannot import 'client' due to syntax error 'invalid syntax (<unknown>, line 354)'
Loading history...
31
    from ...objects.message.user_message import UserMessage
32
    from ...utils.types import APINullable, Color
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 a 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
0 ignored issues
show
best-practice introduced by
Too many instance attributes (16/7)
Loading history...
70
class User(APIObject):
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.types.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: Snowflake
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 if self.premium_type is MISSING else PremiumTypes(
137
                self.premium_type)
138
        )
139
140
    @property
141
    def mention(self) -> str:
142
        """:class:`str`: The user's mention string."""
143
        return f"<@!{self.id}>"
144
145
    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...
146
        return (
147
            f"https://cdn.discordapp.com/avatars/{self.id}/{self.avatar}.{ext}"
148
            f"?size={size}"
149
        )
150
151
    if PILLOW_IMPORT:
152
153
        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...
154
            """Get the user's avatar as a Pillow image.
155
156
            Parameters
157
            ----------
158
            size : :class: int, optional
159
                The size of the image to get. Defaults to 512.
160
            ext : :class: str, optional
161
                The file extension to use. Defaults to 'png'.
162
163
            Returns
164
            -------
165
            :class: Image
166
                The user's avatar as a Pillow image.
167
            """
168
            async with ClientSession().get(url=self.get_avatar_url()) as resp:
169
                avatar = io.BytesIO(await resp.read())
170
                print(Image, dir(Image))
171
                return Image.open(avatar).convert("RGBA")
172
173
    def __str__(self):
174
        return self.username + "#" + self.discriminator
175
176
    @classmethod
177
    async def from_id(cls, client: Client, user_id: int) -> User:
0 ignored issues
show
introduced by
Missing function or method docstring
Loading history...
178
        data = await client.http.get(f"users/{user_id}")
179
        return cls.from_dict(construct_client_dict(client, data))
180
181
    async def get_dm_channel(self) -> channel.Channel:
182
        """
183
        Returns
184
        -------
185
        :class:`~pincer.objects.guild.channel.Channel`
186
            DM channel for this user.
187
        """
188
        return channel.Channel.from_dict(
189
            construct_client_dict(
190
                self._client,
191
                await self._http.post(
192
                    "/users/@me/channels",
193
                    data={"recipient_id": self.id}
194
                )
195
            )
196
        )
197
198
    async def send(self, message: MessageConvertable) -> UserMessage:
199
        """
200
        Sends a message to a user.
201
202
        Parameters
203
        ----------
204
        message : :class:`~pincer.utils.convert_message.MessageConvertable`
205
            Message to be sent to the user.
206
        """
207
        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...
208
        return await channel.send(message)
209