parent
6d1ae5e27c
commit
4965a77407
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Utility functions for handling images.
|
Utility functions for handling images.
|
||||||
|
|
||||||
Requires Pillow (or PIL), as you might imagine.
|
Requires Pillow as you might imagine.
|
||||||
"""
|
"""
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ def get_image_dimensions(file_or_path, close=False):
|
||||||
'close' to True to close the file at the end if it is initially in an open
|
'close' to True to close the file at the end if it is initially in an open
|
||||||
state.
|
state.
|
||||||
"""
|
"""
|
||||||
from django.utils.image import ImageFile as PILImageFile
|
from PIL import ImageFile as PillowImageFile
|
||||||
|
|
||||||
p = PILImageFile.Parser()
|
p = PillowImageFile.Parser()
|
||||||
if hasattr(file_or_path, 'read'):
|
if hasattr(file_or_path, 'read'):
|
||||||
file = file_or_path
|
file = file_or_path
|
||||||
file_pos = file.tell()
|
file_pos = file.tell()
|
||||||
|
@ -46,9 +46,9 @@ def get_image_dimensions(file_or_path, close=False):
|
||||||
file = open(file_or_path, 'rb')
|
file = open(file_or_path, 'rb')
|
||||||
close = True
|
close = True
|
||||||
try:
|
try:
|
||||||
# Most of the time PIL only needs a small chunk to parse the image and
|
# Most of the time Pillow only needs a small chunk to parse the image
|
||||||
# get the dimensions, but with some TIFF files PIL needs to parse the
|
# and get the dimensions, but with some TIFF files Pillow needs to
|
||||||
# whole file.
|
# parse the whole file.
|
||||||
chunk_size = 1024
|
chunk_size = 1024
|
||||||
while 1:
|
while 1:
|
||||||
data = file.read(chunk_size)
|
data = file.read(chunk_size)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import os
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models.fields import Field
|
from django.db.models.fields import Field
|
||||||
from django.core import checks
|
from django.core import checks
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
from django.core.files.base import File
|
from django.core.files.base import File
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
from django.core.files.images import ImageFile
|
from django.core.files.images import ImageFile
|
||||||
|
@ -386,8 +385,8 @@ class ImageField(FileField):
|
||||||
|
|
||||||
def _check_image_library_installed(self):
|
def _check_image_library_installed(self):
|
||||||
try:
|
try:
|
||||||
from django.utils.image import Image # NOQA
|
from PIL import Image # NOQA
|
||||||
except ImproperlyConfigured:
|
except ImportError:
|
||||||
return [
|
return [
|
||||||
checks.Error(
|
checks.Error(
|
||||||
'Cannot use ImageField because Pillow is not installed.',
|
'Cannot use ImageField because Pillow is not installed.',
|
||||||
|
|
|
@ -641,7 +641,7 @@ class ImageField(FileField):
|
||||||
if f is None:
|
if f is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
from django.utils.image import Image
|
from PIL import Image
|
||||||
|
|
||||||
# We need to get a file object for Pillow. We might have a path or we might
|
# We need to get a file object for Pillow. We might have a path or we might
|
||||||
# have to read the data into memory.
|
# have to read the data into memory.
|
||||||
|
@ -659,7 +659,7 @@ class ImageField(FileField):
|
||||||
# verify() must be called immediately after the constructor.
|
# verify() must be called immediately after the constructor.
|
||||||
Image.open(file).verify()
|
Image.open(file).verify()
|
||||||
except Exception:
|
except Exception:
|
||||||
# Pillow (or PIL) doesn't recognize it as an image.
|
# Pillow doesn't recognize it as an image.
|
||||||
six.reraise(ValidationError, ValidationError(
|
six.reraise(ValidationError, ValidationError(
|
||||||
self.error_messages['invalid_image'],
|
self.error_messages['invalid_image'],
|
||||||
code='invalid_image',
|
code='invalid_image',
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
To provide a shim layer over Pillow/PIL situation until the PIL support is
|
|
||||||
removed. See #19934.
|
|
||||||
|
|
||||||
|
|
||||||
Combinations To Account For
|
|
||||||
===========================
|
|
||||||
|
|
||||||
* Pillow:
|
|
||||||
|
|
||||||
* never has ``_imaging`` under any Python
|
|
||||||
* has the ``Image.alpha_composite``, which may aid in detection
|
|
||||||
|
|
||||||
* PIL
|
|
||||||
|
|
||||||
* CPython 2.x may have _imaging (& work)
|
|
||||||
* CPython 2.x may *NOT* have _imaging (broken & needs a error message)
|
|
||||||
* CPython 3.x doesn't work
|
|
||||||
* PyPy will *NOT* have _imaging (but works?)
|
|
||||||
* On some platforms (Homebrew and RHEL6 reported) _imaging isn't available,
|
|
||||||
the needed import is from PIL import _imaging (refs #21355)
|
|
||||||
|
|
||||||
Restated, that looks like:
|
|
||||||
|
|
||||||
* If we're on Python 2.x, it could be either Pillow or PIL:
|
|
||||||
|
|
||||||
* If ``import _imaging`` results in ``ImportError``, either they have a
|
|
||||||
working Pillow installation or a broken PIL installation, so we need to
|
|
||||||
detect further:
|
|
||||||
|
|
||||||
* To detect, we first ``import Image``.
|
|
||||||
* If ``Image`` has a ``alpha_composite`` attribute present, only Pillow
|
|
||||||
has this, so we assume it's working.
|
|
||||||
* If ``Image`` DOES NOT have a ``alpha_composite``attribute, it must be
|
|
||||||
PIL & is a broken (likely C compiler-less) install, which we need to
|
|
||||||
warn the user about.
|
|
||||||
|
|
||||||
* If ``import _imaging`` works, it must be PIL & is a working install.
|
|
||||||
|
|
||||||
* Python 3.x
|
|
||||||
|
|
||||||
* If ``import Image`` works, it must be Pillow, since PIL isn't Python 3.x
|
|
||||||
compatible.
|
|
||||||
|
|
||||||
* PyPy
|
|
||||||
|
|
||||||
* If ``import _imaging`` results in ``ImportError``, it could be either
|
|
||||||
Pillow or PIL, both of which work without it on PyPy, so we're fine.
|
|
||||||
|
|
||||||
|
|
||||||
Approach
|
|
||||||
========
|
|
||||||
|
|
||||||
* Attempt to import ``Image``
|
|
||||||
|
|
||||||
* ``ImportError`` - nothing is installed, toss an exception
|
|
||||||
* Either Pillow or the PIL is installed, so continue detecting
|
|
||||||
|
|
||||||
* Attempt to ``hasattr(Image, 'alpha_composite')``
|
|
||||||
|
|
||||||
* If it works, it's Pillow & working
|
|
||||||
* If it fails, we've got a PIL install, continue detecting
|
|
||||||
|
|
||||||
* The only option here is that we're on Python 2.x or PyPy, of which
|
|
||||||
we only care about if we're on CPython.
|
|
||||||
* If we're on CPython, attempt to ``from PIL import _imaging`` and
|
|
||||||
``import _imaging``
|
|
||||||
|
|
||||||
* ``ImportError`` - Bad install, toss an exception
|
|
||||||
|
|
||||||
"""
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
from django.utils.deprecation import RemovedInDjango18Warning
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
Image = None
|
|
||||||
_imaging = None
|
|
||||||
ImageFile = None
|
|
||||||
|
|
||||||
|
|
||||||
def _detect_image_library():
|
|
||||||
global Image
|
|
||||||
global _imaging
|
|
||||||
global ImageFile
|
|
||||||
|
|
||||||
# Skip re-attempting to import if we've already run detection.
|
|
||||||
if Image is not None:
|
|
||||||
return Image, _imaging, ImageFile
|
|
||||||
|
|
||||||
# Assume it's not there.
|
|
||||||
PIL_imaging = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Try from the Pillow (or one variant of PIL) install location first.
|
|
||||||
from PIL import Image as PILImage
|
|
||||||
except ImportError as err:
|
|
||||||
try:
|
|
||||||
# If that failed, try the alternate import syntax for PIL.
|
|
||||||
import Image as PILImage
|
|
||||||
except ImportError as err:
|
|
||||||
# Neither worked, so it's likely not installed.
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
_("Neither Pillow nor PIL could be imported: %s") % err
|
|
||||||
)
|
|
||||||
|
|
||||||
# ``Image.alpha_composite`` was added to Pillow in SHA: e414c6 & is not
|
|
||||||
# available in any version of the PIL.
|
|
||||||
if hasattr(PILImage, 'alpha_composite'):
|
|
||||||
PIL_imaging = False
|
|
||||||
else:
|
|
||||||
# We're dealing with the PIL. Determine if we're on CPython & if
|
|
||||||
# ``_imaging`` is available.
|
|
||||||
import platform
|
|
||||||
|
|
||||||
# This is the Alex Approved™ way.
|
|
||||||
# See http://mail.python.org/pipermail//pypy-dev/2011-November/008739.html
|
|
||||||
if platform.python_implementation().lower() == 'cpython':
|
|
||||||
# We're on CPython (likely 2.x). Since a C compiler is needed to
|
|
||||||
# produce a fully-working PIL & will create a ``_imaging`` module,
|
|
||||||
# we'll attempt to import it to verify their kit works.
|
|
||||||
try:
|
|
||||||
from PIL import _imaging as PIL_imaging
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
import _imaging as PIL_imaging
|
|
||||||
except ImportError as err:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
_("The '_imaging' module for the PIL could not be "
|
|
||||||
"imported: %s") % err
|
|
||||||
)
|
|
||||||
|
|
||||||
# Try to import ImageFile as well.
|
|
||||||
try:
|
|
||||||
from PIL import ImageFile as PILImageFile
|
|
||||||
except ImportError:
|
|
||||||
# This import cannot fail unless Pillow/PIL install is completely
|
|
||||||
# broken (e.g. missing Python modules).
|
|
||||||
import ImageFile as PILImageFile
|
|
||||||
|
|
||||||
# Finally, warn about deprecation...
|
|
||||||
if PIL_imaging is not False:
|
|
||||||
warnings.warn(
|
|
||||||
"Support for the PIL will be removed in Django 1.8. Please " +
|
|
||||||
"uninstall it & install Pillow instead.",
|
|
||||||
RemovedInDjango18Warning
|
|
||||||
)
|
|
||||||
|
|
||||||
return PILImage, PIL_imaging, PILImageFile
|
|
||||||
|
|
||||||
|
|
||||||
Image, _imaging, ImageFile = _detect_image_library()
|
|
|
@ -27,7 +27,7 @@ to make it dead easy, even for someone who may not be intimately familiar with
|
||||||
that area of the code, to understand the problem and verify the fix:
|
that area of the code, to understand the problem and verify the fix:
|
||||||
|
|
||||||
* Are there clear instructions on how to reproduce the bug? If this
|
* Are there clear instructions on how to reproduce the bug? If this
|
||||||
touches a dependency (such as Pillow/PIL), a contrib module, or a specific
|
touches a dependency (such as Pillow), a contrib module, or a specific
|
||||||
database, are those instructions clear enough even for someone not
|
database, are those instructions clear enough even for someone not
|
||||||
familiar with it?
|
familiar with it?
|
||||||
|
|
||||||
|
|
|
@ -619,22 +619,20 @@ For each field, we describe the default widget used if you don't specify
|
||||||
* Normalizes to: An ``UploadedFile`` object that wraps the file content
|
* Normalizes to: An ``UploadedFile`` object that wraps the file content
|
||||||
and file name into a single object.
|
and file name into a single object.
|
||||||
* Validates that file data has been bound to the form, and that the
|
* Validates that file data has been bound to the form, and that the
|
||||||
file is of an image format understood by Pillow/PIL.
|
file is of an image format understood by Pillow.
|
||||||
* Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
|
* Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
|
||||||
``invalid_image``
|
``invalid_image``
|
||||||
|
|
||||||
Using an ``ImageField`` requires that either `Pillow`_ (recommended) or the
|
Using an ``ImageField`` requires that `Pillow`_ is installed with support
|
||||||
`Python Imaging Library`_ (PIL) are installed and supports the image
|
for the image formats you use. If you encounter a ``corrupt image`` error
|
||||||
formats you use. If you encounter a ``corrupt image`` error when you
|
when you upload an image, it usually means that Pillow doesn't understand
|
||||||
upload an image, it usually means either Pillow or PIL
|
its format. To fix this, install the appropriate library and reinstall
|
||||||
doesn't understand its format. To fix this, install the appropriate
|
Pillow.
|
||||||
library and reinstall Pillow or PIL.
|
|
||||||
|
|
||||||
When you use an ``ImageField`` on a form, you must also remember to
|
When you use an ``ImageField`` on a form, you must also remember to
|
||||||
:ref:`bind the file data to the form <binding-uploaded-files>`.
|
:ref:`bind the file data to the form <binding-uploaded-files>`.
|
||||||
|
|
||||||
.. _Pillow: http://python-imaging.github.io/Pillow/
|
.. _Pillow: http://python-imaging.github.io/Pillow/
|
||||||
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
|
||||||
|
|
||||||
``IntegerField``
|
``IntegerField``
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -841,9 +841,9 @@ optional arguments:
|
||||||
Name of a model field which will be auto-populated with the width of the
|
Name of a model field which will be auto-populated with the width of the
|
||||||
image each time the model instance is saved.
|
image each time the model instance is saved.
|
||||||
|
|
||||||
Requires the `Python Imaging Library`_.
|
Requires the `Pillow`_ library.
|
||||||
|
|
||||||
.. _Python Imaging Library: http://www.pythonware.com/products/pil/
|
.. _Pillow: http://python-imaging.github.io/Pillow/
|
||||||
|
|
||||||
By default, :class:`ImageField` instances are created as ``varchar(100)``
|
By default, :class:`ImageField` instances are created as ``varchar(100)``
|
||||||
columns in your database. As with other fields, you can change the maximum
|
columns in your database. As with other fields, you can change the maximum
|
||||||
|
|
|
@ -226,8 +226,8 @@ User-uploaded content
|
||||||
served in ways that do not follow security best practices. Specifically, an
|
served in ways that do not follow security best practices. Specifically, an
|
||||||
HTML file can be uploaded as an image if that file contains a valid PNG
|
HTML file can be uploaded as an image if that file contains a valid PNG
|
||||||
header followed by malicious HTML. This file will pass verification of the
|
header followed by malicious HTML. This file will pass verification of the
|
||||||
libraries that Django uses for :class:`~django.db.models.ImageField` image
|
library that Django uses for :class:`~django.db.models.ImageField` image
|
||||||
processing (PIL or Pillow). When this file is subsequently displayed to a
|
processing (Pillow). When this file is subsequently displayed to a
|
||||||
user, it may be displayed as HTML depending on the type and configuration of
|
user, it may be displayed as HTML depending on the type and configuration of
|
||||||
your web server.
|
your web server.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.core.files.move import file_move_safe
|
from django.core.files.move import file_move_safe
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
|
@ -18,10 +17,11 @@ from django.utils._os import upath
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.image import Image
|
from PIL import Image
|
||||||
from django.core.files import images
|
except ImportError:
|
||||||
except ImproperlyConfigured:
|
|
||||||
Image = None
|
Image = None
|
||||||
|
else:
|
||||||
|
from django.core.files import images
|
||||||
|
|
||||||
|
|
||||||
class FileTests(unittest.TestCase):
|
class FileTests(unittest.TestCase):
|
||||||
|
@ -112,7 +112,7 @@ class DimensionClosingBug(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Test that get_image_dimensions() properly closes files (#8817)
|
Test that get_image_dimensions() properly closes files (#8817)
|
||||||
"""
|
"""
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
@unittest.skipUnless(Image, "Pillow not installed")
|
||||||
def test_not_closing_of_files(self):
|
def test_not_closing_of_files(self):
|
||||||
"""
|
"""
|
||||||
Open files passed into get_image_dimensions() should stay opened.
|
Open files passed into get_image_dimensions() should stay opened.
|
||||||
|
@ -123,7 +123,7 @@ class DimensionClosingBug(unittest.TestCase):
|
||||||
finally:
|
finally:
|
||||||
self.assertTrue(not empty_io.closed)
|
self.assertTrue(not empty_io.closed)
|
||||||
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
@unittest.skipUnless(Image, "Pillow not installed")
|
||||||
def test_closing_of_filenames(self):
|
def test_closing_of_filenames(self):
|
||||||
"""
|
"""
|
||||||
get_image_dimensions() called with a filename should closed the file.
|
get_image_dimensions() called with a filename should closed the file.
|
||||||
|
@ -163,7 +163,7 @@ class InconsistentGetImageDimensionsBug(unittest.TestCase):
|
||||||
Test that get_image_dimensions() works properly after various calls
|
Test that get_image_dimensions() works properly after various calls
|
||||||
using a file handler (#11158)
|
using a file handler (#11158)
|
||||||
"""
|
"""
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
@unittest.skipUnless(Image, "Pillow not installed")
|
||||||
def test_multiple_calls(self):
|
def test_multiple_calls(self):
|
||||||
"""
|
"""
|
||||||
Multiple calls of get_image_dimensions() should return the same size.
|
Multiple calls of get_image_dimensions() should return the same size.
|
||||||
|
@ -177,7 +177,7 @@ class InconsistentGetImageDimensionsBug(unittest.TestCase):
|
||||||
self.assertEqual(image_pil.size, size_1)
|
self.assertEqual(image_pil.size, size_1)
|
||||||
self.assertEqual(size_1, size_2)
|
self.assertEqual(size_1, size_2)
|
||||||
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
@unittest.skipUnless(Image, "Pillow not installed")
|
||||||
def test_bug_19457(self):
|
def test_bug_19457(self):
|
||||||
"""
|
"""
|
||||||
Regression test for #19457
|
Regression test for #19457
|
||||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import unicode_literals
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from django.core.checks import Error
|
from django.core.checks import Error
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
from django.db import connection, models
|
from django.db import connection, models
|
||||||
|
|
||||||
from .base import IsolatedModelsTestCase
|
from .base import IsolatedModelsTestCase
|
||||||
|
@ -379,8 +378,8 @@ class ImageFieldTests(IsolatedModelsTestCase):
|
||||||
|
|
||||||
def test_pillow_installed(self):
|
def test_pillow_installed(self):
|
||||||
try:
|
try:
|
||||||
import django.utils.image # NOQA
|
from PIL import Image # NOQA
|
||||||
except ImproperlyConfigured:
|
except ImportError:
|
||||||
pillow_installed = False
|
pillow_installed = False
|
||||||
else:
|
else:
|
||||||
pillow_installed = True
|
pillow_installed = True
|
||||||
|
|
|
@ -2,11 +2,9 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.image import Image
|
from PIL import Image
|
||||||
except ImproperlyConfigured:
|
except ImportError:
|
||||||
Image = None
|
Image = None
|
||||||
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
from django.core.files.storage import FileSystemStorage
|
||||||
|
@ -114,7 +112,7 @@ class VerboseNameField(models.Model):
|
||||||
field9 = models.FileField("verbose field9", upload_to="unused")
|
field9 = models.FileField("verbose field9", upload_to="unused")
|
||||||
field10 = models.FilePathField("verbose field10")
|
field10 = models.FilePathField("verbose field10")
|
||||||
field11 = models.FloatField("verbose field11")
|
field11 = models.FloatField("verbose field11")
|
||||||
# Don't want to depend on Pillow/PIL in this test
|
# Don't want to depend on Pillow in this test
|
||||||
#field_image = models.ImageField("verbose field")
|
#field_image = models.ImageField("verbose field")
|
||||||
field12 = models.IntegerField("verbose field12")
|
field12 = models.IntegerField("verbose field12")
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
@ -151,7 +149,7 @@ class Document(models.Model):
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# ImageField
|
# ImageField
|
||||||
|
|
||||||
# If Pillow/PIL available, do these tests.
|
# If Pillow available, do these tests.
|
||||||
if Image:
|
if Image:
|
||||||
class TestImageFieldFile(ImageFieldFile):
|
class TestImageFieldFile(ImageFieldFile):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -20,7 +20,7 @@ if Image:
|
||||||
PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile)
|
PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile)
|
||||||
from .models import temp_storage_dir
|
from .models import temp_storage_dir
|
||||||
else:
|
else:
|
||||||
# Pillow/PIL not available, create dummy classes (tests will be skipped anyway)
|
# Pillow not available, create dummy classes (tests will be skipped anyway)
|
||||||
class Person():
|
class Person():
|
||||||
pass
|
pass
|
||||||
PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person
|
PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person
|
||||||
|
@ -93,7 +93,7 @@ class ImageFieldTestMixin(object):
|
||||||
self.assertEqual(getattr(instance, height_field_name), height)
|
self.assertEqual(getattr(instance, height_field_name), height)
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldTests(ImageFieldTestMixin, TestCase):
|
class ImageFieldTests(ImageFieldTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for ImageField that don't need to be run with each of the
|
Tests for ImageField that don't need to be run with each of the
|
||||||
|
@ -180,7 +180,7 @@ class ImageFieldTests(ImageFieldTestMixin, TestCase):
|
||||||
self.assertEqual(p.mugshot, loaded_p.mugshot)
|
self.assertEqual(p.mugshot, loaded_p.mugshot)
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
|
class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
Tests behavior of an ImageField and its dimensions fields.
|
Tests behavior of an ImageField and its dimensions fields.
|
||||||
|
@ -294,7 +294,7 @@ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
|
||||||
self.assertEqual(p.mugshot.was_opened, True)
|
self.assertEqual(p.mugshot.was_opened, True)
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
|
class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
|
||||||
"""
|
"""
|
||||||
Tests behavior of an ImageField with no dimension fields.
|
Tests behavior of an ImageField with no dimension fields.
|
||||||
|
@ -303,7 +303,7 @@ class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
|
||||||
PersonModel = Person
|
PersonModel = Person
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
|
class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
|
||||||
"""
|
"""
|
||||||
Tests behavior of an ImageField with one dimensions field.
|
Tests behavior of an ImageField with one dimensions field.
|
||||||
|
@ -312,7 +312,7 @@ class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
|
||||||
PersonModel = PersonWithHeight
|
PersonModel = PersonWithHeight
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
|
class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
|
||||||
"""
|
"""
|
||||||
Tests behavior of an ImageField where the dimensions fields are
|
Tests behavior of an ImageField where the dimensions fields are
|
||||||
|
@ -322,7 +322,7 @@ class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
|
||||||
PersonModel = PersonDimensionsFirst
|
PersonModel = PersonDimensionsFirst
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
|
class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
|
||||||
"""
|
"""
|
||||||
Tests behavior of an ImageField when assigning it a File instance
|
Tests behavior of an ImageField when assigning it a File instance
|
||||||
|
@ -333,7 +333,7 @@ class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
|
||||||
File = File
|
File = File
|
||||||
|
|
||||||
|
|
||||||
@skipIf(Image is None, "Pillow/PIL is required to test ImageField")
|
@skipIf(Image is None, "Pillow is required to test ImageField")
|
||||||
class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
|
class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
|
||||||
"""
|
"""
|
||||||
Tests a model with two ImageFields.
|
Tests a model with two ImageFields.
|
||||||
|
|
|
@ -13,7 +13,7 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files.storage import FileSystemStorage
|
from django.core.files.storage import FileSystemStorage
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
@ -154,7 +154,7 @@ class FilePathModel(models.Model):
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.image import Image # NOQA: detect if Pillow is installed
|
from PIL import Image # NOQA: detect if Pillow is installed
|
||||||
|
|
||||||
test_images = True
|
test_images = True
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ try:
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.description
|
return self.description
|
||||||
except ImproperlyConfigured:
|
except ImportError:
|
||||||
test_images = False
|
test_images = False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1852,7 +1852,7 @@ class FileAndImageFieldTests(TestCase):
|
||||||
names.sort()
|
names.sort()
|
||||||
self.assertEqual(names, ['---------', '__init__.py', 'models.py', 'tests.py'])
|
self.assertEqual(names, ['---------', '__init__.py', 'models.py', 'tests.py'])
|
||||||
|
|
||||||
@skipUnless(test_images, "Pillow/PIL not installed")
|
@skipUnless(test_images, "Pillow not installed")
|
||||||
def test_image_field(self):
|
def test_image_field(self):
|
||||||
# ImageField and FileField are nearly identical, but they differ slighty when
|
# ImageField and FileField are nearly identical, but they differ slighty when
|
||||||
# it comes to validation. This specifically tests that #6302 is fixed for
|
# it comes to validation. This specifically tests that #6302 is fixed for
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
A test spanning all the capabilities of all the serializers.
|
A test spanning all the capabilities of all the serializers.
|
||||||
|
|
||||||
This class sets up a model for each model field type
|
This class sets up a model for each model field type
|
||||||
(except for image types, because of the Pillow/PIL dependency).
|
(except for image types, because of the Pillow dependency).
|
||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue