Merge lp:~malept/pyexiv2/0.2-ReadMetadataTestCase into lp:pyexiv2/0.2.x
- 0.2-ReadMetadataTestCase
- Merge into pyexiv2-0.2
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Tilloy | Approve | ||
Review via email:
|
Commit message
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Mark Lee (malept) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
> > 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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
> 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.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Olivier Tilloy (osomon) wrote : | # |
Thanks for your work Mark!
I added a few custom tweaks and merged in 0.2.
Preview Diff
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' |
238 | Binary 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 |
Please see bug 517298 for details.