Merge lp:~malept/pyexiv2/0.2-ReadMetadataTestCase into lp:pyexiv2/0.2.x

Proposed by Mark Lee
Status: Merged
Merged at revision: not available
Proposed branch: lp:~malept/pyexiv2/0.2-ReadMetadataTestCase
Merge into: lp:pyexiv2/0.2.x
Diff against target: 238 lines (+160/-27)
2 files modified
test/ReadMetadataTestCase.py (+158/-25)
test/TestsRunner.py (+2/-2)
To merge this branch: bzr merge lp:~malept/pyexiv2/0.2-ReadMetadataTestCase
Reviewer Review Type Date Requested Status
Olivier Tilloy Approve
Review via email: mp+19028@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Mark Lee (malept) wrote :

Please see bug 517298 for details.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Thanks for the patch Mark! Overall it looks good to me.

I have one remark on the consistency of the checks: the original case tests the python type of the values of EXIF and IPTC tags. In the case you added, the check is on the tag's type, not the type of the corresponding python object.

Also, how about merging some selected XMP metadata from exiv2-bug540.jpg into smiley1.jpg using exiv2 itself, rather than doing the testing on two different files, and what's more on a very large number of XMP tags?

In fact I can see many ways to improve the original test case, but that's definitely out of the scope of your patch. If you can fix the check consistency issue, then I'll merge your branch, and take some time to further enhance the tests.

review: Needs Fixing (code)
Revision history for this message
Mark Lee (malept) wrote :

> Thanks for the patch Mark! Overall it looks good to me.

Thanks for reviewing it.

> I have one remark on the consistency of the checks: the original case tests
> the python type of the values of EXIF and IPTC tags. In the case you added,
> the check is on the tag's type, not the type of the corresponding python
> object.

So you want to check tag.type (e.g., 'Ascii' for some strings)? I presume that you don't want to check tag.__class__ anymore, because that seems to always be ExifTag.

> Also, how about merging some selected XMP metadata from exiv2-bug540.jpg into
> smiley1.jpg using exiv2 itself, rather than doing the testing on two different
> files, and what's more on a very large number of XMP tags?

I can do that. I only did it this current way because it was easy to extract all of the XMP tags and throw them into the testcase. I presume I should put one (or two) XMP tags per type into smiley1.jpg?

Revision history for this message
Olivier Tilloy (osomon) wrote :

> > I have one remark on the consistency of the checks: the original case tests
> > the python type of the values of EXIF and IPTC tags. In the case you added,
> > the check is on the tag's type, not the type of the corresponding python
> > object.
>
> So you want to check tag.type (e.g., 'Ascii' for some strings)? I presume that
> you don't want to check tag.__class__ anymore, because that seems to always be
> ExifTag.

No, for the sake of consistency, I would rather check tag.value.__class__, as is done for EXIF and IPTC tags.

> > Also, how about merging some selected XMP metadata from exiv2-bug540.jpg
> into
> > smiley1.jpg using exiv2 itself, rather than doing the testing on two
> different
> > files, and what's more on a very large number of XMP tags?
>
> I can do that. I only did it this current way because it was easy to extract
> all of the XMP tags and throw them into the testcase. I presume I should put
> one (or two) XMP tags per type into smiley1.jpg?

No need to do it in a first step, the patch is correct without. Let's first merge the patch and then enhance the test case in a second step.

Revision history for this message
Mark Lee (malept) wrote :

> > > I have one remark on the consistency of the checks: the original case
> tests
> > > the python type of the values of EXIF and IPTC tags. In the case you
> added,
> > > the check is on the tag's type, not the type of the corresponding python
> > > object.
> >
> > So you want to check tag.type (e.g., 'Ascii' for some strings)? I presume
> that
> > you don't want to check tag.__class__ anymore, because that seems to always
> be
> > ExifTag.
>
> No, for the sake of consistency, I would rather check tag.value.__class__, as
> is done for EXIF and IPTC tags.

OK, I think I confused myself. I'll change the XMP tests to use Python types instead of ``tag.type``s.

273. By Mark Lee

XMP: Check the tag value types, not the tag type.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Thanks for your work Mark!
I added a few custom tweaks and merged in 0.2.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'test/ReadMetadataTestCase.py'
2--- test/ReadMetadataTestCase.py 2010-01-05 08:28:34 +0000
3+++ test/ReadMetadataTestCase.py 2010-02-17 01:36:19 +0000
4@@ -39,17 +39,38 @@
5 Test case on reading the metadata contained in a file.
6 """
7
8- def checkTypeAndValue(self, tag, etype, evalue):
9- """
10- Check the type and the value of a metadata tag against expected values.
11-
12- Keyword arguments:
13- tag -- the full name of the tag (eg. 'Exif.Image.DateTime')
14- etype -- the expected type of the tag value
15- evalue -- the expected value of the tag
16- """
17- self.assertEqual(tag.__class__, etype)
18- self.assertEqual(tag, evalue)
19+ def checkEXIFTypeAndValue(self, tag, etype, evalue):
20+ """
21+ Check the type and the value of an EXIF tag against expected values.
22+
23+ Keyword arguments:
24+ tag -- the full name of the tag (eg. 'Exif.Image.DateTime')
25+ etype -- the expected type of the tag value
26+ evalue -- the expected value of the tag
27+ """
28+ self.assertEqual(type(tag.value), etype)
29+ self.assertEqual(tag.value, evalue)
30+
31+ def checkIPTCTypeAndValue(self, tag, etype, evalue):
32+ """
33+ Check the type and the value of an IPTC tag against expected values.
34+
35+ Keyword arguments:
36+ tag -- the full name of the tag (eg. 'Exif.Image.DateTime')
37+ etype -- the expected type of the tag value
38+ evalue -- the expected value of the tag
39+ """
40+ if issubclass(etype, tuple):
41+ self.assertEqual(list(tag.values), list(evalue))
42+ else:
43+ self.assertEqual(type(tag.values[0]), etype)
44+ self.assertEqual(tag.values[0], evalue)
45+
46+ def assertCorrectFile(self, filename, md5sum):
47+ """
48+ Ensure that the filename and the MD5 checksum match up.
49+ """
50+ self.assert_(testutils.CheckFileSum(filename, md5sum))
51
52 def testReadMetadata(self):
53 """
54@@ -58,11 +79,11 @@
55 # Check that the reference file is not corrupted
56 filename = os.path.join('data', 'smiley1.jpg')
57 md5sum = 'c066958457c685853293058f9bf129c1'
58- self.assert_(testutils.CheckFileSum(filename, md5sum))
59+ self.assertCorrectFile(filename, md5sum)
60
61 # Read the image metadata
62- image = pyexiv2.Image(filename)
63- image.readMetadata()
64+ image = pyexiv2.ImageMetadata(filename)
65+ image.read()
66
67 # Exhaustive tests on the values of EXIF metadata
68 exifTags = [('Exif.Image.ImageDescription', str, 'Well it is a smiley that happens to be green'),
69@@ -77,9 +98,9 @@
70 ('Exif.Photo.Flash', int, 80),
71 ('Exif.Photo.PixelXDimension', long, 167L),
72 ('Exif.Photo.PixelYDimension', long, 140L)]
73- self.assertEqual(image.exifKeys(), [tag[0] for tag in exifTags])
74- for tag in exifTags:
75- self.checkTypeAndValue(image[tag[0]], tag[1], tag[2])
76+ self.assertEqual(image.exif_keys, [tag[0] for tag in exifTags])
77+ for key, ktype, value in exifTags:
78+ self.checkEXIFTypeAndValue(image[key], ktype, value)
79
80 # Exhaustive tests on the values of IPTC metadata
81 iptcTags = [('Iptc.Application2.Caption', str, 'yelimS green faced dude (iptc caption)'),
82@@ -93,11 +114,123 @@
83 ('Iptc.Application2.Category', str, 'Things'),
84 ('Iptc.Application2.Keywords', tuple, ('Green', 'Smiley', 'Dude')),
85 ('Iptc.Application2.Copyright', str, '\xa9 2004 Nobody')]
86- self.assertEqual(image.iptcKeys(), [tag[0] for tag in iptcTags])
87- for tag in iptcTags:
88- self.checkTypeAndValue(image[tag[0]], tag[1], tag[2])
89-
90- # Test on the JPEG comment
91- self.checkTypeAndValue(image.getComment(),
92- str, 'This is a jpeg comment, about the green smiley.')
93-
94+ self.assertEqual(image.iptc_keys, [tag[0] for tag in iptcTags])
95+ for key, ktype, value in iptcTags:
96+ self.checkIPTCTypeAndValue(image[key], ktype, value)
97+
98+ def testReadMetadataXMP(self):
99+ filename = os.path.join('data', 'exiv2-bug540.jpg')
100+ md5sum = '64d4b7eab1e78f1f6bfb3c966e99eef2'
101+ self.assertCorrectFile(filename, md5sum)
102+
103+ # Read the image metadata
104+ image = pyexiv2.ImageMetadata(filename)
105+ image.read()
106+
107+ xmpTags = [('Xmp.dc.creator', list, [u'Ian Britton']),
108+ ('Xmp.dc.description', dict, {u'x-default': u'Communications'}),
109+ ('Xmp.dc.rights', dict, {u'x-default': u'ian Britton - FreeFoto.com'}),
110+ ('Xmp.dc.source', unicode, u'FreeFoto.com'),
111+ ('Xmp.dc.subject', list, [u'Communications']),
112+ ('Xmp.dc.title', dict, {u'x-default': u'Communications'}),
113+ ('Xmp.exif.ApertureValue',
114+ pyexiv2.utils.Rational,
115+ pyexiv2.utils.Rational(8, 1)),
116+ ('Xmp.exif.BrightnessValue',
117+ pyexiv2.utils.Rational,
118+ pyexiv2.utils.Rational(333, 1280)),
119+ ('Xmp.exif.ColorSpace', int, 1),
120+ ('Xmp.exif.DateTimeOriginal',
121+ datetime.datetime,
122+ datetime.datetime(2002, 7, 13, 15, 58, 28, tzinfo=pyexiv2.utils.FixedOffset())),
123+ ('Xmp.exif.ExifVersion', unicode, u'0200'),
124+ ('Xmp.exif.ExposureBiasValue',
125+ pyexiv2.utils.Rational,
126+ pyexiv2.utils.Rational(-13, 20)),
127+ ('Xmp.exif.ExposureProgram', int, 4),
128+ ('Xmp.exif.FNumber',
129+ pyexiv2.utils.Rational,
130+ pyexiv2.utils.Rational(3, 5)),
131+ ('Xmp.exif.FileSource', int, 0),
132+ ('Xmp.exif.FlashpixVersion', unicode, u'0100'),
133+ ('Xmp.exif.FocalLength',
134+ pyexiv2.utils.Rational,
135+ pyexiv2.utils.Rational(0, 1)),
136+ ('Xmp.exif.FocalPlaneResolutionUnit', int, 2),
137+ ('Xmp.exif.FocalPlaneXResolution',
138+ pyexiv2.utils.Rational,
139+ pyexiv2.utils.Rational(3085, 256)),
140+ ('Xmp.exif.FocalPlaneYResolution',
141+ pyexiv2.utils.Rational,
142+ pyexiv2.utils.Rational(3085, 256)),
143+ ('Xmp.exif.GPSLatitude',
144+ pyexiv2.utils.GPSCoordinate,
145+ pyexiv2.utils.GPSCoordinate.from_string('54,59.380000N')),
146+ ('Xmp.exif.GPSLongitude',
147+ pyexiv2.utils.GPSCoordinate,
148+ pyexiv2.utils.GPSCoordinate.from_string('1,54.850000W')),
149+ ('Xmp.exif.GPSMapDatum', unicode, u'WGS84'),
150+ ('Xmp.exif.GPSTimeStamp',
151+ datetime.datetime,
152+ datetime.datetime(2002, 7, 13, 14, 58, 24, tzinfo=pyexiv2.utils.FixedOffset())),
153+ ('Xmp.exif.GPSVersionID', unicode, u'2.0.0.0'),
154+ ('Xmp.exif.ISOSpeedRatings', list, [0]),
155+ ('Xmp.exif.MeteringMode', int, 5),
156+ ('Xmp.exif.PixelXDimension', int, 2400),
157+ ('Xmp.exif.PixelYDimension', int, 1600),
158+ ('Xmp.exif.SceneType', int, 0),
159+ ('Xmp.exif.SensingMethod', int, 2),
160+ ('Xmp.exif.ShutterSpeedValue',
161+ pyexiv2.utils.Rational,
162+ pyexiv2.utils.Rational(30827, 3245)),
163+ ('Xmp.pdf.Keywords', unicode, u'Communications'),
164+ ('Xmp.photoshop.AuthorsPosition', unicode, u'Photographer'),
165+ ('Xmp.photoshop.CaptionWriter', unicode, u'Ian Britton'),
166+ ('Xmp.photoshop.Category', unicode, u'BUS'),
167+ ('Xmp.photoshop.City', unicode, u' '),
168+ ('Xmp.photoshop.Country', unicode, u'Ubited Kingdom'),
169+ ('Xmp.photoshop.Credit', unicode, u'Ian Britton'),
170+ ('Xmp.photoshop.DateCreated', datetime.date, datetime.date(2002, 6, 20)),
171+ ('Xmp.photoshop.Headline', unicode, u'Communications'),
172+ ('Xmp.photoshop.State', unicode, u' '),
173+ ('Xmp.photoshop.SupplementalCategories', list, [u'Communications']),
174+ ('Xmp.photoshop.Urgency', int, 5),
175+ ('Xmp.tiff.Artist', unicode, u'Ian Britton'),
176+ ('Xmp.tiff.BitsPerSample', list, [8]),
177+ ('Xmp.tiff.Compression', int, 6),
178+ ('Xmp.tiff.Copyright',
179+ dict,
180+ {u'x-default': u'ian Britton - FreeFoto.com'}),
181+ ('Xmp.tiff.ImageDescription', dict, {u'x-default': u'Communications'}),
182+ ('Xmp.tiff.ImageLength', int, 400),
183+ ('Xmp.tiff.ImageWidth', int, 600),
184+ ('Xmp.tiff.Make', unicode, u'FUJIFILM'),
185+ ('Xmp.tiff.Model', unicode, u'FinePixS1Pro'),
186+ ('Xmp.tiff.Orientation', int, 1),
187+ ('Xmp.tiff.ResolutionUnit', int, 2),
188+ ('Xmp.tiff.Software', unicode, u'Adobe Photoshop 7.0'),
189+ ('Xmp.tiff.XResolution',
190+ pyexiv2.utils.Rational,
191+ pyexiv2.utils.Rational(300, 1)),
192+ ('Xmp.tiff.YCbCrPositioning', int, 2),
193+ ('Xmp.tiff.YResolution',
194+ pyexiv2.utils.Rational,
195+ pyexiv2.utils.Rational(300, 1)),
196+ ('Xmp.xmp.CreateDate',
197+ datetime.datetime,
198+ datetime.datetime(2002, 7, 13, 15, 58, 28, tzinfo=pyexiv2.utils.FixedOffset())),
199+ ('Xmp.xmp.ModifyDate',
200+ datetime.datetime,
201+ datetime.datetime(2002, 7, 19, 13, 28, 10, tzinfo=pyexiv2.utils.FixedOffset())),
202+ ('Xmp.xmpBJ.JobRef', list, []),
203+ ('Xmp.xmpBJ.JobRef[1]', str, ''),
204+ ('Xmp.xmpBJ.JobRef[1]/stJob:name', str, 'Photographer'),
205+ ('Xmp.xmpMM.DocumentID',
206+ str,
207+ 'adobe:docid:photoshop:84d4dba8-9b11-11d6-895d-c4d063a70fb0'),
208+ ('Xmp.xmpRights.Marked', bool, True),
209+ ('Xmp.xmpRights.WebStatement', str, 'www.freefoto.com')]
210+ for key, xtype, value in xmpTags:
211+ tag = image[key]
212+ self.assertEqual(type(tag.value), xtype)
213+ self.assertEqual(tag.value, value)
214
215=== modified file 'test/TestsRunner.py'
216--- test/TestsRunner.py 2010-01-19 18:42:25 +0000
217+++ test/TestsRunner.py 2010-02-17 01:36:19 +0000
218@@ -28,7 +28,7 @@
219 import unittest
220
221 # Test cases to run
222-#from ReadMetadataTestCase import ReadMetadataTestCase
223+from ReadMetadataTestCase import ReadMetadataTestCase
224 #from Bug146313_TestCase import Bug146313_TestCase
225 #from Bug173387_TestCase import Bug173387_TestCase
226 #from Bug175070_TestCase import Bug175070_TestCase
227@@ -46,7 +46,7 @@
228 if __name__ == '__main__':
229 # Instantiate a test suite containing all the test cases
230 suite = unittest.TestSuite()
231- #suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(ReadMetadataTestCase))
232+ suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(ReadMetadataTestCase))
233 #suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(Bug146313_TestCase))
234 #suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(Bug173387_TestCase))
235 #suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(Bug175070_TestCase))
236
237=== added file 'test/data/exiv2-bug540.jpg'
238Binary files test/data/exiv2-bug540.jpg 1970-01-01 00:00:00 +0000 and test/data/exiv2-bug540.jpg 2010-02-17 01:36:19 +0000 differ

Subscribers

People subscribed via source and target branches