merge from master

This commit is contained in:
wiredfool 2014-06-05 00:13:47 +00:00
commit 09db145329
9 changed files with 183 additions and 66 deletions

59
.gitignore vendored
View File

@ -1,11 +1,56 @@
*.pyc # Byte-compiled / optimized / DLL files
*.egg-info __pycache__/
build *.py[cod]
dist
.tox # C extensions
*.so *.so
docs/_build
*~ # Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
# Vim cruft # Vim cruft
.*.swp .*.swp

View File

@ -17,6 +17,7 @@ python:
install: install:
- "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake" - "sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-qt4 ghostscript libffi-dev cmake"
- "pip install cffi" - "pip install cffi"
- "pip install coveralls"
# webp # webp
- pushd depends && ./install_webp.sh && popd - pushd depends && ./install_webp.sh && popd
@ -25,10 +26,18 @@ install:
- pushd depends && ./install_openjpeg.sh && popd - pushd depends && ./install_openjpeg.sh && popd
script: script:
- coverage erase
- python setup.py clean - python setup.py clean
- python setup.py build_ext --inplace - python setup.py build_ext --inplace
- python selftest.py - coverage run --append --include=PIL/* selftest.py
- python Tests/run.py - python Tests/run.py --coverage
after_success:
- coverage report
- coveralls
- pip install pep8 pyflakes
- pep8 PIL/*.py
- pyflakes PIL/*.py
matrix: matrix:
allow_failures: allow_failures:

View File

@ -1,6 +1,15 @@
Changelog (Pillow) Changelog (Pillow)
================== ==================
2.5.0 (unreleased)
------------------
- Have the tempfile use a suffix with a dot
[wiredfool]
- Fix variable name used for transparency manipulations
[nijel]
2.4.0 (2014-04-01) 2.4.0 (2014-04-01)
------------------ ------------------

View File

@ -505,15 +505,18 @@ class Image:
def _dump(self, file=None, format=None): def _dump(self, file=None, format=None):
import tempfile, os import tempfile, os
suffix = ''
if format:
suffix = '.'+format
if not file: if not file:
f, file = tempfile.mkstemp(format or '') f, file = tempfile.mkstemp(suffix)
os.close(f) os.close(f)
self.load() self.load()
if not format or format == "PPM": if not format or format == "PPM":
self.im.save_ppm(file) self.im.save_ppm(file)
else: else:
if file.endswith(format): if not file.endswith(format):
file = file + "." + format file = file + "." + format
self.save(file, format) self.save(file, format)
return file return file
@ -807,7 +810,7 @@ class Image:
new_im = self._new(im) new_im = self._new(im)
if delete_trns: if delete_trns:
#crash fail if we leave a bytes transparency in an rgb/l mode. #crash fail if we leave a bytes transparency in an rgb/l mode.
del(new.info['transparency']) del(new_im.info['transparency'])
if trns is not None: if trns is not None:
if new_im.mode == 'P': if new_im.mode == 'P':
try: try:

View File

@ -5,8 +5,9 @@ Pillow
Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors. Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
.. image:: https://travis-ci.org/python-imaging/Pillow.png .. image:: https://travis-ci.org/python-imaging/Pillow.svg?branch=master
:target: https://travis-ci.org/python-imaging/Pillow :target: https://travis-ci.org/python-imaging/Pillow
:alt: Travis CI build status
.. image:: https://pypip.in/v/Pillow/badge.png .. image:: https://pypip.in/v/Pillow/badge.png
:target: https://pypi.python.org/pypi/Pillow/ :target: https://pypi.python.org/pypi/Pillow/
@ -16,4 +17,7 @@ Pillow is the "friendly" PIL fork by Alex Clark and Contributors. PIL is the Pyt
:target: https://pypi.python.org/pypi/Pillow/ :target: https://pypi.python.org/pypi/Pillow/
:alt: Number of PyPI downloads :alt: Number of PyPI downloads
.. image:: https://coveralls.io/repos/python-imaging/Pillow/badge.png?branch=master
:target: https://coveralls.io/r/python-imaging/Pillow?branch=master
The documentation is hosted at http://pillow.readthedocs.org/. It contains installation instructions, tutorials, reference, compatibility details, and more. The documentation is hosted at http://pillow.readthedocs.org/. It contains installation instructions, tutorials, reference, compatibility details, and more.

View File

@ -2,7 +2,12 @@ from __future__ import print_function
# minimal test runner # minimal test runner
import glob, os, os.path, sys, tempfile, re import glob
import os
import os.path
import re
import sys
import tempfile
try: try:
root = os.path.dirname(__file__) root = os.path.dirname(__file__)
@ -34,6 +39,7 @@ files.sort()
success = failure = 0 success = failure = 0
include = [x for x in sys.argv[1:] if x[:2] != "--"] include = [x for x in sys.argv[1:] if x[:2] != "--"]
skipped = [] skipped = []
failed = []
python_options = " ".join(python_options) python_options = " ".join(python_options)
tester_options = " ".join(tester_options) tester_options = " ".join(tester_options)
@ -91,7 +97,7 @@ for file in files:
# if there's an ok at the end, it's not really ok # if there's an ok at the end, it's not really ok
result = result[:-3] result = result[:-3]
print(result) print(result)
failure = failure + 1 failed.append(test)
else: else:
success = success + 1 success = success + 1
@ -105,6 +111,7 @@ if tempfiles:
print(file) print(file)
print("-"*68) print("-"*68)
def tests(n): def tests(n):
if n == 1: if n == 1:
return "1 test" return "1 test"
@ -112,10 +119,12 @@ def tests(n):
return "%d tests" % n return "%d tests" % n
if skipped: if skipped:
print("---", tests(len(skipped)), "skipped.") print("---", tests(len(skipped)), "skipped:")
print(skipped) print(", ".join(skipped))
if failure: if failed:
print("***", tests(failure), "of", (success + failure), "failed.") failure = len(failed)
print("***", tests(failure), "of", (success + failure), "failed:")
print(", ".join(failed))
sys.exit(1) sys.exit(1)
else: else:
print(tests(success), "passed.") print(tests(success), "passed.")

View File

@ -2,6 +2,7 @@ from tester import *
from PIL import Image from PIL import Image
def verify(im1): def verify(im1):
im2 = lena("I") im2 = lena("I")
assert_equal(im1.size, im2.size) assert_equal(im1.size, im2.size)
@ -18,6 +19,7 @@ def verify(im1):
return return
success() success()
def test_basic(): def test_basic():
# PIL 1.1 has limited support for 16-bit image data. Check that # PIL 1.1 has limited support for 16-bit image data. Check that
# create/copy/transform and save works as expected. # create/copy/transform and save works as expected.

View File

@ -11,8 +11,6 @@ except NameError:
# we expect a NameError on py2.x, since it doesn't have ResourceWarnings. # we expect a NameError on py2.x, since it doesn't have ResourceWarnings.
pass pass
import sys import sys
py3 = (sys.version_info >= (3, 0)) py3 = (sys.version_info >= (3, 0))
@ -22,6 +20,7 @@ _target = None
_tempfiles = [] _tempfiles = []
_logfile = None _logfile = None
def success(): def success():
import sys import sys
success.count += 1 success.count += 1
@ -29,8 +28,10 @@ def success():
print(sys.argv[0], success.count, failure.count, file=_logfile) print(sys.argv[0], success.count, failure.count, file=_logfile)
return True return True
def failure(msg=None, frame=None): def failure(msg=None, frame=None):
import sys, linecache import sys
import linecache
failure.count += 1 failure.count += 1
if _target: if _target:
if frame is None: if frame is None:
@ -49,6 +50,7 @@ def failure(msg=None, frame=None):
success.count = failure.count = 0 success.count = failure.count = 0
# predicates # predicates
def assert_true(v, msg=None): def assert_true(v, msg=None):
@ -57,24 +59,28 @@ def assert_true(v, msg=None):
else: else:
failure(msg or "got %r, expected true value" % v) failure(msg or "got %r, expected true value" % v)
def assert_false(v, msg=None): def assert_false(v, msg=None):
if v: if v:
failure(msg or "got %r, expected false value" % v) failure(msg or "got %r, expected false value" % v)
else: else:
success() success()
def assert_equal(a, b, msg=None): def assert_equal(a, b, msg=None):
if a == b: if a == b:
success() success()
else: else:
failure(msg or "got %r, expected %r" % (a, b)) failure(msg or "got %r, expected %r" % (a, b))
def assert_almost_equal(a, b, msg=None, eps=1e-6): def assert_almost_equal(a, b, msg=None, eps=1e-6):
if abs(a-b) < eps: if abs(a-b) < eps:
success() success()
else: else:
failure(msg or "got %r, expected %r" % (a, b)) failure(msg or "got %r, expected %r" % (a, b))
def assert_deep_equal(a, b, msg=None): def assert_deep_equal(a, b, msg=None):
try: try:
if len(a) == len(b): if len(a) == len(b):
@ -95,8 +101,10 @@ def assert_match(v, pattern, msg=None):
else: else:
failure(msg or "got %r, doesn't match pattern %r" % (v, pattern)) failure(msg or "got %r, doesn't match pattern %r" % (v, pattern))
def assert_exception(exc_class, func): def assert_exception(exc_class, func):
import sys, traceback import sys
import traceback
try: try:
func() func()
except exc_class: except exc_class:
@ -108,8 +116,10 @@ def assert_exception(exc_class, func):
else: else:
failure("expected %r exception, got no exception" % exc_class.__name__) failure("expected %r exception, got no exception" % exc_class.__name__)
def assert_no_exception(func): def assert_no_exception(func):
import sys, traceback import sys
import traceback
try: try:
func() func()
except: except:
@ -118,11 +128,14 @@ def assert_no_exception(func):
else: else:
success() success()
def assert_warning(warn_class, func): def assert_warning(warn_class, func):
# note: this assert calls func three times! # note: this assert calls func three times!
import warnings import warnings
def warn_error(message, category=UserWarning, **options): def warn_error(message, category=UserWarning, **options):
raise category(message) raise category(message)
def warn_ignore(message, category=UserWarning, **options): def warn_ignore(message, category=UserWarning, **options):
pass pass
warn = warnings.warn warn = warnings.warn
@ -141,15 +154,18 @@ def assert_warning(warn_class, func):
from io import BytesIO from io import BytesIO
def fromstring(data): def fromstring(data):
from PIL import Image from PIL import Image
return Image.open(BytesIO(data)) return Image.open(BytesIO(data))
def tostring(im, format, **options): def tostring(im, format, **options):
out = BytesIO() out = BytesIO()
im.save(out, format, **options) im.save(out, format, **options)
return out.getvalue() return out.getvalue()
def lena(mode="RGB", cache={}): def lena(mode="RGB", cache={}):
from PIL import Image from PIL import Image
im = cache.get(mode) im = cache.get(mode)
@ -165,6 +181,7 @@ def lena(mode="RGB", cache={}):
cache[mode] = im cache[mode] = im
return im return im
def assert_image(im, mode, size, msg=None): def assert_image(im, mode, size, msg=None):
if mode is not None and im.mode != mode: if mode is not None and im.mode != mode:
failure(msg or "got mode %r, expected %r" % (im.mode, mode)) failure(msg or "got mode %r, expected %r" % (im.mode, mode))
@ -173,6 +190,7 @@ def assert_image(im, mode, size, msg=None):
else: else:
success() success()
def assert_image_equal(a, b, msg=None): def assert_image_equal(a, b, msg=None):
if a.mode != b.mode: if a.mode != b.mode:
failure(msg or "got mode %r, expected %r" % (a.mode, b.mode)) failure(msg or "got mode %r, expected %r" % (a.mode, b.mode))
@ -184,6 +202,7 @@ def assert_image_equal(a, b, msg=None):
else: else:
success() success()
def assert_image_similar(a, b, epsilon, msg=None): def assert_image_similar(a, b, epsilon, msg=None):
epsilon = float(epsilon) epsilon = float(epsilon)
if a.mode != b.mode: if a.mode != b.mode:
@ -200,12 +219,18 @@ def assert_image_similar(a, b, epsilon, msg=None):
diff += abs(abyte-bbyte) diff += abs(abyte-bbyte)
ave_diff = float(diff)/(a.size[0]*a.size[1]) ave_diff = float(diff)/(a.size[0]*a.size[1])
if epsilon < ave_diff: if epsilon < ave_diff:
return failure(msg or "average pixel value difference %.4f > epsilon %.4f" %(ave_diff, epsilon)) return failure(
msg or "average pixel value difference %.4f > epsilon %.4f" % (
ave_diff, epsilon))
else: else:
return success() return success()
def tempfile(template, *extra): def tempfile(template, *extra):
import os, os.path, sys, tempfile import os
import os.path
import sys
import tempfile
files = [] files = []
root = os.path.join(tempfile.gettempdir(), 'pillow-tests') root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
try: try:
@ -222,11 +247,13 @@ def tempfile(template, *extra):
_tempfiles.extend(files) _tempfiles.extend(files)
return files[0] return files[0]
# test runner # test runner
def run(): def run():
global _target, _tests, run global _target, _tests, run
import sys, traceback import sys
import traceback
_target = sys.modules["__main__"] _target = sys.modules["__main__"]
run = None # no need to run twice run = None # no need to run twice
tests = [] tests = []
@ -251,29 +278,42 @@ def run():
sys.argv[0], lineno, v)) sys.argv[0], lineno, v))
failure.count += 1 failure.count += 1
def yield_test(function, *args): def yield_test(function, *args):
# collect delayed/generated tests # collect delayed/generated tests
_tests.append((function, args)) _tests.append((function, args))
def skip(msg=None): def skip(msg=None):
import os import os
print("skip") print("skip")
os._exit(0) # don't run exit handlers os._exit(0) # don't run exit handlers
def ignore(pattern): def ignore(pattern):
"""Tells the driver to ignore messages matching the pattern, for the """Tells the driver to ignore messages matching the pattern, for the
duration of the current test.""" duration of the current test."""
print('ignore: %s' % pattern) print('ignore: %s' % pattern)
def _setup(): def _setup():
global _logfile global _logfile
import sys
if "--coverage" in sys.argv:
import coverage
cov = coverage.coverage(auto_data=True, include="PIL/*")
cov.start()
def report(): def report():
if run: if run:
run() run()
if success.count and not failure.count: if success.count and not failure.count:
print("ok") print("ok")
# only clean out tempfiles if test passed # only clean out tempfiles if test passed
import os, os.path, tempfile import os
import os.path
import tempfile
for file in _tempfiles: for file in _tempfiles:
try: try:
os.remove(file) os.remove(file)
@ -285,18 +325,9 @@ def _setup():
except OSError: except OSError:
pass pass
if "--coverage" in sys.argv: import atexit
import coverage
coverage.stop()
# The coverage module messes up when used from inside an
# atexit handler. Do an explicit save to make sure that
# we actually flush the coverage cache.
coverage.the_coverage.save()
import atexit, sys
atexit.register(report) atexit.register(report)
if "--coverage" in sys.argv:
import coverage
coverage.start()
if "--log" in sys.argv: if "--log" in sys.argv:
_logfile = open("test.log", "a") _logfile = open("test.log", "a")

View File

@ -4,8 +4,9 @@ Pillow
Pillow is the 'friendly' PIL fork by Alex Clark and Contributors. PIL is the Pillow is the 'friendly' PIL fork by Alex Clark and Contributors. PIL is the
Python Imaging Library by Fredrik Lundh and Contributors. Python Imaging Library by Fredrik Lundh and Contributors.
.. image:: https://travis-ci.org/python-imaging/Pillow.png .. image:: https://travis-ci.org/python-imaging/Pillow.svg?branch=master
:target: https://travis-ci.org/python-imaging/Pillow :target: https://travis-ci.org/python-imaging/Pillow
:alt: Travis CI build status
.. image:: https://pypip.in/v/Pillow/badge.png .. image:: https://pypip.in/v/Pillow/badge.png
:target: https://pypi.python.org/pypi/Pillow/ :target: https://pypi.python.org/pypi/Pillow/
@ -15,6 +16,10 @@ Python Imaging Library by Fredrik Lundh and Contributors.
:target: https://pypi.python.org/pypi/Pillow/ :target: https://pypi.python.org/pypi/Pillow/
:alt: Number of PyPI downloads :alt: Number of PyPI downloads
.. image:: https://coveralls.io/repos/python-imaging/Pillow/badge.png?branch=master
:target: https://coveralls.io/r/python-imaging/Pillow?branch=master
:alt: Test coverage
To start using Pillow, please read the :doc:`installation To start using Pillow, please read the :doc:`installation
instructions <installation>`. instructions <installation>`.