Repository: python-pillow/Pillow

Issue:
Pillow cannot be loaded in python optimize (2) mode
### What did you do?
I was loading the PIL module with 'import PIL' when running Python with PYTHONOPTIMZE=2 (or python -OO).

### What did you expect to happen?
I Expected the PIL/Pillow Library to be imported.

### What actually happened?
I received an exception:
AttributeError: 'NoneType' object has no attribute 'format'

### What versions of Pillow and Python are you using?
Pillow 5.2.0 / Python 3.6.5

### Reason:

PYTHONOPTIMIZE=2 / python -OO strips the _ _ doc _ _ variable.

## Example:

create a file called test.py with only import PIL

```python
import PIL
```

Execute it with python in optimize mode
```sh
python -OO test.py
```
You will receive the following exception:
```
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    import PIL
  File "/usr/lib/python3.6/site-packages/PIL/__init__.py", line 27, in <module>
    __doc__ = __doc__.format(__version__)  # include version in docstring
AttributeError: 'NoneType' object has no attribute 'format'
```


Discussion:

Resolving patch:
diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py
--- a/src/PIL/ImageDraw.py
+++ b/src/PIL/ImageDraw.py
@@ -246,7 +246,7 @@ def multiline_text(self, xy, text, fill=None, font=None, anchor=None,
             elif align == "right":
                 left += (max_width - widths[idx])
             else:
-                assert False, 'align must be "left", "center" or "right"'
+                raise ValueError('align must be "left", "center" or "right"')
             self.text((left, top), line, fill, font, anchor,
                       direction=direction, features=features)
             top += line_spacing
diff --git a/src/PIL/ImageTk.py b/src/PIL/ImageTk.py
--- a/src/PIL/ImageTk.py
+++ b/src/PIL/ImageTk.py
@@ -32,13 +32,6 @@
 else:
     import Tkinter as tkinter
 
-# required for pypy, which always has cffi installed
-try:
-    from cffi import FFI
-    ffi = FFI()
-except ImportError:
-    pass
-
 from . import Image
 from io import BytesIO
 
@@ -192,7 +185,11 @@ def paste(self, im, box=None):
                 from . import _imagingtk
                 try:
                     if hasattr(tk, 'interp'):
-                        # Pypy is using a ffi cdata element
+                        # Required for PyPy, which always has CFFI installed
+                        from cffi import FFI
+                        ffi = FFI()
+
+                        # PyPy is using an FFI CDATA element
                         # (Pdb) self.tk.interp
                         #  <cdata 'Tcl_Interp *' 0x3061b50>
                         _imagingtk.tkinit(
diff --git a/src/PIL/__init__.py b/src/PIL/__init__.py
--- a/src/PIL/__init__.py
+++ b/src/PIL/__init__.py
@@ -1,4 +1,4 @@
-"""Pillow {} (Fork of the Python Imaging Library)
+"""Pillow (Fork of the Python Imaging Library)
 
 Pillow is the friendly PIL fork by Alex Clark and Contributors.
     https://github.com/python-pillow/Pillow/
@@ -24,8 +24,6 @@
 
 del _version
 
-__doc__ = __doc__.format(__version__)  # include version in docstring
-
 
 _plugins = ['BlpImagePlugin',
             'BmpImagePlugin',


Test patch:
diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py
--- a/Tests/test_image_access.py
+++ b/Tests/test_image_access.py
@@ -1,15 +1,20 @@
 from helper import unittest, PillowTestCase, hopper, on_appveyor
 
-try:
-    from PIL import PyAccess
-except ImportError:
-    # Skip in setUp()
-    pass
-
 from PIL import Image
 import sys
 import os
 
+# CFFI imports pycparser which doesn't support PYTHONOPTIMIZE=2
+# https://github.com/eliben/pycparser/pull/198#issuecomment-317001670
+if os.environ.get("PYTHONOPTIMIZE") == "2":
+    cffi = None
+else:
+    try:
+        from PIL import PyAccess
+        import cffi
+    except ImportError:
+        cffi = None
+
 
 class AccessTest(PillowTestCase):
     # initial value
@@ -113,38 +118,20 @@ def test_signedness(self):
             self.check(mode, 2**16-1)
 
 
+@unittest.skipIf(cffi is None, "No cffi")
 class TestCffiPutPixel(TestImagePutPixel):
     _need_cffi_access = True
 
-    def setUp(self):
-        try:
-            import cffi
-            assert cffi  # silence warning
-        except ImportError:
-            self.skipTest("No cffi")
-
 
+@unittest.skipIf(cffi is None, "No cffi")
 class TestCffiGetPixel(TestImageGetPixel):
     _need_cffi_access = True
 
-    def setUp(self):
-        try:
-            import cffi
-            assert cffi  # silence warning
-        except ImportError:
-            self.skipTest("No cffi")
-
 
+@unittest.skipIf(cffi is None, "No cffi")
 class TestCffi(AccessTest):
     _need_cffi_access = True
 
-    def setUp(self):
-        try:
-            import cffi
-            assert cffi  # silence warning
-        except ImportError:
-            self.skipTest("No cffi")
-
     def _test_get_access(self, im):
         """Do we get the same thing as the old pixel access
 
diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py
--- a/Tests/test_imagefont.py
+++ b/Tests/test_imagefont.py
@@ -215,7 +215,7 @@ def test_unknown_align(self):
 
         # Act/Assert
         self.assertRaises(
-            AssertionError,
+            ValueError,
             draw.multiline_text, (0, 0), TEST_TEXT, font=ttf, align="unknown")
 
     def test_draw_align(self):