From 6ef2b5a626270fa7dae1099fc3617a34112af149 Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Tue, 30 Nov 2010 20:45:40 +0100 Subject: Conditional import of fractions.Fraction for partial support if present. --- src/pyexiv2/utils.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pyexiv2/utils.py b/src/pyexiv2/utils.py index 64138d2..5b0a3d5 100644 --- a/src/pyexiv2/utils.py +++ b/src/pyexiv2/utils.py @@ -31,6 +31,16 @@ Utilitary classes and functions. import datetime import re +# Support for fractions.Fraction as a replacement for the Rational class is not +# implemented yet as we have to support versions of Python < 2.6 +# (see https://launchpad.net/bugs/514415). +# However, it doesn’t hurt to accept Fraction objects as values when the module +# is available (see https://launchpad.net/bugs/683232). +try: + from fractions import Fraction +except ImportError: + Fraction = None + class FixedOffset(datetime.tzinfo): -- cgit From aed5a5ebc8fa63834c2a29e1614debf4e92c04ac Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Tue, 30 Nov 2010 20:46:26 +0100 Subject: Accept Fraction objects for Rational and SRational values in EXIF tags. --- src/pyexiv2/exif.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pyexiv2/exif.py b/src/pyexiv2/exif.py index 0acb775..a3b83b1 100644 --- a/src/pyexiv2/exif.py +++ b/src/pyexiv2/exif.py @@ -30,7 +30,8 @@ EXIF specific code. import libexiv2python -from pyexiv2.utils import Rational, NotifyingList, ListenerInterface, \ +from pyexiv2.utils import Rational, Fraction, \ + NotifyingList, ListenerInterface, \ undefined_to_string, string_to_undefined import time @@ -376,13 +377,13 @@ class ExifTag(ListenerInterface): raise ExifValueError(value, self.type) elif self.type == 'Rational': - if type(value) is Rational and value.numerator >= 0: + if type(value) in (Rational, Fraction) and value.numerator >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SRational': - if type(value) is Rational: + if type(value) in (Rational, Fraction): return str(value) else: raise ExifValueError(value, self.type) -- cgit From bd8fdd0665f848a566ccfee0b8dff9c67a52488b Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Tue, 30 Nov 2010 20:47:00 +0100 Subject: Conditional unit test for Fraction objects in EXIF tags. --- test/exif.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/exif.py b/test/exif.py index 4ddb360..263437e 100644 --- a/test/exif.py +++ b/test/exif.py @@ -27,7 +27,7 @@ import unittest from pyexiv2.exif import ExifTag, ExifValueError -from pyexiv2.utils import Rational +from pyexiv2.utils import Rational, Fraction import datetime @@ -263,6 +263,8 @@ class TestExifTag(unittest.TestCase): tag = ExifTag('Exif.Image.XResolution') self.assertEqual(tag.type, 'Rational') self.assertEqual(tag._convert_to_string(Rational(5, 3)), '5/3') + if Fraction is not None: + self.assertEqual(tag._convert_to_string(Fraction('1.6')), '8/5') # Invalid values self.failUnlessRaises(ExifValueError, tag._convert_to_string, 'invalid') @@ -287,6 +289,9 @@ class TestExifTag(unittest.TestCase): self.assertEqual(tag.type, 'SRational') self.assertEqual(tag._convert_to_string(Rational(5, 3)), '5/3') self.assertEqual(tag._convert_to_string(Rational(-5, 3)), '-5/3') + if Fraction is not None: + self.assertEqual(tag._convert_to_string(Fraction('1.6')), '8/5') + self.assertEqual(tag._convert_to_string(Fraction('-1.6')), '-8/5') # Invalid values self.failUnlessRaises(ExifValueError, tag._convert_to_string, 'invalid') -- cgit From 95ed963c2cdbdeff64fc70168d44ac9e47d051d2 Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Tue, 30 Nov 2010 20:47:42 +0100 Subject: Accept Fraction objects for Rational values in XMP tags. --- src/pyexiv2/xmp.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pyexiv2/xmp.py b/src/pyexiv2/xmp.py index 2142c41..f13db7b 100644 --- a/src/pyexiv2/xmp.py +++ b/src/pyexiv2/xmp.py @@ -30,7 +30,7 @@ XMP specific code. import libexiv2python -from pyexiv2.utils import FixedOffset, Rational, GPSCoordinate +from pyexiv2.utils import FixedOffset, Rational, Fraction, GPSCoordinate import datetime import re @@ -435,7 +435,8 @@ class XmpTag(object): raise XmpValueError(value, type) elif type == 'Rational': - if isinstance(value, Rational): + if isinstance(value, Rational) or \ + (Fraction is not None and isinstance(value, Fraction)): return str(value) else: raise XmpValueError(value, type) -- cgit From 9b18a14ed49351304e1ac4d63d1a6411d22bb1a0 Mon Sep 17 00:00:00 2001 From: Olivier Tilloy Date: Tue, 30 Nov 2010 20:48:22 +0100 Subject: Unit tests for Rational conversions in XMP tags. --- test/xmp.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/xmp.py b/test/xmp.py index 10e03a8..845b048 100644 --- a/test/xmp.py +++ b/test/xmp.py @@ -27,7 +27,7 @@ import unittest from pyexiv2.xmp import XmpTag, XmpValueError -from pyexiv2.utils import FixedOffset +from pyexiv2.utils import FixedOffset, Rational, Fraction import datetime @@ -281,6 +281,31 @@ class TestXmpTag(unittest.TestCase): # Invalid values self.failUnlessRaises(XmpValueError, tag._convert_to_string, None, 'URL') + def test_convert_to_python_rational(self): + # Valid values + tag = XmpTag('Xmp.xmpDM.videoPixelAspectRatio') + self.assertEqual(tag.type, 'Rational') + self.assertEqual(tag._convert_to_python('5/3', 'Rational'), Rational(5, 3)) + self.assertEqual(tag._convert_to_python('-5/3', 'Rational'), Rational(-5, 3)) + + # Invalid values + self.failUnlessRaises(XmpValueError, tag._convert_to_python, 'invalid', 'Rational') + self.failUnlessRaises(XmpValueError, tag._convert_to_python, '5 / 3', 'Rational') + self.failUnlessRaises(XmpValueError, tag._convert_to_python, '5/-3', 'Rational') + + def test_convert_to_string_rational(self): + # Valid values + tag = XmpTag('Xmp.xmpDM.videoPixelAspectRatio') + self.assertEqual(tag.type, 'Rational') + self.assertEqual(tag._convert_to_string(Rational(5, 3), 'Rational'), '5/3') + self.assertEqual(tag._convert_to_string(Rational(-5, 3), 'Rational'), '-5/3') + if Fraction is not None: + self.assertEqual(tag._convert_to_string(Fraction('1.6'), 'Rational'), '8/5') + self.assertEqual(tag._convert_to_string(Fraction('-1.6'), 'Rational'), '-8/5') + + # Invalid values + self.failUnlessRaises(XmpValueError, tag._convert_to_string, 'invalid', 'Rational') + # TODO: other types -- cgit