Commits

Anonymous committed 97905ec Merge

Merged nicfit/eyed3 into default

Comments (0)

Files changed (19)

File contents unchanged.

docs/changelog.rst

 ChangeLog
 #########
 
+.. _release-0.7.2:
+# Up to date as of r222
+
+**0.7.2** - TBD (TBD)
+  New Features:
+    * Documentation and examples are now included in source distribution.
+    * [classic plugin] Removed ``-p`` for setting publisher since using it
+      when ``-P`` is intended is destructive.
+    * [statistics plgin] Added rules for "lint-like" checking of a collection.
+      The rules are not yet configurable.
+    * Error is now the default log level.
+
+  Bug fixes:
+    * Convert '/' to '-' in TagTemplate names (i.e. --rename)
+    * Drop TSIZ frames when converting to ID3 v2.4
+    * ID3 tag padding size now set correctly.
+    * Fixes for Unicode paths.
+    * License clarification in pkg-info.
+    * The ``-b`` setup.py argument is now properly supported.
+
 .. _release-0.7.1:
 .. _ID3 chapters and table-of-contents: http://www.id3.org/id3v2-chapters-1.0
 
 PROJECT = u"eyeD3"
 VERSION = "0.7.2"
 
-LICENSE     = open("COPYING", "r").read().strip('\n')
+LICENSE = open("COPYING", "r").read().strip('\n')
 DESCRIPTION = "Python audio data toolkit (ID3 and MP3)"
 LONG_DESCRIPTION = """
 eyeD3 is a Python module and command line program for processing ID3 tags.
 play time, etc.) is also provided. The formats supported are ID3
 v1.0/v1.1 and v2.3/v2.4.
 """
-URL          = "http://eyeD3.nicfit.net"
-AUTHOR       = "Travis Shirk"
+URL = "http://eyeD3.nicfit.net"
+AUTHOR = "Travis Shirk"
 AUTHOR_EMAIL = "travis@pobox.com"
 SRC_DIST_TGZ = "%s-%s.tgz" % (PROJECT, VERSION)
 SRC_DIST_ZIP = "%s.zip" % os.path.splitext(SRC_DIST_TGZ)[0]
-DOC_DIST     = "%s_docs-%s.tgz" % (PROJECT, VERSION)
-MD5_DIST     = "%s.md5" % os.path.splitext(SRC_DIST_TGZ)[0]
-DOC_BUILD_D  = "docs/_build"
+DOC_DIST = "%s_docs-%s.tgz" % (PROJECT, VERSION)
+MD5_DIST = "%s.md5" % os.path.splitext(SRC_DIST_TGZ)[0]
+DOC_BUILD_D = "docs/_build"
 
 PACKAGE_DATA = paver.setuputils.find_package_data("src/eyed3",
                                                   package="eyed3",
         url=URL,
         download_url="%s/releases/%s" % (URL, SRC_DIST_TGZ),
         license="GPL",
-        package_dir={"": "src" },
+        package_dir={"": "src"},
         packages=setuptools.find_packages("src",
                                           exclude=["test", "test.*"]),
         zip_safe=False,
     ),
 
     cog=Bunch(
-       beginspec='{{{cog',
-       endspec='}}}',
-       endoutput='{{{end}}}',
-       includedir=path(__file__).abspath().dirname(),
+        beginspec='{{{cog',
+        endspec='}}}',
+        endoutput='{{{end}}}',
+        includedir=path(__file__).abspath().dirname(),
     ),
 
     test=Bunch(
-       pdb=False,
-       coverage=False,
+        pdb=False,
+        coverage=False,
     ),
 
     release=Bunch(
     ),
 )
 
+
 @task
 @no_help
 def eyed3_info():
         target_file.write(src_data)
         target_file.close()
 
+
 @task
 @needs("eyed3_info",
        "setuptools.command.build")
     '''Build the code'''
     pass
 
+
 @task
 @needs("test_clean")
 def clean():
     except ImportError:
         pass
 
+
 @task
 def docs_clean(options):
     '''Clean docs'''
     except ImportError:
         pass
 
+
 @task
 @needs("distclean", "docs_clean")
 def maintainer_clean():
     path("paver-minilib.zip").remove()
     path("setup.py").remove()
 
+
 @task
 @needs("clean")
 def distclean():
         f.remove()
     path("src/eyed3/info.py").remove()
 
+
 @task
 @needs("cog")
 def docs(options):
     print("Docs: file://%s/%s/%s/html/index.html" %
           (os.getcwd(), options.docroot, options.builddir))
 
+
 @task
 @needs("distclean",
        "eyed3_info",
         print("Coverage Report: file://%s/build/test/coverage/index.html" %
               os.getcwd())
 
+
 @task
 def test_clean():
     '''Clean tests'''
     path("built/test/html").rmtree()
     path(".coverage").remove()
 
+
 @task
 @needs("sdist")
 def test_dist():
 
     pass
 
+
 @task
 def checklist():
     '''Show release procedure'''
 - ebuild
 """ % globals())
 
+
 @task
 @cmdopts([("test", "",
            u"Run in a mode where commits, pushes, etc. are performed"),
     resp = raw_input()
     return True if resp in ["y", "yes"] else False
 
+
 def cog_pluginHelp(name):
     from string import Template
     import argparse
     return template.substitute(substs)
 __builtins__["cog_pluginHelp"] = cog_pluginHelp
 
+
 # XXX: modified from paver.doctools._runcog to add includers
 def _runcog(options, uncog=False):
     """Common function for the cog and runcog tasks."""
         dry("cog %s" % f, c.processOneFile, f)
 
 from paver.doctools import Includer, _cogsh
+
+
 class CliExample(Includer):
     def __call__(self, fn, section=None, lang="bash"):
         # Resetting self.cog to get a string back from Includer.__call__
         raw = Includer.__call__(self, fn, section=section)
         self.cog = cog
 
-        commands = []
-
         self.cog.gen.out(u"\n.. code-block:: %s\n\n" % lang)
         for line in raw.splitlines(True):
             if line.strip() == "":
                 if output:
                     self.cog.gen.out("\n")
 
+
 @task
 def cog(options):
     '''Run cog on all docs'''

src/eyed3/__init__.py

 #
 ################################################################################
 '''Top-level module.'''
-import sys, locale, exceptions
+import sys
+import locale
+import exceptions
 
 
 _DEFAULT_ENCODING = "latin1"
     '''
     import types
     from .info import VERSION_TUPLE as CURRENT_VERSION
+
     def t2s(_t):
         return ".".join([str(v) for v in _t])
 

src/eyed3/core.py

 
 AUDIO_NONE = 0
 '''Audio type selecter for no audio.'''
-AUDIO_MP3 =  1
+AUDIO_MP3  = 1
 '''Audio type selecter for mpeg (mp3) audio.'''
 
 AUDIO_TYPES = (AUDIO_NONE, AUDIO_MP3)
 
         new_name = u"%s%s" % (os.path.join(dir, name), base_ext)
         if os.path.exists(new_name):
-            raise Exception("File '%s' exists, will not overwrite" % new_name)
+            raise IOError("File '%s' exists, will not overwrite" % new_name)
         elif not os.path.exists(os.path.dirname(new_name)):
-            raise Exception("Target directory '%s' does not exists, will not "
-                            "create" % os.path.dirname(new_name))
+            raise IOError("Target directory '%s' does not exists, will not "
+                          "create" % os.path.dirname(new_name))
 
         os.rename(self.path, new_name)
         self.path = new_name

src/eyed3/id3/frames.py

 import re
 from cStringIO import StringIO
 from collections import namedtuple
+import logging
 
 from .. import core
 from ..utils import requireUnicode
 from ..utils.binfuncs import *
+from .. import Exception as BaseException
 from . import ID3_V2, ID3_V2_3, ID3_V2_4
 from . import (LATIN1_ENCODING, UTF_8_ENCODING, UTF_16BE_ENCODING,
                UTF_16_ENCODING, DEFAULT_LANG)
 from .headers import FrameHeader
 
-import logging
+
 log = logging.getLogger(__name__)
 
-from .. import Exception as BaseException
+
 class FrameException(BaseException):
     pass
 
         # Format flags in the frame header may add extra data to the
         # beginning of this data.
         if header.minor_version <= 3:
-            # 2.3:  compression(4), encryption(1), group(1) 
+            # 2.3:  compression(4), encryption(1), group(1)
             if header.compressed:
                 self.decompressed_size = bin2dec(bytes2bin(data[:4]))
                 data = data[4:]
                 data = data[4:]
                 log.debug("Data Length: %d" % self.data_len)
                 if header.compressed:
-                   self.decompressed_size = self.data_len
-                   log.debug("Decompressed Size: %d" % self.decompressed_size)
+                    self.decompressed_size = self.data_len
+                    log.debug("Decompressed Size: %d" % self.decompressed_size)
 
         if header.minor_version == 4 and header.unsync:
             data = deunsyncData(data)
     # Process a 3 byte language code (ISO 639-2).
     # This code must match the [A-Z][A-Z][A-Z]
     # (although case is ignored) and be ascii to be considered valid. When
-    # deemed invalid warnings are logged and the value is changed to 
+    # deemed invalid warnings are logged and the value is changed to
     # \c DEFAULT_LANG.
     #
     # \param lang The code.
         try:
             # Test ascii encoding, it MUST be
             lang = lang.encode("ascii")
-        except (UnicodeEncodeError, UnicodeDecodeError) as ex:
+        except (UnicodeEncodeError, UnicodeDecodeError):
             log.warning("Fixing invalid lyrics language code: %s" % lang)
             lang = DEFAULT_LANG
 
     def description(self, txt):
         self._description = txt
 
-    # Data string format: encoding (one byte) + description + "\x00" + text
     def parse(self, data, frame_header):
+        '''Data string format:
+        encoding (one byte) + description + "\x00" + text '''
         # Calling Frame, not TextFrame implementation here since TextFrame
         # does not know about description
         Frame.parse(self, data, frame_header)
         self.date = self.text
         self.encoding = LATIN1_ENCODING
 
+    def parse(self, data, frame_header):
+        super(DateFrame, self).parse(data, frame_header)
+        try:
+            if self.text:
+                _ = core.Date.parse(self.text.encode("latin1"))
+        except ValueError:
+            # Date is invalid, log it and reset.
+            core.parseError(FrameException(u"Invalid date: " + self.text))
+            self.text = u''
+
     @property
     def date(self):
         return core.Date.parse(self.text.encode("latin1")) if self.text \
         self.data = self.url
         return super(UrlFrame, self).render()
 
-##
-# Data string format:
-# encoding (one byte) + description + "\x00" + url (ascii)
+
 class UserUrlFrame(UrlFrame):
+    '''
+    Data string format:
+    encoding (one byte) + description + "\x00" + url (ascii)
+    '''
     @requireUnicode("description")
     def __init__(self, id=USERURL_FID, description=u"", url=""):
         UrlFrame.__init__(self, id, url=url)
                                            "type"))
         if (self.mime_type != self.URL_MIME_TYPE and
                 self.mime_type.find("/") == -1):
-           self.mime_type = "image/" + self.mime_type
+            self.mime_type = "image/" + self.mime_type
 
         pt = ord(input.read(1))
         log.debug("Initial APIC picture type: %d" % pt)
         log.debug("description len: %d" % len(desc))
         log.debug("image len: %d" % len(img))
         self.description = decodeUnicode(desc, encoding)
-        log.debug("APIC description: %s" % self.description);
+        log.debug("APIC description: %s" % self.description)
 
         if self.mime_type.find(self.URL_MIME_TYPE) != -1:
             self.image_data = None
         self.data = data
         return super(ImageFrame, self).render()
 
-
     @staticmethod
     def picTypeToString(t):
         if t == ImageFrame.OTHER:
         elif s == "PUBLISHER_LOGO":
             return ImageFrame.PUBLISHER_LOGO
         else:
-          raise ValueError("Invalid APIC picture type: %s" % s)
+            raise ValueError("Invalid APIC picture type: %s" % s)
 
 
 class ObjectFrame(Frame):
             self.mime_type = input.read(3)
         log.debug("GEOB mime type: %s" % self.mime_type)
         if not self.mime_type:
-           core.parseError(FrameException("GEOB frame does not contain a mime "
-                                          "type"))
+            core.parseError(FrameException("GEOB frame does not contain a "
+                                           "mime type"))
         if self.mime_type.find("/") == -1:
-           core.parseError(FrameException("GEOB frame does not contain a valid "
-                                          "mime type"))
+            core.parseError(FrameException("GEOB frame does not contain a "
+                                           "valid mime type"))
 
         self.filename = u""
         self.description = u""
     @property
     def rating(self):
         return self._rating
+
     @rating.setter
     def rating(self, rating):
         if rating < 0 or rating > 255:
     @property
     def email(self):
         return self._email
+
     @email.setter
     def email(self, email):
         self._email = email.encode("ascii")
     @property
     def count(self):
         return self._count
+
     @count.setter
     def count(self, count):
         if count < 0:
         self.data = data
         return super(PopularityFrame, self).render()
 
+
 class UniqueFileIDFrame(Frame):
     def __init__(self, id=UNIQUE_FILE_ID_FID, owner_id=None, uniq_id=None):
         super(UniqueFileIDFrame, self).__init__(id)
         self.data = self.owner_id + "\x00" + self.uniq_id
         return super(UniqueFileIDFrame, self).render()
 
+
 class DescriptionLangTextFrame(Frame):
 
     @requireUnicode(2, 4)
         super(CommentFrame, self).__init__(id, description, lang, text)
         assert(self.id == COMMENT_FID)
 
+
 class LyricsFrame(DescriptionLangTextFrame):
     def __init__(self, id=LYRICS_FID, description=u"", lang=DEFAULT_LANG,
                  text=u""):
         super(LyricsFrame, self).__init__(id, description, lang, text)
         assert(self.id == LYRICS_FID)
 
+
 class TermsOfUseFrame(Frame):
     @requireUnicode("text")
     def __init__(self, id="USER", text=u"", lang=DEFAULT_LANG):
                      self.text.encode(id3EncodingToString(self.encoding)))
         return super(TermsOfUseFrame, self).render()
 
+
 class TocFrame(Frame):
     '''Table of content frame. There may be more than one, but only one may
     have the top-level flag set.
 
 StartEndTuple = namedtuple("StartEndTuple", ["start", "end"])
 
+
 class ChapterFrame(Frame):
     '''Frame type for chapter/section of the audio file.
     <ID3v2.3 or ID3v2.4 frame header, ID: "CHAP">           (10 bytes)
         '''Read frames starting from the current read position of the file
         object. Returns the amount of padding which occurs after the tag, but
         before the audio content.  A return valule of 0 does not mean error.'''
-        from .headers import FrameHeader
-
         self.clear()
 
         padding_size = 0
             log.debug("De-unsynch'd %d bytes at once (<= 2.3 tag) to %d bytes" %
                       (og_size, size_left))
 
-        # Adding bytes to simulate the tag header(s) in the buffer.  This keeps 
+        # Adding bytes to simulate the tag header(s) in the buffer.  This keeps
         # f.tell() values matching the file offsets for logging.
         prepadding = '\x00' * 10  # Tag header
         prepadding += '\x00' * extended_header.size
             dict.__setitem__(self, fid, [frame])
 
     def getAllFrames(self):
+        '''Return all the frames in the set as a list. The list is sorted
+        in an arbitrary but consistent order.'''
         frames = []
         for flist in list(self.values()):
             frames += flist
+        frames.sort()
         return frames
 
     @requireUnicode(2)
         assert(fid[0] == "T" and fid in list(ID3_FRAMES.keys()))
 
         if fid in self:
-            curr = self[fid][0].text = text
+            self[fid][0].text = text
         else:
             if fid in DATE_FIDS:
                 self[fid] = DateFrame(fid, date=text)
             else:
                 self[fid] = TextFrame(fid, text=text)
 
+
 def deunsyncData(data):
     output = []
     safe = True
         if encoding == LATIN1_ENCODING or encoding == UTF_8_ENCODING:
             (d, t) = data.split("\x00", 1)
         elif encoding == UTF_16_ENCODING or encoding == UTF_16BE_ENCODING:
-            # Two null bytes split, but since each utf16 char is also two 
+            # Two null bytes split, but since each utf16 char is also two
             # bytes we need to ensure we found a proper boundary.
             (d, t) = data.split("\x00\x00", 1)
             if (len(d) % 2) != 0:
     else:
         raise ValueError("Encoding unknown: %s" % encoding)
 
+
 def stringToEncoding(s):
     s = s.replace('-', '_')
     if s in ("latin_1", "latin1"):
     "TCP" : "TCP ", # iTunes "extension" for compilation marking
     "CM1" : "CM1 ", # Seems to be some script kiddie tagging the tag.
                     # For example, [rH] join #rH on efnet [rH]
-    "PCS" : "PCST", # iTunes extension for podcast marking. 
+    "PCS" : "PCST", # iTunes extension for podcast marking.
 }
 
 import apple
 NONSTANDARD_ID3_FRAMES = {
-        "NCON": ("Undefined MusicMatch extension", ID3_V2, Frame),
-        "TCMP": ("iTunes complilation flag extension", ID3_V2, TextFrame),
-        "XSOA": ("Album sort-order string extension for v2.3",
-                 ID3_V2_3, TextFrame),
-        "XSOP": ("Performer sort-order string extension for v2.3",
-                 ID3_V2_3, TextFrame),
-        "XSOT": ("Title sort-order string extension for v2.3",
-                 ID3_V2_3, TextFrame),
-        "XDOR": ("MusicBrainz release date (full) extension for v2.3",
-                 ID3_V2_3, TextFrame),
+    "NCON": ("Undefined MusicMatch extension", ID3_V2, Frame),
+    "TCMP": ("iTunes complilation flag extension", ID3_V2, TextFrame),
+    "XSOA": ("Album sort-order string extension for v2.3",
+             ID3_V2_3, TextFrame),
+    "XSOP": ("Performer sort-order string extension for v2.3",
+             ID3_V2_3, TextFrame),
+    "XSOT": ("Title sort-order string extension for v2.3",
+             ID3_V2_3, TextFrame),
+    "XDOR": ("MusicBrainz release date (full) extension for v2.3",
+             ID3_V2_3, TextFrame),
 
-        "PCST": ("iTunes extension; marks the file as a podcast",
-                 ID3_V2, apple.PCST),
-        "TKWD": ("iTunes extension; podcast keywords?",
-                 ID3_V2, apple.TKWD),
-        "TDES": ("iTunes extension; podcast description?",
-                 ID3_V2, apple.TDES),
-        "TGID": ("iTunes extension; podcast ?????",
-                 ID3_V2, apple.TGID),
-        "WFED": ("iTunes extension; podcast feed URL?",
-                 ID3_V2, apple.WFED),
+    "PCST": ("iTunes extension; marks the file as a podcast",
+             ID3_V2, apple.PCST),
+    "TKWD": ("iTunes extension; podcast keywords?",
+             ID3_V2, apple.TKWD),
+    "TDES": ("iTunes extension; podcast description?",
+             ID3_V2, apple.TDES),
+    "TGID": ("iTunes extension; podcast ?????",
+             ID3_V2, apple.TGID),
+    "WFED": ("iTunes extension; podcast feed URL?",
+             ID3_V2, apple.WFED),
 }
 

src/eyed3/id3/tag.py

 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 ################################################################################
-import types, sys, string, re, os, shutil, types, tempfile
+import os
+import types
+import string
+import shutil
+import tempfile
 
 from ..utils import requireUnicode, chunkCopy
 from .. import core
+from .. import Exception as BaseException
 from . import (ID3_ANY_VERSION, ID3_V1, ID3_V1_0, ID3_V1_1,
                ID3_V2, ID3_V2_2, ID3_V2_3, ID3_V2_4, versionToString)
 from . import DEFAULT_LANG
 from . import frames
 from .headers import TagHeader, ExtendedTagHeader
 
-
 import logging
 log = logging.getLogger(__name__)
 
-from .. import Exception as BaseException
+
 class TagException(BaseException):
-   pass
+    pass
+
 
 ID3_V1_COMMENT_DESC = u"ID3v1.x Comment"
 DEFAULT_PADDING = 1024
 
+
 class Tag(core.Tag):
     def __init__(self):
         core.Tag.__init__(self)
         ## Optional extended header in v2 tags.
         self.extended_header = ExtendedTagHeader()
         ## Contains the tag's frames. ID3v1 fields are read and converted
-        #  the the corresponding v2 frame.  
+        #  the the corresponding v2 frame.
         self.frame_set = frames.FrameSet()
         self._comments = CommentsAccessor(self.frame_set)
         self._images = ImagesAccessor(self.frame_set)
         version = version or ID3_ANY_VERSION
 
         close_file = False
-        if type(fileobj) is types.FileType:
+        if isinstance(fileobj, types.FileType):
             filename = fileobj.name
         elif type(fileobj) in types.StringTypes:
             filename = fileobj
         if artist:
             self.artist = unicode(artist, v1_enc)
 
-
         album = tag_data[63:93].strip(STRIP_CHARS)
         log.debug("Album: %s" % album)
         if album:
     def version(self, v):
         self.header.version = v
 
-    ## Test ID3 major version for v1.x
     def isV1(self):
+        '''Test ID3 major version for v1.x'''
         return self.header.major_version == 1
-    ## Test ID3 major version for v2.x
+
     def isV2(self):
+        '''Test ID3 major version for v2.x'''
         return self.header.major_version == 2
 
     @requireUnicode(2)
     @requireUnicode(1)
     def _setArtist(self, val):
         self.setTextFrame(frames.ARTIST_FID, val)
+
     def _getArtist(self):
         return self.getTextFrame(frames.ARTIST_FID)
 
     @requireUnicode(1)
     def _setAlbum(self, val):
         self.setTextFrame(frames.ALBUM_FID, val)
+
     def _getAlbum(self):
         return self.getTextFrame(frames.ALBUM_FID)
 
     @requireUnicode(1)
     def _setTitle(self, val):
         self.setTextFrame(frames.TITLE_FID, val)
+
     def _getTitle(self):
         return self.getTextFrame(frames.TITLE_FID)
 
 
         n = (tn, tt)
 
-        if n[0] == None and n[1] == None:
+        if n[0] is None and n[1] is None:
             if self.frame_set[fid]:
                 del self.frame_set[fid]
             return
 
         total_str = ""
-        if n[1] != None:
+        if n[1] is not None:
             if n[1] >= 0 and n[1] <= 9:
                 total_str = "0" + str(n[1])
             else:
             bpm_str = self.frame_set[frames.BPM_FID][0].text or u"0"
             try:
                 # Round floats since the spec says this is an integer
-                bpm = int(float(bpm_str) + 0.5)
+                bpm = int(round(float(bpm_str)))
             except ValueError as ex:
                 log.warning(ex)
         return bpm
 
     def _setBpm(self, bpm):
-       assert(bpm >= 0)
-       self.setTextFrame(frames.BPM_FID, unicode(str(bpm)))
+        assert(bpm >= 0)
+        self.setTextFrame(frames.BPM_FID, unicode(str(bpm)))
 
     bpm = property(_getBpm, _setBpm)
 
     def play_count(self):
         if frames.PLAYCOUNT_FID in self.frame_set:
             pc = self.frame_set[frames.PLAYCOUNT_FID][0]
-            assert(type(pc.count) in (int,))
             return pc.count
         else:
             return None
             pc.count = count
         else:
             self.frame_set[frames.PLAYCOUNT_FID] = \
-                    frames.PlayCountFrame(count=count)
+                frames.PlayCountFrame(count=count)
 
     def _getPublisher(self):
         if frames.PUBLISHER_FID in self.frame_set:
             cdid.toc = str(toc)
         else:
             self.frame_set[frames.CDID_FID] = \
-                    frames.MusicCDIdFrame(toc=toc)
+                frames.MusicCDIdFrame(toc=toc)
 
     @property
     def images(self):
 
     def _getEncodingDate(self):
         return self._getDate("TDEN")
+
     def _setEncodingDate(self, date):
         self._setDate("TDEN", date)
     encoding_date = property(_getEncodingDate, _setEncodingDate)
                 self.recording_date)
 
     def _getReleaseDate(self):
-        return self._getDate("TDRL") if self.version == ID3_V2_4\
+        return self._getDate("TDRL") if self.version == ID3_V2_4 \
                                      else self._getV23OrignalReleaseDate()
+
     def _setReleaseDate(self, date):
         self._setDate("TDRL" if self.version == ID3_V2_4 else "TORY", date)
 
 
     def _getOrigReleaseDate(self):
         return self._getDate("TDOR") or self._getV23OrignalReleaseDate()
+
     def _setOrigReleaseDate(self, date):
         self._setDate("TDOR", date)
 
 
     def _getRecordingDate(self):
         return self._getDate("TDRC") or self._getV23RecordingDate()
+
     def _setRecordingDate(self, date):
         if self.version == ID3_V2_4:
             self._setDate("TDRC", date)
 
     def _getTaggingDate(self):
         return self._getDate("TDTG")
+
     def _setTaggingDate(self, date):
         self._setDate("TDTG", date)
     tagging_date = property(_getTaggingDate, _setTaggingDate)
 
     def _setDate(self, fid, date):
         assert(fid in frames.DATE_FIDS or
-                fid in frames.DEPRECATED_DATE_FIDS)
+               fid in frames.DEPRECATED_DATE_FIDS)
 
         if date is None:
             try:
     @property
     def disc_num(self):
         return self._splitNum(frames.DISCNUM_FID)
+
     @disc_num.setter
     def disc_num(self, val):
         self._setNum(frames.DISCNUM_FID, val)
             return Genre.parse(f[0].text)
         else:
             return None
+
     def _setGenre(self, g):
         '''
         Set the genre. Four types are accepted for the ``g`` argument.
     @property
     def commercial_url(self):
         return self._getUrlFrame(frames.URL_COMMERCIAL_FID)
+
     @commercial_url.setter
     def commercial_url(self, url):
         self._setUrlFrame(frames.URL_COMMERCIAL_FID, url)
     @property
     def copyright_url(self):
         return self._getUrlFrame(frames.URL_COPYRIGHT_FID)
+
     @copyright_url.setter
     def copyright_url(self, url):
         self._setUrlFrame(frames.URL_COPYRIGHT_FID, url)
     @property
     def audio_file_url(self):
         return self._getUrlFrame(frames.URL_AUDIOFILE_FID)
+
     @audio_file_url.setter
     def audio_file_url(self, url):
         self._setUrlFrame(frames.URL_AUDIOFILE_FID, url)
     @property
     def audio_source_url(self):
         return self._getUrlFrame(frames.URL_AUDIOSRC_FID)
+
     @audio_source_url.setter
     def audio_source_url(self, url):
         self._setUrlFrame(frames.URL_AUDIOSRC_FID, url)
     @property
     def artist_url(self):
         return self._getUrlFrame(frames.URL_ARTIST_FID)
+
     @artist_url.setter
     def artist_url(self, url):
         self._setUrlFrame(frames.URL_ARTIST_FID, url)
     @property
     def internet_radio_url(self):
         return self._getUrlFrame(frames.URL_INET_RADIO_FID)
+
     @internet_radio_url.setter
     def internet_radio_url(self, url):
         self._setUrlFrame(frames.URL_INET_RADIO_FID, url)
     @property
     def payment_url(self):
         return self._getUrlFrame(frames.URL_PAYMENT_FID)
+
     @payment_url.setter
     def payment_url(self, url):
         self._setUrlFrame(frames.URL_PAYMENT_FID, url)
     @property
     def publisher_url(self):
         return self._getUrlFrame(frames.URL_PUBLISHER_FID)
+
     @publisher_url.setter
     def publisher_url(self, url):
         self._setUrlFrame(frames.URL_PUBLISHER_FID, url)
             shutil.copyfile(self.file_info.name, backup_name)
 
         if version[0] == 1:
-            self.__saveV1Tag(version)
+            self._saveV1Tag(version)
         elif version[0] == 2:
-            self.__saveV2Tag(version, encoding)
+            self._saveV2Tag(version, encoding)
         else:
             assert(not "Version bug: %s" % str(version))
 
-    def __saveV1Tag(self, version):
+    def _saveV1Tag(self, version):
         assert(version[0] == 1)
 
         def pack(s, n):
 
         cmt = ""
         for c in self.comments:
-           if c.description == ID3_V1_COMMENT_DESC:
-              cmt = c.text
-              # We prefer this one over ""
-              break
-           elif c.description == "":
-              cmt = c.text
-              # Keep searching in case we find the description eyeD3 uses.
+            if c.description == ID3_V1_COMMENT_DESC:
+                cmt = c.text
+                # We prefer this one over ""
+                break
+            elif c.description == "":
+                cmt = c.text
+                # Keep searching in case we find the description eyeD3 uses.
         cmt = pack(cmt.encode("latin_1"), 30)
 
         if version != ID3_V1_0:
-           track = self.track_num[0]
-           if track != None:
-              cmt = cmt[0:28] + "\x00" + chr(int(track) & 0xff)
+            track = self.track_num[0]
+            if track is not None:
+                cmt = cmt[0:28] + "\x00" + chr(int(track) & 0xff)
         tag += cmt
 
         if not self.genre or self.genre.id is None:
-           genre = 0
+            genre = 0
         else:
-           genre = self.genre.id
+            genre = self.genre.id
         tag += chr(genre & 0xff)
 
         assert(len(tag) == 128)
                 else:
                     tag_file.seek(0, 2)
             except IOError:
-               # File is smaller than 128 bytes.
-               tag_file.seek(0, 2)
+                # File is smaller than 128 bytes.
+                tag_file.seek(0, 2)
 
             tag_file.write(tag)
             tag_file.flush()
                    {"tag_header": header_data,
                     "ext_header": ext_header_data,
                     "frames": frame_data,
-                   }
+                    }
         assert(len(tag_data) == (total_size - padding_size))
         return (rewrite_required, tag_data, "\x00" * padding_size)
 
-    def __saveV2Tag(self, version, encoding):
+    def _saveV2Tag(self, version, encoding):
         assert(version[0] == 2 and version[1] != 2)
         log.debug("Rendering tag version: %s" % versionToString(version))
 
             else:
                 if f.id in DATE_FIDS:
                     date_frames[f.id] = f
-        
+
         if date_frames:
             if version == ID3_V2_4:
                 if "TORY" in date_frames or "XDOR" in date_frames:
 
 
 ##
-# This class is for storing information about a parsed file. It containts info 
+# This class is for storing information about a parsed file. It containts info
 # such as the filename, original tag size, and amount of padding all of which
 # can make rewriting faster.
 class FileInfo:
         self.tag_size = 0  # This includes the padding byte count.
         self.tag_padding_size = 0
 
+
 class AccessorBase(object):
     def __init__(self, fid, fs, match_func=None):
         self._fid = fid
     def get(self, description, lang=DEFAULT_LANG):
         return super(DltAccessor, self).get(description, lang=lang)
 
+
 class CommentsAccessor(DltAccessor):
     def __init__(self, fs):
         super(CommentsAccessor, self).__init__(frames.CommentFrame,
                                                frames.COMMENT_FID, fs)
 
+
 class LyricsAccessor(DltAccessor):
     def __init__(self, fs):
         super(LyricsAccessor, self).__init__(frames.LyricsFrame,
                                              frames.LYRICS_FID, fs)
 
+
 class ImagesAccessor(AccessorBase):
     def __init__(self, fs):
         def match_func(frame, description):
     def get(self, description):
         return super(ImagesAccessor, self).get(description)
 
+
 class ObjectsAccessor(AccessorBase):
     def __init__(self, fs):
 
     def get(self, description):
         return super(ObjectsAccessor, self).get(description)
 
+
 class PrivatesAccessor(AccessorBase):
     def __init__(self, fs):
 
     def get(self, owner_id):
         return super(PrivatesAccessor, self).get(owner_id)
 
+
 class UserTextsAccessor(AccessorBase):
     def __init__(self, fs):
         def match_func(frame, description):
     def get(self, description):
         return super(UserTextsAccessor, self).get(description)
 
+
 class UniqueFileIdAccessor(AccessorBase):
     def __init__(self, fs):
         def match_func(frame, owner_id):
     def get(self, description):
         return super(UserUrlsAccessor, self).get(description)
 
+
 class PopularitiesAccessor(AccessorBase):
     def __init__(self, fs):
         def match_func(frame, email):
             return frame.element_id == element_id
         super(ChaptersAccessor, self).__init__(frames.CHAPTER_FID, fs,
                                                match_func)
+
     def set(self, element_id, times, offsets=(None, None), sub_frames=None):
         flist = self._fs[frames.CHAPTER_FID] or []
         for chap in flist:
         raise IndexError("toc '%s' not found" % elem_id)
 
 
-
-import string
 class TagTemplate(string.Template):
     idpattern = r'[_a-z][_a-z0-9:]*'
 

src/eyed3/main.py

 #
 ################################################################################
 from __future__ import print_function
-import sys, exceptions, os.path
-import ConfigParser
-import traceback
+import sys
+import exceptions
+import os.path
 import textwrap
-import eyed3, eyed3.utils, eyed3.utils.cli, eyed3.plugins, eyed3.info
+import eyed3
+import eyed3.utils
+import eyed3.utils.cli
+import eyed3.plugins
+import eyed3.info
 
 
 DEFAULT_PLUGIN = "classic"
 
 
 def _listPlugins(config):
-    from eyed3.utils.cli import GREEN, GREY, boldText, colorText
+    from eyed3.utils.cli import GREEN, GREY, boldText
 
     print("")
+
     def header(name):
         is_default = name == DEFAULT_PLUGIN
         return (boldText("* ", c=GREEN if is_default else None) +
 
     if args.config:
         config_file = os.path.abspath(config_file)
-    elif args.no_config == False:
+    elif args.no_config is False:
         config_file = DEFAULT_CONFIG
 
     if not config_file:
 
     return config
 
+
 def _getPluginPath(config):
     plugin_path = [eyed3.info.USER_PLUGINS_DIR]
 
     '''This is the main function for profiling
     http://code.google.com/appengine/kb/commontasks.html#profiling
     '''
-    import cProfile, pstats, StringIO
+    import cProfile
+    import pstats
+    import StringIO
 
     eyed3.log.debug("driver profileMain")
     prof = cProfile.Profile()
                        help="Do not load the default user config '%s'. "
                             "The -c/--config options are still honored if "
                             "present." % DEFAULT_CONFIG)
+        p.add_argument("--no-color", action="store_true", dest="no_color",
+                       help="Do not load the default user config '%s'. "
+                            "Suppress color codes in console output.")
 
         # Debugging options
         group = p.debug_arg_group
 
     if config and config.has_option("default", "options"):
         cmd_line_args.extend(config.get("default", "options").split())
+    if config and config.has_option(plugin_name, "options"):
+        cmd_line_args.extend(config.get(plugin_name, "options").split())
 
     # Reparse the command line including options from the config.
     args = parser.parse_args(args=cmd_line_args)
         args, _, config = parseCommandLine()
 
         for fp in [sys.stdout, sys.stderr]:
-            eyed3.utils.cli.enableColorOutput(fp, os.isatty(fp.fileno()))
+            color = not args.no_color and os.isatty(fp.fileno())
+            eyed3.utils.cli.enableColorOutput(fp, color)
 
-        mainFunc = main if args.debug_profile == False else profileMain
+        mainFunc = main if args.debug_profile is False else profileMain
         retval = mainFunc(args, config)
     except KeyboardInterrupt:
         retval = 0
     except IOError as ex:
         eyed3.utils.cli.printError(ex)
     except exceptions.Exception as ex:
-        msg = "Uncaught exception: %s\n%s" % (str(ex), traceback.format_exc())
-        eyed3.log.exception(msg)
-        sys.stderr.write("%s\n" % msg)
+        eyed3.utils.cli.printError("Uncaught exception: %s\n" % str(ex))
+        eyed3.log.exception(ex)
 
         if args.debug_pdb:
-            import pdb
-            pdb.post_mortem()
+            try:
+                import ipdb as pdb
+            except ImportError:
+                import pdb
+
+            e, m, tb = sys.exc_info()
+            pdb.post_mortem(tb)
     finally:
         sys.exit(retval)
 

src/eyed3/plugins/__init__.py

         _PLUGINS = {}
 
     def _isValidModule(f, d):
-        '''Determin if file ``f`` is a valid module file name.'''
+        '''Determine if file ``f`` is a valid module file name.'''
         # 1) tis a file
         # 2) does not start with '_', or '.'
         # 3) avoid the .pyc dup
                     continue
 
                 mod_name = os.path.splitext(f)[0]
-                mod = __import__(mod_name, globals=globals(),
-                                 locals=locals())
+                try:
+                    mod = __import__(mod_name, globals=globals(),
+                                     locals=locals())
+                except ImportError as ex:
+                    log.warning("Plugin '%s' requires packages that are not "
+                                "installed: %s" % ((f, d), ex))
+                    continue
+                except exceptions.Exception as ex:
+                    log.exception("Bad plugin '%s'", (f, d))
+                    continue
 
                 for attr in [getattr(mod, a) for a in dir(mod)]:
                     if (type(attr) == types.TypeType and
                         PluginClass = attr
                         if (PluginClass not in list(_PLUGINS.values()) and
                                 len(PluginClass.NAMES)):
-                            log.debug("loading plugin '%s' fron '%s%s%s'",
+                            log.debug("loading plugin '%s' from '%s%s%s'",
                                       mod, d, os.path.sep, f)
                             # Setting the main name outside the loop to ensure
                             # there is at least one, otherwise a KeyError is
                             if name and name in PluginClass.NAMES:
                                 return PluginClass
 
-        except ImportError as ex:
-            log.warning("Plugin '%s' requires packages that are not "
-                        "installed: %s" % ((f, d), ex))
-            continue
-        except exceptions.Exception as ex:
-            log.exception("Bad plugin '%s'", (f, d))
-            continue
-
         finally:
             if d in sys.path:
                 sys.path.remove(d)

src/eyed3/plugins/classic.py

 from __future__ import print_function
 
 import os, stat, exceptions, re
-import traceback
 from eyed3 import LOCAL_ENCODING
 from eyed3.plugins import LoaderPlugin
 from eyed3 import core, id3, mp3, utils
 
 FIELD_DELIM = ':'
 
+
 class ClassicPlugin(LoaderPlugin):
     SUMMARY = u"Classic eyeD3 interface for viewing and editing tags."
     DESCRIPTION = u"""
 
         def UnicodeArg(arg):
             return unicode(arg, LOCAL_ENCODING)
+
         def PositiveIntArg(i):
             i = int(i)
             if i < 0:
             NEW_DELIM = "#DELIM#"
             arg = re.sub(r"\\%s" % FIELD_DELIM, NEW_DELIM, arg)
             return tuple(re.sub(NEW_DELIM, FIELD_DELIM, s)
-                            for s in arg.split(FIELD_DELIM))
+                         for s in arg.split(FIELD_DELIM))
 
         def DescLangArg(arg):
             arg = unicode(arg, LOCAL_ENCODING)
             desc = vals[0]
             lang = vals[1] if len(vals) > 1 else id3.DEFAULT_LANG
             return (desc, str(lang)[:3] or id3.DEFAULT_LANG)
+
         def DescTextArg(arg):
             arg = unicode(arg, LOCAL_ENCODING)
             vals = _splitArgs(arg)
             text = vals[1] if len(vals) > 1 else u""
             return (desc, text)
         KeyValueArg = DescTextArg
+
         def DescUrlArg(arg):
             desc, url = DescTextArg(arg)
             return (desc, url.encode("latin1"))
                 raise ValueError("No frame ID")
             text = vals[1] if len(vals) > 1 else u""
             return (fid, text)
+
         def UrlFrameArg(arg):
             fid, url = TextFrameArg(arg)
             return (fid, url.encode("latin1"))
 
         def DateArg(date_str):
             return core.Date.parse(date_str) if date_str else ""
+
         def CommentArg(arg):
             arg = unicode(arg, LOCAL_ENCODING)
             vals = _splitArgs(arg)
             desc = vals[1] if len(vals) > 1 else u""
             lang = vals[2] if len(vals) > 2 else id3.DEFAULT_LANG
             return (text, desc, str(lang)[:3])
+
         def LyricsArg(arg):
             text, desc, lang = CommentArg(arg)
             try:
             except:
                 raise ValueError("Unable to read file")
             return (unicode(data, LOCAL_ENCODING), desc, lang)
+
         def PlayCountArg(pc):
             if not pc:
                 raise ValueError("value required")
             if pc < 0:
                 raise ValueError("out of range")
             return (increment, pc)
+
         def BpmArg(bpm):
             bpm = int(float(bpm) + 0.5)
             if bpm <= 0:
                 raise ValueError("out of range")
             return bpm
+
         def DirArg(d):
             if not d:
                 raise ValueError()
             return d
+
         def ImageArg(s):
             '''PATH:TYPE[:DESCRIPTION]
             Returns (path, type_id, mime_type, description)'''
                 raise ValueError("too few parts")
 
             path, type_str = args[:2]
-            desc = args[2] if len(args) > 2 else u""
+            desc = unicode(args[2], LOCAL_ENCODING) if len(args) > 2 else u""
             mt = None
             try:
                 type_id = id3.frames.ImageFrame.stringToPicType(type_str)
 
             if not path:
                 raise ValueError("path required")
-            elif True in [path.startswith(prefix) for prefix in ["http://",
-                                                                 "https://",]]:
+            elif True in [path.startswith(prefix)
+                          for prefix in ["http://", "https://"]]:
                 mt = ImageFrame.URL_MIME_TYPE
             else:
                 if not os.path.isfile(path):
                     raise ValueError("Cannot determine mime-type")
 
             return (path, type_id, mt, desc)
+
         def ObjectArg(s):
             '''OBJ_PATH:MIME-TYPE[:DESCRIPTION[:FILENAME]],
             Returns (path, mime_type, description, filename)'''
             else:
                 raise ValueError("path required")
             return (path, mt, desc, filename)
+
         def UniqFileIdArg(arg):
             owner_id, id = KeyValueArg(arg)
             if not owner_id:
                 raise ValueError("owner_id required")
-            id = str(id) # don't want to pass unicocode
+            id = str(id)  # don't want to pass unicocode
             if len(id) > 64:
                 raise ValueError("id must be <= 64 bytes")
             return (owner_id, id)
+
         def PopularityArg(arg):
             '''EMAIL:RATING[:PLAY_COUNT]
             Returns (email, rating, play_count)'''
                           choices=_encodings, metavar='|'.join(_encodings),
                           help=ARGS_HELP["--encoding"])
 
-        # Misc options 
+        # Misc options
         gid4 = arg_parser.add_argument_group("Misc options")
         gid4.add_argument("--force-update", action="store_true", default=False,
                           dest="force_update", help=ARGS_HELP["--force-update"])
         if not self.audio_file:
             return
 
-        try:
-            self.printHeader(f)
-            printMsg("-" * 79)
+        self.printHeader(f)
+        printMsg("-" * 79)
 
-            new_tag = False
-            if (not self.audio_file.tag or
-                    self.handleRemoves(self.audio_file.tag)):
-                # No tag, but there might be edit options coming.
-                self.audio_file.tag = id3.Tag()
-                self.audio_file.tag.file_info = id3.FileInfo(f)
-                self.audio_file.tag.version = parse_version
-                new_tag = True
+        new_tag = False
+        if (not self.audio_file.tag or
+                self.handleRemoves(self.audio_file.tag)):
+            # No tag, but there might be edit options coming.
+            self.audio_file.tag = id3.Tag()
+            self.audio_file.tag.file_info = id3.FileInfo(f)
+            self.audio_file.tag.version = parse_version
+            new_tag = True
 
-            save_tag = (self.handleEdits(self.audio_file.tag) or
-                        self.args.force_update or self.args.convert_version)
+        save_tag = (self.handleEdits(self.audio_file.tag) or
+                    self.args.force_update or self.args.convert_version)
 
-            self.printAudioInfo(self.audio_file.info)
+        self.printAudioInfo(self.audio_file.info)
 
-            if not save_tag and new_tag:
-                printError("No ID3 %s tag found!" %
-                           id3.versionToString(self.args.tag_version))
-                return
+        if not save_tag and new_tag:
+            printError("No ID3 %s tag found!" %
+                       id3.versionToString(self.args.tag_version))
+            return
 
-            self.printTag(self.audio_file.tag)
+        self.printTag(self.audio_file.tag)
 
-            if save_tag:
-                # Use current tag version unless a convert was supplied
-                version = (self.args.convert_version or
-                           self.audio_file.tag.version)
-                printWarning("Writing ID3 version %s" %
-                             id3.versionToString(version))
+        if save_tag:
+            # Use current tag version unless a convert was supplied
+            version = (self.args.convert_version or
+                       self.audio_file.tag.version)
+            printWarning("Writing ID3 version %s" %
+                         id3.versionToString(version))
 
-                self.audio_file.tag.save(version=version,
-                                         encoding=self.args.text_encoding,
-                                         backup=self.args.backup)
+            self.audio_file.tag.save(version=version,
+                                     encoding=self.args.text_encoding,
+                                     backup=self.args.backup)
 
-            if self.args.rename_pattern:
-                # Handle file renaming.
-                from eyed3.id3.tag import TagTemplate
-                template = TagTemplate(self.args.rename_pattern)
-                name = template.substitute(self.audio_file.tag, zeropad=True)
-                orig = self.audio_file.path
+        if self.args.rename_pattern:
+            # Handle file renaming.
+            from eyed3.id3.tag import TagTemplate
+            template = TagTemplate(self.args.rename_pattern)
+            name = template.substitute(self.audio_file.tag, zeropad=True)
+            orig = self.audio_file.path
+            try:
                 self.audio_file.rename(name)
-                printWarning("Renamed '%s' to '%s'" % (orig,
-                                                       self.audio_file.path))
-            printMsg("-" * 79)
-        except exceptions.Exception as ex:
-            log.error(traceback.format_exc())
-            if self.args.debug_pdb:
-                import pdb; pdb.set_trace()
-            raise StopIteration()
+                printWarning("Renamed '%s' to '%s'" %
+                             (orig, self.audio_file.path))
+            except IOError as ex:
+                printError(ex.message)
+
+        printMsg("-" * 79)
 
     def printHeader(self, file_path):
         from stat import ST_SIZE
                     retval = True
                 else:
                     printError("Removing %s failed, %s not found" %
-                                 (what, str(vals)))
+                               (what, str(vals)))
 
         # --add-comment, --add-lyrics
         for what, arg, accessor in (("comment", self.args.comments,
         "--album": "Set the album name",
         "--title": "Set the track title",
         "--track": "Set the track number",
-        "--track-total":"Set total number of tracks",
+        "--track-total": "Set total number of tracks",
 
         "--genre": "Set the genre. If the argument is a standard ID3 genre "
                    "name or number both will be set. Otherwise, any string "

src/eyed3/utils/__init__.py

 #
 ################################################################################
 from __future__ import print_function
-import os, re
+import os
+import re
 
-import mimetypes, StringIO
+ID3_MIME_TYPE = "application/x-id3"
+ID3_MIME_TYPE_EXTENSIONS = (".id3", ".tag")
+
+import StringIO
+import mimetypes
 _mime_types = mimetypes.MimeTypes()
-_mime_types.readfp(StringIO.StringIO("application/x-id3 id3 tag"))
+_mime_types.readfp(StringIO.StringIO("%s %s" %
+                   (ID3_MIME_TYPE,
+                    " ".join((e[1:] for e in ID3_MIME_TYPE_EXTENSIONS)))))
 del mimetypes
 del StringIO
 
     import magic as magic_mod
     # Need to handle different versions of magic, as the new
     # APIs are totally different
-    if hasattr(magic_mod, open) and hasattr(magic_mod, load):
+    if hasattr(magic_mod, "open") and hasattr(magic_mod, "load"):
         # old magic
-        _magic = magic_mod.open(magic.MAGIC_SYMLINK | magic.MAGIC_MIME)
+        _magic = magic_mod.open(magic_mod.MAGIC_SYMLINK | magic_mod.MAGIC_MIME)
         _magic.load()
+
         def magic_func(path):
             return _magic.file(path)
     else:
         # new magic
         _magic = magic_mod.Magic(mime=True)
+
         def magic_func(path):
-            return _magic.from_file(path)
+            # If a unicode path is passed a conversion to ascii is attempted
+            # by from_file. Give the path encoded per LOCAL_FS_ENCODING
+            return _magic.from_file(path.encode(LOCAL_FS_ENCODING))
 except:
     magic_func = None
 
     mime = None
 
     if magic_func:
-        mime = magic_func(filename)
-        if mime:
-            mime = mime.split(";")[0]
+        if (os.path.splitext(filename)[1] in ID3_MIME_TYPE_EXTENSIONS):
+            # Need to check custom types manually if not using _mime_types
+            mime = ID3_MIME_TYPE
+        else:
+            mime = magic_func(filename)
+            if mime:
+                mime = mime.split(";")[0]
 
     if not mime:
         mime, enc = _mime_types.guess_type(filename, strict=False)
         '''Called when there are no more files to handle.'''
         pass
 
+
 def requireUnicode(*args):
     '''Function decorator to enforce unicode argument types.
     ``None`` is a valid argument value, in all cases, regardless of not being
     return "%.2f %s" % (sz, unit)
 
 
-##
-# \brief Format a timedelta object into a string
-# \param td The timedelta to represent.
 def formatTimeDelta(td):
+    '''Format a timedelta object ``td`` into a string. '''
     days = td.days
     hours = td.seconds / 3600
     mins = (td.seconds % 3600) / 60
         else:
             done = True
         del data
-

src/test/__init__.py

 #
 ################################################################################
 from StringIO import StringIO
-import os, logging, sys
+import os
+import sys
+import logging
 import eyed3
 
 DATA_D = os.path.join(os.path.abspath(os.path.curdir), "src", "test", "data")
                 s.seek(self._seek_offset)
         sys.stdout, sys.stderr = self._orig_stdout, self._orig_stderr
 
+#if sys.version_info[1] == 6:
+

src/test/id3/test_frames.py

                        UTF_16BE_ENCODING)
 from eyed3.id3 import ID3_V1_0, ID3_V1_1, ID3_V2_2, ID3_V2_3, ID3_V2_4
 from eyed3.id3.frames import *
+from ..compat import *
+
 
 class FrameTest(unittest.TestCase):
     def testCtor(self):

src/test/id3/test_headers.py

 from eyed3.utils.binfuncs import dec2bin, bin2bytes, bin2synchsafe
 from eyed3.id3.headers import *
 from eyed3.id3 import ID3_DEFAULT_VERSION, TagException
+from ..compat import *
+
 
 class TestTagHeader(unittest.TestCase):
     def testCtor(self):

src/test/id3/test_tag.py

 from eyed3.core import Date
 from eyed3.id3 import Tag, ID3_DEFAULT_VERSION, ID3_V2_3, ID3_V2_4
 from eyed3.id3 import frames
+from ..compat import *
+
 
 def testTagImport():
     import eyed3.id3, eyed3.id3.tag
         assert_equal(name, unicode(name))
         assert_equal(fi.tag_size, 0)
 
-    # FIXME Passing invalid unicode 
+    # FIXME Passing invalid unicode
 
 def testTagMainProps():
     tag = Tag()
     tag.user_url_frames.set("Foobazz", u"Desc2")
     assert_equal(len(tag.user_url_frames), 1)
 
+
 def testSortOrderConversions():
     test_file = "/tmp/soconvert.id3"
 

src/test/mp3/test_mp3.py

 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 ################################################################################
-import os, StringIO, unittest
+import sys
+if sys.version_info[:2] == (2, 6):
+    import unittest2 as unittest
+else:
+    import unittest
+import os
+import StringIO
 from nose.tools import *
 from .. import DATA_D
 

src/test/test__init__.py

 ################################################################################
 from nose.tools import *
 import eyed3
+from .compat import *
+
 
 def testLocale():
     assert_true(eyed3.LOCAL_ENCODING)

src/test/test_classic_plugin.py

 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 ################################################################################
-import unittest
+import sys
+if sys.version_info[:2] == (2, 6):
+    import unittest2 as unittest
+else:
+    import unittest
 import os, shutil
 from nose.tools import *
 import eyed3
 from eyed3 import main, id3, core
 from . import DATA_D, RedirectStdStreams
+from .compat import *
 
 def testPluginOption():
     for arg in ["--help", "-h"]:

src/test/test_plugins.py

 from nose.tools import *
 from eyed3.plugins import *
 from eyed3.plugins import examples, classic
+from .compat import *
+
 
 def test_load():
     plugins = load()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.