Commit 4965a774 authored by Tim Graham's avatar Tim Graham
Browse files

Removed PIL compatability layer per deprecation timeline.

refs #19934.
parent 6d1ae5e2
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
"""
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)
+2 −3
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@ import os
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 @@ class ImageField(FileField):

    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.',
+2 −2
Original line number Diff line number Diff line
@@ -641,7 +641,7 @@ class ImageField(FileField):
        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 @@ class ImageField(FileField):
            # 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',

django/utils/image.py

deleted100644 → 0
+0 −157
Original line number Diff line number Diff line
# -*- 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()
+1 −1
Original line number Diff line number Diff line
@@ -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?

Loading