3030from typing import TYPE_CHECKING , Any , Literal
3131
3232import yarl
33+ from typing_extensions import Final , override
3334
3435from . import utils
3536from .errors import DiscordException , InvalidArgument
3940if TYPE_CHECKING :
4041 ValidStaticFormatTypes = Literal ["webp" , "jpeg" , "jpg" , "png" ]
4142 ValidAssetFormatTypes = Literal ["webp" , "jpeg" , "jpg" , "png" , "gif" ]
43+ from .state import ConnectionState
4244
4345VALID_STATIC_FORMATS = frozenset ({"jpeg" , "jpg" , "webp" , "png" })
4446VALID_ASSET_FORMATS = VALID_STATIC_FORMATS | {"gif" }
4951
5052class AssetMixin :
5153 url : str
52- _state : Any | None
54+ _state : ConnectionState | None
5355
5456 async def read (self ) -> bytes :
5557 """|coro|
@@ -77,7 +79,9 @@ async def read(self) -> bytes:
7779
7880 async def save (
7981 self ,
80- fp : str | bytes | os .PathLike | io .BufferedIOBase ,
82+ fp : (
83+ str | bytes | os .PathLike | io .BufferedIOBase
84+ ), # pyright: ignore [reportMissingTypeArgument]
8185 * ,
8286 seek_begin : bool = True ,
8387 ) -> int :
@@ -117,7 +121,7 @@ async def save(
117121 fp .seek (0 )
118122 return written
119123 else :
120- with open (fp , "wb" ) as f :
124+ with open (fp , "wb" ) as f : # pyright: ignore [reportUnknownArgumentType]
121125 return f .write (data )
122126
123127
@@ -154,16 +158,23 @@ class Asset(AssetMixin):
154158 "_key" ,
155159 )
156160
157- BASE = "https://cdn.discordapp.com"
161+ BASE : Final = "https://cdn.discordapp.com"
158162
159- def __init__ (self , state , * , url : str , key : str , animated : bool = False ):
160- self ._state = state
161- self ._url = url
162- self ._animated = animated
163- self ._key = key
163+ def __init__ (
164+ self ,
165+ state : ConnectionState | None ,
166+ * ,
167+ url : str ,
168+ key : str ,
169+ animated : bool = False ,
170+ ):
171+ self ._state : ConnectionState | None = state
172+ self ._url : str = url
173+ self ._animated : bool = animated
174+ self ._key : str = key
164175
165176 @classmethod
166- def _from_default_avatar (cls , state , index : int ) -> Asset :
177+ def _from_default_avatar (cls , state : ConnectionState , index : int ) -> Asset :
167178 return cls (
168179 state ,
169180 url = f"{ cls .BASE } /embed/avatars/{ index } .png" ,
@@ -172,7 +183,7 @@ def _from_default_avatar(cls, state, index: int) -> Asset:
172183 )
173184
174185 @classmethod
175- def _from_avatar (cls , state , user_id : int , avatar : str ) -> Asset :
186+ def _from_avatar (cls , state : ConnectionState , user_id : int , avatar : str ) -> Asset :
176187 animated = avatar .startswith ("a_" )
177188 format = "gif" if animated else "png"
178189 return cls (
@@ -184,7 +195,10 @@ def _from_avatar(cls, state, user_id: int, avatar: str) -> Asset:
184195
185196 @classmethod
186197 def _from_avatar_decoration (
187- cls , state , user_id : int , avatar_decoration : str
198+ cls ,
199+ state : ConnectionState ,
200+ user_id : int ,
201+ avatar_decoration : str , # pyright: ignore [reportUnusedParameter]
188202 ) -> Asset :
189203 animated = avatar_decoration .startswith ("a_" )
190204 endpoint = (
@@ -201,7 +215,7 @@ def _from_avatar_decoration(
201215
202216 @classmethod
203217 def _from_guild_avatar (
204- cls , state , guild_id : int , member_id : int , avatar : str
218+ cls , state : ConnectionState , guild_id : int , member_id : int , avatar : str
205219 ) -> Asset :
206220 animated = avatar .startswith ("a_" )
207221 format = "gif" if animated else "png"
@@ -214,7 +228,7 @@ def _from_guild_avatar(
214228
215229 @classmethod
216230 def _from_guild_banner (
217- cls , state , guild_id : int , member_id : int , banner : str
231+ cls , state : ConnectionState , guild_id : int , member_id : int , banner : str
218232 ) -> Asset :
219233 animated = banner .startswith ("a_" )
220234 format = "gif" if animated else "png"
@@ -226,7 +240,9 @@ def _from_guild_banner(
226240 )
227241
228242 @classmethod
229- def _from_icon (cls , state , object_id : int , icon_hash : str , path : str ) -> Asset :
243+ def _from_icon (
244+ cls , state : ConnectionState , object_id : int , icon_hash : str , path : str
245+ ) -> Asset :
230246 return cls (
231247 state ,
232248 url = f"{ cls .BASE } /{ path } -icons/{ object_id } /{ icon_hash } .png?size=1024" ,
@@ -235,7 +251,9 @@ def _from_icon(cls, state, object_id: int, icon_hash: str, path: str) -> Asset:
235251 )
236252
237253 @classmethod
238- def _from_cover_image (cls , state , object_id : int , cover_image_hash : str ) -> Asset :
254+ def _from_cover_image (
255+ cls , state : ConnectionState , object_id : int , cover_image_hash : str
256+ ) -> Asset :
239257 return cls (
240258 state ,
241259 url = f"{ cls .BASE } /app-assets/{ object_id } /store/{ cover_image_hash } .png?size=1024" ,
@@ -244,7 +262,9 @@ def _from_cover_image(cls, state, object_id: int, cover_image_hash: str) -> Asse
244262 )
245263
246264 @classmethod
247- def _from_guild_image (cls , state , guild_id : int , image : str , path : str ) -> Asset :
265+ def _from_guild_image (
266+ cls , state : ConnectionState , guild_id : int , image : str , path : str
267+ ) -> Asset :
248268 animated = False
249269 format = "png"
250270 if path == "banners" :
@@ -259,7 +279,9 @@ def _from_guild_image(cls, state, guild_id: int, image: str, path: str) -> Asset
259279 )
260280
261281 @classmethod
262- def _from_guild_icon (cls , state , guild_id : int , icon_hash : str ) -> Asset :
282+ def _from_guild_icon (
283+ cls , state : ConnectionState , guild_id : int , icon_hash : str
284+ ) -> Asset :
263285 animated = icon_hash .startswith ("a_" )
264286 format = "gif" if animated else "png"
265287 return cls (
@@ -270,7 +292,7 @@ def _from_guild_icon(cls, state, guild_id: int, icon_hash: str) -> Asset:
270292 )
271293
272294 @classmethod
273- def _from_sticker_banner (cls , state , banner : int ) -> Asset :
295+ def _from_sticker_banner (cls , state : ConnectionState , banner : int ) -> Asset :
274296 return cls (
275297 state ,
276298 url = f"{ cls .BASE } /app-assets/710982414301790216/store/{ banner } .png" ,
@@ -279,7 +301,9 @@ def _from_sticker_banner(cls, state, banner: int) -> Asset:
279301 )
280302
281303 @classmethod
282- def _from_user_banner (cls , state , user_id : int , banner_hash : str ) -> Asset :
304+ def _from_user_banner (
305+ cls , state : ConnectionState , user_id : int , banner_hash : str
306+ ) -> Asset :
283307 animated = banner_hash .startswith ("a_" )
284308 format = "gif" if animated else "png"
285309 return cls (
@@ -291,7 +315,7 @@ def _from_user_banner(cls, state, user_id: int, banner_hash: str) -> Asset:
291315
292316 @classmethod
293317 def _from_scheduled_event_image (
294- cls , state , event_id : int , cover_hash : str
318+ cls , state : ConnectionState , event_id : int , cover_hash : str
295319 ) -> Asset :
296320 return cls (
297321 state ,
@@ -300,24 +324,29 @@ def _from_scheduled_event_image(
300324 animated = False ,
301325 )
302326
327+ @override
303328 def __str__ (self ) -> str :
304329 return self ._url
305330
306331 def __len__ (self ) -> int :
307332 return len (self ._url )
308333
334+ @override
309335 def __repr__ (self ):
310336 shorten = self ._url .replace (self .BASE , "" )
311337 return f"<Asset url={ shorten !r} >"
312338
313- def __eq__ (self , other ):
339+ @override
340+ def __eq__ (self , other : Any ): # pyright: ignore [reportExplicitAny]
314341 return isinstance (other , Asset ) and self ._url == other ._url
315342
343+ @override
316344 def __hash__ (self ):
317345 return hash (self ._url )
318346
319347 @property
320- def url (self ) -> str :
348+ @override
349+ def url (self ) -> str : # pyright: ignore [reportIncompatibleVariableOverride]
321350 """Returns the underlying URL of the asset."""
322351 return self ._url
323352
0 commit comments