[Python-modules-commits] [mutagen] 01/07: Import mutagen_1.32.orig.tar.gz

Tristan Seligmann mithrandi at moszumanska.debian.org
Sun May 22 07:45:46 UTC 2016


This is an automated email from the git hooks/post-receive script.

mithrandi pushed a commit to branch master
in repository mutagen.

commit d51dc5c78e408c3c152d4625a64d1c0ea6ff2bb1
Author: Tristan Seligmann <mithrandi at debian.org>
Date:   Sun May 22 04:25:06 2016 +0200

    Import mutagen_1.32.orig.tar.gz
---
 NEWS                           |  25 ++++-
 PKG-INFO                       |   4 +-
 README.rst                     |  58 +-----------
 docs/Makefile                  |  12 +--
 docs/api/base.rst              |   5 +
 docs/api/index.rst             |   2 +-
 docs/api/smf.rst               |  11 +++
 docs/conf.py                   |   8 +-
 docs/contact.rst               |  10 ++
 docs/ext.py                    |  10 +-
 docs/index.rst                 |  67 ++++++--------
 docs/man/index.rst             |  27 +++++-
 docs/tutorial.rst              |   2 +-
 mutagen/__init__.py            |   6 +-
 mutagen/_file.py               |   8 +-
 mutagen/_tags.py               |  33 ++++++-
 mutagen/_vorbis.py             |   2 +-
 mutagen/asf/__init__.py        |   4 +-
 mutagen/asf/_objects.py        |  29 +++++-
 mutagen/easymp4.py             |   4 +-
 mutagen/flac.py                |   6 +-
 mutagen/id3/__init__.py        |  12 +--
 mutagen/id3/_frames.py         |  45 ++++++---
 mutagen/id3/_specs.py          |  17 +++-
 mutagen/m4a.py                 |   4 +-
 mutagen/mp4/__init__.py        |  79 +++++++++-------
 mutagen/smf.py                 | 203 +++++++++++++++++++++++++++++++++++++++++
 setup.py                       |   2 +-
 tests/data/sample.mid          | Bin 0 -> 8444 bytes
 tests/quality/test_pep8.py     |   2 +-
 tests/quality/test_pyflakes.py |   3 +-
 tests/test___init__.py         |   4 +
 tests/test__id3frames.py       |  36 +++++++-
 tests/test__id3specs.py        |   9 +-
 tests/test_aiff.py             |   2 +
 tests/test_apev2.py            |   4 +-
 tests/test_asf.py              |  22 ++++-
 tests/test_easyid3.py          |   4 +-
 tests/test_flac.py             |   4 +-
 tests/test_id3.py              |  53 ++++++-----
 tests/test_mp3.py              |   2 +-
 tests/test_mp4.py              |  17 ++--
 tests/test_musepack.py         |   2 +-
 tests/test_ogg.py              |   2 +-
 tests/test_smf.py              |  27 ++++++
 45 files changed, 643 insertions(+), 245 deletions(-)

diff --git a/NEWS b/NEWS
index 99faafc..cb4960a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,22 @@
+1.32 - 2016.05.02
+-----------------
+
+* Add basic SMF (Standard MIDI File) support (:mod:`mutagen.smf`)
+* FLAC: add ``audio/flac`` mime type. :bug:`235`
+* ASF: Fixed crash when object size is longer than the header and file length
+  (Ben Ockmore)
+* ID3: Validate attributes set after frame creation :bb-pr:`8`
+  (Daniel Plachotich)
+* MP4: validate values in ``__setitem__`` so things don't fail in save()
+  :bug:`236`
+* tests: Fix SynchronizedTextSpec test on big-endian machines :bug:`247`
+  (Daniel Plachotich)
+* ID3: do type checking in ``__setitem__`` :bug:`251`
+* Building the documentation now requires sphinx >= 1.3
+* New :class:`mutagen.Tags` base class for tags
+* Moved from Bitbucket to GitHub
+
+
 1.31 - 2015.09.10
 -----------------
 
@@ -96,7 +115,7 @@
 * MP4:
 
   * New ``MP4Info.codec`` for identifying the contained audio codec
-    e.g. ``"mp4a"``, ``"alac"``, ``"mp4a.40.2"``, ``"ac-3"`` etc. :pr:`6`
+    e.g. ``"mp4a"``, ``"alac"``, ``"mp4a.40.2"``, ``"ac-3"`` etc. :bb-pr:`6`
   * New ``MP4Info.codec_description``: name of the audio codec
     e.g. ``"ALAC"``, ``"AAC LC"``, ``"AC-3"``
 
@@ -117,7 +136,7 @@
 * MP4:
 
   * Parse channels/sample_rate/bits_per_sample/bitrate for ALAC files
-    :bug:`199` :pr:`5` (Adrian Sampson, Christoph Reiter)
+    :bug:`199` :bb-pr:`5` (Adrian Sampson, Christoph Reiter)
 
 * ASF:
 
@@ -132,7 +151,7 @@
 
 * docs:
 
-  * New logo :pr:`4` (Samuel Messner)
+  * New logo :bb-pr:`4` (Samuel Messner)
   * Add examples for handling cover art in vorbiscomment :bug:`200`
   * Add examples for id3v2.3
 
diff --git a/PKG-INFO b/PKG-INFO
index 306b01c..4594950 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: mutagen
-Version: 1.31
+Version: 1.32
 Summary: read and write audio tags for many formats
-Home-page: https://bitbucket.org/lazka/mutagen
+Home-page: https://github.com/quodlibet/mutagen
 Author: Michael Urman
 Author-email: quod-libet-development at groups.google.com
 License: GNU GPL v2
diff --git a/README.rst b/README.rst
index 7ea1b21..1affc6a 100644
--- a/README.rst
+++ b/README.rst
@@ -1,58 +1,8 @@
 Mutagen
 =======
 
-Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC, 
-M4A, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg 
-Theora, Ogg Vorbis, True Audio, WavPack, OptimFROG, and AIFF audio files. 
-All versions of ID3v2 are supported, and all standard ID3v2.4 frames are 
-parsed. It can read Xing headers to accurately calculate the bitrate and 
-length of MP3s. ID3 and APEv2 tags can be edited regardless of audio 
-format. It can also manipulate Ogg streams on an individual packet/page 
-level.
+Mutagen is a Python module to handle audio metadata. For more information
+visit http://mutagen.readthedocs.org
 
-Mutagen works on Python 2.6, 2.7, 3.3, 3.4 (CPython and PyPy) and has no 
-dependencies outside the Python standard library.
-
-
-Installing
-----------
-
- $ ./setup.py build
- $ su -c "./setup.py install"
-
-
-Documentation
--------------
-
-The primary documentation for Mutagen is the doc strings found in
-the source code and the sphinx documentation in the docs/ directory.
-
-To build the docs (needs sphinx):
-
- $ ./setup.py build_sphinx
-
-The tools/ directory contains several useful examples.
-
-The docs are also hosted on readthedocs.org:
-
- http://mutagen.readthedocs.org
-
-
-Testing the Module
-------------------
-
-To test Mutagen's MP3 reading support, run
- $ tools/mutagen-pony <your top-level MP3 directory here>
-Mutagen will try to load all of them, and report any errors.
-
-To look at the tags in files, run
- $ tools/mutagen-inspect filename ...
-
-To run our test suite,
- $ ./setup.py test
-
-
-Compatibility/Bugs
-------------------
-
-See docs/bugs.rst
+.. image:: https://travis-ci.org/quodlibet/mutagen.svg?branch=master
+    :target: https://travis-ci.org/quodlibet/mutagen
diff --git a/docs/Makefile b/docs/Makefile
index 473139b..3720e52 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,13 +1,7 @@
-all: _rtd_theme
-	sphinx-build -E -Dhtml_theme=_rtd_theme -Dhtml_theme_path=. -b html -n . _build
+all:
+	sphinx-build -E -b html -n . _build
 
 clean:
-	rm -rf _build _rtd_theme
+	rm -rf _build
 
 .PHONY: clean
-
-_rtd_theme:
-	wget https://github.com/snide/sphinx_rtd_theme/archive/master.tar.gz
-	tar --strip-components=1 -zxvf master.tar.gz sphinx_rtd_theme-master/sphinx_rtd_theme
-	mv sphinx_rtd_theme _rtd_theme
-	rm master.tar.gz
diff --git a/docs/api/base.rst b/docs/api/base.rst
index b714f81..b7f9cb7 100644
--- a/docs/api/base.rst
+++ b/docs/api/base.rst
@@ -23,6 +23,11 @@ Base Classes
     .. automethod:: save()
 
 
+.. autoclass:: mutagen.Tags
+
+    .. automethod:: pprint()
+
+
 .. autoclass:: mutagen.Metadata
 
     .. automethod:: delete()
diff --git a/docs/api/index.rst b/docs/api/index.rst
index d98368d..c4a0976 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -21,7 +21,7 @@ API
     oggtheora
     oggvorbis
     optimfrog
+    smf
     trueaudio
     vcomment
     wavpack
-
diff --git a/docs/api/smf.rst b/docs/api/smf.rst
new file mode 100644
index 0000000..6abd86c
--- /dev/null
+++ b/docs/api/smf.rst
@@ -0,0 +1,11 @@
+Standard MIDI File
+==================
+
+.. automodule:: mutagen.smf
+
+.. autoclass:: mutagen.smf.SMF(filename)
+    :show-inheritance:
+    :members:
+
+.. autoclass:: mutagen.smf.SMFInfo()
+    :members:
diff --git a/docs/conf.py b/docs/conf.py
index 10ceb0d..554fab6 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -8,6 +8,7 @@ sys.path.insert(0, dir_)
 sys.path.insert(0, os.path.abspath(os.path.join(dir_, "..")))
 import mutagen
 
+needs_sphinx = "1.3"
 
 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'ext']
 intersphinx_mapping = {'python': ('http://docs.python.org/2.7', None)}
@@ -19,8 +20,11 @@ copyright = u'2014, Joe Wreschnig, Michael Urman, Lukáš Lalinský, ' \
 version = mutagen.version_string
 release = mutagen.version_string
 exclude_patterns = ['_build']
-bug_url_template = "http://bitbucket.org/lazka/mutagen/issue/%s"
-pr_url_template = "http://bitbucket.org/lazka/mutagen/pull-request/%s"
+bug_url_template = "https://github.com/quodlibet/mutagen/issues/%s"
+pr_url_template = "https://github.com/quodlibet/mutagen/pull/%s"
+bbpr_url_template = "https://bitbucket.org/lazka/mutagen/pull-requests/%s"
 
 autodoc_member_order = "bysource"
 default_role = "obj"
+
+html_theme = "sphinx_rtd_theme"
diff --git a/docs/contact.rst b/docs/contact.rst
new file mode 100644
index 0000000..25931ca
--- /dev/null
+++ b/docs/contact.rst
@@ -0,0 +1,10 @@
+Contact
+-------
+
+For historical and practical reasons, Mutagen shares a `mailing list
+<http://groups.google.com/group/quod-libet-development/>`_ and IRC channel
+(#quodlibet on irc.oftc.net) with Quod Libet.
+
+If you need help using Mutagen or would like to discuss the library, please
+use the mailing list or the `issue tracker
+<https://github.com/quodlibet/mutagen/issues>`_.
diff --git a/docs/ext.py b/docs/ext.py
index 397bc1d..8949d62 100644
--- a/docs/ext.py
+++ b/docs/ext.py
@@ -15,10 +15,14 @@ def bug_role(name, rawtext, text, lineno, inliner, *args, **kwargs):
 
 def pr_role(name, rawtext, text, lineno, inliner, *args, **kwargs):
     app = inliner.document.settings.env.app
-    url_tmpl = app.config.pr_url_template or "missing/%s"
+    if name == "pr":
+        url_tmpl = app.config.pr_url_template
+    else:
+        url_tmpl = app.config.bbpr_url_template
+    url_tmpl = url_tmpl or "missing/%s"
     node = nodes.reference(
         rawtext,
-        "[pr-%s]" % text,
+        "[%s-%s]" % (name, text),
         refuri=url_tmpl % text)
     return [node], []
 
@@ -26,5 +30,7 @@ def pr_role(name, rawtext, text, lineno, inliner, *args, **kwargs):
 def setup(app):
     app.add_role('bug', bug_role)
     app.add_config_value('bug_url_template', None, 'env')
+    app.add_role('bb-pr', pr_role)
     app.add_role('pr', pr_role)
     app.add_config_value('pr_url_template', None, 'env')
+    app.add_config_value('bbpr_url_template', None, 'env')
diff --git a/docs/index.rst b/docs/index.rst
index 6a5a628..a14538d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2,31 +2,18 @@
    :align: center
    :width: 400px
 
-----
-
 .. toctree::
+    :hidden:
     :titlesonly:
     :maxdepth: 2
 
-    tutorial
     changelog
-    api_notes
-    bugs
+    tutorial
     api/index
     man/index
-
-=====================
-Mutagen Documentation
-=====================
-
-.. note::
-
-    This documentation is still incomplete and it's recommended to read the
-    `source <https://bitbucket.org/lazka/mutagen/src/default/mutagen>`__
-    for the full details.
-
-What is Mutagen?
-----------------
+    api_notes
+    bugs
+    contact
 
 Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC, 
 M4A, Monkey's Audio, MP3, Musepack, Ogg Opus, Ogg FLAC, Ogg Speex, Ogg 
@@ -43,14 +30,30 @@ dependencies outside the Python standard library.
 There is a :doc:`brief tutorial with several API examples. 
 <tutorial>`
 
+
+Installing
+----------
+
+::
+
+    pip install mutagen
+
+or
+
+::
+
+    sudo apt-get install python-mutagen python3-mutagen
+
+
 Where do I get it?
 ------------------
 
-Mutagen is hosted on `Bitbucket <http://bitbucket.org/lazka/mutagen>`_. The 
+Mutagen is hosted on `GitHub <https://github.com/quodlibet/mutagen>`_. The 
 `download page <https://bitbucket.org/lazka/mutagen/downloads>`_ will have the 
-latest version or check out the Mercurial repository::
+latest version or check out the git repository::
+
+    $ git clone https://github.com/quodlibet/mutagen.git
 
-    $ hg clone https://bitbucket.org/lazka/mutagen
 
 Why Mutagen?
 ------------
@@ -71,6 +74,7 @@ Therefore we felt it was necessary to write our own.
   test that prevents them from recurring, and new features are committed with
   a full test suite. 
 
+
 Real World Use
 --------------
 
@@ -80,23 +84,8 @@ collection.
 
 The following software projects are using Mutagen for tagging:
 
-* `Ex Falso and Quod Libet <http://code.google.com/p/quodlibet/>`_, a flexible tagger and player
+* `Ex Falso and Quod Libet <https://quodlibet.readthedocs.org>`_, a flexible tagger and player
 * `Beets <http://beets.radbox.org/>`_, a music library manager and MusicBrainz tagger
-* `Picard <http://musicbrainz.org/doc/PicardQt>`_, cross-platform MusicBrainz tagger
-* `Puddletag <http://puddletag.sourceforge.net/>`_, an audio tag editor
-* `Listen <http://listengnome.free.fr/>`_, a music player for GNOME
+* `Picard <https://picard.musicbrainz.org/>`_, cross-platform MusicBrainz tagger
+* `Puddletag <http://puddletag.net/>`_, an audio tag editor
 * `Exaile <http://www.exaile.org/>`_, a media player aiming to be similar to KDE's AmaroK, but for GTK+
-* `ZOMG <http://zomg.alioth.debian.org/>`_, a command-line player for ZSH
-* `pytagsfs <http://www.pytagsfs.org/>`_, virtual file system for organizing media files by metadata
-* Debian's version of `JACK <http://jack.sourceforge.net/>`_, an audio CD ripper, uses Mutagen to tag FLACs
-* Amarok's replaygain `script <http://www.kde-apps.org/content/show.php?content=26073>`_
-
-Contact
--------
-
-For historical and practical reasons, Mutagen shares a `mailing list 
-<http://groups.google.com/group/quod-libet-development/>`_ and IRC channel 
-(#quodlibet on irc.oftc.net) with Quod Libet. If you need help using Mutagen 
-or would like to discuss the library, please use the mailing list. Bugs and 
-patches should go to the `issue tracker 
-<https://bitbucket.org/lazka/mutagen/issues>`_.
diff --git a/docs/man/index.rst b/docs/man/index.rst
index f6b011b..604fb8f 100644
--- a/docs/man/index.rst
+++ b/docs/man/index.rst
@@ -1,7 +1,8 @@
-Tools
-=====
+Command Line Tools
+==================
 
 .. toctree::
+    :hidden:
     :titlesonly:
 
     mid3cp
@@ -11,3 +12,25 @@ Tools
     mutagen-inspect
     mutagen-pony
 
+
+In addition to the Python library mutagen installs some command line tools:
+
+:doc:`mid3cp`
+    copies the ID3 tags from a source file to a destination file
+
+:doc:`mid3iconv`
+    converts ID3 tags from legacy encodings to Unicode and stores them using
+    the ID3v2 format
+
+:doc:`mid3v2`
+    is a Mutagen-based replacement for id3lib’s id3v2
+
+:doc:`moggsplit`
+    splits a multiplexed Ogg stream into separate files
+
+:doc:`mutagen-inspect`
+    loads and prints information about an audio file and its tags
+
+:doc:`mutagen-pony`
+    scans any directories given and reports on the kinds of tags in the MP3s
+    it finds in them
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 33e5323..ca40095 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -69,7 +69,7 @@ the title of an ID3 tag, you need to do the following::
 
 If you use the ID3 module, you should familiarize yourself with how
 ID3v2 tags are stored, by reading the the details of the ID3v2
-standard at http://www.id3.org/develop.html.
+standard at http://id3.org/id3v2.4.0-structure.
 
 
 ID3 Versions
diff --git a/mutagen/__init__.py b/mutagen/__init__.py
index 03ad7ae..c1abc0b 100644
--- a/mutagen/__init__.py
+++ b/mutagen/__init__.py
@@ -22,9 +22,9 @@ for certain keys, again depending on format.
 
 from mutagen._util import MutagenError
 from mutagen._file import FileType, StreamInfo, File
-from mutagen._tags import Metadata, PaddingInfo
+from mutagen._tags import Tags, Metadata, PaddingInfo
 
-version = (1, 31)
+version = (1, 32)
 """Version tuple."""
 
 version_string = ".".join(map(str, version))
@@ -38,6 +38,8 @@ StreamInfo
 
 File
 
+Tags
+
 Metadata
 
 PaddingInfo
diff --git a/mutagen/_file.py b/mutagen/_file.py
index 5daa252..95f400c 100644
--- a/mutagen/_file.py
+++ b/mutagen/_file.py
@@ -16,8 +16,8 @@ class FileType(DictMixin):
 
     Attributes:
 
-    * info -- stream information (length, bitrate, sample rate)
-    * tags -- metadata tags, if any
+    * info -- :class:`StreamInfo` -- (length, bitrate, sample rate)
+    * tags -- :class:`Tags` -- metadata tags, if any
 
     Each file format has different potential tags and stream
     information.
@@ -229,9 +229,11 @@ def File(filename, options=None, easy=False):
         from mutagen.optimfrog import OptimFROG
         from mutagen.aiff import AIFF
         from mutagen.aac import AAC
+        from mutagen.smf import SMF
         options = [MP3, TrueAudio, OggTheora, OggSpeex, OggVorbis, OggFLAC,
                    FLAC, AIFF, APEv2File, MP4, ID3FileType, WavPack,
-                   Musepack, MonkeysAudio, OptimFROG, ASF, OggOpus, AAC]
+                   Musepack, MonkeysAudio, OptimFROG, ASF, OggOpus, AAC,
+                   SMF]
 
     if not options:
         return None
diff --git a/mutagen/_tags.py b/mutagen/_tags.py
index ce250ad..e6365f0 100644
--- a/mutagen/_tags.py
+++ b/mutagen/_tags.py
@@ -71,10 +71,28 @@ class PaddingInfo(object):
             type(self).__name__, self.size, self.padding)
 
 
-class Metadata(object):
-    """An abstract dict-like object.
+class Tags(object):
+    """`Tags` is the base class for many of the tag objects in Mutagen.
 
-    Metadata is the base class for many of the tag objects in Mutagen.
+    In many cases it has a dict like interface.
+    """
+
+    __module__ = "mutagen"
+
+    def pprint(self):
+        """
+        :returns: tag information
+        :rtype: mutagen.text
+        """
+
+        raise NotImplementedError
+
+
+class Metadata(Tags):
+    """Like :class:`Tags` but for standalone tagging formats that are not
+    solely managed by a container format.
+
+    Provides methods to load, save and delete tags.
     """
 
     __module__ = "mutagen"
@@ -83,11 +101,14 @@ class Metadata(object):
         if args or kwargs:
             self.load(*args, **kwargs)
 
-    def load(self, *args, **kwargs):
+    def load(self, filename, **kwargs):
         raise NotImplementedError
 
     def save(self, filename=None):
-        """Save changes to a file."""
+        """Save changes to a file.
+
+        :raises mutagen.MutagenError: if saving wasn't possible
+        """
 
         raise NotImplementedError
 
@@ -96,6 +117,8 @@ class Metadata(object):
 
         In most cases this means any traces of the tag will be removed
         from the file.
+
+        :raises mutagen.MutagenError: if deleting wasn't possible
         """
 
         raise NotImplementedError
diff --git a/mutagen/_vorbis.py b/mutagen/_vorbis.py
index da20240..17634e0 100644
--- a/mutagen/_vorbis.py
+++ b/mutagen/_vorbis.py
@@ -57,7 +57,7 @@ class VorbisEncodingError(error):
     pass
 
 
-class VComment(mutagen.Metadata, list):
+class VComment(mutagen.Tags, list):
     """A Vorbis comment parser, accessor, and renderer.
 
     All comment ordering is preserved. A VComment is a list of
diff --git a/mutagen/asf/__init__.py b/mutagen/asf/__init__.py
index e667192..7d37a86 100644
--- a/mutagen/asf/__init__.py
+++ b/mutagen/asf/__init__.py
@@ -10,7 +10,7 @@
 
 __all__ = ["ASF", "Open"]
 
-from mutagen import FileType, Metadata, StreamInfo
+from mutagen import FileType, Tags, StreamInfo
 from mutagen._util import resize_bytes, DictMixin
 from mutagen._compat import string_types, long_, PY3, izip
 
@@ -79,7 +79,7 @@ class ASFInfo(StreamInfo):
         return s
 
 
-class ASFTags(list, DictMixin, Metadata):
+class ASFTags(list, DictMixin, Tags):
     """Dictionary containing ASF attributes."""
 
     def __getitem__(self, key):
diff --git a/mutagen/asf/_objects.py b/mutagen/asf/_objects.py
index ed94267..001c58a 100644
--- a/mutagen/asf/_objects.py
+++ b/mutagen/asf/_objects.py
@@ -85,11 +85,34 @@ class HeaderObject(BaseObject):
 
         header = cls()
 
-        size, num_objects = cls.parse_size(fileobj)
+        remaining_header, num_objects = cls.parse_size(fileobj)
+        remaining_header -= 30
+
         for i in xrange(num_objects):
-            guid, size = struct.unpack("<16sQ", fileobj.read(24))
+            obj_header_size = 24
+            if remaining_header < obj_header_size:
+                raise ASFHeaderError("invalid header size")
+            data = fileobj.read(obj_header_size)
+            if len(data) != obj_header_size:
+                raise ASFHeaderError("truncated")
+            remaining_header -= obj_header_size
+
+            guid, size = struct.unpack("<16sQ", data)
             obj = BaseObject._get_object(guid)
-            data = fileobj.read(size - 24)
+
+            payload_size = size - obj_header_size
+            if remaining_header < payload_size:
+                raise ASFHeaderError("invalid object size")
+            remaining_header -= payload_size
+
+            try:
+                data = fileobj.read(payload_size)
+            except OverflowError:
+                # read doesn't take 64bit values
+                raise ASFHeaderError("invalid header size")
+            if len(data) != payload_size:
+                raise ASFHeaderError("truncated")
+
             obj.parse(asf, data)
             header.objects.append(obj)
 
diff --git a/mutagen/easymp4.py b/mutagen/easymp4.py
index b965f37..8ad7fd0 100644
--- a/mutagen/easymp4.py
+++ b/mutagen/easymp4.py
@@ -6,7 +6,7 @@
 # it under the terms of version 2 of the GNU General Public License as
 # published by the Free Software Foundation.
 
-from mutagen import Metadata
+from mutagen import Tags
 from mutagen._util import DictMixin, dict_match
 from mutagen.mp4 import MP4, MP4Tags, error, delete
 from ._compat import PY2, text_type, PY3
@@ -19,7 +19,7 @@ class EasyMP4KeyError(error, KeyError, ValueError):
     pass
 
 
-class EasyMP4Tags(DictMixin, Metadata):
+class EasyMP4Tags(DictMixin, Tags):
     """A file with MPEG-4 iTunes metadata.
 
     Like Vorbis comments, EasyMP4Tags keys are case-insensitive ASCII
diff --git a/mutagen/flac.py b/mutagen/flac.py
index e6cd1cf..f3cc5ab 100644
--- a/mutagen/flac.py
+++ b/mutagen/flac.py
@@ -654,7 +654,7 @@ class FLAC(mutagen.FileType):
     * pictures -- list of embedded pictures
     """
 
-    _mimes = ["audio/x-flac", "application/x-flac"]
+    _mimes = ["audio/flac", "audio/x-flac", "application/x-flac"]
 
     info = None
     """A `StreamInfo`"""
@@ -689,9 +689,9 @@ class FLAC(mutagen.FileType):
             # so we have to too.  Instead of parsing the size
             # given, parse an actual Vorbis comment, leaving
             # fileobj in the right position.
-            # http://code.google.com/p/mutagen/issues/detail?id=52
+            # https://github.com/quodlibet/mutagen/issues/52
             # ..same for the Picture block:
-            # http://code.google.com/p/mutagen/issues/detail?id=106
+            # https://github.com/quodlibet/mutagen/issues/106
             start = fileobj.tell()
             block = block_type(fileobj)
             real_size = fileobj.tell() - start
diff --git a/mutagen/id3/__init__.py b/mutagen/id3/__init__.py
index 9aef865..11bf54e 100644
--- a/mutagen/id3/__init__.py
+++ b/mutagen/id3/__init__.py
@@ -141,7 +141,7 @@ class ID3Header(object):
                 # a frame, and if it's *not* a frame we're going to be
                 # completely lost anyway, this seems to be the most
                 # correct check.
-                # http://code.google.com/p/quodlibet/issues/detail?id=126
+                # https://github.com/quodlibet/quodlibet/issues/126
                 self._flags ^= 0x40
                 extsize = 0
                 fileobj.seek(-4, 1)
@@ -354,6 +354,11 @@ class ID3(DictProxy, mutagen.Metadata):
         """Add a frame to the tag."""
         return self.loaded_frame(frame)
 
+    def __setitem__(self, key, tag):
+        if not isinstance(tag, Frame):
+            raise TypeError("%r not a Frame instance" % tag)
+        super(ID3, self).__setitem__(key, tag)
+
     def __read_frames(self, data, frames):
         assert self.version >= ID3Header._V22
 
@@ -635,11 +640,6 @@ class ID3(DictProxy, mutagen.Metadata):
             # Get rid of "(xx)Foobr" format.
             self["TCON"].genres = self["TCON"].genres
 
-        # ID3v2.2 LNK frames are just way too different to upgrade.
-        for frame in self.getall("LINK"):
-            if len(frame.frameid) != 4:
-                del self[frame.HashKey]
-
         mimes = {"PNG": "image/png", "JPG": "image/jpeg"}
         for pic in self.getall("APIC"):
             if pic.mime in mimes:
diff --git a/mutagen/id3/_frames.py b/mutagen/id3/_frames.py
index c185cef..33ecf5c 100644
--- a/mutagen/id3/_frames.py
+++ b/mutagen/id3/_frames.py
@@ -15,7 +15,8 @@ from ._specs import (
     EncodingSpec, ASPIIndexSpec, SizedIntegerSpec, IntegerSpec,
     VolumeAdjustmentsSpec, VolumePeakSpec, VolumeAdjustmentSpec,
     ChannelSpec, MultiSpec, SynchronizedTextSpec, KeyEventSpec, TimeStampSpec,
-    EncodedNumericPartTextSpec, EncodedNumericTextSpec, SpecError)
+    EncodedNumericPartTextSpec, EncodedNumericTextSpec, SpecError,
+    PictureTypeSpec)
 from .._compat import text_type, string_types, swap_to_string, iteritems, izip
 
 
@@ -62,14 +63,16 @@ class Frame(object):
             other._to_other(self)
         else:
             for checker, val in izip(self._framespec, args):
-                setattr(self, checker.name, checker.validate(self, val))
+                setattr(self, checker.name, val)
             for checker in self._framespec[len(args):]:
-                try:
-                    validated = checker.validate(
-                        self, kwargs.get(checker.name, None))
-                except ValueError as e:
-                    raise ValueError("%s: %s" % (checker.name, e))
-                setattr(self, checker.name, validated)
+                setattr(self, checker.name, kwargs.get(checker.name))
+
+    def __setattr__(self, name, value):
+        for checker in self._framespec:
+            if checker.name == name:
+                self.__dict__[name] = checker.validate(self, value)
+                return
+        super(Frame, self).__setattr__(name, value)
 
     def _to_other(self, other):
         # this impl covers subclasses with the same framespec
@@ -170,8 +173,8 @@ class Frame(object):
                 except ValueError:
                     # Some things write synch-unsafe data with either the frame
                     # or global unsynch flag set. Try to load them as is.
-                    # https://bitbucket.org/lazka/mutagen/issue/210
-                    # https://bitbucket.org/lazka/mutagen/issue/223
+                    # https://github.com/quodlibet/mutagen/issues/210
+                    # https://github.com/quodlibet/mutagen/issues/223
                     pass
             if tflags & Frame.FLAG24_ENCRYPT:
                 raise ID3EncryptionUnsupportedError
@@ -221,11 +224,17 @@ class FrameOpt(Frame):
         super(FrameOpt, self).__init__(*args, **kwargs)
         for spec in self._optionalspec:
             if spec.name in kwargs:
-                validated = spec.validate(self, kwargs[spec.name])
-                setattr(self, spec.name, validated)
+                setattr(self, spec.name, kwargs[spec.name])
             else:
                 break
 
+    def __setattr__(self, name, value):
+        for checker in self._optionalspec:
+            if checker.name == name:
+                self.__dict__[name] = checker.validate(self, value)
+                return
+        super(FrameOpt, self).__setattr__(name, value)
+
     def _to_other(self, other):
         super(FrameOpt, self)._to_other(other)
 
@@ -1104,7 +1113,7 @@ class APIC(Frame):
     _framespec = [
         EncodingSpec('encoding'),
         Latin1TextSpec('mime'),
-        ByteSpec('type'),
+        PictureTypeSpec('type'),
         EncodedTextSpec('desc'),
         BinaryDataSpec('data'),
     ]
@@ -1834,7 +1843,7 @@ class PIC(APIC):
     _framespec = [
         EncodingSpec('encoding'),
         StringSpec('mime', 3),
-        ByteSpec('type'),
+        PictureTypeSpec('type'),
         EncodedTextSpec('desc'),
         BinaryDataSpec('data')
     ]
@@ -1894,7 +1903,13 @@ class LNK(LINK):
         if not isinstance(other, LINK):
             raise TypeError
 
-        other.frameid = self.frameid
+        if isinstance(other, LNK):
+            other.frameid = self.frameid
+        else:
+            try:
+                other.frameid = Frames_2_2[self.frameid].__bases__[0].__name__
+            except KeyError:
+                other.frameid = self.frameid.ljust(4)
         other.url = self.url
         if hasattr(self, "data"):
             other.data = self.data
diff --git a/mutagen/id3/_specs.py b/mutagen/id3/_specs.py
index 4358a65..22e4335 100644
--- a/mutagen/id3/_specs.py
+++ b/mutagen/id3/_specs.py
@@ -131,6 +131,19 @@ class ByteSpec(Spec):
         return value
 
 
+class PictureTypeSpec(ByteSpec):
+
+    def read(self, frame, data):
+        value, data = ByteSpec.read(self, frame, data)
+        return PictureType(value), data
+
+    def validate(self, frame, value):
+        value = ByteSpec.validate(self, frame, value)
+        if value is not None:
+            return PictureType(value)
+        return value
+
+
 class IntegerSpec(Spec):
     def read(self, frame, data):
         return int(BitPaddedInt(data, bits=8)), b''
@@ -180,7 +193,7 @@ class EncodingSpec(ByteSpec):
         if enc not in (Encoding.LATIN1, Encoding.UTF16, Encoding.UTF16BE,
                        Encoding.UTF8):
             raise SpecError('Invalid Encoding: %r' % enc)
-        return enc, data
+        return Encoding(enc), data
 
     def validate(self, frame, value):
         if value is None:
@@ -188,7 +201,7 @@ class EncodingSpec(ByteSpec):
         if value not in (Encoding.LATIN1, Encoding.UTF16, Encoding.UTF16BE,
                          Encoding.UTF8):
             raise ValueError('Invalid Encoding: %r' % value)
-        return value
+        return Encoding(value)
 
     def _validate23(self, frame, value, **kwargs):
         # only 0, 1 are valid in v2.3, default to utf-16
diff --git a/mutagen/m4a.py b/mutagen/m4a.py
index 5730ace..3ed148c 100644
--- a/mutagen/m4a.py
+++ b/mutagen/m4a.py
@@ -13,7 +13,7 @@ since 1.31: mutagen.m4a will no longer work; any operation that could fail
 
 import warnings
 
-from mutagen import FileType, Metadata, StreamInfo
+from mutagen import FileType, Tags, StreamInfo
 from ._util import DictProxy, MutagenError
 
 warnings.warn(
@@ -53,7 +53,7 @@ class M4ACover(bytes):
         return self
 
 
-class M4ATags(DictProxy, Metadata):
+class M4ATags(DictProxy, Tags):
 
     def load(self, atoms, fileobj):
         raise error("deprecated")
diff --git a/mutagen/mp4/__init__.py b/mutagen/mp4/__init__.py
index bc242ee..e3c16a7 100644
--- a/mutagen/mp4/__init__.py
+++ b/mutagen/mp4/__init__.py
@@ -26,7 +26,7 @@ were all consulted.
 import struct
 import sys
 
-from mutagen import FileType, Metadata, StreamInfo, PaddingInfo
+from mutagen import FileType, Tags, StreamInfo, PaddingInfo
 from mutagen._constants import GENRES
 from mutagen._util import (cdata, insert_bytes, DictProxy, MutagenError,
                            hashable, enum, get_size, resize_bytes)
@@ -237,7 +237,22 @@ def _find_padding(atom_path):
         pass
 
 
-class MP4Tags(DictProxy, Metadata):
+def _item_sort_key(key, value):
+    # iTunes always writes the tags in order of "relevance", try
+    # to copy it as closely as possible.
+    order = ["\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb",
+             "\xa9gen", "gnre", "trkn", "disk",
+             "\xa9day", "cpil", "pgap", "pcst", "tmpo",
+             "\xa9too", "----", "covr", "\xa9lyr"]
+    order = dict(izip(order, xrange(len(order))))
+    last = len(order)
+    # If there's no key-based way to distinguish, order by length.
+    # If there's still no way, go by string comparison on the
+    # values, so we at least have something determinstic.
+    return (order.get(key[:4], last), len(repr(value)), repr(value))
+
+
+class MP4Tags(DictProxy, Tags):
     r"""Dictionary containing Apple iTunes metadata list key/values.
 
     Keys are four byte identifiers, except for freeform ('----')
@@ -305,7 +320,9 @@ class MP4Tags(DictProxy, Metadata):
 
     def __init__(self, *args, **kwargs):
         self._failed_atoms = {}
-        super(MP4Tags, self).__init__(*args, **kwargs)
+        super(MP4Tags, self).__init__()
+        if args or kwargs:
+            self.load(*args, **kwargs)
 
     def load(self, atoms, fileobj):
         try:
@@ -337,42 +354,30 @@ class MP4Tags(DictProxy, Metadata):
     def __setitem__(self, key, value):
         if not isinstance(key, str):
             raise TypeError("key has to be str")
+        self._render(key, value)
         super(MP4Tags, self).__setitem__(key, value)
 
     @classmethod
     def _can_load(cls, atoms):
         return b"moov.udta.meta.ilst" in atoms
 
-    @staticmethod
-    def _key_sort(item):
-        (key, v) = item
-        # iTunes always writes the tags in order of "relevance", try
-        # to copy it as closely as possible.
-        order = ["\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb",
-                 "\xa9gen", "gnre", "trkn", "disk",
-                 "\xa9day", "cpil", "pgap", "pcst", "tmpo",
... 857 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/mutagen.git



More information about the Python-modules-commits mailing list