Search code examples
pythondjangodockerpython-imaging-libraryalpine-linux

Django does not find Pillow though installed


Django struggles to find Pillow and I'm not quite sure why.

Environment

Linux Alpine based Docker image, Django 2.2. Here are the relevant parts of:

The Dockerfile

RUN apk update \
    && apk add --virtual build-deps gcc python3-dev musl-dev jpeg-dev zlib-dev \
    && apk add --no-cache mariadb-dev mariadb-client

# install dependencies
RUN pip install --upgrade pip
RUN pip install pipenv
RUN pip install mysqlclient
COPY ./Pipfile /usr/src/cms/Pipfile
RUN pipenv install --skip-lock --system --dev
RUN apk del build-deps

The Pipfile

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
django = "==2.2"
markdown = "==3.1.1"
pillow = "==5.0.0"

[requires]
python_version = "3.6"

The issue

When I run python manage.py runserver 0.0.0.0:8000 from the container, I get the following error:

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
website.Photo.photo: (fields.E210) Cannot use ImageField because Pillow is not installed.
    HINT: Get Pillow at https://pypi.org/project/Pillow/ or run command "pip install Pillow".

which is weird because pip install Pillow gives me

Requirement already satisfied: Pillow in /usr/local/lib/python3.7/site-packages (5.4.1)

About Pillow's conflict with PIL

While having a look at /usr/local/lib/python3.7/site-packages, I noticed that I had both PIL and Pillow. Is this:

  1. the source of a conflict (Pillow's documentation) is quite specific about the need to uninstall PIL
  2. pillow's use of the very name PIL to maintain compatibility as suggested in this discussion?

From the facts that i) pip uninstall PIL -> not installed ii) print(PIL.PILLOW_VERSION) -> 5.0.0 in python's shell and that iii) Django uses from PIL import Image source, I would go for hypotheses 2. So if Pillow is installed in the container, why does not Django find it?

Current path

>>> from PIL import Image
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/PIL/Image.py", line 58, in <module>
    from . import _imaging as core
ImportError: Error loading shared library libjpeg.so.8: No such file or directory (needed by /usr/local/lib/python3.7/site-packages/PIL/_imaging.cpython-37m-x86_64-linux-gnu.so)

I added jpeg-dev to the Dockerfile but, somehow, it does not seem to be enough. Still digging. Thanks for any clue


Solution

  • Turns out, jpeg-dev (required by the compilation) was not enough to satisfy all dependencies during execution. Adding libjpeg solved the issue. Updated Dockerfile

    # install mysqlclient
    RUN apk update \
        && apk add --virtual build-deps gcc python3-dev musl-dev jpeg-dev zlib-dev \
        && apk add --no-cache mariadb-dev mariadb-client
    
    # install dependencies
    RUN pip install --upgrade pip
    RUN pip install pipenv
    RUN pip install mysqlclient
    RUN apk add libjpeg      -------------> et voila
    COPY ./Pipfile /usr/src/cms/Pipfile
    RUN pipenv install --skip-lock --system --dev
    RUN apk del build-deps