From 931a6b636b66a4b297e32278b6c847021fa1f4c6 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 2 Sep 2012 16:00:18 -0700 Subject: [PATCH 1/3] fix for plugins not modifying files' tags --- beets/importer.py | 6 +++++- docs/changelog.rst | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/beets/importer.py b/beets/importer.py index 8a8418656..f58481bd8 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -727,6 +727,10 @@ def plugin_stage(config, func): continue func(config, task) + # Stage may modify DB, so re-load cached item data. + for item in task.imported_items(): + config.lib.load(item) + def manipulate_files(config): """A coroutine (pipeline stage) that performs necessary file manipulations *after* items have been added to the library. @@ -737,7 +741,7 @@ def manipulate_files(config): if task.should_skip(): continue - # Move/copy files. + # Move/copy/write files. items = task.imported_items() task.old_paths = [item.path for item in items] # For deletion. for item in items: diff --git a/docs/changelog.rst b/docs/changelog.rst index 08ad9247d..eecd3df77 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -22,6 +22,8 @@ Changelog * Add the track mapping dictionary to the ``album_distance`` plugin function. * Fix an assertion failure when the MusicBrainz main database and search server disagree. +* Fix a bug that caused the :doc:`/plugins/lastgenre` and other plugins not to + modify files' tags even when they successfully change the database. .. _Tomahawk resolver: http://beets.radbox.org/blog/tomahawk-resolver.html From 90b3dba085429a2ca38f26e7e2e187fe14296e79 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 8 Sep 2012 16:24:39 -0700 Subject: [PATCH 2/3] fix match() on RegexpQuery for non-string values --- beets/library.py | 4 ++++ docs/changelog.rst | 1 + test/test_query.py | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/beets/library.py b/beets/library.py index 40265231e..6450af9c7 100644 --- a/beets/library.py +++ b/beets/library.py @@ -452,6 +452,10 @@ class RegexpQuery(FieldQuery): def match(self, item): value = getattr(item, self.field) or '' + if value is None: + value = u'' + elif not isinstance(value, basestring): + value = unicode(value) return self.regexp.search(value) is not None class BooleanQuery(MatchQuery): diff --git a/docs/changelog.rst b/docs/changelog.rst index eecd3df77..bc4815dcf 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,7 @@ Changelog * Fix album queries for ``artpath`` and other non-item fields. * Null values in the database can now be matched with the empty-string regular expression, ``^$``. +* Regular expressions more reliably match non-string values. * :doc:`/plugins/fetchart`: Fix a bug where cover art filenames could lack a ``.jpg`` extension. * :doc:`/plugins/lyrics`: Fix an exception with non-ASCII lyrics. diff --git a/test/test_query.py b/test/test_query.py index 5a4debefc..6dc212a8a 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -302,6 +302,22 @@ class MemoryGetTest(unittest.TestCase, AssertsMixin): self.assert_matched(results, u'caf\xe9') self.assert_done(results) +class MatchTest(unittest.TestCase): + def setUp(self): + self.item = _common.item() + + def test_regex_match_positive(self): + q = beets.library.RegexpQuery('album', '^the album$') + self.assertTrue(q.match(self.item)) + + def test_regex_match_negative(self): + q = beets.library.RegexpQuery('album', '^album$') + self.assertFalse(q.match(self.item)) + + def test_regex_match_non_string_value(self): + q = beets.library.RegexpQuery('disc', '^6$') + self.assertTrue(q.match(self.item)) + class PathQueryTest(unittest.TestCase, AssertsMixin): def setUp(self): self.lib = beets.library.Library(':memory:') From dc054907d5de4f99c8bd4ecb8e2ecb914ff448c5 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sun, 9 Sep 2012 12:17:13 -0700 Subject: [PATCH 3/3] fix non-string value matching in SubstringQuery --- beets/library.py | 13 +++---------- beets/util/__init__.py | 9 +++++++++ docs/changelog.rst | 2 +- test/test_query.py | 12 ++++++++++++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/beets/library.py b/beets/library.py index 6450af9c7..ef97161a6 100644 --- a/beets/library.py +++ b/beets/library.py @@ -166,10 +166,7 @@ def _regexp(expr, val): """ if expr is None: return False - if val is None: - val = u'' - if not isinstance(val, basestring): - val = unicode(val) + val = util.as_string(val) try: res = re.search(expr, val) except re.error: @@ -436,7 +433,7 @@ class SubstringQuery(FieldQuery): return clause, subvals def match(self, item): - value = getattr(item, self.field) or '' + value = util.as_string(getattr(item, self.field)) return self.pattern.lower() in value.lower() class RegexpQuery(FieldQuery): @@ -451,11 +448,7 @@ class RegexpQuery(FieldQuery): return clause, subvals def match(self, item): - value = getattr(item, self.field) or '' - if value is None: - value = u'' - elif not isinstance(value, basestring): - value = unicode(value) + value = util.as_string(getattr(item, self.field)) return self.regexp.search(value) is not None class BooleanQuery(MatchQuery): diff --git a/beets/util/__init__.py b/beets/util/__init__.py index 380bfaf8e..6c29c7c0e 100644 --- a/beets/util/__init__.py +++ b/beets/util/__init__.py @@ -467,6 +467,15 @@ def str2bool(value): else: return False +def as_string(value): + """Convert a value to a Unicode object for matching with a query. + None becomes the empty string. + """ + if value is None: + return u'' + else: + return unicode(value) + def levenshtein(s1, s2): """A nice DP edit distance implementation from Wikibooks: http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/ diff --git a/docs/changelog.rst b/docs/changelog.rst index bc4815dcf..03aab8744 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,7 +12,7 @@ Changelog * Fix album queries for ``artpath`` and other non-item fields. * Null values in the database can now be matched with the empty-string regular expression, ``^$``. -* Regular expressions more reliably match non-string values. +* Queries now correctly match non-string values in path format predicates. * :doc:`/plugins/fetchart`: Fix a bug where cover art filenames could lack a ``.jpg`` extension. * :doc:`/plugins/lyrics`: Fix an exception with non-ASCII lyrics. diff --git a/test/test_query.py b/test/test_query.py index 6dc212a8a..eae9abced 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -318,6 +318,18 @@ class MatchTest(unittest.TestCase): q = beets.library.RegexpQuery('disc', '^6$') self.assertTrue(q.match(self.item)) + def test_substring_match_positive(self): + q = beets.library.SubstringQuery('album', 'album') + self.assertTrue(q.match(self.item)) + + def test_substring_match_negative(self): + q = beets.library.SubstringQuery('album', 'ablum') + self.assertFalse(q.match(self.item)) + + def test_substring_match_non_string_value(self): + q = beets.library.SubstringQuery('disc', '6') + self.assertTrue(q.match(self.item)) + class PathQueryTest(unittest.TestCase, AssertsMixin): def setUp(self): self.lib = beets.library.Library(':memory:')