Control: tags 851016 + patch
Control: tags 851016 + pending

Dear maintainer,

I've prepared an NMU for beets (versioned as 1.3.19-2.1) and
uploaded it to DELAYED/7. Please feel free to tell me if I
should delay it longer.

Regards,
    S
diffstat for beets-1.3.19 beets-1.3.19

 changelog                                              |   14 
 control                                                |    4 
 patches/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch |   24 +
 patches/mediafile-Cleanup-mutagen-error-handling.patch |  241 +++++++++++++++++
 patches/series                                         |    2 
 5 files changed, 283 insertions(+), 2 deletions(-)

diff -Nru beets-1.3.19/debian/changelog beets-1.3.19/debian/changelog
--- beets-1.3.19/debian/changelog	2016-08-30 06:07:14.000000000 +0100
+++ beets-1.3.19/debian/changelog	2017-01-23 09:41:08.000000000 +0000
@@ -1,3 +1,17 @@
+beets (1.3.19-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * d/p/mediafile-Cleanup-mutagen-error-handling.patch:
+    Add patch backported from upstream to update exception handling for
+    python-mutagen >= 1.33. This fixes a test failure and
+    FTBFS (Closes: #851016)
+  * d/p/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch:
+    Add patch backported from upstream to fix a failing test with
+    python-mutagen >= 1.35
+    - d/control: depend and build-depend on a compatible version
+
+ -- Simon McVittie <s...@debian.org>  Mon, 23 Jan 2017 09:41:08 +0000
+
 beets (1.3.19-2) unstable; urgency=medium
 
   * Fix occasional FTBFS due to lack of mock cleanup. Thanks Santiago Vila.
diff -Nru beets-1.3.19/debian/control beets-1.3.19/debian/control
--- beets-1.3.19/debian/control	2016-08-30 04:40:16.000000000 +0100
+++ beets-1.3.19/debian/control	2017-01-23 09:41:08.000000000 +0000
@@ -17,7 +17,7 @@
  python-mpd,
  python-munkres,
  python-musicbrainzngs (>= 0.4),
- python-mutagen (>= 1.27),
+ python-mutagen (>= 1.35),
  python-pathlib,
  python-pylast,
  python-rarfile,
@@ -41,7 +41,7 @@
  libjs-underscore,
  python-enum34,
  python-musicbrainzngs (>= 0.4),
- python-mutagen (>= 1.21),
+ python-mutagen (>= 1.35),
  python-pkg-resources,
  ${misc:Depends},
  ${python:Depends}
diff -Nru beets-1.3.19/debian/patches/mediafile-Cleanup-mutagen-error-handling.patch beets-1.3.19/debian/patches/mediafile-Cleanup-mutagen-error-handling.patch
--- beets-1.3.19/debian/patches/mediafile-Cleanup-mutagen-error-handling.patch	1970-01-01 01:00:00.000000000 +0100
+++ beets-1.3.19/debian/patches/mediafile-Cleanup-mutagen-error-handling.patch	2017-01-23 09:41:08.000000000 +0000
@@ -0,0 +1,241 @@
+From: Christoph Reiter <reiter.christ...@gmail.com>
+Date: Mon, 27 Jun 2016 09:43:48 +0200
+Subject: mediafile: Cleanup mutagen error handling
+
+Instead of the individial mutagen format exceptions use the
+mutagen.MutagenError exception introduced in 1.25.
+
+Since 1.33 mutagen will only raise MutagenError for load/save/delete
+and no longer raise IOError. Translate both errors to UnreadableFileError
+to support older and newer mutagen versions. Unify error handling
+in __init__(), save() and delete().
+
+Since it's no longer possible to get an IOError from MediaFile, adjust
+all callers and tests accordingly.
+
+This was tested with mutagen 1.27 and current mutagen master.
+
+[smcv: backported to 1.3.19 by replacing six.text_type with unicode]
+
+Origin: upstream, 1.4.1, commit:629241efd389bea7b4075f2591a06f2ef462dc82
+---
+ beets/library.py       |  8 +++----
+ beets/mediafile.py     | 65 +++++++++++++++++++++++---------------------------
+ beetsplug/scrub.py     | 13 ++++++----
+ test/test_mediafile.py | 23 +++++++++++++++++-
+ 4 files changed, 64 insertions(+), 45 deletions(-)
+
+diff --git a/beets/library.py b/beets/library.py
+index 3450a35a..70fff1a7 100644
+--- a/beets/library.py
++++ b/beets/library.py
+@@ -25,7 +25,7 @@ import re
+ from unidecode import unidecode
+ 
+ from beets import logging
+-from beets.mediafile import MediaFile, MutagenError, UnreadableFileError
++from beets.mediafile import MediaFile, UnreadableFileError
+ from beets import plugins
+ from beets import util
+ from beets.util import bytestring_path, syspath, normpath, samefile
+@@ -560,7 +560,7 @@ class Item(LibModel):
+             read_path = normpath(read_path)
+         try:
+             mediafile = MediaFile(syspath(read_path))
+-        except (OSError, IOError, UnreadableFileError) as exc:
++        except UnreadableFileError as exc:
+             raise ReadError(read_path, exc)
+ 
+         for key in self._media_fields:
+@@ -607,14 +607,14 @@ class Item(LibModel):
+         try:
+             mediafile = MediaFile(syspath(path),
+                                   id3v23=beets.config['id3v23'].get(bool))
+-        except (OSError, IOError, UnreadableFileError) as exc:
++        except UnreadableFileError as exc:
+             raise ReadError(self.path, exc)
+ 
+         # Write the tags to the file.
+         mediafile.update(item_tags)
+         try:
+             mediafile.save()
+-        except (OSError, IOError, MutagenError) as exc:
++        except UnreadableFileError as exc:
+             raise WriteError(self.path, exc)
+ 
+         # The file has a new mtime.
+diff --git a/beets/mediafile.py b/beets/mediafile.py
+index 556b41bb..026da3e1 100644
+--- a/beets/mediafile.py
++++ b/beets/mediafile.py
+@@ -1344,32 +1344,12 @@ class MediaFile(object):
+         path = syspath(path)
+         self.path = path
+ 
+-        unreadable_exc = (
+-            mutagen.mp3.error,
+-            mutagen.id3.error,
+-            mutagen.flac.error,
+-            mutagen.monkeysaudio.MonkeysAudioHeaderError,
+-            mutagen.mp4.error,
+-            mutagen.oggopus.error,
+-            mutagen.oggvorbis.error,
+-            mutagen.ogg.error,
+-            mutagen.asf.error,
+-            mutagen.apev2.error,
+-            mutagen.aiff.error,
+-        )
+         try:
+             self.mgfile = mutagen.File(path)
+-        except unreadable_exc as exc:
+-            log.debug(u'header parsing failed: {0}', unicode(exc))
++        except (mutagen.MutagenError, IOError) as exc:
++            # Mutagen <1.33 could raise IOError
++            log.debug(u'parsing failed: {0}', unicode(exc))
+             raise UnreadableFileError(path)
+-        except IOError as exc:
+-            if type(exc) == IOError:
+-                # This is a base IOError, not a subclass from Mutagen or
+-                # anywhere else.
+-                raise
+-            else:
+-                log.debug(u'{}', traceback.format_exc())
+-                raise MutagenError(path, exc)
+         except Exception as exc:
+             # Isolate bugs in Mutagen.
+             log.debug(u'{}', traceback.format_exc())
+@@ -1426,7 +1406,8 @@ class MediaFile(object):
+         self.id3v23 = id3v23 and self.type == 'mp3'
+ 
+     def save(self):
+-        """Write the object's tags back to the file.
++        """Write the object's tags back to the file. May
++        throw `UnreadableFileError`.
+         """
+         # Possibly save the tags to ID3v2.3.
+         kwargs = {}
+@@ -1438,27 +1419,41 @@ class MediaFile(object):
+             id3.update_to_v23()
+             kwargs['v2_version'] = 3
+ 
+-        # Isolate bugs in Mutagen.
+         try:
+             self.mgfile.save(**kwargs)
+-        except (IOError, OSError):
+-            # Propagate these through: they don't represent Mutagen bugs.
+-            raise
++        except (mutagen.MutagenError, IOError) as exc:
++            # Mutagen <1.33 could raise IOError
++            log.debug(u'saving failed: {0}', unicode(exc))
++            raise UnreadableFileError(self.path)
+         except Exception as exc:
++            # Isolate bugs in Mutagen.
+             log.debug(u'{}', traceback.format_exc())
+             log.error(u'uncaught Mutagen exception in save: {0}', exc)
+             raise MutagenError(self.path, exc)
+ 
+     def delete(self):
+-        """Remove the current metadata tag from the file.
++        """Remove the current metadata tag from the file. May
++        throw `UnreadableFileError`.
+         """
++
+         try:
+-            self.mgfile.delete()
+-        except NotImplementedError:
+-            # For Mutagen types that don't support deletion (notably,
+-            # ASF), just delete each tag individually.
+-            for tag in self.mgfile.keys():
+-                del self.mgfile[tag]
++            try:
++                self.mgfile.delete()
++            except NotImplementedError:
++                # FIXME: This is fixed in mutagen >=1.31
++                # For Mutagen types that don't support deletion (notably,
++                # ASF), just delete each tag individually.
++                for tag in self.mgfile.keys():
++                    del self.mgfile[tag]
++        except (mutagen.MutagenError, IOError) as exc:
++            # Mutagen <1.33 could raise IOError
++            log.debug(u'deleting failed: {0}', unicode(exc))
++            raise UnreadableFileError(self.path)
++        except Exception as exc:
++            # Isolate bugs in Mutagen.
++            log.debug(u'{}', traceback.format_exc())
++            log.error(u'uncaught Mutagen exception in save: {0}', exc)
++            raise MutagenError(self.path, exc)
+ 
+     # Convenient access to the set of available fields.
+ 
+diff --git a/beetsplug/scrub.py b/beetsplug/scrub.py
+index ed4040d5..4dcefe57 100644
+--- a/beetsplug/scrub.py
++++ b/beetsplug/scrub.py
+@@ -119,7 +119,7 @@ class ScrubPlugin(BeetsPlugin):
+             try:
+                 mf = mediafile.MediaFile(util.syspath(item.path),
+                                          config['id3v23'].get(bool))
+-            except IOError as exc:
++            except mediafile.UnreadableFileError as exc:
+                 self._log.error(u'could not open file to scrub: {0}',
+                                 exc)
+             art = mf.art
+@@ -133,10 +133,13 @@ class ScrubPlugin(BeetsPlugin):
+             item.try_write()
+             if art:
+                 self._log.debug(u'restoring art')
+-                mf = mediafile.MediaFile(util.syspath(item.path),
+-                                         config['id3v23'].get(bool))
+-                mf.art = art
+-                mf.save()
++                try:
++                    mf = mediafile.MediaFile(util.syspath(item.path),
++                                             config['id3v23'].get(bool))
++                    mf.art = art
++                    mf.save()
++                except mediafile.UnreadableFileError as exc:
++                    self._log.error(u'could not write tags: {0}', exc)
+ 
+     def import_task_files(self, session, task):
+         """Automatically scrub imported files."""
+diff --git a/test/test_mediafile.py b/test/test_mediafile.py
+index e2fdd9fc..2ec3704f 100644
+--- a/test/test_mediafile.py
++++ b/test/test_mediafile.py
+@@ -28,7 +28,7 @@ from test import _common
+ from test._common import unittest
+ from beets.mediafile import MediaFile, MediaField, Image, \
+     MP3DescStorageStyle, StorageStyle, MP4StorageStyle, \
+-    ASFStorageStyle, ImageType, CoverArtField
++    ASFStorageStyle, ImageType, CoverArtField, UnreadableFileError
+ from beets.library import Item
+ from beets.plugins import BeetsPlugin
+ from beets.util import bytestring_path
+@@ -453,6 +453,27 @@ class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
+         if os.path.isdir(self.temp_dir):
+             shutil.rmtree(self.temp_dir)
+ 
++    def test_read_nonexisting(self):
++        mediafile = self._mediafile_fixture('full')
++        os.remove(mediafile.path)
++        self.assertRaises(UnreadableFileError, MediaFile, mediafile.path)
++
++    def test_save_nonexisting(self):
++        mediafile = self._mediafile_fixture('full')
++        os.remove(mediafile.path)
++        try:
++            mediafile.save()
++        except UnreadableFileError:
++            pass
++
++    def test_delete_nonexisting(self):
++        mediafile = self._mediafile_fixture('full')
++        os.remove(mediafile.path)
++        try:
++            mediafile.delete()
++        except UnreadableFileError:
++            pass
++
+     def test_read_audio_properties(self):
+         mediafile = self._mediafile_fixture('full')
+         for key, value in self.audio_properties.items():
diff -Nru beets-1.3.19/debian/patches/series beets-1.3.19/debian/patches/series
--- beets-1.3.19/debian/patches/series	2016-08-30 00:23:52.000000000 +0100
+++ beets-1.3.19/debian/patches/series	2017-01-23 09:41:08.000000000 +0000
@@ -3,3 +3,5 @@
 fix-test_mediafile_edge
 fix-test_nonexistent_file
 skip-test_query-path-tests
+mediafile-Cleanup-mutagen-error-handling.patch
+Test-true-FLAC-bitrate-from-Mutagen-1.35.patch
diff -Nru beets-1.3.19/debian/patches/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch beets-1.3.19/debian/patches/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch
--- beets-1.3.19/debian/patches/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch	1970-01-01 01:00:00.000000000 +0100
+++ beets-1.3.19/debian/patches/Test-true-FLAC-bitrate-from-Mutagen-1.35.patch	2017-01-23 09:41:08.000000000 +0000
@@ -0,0 +1,24 @@
+From: Adrian Sampson <adr...@radbox.org>
+Date: Fri, 23 Dec 2016 20:23:23 -0500
+Subject: Test "true" FLAC bitrate from Mutagen 1.35
+
+Fix #2343.
+
+Origin: upstream, 1.4.3, commit:10f0d03d790da2e849125104a718a9f14ac535e6
+---
+ test/test_mediafile.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test/test_mediafile.py b/test/test_mediafile.py
+index 2ec3704f..6fea9ab7 100644
+--- a/test/test_mediafile.py
++++ b/test/test_mediafile.py
+@@ -896,7 +896,7 @@ class FlacTest(ReadWriteTestBase, PartialTestMixin,
+     extension = 'flac'
+     audio_properties = {
+         'length': 1.0,
+-        'bitrate': 175120,
++        'bitrate': 108688,
+         'format': u'FLAC',
+         'samplerate': 44100,
+         'bitdepth': 16,

Reply via email to