Merge branch 'master' into rm-deprecated-fn
3
.gitignore
vendored
|
@ -34,6 +34,9 @@ htmlcov/
|
|||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Test files
|
||||
test_images
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ notifications:
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: "pypy"
|
||||
- python: "pypy3"
|
||||
- python: "pypy-5.7.1"
|
||||
- python: "pypy3.3-5.2-alpha1"
|
||||
- python: '3.6'
|
||||
- python: '2.7'
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
|
|
|
@ -3,18 +3,16 @@
|
|||
set -e
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev\
|
||||
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk \
|
||||
python-qt4 ghostscript libffi-dev libjpeg-turbo-progs cmake imagemagick
|
||||
pip install cffi
|
||||
pip install nose
|
||||
pip install check-manifest
|
||||
pip install olefile
|
||||
# Pyroma tests sometimes hang on PyPy; skip
|
||||
if [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then pip install pyroma; fi
|
||||
|
||||
pip install pyroma
|
||||
pip install coverage
|
||||
|
||||
# docs only on python 2.7
|
||||
# docs only on Python 2.7
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi
|
||||
|
||||
# clean checkout for manifest
|
||||
|
|
|
@ -4,6 +4,15 @@ Changelog (Pillow)
|
|||
4.2.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Update Feature Detection
|
||||
[wiredfool]
|
||||
|
||||
- CI: Update pypy on TravisCI
|
||||
[hugovk]
|
||||
|
||||
- ImageMorph: Fix wrong expected size of MRLs read from disk #2561
|
||||
[dov]
|
||||
|
||||
- Docs: Update install docs for FreeBSD #2546
|
||||
[wiredfool]
|
||||
|
||||
|
|
|
@ -176,8 +176,8 @@ class IcoFile(object):
|
|||
# figure out where AND mask image starts
|
||||
mode = a[0]
|
||||
bpp = 8
|
||||
for k in BmpImagePlugin.BIT2MODE.keys():
|
||||
if mode == BmpImagePlugin.BIT2MODE[k][1]:
|
||||
for k, v in BmpImagePlugin.BIT2MODE.items():
|
||||
if mode == v[1]:
|
||||
bpp = k
|
||||
break
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ def _conv_type_shape(im):
|
|||
return shape+(extra,), typ
|
||||
|
||||
|
||||
MODES = sorted(_MODEINFO.keys())
|
||||
MODES = sorted(_MODEINFO)
|
||||
|
||||
# raw modes that may be memory mapped. NOTE: if you change this, you
|
||||
# may have to modify the stride calculation in map.c too!
|
||||
|
|
|
@ -283,6 +283,7 @@ def Draw(im, mode=None):
|
|||
except AttributeError:
|
||||
return ImageDraw(im, mode)
|
||||
|
||||
|
||||
# experimental access to the outline API
|
||||
try:
|
||||
Outline = Image.core.outline
|
||||
|
|
|
@ -123,7 +123,7 @@ class LutBuilder(object):
|
|||
.replace('0', 'Z')
|
||||
.replace('1', '0')
|
||||
.replace('Z', '1'))
|
||||
res = '%d' % (1-int(res))
|
||||
res = 1-int(res)
|
||||
patterns.append((pattern, res))
|
||||
|
||||
return patterns
|
||||
|
@ -152,8 +152,8 @@ class LutBuilder(object):
|
|||
patterns += self._pattern_permute(pattern, options, result)
|
||||
|
||||
# # Debugging
|
||||
# for p,r in patterns:
|
||||
# print(p,r)
|
||||
# for p, r in patterns:
|
||||
# print(p, r)
|
||||
# print('--')
|
||||
|
||||
# compile the patterns into regular expressions for speed
|
||||
|
@ -234,7 +234,7 @@ class MorphOp(object):
|
|||
with open(filename, 'rb') as f:
|
||||
self.lut = bytearray(f.read())
|
||||
|
||||
if len(self.lut) != 8192:
|
||||
if len(self.lut) != LUT_SIZE:
|
||||
self.lut = None
|
||||
raise Exception('Wrong size operator file!')
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
tagdata = self.fp.read(size)
|
||||
else:
|
||||
tagdata = None
|
||||
if tag in list(self.info.keys()):
|
||||
if tag in self.info:
|
||||
if isinstance(self.info[tag], list):
|
||||
self.info[tag].append(tagdata)
|
||||
else:
|
||||
|
|
|
@ -66,6 +66,7 @@ class McIdasImageFile(ImageFile.ImageFile):
|
|||
|
||||
self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# registry
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
# Image plugin for PDF images (output only).
|
||||
##
|
||||
|
||||
from . import Image, ImageFile
|
||||
from . import Image, ImageFile, ImageSequence
|
||||
from ._binary import i8
|
||||
import io
|
||||
|
||||
|
@ -133,13 +133,24 @@ def _save(im, fp, filename, save_all=False):
|
|||
|
||||
#
|
||||
# pages
|
||||
numberOfPages = 1
|
||||
ims = [im]
|
||||
if save_all:
|
||||
try:
|
||||
numberOfPages = im.n_frames
|
||||
except AttributeError:
|
||||
# Image format does not have n_frames. It is a single frame image
|
||||
pass
|
||||
append_images = im.encoderinfo.get("append_images", [])
|
||||
for append_im in append_images:
|
||||
if append_im.mode != im.mode:
|
||||
append_im = append_im.convert(im.mode)
|
||||
append_im.encoderinfo = im.encoderinfo.copy()
|
||||
ims.append(append_im)
|
||||
numberOfPages = 0
|
||||
for im in ims:
|
||||
im_numberOfPages = 1
|
||||
if save_all:
|
||||
try:
|
||||
im_numberOfPages = im.n_frames
|
||||
except AttributeError:
|
||||
# Image format does not have n_frames. It is a single frame image
|
||||
pass
|
||||
numberOfPages += im_numberOfPages
|
||||
pages = [str(pageNumber*3+4)+" 0 R"
|
||||
for pageNumber in range(0, numberOfPages)]
|
||||
|
||||
|
@ -151,90 +162,92 @@ def _save(im, fp, filename, save_all=False):
|
|||
Kids="["+"\n".join(pages)+"]")
|
||||
_endobj(fp)
|
||||
|
||||
for pageNumber in range(0, numberOfPages):
|
||||
im.seek(pageNumber)
|
||||
pageNumber = 0
|
||||
for imSequence in ims:
|
||||
for im in ImageSequence.Iterator(imSequence):
|
||||
#
|
||||
# image
|
||||
|
||||
#
|
||||
# image
|
||||
op = io.BytesIO()
|
||||
|
||||
op = io.BytesIO()
|
||||
if filter == "/ASCIIHexDecode":
|
||||
if bits == 1:
|
||||
# FIXME: the hex encoder doesn't support packed 1-bit
|
||||
# images; do things the hard way...
|
||||
data = im.tobytes("raw", "1")
|
||||
im = Image.new("L", (len(data), 1), None)
|
||||
im.putdata(data)
|
||||
ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)])
|
||||
elif filter == "/DCTDecode":
|
||||
Image.SAVE["JPEG"](im, op, filename)
|
||||
elif filter == "/FlateDecode":
|
||||
ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)])
|
||||
elif filter == "/RunLengthDecode":
|
||||
ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)])
|
||||
else:
|
||||
raise ValueError("unsupported PDF filter (%s)" % filter)
|
||||
|
||||
if filter == "/ASCIIHexDecode":
|
||||
if bits == 1:
|
||||
# FIXME: the hex encoder doesn't support packed 1-bit
|
||||
# images; do things the hard way...
|
||||
data = im.tobytes("raw", "1")
|
||||
im = Image.new("L", (len(data), 1), None)
|
||||
im.putdata(data)
|
||||
ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)])
|
||||
elif filter == "/DCTDecode":
|
||||
Image.SAVE["JPEG"](im, op, filename)
|
||||
elif filter == "/FlateDecode":
|
||||
ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)])
|
||||
elif filter == "/RunLengthDecode":
|
||||
ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)])
|
||||
else:
|
||||
raise ValueError("unsupported PDF filter (%s)" % filter)
|
||||
#
|
||||
# Get image characteristics
|
||||
|
||||
#
|
||||
# Get image characteristics
|
||||
width, height = im.size
|
||||
|
||||
width, height = im.size
|
||||
xref.append(fp.tell())
|
||||
_obj(
|
||||
fp, pageNumber*3+3,
|
||||
Type="/XObject",
|
||||
Subtype="/Image",
|
||||
Width=width, # * 72.0 / resolution,
|
||||
Height=height, # * 72.0 / resolution,
|
||||
Length=len(op.getvalue()),
|
||||
Filter=filter,
|
||||
BitsPerComponent=bits,
|
||||
DecodeParams=params,
|
||||
ColorSpace=colorspace)
|
||||
|
||||
xref.append(fp.tell())
|
||||
_obj(
|
||||
fp, pageNumber*3+3,
|
||||
Type="/XObject",
|
||||
Subtype="/Image",
|
||||
Width=width, # * 72.0 / resolution,
|
||||
Height=height, # * 72.0 / resolution,
|
||||
Length=len(op.getvalue()),
|
||||
Filter=filter,
|
||||
BitsPerComponent=bits,
|
||||
DecodeParams=params,
|
||||
ColorSpace=colorspace)
|
||||
fp.write("stream\n")
|
||||
fp.fp.write(op.getvalue())
|
||||
fp.write("\nendstream\n")
|
||||
|
||||
fp.write("stream\n")
|
||||
fp.fp.write(op.getvalue())
|
||||
fp.write("\nendstream\n")
|
||||
_endobj(fp)
|
||||
|
||||
_endobj(fp)
|
||||
#
|
||||
# page
|
||||
|
||||
#
|
||||
# page
|
||||
xref.append(fp.tell())
|
||||
_obj(fp, pageNumber*3+4)
|
||||
fp.write(
|
||||
"<<\n/Type /Page\n/Parent 2 0 R\n"
|
||||
"/Resources <<\n/ProcSet [ /PDF %s ]\n"
|
||||
"/XObject << /image %d 0 R >>\n>>\n"
|
||||
"/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\n" % (
|
||||
procset,
|
||||
pageNumber*3+3,
|
||||
int(width * 72.0 / resolution),
|
||||
int(height * 72.0 / resolution),
|
||||
pageNumber*3+5))
|
||||
_endobj(fp)
|
||||
|
||||
xref.append(fp.tell())
|
||||
_obj(fp, pageNumber*3+4)
|
||||
fp.write(
|
||||
"<<\n/Type /Page\n/Parent 2 0 R\n"
|
||||
"/Resources <<\n/ProcSet [ /PDF %s ]\n"
|
||||
"/XObject << /image %d 0 R >>\n>>\n"
|
||||
"/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\n" % (
|
||||
procset,
|
||||
pageNumber*3+3,
|
||||
int(width * 72.0 / resolution),
|
||||
int(height * 72.0 / resolution),
|
||||
pageNumber*3+5))
|
||||
_endobj(fp)
|
||||
#
|
||||
# page contents
|
||||
|
||||
#
|
||||
# page contents
|
||||
op = TextWriter(io.BytesIO())
|
||||
|
||||
op = TextWriter(io.BytesIO())
|
||||
op.write(
|
||||
"q %d 0 0 %d 0 0 cm /image Do Q\n" % (
|
||||
int(width * 72.0 / resolution),
|
||||
int(height * 72.0 / resolution)))
|
||||
|
||||
op.write(
|
||||
"q %d 0 0 %d 0 0 cm /image Do Q\n" % (
|
||||
int(width * 72.0 / resolution),
|
||||
int(height * 72.0 / resolution)))
|
||||
xref.append(fp.tell())
|
||||
_obj(fp, pageNumber*3+5, Length=len(op.fp.getvalue()))
|
||||
|
||||
xref.append(fp.tell())
|
||||
_obj(fp, pageNumber*3+5, Length=len(op.fp.getvalue()))
|
||||
fp.write("stream\n")
|
||||
fp.fp.write(op.fp.getvalue())
|
||||
fp.write("\nendstream\n")
|
||||
|
||||
fp.write("stream\n")
|
||||
fp.fp.write(op.fp.getvalue())
|
||||
fp.write("\nendstream\n")
|
||||
_endobj(fp)
|
||||
|
||||
_endobj(fp)
|
||||
pageNumber += 1
|
||||
|
||||
#
|
||||
# trailer
|
||||
|
|
|
@ -2,45 +2,26 @@ from . import Image
|
|||
|
||||
modules = {
|
||||
"pil": "PIL._imaging",
|
||||
"tkinter": "PIL._imagingtk",
|
||||
"tkinter": "PIL._tkinter_finder",
|
||||
"freetype2": "PIL._imagingft",
|
||||
"littlecms2": "PIL._imagingcms",
|
||||
"webp": "PIL._webp",
|
||||
"transp_webp": ("WEBP", "WebPDecoderBuggyAlpha")
|
||||
}
|
||||
|
||||
|
||||
def check_module(feature):
|
||||
if feature not in modules:
|
||||
if not (feature in modules):
|
||||
raise ValueError("Unknown module %s" % feature)
|
||||
|
||||
module = modules[feature]
|
||||
|
||||
method_to_call = None
|
||||
if isinstance(module, tuple):
|
||||
module, method_to_call = module
|
||||
|
||||
try:
|
||||
imported_module = __import__(module)
|
||||
except ImportError:
|
||||
# If a method is being checked, None means that
|
||||
# rather than the method failing, the module required for the method
|
||||
# failed to be imported first
|
||||
return None if method_to_call else False
|
||||
|
||||
if method_to_call:
|
||||
method = getattr(imported_module, method_to_call)
|
||||
return method() is True
|
||||
else:
|
||||
return True
|
||||
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
def get_supported_modules():
|
||||
supported_modules = []
|
||||
for feature in modules:
|
||||
if check_module(feature):
|
||||
supported_modules.append(feature)
|
||||
return supported_modules
|
||||
return [f for f in modules if check_module(f)]
|
||||
|
||||
codecs = {
|
||||
"jpg": "jpeg",
|
||||
|
@ -49,7 +30,6 @@ codecs = {
|
|||
"libtiff": "libtiff"
|
||||
}
|
||||
|
||||
|
||||
def check_codec(feature):
|
||||
if feature not in codecs:
|
||||
raise ValueError("Unknown codec %s" % feature)
|
||||
|
@ -60,8 +40,38 @@ def check_codec(feature):
|
|||
|
||||
|
||||
def get_supported_codecs():
|
||||
supported_codecs = []
|
||||
for feature in codecs:
|
||||
if check_codec(feature):
|
||||
supported_codecs.append(feature)
|
||||
return supported_codecs
|
||||
return [f for f in codecs if check_codec(f)]
|
||||
|
||||
features = {
|
||||
"webp_mux": ("PIL._webp", 'HAVE_WEBPMUX'),
|
||||
"transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"),
|
||||
}
|
||||
|
||||
def check_feature(feature):
|
||||
if feature not in features:
|
||||
raise ValueError("Unknown feature %s" % feature)
|
||||
|
||||
module, flag = features[feature]
|
||||
|
||||
try:
|
||||
imported_module = __import__(module, fromlist=['PIL'])
|
||||
return getattr(imported_module, flag)
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
|
||||
def get_supported_features():
|
||||
return [f for f in features if check_feature(f)]
|
||||
|
||||
|
||||
def check(feature):
|
||||
return (feature in modules and check_module(feature) or \
|
||||
feature in codecs and check_codec(feature) or \
|
||||
feature in features and check_feature(feature))
|
||||
|
||||
def get_supported():
|
||||
ret = get_supported_modules()
|
||||
ret.extend(get_supported_features())
|
||||
ret.extend(get_supported_codecs())
|
||||
return ret
|
||||
|
||||
|
|
BIN
Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara
Normal file
BIN
Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
Tests/images/imagedraw_arc_end_le_start.png
Normal file
After Width: | Height: | Size: 218 B |
BIN
Tests/images/imagedraw_arc_no_loops.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
Tests/images/imagedraw_big_rectangle.png
Normal file
After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 326 B |
BIN
Tests/images/imagedraw_chord_L.png
Normal file
After Width: | Height: | Size: 257 B |
BIN
Tests/images/imagedraw_chord_RGB.png
Normal file
After Width: | Height: | Size: 324 B |
BIN
Tests/images/imagedraw_ellipse_L.png
Normal file
After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 466 B After Width: | Height: | Size: 466 B |
BIN
Tests/images/imagedraw_polygon_kite_L.png
Normal file
After Width: | Height: | Size: 499 B |
BIN
Tests/images/imagedraw_polygon_kite_RGB.png
Normal file
After Width: | Height: | Size: 647 B |
BIN
Tests/images/imagedraw_wide_line_dot.png
Normal file
After Width: | Height: | Size: 116 B |
|
@ -99,8 +99,7 @@ class TestBmpReference(PillowTestCase):
|
|||
os.path.join(base, 'g', 'pal8rle.bmp'),
|
||||
os.path.join(base, 'g', 'pal4rle.bmp'))
|
||||
if f not in unsupported:
|
||||
self.assertTrue(
|
||||
False, "Unsupported Image %s: %s" % (f, msg))
|
||||
self.fail("Unsupported Image %s: %s" % (f, msg))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -21,7 +21,7 @@ class TestDecompressionBomb(PillowTestCase):
|
|||
# Arrange
|
||||
# Turn limit off
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
self.assertEqual(Image.MAX_IMAGE_PIXELS, None)
|
||||
self.assertIsNone(Image.MAX_IMAGE_PIXELS)
|
||||
|
||||
# Act / Assert
|
||||
# Implicit assert: no warning.
|
||||
|
|
|
@ -2,19 +2,50 @@ from helper import unittest, PillowTestCase
|
|||
|
||||
from PIL import features
|
||||
|
||||
try:
|
||||
from PIL import _webp
|
||||
HAVE_WEBP = True
|
||||
except:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
class TestFeatures(PillowTestCase):
|
||||
|
||||
def test_check_features(self):
|
||||
for feature in features.modules:
|
||||
self.assertTrue(
|
||||
features.check_module(feature) in [True, False, None])
|
||||
for feature in features.codecs:
|
||||
self.assertTrue(features.check_codec(feature) in [True, False])
|
||||
def test_check(self):
|
||||
# Check the correctness of the convenience function
|
||||
for module in features.modules:
|
||||
self.assertEqual(features.check_module(module),
|
||||
features.check(module))
|
||||
for codec in features.codecs:
|
||||
self.assertEqual(features.check_codec(codec),
|
||||
features.check(codec))
|
||||
for feature in features.features:
|
||||
self.assertEqual(features.check_feature(feature),
|
||||
features.check(feature))
|
||||
|
||||
def test_supported_features(self):
|
||||
@unittest.skipUnless(HAVE_WEBP, True)
|
||||
def check_webp_transparency(self):
|
||||
self.assertEqual(features.check('transp_webp'),
|
||||
not _webp.WebPDecoderBuggyAlpha())
|
||||
self.assertEqual(features.check('transp_webp'),
|
||||
_webp.HAVE_TRANSPARENCY)
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP, True)
|
||||
def check_webp_mux(self):
|
||||
self.assertEqual(features.check('webp_mux'),
|
||||
_webp.HAVE_WEBPMUX)
|
||||
|
||||
def test_check_modules(self):
|
||||
for feature in features.modules:
|
||||
self.assertIn(features.check_module(feature), [True, False])
|
||||
for feature in features.codecs:
|
||||
self.assertIn(features.check_codec(feature), [True, False])
|
||||
|
||||
def test_supported_modules(self):
|
||||
self.assertIsInstance(features.get_supported_modules(), list)
|
||||
self.assertIsInstance(features.get_supported_codecs(), list)
|
||||
self.assertIsInstance(features.get_supported_features(), list)
|
||||
self.assertIsInstance(features.get_supported(), list)
|
||||
|
||||
def test_unsupported_codec(self):
|
||||
# Arrange
|
||||
|
|
|
@ -26,8 +26,8 @@ class TestFileCur(PillowTestCase):
|
|||
no_cursors_file = "Tests/images/no_cursors.cur"
|
||||
|
||||
cur = CurImagePlugin.CurImageFile(TEST_FILE)
|
||||
cur.fp = open(no_cursors_file, "rb")
|
||||
self.assertRaises(TypeError, cur._open)
|
||||
with open(no_cursors_file, "rb") as cur.fp:
|
||||
self.assertRaises(TypeError, cur._open)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -50,7 +50,7 @@ class TestFileDcx(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_seek_too_far(self):
|
||||
# Arrange
|
||||
|
|
|
@ -38,7 +38,7 @@ class TestFileFli(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -226,7 +226,7 @@ class TestFileGif(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_dispose_none(self):
|
||||
img = Image.open("Tests/images/dispose_none.gif")
|
||||
|
|
|
@ -30,7 +30,7 @@ class TestFileIm(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_roundtrip(self):
|
||||
out = self.tempfile('temp.im')
|
||||
|
|
|
@ -93,7 +93,7 @@ class TestFileJpeg(PillowTestCase):
|
|||
self.assertEqual(test(72), (72, 72))
|
||||
self.assertEqual(test(300), (300, 300))
|
||||
self.assertEqual(test(100, 200), (100, 200))
|
||||
self.assertEqual(test(0), None) # square pixels
|
||||
self.assertIsNone(test(0)) # square pixels
|
||||
|
||||
def test_icc(self):
|
||||
# Test ICC support
|
||||
|
@ -439,7 +439,7 @@ class TestFileJpeg(PillowTestCase):
|
|||
def test_no_duplicate_0x1001_tag(self):
|
||||
# Arrange
|
||||
from PIL import ExifTags
|
||||
tag_ids = dict(zip(ExifTags.TAGS.values(), ExifTags.TAGS.keys()))
|
||||
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}
|
||||
|
||||
# Assert
|
||||
self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001)
|
||||
|
|
|
@ -173,8 +173,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
'RowsPerStrip',
|
||||
'StripOffsets']
|
||||
for field in requested_fields:
|
||||
self.assertTrue(field in reloaded,
|
||||
"%s not in metadata" % field)
|
||||
self.assertIn(field, reloaded, "%s not in metadata" % field)
|
||||
|
||||
def test_additional_metadata(self):
|
||||
# these should not crash. Seriously dummy data, most of it doesn't make
|
||||
|
@ -190,7 +189,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
# Exclude ones that have special meaning
|
||||
# that we're already testing them
|
||||
im = Image.open('Tests/images/hopper_g4.tif')
|
||||
for tag in im.tag_v2.keys():
|
||||
for tag in im.tag_v2:
|
||||
try:
|
||||
del(core_items[tag])
|
||||
except:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
|
||||
from PIL import McIdasImagePlugin
|
||||
from PIL import Image, McIdasImagePlugin
|
||||
|
||||
|
||||
class TestFileMcIdas(PillowTestCase):
|
||||
|
@ -12,6 +12,24 @@ class TestFileMcIdas(PillowTestCase):
|
|||
lambda:
|
||||
McIdasImagePlugin.McIdasImageFile(invalid_file))
|
||||
|
||||
def test_valid_file(self):
|
||||
# Arrange
|
||||
# https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8
|
||||
# https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/
|
||||
test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara"
|
||||
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png"
|
||||
|
||||
# Act
|
||||
im = Image.open(test_file)
|
||||
im.load()
|
||||
|
||||
# Assert
|
||||
self.assertEqual(im.format, "MCIDAS")
|
||||
self.assertEqual(im.mode, "I")
|
||||
self.assertEqual(im.size, (1800, 400))
|
||||
im2 = Image.open(saved_file)
|
||||
self.assert_image_equal(im, im2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -110,7 +110,7 @@ class TestFileMpo(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_image_grab(self):
|
||||
for test_file in test_files:
|
||||
|
|
|
@ -74,6 +74,12 @@ class TestFilePdf(PillowTestCase):
|
|||
self.assertTrue(os.path.isfile(outfile))
|
||||
self.assertGreater(os.path.getsize(outfile), 0)
|
||||
|
||||
# Append images
|
||||
im.save(outfile, save_all=True, append_images=[hopper()])
|
||||
|
||||
self.assertTrue(os.path.isfile(outfile))
|
||||
self.assertGreater(os.path.getsize(outfile), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -316,7 +316,7 @@ class TestFilePng(PillowTestCase):
|
|||
test_file = f.read()[:offset]
|
||||
|
||||
im = Image.open(BytesIO(test_file))
|
||||
self.assertTrue(im.fp is not None)
|
||||
self.assertIsNotNone(im.fp)
|
||||
self.assertRaises((IOError, SyntaxError), im.verify)
|
||||
|
||||
def test_verify_ignores_crc_error(self):
|
||||
|
@ -331,7 +331,7 @@ class TestFilePng(PillowTestCase):
|
|||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
try:
|
||||
im = load(image_data)
|
||||
self.assertTrue(im is not None)
|
||||
self.assertIsNotNone(im)
|
||||
finally:
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
|
@ -462,7 +462,7 @@ class TestFilePng(PillowTestCase):
|
|||
|
||||
def test_save_icc_profile(self):
|
||||
im = Image.open("Tests/images/icc_profile_none.png")
|
||||
self.assertEqual(im.info['icc_profile'], None)
|
||||
self.assertIsNone(im.info['icc_profile'])
|
||||
|
||||
with_icc = Image.open("Tests/images/icc_profile.png")
|
||||
expected_icc = with_icc.info['icc_profile']
|
||||
|
@ -485,7 +485,7 @@ class TestFilePng(PillowTestCase):
|
|||
|
||||
def test_roundtrip_no_icc_profile(self):
|
||||
im = Image.open("Tests/images/icc_profile_none.png")
|
||||
self.assertEqual(im.info['icc_profile'], None)
|
||||
self.assertIsNone(im.info['icc_profile'])
|
||||
|
||||
im = roundtrip(im)
|
||||
self.assertNotIn('icc_profile', im.info)
|
||||
|
|
|
@ -44,7 +44,7 @@ class TestImagePsd(PillowTestCase):
|
|||
im.seek(n_frames+1)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_seek_tell(self):
|
||||
im = Image.open(test_file)
|
||||
|
|
|
@ -69,7 +69,7 @@ class TestImageSpider(PillowTestCase):
|
|||
img_list = SpiderImagePlugin.loadImageSeries(file_list)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(img_list, None)
|
||||
self.assertIsNone(img_list)
|
||||
|
||||
def test_isInt_not_a_number(self):
|
||||
# Arrange
|
||||
|
|
|
@ -234,7 +234,7 @@ class TestFileTiff(PillowTestCase):
|
|||
im.seek(n_frames)
|
||||
break
|
||||
except EOFError:
|
||||
self.assertTrue(im.tell() < n_frames)
|
||||
self.assertLess(im.tell(), n_frames)
|
||||
|
||||
def test_multipage(self):
|
||||
# issue #862
|
||||
|
@ -482,7 +482,6 @@ class TestFileTiff(PillowTestCase):
|
|||
im.load()
|
||||
self.assertFalse(fp.closed)
|
||||
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
|
||||
class TestFileTiffW32(PillowTestCase):
|
||||
def test_fd_leak(self):
|
||||
|
|
|
@ -96,7 +96,7 @@ class TestFileWebpMetadata(PillowTestCase):
|
|||
|
||||
file_path = "Tests/images/flower.jpg"
|
||||
image = Image.open(file_path)
|
||||
self.assertTrue('exif' in image.info)
|
||||
self.assertIn('exif', image.info)
|
||||
|
||||
test_buffer = BytesIO()
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ class TestImage(PillowTestCase):
|
|||
im2 = Image.new('RGB', (25, 25), 'white')
|
||||
|
||||
# Act / Assert
|
||||
self.assertTrue(im1 != im2)
|
||||
self.assertNotEqual(im1, im2)
|
||||
|
||||
def test_alpha_composite(self):
|
||||
# https://stackoverflow.com/questions/3374878
|
||||
|
@ -390,7 +390,7 @@ class TestRegistry(PillowTestCase):
|
|||
def test_encode_registry(self):
|
||||
|
||||
Image.register_encoder('MOCK', mock_encode)
|
||||
self.assert_('MOCK' in Image.ENCODERS)
|
||||
self.assertIn('MOCK', Image.ENCODERS)
|
||||
|
||||
enc = Image._getencoder('RGB', 'MOCK', ('args',), extra=('extra',))
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class TestImageGetBbox(PillowTestCase):
|
|||
|
||||
# 8-bit mode
|
||||
im = Image.new("L", (100, 100), 0)
|
||||
self.assertEqual(im.getbbox(), None)
|
||||
self.assertIsNone(im.getbbox())
|
||||
|
||||
im.paste(255, (10, 25, 90, 75))
|
||||
self.assertEqual(im.getbbox(), (10, 25, 90, 75))
|
||||
|
@ -27,7 +27,7 @@ class TestImageGetBbox(PillowTestCase):
|
|||
|
||||
# 32-bit mode
|
||||
im = Image.new("RGB", (100, 100), 0)
|
||||
self.assertEqual(im.getbbox(), None)
|
||||
self.assertIsNone(im.getbbox())
|
||||
|
||||
im.paste(255, (10, 25, 90, 75))
|
||||
self.assertEqual(im.getbbox(), (10, 25, 90, 75))
|
||||
|
|
|
@ -20,15 +20,15 @@ class TestImageGetColors(PillowTestCase):
|
|||
self.assertEqual(getcolors("I"), 255)
|
||||
self.assertEqual(getcolors("F"), 255)
|
||||
self.assertEqual(getcolors("P"), 90) # fixed palette
|
||||
self.assertEqual(getcolors("RGB"), None)
|
||||
self.assertEqual(getcolors("RGBA"), None)
|
||||
self.assertEqual(getcolors("CMYK"), None)
|
||||
self.assertEqual(getcolors("YCbCr"), None)
|
||||
self.assertIsNone(getcolors("RGB"))
|
||||
self.assertIsNone(getcolors("RGBA"))
|
||||
self.assertIsNone(getcolors("CMYK"))
|
||||
self.assertIsNone(getcolors("YCbCr"))
|
||||
|
||||
self.assertEqual(getcolors("L", 128), None)
|
||||
self.assertIsNone(getcolors("L", 128))
|
||||
self.assertEqual(getcolors("L", 1024), 255)
|
||||
|
||||
self.assertEqual(getcolors("RGB", 8192), None)
|
||||
self.assertIsNone(getcolors("RGB", 8192))
|
||||
self.assertEqual(getcolors("RGB", 16384), 10100)
|
||||
self.assertEqual(getcolors("RGB", 100000), 10100)
|
||||
|
||||
|
@ -48,7 +48,7 @@ class TestImageGetColors(PillowTestCase):
|
|||
(7960, (31, 20, 33))]
|
||||
|
||||
A = im.getcolors(maxcolors=2)
|
||||
self.assertEqual(A, None)
|
||||
self.assertIsNone(A)
|
||||
|
||||
A = im.getcolors(maxcolors=3)
|
||||
A.sort()
|
||||
|
|
|
@ -9,15 +9,15 @@ class TestImageGetPalette(PillowTestCase):
|
|||
if p:
|
||||
return p[:10]
|
||||
return None
|
||||
self.assertEqual(palette("1"), None)
|
||||
self.assertEqual(palette("L"), None)
|
||||
self.assertEqual(palette("I"), None)
|
||||
self.assertEqual(palette("F"), None)
|
||||
self.assertIsNone(palette("1"))
|
||||
self.assertIsNone(palette("L"))
|
||||
self.assertIsNone(palette("I"))
|
||||
self.assertIsNone(palette("F"))
|
||||
self.assertEqual(palette("P"), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
self.assertEqual(palette("RGB"), None)
|
||||
self.assertEqual(palette("RGBA"), None)
|
||||
self.assertEqual(palette("CMYK"), None)
|
||||
self.assertEqual(palette("YCbCr"), None)
|
||||
self.assertIsNone(palette("RGB"))
|
||||
self.assertIsNone(palette("RGBA"))
|
||||
self.assertIsNone(palette("CMYK"))
|
||||
self.assertIsNone(palette("YCbCr"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -16,8 +16,8 @@ class TestImagingResampleVulnerability(PillowTestCase):
|
|||
def test_invalid_size(self):
|
||||
im = hopper()
|
||||
|
||||
# Should not crash
|
||||
im.resize((100, 100))
|
||||
self.assertTrue(True, "Should not Crash")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
im.resize((-100, 100))
|
||||
|
|
|
@ -222,7 +222,7 @@ class TestImageCms(PillowTestCase):
|
|||
self.assertTrue(img_srgb.info['icc_profile'])
|
||||
|
||||
profile = ImageCmsProfile(BytesIO(img_srgb.info['icc_profile']))
|
||||
self.assertTrue('sRGB' in ImageCms.getProfileDescription(profile))
|
||||
self.assertIn('sRGB', ImageCms.getProfileDescription(profile))
|
||||
|
||||
def test_lab_roundtrip(self):
|
||||
# check to see if we're at least internally consistent.
|
||||
|
@ -275,12 +275,12 @@ class TestImageCms(PillowTestCase):
|
|||
assert_truncated_tuple_equal(p.blue_colorant, ((0.14306640625, 0.06060791015625, 0.7140960693359375), (0.1558847490315394, 0.06603820639433387, 0.06060791015625)))
|
||||
assert_truncated_tuple_equal(p.blue_primary, ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015), (0.15588475410450106, 0.06603820408959558, 0.06060790921083026)))
|
||||
assert_truncated_tuple_equal(p.chromatic_adaptation, (((1.04791259765625, 0.0229339599609375, -0.050201416015625), (0.02960205078125, 0.9904632568359375, -0.0170745849609375), (-0.009246826171875, 0.0150604248046875, 0.7517852783203125)), ((1.0267159024652783, 0.022470062342089134, 0.0229339599609375), (0.02951378324103937, 0.9875098886387147, 0.9904632568359375), (-0.012205438066465256, 0.01987915407854985, 0.0150604248046875))))
|
||||
self.assertEqual(p.chromaticity, None)
|
||||
self.assertIsNone(p.chromaticity)
|
||||
self.assertEqual(p.clut, {0: (False, False, True), 1: (False, False, True), 2: (False, False, True), 3: (False, False, True)})
|
||||
self.assertEqual(p.color_space, 'RGB')
|
||||
self.assertEqual(p.colorant_table, None)
|
||||
self.assertEqual(p.colorant_table_out, None)
|
||||
self.assertEqual(p.colorimetric_intent, None)
|
||||
self.assertIsNone(p.colorant_table)
|
||||
self.assertIsNone(p.colorant_table_out)
|
||||
self.assertIsNone(p.colorimetric_intent)
|
||||
self.assertEqual(p.connection_space, 'XYZ ')
|
||||
self.assertEqual(p.copyright, 'Copyright International Color Consortium, 2009')
|
||||
self.assertEqual(p.creation_date, datetime.datetime(2009, 2, 27, 21, 36, 31))
|
||||
|
@ -292,17 +292,17 @@ class TestImageCms(PillowTestCase):
|
|||
self.assertEqual(p.header_model, '\x00\x00\x00\x00')
|
||||
self.assertEqual(p.icc_measurement_condition, {'backing': (0.0, 0.0, 0.0), 'flare': 0.0, 'geo': 'unknown', 'observer': 1, 'illuminant_type': 'D65'})
|
||||
self.assertEqual(p.icc_version, 33554432)
|
||||
self.assertEqual(p.icc_viewing_condition, None)
|
||||
self.assertIsNone(p.icc_viewing_condition)
|
||||
self.assertEqual(p.intent_supported, {0: (True, True, True), 1: (True, True, True), 2: (True, True, True), 3: (True, True, True)})
|
||||
self.assertEqual(p.is_matrix_shaper, True)
|
||||
self.assertTrue(p.is_matrix_shaper)
|
||||
self.assertEqual(p.luminance, ((0.0, 80.0, 0.0), (0.0, 1.0, 80.0)))
|
||||
self.assertEqual(p.manufacturer, None)
|
||||
self.assertIsNone(p.manufacturer)
|
||||
assert_truncated_tuple_equal(p.media_black_point, ((0.012054443359375, 0.0124969482421875, 0.01031494140625), (0.34573304157549234, 0.35842450765864337, 0.0124969482421875)))
|
||||
assert_truncated_tuple_equal(p.media_white_point, ((0.964202880859375, 1.0, 0.8249053955078125), (0.3457029219802284, 0.3585375327567059, 1.0)))
|
||||
assert_truncated_tuple_equal((p.media_white_point_temperature,), (5000.722328847392,))
|
||||
self.assertEqual(p.model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB')
|
||||
self.assertEqual(p.pcs, 'XYZ')
|
||||
self.assertEqual(p.perceptual_rendering_intent_gamut, None)
|
||||
self.assertIsNone(p.perceptual_rendering_intent_gamut)
|
||||
self.assertEqual(p.product_copyright, 'Copyright International Color Consortium, 2009')
|
||||
self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled')
|
||||
self.assertEqual(p.product_description, 'sRGB IEC61966-2-1 black scaled')
|
||||
|
@ -313,9 +313,9 @@ class TestImageCms(PillowTestCase):
|
|||
assert_truncated_tuple_equal(p.red_colorant, ((0.436065673828125, 0.2224884033203125, 0.013916015625), (0.6484536316398539, 0.3308524880306778, 0.2224884033203125)))
|
||||
assert_truncated_tuple_equal(p.red_primary, ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925), (0.6484536250319214, 0.3308524944738204, 0.22248840582960838)))
|
||||
self.assertEqual(p.rendering_intent, 0)
|
||||
self.assertEqual(p.saturation_rendering_intent_gamut, None)
|
||||
self.assertEqual(p.screening_description, None)
|
||||
self.assertEqual(p.target, None)
|
||||
self.assertIsNone(p.saturation_rendering_intent_gamut)
|
||||
self.assertIsNone(p.screening_description)
|
||||
self.assertIsNone(p.target)
|
||||
self.assertEqual(p.technology, 'CRT ')
|
||||
self.assertEqual(p.version, 2.0)
|
||||
self.assertEqual(p.viewing_condition, 'Reference Viewing Condition in IEC 61966-2-1')
|
||||
|
|
|
@ -119,7 +119,7 @@ class TestImageColor(PillowTestCase):
|
|||
# look for rounding errors (based on code by Tim Hatch)
|
||||
def test_rounding_errors(self):
|
||||
|
||||
for color in list(ImageColor.colormap.keys()):
|
||||
for color in ImageColor.colormap:
|
||||
expected = Image.new(
|
||||
"RGB", (1, 1), color).convert("L").getpixel((0, 0))
|
||||
actual = ImageColor.getcolor(color, 'L')
|
||||
|
|
|
@ -30,6 +30,8 @@ BBOX2 = [X0, Y0, X1, Y1]
|
|||
POINTS1 = [(10, 10), (20, 40), (30, 30)]
|
||||
POINTS2 = [10, 10, 20, 40, 30, 30]
|
||||
|
||||
KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]
|
||||
|
||||
|
||||
class TestImageDraw(PillowTestCase):
|
||||
|
||||
|
@ -78,6 +80,37 @@ class TestImageDraw(PillowTestCase):
|
|||
self.helper_arc(BBOX2, 0, 180)
|
||||
self.helper_arc(BBOX2, 0.5, 180.4)
|
||||
|
||||
def test_arc_end_le_start(self):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
start = 270.5
|
||||
end = 0
|
||||
|
||||
# Act
|
||||
draw.arc(BBOX1, start=start, end=end)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(
|
||||
im, Image.open("Tests/images/imagedraw_arc_end_le_start.png"))
|
||||
|
||||
def test_arc_no_loops(self):
|
||||
# No need to go in loops
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
start = 5
|
||||
end = 370
|
||||
|
||||
# Act
|
||||
draw.arc(BBOX1, start=start, end=end)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_arc_no_loops.png"), 1)
|
||||
|
||||
def test_bitmap(self):
|
||||
# Arrange
|
||||
small = Image.open("Tests/images/pil123rgba.png").resize((50, 50))
|
||||
|
@ -92,45 +125,49 @@ class TestImageDraw(PillowTestCase):
|
|||
self.assert_image_equal(
|
||||
im, Image.open("Tests/images/imagedraw_bitmap.png"))
|
||||
|
||||
def helper_chord(self, bbox, start, end):
|
||||
def helper_chord(self, mode, bbox, start, end):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
im = Image.new(mode, (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_chord_{}.png".format(mode)
|
||||
|
||||
# Act
|
||||
draw.chord(bbox, start, end, fill="red", outline="yellow")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_chord.png"), 1)
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
||||
def test_chord1(self):
|
||||
self.helper_chord(BBOX1, 0, 180)
|
||||
self.helper_chord(BBOX1, 0.5, 180.4)
|
||||
for mode in ["RGB", "L"]:
|
||||
self.helper_chord(mode, BBOX1, 0, 180)
|
||||
self.helper_chord(mode, BBOX1, 0.5, 180.4)
|
||||
|
||||
def test_chord2(self):
|
||||
self.helper_chord(BBOX2, 0, 180)
|
||||
self.helper_chord(BBOX2, 0.5, 180.4)
|
||||
for mode in ["RGB", "L"]:
|
||||
self.helper_chord(mode, BBOX2, 0, 180)
|
||||
self.helper_chord(mode, BBOX2, 0.5, 180.4)
|
||||
|
||||
def helper_ellipse(self, bbox):
|
||||
def helper_ellipse(self, mode, bbox):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
im = Image.new(mode, (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode)
|
||||
|
||||
# Act
|
||||
draw.ellipse(bbox, fill="green", outline="blue")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_ellipse.png"), 1)
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
||||
def test_ellipse1(self):
|
||||
self.helper_ellipse(BBOX1)
|
||||
for mode in ["RGB", "L"]:
|
||||
self.helper_ellipse(mode, BBOX1)
|
||||
|
||||
def test_ellipse2(self):
|
||||
self.helper_ellipse(BBOX2)
|
||||
for mode in ["RGB", "L"]:
|
||||
self.helper_ellipse(mode, BBOX2)
|
||||
|
||||
def test_ellipse_edge(self):
|
||||
# Arrange
|
||||
|
@ -267,6 +304,23 @@ class TestImageDraw(PillowTestCase):
|
|||
def test_polygon2(self):
|
||||
self.helper_polygon(POINTS2)
|
||||
|
||||
def test_polygon_kite(self):
|
||||
# Test drawing lines of different gradients (dx>dy, dy>dx) and
|
||||
# vertical (dx==0) and horizontal (dy==0) lines
|
||||
for mode in ["RGB", "L"]:
|
||||
# Arrange
|
||||
im = Image.new(mode, (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_polygon_kite_{}.png".format(
|
||||
mode)
|
||||
|
||||
# Act
|
||||
draw.polygon(KITE_POINTS, fill="blue", outline="yellow")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_equal(im, Image.open(expected))
|
||||
|
||||
def helper_rectangle(self, bbox):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
|
@ -286,6 +340,21 @@ class TestImageDraw(PillowTestCase):
|
|||
def test_rectangle2(self):
|
||||
self.helper_rectangle(BBOX2)
|
||||
|
||||
def test_big_rectangle(self):
|
||||
# Test drawing a rectangle bigger than the image
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
bbox = [(-1, -1), (W+1, H+1)]
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_big_rectangle.png"
|
||||
|
||||
# Act
|
||||
draw.rectangle(bbox, fill="orange")
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
||||
def test_floodfill(self):
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
|
@ -478,6 +547,21 @@ class TestImageDraw(PillowTestCase):
|
|||
self.assert_image_equal(img, expected,
|
||||
'line oblique 45 inverted 3px wide B failed')
|
||||
|
||||
def test_wide_line_dot(self):
|
||||
# Test drawing a wide "line" from one point to another just draws
|
||||
# a single point
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_wide_line_dot.png"
|
||||
|
||||
# Act
|
||||
draw.line([(50, 50), (50, 50)], width=3)
|
||||
del draw
|
||||
|
||||
# Assert
|
||||
self.assert_image_similar(im, Image.open(expected), 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -38,7 +38,7 @@ class TestImageGrabImport(PillowTestCase):
|
|||
|
||||
# Assert
|
||||
if sys.platform in ["win32", "darwin"]:
|
||||
self.assertIsNone(exception, None)
|
||||
self.assertIsNone(exception)
|
||||
else:
|
||||
self.assertIsInstance(exception, ImportError)
|
||||
self.assertEqual(str(exception),
|
||||
|
|
|
@ -176,6 +176,40 @@ class MorphTests(PillowTestCase):
|
|||
self.assertEqual(len(coords), 4)
|
||||
self.assertEqual(tuple(coords), ((2, 2), (4, 2), (2, 4), (4, 4)))
|
||||
|
||||
def test_mirroring(self):
|
||||
# Test 'M' for mirroring
|
||||
mop = ImageMorph.MorphOp(patterns=['1:(... ... ...)->0',
|
||||
'M:(00. 01. ...)->1'])
|
||||
count, Aout = mop.apply(self.A)
|
||||
self.assertEqual(count, 7)
|
||||
self.assert_img_equal_img_string(Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1.1..
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""")
|
||||
|
||||
def test_negate(self):
|
||||
# Test 'N' for negate
|
||||
mop = ImageMorph.MorphOp(patterns=['1:(... ... ...)->0',
|
||||
'N:(00. 01. ...)->1'])
|
||||
count, Aout = mop.apply(self.A)
|
||||
self.assertEqual(count, 8)
|
||||
self.assert_img_equal_img_string(Aout,
|
||||
"""
|
||||
.......
|
||||
.......
|
||||
..1....
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
.......
|
||||
""")
|
||||
|
||||
def test_non_binary_images(self):
|
||||
im = hopper('RGB')
|
||||
mop = ImageMorph.MorphOp(op_name="erosion8")
|
||||
|
@ -184,6 +218,74 @@ class MorphTests(PillowTestCase):
|
|||
self.assertRaises(Exception, lambda: mop.match(im))
|
||||
self.assertRaises(Exception, lambda: mop.get_on_pixels(im))
|
||||
|
||||
def test_add_patterns(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name='corner')
|
||||
self.assertEqual(lb.patterns, ['1:(... ... ...)->0',
|
||||
'4:(00. 01. ...)->1'])
|
||||
new_patterns = ['M:(00. 01. ...)->1',
|
||||
'N:(00. 01. ...)->1']
|
||||
|
||||
# Act
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(
|
||||
lb.patterns,
|
||||
['1:(... ... ...)->0',
|
||||
'4:(00. 01. ...)->1',
|
||||
'M:(00. 01. ...)->1',
|
||||
'N:(00. 01. ...)->1'])
|
||||
|
||||
def test_unknown_pattern(self):
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: ImageMorph.LutBuilder(op_name='unknown'))
|
||||
|
||||
def test_pattern_syntax_error(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name='corner')
|
||||
new_patterns = ['a pattern with a syntax error']
|
||||
lb.add_patterns(new_patterns)
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
lambda: lb.build_lut())
|
||||
|
||||
def test_load_invalid_mrl(self):
|
||||
# Arrange
|
||||
invalid_mrl = 'Tests/images/hopper.png'
|
||||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act / Assert
|
||||
self.assertRaises(Exception, lambda: mop.load_lut(invalid_mrl))
|
||||
|
||||
def test_roundtrip_mrl(self):
|
||||
# Arrange
|
||||
tempfile = self.tempfile('temp.mrl')
|
||||
mop = ImageMorph.MorphOp(op_name='corner')
|
||||
initial_lut = mop.lut
|
||||
|
||||
# Act
|
||||
mop.save_lut(tempfile)
|
||||
mop.load_lut(tempfile)
|
||||
|
||||
# Act / Assert
|
||||
self.assertEqual(mop.lut, initial_lut)
|
||||
|
||||
def test_set_lut(self):
|
||||
# Arrange
|
||||
lb = ImageMorph.LutBuilder(op_name='corner')
|
||||
lut = lb.build_lut()
|
||||
mop = ImageMorph.MorphOp()
|
||||
|
||||
# Act
|
||||
mop.set_lut(lut)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(mop.lut, lut)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -45,7 +45,7 @@ class TestImageTk(PillowTestCase):
|
|||
|
||||
# Test no relevant entry
|
||||
im = ImageTk._get_image_from_kw(kw)
|
||||
self.assertEqual(im, None)
|
||||
self.assertIsNone(im)
|
||||
|
||||
def test_photoimage(self):
|
||||
for mode in TK_MODES:
|
||||
|
|
|
@ -34,10 +34,10 @@ class Test_IFDRational(PillowTestCase):
|
|||
|
||||
xres = IFDRational(72)
|
||||
yres = IFDRational(72)
|
||||
self.assertTrue(xres._val is not None)
|
||||
self.assertTrue(xres.numerator is not None)
|
||||
self.assertTrue(xres.denominator is not None)
|
||||
self.assertTrue(yres._val is not None)
|
||||
self.assertIsNotNone(xres._val)
|
||||
self.assertIsNotNone(xres.numerator)
|
||||
self.assertIsNotNone(xres.denominator)
|
||||
self.assertIsNotNone(yres._val)
|
||||
|
||||
self.assertTrue(xres and 1)
|
||||
self.assertTrue(xres and yres)
|
||||
|
|
13
_imaging.c
|
@ -631,18 +631,6 @@ _new(PyObject* self, PyObject* args)
|
|||
return PyImagingNew(ImagingNew(mode, xsize, ysize));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_new_array(PyObject* self, PyObject* args)
|
||||
{
|
||||
char* mode;
|
||||
int xsize, ysize;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize))
|
||||
return NULL;
|
||||
|
||||
return PyImagingNew(ImagingNewArray(mode, xsize, ysize));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
_new_block(PyObject* self, PyObject* args)
|
||||
{
|
||||
|
@ -3027,7 +3015,6 @@ static struct PyMethodDef methods[] = {
|
|||
#endif
|
||||
|
||||
/* Misc. */
|
||||
{"new_array", (PyCFunction)_new_array, 1},
|
||||
{"new_block", (PyCFunction)_new_block, 1},
|
||||
|
||||
{"save_ppm", (PyCFunction)_save_ppm, 1},
|
||||
|
|
13
_webp.c
|
@ -247,8 +247,12 @@ PyObject* WebPDecoderVersion_wrapper(PyObject* self, PyObject* args){
|
|||
* The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well.
|
||||
* Files that are valid with 0.3 are reported as being invalid.
|
||||
*/
|
||||
int WebPDecoderBuggyAlpha() {
|
||||
return WebPGetDecoderVersion()==0x0103;
|
||||
}
|
||||
|
||||
PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){
|
||||
return Py_BuildValue("i", WebPGetDecoderVersion()==0x0103);
|
||||
return Py_BuildValue("i", WebPDecoderBuggyAlpha());
|
||||
}
|
||||
|
||||
static PyMethodDef webpMethods[] =
|
||||
|
@ -268,6 +272,11 @@ void addMuxFlagToModule(PyObject* m) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void addTransparencyFlagToModule(PyObject* m) {
|
||||
PyModule_AddObject(m, "HAVE_TRANSPARENCY",
|
||||
PyBool_FromLong(!WebPDecoderBuggyAlpha()));
|
||||
}
|
||||
|
||||
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
PyMODINIT_FUNC
|
||||
|
@ -284,6 +293,7 @@ PyInit__webp(void) {
|
|||
|
||||
m = PyModule_Create(&module_def);
|
||||
addMuxFlagToModule(m);
|
||||
addTransparencyFlagToModule(m);
|
||||
return m;
|
||||
}
|
||||
#else
|
||||
|
@ -292,5 +302,6 @@ init_webp(void)
|
|||
{
|
||||
PyObject* m = Py_InitModule("_webp", webpMethods);
|
||||
addMuxFlagToModule(m);
|
||||
addTransparencyFlagToModule(m);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -45,8 +45,8 @@ image. The current release supports the following standard modes:
|
|||
PIL also provides limited support for a few special modes, including ``LA`` (L
|
||||
with alpha), ``RGBX`` (true color with padding) and ``RGBa`` (true color with
|
||||
premultiplied alpha). However, PIL doesn’t support user-defined modes; if you
|
||||
to handle band combinations that are not listed above, use a sequence of Image
|
||||
objects.
|
||||
need to handle band combinations that are not listed above, use a sequence of
|
||||
Image objects.
|
||||
|
||||
You can read the mode of an image through the :py:attr:`~PIL.Image.Image.mode`
|
||||
attribute. This is a string containing one of the above values.
|
||||
|
@ -114,7 +114,7 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
in the input image is used.
|
||||
|
||||
``HAMMING``
|
||||
Produces more sharp image than ``BILINEAR``, doesn't have dislocations
|
||||
Produces a sharper image than ``BILINEAR``, doesn't have dislocations
|
||||
on local level like with ``BOX``.
|
||||
This filter can only be used with the :py:meth:`~PIL.Image.Image.resize`
|
||||
and :py:meth:`~PIL.Image.Image.thumbnail` methods.
|
||||
|
|
|
@ -276,6 +276,7 @@ Converting between modes
|
|||
|
||||
::
|
||||
|
||||
from PIL import Image
|
||||
im = Image.open("hopper.ppm").convert("L")
|
||||
|
||||
The library supports transformations between each supported mode and the “L”
|
||||
|
@ -459,6 +460,7 @@ As described earlier, the :py:func:`~PIL.Image.open` function of the
|
|||
:py:mod:`~PIL.Image` module is used to open an image file. In most cases, you
|
||||
simply pass it the filename as an argument::
|
||||
|
||||
from PIL import Image
|
||||
im = Image.open("hopper.ppm")
|
||||
|
||||
If everything goes well, the result is an :py:class:`PIL.Image.Image` object.
|
||||
|
@ -473,8 +475,9 @@ Reading from an open file
|
|||
|
||||
::
|
||||
|
||||
fp = open("hopper.ppm", "rb")
|
||||
im = Image.open(fp)
|
||||
from PIL import Image
|
||||
with open("hopper.ppm", "rb") as fp:
|
||||
im = Image.open(fp)
|
||||
|
||||
To read an image from string data, use the :py:class:`~StringIO.StringIO`
|
||||
class:
|
||||
|
|
|
@ -402,11 +402,11 @@ These platforms have been reported to work at the versions mentioned.
|
|||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
| Gentoo Linux | 2.7,3.2 | 2.1.0 |x86-64 |
|
||||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
| FreeBSD 10.2 | 2.7,3.4 | 3.1.0 |x86-64 |
|
||||
| FreeBSD 11.0 | 2.7,3.4,3.5,3.6 | 4.1.1 |x86-64 |
|
||||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
| FreeBSD 10.3 | 2.7,3.4,3.5 | 4.1.1 |x86-64 |
|
||||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
| FreeBSD 11.0 | 2.7,3.4,3.5,3.6 | 4.1.1 |x86-64 |
|
||||
| FreeBSD 10.2 | 2.7,3.4 | 3.1.0 |x86-64 |
|
||||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
| Windows 8.1 Pro | 2.6,2.7,3.2,3.3,3.4 | 2.4.0 |x86,x86-64 |
|
||||
+----------------------------------+------------------------------+--------------------------------+-----------------------+
|
||||
|
|
|
@ -10,7 +10,7 @@ Internal Limits
|
|||
* Image sizes cannot be negative. These are checked both in
|
||||
``Storage.c`` and ``Image.py``
|
||||
|
||||
* Image sizes may be 0. (At least, prior to 3.4)
|
||||
* Image sizes may be 0. (Although not in 3.4)
|
||||
|
||||
* Maximum pixel dimensions are limited to INT32, or 2^31 by the sizes
|
||||
in the image header.
|
||||
|
|
|
@ -148,7 +148,7 @@ Blur performance
|
|||
|
||||
Box filter computation time is constant relative to the radius and depends
|
||||
on source image size only. Because the new Gaussian blur implementation
|
||||
is based on box filter, its computation time also doesn't depends on the blur
|
||||
is based on box filter, its computation time also doesn't depend on the blur
|
||||
radius.
|
||||
|
||||
For example, previously, if the execution time for a given test image was 1
|
||||
|
@ -172,4 +172,3 @@ specified as strings with included spaces (e.g. 'x resolution'). This
|
|||
was difficult to use as kwargs without constructing and passing a
|
||||
dictionary. These parameters now use the underscore character instead
|
||||
of space. (e.g. 'x_resolution')
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ Out of Spec Metadata
|
|||
++++++++++++++++++++
|
||||
|
||||
In Pillow 3.0 and 3.1, images that contain metadata that is internally
|
||||
consistent but not in agreement with the TIFF spec may cause an
|
||||
consistent, but not in agreement with the TIFF spec, may cause an
|
||||
exception when reading the metadata. This can happen when a tag that
|
||||
is specified to have a single value is stored with an array of values.
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ Resizing
|
|||
========
|
||||
|
||||
Image resampling for 8-bit per channel images was rewritten using only integer
|
||||
computings. This is faster on most of the platforms and doesn't introduce
|
||||
precision errors on the wide range of scales. With other performance
|
||||
improvements, this makes resampling 60% faster on average.
|
||||
computings. This is faster on most platforms and doesn't introduce precision
|
||||
errors on the wide range of scales. With other performance improvements, this
|
||||
makes resampling 60% faster on average.
|
||||
|
||||
Color calculation for images in the ``LA`` mode on semitransparent pixels
|
||||
was fixed.
|
||||
|
@ -41,7 +41,7 @@ Rotation
|
|||
========
|
||||
|
||||
Rotation for angles divisible by 90 degrees now always uses transposition.
|
||||
This greatly improve both quality and performance in this cases.
|
||||
This greatly improves both quality and performance in this case.
|
||||
Also, the bug with wrong image size calculation when rotating by 90 degrees
|
||||
was fixed.
|
||||
|
||||
|
@ -52,4 +52,3 @@ Image Metadata
|
|||
The return type for binary data in version 2 Exif and Tiff metadata
|
||||
has been changed from a tuple of integers to bytes. This is a change
|
||||
from the behavior since ``3.0.0``.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ New resizing filters
|
|||
Two new filters available for ``Image.resize()`` and ``Image.thumbnail()``
|
||||
functions: ``BOX`` and ``HAMMING``. ``BOX`` is the high-performance filter with
|
||||
two times shorter window than ``BILINEAR``. It can be used for image reduction
|
||||
3 and more times and produces a more sharp result than ``BILINEAR``.
|
||||
3 and more times and produces a sharper result than ``BILINEAR``.
|
||||
|
||||
``HAMMING`` filter has the same performance as ``BILINEAR`` filter while
|
||||
providing the image downscaling quality comparable to ``BICUBIC``.
|
||||
|
@ -25,7 +25,7 @@ image as a JPEG. This will become an error in Pillow 4.2.
|
|||
New DDS Decoders
|
||||
================
|
||||
|
||||
Pillow can now decode DXT3 images, as well as the previously support
|
||||
Pillow can now decode DXT3 images, as well as the previously supported
|
||||
DXT1 and DXT5 formats. All three formats are now decoded in C code for
|
||||
better performance.
|
||||
|
||||
|
@ -44,7 +44,7 @@ in effect, e.g.::
|
|||
Save multiple frame TIFF
|
||||
========================
|
||||
|
||||
Multiple frames can now be saved in a TIFF file by using the ``save_all`` option.
|
||||
Multiple frames can now be saved in a TIFF file by using the ``save_all`` option.
|
||||
e.g.::
|
||||
|
||||
im.save("filename.tiff", format="TIFF", save_all=True)
|
||||
|
|
|
@ -605,11 +605,6 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1,
|
|||
|
||||
DRAWINIT();
|
||||
|
||||
if (width <= 1) {
|
||||
draw->line(im, x0, y0, x1, y1, ink);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dx = x1-x0;
|
||||
dy = y1-y0;
|
||||
if (dx == 0 && dy == 0) {
|
||||
|
@ -1030,20 +1025,6 @@ ImagingOutlineCurve(ImagingOutline outline, float x1, float y1,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ImagingOutlineCurve2(ImagingOutline outline, float cx, float cy,
|
||||
float x3, float y3)
|
||||
{
|
||||
/* add bezier curve based on three control points (as
|
||||
in the Flash file format) */
|
||||
|
||||
return ImagingOutlineCurve(
|
||||
outline,
|
||||
(outline->x + cx + cx)/3, (outline->y + cy + cy)/3,
|
||||
(cx + cx + x3)/3, (cy + cy + y3)/3,
|
||||
x3, y3);
|
||||
}
|
||||
|
||||
int
|
||||
ImagingOutlineClose(ImagingOutline outline)
|
||||
{
|
||||
|
|
|
@ -268,7 +268,7 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
|
|||
/* -------------------------------------------------------------------- */
|
||||
|
||||
int ImagingJpegDecodeCleanup(ImagingCodecState state){
|
||||
/* called to fee the decompression engine when the decode terminates
|
||||
/* called to free the decompression engine when the decode terminates
|
||||
due to a corrupt or truncated image
|
||||
*/
|
||||
JPEGSTATE* context = (JPEGSTATE*) state->context;
|
||||
|
|
|
@ -54,7 +54,8 @@ def _mp_compile(self, sources, output_dir=None, macros=None,
|
|||
|
||||
def install():
|
||||
|
||||
fl_pypy3 = hasattr(sys, 'pypy_version_info') and sys.version_info > (3, 0)
|
||||
fl_pypy3 = (hasattr(sys, 'pypy_version_info') and
|
||||
(3, 0) < sys.version_info < (3, 3))
|
||||
fl_win = sys.platform.startswith('win')
|
||||
fl_cygwin = sys.platform.startswith('cygwin')
|
||||
|
||||
|
@ -82,4 +83,5 @@ def install():
|
|||
print("Single threaded build, not installing mp_compile:"
|
||||
"%s processes" % MAX_PROCS)
|
||||
|
||||
|
||||
install()
|
||||
|
|
17
selftest.py
|
@ -178,25 +178,14 @@ if __name__ == "__main__":
|
|||
("freetype2", "FREETYPE2"),
|
||||
("littlecms2", "LITTLECMS2"),
|
||||
("webp", "WEBP"),
|
||||
("transp_webp", "Transparent WEBP")
|
||||
]:
|
||||
supported = features.check_module(name)
|
||||
|
||||
if supported is None:
|
||||
# A method was being tested, but the module required
|
||||
# for the method could not be correctly imported
|
||||
pass
|
||||
elif supported:
|
||||
print("---", feature, "support ok")
|
||||
else:
|
||||
print("***", feature, "support not installed")
|
||||
for name, feature in [
|
||||
("transp_webp", "Transparent WEBP"),
|
||||
("webp_mux", "WEBPMUX"),
|
||||
("jpg", "JPEG"),
|
||||
("jpg_2000", "OPENJPEG (JPEG2000)"),
|
||||
("zlib", "ZLIB (PNG/ZIP)"),
|
||||
("libtiff", "LIBTIFF")
|
||||
]:
|
||||
if features.check_codec(name):
|
||||
if features.check(name):
|
||||
print("---", feature, "support ok")
|
||||
else:
|
||||
print("***", feature, "support not installed")
|
||||
|
|
|
@ -12,7 +12,7 @@ from config import (compilers, compiler_from_env, pythons, pyversion_from_env,
|
|||
|
||||
def setup_vms():
|
||||
ret = []
|
||||
for py in pythons.keys():
|
||||
for py in pythons:
|
||||
for arch in ('', X64_EXT):
|
||||
ret.append("virtualenv -p c:/Python%s%s/python.exe --clear %s%s%s"
|
||||
% (py, arch, VIRT_BASE, py, arch))
|
||||
|
|
|
@ -116,7 +116,7 @@ def pyversion_from_env():
|
|||
py = os.environ['PYTHON']
|
||||
|
||||
py_version = '27'
|
||||
for k in pythons.keys():
|
||||
for k in pythons:
|
||||
if k in py:
|
||||
py_version = k
|
||||
break
|
||||
|
|