Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Removed PIL compatability layer per deprecation timeline.

refs #19934.
  • Loading branch information...
commit 4965a774074780f3e4858bcc975476f71edf2c2c 1 parent 6d1ae5e
@timgraham timgraham authored
View
12 django/core/files/images.py
@@ -1,7 +1,7 @@
"""
Utility functions for handling images.
-Requires Pillow (or PIL), as you might imagine.
+Requires Pillow as you might imagine.
"""
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
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'):
file = file_or_path
file_pos = file.tell()
@@ -46,9 +46,9 @@ def get_image_dimensions(file_or_path, close=False):
file = open(file_or_path, 'rb')
close = True
try:
- # Most of the time PIL only needs a small chunk to parse the image and
- # get the dimensions, but with some TIFF files PIL needs to parse the
- # whole file.
+ # Most of the time Pillow only needs a small chunk to parse the image
+ # and get the dimensions, but with some TIFF files Pillow needs to
+ # parse the whole file.
chunk_size = 1024
while 1:
data = file.read(chunk_size)
View
5 django/db/models/fields/files.py
@@ -4,7 +4,6 @@
from django import forms
from django.db.models.fields import Field
from django.core import checks
-from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import File
from django.core.files.storage import default_storage
from django.core.files.images import ImageFile
@@ -386,8 +385,8 @@ def check(self, **kwargs):
def _check_image_library_installed(self):
try:
- from django.utils.image import Image # NOQA
- except ImproperlyConfigured:
+ from PIL import Image # NOQA
+ except ImportError:
return [
checks.Error(
'Cannot use ImageField because Pillow is not installed.',
View
4 django/forms/fields.py
@@ -641,7 +641,7 @@ def to_python(self, data):
if f is 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
# have to read the data into memory.
@@ -659,7 +659,7 @@ def to_python(self, data):
# verify() must be called immediately after the constructor.
Image.open(file).verify()
except Exception:
- # Pillow (or PIL) doesn't recognize it as an image.
+ # Pillow doesn't recognize it as an image.
six.reraise(ValidationError, ValidationError(
self.error_messages['invalid_image'],
code='invalid_image',
View
157 django/utils/image.py
@@ -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()
View
2  docs/faq/contributing.txt
@@ -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:
* 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
familiar with it?
View
14 docs/ref/forms/fields.txt
@@ -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
and file name into a single object.
* 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``,
``invalid_image``
- Using an ``ImageField`` requires that either `Pillow`_ (recommended) or the
- `Python Imaging Library`_ (PIL) are installed and supports the image
- formats you use. If you encounter a ``corrupt image`` error when you
- upload an image, it usually means either Pillow or PIL
- doesn't understand its format. To fix this, install the appropriate
- library and reinstall Pillow or PIL.
+ Using an ``ImageField`` requires that `Pillow`_ is installed with support
+ for the image formats you use. If you encounter a ``corrupt image`` error
+ when you upload an image, it usually means that Pillow doesn't understand
+ its format. To fix this, install the appropriate library and reinstall
+ Pillow.
When you use an ``ImageField`` on a form, you must also remember to
:ref:`bind the file data to the form <binding-uploaded-files>`.
.. _Pillow: http://python-imaging.github.io/Pillow/
-.. _Python Imaging Library: http://www.pythonware.com/products/pil/
``IntegerField``
~~~~~~~~~~~~~~~~
View
4 docs/ref/models/fields.txt
@@ -841,9 +841,9 @@ optional arguments:
Name of a model field which will be auto-populated with the width of the
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)``
columns in your database. As with other fields, you can change the maximum
View
4 docs/topics/security.txt
@@ -226,8 +226,8 @@ User-uploaded content
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
header followed by malicious HTML. This file will pass verification of the
- libraries that Django uses for :class:`~django.db.models.ImageField` image
- processing (PIL or Pillow). When this file is subsequently displayed to a
+ library that Django uses for :class:`~django.db.models.ImageField` image
+ processing (Pillow). When this file is subsequently displayed to a
user, it may be displayed as HTML depending on the type and configuration of
your web server.
View
16 tests/files/tests.py
@@ -8,7 +8,6 @@
import unittest
import zlib
-from django.core.exceptions import ImproperlyConfigured
from django.core.files import File
from django.core.files.move import file_move_safe
from django.core.files.base import ContentFile
@@ -18,10 +17,11 @@
from django.utils import six
try:
- from django.utils.image import Image
- from django.core.files import images
-except ImproperlyConfigured:
+ from PIL import Image
+except ImportError:
Image = None
+else:
+ from django.core.files import images
class FileTests(unittest.TestCase):
@@ -112,7 +112,7 @@ class DimensionClosingBug(unittest.TestCase):
"""
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):
"""
Open files passed into get_image_dimensions() should stay opened.
@@ -123,7 +123,7 @@ def test_not_closing_of_files(self):
finally:
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):
"""
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
using a file handler (#11158)
"""
- @unittest.skipUnless(Image, "Pillow/PIL not installed")
+ @unittest.skipUnless(Image, "Pillow not installed")
def test_multiple_calls(self):
"""
Multiple calls of get_image_dimensions() should return the same size.
@@ -177,7 +177,7 @@ def test_multiple_calls(self):
self.assertEqual(image_pil.size, size_1)
self.assertEqual(size_1, size_2)
- @unittest.skipUnless(Image, "Pillow/PIL not installed")
+ @unittest.skipUnless(Image, "Pillow not installed")
def test_bug_19457(self):
"""
Regression test for #19457
View
5 tests/invalid_models_tests/test_ordinary_fields.py
@@ -4,7 +4,6 @@
import unittest
from django.core.checks import Error
-from django.core.exceptions import ImproperlyConfigured
from django.db import connection, models
from .base import IsolatedModelsTestCase
@@ -379,8 +378,8 @@ class ImageFieldTests(IsolatedModelsTestCase):
def test_pillow_installed(self):
try:
- import django.utils.image # NOQA
- except ImproperlyConfigured:
+ from PIL import Image # NOQA
+ except ImportError:
pillow_installed = False
else:
pillow_installed = True
View
10 tests/model_fields/models.py
@@ -2,11 +2,9 @@
import tempfile
import warnings
-from django.core.exceptions import ImproperlyConfigured
-
try:
- from django.utils.image import Image
-except ImproperlyConfigured:
+ from PIL import Image
+except ImportError:
Image = None
from django.core.files.storage import FileSystemStorage
@@ -114,7 +112,7 @@ class VerboseNameField(models.Model):
field9 = models.FileField("verbose field9", upload_to="unused")
field10 = models.FilePathField("verbose field10")
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")
field12 = models.IntegerField("verbose field12")
with warnings.catch_warnings(record=True) as w:
@@ -151,7 +149,7 @@ class Document(models.Model):
###############################################################################
# ImageField
-# If Pillow/PIL available, do these tests.
+# If Pillow available, do these tests.
if Image:
class TestImageFieldFile(ImageFieldFile):
"""
View
16 tests/model_fields/test_imagefield.py
@@ -20,7 +20,7 @@
PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile)
from .models import temp_storage_dir
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():
pass
PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person
@@ -93,7 +93,7 @@ def check_dimensions(self, instance, width, 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):
"""
Tests for ImageField that don't need to be run with each of the
@@ -180,7 +180,7 @@ def test_pickle(self):
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):
"""
Tests behavior of an ImageField and its dimensions fields.
@@ -294,7 +294,7 @@ def test_dimensions(self):
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):
"""
Tests behavior of an ImageField with no dimension fields.
@@ -303,7 +303,7 @@ class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
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):
"""
Tests behavior of an ImageField with one dimensions field.
@@ -312,7 +312,7 @@ class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
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):
"""
Tests behavior of an ImageField where the dimensions fields are
@@ -322,7 +322,7 @@ class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
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):
"""
Tests behavior of an ImageField when assigning it a File instance
@@ -333,7 +333,7 @@ class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
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):
"""
Tests a model with two ImageFields.
View
6 tests/model_forms/models.py
@@ -13,7 +13,7 @@
import tempfile
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.db import models
from django.utils import six
@@ -154,7 +154,7 @@ class FilePathModel(models.Model):
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
@@ -193,7 +193,7 @@ def custom_upload_path(self, filename):
def __str__(self):
return self.description
-except ImproperlyConfigured:
+except ImportError:
test_images = False
View
2  tests/model_forms/tests.py
@@ -1852,7 +1852,7 @@ class Meta:
names.sort()
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):
# ImageField and FileField are nearly identical, but they differ slighty when
# it comes to validation. This specifically tests that #6302 is fixed for
View
2  tests/serializers_regress/models.py
@@ -2,7 +2,7 @@
A test spanning all the capabilities of all the serializers.
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
Please sign in to comment.
Something went wrong with that request. Please try again.