--- ApeTag.py.orig 2007-11-07 01:15:19 UTC +++ ApeTag.py @@ -104,6 +104,7 @@ APEv2 specification is here: from os.path import isfile as _isfile from struct import pack as _pack, unpack as _unpack +from functools import reduce # Variable definitions @@ -115,7 +116,7 @@ _tagmustexistcommands = 'update getfields getrawtag'.s _stringallowedcommands = 'getrawtag getnewrawtag getfields hastag'.split() _filelikeattrs = 'flush read seek tell truncate write'.split() _badapeitemkeys = 'id3 tag oggs mp+'.split() -_badapeitemkeychars = ''.join([chr(x) for x in range(32) + range(128,256)]) +_badapeitemkeychars = ''.join([chr(x) for x in list(range(32)) + list(range(128,256))]) _apeitemtypes = 'utf8 binary external reserved'.split() _apeheaderflags = "\x00\x00\xA0" _apefooterflags = "\x00\x00\x80" @@ -160,7 +161,7 @@ del i # Classes -class TagError(StandardError): +class TagError(Exception): '''Raised when there is an error during a tagging operation''' pass @@ -171,16 +172,16 @@ class ApeItem(list): if key is None: return if not self.validkey(key): - raise TagError, 'Invalid item key for ape tag item: %r' % key + raise TagError('Invalid item key for ape tag item: %r' % key) if type not in _apeitemtypes: - raise TagError, 'Invalid item type for ape tag item: %r' % type + raise TagError('Invalid item type for ape tag item: %r' % type) self.key = key self.readonly = bool(readonly) self.type = type - if isinstance(values, basestring): + if isinstance(values, str): values = [values] if type == 'utf8' or type == 'external': - values = [unicode(value) for value in values] + values = [str(value) for value in values] self.extend(values) def maketag(self): @@ -201,26 +202,26 @@ class ApeItem(list): del self[:] itemlength = _unpack(" 3: - raise TagError, 'Corrupt tag, invalid item flags, bits 3-7 ' \ - 'nonzero at position %i' % curpos + raise TagError('Corrupt tag, invalid item flags, bits 3-7 ' \ + 'nonzero at position %i' % curpos) self.type = _apeitemtypes[type] self.readonly = bool(readonly) curpos += 8 keyend = data.find("\x00", curpos) if keyend < curpos: - raise TagError, 'Corrupt tag, unterminated item key at position ' \ - '%i' % curpos + raise TagError('Corrupt tag, unterminated item key at position ' \ + '%i' % curpos) itemkey = data[curpos:keyend] if not self.validkey(itemkey): - raise TagError, 'Corrupt tag, invalid item key at position ' \ - '%i: %r' % (curpos, itemkey) + raise TagError('Corrupt tag, invalid item key at position ' \ + '%i: %r' % (curpos, itemkey)) self.key = itemkey curpos = keyend + itemlength + 1 itemvalue = data[keyend+1:curpos] @@ -246,30 +247,30 @@ def _ape(fil, action, callback = None, callbackkwargs if _apepreamble != data[:12]: if action in _tagmustexistcommands: - raise TagError, "Nonexistant or corrupt tag, can't %s" % action + raise TagError("Nonexistant or corrupt tag, can't %s" % action) elif action == "delete": return 0 data = '' tagstart = filesize - len(id3data) elif _apefooterflags != data[21:24] or \ (data[20] != '\0' and data[20] != '\1'): - raise TagError, "Bad tag footer flags" + raise TagError("Bad tag footer flags") else: # file has a valid APE footer apesize = _unpack(" _maxapesize: - raise TagError, 'Existing tag is too large: %i bytes' % apesize + raise TagError('Existing tag is too large: %i bytes' % apesize) if apesize + len(id3data) > filesize: - raise TagError, 'Existing tag says it is larger than the file: ' \ - '%i bytes' % apesize + raise TagError('Existing tag says it is larger than the file: ' \ + '%i bytes' % apesize) fil.seek(-apesize - len(id3data), 2) tagstart = fil.tell() data = fil.read(apesize) if _apepreamble != data[:12] or _apeheaderflags != data[21:24] or \ (data[20] != '\0' and data[20] != '\1'): - raise TagError, 'Nonexistent or corrupt tag, missing tag header' + raise TagError('Nonexistent or corrupt tag, missing tag header') if apesize != _unpack(" _maxapesize: - raise TagError, 'New tag is too large: %i bytes' % len(data) + raise TagError('New tag is too large: %i bytes' % len(data)) if updateid3: if action == 'replace': id3data = '' elif action != 'create' and not id3data: - raise TagError, "Nonexistant or corrupt tag, can't %s" % action + raise TagError("Nonexistant or corrupt tag, can't %s" % action) if callable(updateid3): id3data = _id3(id3data, "getnewrawtag", updateid3, callbackkwargs) else: @@ -330,7 +331,7 @@ def _ape(fil, action, callback = None, callbackkwargs def _apefieldstoid3fields(fields): '''Convert APE tag fields to ID3 tag fields ''' id3fields = {} - for key, value in fields.iteritems(): + for key, value in fields.items(): key = key.lower() if isinstance(value, (list, tuple)): if not value: @@ -347,7 +348,7 @@ def _apefieldstoid3fields(fields): else: id3fields['track'] = 0 elif key == 'genre': - if isinstance(value, basestring) and value.lower() in _id3genresdict: + if isinstance(value, str) and value.lower() in _id3genresdict: id3fields[key] = value else: id3fields[key] = '' @@ -357,7 +358,7 @@ def _apefieldstoid3fields(fields): except ValueError: pass elif key in _id3fields: - if isinstance(value, unicode): + if isinstance(value, str): value = value.encode('utf8') id3fields[key] = value return id3fields @@ -367,28 +368,28 @@ _apelengthreduce = lambda i1, i2: i1 + len(i2) def _checkargs(fil, action): '''Check that arguments are valid, convert them, or raise an error''' if not (isinstance(action,str) and action.lower() in _commands): - raise TagError, "%r is not a valid action" % action + raise TagError("%r is not a valid action" % action) action = action.lower() fil = _getfileobj(fil, action) for attr in _filelikeattrs: if not hasattr(fil, attr) or not callable(getattr(fil, attr)): - raise TagError, "fil does not support method %r" % attr + raise TagError("fil does not support method %r" % attr) return fil, action def _checkfields(fields): '''Check that the fields quacks like a dict''' if not hasattr(fields, 'items') or not callable(fields.items): - raise TagError, "fields does not support method 'items'" + raise TagError("fields does not support method 'items'") def _checkremovefields(removefields): '''Check that removefields is iterable''' if not hasattr(removefields, '__iter__') \ or not callable(removefields.__iter__): - raise TagError, "removefields is not an iterable" + raise TagError("removefields is not an iterable") def _getfileobj(fil, action): '''Return a file object if given a filename, otherwise return file''' - if isinstance(fil, basestring) and _isfile(fil): + if isinstance(fil, str) and _isfile(fil): if action in _stringallowedcommands: mode = 'rb' else: @@ -423,7 +424,7 @@ def _id3(fil, action, callback = None, callbackkwargs= '''Get or Modify ID3 tag for file''' if isinstance(fil, str): if action not in _stringallowedcommands: - raise TagError, "String not allowed for %s action" % action + raise TagError("String not allowed for %s action" % action) data = fil else: fil.seek(0, 2) @@ -438,7 +439,7 @@ def _id3(fil, action, callback = None, callbackkwargs= if action == "delete": return 0 if action in _tagmustexistcommands: - raise TagError, "Nonexistant or corrupt tag, can't %s" % action + raise TagError("Nonexistant or corrupt tag, can't %s" % action) data = '' else: tagstart -= 128 @@ -473,7 +474,7 @@ def _id3(fil, action, callback = None, callbackkwargs= def _makeapev2tag(apeitems): '''Construct an APE tag string from a dict of ApeItems''' - apeentries = [item.maketag() for item in apeitems.itervalues()] + apeentries = [item.maketag() for item in apeitems.values()] apeentries.sort(_sortapeitems) apesize = _pack(" (len(data) - 32)/11: - raise TagError, 'Corrupt tag, specifies more items that is possible ' \ - 'given space remaining: %i items' % numitems + raise TagError('Corrupt tag, specifies more items that is possible ' \ + 'given space remaining: %i items' % numitems) curpos = 32 tagitemend = len(data) - 32 for x in range(numitems): if curpos >= tagitemend: - raise TagError, 'Corrupt tag, end of tag reached with more items' \ - 'specified' + raise TagError('Corrupt tag, end of tag reached with more items' \ + 'specified') item = ApeItem() curpos = item.parsetag(data, curpos) itemkey = item.key.lower() if itemkey in apeitems: - raise TagError, 'Corrupt tag, duplicate item key: %r' % itemkey + raise TagError('Corrupt tag, duplicate item key: %r' % itemkey) apeitems[itemkey] = item if tagitemend - curpos: - raise TagError, 'Corrupt tag, parsing complete but not at end ' \ - 'of input: %i bytes remaining' % (len(data) - curpos) + raise TagError('Corrupt tag, parsing complete but not at end ' \ + 'of input: %i bytes remaining' % (len(data) - curpos)) return apeitems def _parseid3tag(data): '''Parse an ID3 tag and return a dictionary of tag fields''' fields = {} - for key,(start,end) in _id3fields.iteritems(): + for key,(start,end) in _id3fields.items(): fields[key] = data[start:end].rstrip("\x00") if data[125] == "\x00": # ID3v1.1 tags have tracks @@ -575,30 +576,30 @@ def _parseid3tag(data): def _printapeitems(apeitems): '''Pretty print given APE Items''' - items = apeitems.items() + items = list(apeitems.items()) items.sort() - print 'APE Tag\n-------' + print('APE Tag\n-------') for key, value in items: if value.readonly: key = '[read only] %s' % key if value.type == 'utf8': - value = u', '.join([v.encode('ascii', 'replace') for v in value]) + value = ', '.join([v.encode('ascii', 'replace') for v in value]) else: key = '[%s] %s' % (value.type, key) if value.type == 'binary': value = '[binary data]' else: value = ', '.join(value) - print '%s: %s' % (key, value) + print('%s: %s' % (key, value)) def _printid3items(tagfields): '''Pretty print given ID3 Fields''' - items = tagfields.items() + items = list(tagfields.items()) items.sort() - print 'ID3 Tag\n-------' + print('ID3 Tag\n-------') for key, value in items: if value: - print '%s: %s' % (key, value) + print('%s: %s' % (key, value)) def _removeapeitems(apeitems, removefields): '''Remove items from the APE tag''' @@ -609,7 +610,7 @@ def _removeapeitems(apeitems, removefields): def _restoredictcase(apeitems): '''Restore the case of the dictionary keys for the ApeItems''' fixeditems = {} - for value in apeitems.itervalues(): + for value in apeitems.values(): fixeditems[value.key] = value return fixeditems @@ -634,13 +635,13 @@ def _tag(function, fil, action="update", *args, **kwar try: return function(fil, action, *args, **kwargs) finally: - if isinstance(origfil, basestring): + if isinstance(origfil, str): # filename given as an argument, close file object fil.close() def _updateapeitems(apeitems, fields): '''Add/Update apeitems using data from fields''' - for key, value in fields.iteritems(): + for key, value in fields.items(): if isinstance(value, ApeItem): apeitems[value.key.lower()] = value else: @@ -655,7 +656,7 @@ def _updateapetagcallback(apeitems, fields={}, removef def _updateid3fields(tagfields, fields): '''Update ID3v1 tagfields using fields''' - for field, value in fields.iteritems(): + for field, value in fields.items(): if isinstance(field, str): tagfields[field.lower()] = value return tagfields @@ -806,10 +807,10 @@ if __name__ == '__main__': import sys for filename in sys.argv[1:]: if _isfile(filename): - print '\n%s' % filename + print('\n%s' % filename) try: printtags(filename) except TagError: - print 'Missing APE or ID3 Tag' + print('Missing APE or ID3 Tag') else: - print "%s: file doesn't exist" % filename + print("%s: file doesn't exist" % filename) --- test_ApeTag.py.orig 2007-11-07 01:12:54 UTC +++ test_ApeTag.py @@ -1,6 +1,6 @@ #!/usr/bin/env python import ApeTag -import cStringIO +import io import unittest import os.path @@ -29,7 +29,7 @@ def rr(string, position, characters, io = True): return s def sio(string): - x = cStringIO.StringIO() + x = io.StringIO() x.write(string) return x