Refactor MRO of InputMedia* and Some File-Like Classes (#2717)

This commit is contained in:
eldbud 2021-10-15 19:03:56 +03:00 committed by Hinrich Mahler
parent 59014bee64
commit 7e51901d51
23 changed files with 411 additions and 524 deletions

View file

@ -3,6 +3,9 @@
telegram.Animation telegram.Animation
================== ==================
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Animation .. autoclass:: telegram.Animation
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -3,6 +3,9 @@
telegram.Audio telegram.Audio
============== ==============
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Audio .. autoclass:: telegram.Audio
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -2,7 +2,9 @@
telegram.Document telegram.Document
================= =================
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Document .. autoclass:: telegram.Document
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -2,7 +2,9 @@
telegram.PhotoSize telegram.PhotoSize
================== ==================
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.PhotoSize .. autoclass:: telegram.PhotoSize
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -3,6 +3,9 @@
telegram.Sticker telegram.Sticker
================ ================
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Sticker .. autoclass:: telegram.Sticker
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -3,6 +3,9 @@
telegram.Video telegram.Video
============== ==============
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Video .. autoclass:: telegram.Video
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -3,6 +3,9 @@
telegram.VideoNote telegram.VideoNote
================== ==================
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.VideoNote .. autoclass:: telegram.VideoNote
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -3,6 +3,9 @@
telegram.Voice telegram.Voice
============== ==============
.. Also lists methods of _BaseThumbedMedium, but not the ones of TelegramObject
.. autoclass:: telegram.Voice .. autoclass:: telegram.Voice
:members: :members:
:show-inheritance: :show-inheritance:
:inherited-members: TelegramObject

View file

@ -223,9 +223,7 @@ class Bot(TelegramObject):
for key, val in data.items(): for key, val in data.items():
# 1) # 1)
if isinstance(val, InputMedia): if isinstance(val, InputMedia):
val.parse_mode = DefaultValue.get_value( # type: ignore[attr-defined] val.parse_mode = DefaultValue.get_value(val.parse_mode)
val.parse_mode # type: ignore[attr-defined]
)
elif key == 'media' and isinstance(val, list): elif key == 'media' and isinstance(val, list):
for media in val: for media in val:
media.parse_mode = DefaultValue.get_value(media.parse_mode) media.parse_mode = DefaultValue.get_value(media.parse_mode)

View file

@ -0,0 +1,82 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2021
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Common base class for media objects"""
from typing import TYPE_CHECKING
from telegram import TelegramObject
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING:
from telegram import Bot, File
class _BaseMedium(TelegramObject):
"""Base class for objects representing the various media file types.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
Args:
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`, optional): File size.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
file_id (:obj:`str`): File identifier.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`): Optional. File size.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
__slots__ = ('bot', 'file_id', 'file_size', 'file_unique_id')
def __init__(
self, file_id: str, file_unique_id: str, file_size: int = None, bot: 'Bot' = None
):
# Required
self.file_id: str = str(file_id)
self.file_unique_id = str(file_unique_id)
# Optionals
self.file_size = file_size
self.bot = bot
self._id_attrs = (self.file_unique_id,)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015-2021
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser Public License for more details.
#
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Common base class for media objects with thumbnails"""
from typing import TYPE_CHECKING, TypeVar, Type, Optional
from telegram import PhotoSize
from telegram._files._basemedium import _BaseMedium
from telegram._utils.types import JSONDict
if TYPE_CHECKING:
from telegram import Bot
ThumbedMT = TypeVar('ThumbedMT', bound='_BaseThumbedMedium', covariant=True)
class _BaseThumbedMedium(_BaseMedium):
"""Base class for objects representing the various media file types that may include a
thumbnail.
Objects of this class are comparable in terms of equality. Two objects of this class are
considered equal, if their :attr:`file_unique_id` is equal.
Args:
file_id (:obj:`str`): Identifier for this file, which can be used to download
or reuse the file.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`, optional): File size.
thumb (:class:`telegram.PhotoSize`, optional): Thumbnail as defined by sender.
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
Attributes:
file_id (:obj:`str`): File identifier.
file_unique_id (:obj:`str`): Unique identifier for this file, which
is supposed to be the same over time and for different bots.
Can't be used to download or reuse the file.
file_size (:obj:`int`): Optional. File size.
thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail as defined by sender.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
"""
__slots__ = ('thumb',)
def __init__(
self,
file_id: str,
file_unique_id: str,
file_size: int = None,
thumb: PhotoSize = None,
bot: 'Bot' = None,
):
super().__init__(
file_id=file_id, file_unique_id=file_unique_id, file_size=file_size, bot=bot
)
self.thumb = thumb
@classmethod
def de_json(cls: Type[ThumbedMT], data: Optional[JSONDict], bot: 'Bot') -> Optional[ThumbedMT]:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)

View file

@ -17,17 +17,16 @@
# You should have received a copy of the GNU Lesser Public License # You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Animation.""" """This module contains an object that represents a Telegram Animation."""
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any
from telegram import PhotoSize, TelegramObject from telegram import PhotoSize
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Animation(TelegramObject): class Animation(_BaseThumbedMedium):
"""This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound). """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -65,18 +64,7 @@ class Animation(TelegramObject):
""" """
__slots__ = ( __slots__ = ('duration', 'height', 'file_name', 'mime_type', 'width')
'bot',
'width',
'file_id',
'file_size',
'file_name',
'thumb',
'duration',
'mime_type',
'height',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -92,45 +80,17 @@ class Animation(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.width = int(width) self.width = int(width)
self.height = int(height) self.height = int(height)
self.duration = duration self.duration = duration
# Optionals # Optional
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_name = file_name
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Animation']:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -18,17 +18,16 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Audio.""" """This module contains an object that represents a Telegram Audio."""
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any
from telegram import PhotoSize, TelegramObject from telegram import PhotoSize
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Audio(TelegramObject): class Audio(_BaseThumbedMedium):
"""This object represents an audio file to be treated as music by the Telegram clients. """This object represents an audio file to be treated as music by the Telegram clients.
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -69,18 +68,7 @@ class Audio(TelegramObject):
""" """
__slots__ = ( __slots__ = ('duration', 'file_name', 'mime_type', 'performer', 'title')
'file_id',
'bot',
'file_size',
'file_name',
'thumb',
'title',
'duration',
'performer',
'mime_type',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -96,45 +84,17 @@ class Audio(TelegramObject):
file_name: str = None, file_name: str = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
)
# Required # Required
self.file_id = str(file_id) self.duration = duration
self.file_unique_id = str(file_unique_id) # Optional
self.duration = int(duration)
# Optionals
self.performer = performer self.performer = performer
self.title = title self.title = title
self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_name = file_name
self.thumb = thumb
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Audio']:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -18,17 +18,16 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Document.""" """This module contains an object that represents a Telegram Document."""
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any
from telegram import PhotoSize, TelegramObject from telegram import PhotoSize
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Document(TelegramObject): class Document(_BaseThumbedMedium):
"""This object represents a general file """This object represents a general file
(as opposed to photos, voice messages and audio files). (as opposed to photos, voice messages and audio files).
@ -60,15 +59,7 @@ class Document(TelegramObject):
""" """
__slots__ = ( __slots__ = ('file_name', 'mime_type')
'bot',
'file_id',
'file_size',
'file_name',
'thumb',
'mime_type',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -81,42 +72,13 @@ class Document(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
# Required super().__init__(
self.file_id = str(file_id) file_id=file_id,
self.file_unique_id = str(file_unique_id) file_unique_id=file_unique_id,
# Optionals file_size=file_size,
self.thumb = thumb thumb=thumb,
self.file_name = file_name bot=bot,
)
# Optional
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_name = file_name
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Document']:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -18,7 +18,7 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram InputMedia Objects.""" """Base class for Telegram InputMedia Objects."""
from typing import Union, List, Tuple from typing import Union, List, Tuple, Optional
from telegram import ( from telegram import (
Animation, Animation,
@ -34,18 +34,59 @@ from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.files import parse_file_input from telegram._utils.files import parse_file_input
from telegram._utils.types import FileInput, JSONDict, ODVInput from telegram._utils.types import FileInput, JSONDict, ODVInput
MediaType = Union[Animation, Audio, Document, PhotoSize, Video]
class InputMedia(TelegramObject): class InputMedia(TelegramObject):
"""Base class for Telegram InputMedia Objects. """
Base class for Telegram InputMedia Objects.
See :class:`telegram.InputMediaAnimation`, :class:`telegram.InputMediaAudio`, .. versionchanged:: 14.0:
:class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto` and Added arguments and attributes :attr:`media_type`, :attr:`media`, :attr:`caption`,
:class:`telegram.InputMediaVideo` for detailed use. :attr:`caption_entities`, :attr:`parse_mode`.
Args:
media_type (:obj:`str`) Type of media that the instance represents.
media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \
:class:`telegram.Animation` | :class:`telegram.Audio` | \
:class:`telegram.Document` | :class:`telegram.PhotoSize` | \
:class:`telegram.Video`):
File to send. Pass a file_id to send a file that exists on the Telegram servers
(recommended), pass an HTTP URL for Telegram to get a file from the Internet.
Lastly you can pass an existing telegram media object of the corresponding type
to send.
caption (:obj:`str`, optional): Caption of the media to be sent, 0-1024 characters
after entities parsing.
caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special
entities that appear in the caption, which can be specified instead of parse_mode.
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width text or inline URLs in the media caption. See the constants
in :class:`telegram.ParseMode` for the available modes.
Attributes:
type (:obj:`str`): Type of the input media.
media (:obj:`str` | :class:`telegram.InputFile`): Media to send.
caption (:obj:`str`): Optional. Caption of the media to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special
entities that appear in the caption.
""" """
__slots__ = () __slots__ = ('caption', 'caption_entities', 'media', 'parse_mode', 'type')
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None
def __init__(
self,
media_type: str,
media: Union[str, InputFile, MediaType],
caption: str = None,
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
parse_mode: ODVInput[str] = DEFAULT_NONE,
):
self.type = media_type
self.media = media
self.caption = caption
self.caption_entities = caption_entities
self.parse_mode = parse_mode
def to_dict(self) -> JSONDict: def to_dict(self) -> JSONDict:
"""See :meth:`telegram.TelegramObject.to_dict`.""" """See :meth:`telegram.TelegramObject.to_dict`."""
@ -58,6 +99,10 @@ class InputMedia(TelegramObject):
return data return data
@staticmethod
def _parse_thumb_input(thumb: Optional[FileInput]) -> Optional[Union[str, InputFile]]:
return parse_file_input(thumb, attach=True) if thumb is not None else thumb
class InputMediaAnimation(InputMedia): class InputMediaAnimation(InputMedia):
"""Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
@ -102,7 +147,7 @@ class InputMediaAnimation(InputMedia):
duration (:obj:`int`, optional): Animation duration. duration (:obj:`int`, optional): Animation duration.
Attributes: Attributes:
type (:obj:`str`): ``animation``. type (:obj:`str`): ``'animation'``.
media (:obj:`str` | :class:`telegram.InputFile`): Animation to send. media (:obj:`str` | :class:`telegram.InputFile`): Animation to send.
caption (:obj:`str`): Optional. Caption of the document to be sent. caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
@ -115,17 +160,7 @@ class InputMediaAnimation(InputMedia):
""" """
__slots__ = ( __slots__ = ('duration', 'height', 'thumb', 'width')
'caption_entities',
'width',
'media',
'thumb',
'caption',
'duration',
'parse_mode',
'height',
'type',
)
def __init__( def __init__(
self, self,
@ -139,29 +174,19 @@ class InputMediaAnimation(InputMedia):
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None, filename: str = None,
): ):
self.type = 'animation'
if isinstance(media, Animation): if isinstance(media, Animation):
self.media: Union[str, InputFile] = media.file_id width = media.width if width is None else width
self.width = media.width height = media.height if height is None else height
self.height = media.height duration = media.duration if duration is None else duration
self.duration = media.duration media = media.file_id
else: else:
self.media = parse_file_input(media, attach=True, filename=filename) media = parse_file_input(media, attach=True, filename=filename)
if thumb: super().__init__('animation', media, caption, caption_entities, parse_mode)
self.thumb = parse_file_input(thumb, attach=True) self.thumb = self._parse_thumb_input(thumb)
self.width = width
if caption: self.height = height
self.caption = caption self.duration = duration
self.parse_mode = parse_mode
self.caption_entities = caption_entities
if width:
self.width = width
if height:
self.height = height
if duration:
self.duration = duration
class InputMediaPhoto(InputMedia): class InputMediaPhoto(InputMedia):
@ -190,7 +215,7 @@ class InputMediaPhoto(InputMedia):
entities that appear in the caption, which can be specified instead of parse_mode. entities that appear in the caption, which can be specified instead of parse_mode.
Attributes: Attributes:
type (:obj:`str`): ``photo``. type (:obj:`str`): ``'photo'``.
media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. media (:obj:`str` | :class:`telegram.InputFile`): Photo to send.
caption (:obj:`str`): Optional. Caption of the document to be sent. caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
@ -199,7 +224,7 @@ class InputMediaPhoto(InputMedia):
""" """
__slots__ = ('caption_entities', 'media', 'caption', 'parse_mode', 'type') __slots__ = ()
def __init__( def __init__(
self, self,
@ -209,13 +234,8 @@ class InputMediaPhoto(InputMedia):
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None, filename: str = None,
): ):
self.type = 'photo' media = parse_file_input(media, PhotoSize, attach=True, filename=filename)
self.media = parse_file_input(media, PhotoSize, attach=True, filename=filename) super().__init__('photo', media, caption, caption_entities, parse_mode)
if caption:
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
class InputMediaVideo(InputMedia): class InputMediaVideo(InputMedia):
@ -226,7 +246,7 @@ class InputMediaVideo(InputMedia):
width, height and duration from that video, unless otherwise specified with the optional width, height and duration from that video, unless otherwise specified with the optional
arguments. arguments.
* ``thumb`` will be ignored for small video files, for which Telegram can easily * ``thumb`` will be ignored for small video files, for which Telegram can easily
generate thumb nails. However, this behaviour is undocumented and might be changed generate thumbnails. However, this behaviour is undocumented and might be changed
by Telegram. by Telegram.
Args: Args:
@ -266,7 +286,7 @@ class InputMediaVideo(InputMedia):
Accept :obj:`bytes` as input. Accept :obj:`bytes` as input.
Attributes: Attributes:
type (:obj:`str`): ``video``. type (:obj:`str`): ``'video'``.
media (:obj:`str` | :class:`telegram.InputFile`): Video file to send. media (:obj:`str` | :class:`telegram.InputFile`): Video file to send.
caption (:obj:`str`): Optional. Caption of the document to be sent. caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
@ -281,18 +301,7 @@ class InputMediaVideo(InputMedia):
""" """
__slots__ = ( __slots__ = ('duration', 'height', 'thumb', 'supports_streaming', 'width')
'caption_entities',
'width',
'media',
'thumb',
'supports_streaming',
'caption',
'duration',
'parse_mode',
'height',
'type',
)
def __init__( def __init__(
self, self,
@ -307,31 +316,21 @@ class InputMediaVideo(InputMedia):
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None, filename: str = None,
): ):
self.type = 'video'
if isinstance(media, Video): if isinstance(media, Video):
self.media: Union[str, InputFile] = media.file_id width = width if width is not None else media.width
self.width = media.width height = height if height is not None else media.height
self.height = media.height duration = duration if duration is not None else media.duration
self.duration = media.duration media = media.file_id
else: else:
self.media = parse_file_input(media, attach=True, filename=filename) media = parse_file_input(media, attach=True, filename=filename)
if thumb: super().__init__('video', media, caption, caption_entities, parse_mode)
self.thumb = parse_file_input(thumb, attach=True) self.width = width
self.height = height
if caption: self.duration = duration
self.caption = caption self.thumb = self._parse_thumb_input(thumb)
self.parse_mode = parse_mode self.supports_streaming = supports_streaming
self.caption_entities = caption_entities
if width:
self.width = width
if height:
self.height = height
if duration:
self.duration = duration
if supports_streaming:
self.supports_streaming = supports_streaming
class InputMediaAudio(InputMedia): class InputMediaAudio(InputMedia):
@ -379,7 +378,7 @@ class InputMediaAudio(InputMedia):
Accept :obj:`bytes` as input. Accept :obj:`bytes` as input.
Attributes: Attributes:
type (:obj:`str`): ``audio``. type (:obj:`str`): ``'audio'``.
media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send. media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send.
caption (:obj:`str`): Optional. Caption of the document to be sent. caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
@ -393,17 +392,7 @@ class InputMediaAudio(InputMedia):
""" """
__slots__ = ( __slots__ = ('duration', 'performer', 'thumb', 'title')
'caption_entities',
'media',
'thumb',
'caption',
'title',
'duration',
'type',
'parse_mode',
'performer',
)
def __init__( def __init__(
self, self,
@ -417,29 +406,19 @@ class InputMediaAudio(InputMedia):
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None, filename: str = None,
): ):
self.type = 'audio'
if isinstance(media, Audio): if isinstance(media, Audio):
self.media: Union[str, InputFile] = media.file_id duration = media.duration if duration is None else duration
self.duration = media.duration performer = media.performer if performer is None else performer
self.performer = media.performer title = media.title if title is None else title
self.title = media.title media = media.file_id
else: else:
self.media = parse_file_input(media, attach=True, filename=filename) media = parse_file_input(media, attach=True, filename=filename)
if thumb: super().__init__('audio', media, caption, caption_entities, parse_mode)
self.thumb = parse_file_input(thumb, attach=True) self.thumb = self._parse_thumb_input(thumb)
self.duration = duration
if caption: self.title = title
self.caption = caption self.performer = performer
self.parse_mode = parse_mode
self.caption_entities = caption_entities
if duration:
self.duration = duration
if performer:
self.performer = performer
if title:
self.title = title
class InputMediaDocument(InputMedia): class InputMediaDocument(InputMedia):
@ -480,7 +459,7 @@ class InputMediaDocument(InputMedia):
the document is sent as part of an album. the document is sent as part of an album.
Attributes: Attributes:
type (:obj:`str`): ``document``. type (:obj:`str`): ``'document'``.
media (:obj:`str` | :class:`telegram.InputFile`): File to send. media (:obj:`str` | :class:`telegram.InputFile`): File to send.
caption (:obj:`str`): Optional. Caption of the document to be sent. caption (:obj:`str`): Optional. Caption of the document to be sent.
parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting.
@ -493,15 +472,7 @@ class InputMediaDocument(InputMedia):
""" """
__slots__ = ( __slots__ = ('disable_content_type_detection', 'thumb')
'caption_entities',
'media',
'thumb',
'caption',
'parse_mode',
'type',
'disable_content_type_detection',
)
def __init__( def __init__(
self, self,
@ -513,14 +484,7 @@ class InputMediaDocument(InputMedia):
caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None,
filename: str = None, filename: str = None,
): ):
self.type = 'document' media = parse_file_input(media, Document, attach=True, filename=filename)
self.media = parse_file_input(media, Document, attach=True, filename=filename) super().__init__('document', media, caption, caption_entities, parse_mode)
self.thumb = self._parse_thumb_input(thumb)
if thumb:
self.thumb = parse_file_input(thumb, attach=True)
if caption:
self.caption = caption
self.parse_mode = parse_mode
self.caption_entities = caption_entities
self.disable_content_type_detection = disable_content_type_detection self.disable_content_type_detection = disable_content_type_detection

View file

@ -20,15 +20,13 @@
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from telegram import TelegramObject from telegram._files._basemedium import _BaseMedium
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class PhotoSize(TelegramObject): class PhotoSize(_BaseMedium):
"""This object represents one size of a photo or a file/sticker thumbnail. """This object represents one size of a photo or a file/sticker thumbnail.
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -58,7 +56,7 @@ class PhotoSize(TelegramObject):
""" """
__slots__ = ('bot', 'width', 'file_id', 'file_size', 'height', 'file_unique_id') __slots__ = ('width', 'height')
def __init__( def __init__(
self, self,
@ -70,29 +68,9 @@ class PhotoSize(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id, file_unique_id=file_unique_id, file_size=file_size, bot=bot
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.width = int(width) self.width = int(width)
self.height = int(height) self.height = int(height)
# Optionals
self.file_size = file_size
self.bot = bot
self._id_attrs = (self.file_unique_id,)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -21,14 +21,14 @@
from typing import TYPE_CHECKING, Any, List, Optional, ClassVar from typing import TYPE_CHECKING, Any, List, Optional, ClassVar
from telegram import PhotoSize, TelegramObject, constants from telegram import PhotoSize, TelegramObject, constants
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput from telegram._utils.types import JSONDict
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Sticker(TelegramObject): class Sticker(_BaseThumbedMedium):
"""This object represents a sticker. """This object represents a sticker.
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -85,18 +85,13 @@ class Sticker(TelegramObject):
""" """
__slots__ = ( __slots__ = (
'bot', 'emoji',
'width', 'height',
'file_id',
'is_animated', 'is_animated',
'is_video', 'is_video',
'file_size',
'thumb',
'set_name',
'mask_position', 'mask_position',
'height', 'set_name',
'file_unique_id', 'width',
'emoji',
) )
def __init__( def __init__(
@ -115,22 +110,22 @@ class Sticker(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.width = int(width) self.width = int(width)
self.height = int(height) self.height = int(height)
self.is_animated = is_animated self.is_animated = is_animated
self.is_video = is_video self.is_video = is_video
# Optionals # Optional
self.thumb = thumb
self.emoji = emoji self.emoji = emoji
self.file_size = file_size
self.set_name = set_name self.set_name = set_name
self.mask_position = mask_position self.mask_position = mask_position
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod @classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']: def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']:
@ -145,22 +140,6 @@ class Sticker(TelegramObject):
return cls(bot=bot, **data) return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)
class StickerSet(TelegramObject): class StickerSet(TelegramObject):
"""This object represents a sticker set. """This object represents a sticker set.
@ -200,13 +179,13 @@ class StickerSet(TelegramObject):
""" """
__slots__ = ( __slots__ = (
'contains_masks',
'is_animated', 'is_animated',
'is_video', 'is_video',
'contains_masks', 'name',
'stickers',
'thumb', 'thumb',
'title', 'title',
'stickers',
'name',
) )
def __init__( def __init__(
@ -226,7 +205,7 @@ class StickerSet(TelegramObject):
self.is_video = is_video self.is_video = is_video
self.contains_masks = contains_masks self.contains_masks = contains_masks
self.stickers = stickers self.stickers = stickers
# Optionals # Optional
self.thumb = thumb self.thumb = thumb
self._id_attrs = (self.name,) self._id_attrs = (self.name,)

View file

@ -61,13 +61,13 @@ class Venue(TelegramObject):
""" """
__slots__ = ( __slots__ = (
'google_place_type',
'location',
'title',
'address', 'address',
'foursquare_type', 'location',
'foursquare_id', 'foursquare_id',
'foursquare_type',
'google_place_id', 'google_place_id',
'google_place_type',
'title',
) )
def __init__( def __init__(

View file

@ -18,17 +18,16 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram Video.""" """This module contains an object that represents a Telegram Video."""
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING, Any
from telegram import PhotoSize, TelegramObject from telegram import PhotoSize
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Video(TelegramObject): class Video(_BaseThumbedMedium):
"""This object represents a video file. """This object represents a video file.
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -66,18 +65,7 @@ class Video(TelegramObject):
""" """
__slots__ = ( __slots__ = ('duration', 'file_name', 'height', 'mime_type', 'width')
'bot',
'width',
'file_id',
'file_size',
'file_name',
'thumb',
'duration',
'mime_type',
'height',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -93,45 +81,17 @@ class Video(TelegramObject):
file_name: str = None, file_name: str = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.width = int(width) self.width = int(width)
self.height = int(height) self.height = int(height)
self.duration = int(duration) self.duration = duration
# Optionals # Optional
self.thumb = thumb
self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_name = file_name
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Video']:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -18,17 +18,16 @@
# along with this program. If not, see [http://www.gnu.org/licenses/]. # along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains an object that represents a Telegram VideoNote.""" """This module contains an object that represents a Telegram VideoNote."""
from typing import TYPE_CHECKING, Optional, Any from typing import TYPE_CHECKING, Any
from telegram import PhotoSize, TelegramObject from telegram import PhotoSize
from telegram._utils.defaultvalue import DEFAULT_NONE from telegram._files._basethumbedmedium import _BaseThumbedMedium
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class VideoNote(TelegramObject): class VideoNote(_BaseThumbedMedium):
"""This object represents a video message (available in Telegram apps as of v.4.0). """This object represents a video message (available in Telegram apps as of v.4.0).
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -61,15 +60,7 @@ class VideoNote(TelegramObject):
""" """
__slots__ = ( __slots__ = ('duration', 'length')
'bot',
'length',
'file_id',
'file_size',
'thumb',
'duration',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -82,42 +73,13 @@ class VideoNote(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
thumb=thumb,
bot=bot,
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.length = int(length) self.length = int(length)
self.duration = int(duration) self.duration = duration
# Optionals
self.thumb = thumb
self.file_size = file_size
self.bot = bot
self._id_attrs = (self.file_unique_id,)
@classmethod
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VideoNote']:
"""See :meth:`telegram.TelegramObject.de_json`."""
data = cls._parse_data(data)
if not data:
return None
data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot)
return cls(bot=bot, **data)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -20,15 +20,13 @@
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from telegram import TelegramObject from telegram._files._basemedium import _BaseMedium
from telegram._utils.defaultvalue import DEFAULT_NONE
from telegram._utils.types import JSONDict, ODVInput
if TYPE_CHECKING: if TYPE_CHECKING:
from telegram import Bot, File from telegram import Bot
class Voice(TelegramObject): class Voice(_BaseMedium):
"""This object represents a voice note. """This object represents a voice note.
Objects of this class are comparable in terms of equality. Two objects of this class are Objects of this class are comparable in terms of equality. Two objects of this class are
@ -58,14 +56,7 @@ class Voice(TelegramObject):
""" """
__slots__ = ( __slots__ = ('duration', 'mime_type')
'bot',
'file_id',
'file_size',
'duration',
'mime_type',
'file_unique_id',
)
def __init__( def __init__(
self, self,
@ -77,29 +68,13 @@ class Voice(TelegramObject):
bot: 'Bot' = None, bot: 'Bot' = None,
**_kwargs: Any, **_kwargs: Any,
): ):
super().__init__(
file_id=file_id,
file_unique_id=file_unique_id,
file_size=file_size,
bot=bot,
)
# Required # Required
self.file_id = str(file_id)
self.file_unique_id = str(file_unique_id)
self.duration = int(duration) self.duration = int(duration)
# Optionals # Optional
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size
self.bot = bot
self._id_attrs = (self.file_unique_id,)
def get_file(
self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None
) -> 'File':
"""Convenience wrapper over :attr:`telegram.Bot.get_file`
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
Returns:
:class:`telegram.File`
Raises:
:class:`telegram.error.TelegramError`
"""
return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs)

View file

@ -159,10 +159,8 @@ class ExtBot(Bot):
) )
# 3) # 3)
elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE: # type: ignore elif isinstance(val, InputMedia) and val.parse_mode is DEFAULT_NONE:
val.parse_mode = ( # type: ignore[attr-defined] val.parse_mode = self.defaults.parse_mode if self.defaults else None
self.defaults.parse_mode if self.defaults else None
)
elif key == 'media' and isinstance(val, list): elif key == 'media' and isinstance(val, list):
for media in val: for media in val:
if media.parse_mode is DEFAULT_NONE: if media.parse_mode is DEFAULT_NONE:

View file

@ -164,6 +164,8 @@ def check_object(h4):
ignored |= {'credentials'} ignored |= {'credentials'}
elif name == 'PassportElementError': elif name == 'PassportElementError':
ignored |= {'message', 'type', 'source'} ignored |= {'message', 'type', 'source'}
elif name == 'InputMedia':
ignored |= {'caption', 'caption_entities', 'media', 'media_type', 'parse_mode'}
elif name.startswith('InputMedia'): elif name.startswith('InputMedia'):
ignored |= {'filename'} # Convenience parameter ignored |= {'filename'} # Convenience parameter