Add Filters.document.file_extension (#2169)

Co-authored-by: Matheus Lemos <matheuslemosf@protonmail.com>
Co-authored-by: Bibo-Joshi <hinrich.mahler@freenet.de>
This commit is contained in:
Evgeny Denisov 2020-11-06 20:41:54 +03:00 committed by GitHub
parent 3b9187ed5a
commit ac449deb5d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 194 additions and 0 deletions

View file

@ -39,6 +39,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Eugene Lisitsky <https://github.com/lisitsky>`_ - `Eugene Lisitsky <https://github.com/lisitsky>`_
- `Eugenio Panadero <https://github.com/azogue>`_ - `Eugenio Panadero <https://github.com/azogue>`_
- `Evan Haberecht <https://github.com/habereet>`_ - `Evan Haberecht <https://github.com/habereet>`_
- `Evgeny Denisov <https://github.com/eIGato>`_
- `evgfilim1 <https://github.com/evgfilim1>`_ - `evgfilim1 <https://github.com/evgfilim1>`_
- `franciscod <https://github.com/franciscod>`_ - `franciscod <https://github.com/franciscod>`_
- `gamgi <https://github.com/gamgi>`_ - `gamgi <https://github.com/gamgi>`_
@ -62,6 +63,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Loo Zheng Yuan <https://github.com/loozhengyuan>`_ - `Loo Zheng Yuan <https://github.com/loozhengyuan>`_
- `LRezende <https://github.com/lrezende>`_ - `LRezende <https://github.com/lrezende>`_
- `macrojames <https://github.com/macrojames>`_ - `macrojames <https://github.com/macrojames>`_
- `Matheus Lemos <https://github.com/mlemosf>`_
- `Michael Elovskikh <https://github.com/wronglink>`_ - `Michael Elovskikh <https://github.com/wronglink>`_
- `Mischa Krüger <https://github.com/Makman2>`_ - `Mischa Krüger <https://github.com/Makman2>`_
- `naveenvhegde <https://github.com/naveenvhegde>`_ - `naveenvhegde <https://github.com/naveenvhegde>`_

View file

@ -638,6 +638,68 @@ class Filters:
xml = mime_type('application/xml') xml = mime_type('application/xml')
zip = mime_type('application/zip') zip = mime_type('application/zip')
class file_extension(MessageFilter):
"""This filter filters documents by their file ending/extension.
Note:
* This Filter only filters by the file ending/extension of the document,
it doesn't check the validity of document.
* The user can manipulate the file extension of a document and
send media with wrong types that don't fit to this handler.
* Case insensitive by default,
you may change this with the flag ``case_sensitive=True``.
* Extension should be passed without leading dot
unless it's a part of the extension.
* Pass :obj:`None` to filter files with no extension,
i.e. without a dot in the filename.
Example:
* ``Filters.document.file_extension("jpg")``
filters files with extension ``".jpg"``.
* ``Filters.document.file_extension(".jpg")``
filters files with extension ``"..jpg"``.
* ``Filters.document.file_extension("Dockerfile", case_sensitive=True)``
filters files with extension ``".Dockerfile"`` minding the case.
* ``Filters.document.file_extension(None)``
filters files without a dot in the filename.
"""
def __init__(self, file_extension: Optional[str], case_sensitive: bool = False):
"""Initialize the extension you want to filter.
Args:
file_extension (:obj:`str` | :obj:`None`):
media file extension you want to filter.
case_sensitive (:obj:bool, optional):
pass :obj:`True` to make the filter case sensitive.
Default: :obj:`False`.
"""
self.is_case_sensitive = case_sensitive
if file_extension is None:
self.file_extension = None
self.name = "Filters.document.file_extension(None)"
elif case_sensitive:
self.file_extension = f".{file_extension}"
self.name = (
f"Filters.document.file_extension({file_extension!r},"
" case_sensitive=True)"
)
else:
self.file_extension = f".{file_extension}".lower()
self.name = f"Filters.document.file_extension({file_extension.lower()!r})"
def filter(self, message: Message) -> bool:
"""""" # remove method from docs
if message.document is None:
return False
if self.file_extension is None:
return "." not in message.document.file_name
if self.is_case_sensitive:
filename = message.document.file_name
else:
filename = message.document.file_name.lower()
return filename.endswith(self.file_extension)
def filter(self, message: Message) -> bool: def filter(self, message: Message) -> bool:
return bool(message.document) return bool(message.document)
@ -694,6 +756,29 @@ officedocument.wordprocessingml.document")``-
wav: Same as ``Filters.document.mime_type("audio/x-wav")``- wav: Same as ``Filters.document.mime_type("audio/x-wav")``-
xml: Same as ``Filters.document.mime_type("application/xml")``- xml: Same as ``Filters.document.mime_type("application/xml")``-
zip: Same as ``Filters.document.mime_type("application/zip")``- zip: Same as ``Filters.document.mime_type("application/zip")``-
file_extension: This filter filters documents by their file ending/extension.
Note:
* This Filter only filters by the file ending/extension of the document,
it doesn't check the validity of document.
* The user can manipulate the file extension of a document and
send media with wrong types that don't fit to this handler.
* Case insensitive by default,
you may change this with the flag ``case_sensitive=True``.
* Extension should be passed without leading dot
unless it's a part of the extension.
* Pass :obj:`None` to filter files with no extension,
i.e. without a dot in the filename.
Example:
* ``Filters.document.file_extension("jpg")``
filters files with extension ``".jpg"``.
* ``Filters.document.file_extension(".jpg")``
filters files with extension ``"..jpg"``.
* ``Filters.document.file_extension("Dockerfile", case_sensitive=True)``
filters files with extension ``".Dockerfile"`` minding the case.
* ``Filters.document.file_extension(None)``
filters files without a dot in the filename.
""" """
class _Animation(MessageFilter): class _Animation(MessageFilter):

View file

@ -632,6 +632,113 @@ class TestFilters:
assert Filters.document.category("application/")(update) assert Filters.document.category("application/")(update)
assert Filters.document.mime_type("application/x-sh")(update) assert Filters.document.mime_type("application/x-sh")(update)
def test_filters_file_extension_basic(self, update):
update.message.document = Document(
"file_id",
"unique_id",
file_name="file.jpg",
mime_type="image/jpeg",
)
assert Filters.document.file_extension("jpg")(update)
assert not Filters.document.file_extension("jpeg")(update)
assert not Filters.document.file_extension("file.jpg")(update)
update.message.document.file_name = "file.tar.gz"
assert Filters.document.file_extension("tar.gz")(update)
assert Filters.document.file_extension("gz")(update)
assert not Filters.document.file_extension("tgz")(update)
assert not Filters.document.file_extension("jpg")(update)
update.message.document = None
assert not Filters.document.file_extension("jpg")(update)
def test_filters_file_extension_minds_dots(self, update):
update.message.document = Document(
"file_id",
"unique_id",
file_name="file.jpg",
mime_type="image/jpeg",
)
assert not Filters.document.file_extension(".jpg")(update)
assert not Filters.document.file_extension("e.jpg")(update)
assert not Filters.document.file_extension("file.jpg")(update)
assert not Filters.document.file_extension("")(update)
update.message.document.file_name = "file..jpg"
assert Filters.document.file_extension("jpg")(update)
assert Filters.document.file_extension(".jpg")(update)
assert not Filters.document.file_extension("..jpg")(update)
update.message.document.file_name = "file.docx"
assert Filters.document.file_extension("docx")(update)
assert not Filters.document.file_extension("doc")(update)
assert not Filters.document.file_extension("ocx")(update)
update.message.document.file_name = "file"
assert not Filters.document.file_extension("")(update)
assert not Filters.document.file_extension("file")(update)
update.message.document.file_name = "file."
assert Filters.document.file_extension("")(update)
def test_filters_file_extension_none_arg(self, update):
update.message.document = Document(
"file_id",
"unique_id",
file_name="file.jpg",
mime_type="image/jpeg",
)
assert not Filters.document.file_extension(None)(update)
update.message.document.file_name = "file"
assert Filters.document.file_extension(None)(update)
assert not Filters.document.file_extension("None")(update)
update.message.document.file_name = "file."
assert not Filters.document.file_extension(None)(update)
update.message.document = None
assert not Filters.document.file_extension(None)(update)
def test_filters_file_extension_case_sensitivity(self, update):
update.message.document = Document(
"file_id",
"unique_id",
file_name="file.jpg",
mime_type="image/jpeg",
)
assert Filters.document.file_extension("JPG")(update)
assert Filters.document.file_extension("jpG")(update)
update.message.document.file_name = "file.JPG"
assert Filters.document.file_extension("jpg")(update)
assert not Filters.document.file_extension("jpg", case_sensitive=True)(update)
update.message.document.file_name = "file.Dockerfile"
assert Filters.document.file_extension("Dockerfile", case_sensitive=True)(update)
assert not Filters.document.file_extension("DOCKERFILE", case_sensitive=True)(update)
def test_filters_file_extension_name(self):
assert Filters.document.file_extension("jpg").name == (
"Filters.document.file_extension('jpg')"
)
assert Filters.document.file_extension("JPG").name == (
"Filters.document.file_extension('jpg')"
)
assert Filters.document.file_extension("jpg", case_sensitive=True).name == (
"Filters.document.file_extension('jpg', case_sensitive=True)"
)
assert Filters.document.file_extension("JPG", case_sensitive=True).name == (
"Filters.document.file_extension('JPG', case_sensitive=True)"
)
assert Filters.document.file_extension(".jpg").name == (
"Filters.document.file_extension('.jpg')"
)
assert Filters.document.file_extension("").name == "Filters.document.file_extension('')"
assert (
Filters.document.file_extension(None).name == "Filters.document.file_extension(None)"
)
def test_filters_animation(self, update): def test_filters_animation(self, update):
assert not Filters.animation(update) assert not Filters.animation(update)
update.message.animation = 'test' update.message.animation = 'test'