diff --git a/.gitignore b/.gitignore index 76012ef6..c36547e0 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ nosetests.xml .mr.developer.cfg .project .pydevproject + +# PyCharm +.idea diff --git a/docs/index.rst b/docs/index.rst index b7284dfb..616fe753 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -91,6 +91,13 @@ iban .. autofunction:: iban +image +----- + +.. module:: validators.image + +.. autofunction:: image + ipv4 ---- diff --git a/setup.py b/setup.py index c6c81e53..388b92de 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,8 @@ def get_version(): 'test': [ 'pytest>=2.2.3', 'flake8>=2.4.0', - 'isort>=4.2.2' + 'isort>=4.2.2', + 'pillow>=3.4.2' ], } diff --git a/tests/test_image.py b/tests/test_image.py new file mode 100644 index 00000000..ed7aa480 --- /dev/null +++ b/tests/test_image.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +import os + +import pytest +from PIL import Image + +from validators import image, ValidationFailure + + +@pytest.fixture() +def image_file(tmpdir): + path = os.path.join(str(tmpdir), 'test.png') + img = Image.new('RGBA', (10, 10)) + img.save(str(path), format='PNG') + return str(path) + + +@pytest.fixture() +def text_file(tmpdir): + path = os.path.join(str(tmpdir), 'test.txt') + f = open(path, 'w') + f.close() + return str(path) + + +@pytest.mark.parametrize('address', [ + u'https://i.imgur.com/DKUR9Tk.png', + u'https://i.imgur.com/DKUR9Tk.png?fb' +]) +def test_returns_true_on_valid_image_url(address): + assert image(address) + + +@pytest.mark.parametrize('address', [ + u'http://www.google.com/' +]) +def test_returns_false_on_invalid_image_url(address): + assert isinstance(image(address), ValidationFailure) + + +def test_returns_true_on_valid_image_file(image_file): + assert image(image_file) + + +def test_returns_false_on_invalid_image_file(text_file): + assert isinstance(image(text_file), ValidationFailure) diff --git a/validators/__init__.py b/validators/__init__.py index ee7d91cf..be9f4020 100644 --- a/validators/__init__.py +++ b/validators/__init__.py @@ -4,6 +4,7 @@ from .extremes import Max, Min # noqa from .i18n import fi_business_id, fi_ssn # noqa from .iban import iban # noqa +from .image import image # noqa from .ip_address import ipv4, ipv6 # noqa from .length import length # noqa from .mac_address import mac_address # noqa diff --git a/validators/image.py b/validators/image.py new file mode 100644 index 00000000..141ef3f4 --- /dev/null +++ b/validators/image.py @@ -0,0 +1,63 @@ +import imghdr # isort:skip +import os +from io import BytesIO + +from .url import url +from .utils import ValidationFailure, validator + +try: + from urllib2 import urlopen +except ImportError: + from urllib.request import urlopen + + +def _image_url(path): + result = False + + try: + if url(path): + response = urlopen(path) + data = BytesIO(response.read()) + if imghdr.what(data) is not None: + result = True + else: + result = False + except ValidationFailure: + result = False + + return result + + +def _image_file(path): + result = False + + if os.path.exists(path): + if imghdr.what(path) is not None: + result = True + else: + result = False + + return result + + +@validator +def image(path): + """ + Return whether or not a file is a valid image type. + + If the file is a valid image type this function returns ``True``, otherwise + :class:`~validators.utils.ValidationFailure`. + + :param path: The path to the file to evaluate. + """ + + result = False + + if _image_url(path): + result = True + elif _image_file(path): + result = True + else: + result = False + + return result