From 02f6de5151e381570ffa0e0dd715be88ca87572d Mon Sep 17 00:00:00 2001 From: Marcelo Jorge Vieira Date: Tue, 12 Sep 2017 23:40:20 -0300 Subject: [PATCH] Add support of Python3 --- pexif.py | 68 ++++++++++++++++++++++---------------- scripts/dump_exif.py | 7 ++-- scripts/dump_timestamp.py | 13 ++++---- scripts/getgps.py | 12 ++++--- scripts/noop.py | 9 ++--- scripts/remove_metadata.py | 10 +++--- scripts/setgps.py | 9 ++--- scripts/timezone.py | 8 ++--- test/test.py | 12 +++---- 9 files changed, 84 insertions(+), 64 deletions(-) diff --git a/pexif.py b/pexif.py index c3006b2..7228a33 100644 --- a/pexif.py +++ b/pexif.py @@ -87,21 +87,26 @@ E.g: try: - print img.exif.tiff.exif.FocalLength + six.print_(img.exif.tiff.exif.FocalLength) except AttributeError: - print "No Focal Length data" + six.print_("No Focal Length data") """ -import StringIO +import six import sys from struct import unpack, pack +try: + integer_64 = long +except NameError: # Python3 + integer_64 = int + MAX_HEADER_SIZE = 64 * 1024 DELIM = 0xff EOI = 0xd9 -SOI_MARKER = chr(DELIM) + '\xd8' -EOI_MARKER = chr(DELIM) + '\xd9' +SOI_MARKER = six.int2byte(DELIM) + six.b('\xd8') +EOI_MARKER = six.int2byte(DELIM) + six.b('\xd9') TIFF_OFFSET = 6 TIFF_TAG = 0x2a @@ -122,8 +127,8 @@ def debug(*debug_string): DEBUG to 1.""" if DEBUG: for each in debug_string: - print each, - print + six.print_(each), + six.print_() class DefaultSegment: @@ -160,7 +165,7 @@ def write(self, fd): must write out any data in the segment. This shouldn't in general be overloaded by subclasses, they should instead override the get_data() method.""" - fd.write('\xff') + fd.write(six.b('\xff')) fd.write(pack('B', self.marker)) data = self.get_data() fd.write(pack('>H', len(data) + 2)) @@ -180,8 +185,8 @@ def dump(self, fd): """This is called by JpegFile.dump() to output a human readable representation of the segment. Subclasses should overload this to provide extra information.""" - print >> fd, " Section: [%5s] Size: %6d" % \ - (jpeg_markers[self.marker][0], len(self.data)) + six.print_(" Section: [%5s] Size: %6d" \ + % (jpeg_markers[self.marker][0], len(self.data)), file=fd) class StartOfScanSegment(DefaultSegment): @@ -218,8 +223,8 @@ def write(self, fd): def dump(self, fd): """Dump as ascii readable data to a given file object""" - print >> fd, " Section: [ SOS] Size: %6d Image data size: %6d" % \ - (len(self.data), len(self.img_data)) + six.print_(" Section: [ SOS] Size: %6d Image data size: %6d" % \ + (len(self.data), len(self.img_data)), file=fd) class ExifType: @@ -435,9 +440,9 @@ def __init__(self, e, offset, exif_file, mode, data=None): # raise JpegFile.InvalidFile("ASCII tag '%s' not # NULL-terminated: %s [%s]" % (self.tags.get(tag, # (hex(tag), 0))[0], the_data, map(ord, the_data))) - # print "ASCII tag '%s' not NULL-terminated: + # six.print_("ASCII tag '%s' not NULL-terminated: # %s [%s]" % (self.tags.get(tag, (hex(tag), 0))[0], - # the_data, map(ord, the_data)) + # the_data, map(ord, the_data))) actual_data = the_data elif exif_type == SHORT: actual_data = list(unpack(e + ("H" * components), the_data)) @@ -453,7 +458,7 @@ def __init__(self, e, offset, exif_file, mode, data=None): the_data[i*8: i*8+8]))) else: - raise "Can't handle this" + six.raise_from("Can't handle this") if (byte_size > 4): debug("%s" % actual_data) @@ -521,7 +526,7 @@ def getdata(self, e, offset, last=0): for i in range(components): actual_data += pack(e + t, *the_data[i].as_tuple()) else: - raise "Can't handle this", exif_type + raise six.raise_from("Can't handle this", exif_type) if (byte_size) > 4: output_data += actual_data actual_data = pack(e + "I", data_offset) @@ -549,7 +554,7 @@ def getdata(self, e, offset, last=0): def dump(self, f, indent=""): """Dump the IFD file""" - print >> f, indent + "<--- %s start --->" % self.name + six.print_(indent + "<--- %s start --->" % self.name, file=f) for entry in self.entries: tag, exif_type, data = entry if exif_type == ASCII: @@ -559,9 +564,9 @@ def dump(self, f, indent=""): else: if data and len(data) == 1: data = data[0] - print >> f, indent + " %-40s %s" % \ - (self.tags.get(tag, (hex(tag), 0))[0], data) - print >> f, indent + "<--- %s end --->" % self.name + six.print_(indent + " %-40s %s" % \ + (self.tags.get(tag, (hex(tag), 0))[0], data), file=f) + six.print_(indent + "<--- %s end --->" % self.name, file=f) class IfdInterop(IfdData): @@ -861,7 +866,10 @@ def parse_data(self, data): """Overloads the DefaultSegment method to parse the data of this segment. Can raise InvalidFile if we don't get what we expect.""" exif = unpack("6s", data[:6])[0] - exif = exif.strip('\0') + try: + exif = exif.strip('\0') + except TypeError: + pass if (exif != "Exif"): raise self.InvalidSegment("Bad Exif Marker. Got <%s>, " @@ -910,7 +918,7 @@ def parse_data(self, data): offset = unpack(self.e + "I", tiff_data[start:start+4])[0] def dump(self, fd): - print >> fd, " Section: [ EXIF] Size: %6d" % (len(self.data)) + six.print_(" Section: [ EXIF] Size: %6d" % (len(self.data)), file=fd) for ifd in self.ifds: ifd.dump(fd) @@ -1004,7 +1012,11 @@ def fromFile(filename, mode="rw"): def fromString(str, mode="rw"): """Return a new JpegFile object taking data from a string.""" - return JpegFile(StringIO.StringIO(str), "from buffer", mode=mode) + try: + str = six.b(str) + except AttributeError: + pass + return JpegFile(six.BytesIO(str), "from buffer", mode=mode) fromString = staticmethod(fromString) def fromFd(fd, mode="rw"): @@ -1074,7 +1086,7 @@ def __init__(self, input, filename=None, mode="rw"): def writeString(self): """Write the JpegFile out to a string. Returns a string.""" - f = StringIO.StringIO() + f = six.BytesIO() self.writeFd(f) return f.getvalue() @@ -1093,7 +1105,7 @@ def writeFd(self, output): def dump(self, f=sys.stdout): """Write out ASCII representation of the file on a given file object. Output default to stdout.""" - print >> f, "" % self.filename + six.print_("" % self.filename, file=f) for segment in self._segments: segment.dump(f) @@ -1175,8 +1187,8 @@ def convert(x): (1/60.0 * float(min.num) / min.den) + \ (1/3600.0 * float(sec.num) / sec.den) if not hasattr(self.exif.primary, 'GPSIFD'): - raise self.NoSection, "File %s doesn't have a GPS section." % \ - self.filename + raise self.NoSection("File %s doesn't have a GPS section." % \ + self.filename) gps = self.exif.primary.GPS lat = convert(gps.GPSLatitude) @@ -1200,7 +1212,7 @@ def _parse(val): other = (val - deg) * 60 minutes = int(other) secs = (other - minutes) * 60 - secs = long(secs * JpegFile.SEC_DEN) + secs = integer_64(secs * JpegFile.SEC_DEN) return (sign, deg, minutes, secs) _parse = staticmethod(_parse) diff --git a/scripts/dump_exif.py b/scripts/dump_exif.py index 98bc9b3..c704292 100755 --- a/scripts/dump_exif.py +++ b/scripts/dump_exif.py @@ -1,12 +1,13 @@ #!/usr/bin/env python +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: dump_exif.py filename.jpg""" if len(sys.argv) != 2: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: @@ -14,7 +15,7 @@ ef.dump() except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) diff --git a/scripts/dump_timestamp.py b/scripts/dump_timestamp.py index 2a8dc25..e865f90 100644 --- a/scripts/dump_timestamp.py +++ b/scripts/dump_timestamp.py @@ -1,23 +1,24 @@ #!/usr/bin/env python +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: dump_timestamp.py filename.jpg""" if len(sys.argv) != 2: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: ef = JpegFile.fromFile(sys.argv[1]) primary = ef.get_exif().get_primary() - print "Primary DateTime :", primary.DateTime - print "Extended DateTimeOriginal :", primary.ExtendedEXIF.DateTimeOriginal - print "Extended DateTimeDigitized:", primary.ExtendedEXIF.DateTimeDigitized + print("Primary DateTime : {0}".format(primary.DateTime)) + print("Extended DateTimeOriginal : {0}".format(primary.ExtendedEXIF.DateTimeOriginal)) + print("Extended DateTimeDigitized: {0}".format(primary.ExtendedEXIF.DateTimeDigitized)) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) diff --git a/scripts/getgps.py b/scripts/getgps.py index eb2307b..048f688 100755 --- a/scripts/getgps.py +++ b/scripts/getgps.py @@ -1,23 +1,25 @@ #!/usr/bin/env python + +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: getgps.py filename.jpg""" if len(sys.argv) != 2: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: ef = JpegFile.fromFile(sys.argv[1]) - print ef.get_geo() + print(ef.get_geo()) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) except JpegFile.NoSection: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error get GPS info:", value + print("Error get GPS info: {0}".format(value), file=sys.stderr) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) diff --git a/scripts/noop.py b/scripts/noop.py index 352c3af..13c6e6f 100755 --- a/scripts/noop.py +++ b/scripts/noop.py @@ -1,28 +1,29 @@ #!/usr/bin/env python +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: dump_exif.py filename.jpg out.jpg""" if len(sys.argv) != 3: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: ef = JpegFile.fromFile(sys.argv[1]) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) sys.exit(1) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) sys.exit(1) try: ef.writeFile(sys.argv[2]) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error saving file:", value + print("Error saving file: {0}".format(value), file=sys.stderr) sys.exit(1) diff --git a/scripts/remove_metadata.py b/scripts/remove_metadata.py index b043937..bcce384 100644 --- a/scripts/remove_metadata.py +++ b/scripts/remove_metadata.py @@ -1,11 +1,13 @@ #!/usr/bin/env python + +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: remove_metadata.py filename.jpg""" if len(sys.argv) != 4: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: @@ -13,13 +15,13 @@ ef.remove_metadata(paranoid=True) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) try: ef.writeFile(sys.argv[1]) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error saving file:", value + print("Error saving file: {0}".format(value), file=sys.stderr) diff --git a/scripts/setgps.py b/scripts/setgps.py index 638610b..9ef5a7c 100755 --- a/scripts/setgps.py +++ b/scripts/setgps.py @@ -1,11 +1,12 @@ #!/usr/bin/env python +from __future__ import print_function from pexif import JpegFile import sys usage = """Usage: setgps.py filename.jpg lat lng""" if len(sys.argv) != 4: - print >> sys.stderr, usage + print(usage, file=sys.stderr) sys.exit(1) try: @@ -13,14 +14,14 @@ ef.set_geo(float(sys.argv[2]), float(sys.argv[3])) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) except JpegFile.InvalidFile: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error opening file:", value + print("Error opening file: {0}".format(value), file=sys.stderr) try: ef.writeFile(sys.argv[1]) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error saving file:", value + print("Error saving file: {0}".format(value), file=sys.stderr) diff --git a/scripts/timezone.py b/scripts/timezone.py index fec5f72..cedef58 100644 --- a/scripts/timezone.py +++ b/scripts/timezone.py @@ -7,7 +7,7 @@ -- Andrew Baumann , 20080716 """ - +from __future__ import print_function import sys from pexif import JpegFile, EXIF_OFFSET from datetime import timedelta, datetime @@ -52,14 +52,14 @@ def main(): jf = JpegFile.fromFile(fname) except (IOError, JpegFile.InvalidFile): type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error reading %s:" % fname, value + print("Error reading {0}: {1}".format(fname, value), file=sys.stderr) return 1 exif = jf.get_exif() if exif: primary = exif.get_primary() if exif is None or primary is None: - print >> sys.stderr, "%s has no EXIF tag, skipping" % fname + print("{0} has no EXIF tag, skipping".format(fname), file=sys.stderr) continue adjust_time(primary, delta) @@ -68,7 +68,7 @@ def main(): jf.writeFile(fname) except IOError: type, value, traceback = sys.exc_info() - print >> sys.stderr, "Error saving %s:" % fname, value + print("Error saving {0}: {1}".format(fname, value), file=sys.stderr) return 1 return 0 diff --git a/test/test.py b/test/test.py index 288bbd1..e8a17c6 100644 --- a/test/test.py +++ b/test/test.py @@ -1,7 +1,7 @@ import unittest import pexif -import StringIO import difflib +import six test_data = [ ("test/data/rose.jpg", "test/data/rose.txt"), @@ -54,14 +54,14 @@ def test_dump(self): for test_file, expected_file in test_data: expected = open(expected_file, 'rb').read() jpeg = pexif.JpegFile.fromFile(test_file) - out = StringIO.StringIO() + out = six.BytesIO() jpeg.dump(out) res = "Error in file <%s>\n" % test_file - x = difflib.unified_diff(expected.split('\n'), out.getvalue().split('\n')) + x = difflib.unified_diff(str(expected).split('\n'), str(out.getvalue()).split('\n')) for each in x: res += each res += '\n' - self.assertEqual(expected, out.getvalue(), res) + self.assertEqual(str(expected), str(out.getvalue()), res) class TestExifFunctions(unittest.TestCase): @@ -75,8 +75,8 @@ def test_badendian(self): def test_badtifftag(self): data = list(open(DEFAULT_TESTFILE, "rb").read()) # Now trash the exif signature - assert(data[0x20] == '\x2a') - data[0x20] = '0' + assert(data[six.b(0x20)] == '\x2a') + data[six.b(0x20)] = '0' self.assertRaises(pexif.JpegFile.InvalidFile, pexif.JpegFile.fromString, "".join(data)) def test_goodexif(self):