diff --git a/examples/conversationbot.py b/examples/conversationbot.py index a323ab8c1..cb5e5d282 100644 --- a/examples/conversationbot.py +++ b/examples/conversationbot.py @@ -23,7 +23,7 @@ try: except ImportError: __version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment] -if __version_info__ < (20, 0, 0, "alpha", 1): +if __version_info__ < (20, 0, 0, "beta", 0): raise RuntimeError( f"This example is not compatible with your current PTB version {TG_VER}. To view the " f"{TG_VER} version of this example, " @@ -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("user_photo.jpg") + await photo_file.download_to_memory("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 ab466f669..8dd8dfa64 100644 --- a/examples/passportbot.py +++ b/examples/passportbot.py @@ -21,7 +21,7 @@ try: except ImportError: __version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment] -if __version_info__ < (20, 0, 0, "alpha", 1): +if __version_info__ < (20, 0, 0, "beta", 0): raise RuntimeError( f"This example is not compatible with your current PTB version {TG_VER}. To view the " f"{TG_VER} version of this example, " @@ -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() + await actual_file.download_to_memory() 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() + await front_file.download_to_memory() 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() + await reverse_file.download_to_memory() 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() + await selfie_file.download_to_memory() 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() + await actual_file.download_to_memory() def main() -> None: diff --git a/telegram/_bot.py b/telegram/_bot.py index 6cbcf254a..9d57c18e7 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -3100,10 +3100,9 @@ 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 downloaded - with :meth:`telegram.File.download`. 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. + be e.g. downloaded with :meth:`telegram.File.download_to_memory`. 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. Note: This function may not preserve the original file name and MIME type. diff --git a/telegram/_files/file.py b/telegram/_files/file.py index 1ee3adabc..6ed77969c 100644 --- a/telegram/_files/file.py +++ b/telegram/_files/file.py @@ -21,7 +21,7 @@ import shutil import urllib.parse as urllib_parse from base64 import b64decode from pathlib import Path -from typing import IO, TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, BinaryIO, Optional from telegram._passport.credentials import decrypt from telegram._telegramobject import TelegramObject @@ -35,18 +35,22 @@ if TYPE_CHECKING: class File(TelegramObject): """ - This object represents a file ready to be downloaded. The file can be downloaded with - :attr:`download`. 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`. + 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. + 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`. + 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 :meth:`download()`. + then it will automatically be decrypted as it downloads when you call e.g. + :meth:`download_to_memory`. Args: file_id (:obj:`str`): Identifier for this file, which can be used to download @@ -55,7 +59,8 @@ 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 :attr:`download` to get the file. + file_path (:obj:`str`, optional): File path. Use e.g. :meth:`download_to_memory` to get the + file. Attributes: file_id (:obj:`str`): Identifier for this file. @@ -63,8 +68,8 @@ 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 :meth:`download` to get the file. - + file_path (:obj:`str`): Optional. File path. Use e.g. :meth:`download_to_memory` to get + the file. """ __slots__ = ( @@ -97,38 +102,55 @@ class File(TelegramObject): self._id_attrs = (self.file_unique_id,) - async def download( + def _get_encoded_url(self) -> str: + """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string.""" + sres = urllib_parse.urlsplit(str(self.file_path)) + return urllib_parse.urlunsplit( + urllib_parse.SplitResult( + sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment + ) + ) + + def _prepare_decrypt(self, buf: bytes) -> bytes: + return decrypt(b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf) + + async def download_to_memory( self, custom_path: FilePathInput = None, - out: IO = 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, - ) -> Union[Path, IO]: + ) -> Path: """ Download this file. By default, the file is saved in the current working directory with its - original filename as reported by Telegram. If the file has no filename, it the file ID will - be used as filename. If a :paramref:`custom_path` is supplied, it will be saved to that - path instead. If :paramref:`out` is defined, the file contents will be saved to that object - using the :obj:`out.write` method. + original filename as reported by Telegram. If the file has no filename, the file ID will + be used as filename. If :paramref:`custom_path` is supplied as a :obj:`str` or + :obj:`pathlib.Path`, it will be saved to that path. Note: - * :paramref:`custom_path` and :paramref:`out` are mutually exclusive. - * If neither :paramref:`custom_path` nor :paramref:`out` is 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. + 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. + + 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. + .. versionchanged:: 20.0 * :paramref:`custom_path` parameter now also accepts :class:`pathlib.Path` as argument. * 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`. + Args: - custom_path (:class:`pathlib.Path` | :obj:`str`, optional): Custom path. - out (:obj:`io.BufferedWriter`, optional): A file-like object. Must be opened for - writing in binary mode, if applicable. + 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. 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`. @@ -143,32 +165,22 @@ class File(TelegramObject): :attr:`~telegram.request.BaseRequest.DEFAULT_NONE`. Returns: - :class:`pathlib.Path` | :obj:`io.BufferedWriter`: The same object as :paramref:`out` if - specified. Otherwise, returns the filename downloaded to or the file path of the - local file. - - Raises: - ValueError: If both :paramref:`custom_path` and :paramref:`out` are passed. + :class:`pathlib.Path`: Returns the Path object the file was downloaded to. """ - if custom_path is not None and out is not None: - raise ValueError("`custom_path` and `out` are mutually exclusive") - local_file = is_local_file(self.file_path) url = None if local_file else self._get_encoded_url() - path = Path(self.file_path) if local_file else None - if out: - if local_file: - buf = path.read_bytes() + # if _credentials exists we want to decrypt the file + if local_file and self._credentials: + file_to_decrypt = Path(self.file_path) + buf = self._prepare_decrypt(file_to_decrypt.read_bytes()) + if custom_path is not None: + path = Path(custom_path) else: - buf = await self.get_bot().request.retrieve(url) - if self._credentials: - buf = decrypt( - b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf - ) - out.write(buf) - return out + path = Path(str(file_to_decrypt.parent) + "/decrypted_" + file_to_decrypt.name) + path.write_bytes(buf) + return path if custom_path is not None and local_file: shutil.copyfile(self.file_path, str(custom_path)) @@ -191,20 +203,58 @@ class File(TelegramObject): pool_timeout=pool_timeout, ) if self._credentials: - buf = decrypt( - b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf - ) + buf = self._prepare_decrypt(buf) filename.write_bytes(buf) return filename - def _get_encoded_url(self) -> str: - """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string.""" - sres = urllib_parse.urlsplit(str(self.file_path)) - return urllib_parse.urlunsplit( - urllib_parse.SplitResult( - sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment + async def download_to_object( + self, + out: BinaryIO, + read_timeout: ODVInput[float] = DEFAULT_NONE, + write_timeout: ODVInput[float] = DEFAULT_NONE, + connect_timeout: ODVInput[float] = DEFAULT_NONE, + pool_timeout: ODVInput[float] = DEFAULT_NONE, + ) -> None: + """ + Download this file into memory. :paramref:`out` needs to be supplied with a + :obj:`io.BufferedIOBase`, the file contents will be saved to that object using the + :obj:`out.write` method. + + .. versionadded:: 20.0 + + + Args: + out (:obj:`io.BufferedIOBase`): A file-like object. Must be opened for writing in + binary mode. + 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`. + 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`. + 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`. + 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`. + """ + local_file = is_local_file(self.file_path) + url = None if local_file else self._get_encoded_url() + path = Path(self.file_path) if local_file else None + if local_file: + buf = path.read_bytes() + else: + buf = await self.get_bot().request.retrieve( + url, + read_timeout=read_timeout, + write_timeout=write_timeout, + connect_timeout=connect_timeout, + pool_timeout=pool_timeout, ) - ) + if self._credentials: + buf = self._prepare_decrypt(buf) + out.write(buf) async def download_as_bytearray(self, buf: bytearray = None) -> bytearray: """Download this file and return it as a bytearray. @@ -219,10 +269,15 @@ class File(TelegramObject): """ if buf is None: buf = bytearray() + if is_local_file(self.file_path): - buf.extend(Path(self.file_path).read_bytes()) + bytes_data = Path(self.file_path).read_bytes() else: - buf.extend(await self.get_bot().request.retrieve(self._get_encoded_url())) + bytes_data = await self.get_bot().request.retrieve(self._get_encoded_url()) + if self._credentials: + buf.extend(self._prepare_decrypt(bytes_data)) + else: + buf.extend(bytes_data) return buf def set_credentials(self, credentials: "FileCredentials") -> None: diff --git a/tests/data/image_decrypted.jpg b/tests/data/image_decrypted.jpg new file mode 100644 index 000000000..4ee9244c6 Binary files /dev/null and b/tests/data/image_decrypted.jpg differ diff --git a/tests/data/image_encrypted.jpg b/tests/data/image_encrypted.jpg new file mode 100644 index 000000000..d23371f2a Binary files /dev/null and b/tests/data/image_encrypted.jpg differ diff --git a/tests/test_animation.py b/tests/test_animation.py index 0e0d46790..eda6a2fbc 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -129,7 +129,7 @@ class TestAnimation: assert new_file.file_id == animation.file_id assert new_file.file_path.startswith("https://") - new_filepath = await new_file.download("game.gif") + new_filepath = await new_file.download_to_memory("game.gif") assert new_filepath.is_file() diff --git a/tests/test_audio.py b/tests/test_audio.py index eea5a66ab..e8bd39fce 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -144,7 +144,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("telegram.mp3") + await new_file.download_to_memory("telegram.mp3") assert path.is_file() diff --git a/tests/test_chatphoto.py b/tests/test_chatphoto.py index ff64dcb83..1b57381a8 100644 --- a/tests/test_chatphoto.py +++ b/tests/test_chatphoto.py @@ -86,7 +86,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(jpg_file) + await new_file.download_to_memory(jpg_file) assert jpg_file.is_file() @@ -95,7 +95,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(jpg_file) + await new_file.download_to_memory(jpg_file) assert jpg_file.is_file() diff --git a/tests/test_document.py b/tests/test_document.py index 4a9dbcc89..fca4bc9f1 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -119,7 +119,7 @@ class TestDocument: assert new_file.file_unique_id == document.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download("telegram.png") + await new_file.download_to_memory("telegram.png") assert path.is_file() diff --git a/tests/test_file.py b/tests/test_file.py index ea11b4134..10ef115b6 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -23,7 +23,7 @@ from tempfile import TemporaryFile, mkstemp import pytest from flaky import flaky -from telegram import File, Voice +from telegram import File, FileCredentials, Voice from telegram.error import TelegramError from tests.conftest import data_file @@ -40,6 +40,39 @@ def file(bot): return file +@pytest.fixture(scope="class") +def encrypted_file(bot): + # check https://github.com/python-telegram-bot/python-telegram-bot/wiki/\ + # PTB-test-writing-knowledge-base#how-to-generate-encrypted-passport-files + # if you want to know the source of these values + fc = FileCredentials( + "Oq3G4sX+bKZthoyms1YlPqvWou9esb+z0Bi/KqQUG8s=", + "Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=", + ) + ef = File(TestFile.file_id, TestFile.file_unique_id, TestFile.file_size, TestFile.file_path) + ef.set_bot(bot) + ef.set_credentials(fc) + return ef + + +@pytest.fixture(scope="class") +def encrypted_local_file(bot): + # check encrypted_file() for the source of the fc values + fc = FileCredentials( + "Oq3G4sX+bKZthoyms1YlPqvWou9esb+z0Bi/KqQUG8s=", + "Pt7fKPgYWKA/7a8E64Ea1X8C+Wf7Ky1tF4ANBl63vl4=", + ) + ef = File( + TestFile.file_id, + TestFile.file_unique_id, + TestFile.file_size, + file_path=str(data_file("image_encrypted.jpg")), + ) + ef.set_bot(bot) + ef.set_credentials(fc) + return ef + + @pytest.fixture(scope="class") def local_file(bot): file = File( @@ -95,16 +128,12 @@ class TestFile: with pytest.raises(TelegramError): await bot.get_file(file_id="") - async def test_download_mutually_exclusive(self, file): - with pytest.raises(ValueError, match="`custom_path` and `out` are mutually exclusive"): - await file.download("custom_path", "out") - async def test_download(self, monkeypatch, file): async def test(*args, **kwargs): return self.file_content monkeypatch.setattr(file.get_bot().request, "retrieve", test) - out_file = await file.download() + out_file = await file.download_to_memory() try: assert out_file.read_bytes() == self.file_content @@ -112,7 +141,7 @@ class TestFile: out_file.unlink() async def test_download_local_file(self, local_file): - assert await local_file.download() == Path(local_file.file_path) + assert await local_file.download_to_memory() == Path(local_file.file_path) @pytest.mark.parametrize( "custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"] @@ -125,7 +154,7 @@ class TestFile: file_handle, custom_path = mkstemp() custom_path = Path(custom_path) try: - out_file = await file.download(custom_path_type(custom_path)) + out_file = await file.download_to_memory(custom_path_type(custom_path)) assert out_file == custom_path assert out_file.read_bytes() == self.file_content finally: @@ -139,7 +168,7 @@ class TestFile: file_handle, custom_path = mkstemp() custom_path = Path(custom_path) try: - out_file = await local_file.download(custom_path_type(custom_path)) + out_file = await local_file.download_to_memory(custom_path_type(custom_path)) assert out_file == custom_path assert out_file.read_bytes() == self.file_content finally: @@ -153,7 +182,7 @@ class TestFile: file.file_path = None monkeypatch.setattr(file.get_bot().request, "retrieve", test) - out_file = await file.download() + out_file = await file.download_to_memory() assert str(out_file)[-len(file.file_id) :] == file.file_id try: @@ -167,19 +196,15 @@ class TestFile: monkeypatch.setattr(file.get_bot().request, "retrieve", test) with TemporaryFile() as custom_fobj: - out_fobj = await file.download(out=custom_fobj) - assert out_fobj is custom_fobj - - out_fobj.seek(0) - assert out_fobj.read() == self.file_content + await file.download_to_object(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: - out_fobj = await local_file.download(out=custom_fobj) - assert out_fobj is custom_fobj - - out_fobj.seek(0) - assert out_fobj.read() == self.file_content + await local_file.download_to_object(out=custom_fobj) + custom_fobj.seek(0) + assert custom_fobj.read() == self.file_content async def test_download_bytearray(self, monkeypatch, file): async def test(*args, **kwargs): @@ -210,6 +235,90 @@ class TestFile: assert buf2[len(buf) :] == buf assert buf2[: len(buf)] == buf + async def test_download_encrypted(self, monkeypatch, bot, encrypted_file): + async def test(*args, **kwargs): + 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() + + try: + assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() + finally: + out_file.unlink() + + async def test_download_file_obj_encrypted(self, monkeypatch, encrypted_file): + async def test(*args, **kwargs): + return data_file("image_encrypted.jpg").read_bytes() + + monkeypatch.setattr(encrypted_file.get_bot().request, "retrieve", test) + with TemporaryFile() as custom_fobj: + await encrypted_file.download_to_object(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() + try: + assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() + finally: + out_file.unlink() + + @pytest.mark.parametrize( + "custom_path_type", [str, Path], ids=["str custom_path", "pathlib.Path custom_path"] + ) + async def test_download_custom_path_local_file_encrypted( + self, encrypted_local_file, custom_path_type + ): + 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)) + assert out_file == custom_path + assert out_file.read_bytes() == data_file("image_decrypted.jpg").read_bytes() + finally: + os.close(file_handle) + custom_path.unlink() + + async def test_download_file_obj_local_file_encrypted(self, monkeypatch, encrypted_local_file): + async def test(*args, **kwargs): + return data_file("image_encrypted.jpg").read_bytes() + + 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) + custom_fobj.seek(0) + assert custom_fobj.read() == data_file("image_decrypted.jpg").read_bytes() + + async def test_download_bytearray_encrypted(self, monkeypatch, encrypted_file): + async def test(*args, **kwargs): + return data_file("image_encrypted.jpg").read_bytes() + + monkeypatch.setattr(encrypted_file.get_bot().request, "retrieve", test) + + # Check that a download to a newly allocated bytearray works. + buf = await encrypted_file.download_as_bytearray() + assert buf == bytearray(data_file("image_decrypted.jpg").read_bytes()) + + # Check that a download to a given bytearray works (extends the bytearray). + buf2 = buf[:] + buf3 = await encrypted_file.download_as_bytearray(buf=buf2) + assert buf3 is buf2 + assert buf2[len(buf) :] == buf + assert buf2[: len(buf)] == buf + + async def test_download_bytearray_local_file_encrypted(self, encrypted_local_file): + # Check that a download to a newly allocated bytearray works. + buf = await encrypted_local_file.download_as_bytearray() + assert buf == bytearray(data_file("image_decrypted.jpg").read_bytes()) + + # Check that a download to a given bytearray works (extends the bytearray). + buf2 = buf[:] + buf3 = await encrypted_local_file.download_as_bytearray(buf=buf2) + assert buf3 is buf2 + assert buf2[len(buf) :] == buf + assert buf2[: len(buf)] == buf + def test_equality(self, bot): a = File(self.file_id, self.file_unique_id, bot) b = File("", self.file_unique_id, bot) diff --git a/tests/test_inputfile.py b/tests/test_inputfile.py index adc0575f3..4f8d33a4c 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() - assert await (await message.document.get_file()).download(out=out) + await (await message.document.get_file()).download_to_object(out=out) out.seek(0) assert out.read().decode("utf-8") == "PTB Rocks! ⅞" @@ -158,7 +158,7 @@ class TestInputFile: ) out = BytesIO() - assert await (await message.document.get_file()).download(out=out) + await (await message.document.get_file()).download_to_object(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 ebaff6f33..f478d58a2 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -304,7 +304,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("telegram.jpg") + await new_file.download_to_memory("telegram.jpg") assert path.is_file() diff --git a/tests/test_sticker.py b/tests/test_sticker.py index 3e33cf522..80741f101 100644 --- a/tests/test_sticker.py +++ b/tests/test_sticker.py @@ -169,7 +169,7 @@ class TestSticker: assert new_file.file_unique_id == sticker.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download("telegram.webp") + await new_file.download_to_memory("telegram.webp") assert path.is_file() diff --git a/tests/test_video.py b/tests/test_video.py index 284bbe7b5..c3b7fc099 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -149,7 +149,7 @@ class TestVideo: assert new_file.file_unique_id == video.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download("telegram.mp4") + await new_file.download_to_memory("telegram.mp4") assert path.is_file() diff --git a/tests/test_videonote.py b/tests/test_videonote.py index d5eb7ac36..ca51fe286 100644 --- a/tests/test_videonote.py +++ b/tests/test_videonote.py @@ -133,7 +133,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("telegram2.mp4") + await new_file.download_to_memory("telegram2.mp4") assert path.is_file() diff --git a/tests/test_voice.py b/tests/test_voice.py index e7e0bf61e..d617472db 100644 --- a/tests/test_voice.py +++ b/tests/test_voice.py @@ -121,7 +121,7 @@ class TestVoice: assert new_file.file_unique_id == voice.file_unique_id assert new_file.file_path.startswith("https://") - await new_file.download("telegram.ogg") + await new_file.download_to_memory("telegram.ogg") assert path.is_file()