diff --git a/beets/dbcore/types.py b/beets/dbcore/types.py index 573775467..4862d39b4 100644 --- a/beets/dbcore/types.py +++ b/beets/dbcore/types.py @@ -55,6 +55,7 @@ class Type(object): type, normalize the value to have the appropriate type. This base implementation only reinterprets `None`. """ + # TODO gradually remove the normalization of None. if value is None: return self.null else: @@ -131,6 +132,12 @@ class Float(Type): return 0.0 +class NullFloat(Float): + """Same as `Float`, but does not normalize `None` to `0.0`. + """ + null = None + + class String(Type): """A Unicode string type. """ diff --git a/beets/library.py b/beets/library.py index d053784fc..ca5ece778 100644 --- a/beets/library.py +++ b/beets/library.py @@ -245,10 +245,10 @@ class Item(LibModel): 'albumdisambig': types.String(), 'disctitle': types.String(), 'encoder': types.String(), - 'rg_track_gain': types.Float(), - 'rg_track_peak': types.Float(), - 'rg_album_gain': types.Float(), - 'rg_album_peak': types.Float(), + 'rg_track_gain': types.NullFloat(), + 'rg_track_peak': types.NullFloat(), + 'rg_album_gain': types.NullFloat(), + 'rg_album_peak': types.NullFloat(), 'original_year': types.PaddedInt(4), 'original_month': types.PaddedInt(2), 'original_day': types.PaddedInt(2), @@ -628,8 +628,8 @@ class Album(LibModel): 'albumstatus': types.String(), 'media': types.String(), 'albumdisambig': types.String(), - 'rg_album_gain': types.Float(), - 'rg_album_peak': types.Float(), + 'rg_album_gain': types.NullFloat(), + 'rg_album_peak': types.NullFloat(), 'original_year': types.PaddedInt(4), 'original_month': types.PaddedInt(2), 'original_day': types.PaddedInt(2), diff --git a/test/helper.py b/test/helper.py index 2efb6d9a1..7be39729a 100644 --- a/test/helper.py +++ b/test/helper.py @@ -16,7 +16,7 @@ import sys import os import os.path import shutil -import tempfile +from tempfile import mkdtemp, mkstemp from glob import glob from contextlib import contextmanager from StringIO import StringIO @@ -36,7 +36,7 @@ def controlStdin(input=None): """Sends ``input`` to stdin. >>> with controlStdin('yes'): - ... in = input() + ... input() 'yes' """ org = sys.stdin @@ -47,6 +47,7 @@ def controlStdin(input=None): finally: sys.stdin = org + class TestHelper(object): """Helper mixin for high-level cli and plugin tests. @@ -77,7 +78,7 @@ class TestHelper(object): Make sure you call ``teardown_beets()`` afterwards. """ - self.temp_dir = tempfile.mkdtemp() + self.temp_dir = mkdtemp() os.environ['BEETSDIR'] = self.temp_dir self.config = beets.config @@ -152,5 +153,15 @@ class TestHelper(object): items.append(item) return items + def create_file_fixture(self, pattern='*.mp3'): + """Copies a file matching the glob pattern to a temporary + location and returns the path. + """ + src = glob(os.path.join(_common.RSRC, pattern))[0] + handle, path = mkstemp() + os.close(handle) + shutil.copy(src, path) + return path + def run_command(self, *args): beets.ui._raw_main(list(args)) diff --git a/test/test_replaygain.py b/test/test_replaygain.py index 39a765465..f28d11a21 100644 --- a/test/test_replaygain.py +++ b/test/test_replaygain.py @@ -90,25 +90,25 @@ class ReplayGainCliTestBase(object): self._reset_replaygain(item) def _reset_replaygain(self, item): - item['rg_track_peak'] = 0 - item['rg_track_gain'] = 0 - item['rg_album_gain'] = 0 - item['rg_album_gain'] = 0 + item['rg_track_peak'] = None + item['rg_track_gain'] = None + item['rg_album_gain'] = None + item['rg_album_gain'] = None item.write() item.store() def test_cli_saves_track_gain(self): for item in self.lib.items(): - self.assertEqual(item.rg_track_peak, 0.0) - self.assertEqual(item.rg_track_gain, 0.0) + self.assertIsNone(item.rg_track_peak) + self.assertIsNone(item.rg_track_gain) mediafile = MediaFile(item.path) - self.assertEqual(mediafile.rg_track_peak, 0.0) - self.assertEqual(mediafile.rg_track_gain, 0.0) + self.assertIsNone(mediafile.rg_track_peak) + self.assertIsNone(mediafile.rg_track_gain) ui._raw_main(['replaygain']) for item in self.lib.items(): - self.assertNotEqual(item.rg_track_peak, 0.0) - self.assertNotEqual(item.rg_track_gain, 0.0) + self.assertIsNotNone(item.rg_track_peak) + self.assertIsNotNone(item.rg_track_gain) mediafile = MediaFile(item.path) self.assertAlmostEqual( mediafile.rg_track_peak, item.rg_track_peak, places=6) @@ -127,8 +127,8 @@ class ReplayGainCliTestBase(object): def test_cli_saves_album_gain_to_file(self): for item in self.lib.items(): mediafile = MediaFile(item.path) - self.assertEqual(mediafile.rg_album_peak, 0.0) - self.assertEqual(mediafile.rg_album_gain, 0.0) + self.assertIsNone(mediafile.rg_album_peak) + self.assertIsNone(mediafile.rg_album_gain) ui._raw_main(['replaygain', '-a']) diff --git a/test/test_zero.py b/test/test_zero.py index 333ca2b51..6ad552f3b 100644 --- a/test/test_zero.py +++ b/test/test_zero.py @@ -1,11 +1,21 @@ """Tests for the 'zero' plugin""" from _common import unittest +from helper import TestHelper + + from beets.library import Item +from beets import config from beetsplug.zero import ZeroPlugin +from beets.mediafile import MediaFile -class ZeroPluginTest(unittest.TestCase): +class ZeroPluginTest(unittest.TestCase, TestHelper): + + def tearDown(self): + config.clear() + self.unload_plugins() + def test_no_patterns(self): i = Item( comments='test comment', @@ -39,6 +49,25 @@ class ZeroPluginTest(unittest.TestCase): self.assertEqual(i.comments, '') self.assertEqual(i.year, 2012) + def test_delete_replaygain_tag(self): + path = self.create_file_fixture() + item = Item.from_path(path) + item.rg_track_peak = 0.0 + item.write() + + mediafile = MediaFile(item.path) + self.assertIsNotNone(mediafile.rg_track_peak) + + config['zero'] = { + 'fields': ['rg_track_peak'], + } + self.load_plugins('zero') + + item.write() + mediafile = MediaFile(item.path) + self.assertIsNone(mediafile.rg_track_peak) + + def suite(): return unittest.TestLoader().loadTestsFromName(__name__)