From b0cffb868151ad3fa0b306afe7092ba3e7c4c2a3 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 17 Nov 2013 16:00:15 +0100 Subject: [PATCH] mpd: Move query_from_mpd_search_format into only module using it --- mopidy/frontends/mpd/protocol/music_db.py | 88 +++++++++++++++++-- mopidy/frontends/mpd/translator.py | 79 ----------------- tests/frontends/mpd/protocol/music_db_test.py | 17 ++++ tests/frontends/mpd/translator_test.py | 14 --- 4 files changed, 99 insertions(+), 99 deletions(-) diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index 8e5f7593..1e5f9a4b 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import functools import itertools +import re from mopidy.models import Track from mopidy.frontends.mpd import translator @@ -37,6 +38,81 @@ QUERY_RE = r""" $ """ +MPD_SEARCH_QUERY_RE = re.compile(r""" + \b # Only begin matching at word bundaries + "? # Optional quote around the field type + (?: # A non-capturing group for the field type + [Aa]lbum + | [Aa]rtist + | [Aa]lbumartist + | [Cc]omment + | [Cc]omposer + | [Dd]ate + | [Ff]ile + | [Ff]ilename + | [Gg]enre + | [Pp]erformer + | [Tt]itle + | [Tt]rack + | [Aa]ny + ) + "? # End of optional quote around the field type + \ # A single space + "[^"]+" # Matching a quoted search string +""", flags=(re.UNICODE | re.VERBOSE)) + +MPD_SEARCH_QUERY_PART_RE = re.compile(r""" + \b # Only begin matching at word bundaries + "? # Optional quote around the field type + (?P( # A capturing group for the field type + [Aa]lbum + | [Aa]rtist + | [Aa]lbumartist + | [Cc]omment + | [Cc]omposer + | [Dd]ate + | [Ff]ile + | [Ff]ilename + | [Gg]enre + | [Pp]erformer + | [Tt]itle + | [Tt]rack + | [Aa]ny + )) + "? # End of optional quote around the field type + \ # A single space + "(?P[^"]+)" # Capturing a quoted search string +""", flags=(re.UNICODE | re.VERBOSE)) + + +def _query_from_mpd_search_format(mpd_query): + """ + Parses an MPD ``search`` or ``find`` query and converts it to the Mopidy + query format. + + :param mpd_query: the MPD search query + :type mpd_query: string + """ + query_parts = MPD_SEARCH_QUERY_RE.findall(mpd_query) + query = {} + for query_part in query_parts: + m = MPD_SEARCH_QUERY_PART_RE.match(query_part) + field = m.groupdict()['field'].lower() + if field == 'title': + field = 'track_name' + elif field == 'track': + field = 'track_no' + elif field in ('file', 'filename'): + field = 'uri' + what = m.groupdict()['what'] + if not what: + raise ValueError + if field in query: + query[field].append(what) + else: + query[field] = [what] + return query + def _get_field(field, search_results): return list(itertools.chain(*[getattr(r, field) for r in search_results])) @@ -79,7 +155,7 @@ def count(context, mpd_query): - use multiple tag-needle pairs to make more specific searches. """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: raise MpdArgError('incorrect arguments', command='count') results = context.core.library.find_exact(**query).get() @@ -119,7 +195,7 @@ def find(context, mpd_query): - uses "file" instead of "filename". """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: return results = context.core.library.find_exact(**query).get() @@ -146,7 +222,7 @@ def findadd(context, mpd_query): current playlist. Parameters have the same meaning as for ``find``. """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: return results = context.core.library.find_exact(**query).get() @@ -419,7 +495,7 @@ def search(context, mpd_query): - uses "file" instead of "filename". """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: return results = context.core.library.search(**query).get() @@ -443,7 +519,7 @@ def searchadd(context, mpd_query): not case sensitive. """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: return results = context.core.library.search(**query).get() @@ -466,7 +542,7 @@ def searchaddpl(context, playlist_name, mpd_query): not case sensitive. """ try: - query = translator.query_from_mpd_search_format(mpd_query) + query = _query_from_mpd_search_format(mpd_query) except ValueError: return results = context.core.library.search(**query).get() diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index 95b4a741..4f38effa 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -199,85 +199,6 @@ def query_from_mpd_list_format(field, mpd_query): raise MpdArgError('not able to parse args', command='list') -# XXX The regexps below should be refactored to reuse common patterns here -# and in mopidy.frontends.mpd.protocol.music_db.QUERY_RE. - -MPD_SEARCH_QUERY_RE = re.compile(r""" - \b # Only begin matching at word bundaries - "? # Optional quote around the field type - (?: # A non-capturing group for the field type - [Aa]lbum - | [Aa]rtist - | [Aa]lbumartist - | [Cc]omment - | [Cc]omposer - | [Dd]ate - | [Ff]ile - | [Ff]ilename - | [Gg]enre - | [Pp]erformer - | [Tt]itle - | [Tt]rack - | [Aa]ny - ) - "? # End of optional quote around the field type - \ # A single space - "[^"]+" # Matching a quoted search string -""", flags=(re.UNICODE | re.VERBOSE)) - -MPD_SEARCH_QUERY_PART_RE = re.compile(r""" - \b # Only begin matching at word bundaries - "? # Optional quote around the field type - (?P( # A capturing group for the field type - [Aa]lbum - | [Aa]rtist - | [Aa]lbumartist - | [Cc]omment - | [Cc]omposer - | [Dd]ate - | [Ff]ile - | [Ff]ilename - | [Gg]enre - | [Pp]erformer - | [Tt]itle - | [Tt]rack - | [Aa]ny - )) - "? # End of optional quote around the field type - \ # A single space - "(?P[^"]+)" # Capturing a quoted search string -""", flags=(re.UNICODE | re.VERBOSE)) - - -def query_from_mpd_search_format(mpd_query): - """ - Parses an MPD ``search`` or ``find`` query and converts it to the Mopidy - query format. - - :param mpd_query: the MPD search query - :type mpd_query: string - """ - query_parts = MPD_SEARCH_QUERY_RE.findall(mpd_query) - query = {} - for query_part in query_parts: - m = MPD_SEARCH_QUERY_PART_RE.match(query_part) - field = m.groupdict()['field'].lower() - if field == 'title': - field = 'track_name' - elif field == 'track': - field = 'track_no' - elif field in ('file', 'filename'): - field = 'uri' - what = m.groupdict()['what'] - if not what: - raise ValueError - if field in query: - query[field].append(what) - else: - query[field] = [what] - return query - - # TODO: move to tagcache backend. def tracks_to_tag_cache_format(tracks, media_dir): """ diff --git a/tests/frontends/mpd/protocol/music_db_test.py b/tests/frontends/mpd/protocol/music_db_test.py index 3e0439e6..52a7a390 100644 --- a/tests/frontends/mpd/protocol/music_db_test.py +++ b/tests/frontends/mpd/protocol/music_db_test.py @@ -1,10 +1,27 @@ from __future__ import unicode_literals +import unittest + +from mopidy.frontends.mpd.protocol import music_db from mopidy.models import Album, Artist, SearchResult, Track from tests.frontends.mpd import protocol +class QueryFromMpdSearchFormatTest(unittest.TestCase): + def test_dates_are_extracted(self): + result = music_db._query_from_mpd_search_format( + 'Date "1974-01-02" Date "1975"') + self.assertEqual(result['date'][0], '1974-01-02') + self.assertEqual(result['date'][1], '1975') + + # TODO Test more mappings + + +class QueryFromMpdListFormatTest(unittest.TestCase): + pass # TODO + + class MusicDatabaseHandlerTest(protocol.BaseTestCase): def test_count(self): self.sendRequest('count "artist" "needle"') diff --git a/tests/frontends/mpd/translator_test.py b/tests/frontends/mpd/translator_test.py index a1578791..a6a2eaa9 100644 --- a/tests/frontends/mpd/translator_test.py +++ b/tests/frontends/mpd/translator_test.py @@ -128,20 +128,6 @@ class PlaylistMpdFormatTest(unittest.TestCase): self.assertEqual(dict(result[0])['Track'], 2) -class QueryFromMpdSearchFormatTest(unittest.TestCase): - def test_dates_are_extracted(self): - result = translator.query_from_mpd_search_format( - 'Date "1974-01-02" Date "1975"') - self.assertEqual(result['date'][0], '1974-01-02') - self.assertEqual(result['date'][1], '1975') - - # TODO Test more mappings - - -class QueryFromMpdListFormatTest(unittest.TestCase): - pass # TODO - - class TracksToTagCacheFormatTest(unittest.TestCase): def setUp(self): self.media_dir = '/dir/subdir'