import os
import pickle
from mutagen import MutagenError
from mutagen.id3 import ID3FileType, ID3, RVA2, CHAP, TDRC, CTOC
from mutagen.easyid3 import EasyID3, error as ID3Error
from tests import TestCase, DATA_DIR, get_temp_copy
class TEasyID3(TestCase):
def setUp(self):
self.filename = get_temp_copy(os.path.join(DATA_DIR, 'emptyfile.mp3'))
self.id3 = EasyID3()
self.realid3 = self.id3._EasyID3__id3
def tearDown(self):
os.unlink(self.filename)
def test_size_attr(self):
assert self.id3.size == self.realid3.size
def test_load_filename(self):
self.id3.save(self.filename)
self.id3.load(self.filename)
assert self.id3.filename == self.filename
path = os.path.join(DATA_DIR, 'silence-44-s.mp3')
new = EasyID3(path)
assert new.filename == path
def test_txxx_latin_first_then_non_latin(self):
self.id3["performer"] = [u"foo"]
self.id3["performer"] = [u"\u0243"]
self.id3.save(self.filename)
new = EasyID3(self.filename)
self.assertEqual(new["performer"], [u"\u0243"])
def test_remember_ctr(self):
empty = os.path.join(DATA_DIR, 'emptyfile.mp3')
mp3 = ID3FileType(empty, ID3=EasyID3)
self.failIf(mp3.tags)
mp3["artist"] = ["testing"]
self.failUnless(mp3.tags)
mp3.pprint()
self.failUnless(isinstance(mp3.tags, EasyID3))
def test_save_23(self):
self.id3.save(self.filename, v2_version=3)
self.assertEqual(ID3(self.filename).version, (2, 3, 0))
self.id3.save(self.filename, v2_version=4)
self.assertEqual(ID3(self.filename).version, (2, 4, 0))
def test_save_date_v23(self):
self.id3["date"] = "2004"
assert self.realid3.getall("TDRC")[0] == u"2004"
self.id3.save(self.filename, v2_version=3)
assert self.realid3.getall("TDRC")[0] == u"2004"
assert not self.realid3.getall("TYER")
new = ID3(self.filename, translate=False)
assert new.version == (2, 3, 0)
assert new.getall("TYER")[0] == u"2004"
def test_save_v23_error_restore(self):
self.id3["date"] = "2004"
with self.assertRaises(MutagenError):
self.id3.save("", v2_version=3)
assert self.id3["date"] == ["2004"]
def test_save_v23_recurse_restore(self):
self.realid3.add(CHAP(sub_frames=[TDRC(text="2006")]))
self.realid3.add(CTOC(sub_frames=[TDRC(text="2006")]))
self.id3.save(self.filename, v2_version=3)
for frame_id in ["CHAP", "CTOC"]:
chap = self.realid3.getall(frame_id)[0]
assert chap.sub_frames.getall("TDRC")[0] == "2006"
new = ID3(self.filename, translate=False)
assert new.version == (2, 3, 0)
chap = new.getall(frame_id)[0]
assert not chap.sub_frames.getall("TDRC")
assert chap.sub_frames.getall("TYER")[0] == "2006"
def test_delete(self):
self.id3["artist"] = "foobar"
self.id3.save(self.filename)
self.failUnless(os.path.getsize(self.filename))
self.id3.delete(self.filename)
self.failIf(os.path.getsize(self.filename))
self.failIf(self.id3)
def test_pprint(self):
self.id3["artist"] = "baz"
self.id3.pprint()
def test_in(self):
self.failIf("foo" in self.id3)
def test_empty_file(self):
empty = os.path.join(DATA_DIR, 'emptyfile.mp3')
self.assertRaises(ID3Error, EasyID3, filename=empty)
def test_nonexistent_file(self):
empty = os.path.join(DATA_DIR, 'does', 'not', 'exist')
self.assertRaises(MutagenError, EasyID3, filename=empty)
def test_write_single(self):
for key in EasyID3.valid_keys:
if (key == "date") or (key == "originaldate"):
continue
elif key.startswith("replaygain_"):
continue
self.id3[key] = "a test value"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3[key], ["a test value"])
self.failUnlessEqual(id3.keys(), [key])
self.id3[key] = "a test value"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3[key], ["a test value"])
self.failUnlessEqual(id3.keys(), [key])
del(self.id3[key])
def test_write_double(self):
for key in EasyID3.valid_keys:
if (key == "date") or (key == "originaldate"):
continue
elif key.startswith("replaygain_"):
continue
elif key == "musicbrainz_trackid":
continue
self.id3[key] = ["a test", "value"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(sorted(id3.get(key)), ["a test", "value"])
self.failUnlessEqual(id3.keys(), [key])
self.id3[key] = ["a test", "value"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(sorted(id3.get(key)), ["a test", "value"])
self.failUnlessEqual(id3.keys(), [key])
del(self.id3[key])
def test_write_date(self):
self.id3["date"] = "2004"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["date"], ["2004"])
self.id3["date"] = "2004"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["date"], ["2004"])
def test_date_delete(self):
self.id3["date"] = "2004"
self.failUnlessEqual(self.id3["date"], ["2004"])
del(self.id3["date"])
self.failIf("date" in self.id3.keys())
def test_write_date_double(self):
self.id3["date"] = ["2004", "2005"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["date"], ["2004", "2005"])
self.id3["date"] = ["2004", "2005"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["date"], ["2004", "2005"])
def test_write_original_date(self):
self.id3["originaldate"] = "2004"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["originaldate"], ["2004"])
self.id3["originaldate"] = "2004"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["originaldate"], ["2004"])
def test_original_date_delete(self):
self.id3["originaldate"] = "2004"
self.failUnlessEqual(self.id3["originaldate"], ["2004"])
del(self.id3["originaldate"])
self.failIf("originaldate" in self.id3.keys())
def test_write_original_date_double(self):
self.id3["originaldate"] = ["2004", "2005"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["originaldate"], ["2004", "2005"])
self.id3["originaldate"] = ["2004", "2005"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["originaldate"], ["2004", "2005"])
def test_write_invalid(self):
self.failUnlessRaises(ValueError, self.id3.__getitem__, "notvalid")
self.failUnlessRaises(ValueError, self.id3.__delitem__, "notvalid")
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "notvalid", "tests")
def test_perfomer(self):
self.id3["performer:coder"] = ["piman", "mu"]
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["performer:coder"], ["piman", "mu"])
def test_no_performer(self):
self.failIf("performer:foo" in self.id3)
def test_performer_delete(self):
self.id3["performer:foo"] = "Joe"
self.id3["performer:bar"] = "Joe"
self.failUnless("performer:foo" in self.id3)
self.failUnless("performer:bar" in self.id3)
del(self.id3["performer:foo"])
self.failIf("performer:foo" in self.id3)
self.failUnless("performer:bar" in self.id3)
del(self.id3["performer:bar"])
self.failIf("performer:bar" in self.id3)
self.failIf("TMCL" in self.realid3)
def test_performer_delete_dne(self):
self.failUnlessRaises(KeyError, self.id3.__delitem__, "performer:bar")
self.id3["performer:foo"] = "Joe"
self.failUnlessRaises(KeyError, self.id3.__delitem__, "performer:bar")
def test_txxx_empty(self):
self.id3["asin"] = ""
def test_txxx_set_get(self):
self.failIf("asin" in self.id3.keys())
self.id3["asin"] = "Hello"
self.failUnless("asin" in self.id3.keys())
self.failUnlessEqual(self.id3["asin"], ["Hello"])
self.failUnless("TXXX:ASIN" in self.realid3)
def test_txxx_del_set_del(self):
self.failIf("asin" in self.id3.keys())
self.failUnlessRaises(KeyError, self.id3.__delitem__, "asin")
self.id3["asin"] = "Hello"
self.failUnless("asin" in self.id3.keys())
self.failUnlessEqual(self.id3["asin"], ["Hello"])
del(self.id3["asin"])
self.failIf("asin" in self.id3.keys())
self.failUnlessRaises(KeyError, self.id3.__delitem__, "asin")
def test_txxx_save(self):
self.id3["asin"] = "Hello"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["asin"], ["Hello"])
def test_txxx_unicode(self):
self.id3["asin"] = u"He\u1234llo"
self.failUnlessEqual(self.id3["asin"], [u"He\u1234llo"])
def test_bad_trackid(self):
self.failUnlessRaises(ValueError, self.id3.__setitem__,
"musicbrainz_trackid", ["a", "b"])
self.failIf(self.realid3.getall("RVA2"))
def test_gain_bad_key(self):
self.failIf("replaygain_foo_gain" in self.id3)
self.failIf(self.realid3.getall("RVA2"))
def test_gain_bad_value(self):
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "replaygain_foo_gain", [])
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "replaygain_foo_gain", ["foo"])
self.failUnlessRaises(
ValueError,
self.id3.__setitem__, "replaygain_foo_gain", ["1", "2"])
self.failIf(self.realid3.getall("RVA2"))
def test_peak_bad_key(self):
self.failIf("replaygain_foo_peak" in self.id3)
self.failIf(self.realid3.getall("RVA2"))
def test_peak_bad_value(self):
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "replaygain_foo_peak", [])
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "replaygain_foo_peak", ["foo"])
self.failUnlessRaises(
ValueError,
self.id3.__setitem__, "replaygain_foo_peak", ["1", "1"])
self.failUnlessRaises(
ValueError, self.id3.__setitem__, "replaygain_foo_peak", ["3"])
self.failIf(self.realid3.getall("RVA2"))
def test_gain_peak_get(self):
self.id3["replaygain_foo_gain"] = "+3.5 dB"
self.id3["replaygain_bar_peak"] = "0.5"
self.failUnlessEqual(
self.id3["replaygain_foo_gain"], ["+3.500000 dB"])
self.failUnlessEqual(self.id3["replaygain_foo_peak"], ["0.000000"])
self.failUnlessEqual(
self.id3["replaygain_bar_gain"], ["+0.000000 dB"])
self.failUnlessEqual(self.id3["replaygain_bar_peak"], ["0.500000"])
def test_gain_peak_set(self):
self.id3["replaygain_foo_gain"] = "+3.5 dB"
self.id3["replaygain_bar_peak"] = "0.5"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3["replaygain_foo_gain"], ["+3.500000 dB"])
self.failUnlessEqual(id3["replaygain_foo_peak"], ["0.000000"])
self.failUnlessEqual(id3["replaygain_bar_gain"], ["+0.000000 dB"])
self.failUnlessEqual(id3["replaygain_bar_peak"], ["0.500000"])
def test_gain_peak_delete(self):
self.id3["replaygain_foo_gain"] = "+3.5 dB"
self.id3["replaygain_bar_peak"] = "0.5"
del(self.id3["replaygain_bar_gain"])
del(self.id3["replaygain_foo_peak"])
self.failUnless("replaygain_foo_gain" in self.id3.keys())
self.failUnless("replaygain_bar_gain" in self.id3.keys())
del(self.id3["replaygain_foo_gain"])
del(self.id3["replaygain_bar_peak"])
self.failIf("replaygain_foo_gain" in self.id3.keys())
self.failIf("replaygain_bar_gain" in self.id3.keys())
del(self.id3["replaygain_foo_gain"])
del(self.id3["replaygain_bar_peak"])
self.failIf("replaygain_foo_gain" in self.id3.keys())
self.failIf("replaygain_bar_gain" in self.id3.keys())
def test_gain_peak_capitalization(self):
frame = RVA2(desc=u"Foo", gain=1.0, peak=1.0, channel=0)
self.assertFalse(len(self.realid3))
self.realid3.add(frame)
self.assertTrue("replaygain_Foo_peak" in self.id3)
self.assertTrue("replaygain_Foo_peak" in self.id3.keys())
self.assertTrue("replaygain_Foo_gain" in self.id3)
self.assertTrue("replaygain_Foo_gain" in self.id3.keys())
self.id3["replaygain_Foo_gain"] = ["0.5"]
self.id3["replaygain_Foo_peak"] = ["0.25"]
frames = self.realid3.getall("RVA2")
self.assertEqual(len(frames), 1)
self.assertEqual(frames[0].desc, u"Foo")
self.assertEqual(frames[0].gain, 0.5)
self.assertEqual(frames[0].peak, 0.25)
def test_case_insensitive(self):
self.id3["date"] = [u"2004"]
self.assertEqual(self.id3["DATE"], [u"2004"])
del self.id3["DaTe"]
self.assertEqual(len(self.id3), 0)
self.id3["asin"] = [u"foo"]
self.assertEqual(self.id3["Asin"], [u"foo"])
del self.id3["AsIn"]
self.assertEqual(len(self.id3), 0)
def test_pickle(self):
pickle.dumps(self.id3)
def test_get_fallback(self):
called = []
def get_func(id3, key):
id3.getall("")
self.failUnlessEqual(key, "nope")
called.append(1)
self.id3.GetFallback = get_func
self.id3["nope"]
self.failUnless(called)
def test_set_fallback(self):
called = []
def set_func(id3, key, value):
id3.getall("")
self.failUnlessEqual(key, "nope")
self.failUnlessEqual(value, ["foo"])
called.append(1)
self.id3.SetFallback = set_func
self.id3["nope"] = "foo"
self.failUnless(called)
def test_del_fallback(self):
called = []
def del_func(id3, key):
id3.getall("")
self.failUnlessEqual(key, "nope")
called.append(1)
self.id3.DeleteFallback = del_func
del self.id3["nope"]
self.failUnless(called)
def test_list_fallback(self):
def list_func(id3, key):
id3.getall("")
self.failIf(key)
return ["somekey"]
self.id3.ListFallback = list_func
self.failUnlessEqual(self.id3.keys(), ["somekey"])
def test_text_tags(self):
for tag in ["albumartist", "performer"]:
self.id3[tag] = u"foo"
self.id3.save(self.filename)
id3 = EasyID3(self.filename)
self.failUnlessEqual(id3[tag], [u"foo"])