Hello community,

here is the log from the commit of package python-mutagen for openSUSE:Factory 
checked in at 2019-01-08 12:16:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-mutagen (Old)
 and      /work/SRC/openSUSE:Factory/.python-mutagen.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-mutagen"

Tue Jan  8 12:16:38 2019 rev:32 rq:662312 version:1.42.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-mutagen/python-mutagen.changes    
2018-12-27 00:27:17.359766297 +0100
+++ /work/SRC/openSUSE:Factory/.python-mutagen.new.28833/python-mutagen.changes 
2019-01-08 12:16:39.593028066 +0100
@@ -1,0 +2,9 @@
+Fri Dec 28 03:28:33 UTC 2018 - s...@suspend.net
+
+- update to version 1.42.0:
+  * id3: always read id3v1 tags and include them when no id3v2 exists
+  * id3: add a pretty print implementation for SYLT
+  * vorbis: improved error messages when validating keys/values
+  * Fix pylint warnings when using various save() methods
+
+-------------------------------------------------------------------

Old:
----
  mutagen-1.41.0.tar.gz

New:
----
  mutagen-1.42.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-mutagen.spec ++++++
--- /var/tmp/diff_new_pack.JUy5aF/_old  2019-01-08 12:16:40.129027562 +0100
+++ /var/tmp/diff_new_pack.JUy5aF/_new  2019-01-08 12:16:40.133027558 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-mutagen
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-mutagen
-Version:        1.41.0
+Version:        1.42.0
 Release:        0
 Summary:        Python module to Handle Audio Metadata
 License:        GPL-2.0-or-later

++++++ mutagen-1.41.0.tar.gz -> mutagen-1.42.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/NEWS new/mutagen-1.42.0/NEWS
--- old/mutagen-1.41.0/NEWS     2018-07-16 21:32:50.000000000 +0200
+++ new/mutagen-1.42.0/NEWS     2018-12-26 14:59:06.000000000 +0100
@@ -1,3 +1,23 @@
+1.42.0 - 2018-12-26
+-------------------
+
+* ID3: Always read id3v1 tags and include them when no id3v2 equivalent
+  exists. Can be disabled with the new ``load_v1`` option,
+  see :meth:`id3.ID3.load`
+  :pr:`357` (:user:`Fredrik Strupe <frestr>`)
+* ID3: Add a pretty print implementation for SYLT
+  :pr:`359` (:user:`Hamid Alaei Varnosfaderani <halaei>`)
+* vorbis: Improved error messages when validating keys/values
+  :pr:`356` (:user:`Michael Booth <MJuddBooth>`)
+* Fix pylint warnings when using the various ``save()`` methods :pr:`364`
+
+
+1.41.1 - 2018-08-11
+-------------------
+
+* MP4: fix rtng, stik, shwm getting saved as 16bit ints instead of 8bit 
:bug:`349`
+
+
 1.41.0 - 2018-07-15
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/PKG-INFO new/mutagen-1.42.0/PKG-INFO
--- old/mutagen-1.41.0/PKG-INFO 2018-07-16 21:33:14.000000000 +0200
+++ new/mutagen-1.42.0/PKG-INFO 2018-12-26 14:59:37.000000000 +0100
@@ -1,11 +1,11 @@
 Metadata-Version: 1.1
 Name: mutagen
-Version: 1.41.0
+Version: 1.42.0
 Summary: read and write audio tags for many formats
 Home-page: https://github.com/quodlibet/mutagen
 Author: Michael Urman
 Author-email: quod-libet-developm...@groups.google.com
-License: GNU GPL v2
+License: GPL-2.0-or-later
 Description: .. image:: 
https://cdn.rawgit.com/quodlibet/mutagen/master/docs/images/logo.svg
            :align: center
            :width: 400px
@@ -29,8 +29,8 @@
         .. image:: https://travis-ci.org/quodlibet/mutagen.svg?branch=master
             :target: https://travis-ci.org/quodlibet/mutagen
         
-        .. image:: 
https://ci.appveyor.com/api/projects/status/d22bslvjvt3r1hv1/branch/master?svg=true
-            :target: 
https://ci.appveyor.com/project/lazka/mutagen/branch/master
+        .. image:: 
https://dev.azure.com/quodlibet/mutagen/_apis/build/status/quodlibet.mutagen
+            :target: 
https://dev.azure.com/quodlibet/mutagen/_build/latest?definitionId=3
         
         .. image:: 
https://codecov.io/gh/quodlibet/mutagen/branch/master/graph/badge.svg
           :target: https://codecov.io/gh/quodlibet/mutagen
@@ -46,5 +46,5 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
+Classifier: License :: OSI Approved :: GNU General Public License v2 or later 
(GPLv2+)
 Classifier: Topic :: Multimedia :: Sound/Audio
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/README.rst 
new/mutagen-1.42.0/README.rst
--- old/mutagen-1.41.0/README.rst       2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/README.rst       2018-11-17 13:12:22.000000000 +0100
@@ -21,8 +21,8 @@
 .. image:: https://travis-ci.org/quodlibet/mutagen.svg?branch=master
     :target: https://travis-ci.org/quodlibet/mutagen
 
-.. image:: 
https://ci.appveyor.com/api/projects/status/d22bslvjvt3r1hv1/branch/master?svg=true
-    :target: https://ci.appveyor.com/project/lazka/mutagen/branch/master
+.. image:: 
https://dev.azure.com/quodlibet/mutagen/_apis/build/status/quodlibet.mutagen
+    :target: 
https://dev.azure.com/quodlibet/mutagen/_build/latest?definitionId=3
 
 .. image:: 
https://codecov.io/gh/quodlibet/mutagen/branch/master/graph/badge.svg
   :target: https://codecov.io/gh/quodlibet/mutagen
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/docs/Makefile 
new/mutagen-1.42.0/docs/Makefile
--- old/mutagen-1.41.0/docs/Makefile    2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/docs/Makefile    2018-11-08 18:50:38.000000000 +0100
@@ -1,5 +1,5 @@
 all:
-       python -m sphinx -b html -n . _build
+       python3 -m sphinx -b html -n . _build
 
 clean:
        rm -rf _build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/docs/conf.py 
new/mutagen-1.42.0/docs/conf.py
--- old/mutagen-1.41.0/docs/conf.py     2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/docs/conf.py     2018-11-08 18:50:38.000000000 +0100
@@ -16,8 +16,8 @@
     'sphinx.ext.extlinks',
 ]
 intersphinx_mapping = {
-    'python': ('https://docs.python.org/2.7', None),
-    'python3': ('https://docs.python.org/3.5', None),
+    'python': ('https://docs.python.org/2', None),
+    'python3': ('https://docs.python.org/3', None),
 }
 source_suffix = '.rst'
 master_doc = 'index'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/docs/extra.css 
new/mutagen-1.42.0/docs/extra.css
--- old/mutagen-1.41.0/docs/extra.css   2017-05-25 15:49:20.000000000 +0200
+++ new/mutagen-1.42.0/docs/extra.css   2018-12-26 14:47:44.000000000 +0100
@@ -30,3 +30,7 @@
 .rst-footer-buttons {
     display: none;
 }
+
+.versionmodified {
+    color: #008000;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/__init__.py 
new/mutagen-1.42.0/mutagen/__init__.py
--- old/mutagen-1.41.0/mutagen/__init__.py      2018-07-16 21:32:50.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/__init__.py      2018-12-26 14:59:06.000000000 
+0100
@@ -23,7 +23,7 @@
 from mutagen._file import FileType, StreamInfo, File
 from mutagen._tags import Tags, Metadata, PaddingInfo
 
-version = (1, 41, 0)
+version = (1, 42, 0)
 """Version tuple."""
 
 version_string = ".".join(map(str, version))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/_file.py 
new/mutagen-1.42.0/mutagen/_file.py
--- old/mutagen-1.41.0/mutagen/_file.py 2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/_file.py 2018-11-17 11:56:49.000000000 +0100
@@ -97,7 +97,7 @@
             return self.tags.keys()
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """delete(filething=None)
 
         Remove tags from a file.
@@ -120,7 +120,7 @@
             return self.tags.delete(filething)
 
     @loadfile(writable=True)
-    def save(self, filething, **kwargs):
+    def save(self, filething=None, **kwargs):
         """save(filething=None, **kwargs)
 
         Save metadata tags.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/_tags.py 
new/mutagen-1.42.0/mutagen/_tags.py
--- old/mutagen-1.41.0/mutagen/_tags.py 2017-05-25 15:49:20.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/_tags.py 2018-11-17 11:56:49.000000000 +0100
@@ -115,7 +115,7 @@
         raise NotImplementedError
 
     @loadfile(writable=False)
-    def save(self, filething, **kwargs):
+    def save(self, filething=None, **kwargs):
         """save(filething=None, **kwargs)
 
         Save changes to a file.
@@ -129,7 +129,7 @@
         raise NotImplementedError
 
     @loadfile(writable=False)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """delete(filething=None)
 
         Remove tags from a file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/_tools/mid3v2.py 
new/mutagen-1.42.0/mutagen/_tools/mid3v2.py
--- old/mutagen-1.41.0/mutagen/_tools/mid3v2.py 2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/_tools/mid3v2.py 2018-12-16 14:47:44.000000000 
+0100
@@ -11,6 +11,7 @@
 import sys
 import codecs
 import mimetypes
+import warnings
 
 from optparse import SUPPRESS_HELP
 
@@ -137,7 +138,11 @@
         if PY2:
             bytes_ = bytes_.decode("string_escape")
         else:
-            bytes_ = codecs.escape_decode(bytes_)[0]
+            # With py3.7 this has started to warn for invalid escapes, but we
+            # don't control the input so ignore it.
+            with warnings.catch_warnings():
+                warnings.simplefilter("ignore")
+                bytes_ = codecs.escape_decode(bytes_)[0]
         arg = bytes2fsn(bytes_)
 
     text = fsn2text(arg, strict=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/_vorbis.py 
new/mutagen-1.42.0/mutagen/_vorbis.py
--- old/mutagen-1.41.0/mutagen/_vorbis.py       2017-05-25 15:49:20.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/_vorbis.py       2018-11-08 18:50:38.000000000 
+0100
@@ -157,18 +157,20 @@
         for key, value in self:
             try:
                 if not is_valid_key(key):
-                    raise ValueError
+                    raise ValueError("%r is not a valid key" % key)
             except TypeError:
                 raise ValueError("%r is not a valid key" % key)
 
             if not isinstance(value, text_type):
                 if PY3:
-                    raise ValueError("%r needs to be str" % key)
+                    err = "%r needs to be str for key %r" % (value, key)
+                    raise ValueError(err)
 
                 try:
                     value.decode("utf-8")
                 except Exception:
-                    raise ValueError("%r is not a valid value" % value)
+                    err = "%r is not a valid value for key %r" % (value, key)
+                    raise ValueError(err)
 
         return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/aiff.py 
new/mutagen-1.42.0/mutagen/aiff.py
--- old/mutagen-1.41.0/mutagen/aiff.py  2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/aiff.py  2018-11-17 11:56:49.000000000 +0100
@@ -271,7 +271,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def save(self, filething, v2_version=4, v23_sep='/', padding=None):
+    def save(self, filething=None, v2_version=4, v23_sep='/', padding=None):
         """Save ID3v2 data to the AIFF file"""
 
         fileobj = filething.fileobj
@@ -299,7 +299,7 @@
         chunk.write(data)
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """Completely removes the ID3 chunk from the AIFF file"""
 
         delete(filething)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/apev2.py 
new/mutagen-1.42.0/mutagen/apev2.py
--- old/mutagen-1.41.0/mutagen/apev2.py 2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/apev2.py 2018-11-17 11:56:49.000000000 +0100
@@ -419,7 +419,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True, create=True)
-    def save(self, filething):
+    def save(self, filething=None):
         """Save changes to a file.
 
         If no filename is given, the one most recently loaded is used.
@@ -481,7 +481,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """Remove tags from a file."""
 
         fileobj = filething.fileobj
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/asf/__init__.py 
new/mutagen-1.42.0/mutagen/asf/__init__.py
--- old/mutagen-1.41.0/mutagen/asf/__init__.py  2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/asf/__init__.py  2018-11-17 11:56:49.000000000 
+0100
@@ -252,7 +252,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def save(self, filething, padding=None):
+    def save(self, filething=None, padding=None):
         """save(filething=None, padding=None)
 
         Save tag changes back to the loaded file.
@@ -319,7 +319,7 @@
         raise ASFError
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """delete(filething=None)
 
         Args:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/dsf.py 
new/mutagen-1.42.0/mutagen/dsf.py
--- old/mutagen-1.41.0/mutagen/dsf.py   2017-05-25 15:49:20.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/dsf.py   2018-11-17 11:56:49.000000000 +0100
@@ -199,7 +199,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def save(self, filething, v2_version=4, v23_sep='/', padding=None):
+    def save(self, filething=None, v2_version=4, v23_sep='/', padding=None):
         """Save ID3v2 data to the DSF file"""
 
         fileobj = filething.fileobj
@@ -328,7 +328,7 @@
         self.info = DSFInfo(dsf_file.fmt_chunk)
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         self.tags = None
         delete(filething)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/easyid3.py 
new/mutagen-1.42.0/mutagen/easyid3.py
--- old/mutagen-1.41.0/mutagen/easyid3.py       2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/easyid3.py       2018-11-17 11:56:49.000000000 
+0100
@@ -173,7 +173,8 @@
                     lambda s, v: setattr(s.__id3, 'load', v))
 
     @loadfile(writable=True, create=True)
-    def save(self, filething, v1=1, v2_version=4, v23_sep='/', padding=None):
+    def save(self, filething=None, v1=1, v2_version=4, v23_sep='/',
+             padding=None):
         """save(filething=None, v1=1, v2_version=4, v23_sep='/', padding=None)
 
         Save changes to a file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/flac.py 
new/mutagen-1.42.0/mutagen/flac.py
--- old/mutagen-1.41.0/mutagen/flac.py  2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/flac.py  2018-11-17 11:56:49.000000000 +0100
@@ -394,7 +394,7 @@
         isrc (`mutagen.text`): ISRC code, exactly 12 characters
         type (`int`): 0 for audio, 1 for digital data
         pre_emphasis (`bool`): true if the track is recorded with pre-emphasis
-        indexes (List[`mutagen.flac.CueSheetTrackIndex`]):
+        indexes (list[CueSheetTrackIndex]):
             list of CueSheetTrackIndex objects
     """
 
@@ -442,9 +442,9 @@
         lead_in_samples (`int`): number of lead-in samples
         compact_disc (`bool`): true if the cuesheet corresponds to a
             compact disc
-        tracks (List[`mutagen.flac.CueSheetTrack`]):
+        tracks (list[CueSheetTrack]):
             list of CueSheetTrack objects
-        lead_out (`mutagen.flac.CueSheetTrack` or `None`):
+        lead_out (`CueSheetTrack` or `None`):
             lead-out as CueSheetTrack or None if lead-out was not found
     """
 
@@ -678,7 +678,7 @@
     Attributes:
         cuesheet (`CueSheet`): if any or `None`
         seektable (`SeekTable`): if any or `None`
-        pictures (List[`Picture`]): list of embedded pictures
+        pictures (list[Picture]): list of embedded pictures
         info (`StreamInfo`)
         tags (`mutagen._vorbis.VCommentDict`)
     """
@@ -757,7 +757,7 @@
     add_vorbiscomment = add_tags
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """Remove Vorbis comments from a file.
 
         If no filename is given, the one most recently loaded is used.
@@ -823,16 +823,13 @@
 
     @property
     def pictures(self):
-        """
-        Returns:
-            List[`Picture`]: List of embedded pictures
-        """
+        """list[Picture]: List of embedded pictures"""
 
         return [b for b in self.metadata_blocks if b.code == Picture.code]
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def save(self, filething, deleteid3=False, padding=None):
+    def save(self, filething=None, deleteid3=False, padding=None):
         """Save metadata blocks to a file.
 
         Args:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/id3/_file.py 
new/mutagen-1.42.0/mutagen/id3/_file.py
--- old/mutagen-1.41.0/mutagen/id3/_file.py     2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/id3/_file.py     2018-12-26 14:46:04.000000000 
+0100
@@ -53,8 +53,8 @@
         filething (filething): or `None`
 
     Attributes:
-        version (Tuple[int]): ID3 tag version as a tuple
-        unknown_frames (List[bytes]): raw frame data of any unknown frames
+        version (tuple[int]): ID3 tag version as a tuple
+        unknown_frames (list[bytes]): raw frame data of any unknown frames
             found
         size (int): the total size of the ID3 tag, including the header
     """
@@ -112,10 +112,9 @@
 
     @convert_error(IOError, error)
     @loadfile()
-    def load(self, filething, known_frames=None, translate=True, v2_version=4):
-        """load(filething, known_frames=None, translate=True, v2_version=4)
-
-        Load tags from a filename.
+    def load(self, filething, known_frames=None, translate=True, v2_version=4,
+             load_v1=True):
+        """Load tags from a filename.
 
         Args:
             filename (filething): filename or file object to load tag data from
@@ -126,6 +125,11 @@
                 call update_to_v23() / update_to_v24() manually.
             v2_version (int): if update_to_v23 or update_to_v24 get called
                 (3 or 4)
+            load_v1 (bool): Load tags from ID3v1 header if present. If both
+                ID3v1 and ID3v2 headers are present, combine the tags from
+                the two, with ID3v2 having precedence.
+
+                .. versionadded:: 1.42
 
         Example of loading a custom frame::
 
@@ -149,13 +153,17 @@
         try:
             self._header = ID3Header(fileobj)
         except (ID3NoHeaderError, ID3UnsupportedVersionError):
-            frames, offset = find_id3v1(fileobj)
+            if not load_v1:
+                raise
+
+            frames, offset = find_id3v1(fileobj, v2_version, known_frames)
             if frames is None:
                 raise
 
             self.version = ID3Header._V11
             for v in frames.values():
-                self.add(v)
+                if len(self.getall(v.HashKey)) == 0:
+                    self.add(v)
         else:
             # XXX: attach to the header object so we have it in spec parsing..
             if known_frames is not None:
@@ -165,6 +173,14 @@
             remaining_data = self._read(self._header, data)
             self._padding = len(remaining_data)
 
+            if load_v1:
+                v1v2_ver = 4 if self.version[1] == 4 else 3
+                frames, offset = find_id3v1(fileobj, v1v2_ver, known_frames)
+                if frames:
+                    for v in frames.values():
+                        if len(self.getall(v.HashKey)) == 0:
+                            self.add(v)
+
         if translate:
             if v2_version == 3:
                 self.update_to_v23()
@@ -204,13 +220,14 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True, create=True)
-    def save(self, filething, v1=1, v2_version=4, v23_sep='/', padding=None):
+    def save(self, filething=None, v1=1, v2_version=4, v23_sep='/',
+             padding=None):
         """save(filething=None, v1=1, v2_version=4, v23_sep='/', padding=None)
 
         Save changes to a file.
 
         Args:
-            filename (fspath):
+            filething (filething):
                 Filename to save the tag to. If no filename is given,
                 the one most recently loaded is used.
             v1 (ID3v1SaveOptions):
@@ -268,7 +285,7 @@
             f.truncate()
 
     @loadfile(writable=True)
-    def delete(self, filething, delete_v1=True, delete_v2=True):
+    def delete(self, filething=None, delete_v1=True, delete_v2=True):
         """delete(filething=None, delete_v1=True, delete_v2=True)
 
         Remove tags from a file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/id3/_frames.py 
new/mutagen-1.42.0/mutagen/id3/_frames.py
--- old/mutagen-1.41.0/mutagen/id3/_frames.py   2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/id3/_frames.py   2018-11-08 18:50:38.000000000 
+0100
@@ -1095,13 +1095,18 @@
     def HashKey(self):
         return '%s:%s:%s' % (self.FrameID, self.desc, self.lang)
 
+    def _pprint(self):
+        return str(self)
+
     def __eq__(self, other):
         return str(self) == other
 
     __hash__ = Frame.__hash__
 
     def __str__(self):
-        return u"".join(text for (text, time) in self.text)
+        unit = 'fr' if self.format == 1 else 'ms'
+        return u"\n".join("[{0}{1}]: {2}".format(time, unit, text)
+                          for (text, time) in self.text)
 
     def __bytes__(self):
         return text_type(self).encode("utf-8")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/id3/_id3v1.py 
new/mutagen-1.42.0/mutagen/id3/_id3v1.py
--- old/mutagen-1.41.0/mutagen/id3/_id3v1.py    2017-05-25 15:49:20.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/id3/_id3v1.py    2018-11-08 18:50:38.000000000 
+0100
@@ -13,20 +13,30 @@
 
 from mutagen._util import chr_, text_type
 
-from ._frames import TCON, TRCK, COMM, TDRC, TALB, TPE1, TIT2
+from ._frames import TCON, TRCK, COMM, TDRC, TYER, TALB, TPE1, TIT2
 
 
-def find_id3v1(fileobj):
+def find_id3v1(fileobj, v2_version=4, known_frames=None):
     """Returns a tuple of (id3tag, offset_to_end) or (None, 0)
 
     offset mainly because we used to write too short tags in some cases and
     we need the offset to delete them.
+
+    v2_version: Decides whether ID3v2.3 or ID3v2.4 tags
+                should be returned. Must be 3 or 4.
+
+    known_frames (Dict[`mutagen.text`, `Frame`]): dict mapping frame
+        IDs to Frame objects
     """
 
+    if v2_version not in (3, 4):
+        raise ValueError("Only 3 and 4 possible for v2_version")
+
     # id3v1 is always at the end (after apev2)
 
     extra_read = b"APETAGEX".index(b"TAG")
 
+    old_pos = fileobj.tell()
     try:
         fileobj.seek(-128 - extra_read, 2)
     except IOError as e:
@@ -38,6 +48,7 @@
             raise
 
     data = fileobj.read(128 + extra_read)
+    fileobj.seek(old_pos, 0)
     try:
         idx = data.index(b"TAG")
     except ValueError:
@@ -53,7 +64,7 @@
             if idx == ape_idx + extra_read:
                 return (None, 0)
 
-        tag = ParseID3v1(data[idx:])
+        tag = ParseID3v1(data[idx:], v2_version, known_frames)
         if tag is None:
             return (None, 0)
 
@@ -62,12 +73,21 @@
 
 
 # ID3v1.1 support.
-def ParseID3v1(data):
-    """Parse an ID3v1 tag, returning a list of ID3v2.4 frames.
+def ParseID3v1(data, v2_version=4, known_frames=None):
+    """Parse an ID3v1 tag, returning a list of ID3v2 frames
 
     Returns a {frame_name: frame} dict or None.
+
+    v2_version: Decides whether ID3v2.3 or ID3v2.4 tags
+                should be returned. Must be 3 or 4.
+
+    known_frames (Dict[`mutagen.text`, `Frame`]): dict mapping frame
+        IDs to Frame objects
     """
 
+    if v2_version not in (3, 4):
+        raise ValueError("Only 3 and 4 possible for v2_version")
+
     try:
         data = data[data.index(b"TAG"):]
     except ValueError:
@@ -97,23 +117,45 @@
     title, artist, album, year, comment = map(
         fix, [title, artist, album, year, comment])
 
+    frame_class = {
+        "TIT2": TIT2,
+        "TPE1": TPE1,
+        "TALB": TALB,
+        "TYER": TYER,
+        "TDRC": TDRC,
+        "COMM": COMM,
+        "TRCK": TRCK,
+        "TCON": TCON,
+    }
+    for key in frame_class:
+        if known_frames is not None:
+            if key in known_frames:
+                frame_class[key] = known_frames[key]
+            else:
+                frame_class[key] = None
+
     frames = {}
-    if title:
-        frames["TIT2"] = TIT2(encoding=0, text=title)
-    if artist:
-        frames["TPE1"] = TPE1(encoding=0, text=[artist])
-    if album:
-        frames["TALB"] = TALB(encoding=0, text=album)
+    if title and frame_class["TIT2"]:
+        frames["TIT2"] = frame_class["TIT2"](encoding=0, text=title)
+    if artist and frame_class["TPE1"]:
+        frames["TPE1"] = frame_class["TPE1"](encoding=0, text=[artist])
+    if album and frame_class["TALB"]:
+        frames["TALB"] = frame_class["TALB"](encoding=0, text=album)
     if year:
-        frames["TDRC"] = TDRC(encoding=0, text=year)
-    if comment:
-        frames["COMM"] = COMM(
-            encoding=0, lang="eng", desc="ID3v1 Comment", text=comment)
+        if v2_version == 3 and frame_class["TYER"]:
+            frames["TYER"] = frame_class["TYER"](encoding=0, text=year)
+        elif frame_class["TDRC"]:
+            frames["TDRC"] = frame_class["TDRC"](encoding=0, text=year)
+    if comment and frame_class["COMM"]:
+            frames["COMM"] = frame_class["COMM"](
+                encoding=0, lang="eng", desc="ID3v1 Comment", text=comment)
+
     # Don't read a track number if it looks like the comment was
     # padded with spaces instead of nulls (thanks, WinAmp).
-    if track and ((track != 32) or (data[-3] == b'\x00'[0])):
+    if (track and frame_class["TRCK"] and
+            ((track != 32) or (data[-3] == b'\x00'[0]))):
         frames["TRCK"] = TRCK(encoding=0, text=str(track))
-    if genre != 255:
+    if genre != 255 and frame_class["TCON"]:
         frames["TCON"] = TCON(encoding=0, text=str(genre))
     return frames
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/id3/_tags.py 
new/mutagen-1.42.0/mutagen/id3/_tags.py
--- old/mutagen-1.41.0/mutagen/id3/_tags.py     2017-05-25 15:49:20.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/id3/_tags.py     2018-11-23 12:13:22.000000000 
+0100
@@ -243,7 +243,7 @@
 
         Args:
             key (text): key for frames to delete
-            values (List[`Frame`]): frames to add
+            values (list[Frame]): frames to add
         """
 
         self.delall(key)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/mp4/__init__.py 
new/mutagen-1.42.0/mutagen/mp4/__init__.py
--- old/mutagen-1.41.0/mutagen/mp4/__init__.py  2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/mutagen/mp4/__init__.py  2018-12-24 12:30:05.000000000 
+0100
@@ -392,7 +392,7 @@
 
     @convert_error(IOError, error)
     @loadfile(writable=True)
-    def save(self, filething, padding=None):
+    def save(self, filething=None, padding=None):
 
         values = []
         items = sorted(self.items(), key=lambda kv: _item_sort_key(*kv))
@@ -716,7 +716,8 @@
                 # by itunes for compatibility.
                 if cdata.int8_min <= v <= cdata.int8_max and min_bytes <= 1:
                     data = cdata.to_int8(v)
-                if cdata.int16_min <= v <= cdata.int16_max and min_bytes <= 2:
+                elif cdata.int16_min <= v <= cdata.int16_max and \
+                        min_bytes <= 2:
                     data = cdata.to_int16_be(v)
                 elif cdata.int32_min <= v <= cdata.int32_max and \
                         min_bytes <= 4:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/mutagen/ogg.py 
new/mutagen-1.42.0/mutagen/ogg.py
--- old/mutagen-1.41.0/mutagen/ogg.py   2018-07-08 23:33:34.000000000 +0200
+++ new/mutagen-1.42.0/mutagen/ogg.py   2018-11-17 11:56:49.000000000 +0100
@@ -50,7 +50,7 @@
         offset (`int` or `None`): offset this page was read from (default None)
         complete (`bool`): if the last packet on this page is complete
             (default True)
-        packets (List[`bytes`]): list of raw packet data (default [])
+        packets (list[bytes]): list of raw packet data (default [])
 
     Note that if 'complete' is false, the next page's 'continued'
     property must be true (so set both when constructing pages).
@@ -535,7 +535,7 @@
             raise self._Error("no appropriate stream found")
 
     @loadfile(writable=True)
-    def delete(self, filething):
+    def delete(self, filething=None):
         """delete(filething=None)
 
         Remove tags from a file.
@@ -567,7 +567,7 @@
         raise self._Error
 
     @loadfile(writable=True)
-    def save(self, filething, padding=None):
+    def save(self, filething=None, padding=None):
         """save(filething=None, padding=None)
 
         Save a tag to a file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/setup.py new/mutagen-1.42.0/setup.py
--- old/mutagen-1.41.0/setup.py 2018-07-16 21:00:52.000000000 +0200
+++ new/mutagen-1.42.0/setup.py 2018-12-16 14:42:15.000000000 +0100
@@ -81,7 +81,7 @@
 
             tracked_files = out.splitlines()
             for ignore in [".travis.yml", ".gitignore", ".codecov.yml",
-                           ".appveyor.yml"]:
+                           "azure-pipelines.yml"]:
                 tracked_files.remove(ignore)
 
             diff = set(tracked_files) - set(included_files)
@@ -258,7 +258,7 @@
           description="read and write audio tags for many formats",
           author="Michael Urman",
           author_email="quod-libet-developm...@groups.google.com",
-          license="GNU GPL v2",
+          license="GPL-2.0-or-later",
           classifiers=[
             'Operating System :: OS Independent',
             'Programming Language :: Python :: 2',
@@ -270,7 +270,8 @@
             'Programming Language :: Python :: 3.7',
             'Programming Language :: Python :: Implementation :: CPython',
             'Programming Language :: Python :: Implementation :: PyPy',
-            'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
+            ('License :: OSI Approved :: '
+             'GNU General Public License v2 or later (GPLv2+)'),
             'Topic :: Multimedia :: Sound/Audio',
           ],
           packages=[
Binary files old/mutagen-1.41.0/tests/data/id3v1v2-combined.mp3 and 
new/mutagen-1.42.0/tests/data/id3v1v2-combined.mp3 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/tests/test__id3frames.py 
new/mutagen-1.42.0/tests/test__id3frames.py
--- old/mutagen-1.41.0/tests/test__id3frames.py 2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/tests/test__id3frames.py 2018-11-08 18:50:38.000000000 
+0100
@@ -181,7 +181,8 @@
         ],
         [
             'SYLT', (b'\x00eng\x02\x01some lyrics\x00foo\x00\x00\x00\x00\x01'
-                     b'bar\x00\x00\x00\x00\x10'), "foobar", '',
+                     b'bar\x00\x00\x00\x00\x10'),
+            "[1ms]: foo\n[16ms]: bar", '',
             dict(encoding=0, lang='eng', type=1, format=2, desc='some lyrics')
         ],
         ['POSS', b'\x01\x0f', 15, 15, dict(format=1, position=15)],
@@ -330,7 +331,7 @@
         [
             'SLT', (b'\x00eng\x02\x01some lyrics\x00foo\x00\x00\x00\x00\x01bar'
                     b'\x00\x00\x00\x00\x10'),
-            "foobar", '',
+            "[1ms]: foo\n[16ms]: bar", '',
             dict(encoding=0, lang='eng', type=1, format=2, desc='some lyrics')
         ],
         ['TT1', b'\x00ab\x00', 'ab', '', dict(encoding=0)],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/tests/test_id3.py 
new/mutagen-1.42.0/tests/test_id3.py
--- old/mutagen-1.41.0/tests/test_id3.py        2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/tests/test_id3.py        2018-11-08 18:50:38.000000000 
+0100
@@ -30,9 +30,11 @@
 
     empty = os.path.join(DATA_DIR, 'emptyfile.mp3')
     silence = os.path.join(DATA_DIR, 'silence-44-s.mp3')
+    silence_v1 = os.path.join(DATA_DIR, 'silence-44-s-v1.mp3')
     unsynch = os.path.join(DATA_DIR, 'id3v23_unsynch.id3')
     v22 = os.path.join(DATA_DIR, "id3v22-test.mp3")
     bad_tyer = os.path.join(DATA_DIR, 'bad-TYER-frame.mp3')
+    v1v2_combined = os.path.join(DATA_DIR, "id3v1v2-combined.mp3")
 
     def test_PIC_in_23(self):
         filename = get_temp_empty(".mp3")
@@ -112,6 +114,95 @@
         self.failUnless(tags["TRCK"].text == ["3/11"])
         self.failUnless(tags["TPE1"].text == ["Anais Mitchell"])
 
+    def test_load_v1(self):
+        tags = ID3(self.silence_v1)
+        self.assertEquals(tags["TALB"], "Quod Libet Test Data")
+
+        with self.assertRaises(ID3NoHeaderError):
+            tags = ID3(self.silence_v1, load_v1=False)
+
+    def test_load_v1_v2(self):
+        tags = ID3(self.v1v2_combined)
+        # From ID3v2
+        self.assertEquals(tags["TPE1"].text, ["Anais Mitchell"])
+        # From ID3v1
+        self.assertEquals(tags["TALB"].text, ["Hymns for the Exiled"])
+
+        tags = ID3(self.v1v2_combined, load_v1=False)
+        self.assertEquals(tags["TPE1"].text, ["Anais Mitchell"])
+        with self.assertRaises(KeyError):
+            tags["TALB"]
+
+    def test_load_v1_v2_no_translate(self):
+        tags = ID3(self.v1v2_combined, v2_version=4, translate=False)
+        assert tags.version == (2, 4, 0)
+        assert str(tags["TDRC"].text[0]) == "1337"
+        tags = ID3(self.v1v2_combined, v2_version=3, translate=False)
+        assert tags.version == (2, 4, 0)
+        assert str(tags["TDRC"].text[0]) == "1337"
+
+    def test_load_v1_v2_tcon_translate(self):
+        tags = ID3()
+        tags.add(TCON(text=["12"]))
+        v1_data = MakeID3v1(tags)
+
+        filename = get_temp_copy(self.empty)
+        try:
+            tags = ID3()
+            tags.save(filename=filename, v1=0)
+            with open(filename, "ab") as h:
+                h.write(v1_data)
+            tags = ID3(filename, load_v1=True)
+            assert tags["TCON"][0] == "Other"
+            tags = ID3(filename, load_v1=False)
+            assert "TCON" not in tags
+        finally:
+            os.unlink(filename)
+
+    def test_load_v1_v2_precedence(self):
+        tags = ID3(self.v1v2_combined)
+        self.assertEquals(tags["TRCK"].text, ["3/11"])  # i.e. not 123
+
+        # ID3v2 has TYER=2004 (which isn't a valid v2.4 frame),
+        # ID3v1 has TDRC=1337.
+        self.assertEquals(str(tags["TDRC"].text[0]), "1337")
+        with self.assertRaises(KeyError):
+            tags["TYER"]
+
+        tags = ID3(self.v1v2_combined, v2_version=3)
+
+        # With v2_version=3, the ID3v2 tag should still have precedence
+        self.assertEquals(str(tags["TYER"].text[0]), "2004")
+        with self.assertRaises(KeyError):
+            tags["TDRC"]
+
+    def test_load_v1_comment(self):
+        # Tags with different HashKeys but equal FrameIDs (like COMM)
+        # should be kept separate
+        tags = ID3(self.v1v2_combined)
+        comments = tags.getall("COMM")
+        # From ID3v2
+        self.failUnless("Waterbug Records, www.anaismitchell.com" in comments)
+        # From ID3v1
+        self.failUnless("v1 comment" in comments)
+
+    def test_load_v1_known_frames_override(self):
+        class MyCOMM(COMM):
+            @property
+            def FrameID(self):
+                # We want to replace the existing COMM, so override
+                # the FrameID
+                return COMM.__name__
+
+        frames = dict(id3.Frames)
+        frames["COMM"] = MyCOMM
+        tags = ID3(self.v1v2_combined, known_frames=frames)
+
+        comments = tags.getall("COMM")
+        self.failUnless(len(comments) > 0)
+        for comm in comments:
+            self.assertIsInstance(comm, MyCOMM)
+
     def test_empty_file(self):
         self.assertRaises(ID3Error, ID3, filename=self.empty)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mutagen-1.41.0/tests/test_mp4.py 
new/mutagen-1.42.0/tests/test_mp4.py
--- old/mutagen-1.41.0/tests/test_mp4.py        2018-07-08 23:33:34.000000000 
+0200
+++ new/mutagen-1.42.0/tests/test_mp4.py        2018-08-11 14:06:18.000000000 
+0200
@@ -272,6 +272,17 @@
             b"\x00\x00\x00\x15\x00\x00\x00\x00\x00"
         )
 
+    def test_render_integer_min_size(self):
+        render_int = MP4Tags()._MP4Tags__render_integer
+
+        data = render_int('stik', [42], 1)
+        tags = self.wrap_ilst(data)
+        assert tags['stik'] == [42]
+
+        assert len(render_int('stik', [42], 2)) == len(data) + 1
+        assert len(render_int('stik', [42], 4)) == len(data) + 3
+        assert len(render_int('stik', [42], 8)) == len(data) + 7
+
     def test_render_text(self):
         self.failUnlessEqual(
             MP4Tags()._MP4Tags__render_text(


Reply via email to