aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/pyexiv2/exif.py7
-rw-r--r--src/pyexiv2/utils.py10
-rw-r--r--src/pyexiv2/xmp.py5
-rw-r--r--test/exif.py7
-rw-r--r--test/xmp.py27
5 files changed, 49 insertions, 7 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)
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):
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)
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')
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