add python3 support

This commit is contained in:
John Cupitt 2014-12-10 17:02:51 +00:00
parent 9866127e6a
commit c3102b15bb
6 changed files with 67 additions and 34 deletions

View File

@ -6,6 +6,7 @@
- add .szi as a dzsave zip synonym
- support tiff XMP metadata
- support @density arg to magickload [Lovell]
- support python3.4 and python2.7 in new python binding
25/7/14 started 7.41.0
- start working on --disable-deprecated

View File

@ -1,15 +1,21 @@
# vips8 binding for Python
This overrides file adds a few small helper functions to the
gobject-introspection binding for libvips.
gobject-introspection binding for libvips. It works with python2.7 and
python3.4.
There's a chapter in the libvips API docs on these overrides, see "Using
libvips from Python".
vips-x.y.z/test has a test suite.
vips-x.y.z/test has a test suite. Again, the test suite works with python2.7
and python3.4.
Vips.py needs to be in the overrides directory of your gobject-introspection
pygobject area, for example:
sudo cp Vips.py /usr/lib/python2.7/dist-packages/gi/overrides
or
sudo cp Vips.py /usr/lib/python3.4/dist-packages/gi/overrides

View File

@ -1,9 +1,13 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# vim: tabstop=4 shiftwidth=4 expandtab
# copy this file to /usr/lib/python2.7/dist-packages/gi/overrides, eg.
# overrides for pygobject gobject-introspection binding for libvips, tested
# with python2.7 and python3.4
# copy this file to dist-packages/gi/overrides, eg.
#
# sudo cp Vips.py /usr/lib/python2.7/dist-packages/gi/overrides
# sudo cp Vips.py /usr/lib/python3/dist-packages/gi/overrides
#
# Alternatively, build vips to another prefix, then copy Vips.py and Vips.pyc
# from $prefix/lib/python2.7/dist-packages/gi/overrides to /usr
@ -26,6 +30,12 @@
#
# These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
from __future__ import division
from builtins import map
from builtins import str
from builtins import range
from builtins import object
import sys
import re
import logging
@ -113,7 +123,7 @@ class Error(Exception):
Vips.Error = Error
class Argument:
class Argument(object):
def __init__(self, op, prop):
self.op = op
self.prop = prop
@ -185,7 +195,7 @@ class Operation(Vips.Operation):
args = [Argument(self, x) for x in self.props]
args = [y for y in args
if not y.flags & Vips.ArgumentFlags.DEPRECATED]
args.sort(lambda a, b: a.priority - b.priority)
args.sort(key = lambda x: x.priority)
return args
@ -213,7 +223,7 @@ def _call_base(name, required, optional, self = None, option_string = None):
try:
op = Vips.Operation.new(name)
except TypeError, e:
except TypeError as e:
raise Error('No such operator.')
if op.get_flags() & Vips.OperationFlags.DEPRECATED:
raise Error('No such operator.', 'operator "%s" is deprecated' % name)
@ -285,7 +295,7 @@ def _call_base(name, required, optional, self = None, option_string = None):
not x.flags & enm.REQUIRED}
# set optional input args
for key in optional.keys():
for key in list(optional.keys()):
if key in optional_input:
optional_input[key].set_value(match_image, optional[key])
elif key in optional_output:
@ -322,7 +332,7 @@ def _call_base(name, required, optional, self = None, option_string = None):
out.append(x.get_value())
out_dict = {}
for x in optional.keys():
for x in list(optional.keys()):
if x in optional_output:
out_dict[x] = optional_output[x].get_value()
if out_dict != {}:
@ -425,7 +435,7 @@ setattr(Vips.Image, 'new_from_array', vips_image_new_from_array)
def generate_docstring(name):
try:
op = Vips.Operation.new(name)
except TypeError, e:
except TypeError as e:
raise Error('No such operator.')
if op.get_flags() & Vips.OperationFlags.DEPRECATED:
raise Error('No such operator.', 'operator "%s" is deprecated' % name)
@ -500,7 +510,7 @@ def generate_docstring(name):
# as well as scalars
def smap(func, x):
if isinstance(x, list):
return map(func, x)
return list(map(func, x))
else:
return func(x)
@ -595,6 +605,8 @@ class Image(Vips.Image):
def __rmul__(self, other):
return self.__mul__(other)
# a / const has always been a float in vips, so div and truediv are the
# same
def __div__(self, other):
if isinstance(other, Vips.Image):
return self.divide(other)
@ -604,6 +616,12 @@ class Image(Vips.Image):
def __rdiv__(self, other):
return (self ** -1) * other
def __truediv__(self, other):
return self.__div__(other)
def __rtruediv__(self, other):
return self.__rdiv__(other)
def __floordiv__(self, other):
if isinstance(other, Vips.Image):
return self.divide(other).floor()

View File

@ -1,5 +1,8 @@
#!/usr/bin/python
#!/usr/bin/python3
from __future__ import division
from builtins import zip
from builtins import range
import unittest
import math
@ -26,7 +29,7 @@ all_formats = int_formats + float_formats + complex_formats
# the other
def zip_expand(x, y):
if isinstance(x, list) and isinstance(y, list):
return zip(x, y)
return list(zip(x, y))
elif isinstance(x, list):
return [[i, y] for i in x]
elif isinstance(y, list):
@ -77,9 +80,9 @@ class TestArithmetic(unittest.TestCase):
self.run_cmp(message, im, 10, 10, lambda x: run_fn2(fn, c, x))
def run_arith_const(self, fn, fmt = all_formats):
[self.run_testconst(fn.func_name + ' scalar', fn, x.cast(y), 2)
[self.run_testconst(fn.__name__ + ' scalar', fn, x.cast(y), 2)
for x in self.all_images for y in fmt]
[self.run_testconst(fn.func_name + ' vector', fn, self.colour.cast(y),
[self.run_testconst(fn.__name__ + ' vector', fn, self.colour.cast(y),
[1, 2, 3])
for y in fmt]
@ -102,7 +105,7 @@ class TestArithmetic(unittest.TestCase):
lambda x, y: run_fn2(fn, x, y))
def run_arith(self, fn, fmt = all_formats):
[self.run_test2(fn.func_name + ' image', x.cast(y), x.cast(z), fn)
[self.run_test2(fn.__name__ + ' image', x.cast(y), x.cast(z), fn)
for x in self.all_images for y in fmt for z in fmt]
def setUp(self):
@ -279,7 +282,7 @@ class TestArithmetic(unittest.TestCase):
self.run_cmp(message, im, 10, 10, lambda x: run_fn(fn, x))
def run_unary(self, images, fn, fmt = all_formats):
[self.run_testunary(fn.func_name + ' image', x.cast(y), fn)
[self.run_testunary(fn.__name__ + ' image', x.cast(y), fn)
for x in images for y in fmt]
def test_abs(self):
@ -408,7 +411,7 @@ class TestArithmetic(unittest.TestCase):
def test_histfind_indexed(self):
im = Vips.Image.black(50, 100)
test = im.insert(im + 10, 50, 0, expand = True)
index = test / 10
index = test // 10
for x in noncomplex_formats:
for y in [Vips.BandFormat.UCHAR, Vips.BandFormat.USHORT]:
@ -459,8 +462,8 @@ class TestArithmetic(unittest.TestCase):
v, x, y = hough.maxpos()
angle = 360.0 * x / hough.width
distance = test.height * y / hough.height
angle = 360.0 * x // hough.width
distance = test.height * y // hough.height
self.assertAlmostEqual(angle, 45)
self.assertAlmostEqual(distance, 70)

View File

@ -1,5 +1,7 @@
#!/usr/bin/python
from builtins import zip
import unittest
import math
@ -40,7 +42,7 @@ all_colourspaces = colour_colourspaces + mono_colourspaces + coded_colourspaces
# the other
def zip_expand(x, y):
if isinstance(x, list) and isinstance(y, list):
return zip(x, y)
return list(zip(x, y))
elif isinstance(x, list):
return [[i, y] for i in x]
elif isinstance(y, list):

View File

@ -1,5 +1,7 @@
#!/usr/bin/python
from __future__ import division
from builtins import zip
import unittest
import math
@ -7,6 +9,7 @@ import math
#logging.basicConfig(level = logging.DEBUG)
from gi.repository import Vips
from functools import reduce
unsigned_formats = [Vips.BandFormat.UCHAR,
Vips.BandFormat.USHORT,
@ -76,7 +79,7 @@ rot_angle_bonds = [Vips.Angle.D0,
# the other
def zip_expand(x, y):
if isinstance(x, list) and isinstance(y, list):
return zip(x, y)
return list(zip(x, y))
elif isinstance(x, list):
return [[i, y] for i in x]
elif isinstance(y, list):
@ -123,11 +126,11 @@ class TestConversion(unittest.TestCase):
self.run_cmp_unary(message, im, 10, 10, fn)
def run_unary(self, images, fn, fmt = all_formats):
[self.run_testunary(fn.func_name + (' %s' % y), x.cast(y), fn)
[self.run_testunary(fn.__name__ + (' %s' % y), x.cast(y), fn)
for x in images for y in fmt]
def run_binary(self, images, fn, fmt = all_formats):
[self.run_testbinary(fn.func_name + (' %s %s' % (y, z)),
[self.run_testbinary(fn.__name__ + (' %s %s' % (y, z)),
x.cast(y), x.cast(z), fn)
for x in images for y in fmt for z in fmt]
@ -178,7 +181,7 @@ class TestConversion(unittest.TestCase):
if isinstance(x, Vips.Image):
return x.bandmean()
else:
return [sum(x) / len(x)]
return [sum(x) // len(x)]
self.run_unary([self.colour], bandmean, fmt = noncomplex_formats)
@ -188,7 +191,7 @@ class TestConversion(unittest.TestCase):
# .sort() isn't a function, so we have to run this as a separate
# pass
[x.sort() for x in joined]
return [x[len(x) / 2] for x in joined]
return [x[len(x) // 2] for x in joined]
def bandrank(x, y):
if isinstance(x, Vips.Image) and isinstance(y, Vips.Image):
@ -331,7 +334,7 @@ class TestConversion(unittest.TestCase):
for fmt in noncomplex_formats:
mx = max_value[fmt]
alpha = mx / 2
alpha = mx / 2.0
nalpha = mx - alpha
test = self.colour.bandjoin(black + alpha).cast(fmt)
pixel = test.getpoint(30, 30)
@ -350,7 +353,7 @@ class TestConversion(unittest.TestCase):
im = test.flatten(background = [100, 100, 100])
pixel = test.getpoint(30, 30)
predict = [int(x) * alpha / mx + (100 * nalpha) / mx
predict = [int(x) * alpha / mx + (100 * nalpha) / mx
for x in pixel[:-1]]
self.assertEqual(im.bands, 3)
@ -375,7 +378,7 @@ class TestConversion(unittest.TestCase):
exponent = 2.4
for fmt in noncomplex_formats:
mx = max_value[fmt]
test = (self.colour + mx / 2).cast(fmt)
test = (self.colour + mx / 2.0).cast(fmt)
norm = mx ** exponent / mx
result = test.gamma()
@ -390,7 +393,7 @@ class TestConversion(unittest.TestCase):
exponent = 1.2
for fmt in noncomplex_formats:
mx = max_value[fmt]
test = (self.colour + mx / 2).cast(fmt)
test = (self.colour + mx / 2.0).cast(fmt)
norm = mx ** exponent / mx
result = test.gamma(exponent = 1.0 / 1.2)
@ -518,7 +521,7 @@ class TestConversion(unittest.TestCase):
for fmt in unsigned_formats:
mx = max_value[fmt]
size = sizeof_format[fmt]
test = (self.colour + mx / 8).cast(fmt)
test = (self.colour + mx / 8.0).cast(fmt)
im = test.msb()
before = test.getpoint(10, 10)
@ -534,7 +537,7 @@ class TestConversion(unittest.TestCase):
for fmt in signed_formats:
mx = max_value[fmt]
size = sizeof_format[fmt]
test = (self.colour + mx / 8).cast(fmt)
test = (self.colour + mx / 8.0).cast(fmt)
im = test.msb()
before = test.getpoint(10, 10)
@ -550,7 +553,7 @@ class TestConversion(unittest.TestCase):
for fmt in unsigned_formats:
mx = max_value[fmt]
size = sizeof_format[fmt]
test = (self.colour + mx / 8).cast(fmt)
test = (self.colour + mx / 8.0).cast(fmt)
im = test.msb(band = 1)
before = [test.getpoint(10, 10)[1]]
@ -644,8 +647,8 @@ class TestConversion(unittest.TestCase):
test = self.colour.cast(fmt)
im = test.subsample(3, 3)
self.assertEqual(im.width, test.width / 3)
self.assertEqual(im.height, test.height / 3)
self.assertEqual(im.width, test.width // 3)
self.assertEqual(im.height, test.height // 3)
before = test.getpoint(60, 60)
after = im.getpoint(20, 20)