From 05c6ca06f817d0b757493c4341391fcb07e24d54 Mon Sep 17 00:00:00 2001 From: Bibo-Joshi <22366557+Bibo-Joshi@users.noreply.github.com> Date: Thu, 24 Nov 2022 12:09:51 +0100 Subject: [PATCH] Fix Naming and Keyword Arguments of `File.download_*` Methods (#3380) --- examples/conversationbot.py | 2 +- examples/passportbot.py | 10 ++--- telegram/_bot.py | 2 +- telegram/_files/file.py | 75 ++++++++++++++++++++++++++++--------- tests/test_animation.py | 2 +- tests/test_audio.py | 2 +- tests/test_chatphoto.py | 4 +- tests/test_document.py | 2 +- tests/test_file.py | 24 ++++++------ tests/test_inputfile.py | 4 +- tests/test_photo.py | 2 +- tests/test_sticker.py | 2 +- tests/test_video.py | 2 +- tests/test_videonote.py | 2 +- tests/test_voice.py | 2 +- 15 files changed, 88 insertions(+), 49 deletions(-) diff --git a/examples/conversationbot.py b/examples/conversationbot.py index 8daa27da0..84c9accde 100644 --- a/examples/conversationbot.py +++ b/examples/conversationbot.py @@ -81,7 +81,7 @@ async def photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Stores the photo and asks for a location.""" user = update.message.from_user photo_file = await update.message.photo[-1].get_file() - await photo_file.download_to_memory("user_photo.jpg") + await photo_file.download_to_drive("user_photo.jpg") logger.info("Photo of %s: %s", user.first_name, "user_photo.jpg") await update.message.reply_text( "Gorgeous! Now, send me your location please, or send /skip if you don't want to." diff --git a/examples/passportbot.py b/examples/passportbot.py index 9a87a4443..3cb03ef23 100644 --- a/examples/passportbot.py +++ b/examples/passportbot.py @@ -77,25 +77,25 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: for file in data.files: actual_file = await file.get_file() print(actual_file) - await actual_file.download_to_memory() + await actual_file.download_to_drive() if ( data.type in ("passport", "driver_license", "identity_card", "internal_passport") and data.front_side ): front_file = await data.front_side.get_file() print(data.type, front_file) - await front_file.download_to_memory() + await front_file.download_to_drive() if data.type in ("driver_license" and "identity_card") and data.reverse_side: reverse_file = await data.reverse_side.get_file() print(data.type, reverse_file) - await reverse_file.download_to_memory() + await reverse_file.download_to_drive() if ( data.type in ("passport", "driver_license", "identity_card", "internal_passport") and data.selfie ): selfie_file = await data.selfie.get_file() print(data.type, selfie_file) - await selfie_file.download_to_memory() + await selfie_file.download_to_drive() if data.translation and data.type in ( "passport", "driver_license", @@ -111,7 +111,7 @@ async def msg(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: for file in data.translation: actual_file = await file.get_file() print(actual_file) - await actual_file.download_to_memory() + await actual_file.download_to_drive() def main() -> None: diff --git a/telegram/_bot.py b/telegram/_bot.py index 4321796ab..c55baac3c 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -2834,7 +2834,7 @@ class Bot(TelegramObject, AbstractAsyncContextManager): Use this method to get basic info about a file and prepare it for downloading. For the moment, bots can download files of up to :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD` in size. The file can then - be e.g. downloaded with :meth:`telegram.File.download_to_memory`. It is guaranteed that + be e.g. downloaded with :meth:`telegram.File.download_to_drive`. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling get_file again. diff --git a/telegram/_files/file.py b/telegram/_files/file.py index 6ed77969c..4f9176792 100644 --- a/telegram/_files/file.py +++ b/telegram/_files/file.py @@ -36,21 +36,21 @@ if TYPE_CHECKING: class File(TelegramObject): """ This object represents a file ready to be downloaded. The file can be e.g. downloaded with - :attr:`download_to_memory`. It is guaranteed that the link will be valid for at least 1 hour. + :attr:`download_to_drive`. It is guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`. 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. .. versionchanged:: 20.0: - ``download`` was split into :meth:`download_to_memory` and :meth:`download_to_object`. + ``download`` was split into :meth:`download_to_drive` and :meth:`download_to_memory`. Note: * Maximum file size to download is :tg-const:`telegram.constants.FileSizeLimit.FILESIZE_DOWNLOAD`. * If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`, then it will automatically be decrypted as it downloads when you call e.g. - :meth:`download_to_memory`. + :meth:`download_to_drive`. Args: file_id (:obj:`str`): Identifier for this file, which can be used to download @@ -59,7 +59,7 @@ class File(TelegramObject): 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): Optional. File size in bytes, if known. - file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_memory` to get the + file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_drive` to get the file. Attributes: @@ -68,7 +68,7 @@ class File(TelegramObject): 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:`str`): Optional. File size in bytes. - file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_memory` to get + file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_drive` to get the file. """ @@ -114,9 +114,10 @@ class File(TelegramObject): def _prepare_decrypt(self, buf: bytes) -> bytes: return decrypt(b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf) - async def download_to_memory( + async def download_to_drive( self, custom_path: FilePathInput = None, + *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -130,14 +131,13 @@ class File(TelegramObject): Note: If :paramref:`custom_path` isn't provided and :attr:`file_path` is the path of a - local file (which is the case when a Bot API Server is running in local mode), this - method will just return the path. + local file (which is the case when a Bot API Server is running in local mode), this + method will just return the path. The only exception to this are encrypted files (e.g. a passport file). For these, a - file with the prefix `decrypted_` will be created in the same directory as the - original file in order to decrypt the file without changing the existing one - in-place. - + file with the prefix `decrypted_` will be created in the same directory as the + original file in order to decrypt the file without changing the existing one + in-place. .. versionchanged:: 20.0 @@ -145,12 +145,13 @@ class File(TelegramObject): * Returns :class:`pathlib.Path` object in cases where previously a :obj:`str` was returned. * This method was previously called ``download``. It was split into - :meth:`download_to_memory` and :meth:`download_to_object`. - + :meth:`download_to_drive` and :meth:`download_to_memory`. Args: custom_path (:class:`pathlib.Path` | :obj:`str` , optional): The path where the file will be saved to. If not specified, will be saved in the current working directory. + + Keyword Args: read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. @@ -207,9 +208,10 @@ class File(TelegramObject): filename.write_bytes(buf) return filename - async def download_to_object( + async def download_to_memory( self, out: BinaryIO, + *, read_timeout: ODVInput[float] = DEFAULT_NONE, write_timeout: ODVInput[float] = DEFAULT_NONE, connect_timeout: ODVInput[float] = DEFAULT_NONE, @@ -222,10 +224,11 @@ class File(TelegramObject): .. versionadded:: 20.0 - Args: out (:obj:`io.BufferedIOBase`): A file-like object. Must be opened for writing in binary mode. + + Keyword Args: read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. @@ -256,12 +259,42 @@ class File(TelegramObject): buf = self._prepare_decrypt(buf) out.write(buf) - async def download_as_bytearray(self, buf: bytearray = None) -> bytearray: + async def download_as_bytearray( + self, + buf: bytearray = None, + *, + read_timeout: ODVInput[float] = DEFAULT_NONE, + write_timeout: ODVInput[float] = DEFAULT_NONE, + connect_timeout: ODVInput[float] = DEFAULT_NONE, + pool_timeout: ODVInput[float] = DEFAULT_NONE, + ) -> bytearray: """Download this file and return it as a bytearray. Args: buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data. + Keyword Args: + read_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to + :paramref:`telegram.request.BaseRequest.post.read_timeout`. Defaults to + :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. + + .. versionadded:: 20.0 + write_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to + :paramref:`telegram.request.BaseRequest.post.write_timeout`. Defaults to + :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. + + .. versionadded:: 20.0 + connect_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to + :paramref:`telegram.request.BaseRequest.post.connect_timeout`. Defaults to + :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. + + .. versionadded:: 20.0 + pool_timeout (:obj:`float` | :obj:`None`, optional): Value to pass to + :paramref:`telegram.request.BaseRequest.post.pool_timeout`. Defaults to + :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. + + .. versionadded:: 20.0 + Returns: :obj:`bytearray`: The same object as :paramref:`buf` if it was specified. Otherwise a newly allocated :obj:`bytearray`. @@ -273,7 +306,13 @@ class File(TelegramObject): if is_local_file(self.file_path): bytes_data = Path(self.file_path).read_bytes() else: - bytes_data = await self.get_bot().request.retrieve(self._get_encoded_url()) + bytes_data = await self.get_bot().request.retrieve( + self._get_encoded_url(), + read_timeout=read_timeout, + write_timeout=write_timeout, + connect_timeout=connect_timeout, + pool_timeout=pool_timeout, + ) if self._credentials: buf.extend(self._prepare_decrypt(bytes_data)) else: diff --git a/tests/test_animation.py b/tests/test_animation.py index 059fd43a9..c0d7c540d 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -128,7 +128,7 @@ class TestAnimation: assert new_file.file_id == animation.file_id assert new_file.file_path.startswith("https://") - new_filepath = await new_file.download_to_memory("game.gif") + new_filepath = await new_file.download_to_drive("game.gif") assert new_filepath.is_file() diff --git a/tests/test_audio.py b/tests/test_audio.py index 1e22d49d4..be61f7e5a 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -143,7 +143,7 @@ class TestAudio: assert new_file.file_unique_id == audio.file_unique_id assert str(new_file.file_path).startswith("https://") - await new_file.download_to_memory("telegram.mp3") + await new_file.download_to_drive("telegram.mp3") assert path.is_file() diff --git a/tests/test_chatphoto.py b/tests/test_chatphoto.py index 4b97a78e7..fd738647d 100644 --- a/tests/test_chatphoto.py +++ b/tests/test_chatphoto.py @@ -85,7 +85,7 @@ class TestChatPhoto: assert new_file.file_unique_id == chat_photo.small_file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory(jpg_file) + await new_file.download_to_drive(jpg_file) assert jpg_file.is_file() @@ -94,7 +94,7 @@ class TestChatPhoto: assert new_file.file_unique_id == chat_photo.big_file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory(jpg_file) + await new_file.download_to_drive(jpg_file) assert jpg_file.is_file() diff --git a/tests/test_document.py b/tests/test_document.py index c69f5b074..97941efc1 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -118,7 +118,7 @@ class TestDocument: assert new_file.file_unique_id == document.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory("telegram.png") + await new_file.download_to_drive("telegram.png") assert path.is_file() diff --git a/tests/test_file.py b/tests/test_file.py index 02d2f176c..618ad7a58 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -132,7 +132,7 @@ class TestFile: return self.file_content monkeypatch.setattr(file.get_bot().request, "retrieve", test) - out_file = await file.download_to_memory() + out_file = await file.download_to_drive() try: assert out_file.read_bytes() == self.file_content @@ -140,7 +140,7 @@ class TestFile: out_file.unlink() async def test_download_local_file(self, local_file): - assert await local_file.download_to_memory() == Path(local_file.file_path) + assert await local_file.download_to_drive() == Path(local_file.file_path) @pytest.mark.parametrize( "custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"] @@ -153,7 +153,7 @@ class TestFile: file_handle, custom_path = mkstemp() custom_path = Path(custom_path) try: - out_file = await file.download_to_memory(custom_path_type(custom_path)) + out_file = await file.download_to_drive(custom_path_type(custom_path)) assert out_file == custom_path assert out_file.read_bytes() == self.file_content finally: @@ -167,7 +167,7 @@ class TestFile: file_handle, custom_path = mkstemp() custom_path = Path(custom_path) try: - out_file = await local_file.download_to_memory(custom_path_type(custom_path)) + out_file = await local_file.download_to_drive(custom_path_type(custom_path)) assert out_file == custom_path assert out_file.read_bytes() == self.file_content finally: @@ -181,7 +181,7 @@ class TestFile: file.file_path = None monkeypatch.setattr(file.get_bot().request, "retrieve", test) - out_file = await file.download_to_memory() + out_file = await file.download_to_drive() assert str(out_file)[-len(file.file_id) :] == file.file_id try: @@ -195,13 +195,13 @@ class TestFile: monkeypatch.setattr(file.get_bot().request, "retrieve", test) with TemporaryFile() as custom_fobj: - await file.download_to_object(out=custom_fobj) + await file.download_to_memory(out=custom_fobj) custom_fobj.seek(0) assert custom_fobj.read() == self.file_content async def test_download_file_obj_local_file(self, local_file): with TemporaryFile() as custom_fobj: - await local_file.download_to_object(out=custom_fobj) + await local_file.download_to_memory(out=custom_fobj) custom_fobj.seek(0) assert custom_fobj.read() == self.file_content @@ -239,7 +239,7 @@ class TestFile: return data_file("image_encrypted.jpg").read_bytes() monkeypatch.setattr(encrypted_file.get_bot().request, "retrieve", test) - out_file = await encrypted_file.download_to_memory() + out_file = await encrypted_file.download_to_drive() try: assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() @@ -252,12 +252,12 @@ class TestFile: monkeypatch.setattr(encrypted_file.get_bot().request, "retrieve", test) with TemporaryFile() as custom_fobj: - await encrypted_file.download_to_object(out=custom_fobj) + await encrypted_file.download_to_memory(out=custom_fobj) custom_fobj.seek(0) assert custom_fobj.read() == data_file("image_decrypted.jpg").read_bytes() async def test_download_local_file_encrypted(self, encrypted_local_file): - out_file = await encrypted_local_file.download_to_memory() + out_file = await encrypted_local_file.download_to_drive() try: assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() finally: @@ -272,7 +272,7 @@ class TestFile: file_handle, custom_path = mkstemp() custom_path = Path(custom_path) try: - out_file = await encrypted_local_file.download_to_memory(custom_path_type(custom_path)) + out_file = await encrypted_local_file.download_to_drive(custom_path_type(custom_path)) assert out_file == custom_path assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() finally: @@ -285,7 +285,7 @@ class TestFile: monkeypatch.setattr(encrypted_local_file.get_bot().request, "retrieve", test) with TemporaryFile() as custom_fobj: - await encrypted_local_file.download_to_object(out=custom_fobj) + await encrypted_local_file.download_to_memory(out=custom_fobj) custom_fobj.seek(0) assert custom_fobj.read() == data_file("image_decrypted.jpg").read_bytes() diff --git a/tests/test_inputfile.py b/tests/test_inputfile.py index 4f8d33a4c..1de2f4e47 100644 --- a/tests/test_inputfile.py +++ b/tests/test_inputfile.py @@ -145,7 +145,7 @@ class TestInputFile: message = await bot.send_document(chat_id, data_file("text_file.txt").read_bytes()) out = BytesIO() - await (await message.document.get_file()).download_to_object(out=out) + await (await message.document.get_file()).download_to_memory(out=out) out.seek(0) assert out.read().decode("utf-8") == "PTB Rocks! ⅞" @@ -158,7 +158,7 @@ class TestInputFile: ) out = BytesIO() - await (await message.document.get_file()).download_to_object(out=out) + await (await message.document.get_file()).download_to_memory(out=out) out.seek(0) assert out.read().decode("utf-8") == "PTB Rocks! ⅞" diff --git a/tests/test_photo.py b/tests/test_photo.py index 188d1cc74..d5123d9af 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -303,7 +303,7 @@ class TestPhoto: assert new_file.file_unique_id == photo.file_unique_id assert new_file.file_path.startswith("https://") is True - await new_file.download_to_memory("telegram.jpg") + await new_file.download_to_drive("telegram.jpg") assert path.is_file() diff --git a/tests/test_sticker.py b/tests/test_sticker.py index 9601d6d3c..a6e8f0472 100644 --- a/tests/test_sticker.py +++ b/tests/test_sticker.py @@ -168,7 +168,7 @@ class TestSticker: assert new_file.file_unique_id == sticker.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory("telegram.webp") + await new_file.download_to_drive("telegram.webp") assert path.is_file() diff --git a/tests/test_video.py b/tests/test_video.py index 27f0b7ff0..6cba61603 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -148,7 +148,7 @@ class TestVideo: assert new_file.file_unique_id == video.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory("telegram.mp4") + await new_file.download_to_drive("telegram.mp4") assert path.is_file() diff --git a/tests/test_videonote.py b/tests/test_videonote.py index 2f227fc1b..44855dd28 100644 --- a/tests/test_videonote.py +++ b/tests/test_videonote.py @@ -132,7 +132,7 @@ class TestVideoNote: assert new_file.file_unique_id == video_note.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory("telegram2.mp4") + await new_file.download_to_drive("telegram2.mp4") assert path.is_file() diff --git a/tests/test_voice.py b/tests/test_voice.py index 10b1c7049..17024860c 100644 --- a/tests/test_voice.py +++ b/tests/test_voice.py @@ -120,7 +120,7 @@ class TestVoice: assert new_file.file_unique_id == voice.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download_to_memory("telegram.ogg") + await new_file.download_to_drive("telegram.ogg") assert path.is_file()