Example #1
0
    def _download_gif(self,
                      file: telegram.File,
                      channel_id: str = "") -> Tuple[IO[bytes], str, str, str]:
        """
        Download and convert GIF image.

        Args:
            file: Telegram File object
            channel_id: Destination channel ID of the message

        Returns:
            Tuple[IO[bytes], str, str, str]:
                ``tempfile`` file-like object, MIME type, proposed file name
        """
        file, _, filename, path = self._download_file(file, 'video/mpeg')
        gif_file = tempfile.NamedTemporaryFile(suffix='.gif')
        v = VideoFileClip(path)
        self.logger.info(
            "Convert Telegram MP4 to GIF from "
            "channel %s with size %s", channel_id, v.size)
        if channel_id == "blueset.wechat" and v.size[0] > 600:
            # Workaround: Compress GIF for slave channel `blueset.wechat`
            # TODO: Move this logic to `blueset.wechat` in the future
            subprocess.Popen([
                "ffmpeg", "-y", "-i", path, '-vf', "scale=600:-2",
                gif_file.name
            ],
                             bufsize=0).wait()
        else:
            v.write_gif(gif_file.name, program="ffmpeg")
        file.close()
        gif_file.seek(0)
        return gif_file, "image/gif", os.path.basename(
            gif_file.name), gif_file.name
Example #2
0
    def get_text_from_image(image_file: File) -> str:
        """Get text from image with google vision api"""

        # Get temp file path with tempfile library
        fd, temp_file_path = tempfile.mkstemp()

        # Download image
        image_file.download(temp_file_path)

        # Read image file as binary
        with open(temp_file_path, "rb") as image_file:
            content = image_file.read()

        # Create vision.Image object to use it in document_text_detection function
        image = vision.Image(content=content)

        # Get response from google vision api
        # client field will be add to function in telegram_bot.py script
        response = Ocr.client.document_text_detection(image=image)

        # Get text from response
        text = response.full_text_annotation.text

        # Close file, automatic deletion will occur
        os.close(fd)

        # Return text
        return text
Example #3
0
    def make_assertion(_, data, timeout=DEFAULT_NONE, df_value=DEFAULT_NONE):
        expected_timeout = method_timeout if df_value == DEFAULT_NONE else df_value
        if timeout != expected_timeout:
            pytest.fail(
                f'Got value {timeout} for "timeout", expected {expected_timeout}'
            )

        for arg in (dkw for dkw in kwargs_need_default if dkw != 'timeout'):
            # 'None' should not be passed along to Telegram
            if df_value in [None, DEFAULT_NONE]:
                if arg in data:
                    pytest.fail(
                        f'Got value {data[arg]} for argument {arg}, expected it to be absent'
                    )
            else:
                value = data.get(arg, '`not passed at all`')
                if value != df_value:
                    pytest.fail(
                        f'Got value {value} for argument {arg} instead of {df_value}'
                    )

        if method.__name__ in ['get_file', 'get_small_file', 'get_big_file']:
            # This is here mainly for PassportFile.get_file, which calls .set_credentials on the
            # return value
            out = File(file_id='result', file_unique_id='result')
            nonlocal expected_return_values
            expected_return_values = [out]
            return out.to_dict()
        # Otherwise return None by default, as TGObject.de_json/list(None) in [None, []]
        # That way we can check what gets passed to Request.post without having to actually
        # make a request
        # Some methods expect specific output, so we allow to customize that
        return return_value
Example #4
0
def get_file(file: telegram.File) -> BytesIO:
    attachment = BytesIO()
    attachment.name = str(uuid.uuid4()) + '.' + path.splitext(file.file_path)[1]

    file.download(out=attachment)
    attachment.seek(0, 0)

    return attachment
Example #5
0
    def getFile(self, file_id, **kwargs):
        """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 20MB in
        size.

        Args:
          file_id:
            File identifier to get info about.

        Keyword Args:
            timeout (Optional[float]): If this value is specified, use it as
                the definitive timeout (in seconds) for urlopen() operations.

        Returns:
            :class:`telegram.File`: On success, a :class:`telegram.File`
            object is returned.

        Raises:
            :class:`telegram.TelegramError`

        """

        url = '{0}/getFile'.format(self.base_url)

        data = {'file_id': file_id}

        result = request.post(url, data, timeout=kwargs.get('timeout'))

        if result.get('file_path'):
            result['file_path'] = '%s/%s' % (self.base_file_url,
                                             result['file_path'])

        return File.de_json(result)
Example #6
0
    def getFile(self, file_id, **kwargs):
        """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 20MB in
        size.

        Args:
          file_id:
            File identifier to get info about.

        Keyword Args:
            timeout (Optional[float]): If this value is specified, use it as
                the definitive timeout (in seconds) for urlopen() operations.

        Returns:
            :class:`telegram.File`: On success, a :class:`telegram.File`
            object is returned.

        Raises:
            :class:`telegram.TelegramError`

        """

        url = '{0}/getFile'.format(self.base_url)

        data = {'file_id': file_id}

        result = request.post(url, data, timeout=kwargs.get('timeout'))

        if result.get('file_path'):
            result['file_path'] = '%s/%s' % (self.base_file_url, result['file_path'])

        return File.de_json(result)
Example #7
0
    def getFile(self,
                file_id):
        """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 20MB in
        size.

        Args:
          file_id:
            File identifier to get info about.

        Returns:
          Returns a telegram.File object
        """

        url = '%s/getFile' % self.base_url

        data = {'file_id': file_id}

        result = request.post(url, data)

        if result.get('file_path'):
            result['file_path'] = '%s/%s' % (self.base_file_url,
                                             result['file_path'])

        return File.de_json(result)
Example #8
0
    def getFile(self,
                file_id):
        """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 20MB in
        size.

        Args:
          file_id:
            File identifier to get info about.

        Returns:
          Returns a telegram.File object
        """

        url = '%s/getFile' % self.base_url

        data = {'file_id': file_id}

        result = request.post(url, data)

        if result.get('file_path'):
            result['file_path'] = '%s/%s' % (self.base_file_url,
                                             result['file_path'])

        return File.de_json(result)
Example #9
0
def local_file(bot):
    return File(
        TestFile.file_id,
        TestFile.file_unique_id,
        file_path=str(data_file("local_file.txt")),
        file_size=TestFile.file_size,
        bot=bot,
    )
def file(bot):
    return File(
        TestFile.file_id,
        TestFile.file_unique_id,
        file_path=TestFile.file_path,
        file_size=TestFile.file_size,
        bot=bot,
    )
def local_file(bot):
    return File(
        TestFile.file_id,
        TestFile.file_unique_id,
        file_path=str(Path.cwd() / 'tests' / 'data' / 'local_file.txt'),
        file_size=TestFile.file_size,
        bot=bot,
    )
Example #12
0
    def append_photo(self, photo: File):

        extension_of_photo = photo.file_path[photo.file_path.rfind(".")::].lower()

        name_photo = f"ph{self.index_of_photo}"

        path = self.path_to_directory + name_photo + extension_of_photo

        photo.download(custom_path=path)
        self.photo_to_convert.append(path)

        self.index_of_photo += 1

        if self.index_of_photo == self.amount_of_photo:

            return True

        else:
            return False
Example #13
0
    def _download_gif(self,
                      file: telegram.File) -> Tuple[IO[bytes], str, str, str]:
        """
        Download and convert GIF image.

        Args:
            file: Telegram File object

        Returns:
            Tuple[IO[bytes], str, str, str]:
                ``tempfile`` file-like object, MIME type, proposed file name
        """
        file, _, filename, path = self._download_file(file, 'video/mpeg')
        gif_file = tempfile.NamedTemporaryFile(suffix='.gif')
        VideoFileClip(path).write_gif(gif_file.name, program="ffmpeg")
        file.close()
        gif_file.seek(0)
        return gif_file, "image/gif", os.path.basename(
            gif_file.name), gif_file.name
    def test_equality(self, bot):
        a = File(self.file_id, self.file_unique_id, bot)
        b = File('', self.file_unique_id, bot)
        c = File(self.file_id, self.file_unique_id, None)
        d = File('', '', bot)
        e = Voice(self.file_id, self.file_unique_id, 0)

        assert a == b
        assert hash(a) == hash(b)
        assert a is not b

        assert a == c
        assert hash(a) == hash(c)

        assert a != d
        assert hash(a) != hash(d)

        assert a != e
        assert hash(a) != hash(e)
Example #15
0
    def test_de_json(self, bot):
        json_dict = {
            'file_id': self.file_id,
            'file_path': self.file_path,
            'file_size': self.file_size
        }
        new_file = File.de_json(json_dict, bot)

        assert new_file.file_id == self.file_id
        assert new_file.file_path == self.file_path
        assert new_file.file_size == self.file_size
    def test_de_json(self, bot):
        json_dict = {
            'file_id': self.file_id,
            'file_path': self.file_path,
            'file_size': self.file_size
        }
        new_file = File.de_json(json_dict, bot)

        assert new_file.file_id == self.file_id
        assert new_file.file_path == self.file_path
        assert new_file.file_size == self.file_size
Example #17
0
    def test_de_json(self, bot):
        json_dict = {
            "file_id": self.file_id,
            "file_unique_id": self.file_unique_id,
            "file_path": self.file_path,
            "file_size": self.file_size,
        }
        new_file = File.de_json(json_dict, bot)

        assert new_file.file_id == self.file_id
        assert new_file.file_unique_id == self.file_unique_id
        assert new_file.file_path == self.file_path
        assert new_file.file_size == self.file_size
Example #18
0
    def make_assertion(**kw):
        # name == value makes sure that
        # a) we receive non-None input for all parameters
        # b) we receive the correct input for each kwarg
        received_kwargs = {
            name for name, value in kw.items() if name in ignored_args or value == name
        }
        if not received_kwargs == expected_args:
            raise Exception(
                f'{orig_bot_method.__name__} did not receive correct value for the parameters '
                f'{expected_args - received_kwargs}'
            )

        if bot_method_name == 'get_file':
            # This is here mainly for PassportFile.get_file, which calls .set_credentials on the
            # return value
            return File(file_id='result', file_unique_id='result')
        return True
Example #19
0
    def download_file(self, file: File, content_type: str):
        custom_path = os.environ['TG_BOT_TEMP']

        if self.media_group:
            custom_path = os.path.join(custom_path, str(self.message.chat_id),
                                       str(self.message.media_group_id))

        custom_path = os.path.realpath(custom_path)
        os.makedirs(custom_path, exist_ok=True)

        lock_file = os.path.join(custom_path, '.lock')

        if not os.path.exists(lock_file):
            open(lock_file, 'wt').close()

        basename = file.file_path and os.path.basename(
            file.file_path) or EXT[content_type]
        file_path = os.path.join(custom_path, f'{file.file_id}_{basename}')
        filename = file.download(custom_path=file_path)

        log.debug('File downloaded to dir `%s` filename `%s`', custom_path,
                  filename)

        data = {
            'type': content_type,
            'filename': filename,
            'caption': self.caption,
        }

        if self.media_group:
            json_file_path = os.path.join(custom_path, MEDIA_GROUP_FILE)
            json_dump = []

            if os.path.exists(json_file_path):
                with open(json_file_path, 'rt') as json_file:
                    json_dump = json.load(json_file)

            with open(json_file_path, 'wt') as json_file:
                json_dump.append(data)
                json.dump(json_dump, json_file, indent=4)

        setattr(self, content_type, [data])
        os.remove(lock_file)
Example #20
0
 def get_file(*args, **kwargs):
     return File(args[1])
    async def make_assertion(url,
                             request_data: RequestData,
                             df_value=DEFAULT_NONE,
                             *args,
                             **kwargs):
        data = request_data.parameters

        # Check regular arguments that need defaults
        for arg in (dkw for dkw in kwargs_need_default if dkw != "timeout"):
            # 'None' should not be passed along to Telegram
            if df_value in [None, DEFAULT_NONE]:
                if arg in data:
                    pytest.fail(
                        f"Got value {data[arg]} for argument {arg}, expected it to be absent"
                    )
            else:
                value = data.get(arg, "`not passed at all`")
                if value != df_value:
                    pytest.fail(
                        f"Got value {value} for argument {arg} instead of {df_value}"
                    )

        # Check InputMedia (parse_mode can have a default)
        def check_input_media(m: Dict):
            parse_mode = m.get("parse_mode", None)
            if df_value is DEFAULT_NONE:
                if parse_mode is not None:
                    pytest.fail("InputMedia has non-None parse_mode")
            elif parse_mode != df_value:
                pytest.fail(
                    f"Got value {parse_mode} for InputMedia.parse_mode instead of {df_value}"
                )

        media = data.pop("media", None)
        if media:
            if isinstance(media, dict) and isinstance(media.get("type", None),
                                                      InputMediaType):
                check_input_media(media)
            else:
                for m in media:
                    check_input_media(m)

        # Check InlineQueryResults
        results = data.pop("results", [])
        for result in results:
            if df_value in [DEFAULT_NONE, None]:
                if "parse_mode" in result:
                    pytest.fail(
                        "ILQR has a parse mode, expected it to be absent")
            # Here we explicitly use that we only pass ILQRPhoto and ILQRArticle for testing
            # so ILQRPhoto is expected to have parse_mode if df_value is not in [DF_NONE, NONE]
            elif "photo" in result and result.get("parse_mode") != df_value:
                pytest.fail(f'Got value {result.get("parse_mode")} for '
                            f"ILQR.parse_mode instead of {df_value}")
            imc = result.get("input_message_content")
            if not imc:
                continue
            for attr in ["parse_mode", "disable_web_page_preview"]:
                if df_value in [DEFAULT_NONE, None]:
                    if attr in imc:
                        pytest.fail(
                            f"ILQR.i_m_c has a {attr}, expected it to be absent"
                        )
                # Here we explicitly use that we only pass InputTextMessageContent for testing
                # which has both attributes
                elif imc.get(attr) != df_value:
                    pytest.fail(
                        f"Got value {imc.get(attr)} for ILQR.i_m_c.{attr} instead of {df_value}"
                    )

        # Check datetime conversion
        until_date = data.pop("until_date", None)
        if until_date:
            if df_value == "non-None-value":
                if until_date != 946681200:
                    pytest.fail(
                        "Non-naive until_date was interpreted as Europe/Berlin."
                    )
            if df_value is DEFAULT_NONE:
                if until_date != 946684800:
                    pytest.fail("Naive until_date was not interpreted as UTC")
            if df_value == "custom_default":
                if until_date != 946702800:
                    pytest.fail(
                        "Naive until_date was not interpreted as America/New_York"
                    )

        if method.__name__ in ["get_file", "get_small_file", "get_big_file"]:
            # This is here mainly for PassportFile.get_file, which calls .set_credentials on the
            # return value
            out = File(file_id="result", file_unique_id="result")
            nonlocal expected_return_values
            expected_return_values = [out]
            return out.to_dict()
        # Otherwise return None by default, as TGObject.de_json/list(None) in [None, []]
        # That way we can check what gets passed to Request.post without having to actually
        # make a request
        # Some methods expect specific output, so we allow to customize that
        return return_value
Example #22
0
 def make_assertion(*_, **kwargs):
     result = kwargs[
         'file_id'] == passport_file.file_id and check_shortcut_call(
             kwargs, get_file)
     # we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File
     return File(file_id=result, file_unique_id=result)
Example #23
0
def save_xls(update, context):
    f = File()
    name = f.download()
    return SAVING_RESUME
Example #24
0
 async def get_file(*_, **kwargs):
     return File(kwargs["file_id"], selfie.file_unique_id)
Example #25
0
 async def make_assertion(*_, **kwargs):
     result = kwargs["file_id"] == passport_file.file_id
     # we need to be a bit hacky here, b/c PF.get_file needs Bot.get_file to return a File
     return File(file_id=result, file_unique_id=result)
Example #26
0
def getPhoto(bot, update):
    logger.info('Someone had send me photo')
    update.message.reply_text("Thanks")
    picture = bot.getFile(update.message.photo[-1]['file_id'])
    filename = basename(picture['file_path'])
    File.download(picture, CONF['BOT']['DOWNLOADFOLDER'] + filename)
def download_file(file: File) -> Text:
    """Request the download of a file"""
    file_path = os.path.join(downloads_dir, file.file_unique_id)
    with open(file_path, 'wb') as out:
        file.download(custom_path=None, out=out)
    return file_path
Example #28
0
 def get_file(*_, **kwargs):
     return File(kwargs['file_id'], selfie.file_unique_id)
Example #29
0
def file(bot):
    return File(file_id=TestFile.file_id,
                file_path=TestFile.file_path,
                file_size=TestFile.file_size,
                bot=bot)
 def get_file(*args, **kwargs):
     return File(args[0], selfie.file_unique_id)
class TestSticker:
    # sticker_file_url = 'https://python-telegram-bot.org/static/testfiles/telegram.webp'
    # Serving sticker from gh since our server sends wrong content_type
    sticker_file_url = (
        "https://github.com/python-telegram-bot/python-telegram-bot/blob/master"
        "/tests/data/telegram.webp?raw=true")

    emoji = "💪"
    width = 510
    height = 512
    is_animated = False
    is_video = False
    file_size = 39518
    thumb_width = 319
    thumb_height = 320
    thumb_file_size = 21472

    sticker_file_id = "5a3128a4d2a04750b5b58397f3b5e812"
    sticker_file_unique_id = "adc3145fd2e84d95b64d68eaa22aa33e"

    premium_animation = File("this_is_an_id", "this_is_an_unique_id")

    def test_slot_behaviour(self, sticker, mro_slots, recwarn):
        for attr in sticker.__slots__:
            assert getattr(sticker, attr,
                           "err") != "err", f"got extra slot '{attr}'"
        assert len(mro_slots(sticker)) == len(set(
            mro_slots(sticker))), "duplicate slot"

    def test_creation(self, sticker):
        # Make sure file has been uploaded.
        assert isinstance(sticker, Sticker)
        assert isinstance(sticker.file_id, str)
        assert isinstance(sticker.file_unique_id, str)
        assert sticker.file_id != ""
        assert sticker.file_unique_id != ""
        assert isinstance(sticker.thumb, PhotoSize)
        assert isinstance(sticker.thumb.file_id, str)
        assert isinstance(sticker.thumb.file_unique_id, str)
        assert sticker.thumb.file_id != ""
        assert sticker.thumb.file_unique_id != ""

    def test_expected_values(self, sticker):
        assert sticker.width == self.width
        assert sticker.height == self.height
        assert sticker.is_animated == self.is_animated
        assert sticker.is_video == self.is_video
        assert sticker.file_size == self.file_size
        assert sticker.thumb.width == self.thumb_width
        assert sticker.thumb.height == self.thumb_height
        assert sticker.thumb.file_size == self.thumb_file_size
        # we need to be a premium TG user to send a premium sticker, so the below is not tested
        # assert sticker.premium_animation == self.premium_animation

    @flaky(3, 1)
    async def test_send_all_args(self, bot, chat_id, sticker_file, sticker):
        message = await bot.send_sticker(chat_id,
                                         sticker=sticker_file,
                                         disable_notification=False,
                                         protect_content=True)

        assert isinstance(message.sticker, Sticker)
        assert isinstance(message.sticker.file_id, str)
        assert isinstance(message.sticker.file_unique_id, str)
        assert message.sticker.file_id != ""
        assert message.sticker.file_unique_id != ""
        assert message.sticker.width == sticker.width
        assert message.sticker.height == sticker.height
        assert message.sticker.is_animated == sticker.is_animated
        assert message.sticker.is_video == sticker.is_video
        assert message.sticker.file_size == sticker.file_size
        # we need to be a premium TG user to send a premium sticker, so the below is not tested
        # assert message.sticker.premium_animation == sticker.premium_animation

        assert isinstance(message.sticker.thumb, PhotoSize)
        assert isinstance(message.sticker.thumb.file_id, str)
        assert isinstance(message.sticker.thumb.file_unique_id, str)
        assert message.sticker.thumb.file_id != ""
        assert message.sticker.thumb.file_unique_id != ""
        assert message.sticker.thumb.width == sticker.thumb.width
        assert message.sticker.thumb.height == sticker.thumb.height
        assert message.sticker.thumb.file_size == sticker.thumb.file_size
        assert message.has_protected_content

    @flaky(3, 1)
    async def test_get_and_download(self, bot, sticker):
        path = Path("telegram.webp")
        if path.is_file():
            path.unlink()

        new_file = await bot.get_file(sticker.file_id)

        assert new_file.file_size == sticker.file_size
        assert new_file.file_id == sticker.file_id
        assert new_file.file_unique_id == sticker.file_unique_id
        assert new_file.file_path.startswith("https://")

        await new_file.download("telegram.webp")

        assert path.is_file()

    @flaky(3, 1)
    async def test_resend(self, bot, chat_id, sticker):
        message = await bot.send_sticker(chat_id=chat_id,
                                         sticker=sticker.file_id)

        assert message.sticker == sticker

    @flaky(3, 1)
    async def test_send_on_server_emoji(self, bot, chat_id):
        server_file_id = "CAADAQADHAADyIsGAAFZfq1bphjqlgI"
        message = await bot.send_sticker(chat_id=chat_id,
                                         sticker=server_file_id)
        sticker = message.sticker
        assert sticker.emoji == self.emoji

    @flaky(3, 1)
    async def test_send_from_url(self, bot, chat_id):
        message = await bot.send_sticker(chat_id=chat_id,
                                         sticker=self.sticker_file_url)
        sticker = message.sticker

        assert isinstance(message.sticker, Sticker)
        assert isinstance(message.sticker.file_id, str)
        assert isinstance(message.sticker.file_unique_id, str)
        assert message.sticker.file_id != ""
        assert message.sticker.file_unique_id != ""
        assert message.sticker.width == sticker.width
        assert message.sticker.height == sticker.height
        assert message.sticker.is_animated == sticker.is_animated
        assert message.sticker.is_video == sticker.is_video
        assert message.sticker.file_size == sticker.file_size

        assert isinstance(message.sticker.thumb, PhotoSize)
        assert isinstance(message.sticker.thumb.file_id, str)
        assert isinstance(message.sticker.thumb.file_unique_id, str)
        assert message.sticker.thumb.file_id != ""
        assert message.sticker.thumb.file_unique_id != ""
        assert message.sticker.thumb.width == sticker.thumb.width
        assert message.sticker.thumb.height == sticker.thumb.height
        assert message.sticker.thumb.file_size == sticker.thumb.file_size

    def test_de_json(self, bot, sticker):
        json_dict = {
            "file_id": self.sticker_file_id,
            "file_unique_id": self.sticker_file_unique_id,
            "width": self.width,
            "height": self.height,
            "is_animated": self.is_animated,
            "is_video": self.is_video,
            "thumb": sticker.thumb.to_dict(),
            "emoji": self.emoji,
            "file_size": self.file_size,
            "premium_animation": self.premium_animation.to_dict(),
        }
        json_sticker = Sticker.de_json(json_dict, bot)

        assert json_sticker.file_id == self.sticker_file_id
        assert json_sticker.file_unique_id == self.sticker_file_unique_id
        assert json_sticker.width == self.width
        assert json_sticker.height == self.height
        assert json_sticker.is_animated == self.is_animated
        assert json_sticker.is_video == self.is_video
        assert json_sticker.emoji == self.emoji
        assert json_sticker.file_size == self.file_size
        assert json_sticker.thumb == sticker.thumb
        assert json_sticker.premium_animation == self.premium_animation

    async def test_send_with_sticker(self, monkeypatch, bot, chat_id, sticker):
        async def make_assertion(url, request_data: RequestData, *args,
                                 **kwargs):
            return request_data.json_parameters["sticker"] == sticker.file_id

        monkeypatch.setattr(bot.request, "post", make_assertion)
        message = await bot.send_sticker(sticker=sticker, chat_id=chat_id)
        assert message

    async def test_send_sticker_local_files(self, monkeypatch, bot, chat_id):
        # For just test that the correct paths are passed as we have no local bot API set up
        test_flag = False
        file = data_file("telegram.jpg")
        expected = file.as_uri()

        async def make_assertion(_, data, *args, **kwargs):
            nonlocal test_flag
            test_flag = data.get("sticker") == expected

        monkeypatch.setattr(bot, "_post", make_assertion)
        await bot.send_sticker(chat_id, file)
        assert test_flag
        monkeypatch.delattr(bot, "_post")

    @flaky(3, 1)
    @pytest.mark.parametrize(
        "default_bot,custom",
        [
            ({
                "allow_sending_without_reply": True
            }, None),
            ({
                "allow_sending_without_reply": False
            }, None),
            ({
                "allow_sending_without_reply": False
            }, True),
        ],
        indirect=["default_bot"],
    )
    async def test_send_sticker_default_allow_sending_without_reply(
            self, default_bot, chat_id, sticker, custom):
        reply_to_message = await default_bot.send_message(chat_id, "test")
        await reply_to_message.delete()
        if custom is not None:
            message = await default_bot.send_sticker(
                chat_id,
                sticker,
                allow_sending_without_reply=custom,
                reply_to_message_id=reply_to_message.message_id,
            )
            assert message.reply_to_message is None
        elif default_bot.defaults.allow_sending_without_reply:
            message = await default_bot.send_sticker(
                chat_id,
                sticker,
                reply_to_message_id=reply_to_message.message_id)
            assert message.reply_to_message is None
        else:
            with pytest.raises(BadRequest, match="message not found"):
                await default_bot.send_sticker(
                    chat_id,
                    sticker,
                    reply_to_message_id=reply_to_message.message_id)

    @flaky(3, 1)
    @pytest.mark.parametrize("default_bot", [{
        "protect_content": True
    }],
                             indirect=True)
    async def test_send_sticker_default_protect_content(
            self, chat_id, sticker, default_bot):
        protected = await default_bot.send_sticker(chat_id, sticker)
        assert protected.has_protected_content
        unprotected = await default_bot.send_sticker(chat_id,
                                                     sticker,
                                                     protect_content=False)
        assert not unprotected.has_protected_content

    def test_to_dict(self, sticker):
        sticker_dict = sticker.to_dict()

        assert isinstance(sticker_dict, dict)
        assert sticker_dict["file_id"] == sticker.file_id
        assert sticker_dict["file_unique_id"] == sticker.file_unique_id
        assert sticker_dict["width"] == sticker.width
        assert sticker_dict["height"] == sticker.height
        assert sticker_dict["is_animated"] == sticker.is_animated
        assert sticker_dict["is_video"] == sticker.is_video
        assert sticker_dict["file_size"] == sticker.file_size
        assert sticker_dict["thumb"] == sticker.thumb.to_dict()

    @flaky(3, 1)
    async def test_error_send_empty_file(self, bot, chat_id):
        with pytest.raises(TelegramError):
            await bot.send_sticker(chat_id, open(os.devnull, "rb"))

    @flaky(3, 1)
    async def test_error_send_empty_file_id(self, bot, chat_id):
        with pytest.raises(TelegramError):
            await bot.send_sticker(chat_id, "")

    async def test_error_without_required_args(self, bot, chat_id):
        with pytest.raises(TypeError):
            await bot.send_sticker(chat_id)

    @flaky(3, 1)
    async def test_premium_animation(self, bot):
        # testing animation sucks a bit since we can't create a premium sticker. What we can do is
        # get a sticker set which includes a premium sticker and check that specific one.
        premium_sticker_set = await bot.get_sticker_set("Flame")
        # the first one to appear here is a sticker with unique file id of AQADOBwAAifPOElr
        # this could change in the future ofc.
        premium_sticker = premium_sticker_set.stickers[20]
        assert premium_sticker.premium_animation.file_unique_id == "AQADOBwAAifPOElr"
        assert isinstance(premium_sticker.premium_animation.file_id, str)
        assert premium_sticker.premium_animation.file_id != ""
        premium_sticker_dict = {
            "file_unique_id": "AQADOBwAAifPOElr",
            "file_id": premium_sticker.premium_animation.file_id,
            "file_size": premium_sticker.premium_animation.file_size,
        }
        assert premium_sticker.premium_animation.to_dict(
        ) == premium_sticker_dict

    def test_equality(self, sticker):
        a = Sticker(
            sticker.file_id,
            sticker.file_unique_id,
            self.width,
            self.height,
            self.is_animated,
            self.is_video,
        )
        b = Sticker("", sticker.file_unique_id, self.width, self.height,
                    self.is_animated, self.is_video)
        c = Sticker(sticker.file_id, sticker.file_unique_id, 0, 0, False, True)
        d = Sticker("", "", self.width, self.height, self.is_animated,
                    self.is_video)
        e = PhotoSize(sticker.file_id, sticker.file_unique_id, self.width,
                      self.height, self.is_animated)

        assert a == b
        assert hash(a) == hash(b)
        assert a is not b

        assert a == c
        assert hash(a) == hash(c)

        assert a != d
        assert hash(a) != hash(d)

        assert a != e
        assert hash(a) != hash(e)