Commits

Travis Shirk committed 496342c Merge

merge

  • Participants
  • Parent commits f56378e, af0993c

Comments (0)

Files changed (25)

+5d718266a609aeead539cc5a83e64cf116ded9f8 v0.7.0-rc2
+2012-10-24  Travis Shirk  <travis@pobox.com>
+
+	* docs/installation.rst:
+	Actually, setuptools is required.
+	[20bf7e63858c] [tip] <stable>
+
+	* pavement.py:
+	Include doctools in paver-minilib
+	[a67bf8159d08] <stable>
+
+	* pavement.py, src/eyed3/binfuncs.py:
+	Merge
+	[f56378ec77cb]
+
+	* docs/conf.py:
+	cleanup conf.py
+	[5e584b2b799b] <stable>
+
+	* docs/api/eyed3.rst, docs/api/id3.rst, docs/api/mp3.rst,
+	docs/api/utils.rst, src/eyed3/__init__.py,
+	src/eyed3/id3/__init__.py, src/eyed3/mp3/__init__.py:
+	docs
+	[3a4403fa5d9b] <stable>
+
 2012-10-23  Travis Shirk  <travis@pobox.com>
 
+	* bin/cli_examples.sh, docs/plugins/classic_plugin.rst,
+	docs/plugins/genres_plugin.rst, docs/plugins/lameinfo_plugin.rst,
+	docs/plugins/mimetypes_plugin.rst, docs/plugins/nfo_plugin.rst,
+	pavement.py, src/eyed3/plugins/examples.py,
+	src/eyed3/plugins/lameinfo.py, src/eyed3/plugins/nfo.py,
+	src/eyed3/plugins/statistics.py:
+	moar
+	[68150f623406] <stable>
+
+	* bin/cli_examples.sh, docs/plugins/classic_plugin.rst, pavement.py:
+	Docs
+	[b47b0684ec47] <stable>
+
+	* src/eyed3/plugins/classic.py, src/test/test_classic_plugin.py:
+	More tests and fixes
+	[a6925bfbf119] <stable>
+
+	* .hgignore, src/eyed3/binfuncs.py, src/eyed3/id3/frames.py,
+	src/eyed3/id3/headers.py, src/eyed3/mp3/headers.py,
+	src/eyed3/utils/binfuncs.py, src/test/id3/test_headers.py,
+	src/test/test_binfuncs.py:
+	Moved binfuncs
+	[65d6dbf48ef0] <stable>
+
+	* docs/installation.rst:
+	Some typo fixes and 80 col formatting.
+	[90bef4b67f06] <stable>
+
+	* ChangeLog, fabfile.py:
+	release updates
+	[80baca26fee8] <stable>
+
 	* src/eyed3/main.py:
 	textwrapp --plugins output
-	[5be0db9dab8d] [tip] <stable>
+	[5be0db9dab8d] <stable>
 
 	* MANIFEST.in:
 	Fixed for deleted/moved files
 	merge
 	[ff8093ebe790]
 
-2012-10-21  Travis Shirk  <travis@pobox.com>
-
-	* docs/.static/.keepme, docs/.templates/.keepme, version:
-	merge
-	[dda949875e1b]
-
-2012-10-19  Travis Shirk  <travis@pobox.com>
-
-	* etc/config.ini:
-	Merge
-	[021084b35fea]
-
-2012-10-23  Travis Shirk  <travis@pobox.com>
-
 	* src/eyed3/id3/frames.py, src/eyed3/id3/tag.py,
 	src/eyed3/plugins/classic.py, src/eyed3/utils/__init__.py,
 	src/test/id3/test_tag.py:
 	Don't use sphinx directive in the README
 	[3ac7d6c500e3] <stable>
 
+	* docs/.static/.keepme, docs/.templates/.keepme, version:
+	merge
+	[dda949875e1b]
+
 	* README.rst:
 	Updated
 	[b8a5946e875c] <stable>
 	doc strings, exception consistency
 	[1aba2e98a7c1] <stable>
 
+	* etc/config.ini:
+	Merge
+	[021084b35fea]
+
 	* pavement.py, src/eyed3/id3/frames.py, src/eyed3/mp3/__init__.py:
 	fixesme
 	[334d88302bd4] <stable>
 
 2012-10-17  Travis Shirk  <travis@pobox.com>
 
-	* version:
-	Merged stable
-	[7f1db4ea1938]
-
 	* src/eyed3/utils/cli.py:
 	ANSI goodness
 	[dffb203bbfbe] <stable>
 
 	* version:
-	Bumped
-	[99beb1a0d1c1]
+	Merged stable
+	[7f1db4ea1938]
 
 	* ChangeLog, pavement.py:
 	tests as part of test_dist again.
 	[5c80cfe0d01b] <stable>
 
 	* version:
+	Bumped
+	[99beb1a0d1c1]
+
+	* version:
 	bumped
 	[1ec9ad51e368] <stable>
 
 	merge
 	[7ece6c0c6760]
 
+	* doc/index.rst:
+	Reference vor ID3 v1.x spec.
+	[373d3c2c84b0]
+
 	* doc/cli.rst, doc/index.rst, doc/intro.rst:
 	rethinking docs
 	[1f665b7f7f0e]
 
-	* doc/index.rst:
-	Reference vor ID3 v1.x spec.
-	[373d3c2c84b0]
-
 	* src/eyed3/plugins/default.py, src/test/test_default_plugin.py:
 	Testing thru all the supported versions for writes, etc.
 	[6cf2543aa8a9]
 	merged and added test
 	[666da119c766]
 
-	* src/eyed3/utils/__init__.py:
-	Typo fix, closes issue #1
-	[c325e902ec8e]
-
 	* src/test/__init__.py, src/test/test_main.py, src/test/test_utils.py:
 	Some tests
 	[26bf7cf7f37e]
 	clean of 'dist' directory (setup.py artifact)
 	[223becbd786b]
 
+2012-10-02  Travis Shirk  <travis@pobox.com>
+
+	* src/eyed3/utils/__init__.py:
+	Typo fix, closes issue #1
+	[c325e902ec8e]
+
 2012-09-27  Travis Shirk  <travis@pobox.com>
 
 	* src/eyed3/id3/frames.py:

File bin/cli_examples.sh

 # [[[section REMOVE_ALL_TAGS]]]
 eyeD3 --remove-all example.id3
 # [[[endsection]]]
+
+# [[[section GENRES_PLUGIN1]]]
+eyeD3 --plugin=genres
+# [[[endsection]]]
+
+# [[[section LAME_PLUGIN]]]
+eyeD3 -P lameinfo src/test/data/notag-vbr.mp3
+# [[[endsection]]]

File docs/api/eyed3.rst

-============
-eyeD3 Module
-============
+=====
+eyed3
+=====
 
 .. automodule:: eyed3
     :members:

File docs/api/id3.rst

-================
-eyed3.id3 Module
-================
+=========
+eyed3.id3
+=========
 
 .. automodule:: eyed3.id3
     :members:
     :undoc-members:
 
+eyed3.id3.tag
+=============
+
 .. automodule:: eyed3.id3.tag
     :members:
     :undoc-members:
 
+eyed3.id3.headers
+=================
+
+.. automodule:: eyed3.id3.headers
+    :members:
+    :undoc-members:
+

File docs/api/mp3.rst

 
-================
-eyed3.mp3 Module
-================
+=========
+eyed3.mp3
+=========
 
 .. automodule:: eyed3.mp3
     :members:
     :undoc-members:
+
+eyed3.mp3.headers
+=================
+
+.. automodule:: eyed3.mp3.headers
+    :members:
+    :undoc-members:

File docs/api/utils.rst

 
-================
-eyed3.utils Module
-================
+===========
+eyed3.utils
+===========
 
 .. automodule:: eyed3.utils
     :members:
     :undoc-members:
+
+eyed3.utils.log
+===============
+
+.. automodule:: eyed3.utils.log
+    :members:
+    :undoc-members:
+
+
+eyed3.utils.cli
+===============
+
+.. automodule:: eyed3.utils.cli
+    :members:
+    :undoc-members:
+
+eyed3.utils.binfuncs
+====================
+
+.. automodule:: eyed3.utils.binfuncs
+    :members:
+    :undoc-members:

File docs/conf.py

 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
-version, release = pavement.VERSION.split("-")
+if '-' in pavement.VERSION:
+    version, release = pavement.VERSION.split('-')
+else:
+    version, release = pavement.VERSION, "final"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
-#html_title = None
+html_title = "%s v%s%s" % (project, version,
+                           " (%s)" % release if release else "")
 
 # A shorter title for the navigation bar.  Default is the same as html_title.
 #html_short_title = None
 
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-  ('index', 'eyeD3.tex', u'eyeD3 Documentation',
-   u'Travis Shirk', 'manual'),
-]
+#latex_documents = [
+#  ('index', 'eyeD3.tex', u'eyeD3 Documentation',
+#   u'Travis Shirk', 'manual'),
+#]
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
 # Grouping the document tree into Texinfo files. List of tuples
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
-texinfo_documents = [
-  ('index', 'eyeD3', u'eyeD3 Documentation',
-   u'Travis Shirk', 'eyeD3', 'One line description of project.',
-   'Miscellaneous'),
-]
+#texinfo_documents = [
+#  ('index', 'eyeD3', u'eyeD3 Documentation',
+#   u'Travis Shirk', 'eyeD3', 'One line description of project.',
+#   'Miscellaneous'),
+#]
 
 # Documents to append as an appendix to all manuals.
 #texinfo_appendices = []

File docs/installation.rst

 since 2.7 version provides the best migration path to supporting Python3.
 
 The primary interface for building and installing is `Setuptools`_. For
-example, ``python setup.py install``. This is an illusion though,
-``setuptools`` is *NOT* required because `Paver`_ is used instead and it
-provides the common ``setup.py`` interface that everyone knows and loves. In
-addition, ``Paver`` itself is not required for building/installing, only when
-doing development on eyeD3 itself.
+example, ``python setup.py install``. 
 
-eyeD3 has NO hard dependencies other than Python itself but it may take
+eyeD3 has NO hard dependencies other than Python and setuptools but it may take
 advantage of other packages if they are available.
 
 .. _setuptools: http://pypi.python.org/pypi/setuptools

File docs/plugins/classic_plugin.rst

 Notice how the genre displayed as "Hardcore (id 129)" in the above tag listing.
 This happens because the genre is a recognized value as defined by the ID3 v1
 standard. eyeD3 used to be very strict about genres, but no longer. You can
-store any value you'd like.
+store any value you'd like. For a list of recognized genres and their
+respective IDs see the `genres plugin <genres_plugin.html>`_.
 
 TODO: reference genres plubin
 
 the tag itself. Let's try that now.
 
 .. code-block:: bash
+
   $ eyeD3 --add-image http://example.com/cover.jpg:FRONT_COVER
   eyeD3: error: argument --add-image: invalid ImageArg value: 'http://example.com/cover.jpg:FRONT_COVER'
 

File docs/plugins/genres_plugin.rst

 .. cog.out(cog_pluginHelp("genres"))
 .. }}}
 .. {{{end}}}
+
+Example
+-------
+
+.. {{{cog cli_example("bin/cli_examples.sh", "GENRES_PLUGIN1", lang="bash") }}}
+.. {{{end}}}

File docs/plugins/lameinfo_plugin.rst

 .. cog.out(cog_pluginHelp("lameinfo"))
 .. }}}
 .. {{{end}}}
+
+Example
+-------
+
+.. {{{cog cli_example("bin/cli_examples.sh", "LAME_PLUGIN", lang="bash") }}}
+.. {{{end}}}

File docs/plugins/mimetypes_plugin.rst

 .. }}}
 .. {{{end}}}
 
+Example
+-------
+
+.. code-block:: bash
+
+  $ eyeD3 -P mt /home/travis/music/ 2> /dev/null
+
+  28575 files checked
+  Mime-types:
+  None                :       1 (%0.00)
+  application/pdf     :       2 (%0.01)
+  application/x-trash :       7 (%0.02)
+  audio/mpeg          :   27559 (%96.44)
+  image/gif           :       7 (%0.02)
+  image/jpeg          :     982 (%3.44)
+  image/png           :      16 (%0.06)
+  text/plain          :       1 (%0.00)

File docs/plugins/nfo_plugin.rst

 .. cog.out(cog_pluginHelp("nfo"))
 .. }}}
 .. {{{end}}}
+
+Example
+-------
+
+.. code-block:: bash
+
+  $ eyeD3 -P nfo ~/music/Nine\ Inch\ Nails/1992\ -\ Broken/
+
+  Artist   : Nine Inch Nails
+  Album    : Broken
+  Released : 1992
+  Genre    : Noise
+  
+  Source  : 
+  Encoder : LAME3.95
+  Codec   : mp3
+  Bitrate : ~167 K/s @ 44100 Hz, Joint stereo
+  Tag     : ID3 v2.3
+
+  Ripped By: 
+
+  Track Listing
+  -------------
+   1. Pinion                 (01:02)
+   2. Wish                   (03:46)
+   3. Last                   (04:44)
+   4. Help Me I am in Hell   (01:56)
+   5. Happiness in Slavery   (05:21)
+   6. Gave Up                (04:08)
+   7. Physical (You're So)   (05:29)
+   8. Suck                   (05:07)
+
+  Total play time : 31:33
+  Total size      : 37.74 MB
+
+  ==============================================================================
+  .NFO file created with eyeD3 0.7.0 on Tue Oct 23 23:44:27 2012
+  For more information about eyeD3 go to http://eyeD3.nicfit.net/
+  ==============================================================================
+
 PROJECT = u"eyeD3"
 VERSION = "0.8.0-alpha"
 
-LICENSE = open("COPYING", "r").read().strip('\n')
+LICENSE     = open("COPYING", "r").read().strip('\n')
 DESCRIPTION = "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",
                                                   )
 
 options(
+    minilib=Bunch(
+        extra_files=['doctools']
+    ),
     setup=Bunch(
         name=PROJECT, version=VERSION,
         description=DESCRIPTION, long_description=LONG_DESCRIPTION,
         src_data = re.sub("@VERSION@", VERSION.split('-')[0], src_data)
         src_data = re.sub("@AUTHOR@", AUTHOR, src_data)
         src_data = re.sub("@URL@", URL, src_data)
-        src_data = re.sub("@RELEASE@", VERSION.split('-')[1], src_data)
+        if '-' in VERSION:
+            src_data = re.sub("@RELEASE@", VERSION.split('-')[1], src_data)
+        else:
+            src_data = re.sub("@RELEASE@", "final", src_data)
 
         target_file.write(src_data)
         target_file.close()
 @needs("eyed3_info",
        "generate_setup",
        "minilib",
-       "distclean", # get rid of .pyc that docs (i.e. cog) made
+       "distclean", # get rid of .pyc and docs (i.e. cog) made
        "setuptools.command.sdist",
        )
 def sdist(options):
 
 
 @task
-@needs("distclean", "test_dist", "docdist", "changelog")
+@needs("changelog",
+       "distclean",
+       "sdist", "test_dist", "docdist")
 def release():
     checklist()
 
 Release Procedure
 =================
 
+# Build
 - hg up stable
+- paver test
 - clean working copy / use sandbox
 - Set version in ``pavement.py``
 - Update doc/changelog.rst with date, features, etc.
-- paver release uncog
+- paver release
 - hg tag v%(VERSION)s
 - hg commit -m 'prep for release'
+- hg nudge
 
-# Merge to default
-- hg up default
-- hg merge stable
-
+# Publish
 - Update eyeD3.nicfit.net
   fab -H melvins.nicfit.net:222 deploy
 - Announce to mailing list
 - Announce to FreshMeat
 - Upload to Python Index (paver upload?)
 
+# Merge to default
+- hg up default
+- hg merge stable
+
 - ebuild
 """ % globals())
 
+@task
+def release2():
+    # Ensure we're on stable branch
+    sh("test $(hg branch) = 'stable'")
+
 def cog_pluginHelp(name):
     from string import Template
     import argparse
     if buffer.strip():
         substs["options"] = buffer
     else:
-        substs["options"] = u"None"
+        substs["options"] = u"  No extra options supported"
 
     return template.substitute(substs)
 __builtins__["cog_pluginHelp"] = cog_pluginHelp

File src/eyed3/__init__.py

 _DEFAULT_ENCODING = "latin1"
 
 LOCAL_ENCODING = locale.getpreferredencoding(do_setlocale=True)
-'''The local encoding, default is latin1 if it cannot be determined. The value
-shown in the documenation is NOT the default value, rather it is the computed
-value on the document server.'''
+'''The local encoding, used when parsing command line options, console output,
+etc. The default is always ``latin1`` if it cannot be determined, it is NOT
+the value shown.'''
 if not LOCAL_ENCODING or LOCAL_ENCODING == "ANSI_X3.4-1968":  # pragma: no cover
     LOCAL_ENCODING = _DEFAULT_ENCODING
 
 LOCAL_FS_ENCODING = sys.getfilesystemencoding()
-'''The local file system encoding, default is latin1 if it cannot be determined.
-'''
+'''The local file system encoding, the default is ``latin1`` if it cannot be
+determined.'''
 if not LOCAL_FS_ENCODING:  # pragma: no cover
     LOCAL_FS_ENCODING = _DEFAULT_ENCODING
 
     and raises a ``eyed3.Exception`` otherwise. ``version_spec`` may be a string
     or int tuple. In either case at least **2** version values must be
     specified. For example, "0.7", (0,7,1), etc.
+
+    API compatibility is currently based on major and minor version values,
+    therefore neither version 0.6 or 0.8 is compatible for version 0.7.
     '''
     import types
     from .info import VERSION_TUPLE as CURRENT_VERSION

File src/eyed3/id3/__init__.py

 
 # Version constants and helpers
 ID3_V1              = (1, None, None)
+'''Version 1, 1.0 or 1.1'''
 ID3_V1_0            = (1, 0, 0)
+'''Version 1.0, specifically'''
 ID3_V1_1            = (1, 1, 0)
+'''Version 1.1, specifically'''
 ID3_V2              = (2, None, None)
+'''Version 2, 2.2, 2.3 or 2.4'''
 ID3_V2_2            = (2, 2, 0)
+'''Version 2.2, specifically'''
 ID3_V2_3            = (2, 3, 0)
+'''Version 2.3, specifically'''
 ID3_V2_4            = (2, 4, 0)
+'''Version 2.4, specifically'''
 ID3_DEFAULT_VERSION = ID3_V2_4
+'''The default version for eyeD3 tags and save operations.'''
 ID3_ANY_VERSION     = (ID3_V1[0] | ID3_V2[0], None, None)
+'''Useful for operations where any version will suffice.'''
 
 LATIN1_ENCODING   = b"\x00"
+'''Byte code for latin1'''
 UTF_16_ENCODING   = b"\x01"
+'''Byte code for UTF-16'''
 UTF_16BE_ENCODING = b"\x02"
+'''Byte code for UTF-16 (big endian)'''
 UTF_8_ENCODING    = b"\x03"
+'''Byte code for UTF-8 (Not supported in ID3 versions < 2.4)'''
 
 DEFAULT_LANG = "eng"
+'''Default language code for frames that contain a language portion.'''
 
 def isValidVersion(v, fully_qualified=False):
+    '''Check the tuple ``v`` against the list of valid ID3 version constants.
+    If ``fully_qualified`` is ``True`` it is enforced that there are 3
+    components to the version in ``v``. Returns ``True`` when valid and
+    ``False`` otherwise.'''
     valid = v in [ID3_V1, ID3_V1_0, ID3_V1_1,
                   ID3_V2, ID3_V2_2, ID3_V2_3, ID3_V2_4,
                   ID3_ANY_VERSION]
 
 
 def normalizeVersion(v):
+    '''If version tuple ``v`` is of the non-specific type (v1 or v2, any, etc.)
+    a fully qualified version is returned.'''
     if v == ID3_V1:
         v = ID3_V1_1
     elif v == ID3_V2:
 
 ## Convert an ID3 version constant to a display string
 def versionToString(v):
+    '''Conversion version tuple ``v`` to a string description.'''
     if v == ID3_ANY_VERSION:
        return "v1.x/v2.x"
     elif v[0] == 1:
 
 from .. import Exception as BaseException
 class GenreException(BaseException):
-    '''Problem looking up genre'''
+    '''Excpetion type for exceptions related to genres.'''
 
-##
-# A class containing genre information including the name and/or a numeric ID.
 class Genre(object):
+    '''FIXME'''
 
     @requireUnicode("name")
     def __init__(self, name=None, id=None):
+        '''FIXME'''
         self.id, self.name = None, None
         if not name and id is None:
             return
 
     @property
     def id(self):
+        '''The Genre's id property.
+        When setting the value is strictly enforced and if the value is not
+        a valid genre code a ``ValueError`` is raised. Otherwise the id is
+        set **and** the ``name`` property is updated to the code's string
+        name.
+        '''
         return self._id
 
-    ##
-    # Sets the genre id. The object'ss name field is set to the corresponding
-    # value obtained from eyeD3.id3.genres.
-    #
-    # \param id The genre ID.
-    # \throws GenreException when \a id does not map to a valid ID3 genre.
     @id.setter
     def id(self, val):
         global genres
 
     @property
     def name(self):
+        '''The Genre's name property.
+        When setting the value the name is looked up in the standard genre
+        map and if found the ``id`` ppropery is set to the numeric valud **and**
+        the name is normalized to the sting found in the map. Non standard
+        genres are set (with a warning log) and the ``id`` is set to ``None``.
+        It is valid to set the value to ``None``.
+        '''
         return self._name
 
-    ##
-    # Sets the genre name. The object'ss id field is set to the corresponding
-    # value obtained from \c eyeD3.id3.genres.
-    #
-    # Throws GenreException when name does not map to a valid ID3 v1.1. name.
-    # This behavior can be disabled by passing 0 as the second argument.
     @name.setter
     @requireUnicode(1)
     def name(self, val):
     WINAMP_GENRE_MAX = 147
 
     def __init__(self, *args):
+        '''FIXME'''
         global ID3_GENRES
         super(GenreMap, self).__init__(*args)
 
             key = key.lower()
         return super(GenreMap, self).__getitem__(key)
 
+
 from .. import core
 class TagFile(core.AudioFile):
     '''
 u'Synthpop',
 u'Rock/Pop',
 ]
+'''ID3 genres, as defined in ID3 v1. The position in the list is the genre's
+numeric byte value.'''
 
 from .tag import Tag, FileInfo, TagException, TagTemplate
 genres = GenreMap()
+'''FIXME: where is this used??? All CAPS, constant? meant to be extended?'''
 
 from . import frames

File src/eyed3/mp3/__init__.py

 MIME_TYPES = ["audio/mpeg", "audio/mp3", "audio/x-mp3", "audio/x-mpeg",
               "audio/mpeg3", "audio/x-mpeg3", "audio/mpg", "audio/x-mpg",
               "audio/x-mpegaudio"]
+'''Mime-types that are recognized at MP3'''
 
 def isMp3File(file_name):
+    '''Does a mime-type check on ``file_name`` and returns ``True`` it the
+    file is mp3, and ``False`` otherwise.'''
     return utils.guessMimetype(file_name) in MIME_TYPES
 
 class Mp3AudioInfo(core.AudioInfo):
         self.xing_header = None
         self.vbri_header = None
         self.lame_tag = None
-        # 2-tuple, (vbr:boolean, bitrate:int)
+        '''If not ``None``, the Lame header.
+        See :class:`eyed3.mp3.headers.LameHeader`'''
         self.bit_rate = (None, None)
+        '''2-tuple, (vrb?:boolean, bitrate:int)'''
 
         while self.mp3_header is None:
             # Find first mp3 header

File src/eyed3/plugins/classic.py

         def UnicodeArg(arg):
             return unicode(arg, LOCAL_ENCODING)
         def PositiveIntArg(i):
-            if i in (None, ''):
-                return None
             i = int(i)
             if i < 0:
                 raise ValueError("positive number required")

File src/eyed3/plugins/examples.py

 
 
 class MimeTypesPlugin(Plugin):
-    SUMMARY = u"Displays the mime-type for each file encountered"
     NAMES = ["mimetypes", "mt"]
+    SUMMARY = u"Displays the mime-type for each file scanned."
 
     def __init__(self, arg_parser):
         self.mts = {}
 
 class GenreListPlugin(Plugin):
     SUMMARY = u"Display the full list of standard ID3 genres."
+    DESCRIPTION = u"ID3 v1 defined a list of genres and mapped them to "\
+                   "to numeric values so they can be stored as a single "\
+                   "byte. It is *recommended* that these genres are used "\
+                   "although most newer software (including eyeD3) does not "\
+                   "care."
     NAMES = ["genres"]
 
     def start(self, args, config):

File src/eyed3/plugins/lameinfo.py

 class LameInfoPlugin(LoaderPlugin):
     NAMES = ["lameinfo", "xing"]
     SUMMARY = u"Outputs lame header (if one exists) for file."
+    DESCRIPTION = (
+        u"The 'lame' (or xing) header provides extra information about the mp3 "
+         "that is useful to players and encoders but not officially part of "
+         "the mp3 specification. Variable bit rate mp3s, for example, use this "
+         "header.\n\n"
+         "For more details see "
+         "`here <http://gabriel.mp3-tech.org/mp3infotag.html>`_"
+         )
 
     def printHeader(self, filePath):
         from stat import ST_SIZE

File src/eyed3/plugins/nfo.py

 
 class NfoPlugin(LoaderPlugin):
     NAMES = ["nfo"]
-    SUMMARY = u"Outputs an NFO description for each album processed. " \
-               "(http://en.wikipedia.org/wiki/.nfo)"
+    SUMMARY = u"Create NFO files for each directory scanned."
+    DESCRIPTION = u"Each directory scanned is treated as an album and a "\
+                   "`NFO <http://en.wikipedia.org/wiki/.nfo>`_ file is "\
+                   "written to standard out.\n\n"\
+                   "NFO files are often found in music archives."
 
     def __init__(self, arg_parser):
         super(NfoPlugin, self).__init__(arg_parser)

File src/eyed3/plugins/statistics.py

 
 class StatisticsPlugin(LoaderPlugin):
     NAMES = ['stats']
-    SUMMARY = u"Computes statistics for all audio file and tags "\
-               "encountered. For example, ID3 version, bitrate info, etc."
+    SUMMARY = u"Computes statistics for all audio files scanned."
 
     def __init__(self, arg_parser):
         super(StatisticsPlugin, self).__init__(arg_parser)

File src/test/id3/test_frames.py

         # Comparison is on each member, not reference ID
         assert_equal(df.date, dt)
 
+    # Invalid dates
+    for d in [b"1234:12"]:
+        date = DateFrame("TDRL")
+        date.date = d
+        assert_false(date.date)
 
+        try:
+            date.date = 9
+        except TypeError:
+            pass
+        else:
+            assert_false("TypeError not thrown")
+
+
+
+def test_compression():
+    data = open(__file__).read()
+    compressed = Frame.compress(data)
+    assert_equal(data, Frame.decompress(compressed))
+
+def test_encryption():
+    assert_raises(NotImplementedError, Frame.encrypt, "Iceburn")
+    assert_raises(NotImplementedError, Frame.decrypt, "Iceburn")
+

File src/test/test_classic_plugin.py

             assert_is_not_none(af.tag)
             assert_equal(af.tag.track_num[0], 14)
 
+    def testNewTagTrackNumInvalid(self):
+        for opts in [ ["-n", "abc", self.test_file],
+                      ["--track=-14", self.test_file]
+                      ]:
+
+            with RedirectStdStreams() as out:
+                try:
+                    args, _, config = main.parseCommandLine(opts)
+                except SystemExit as ex:
+                    assert_not_equal(ex.code, 0)
+                else:
+                    assert_false("Should not have gotten here")
+
     def testNewTagTrackTotal(self, version=id3.ID3_DEFAULT_VERSION):
         if version[0] == 1:
             # No support for this in v1.x