Skip to content

Commit 865cae6

Browse files
committed
Merge pull request alastair#239 from alastair/search-params
Add missing valid seach parameters Signed-off-by: Wieland Hoffmann <themineo@gmail.com>
2 parents a8147a8 + 78ffdc8 commit 865cae6

File tree

4 files changed

+184
-76
lines changed

4 files changed

+184
-76
lines changed

Diff for: musicbrainzngs/compat.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
HTTPHandler, build_opener, HTTPError, URLError
4444
from httplib import BadStatusLine, HTTPException
4545
from urlparse import urlunparse
46-
from urllib import urlencode
46+
from urllib import urlencode, quote_plus
4747

4848
bytes = str
4949
unicode = unicode
@@ -54,7 +54,7 @@
5454
HTTPHandler, build_opener
5555
from urllib.error import HTTPError, URLError
5656
from http.client import HTTPException, BadStatusLine
57-
from urllib.parse import urlunparse, urlencode
57+
from urllib.parse import urlunparse, urlencode, quote_plus
5858

5959
unicode = str
6060
bytes = bytes

Diff for: musicbrainzngs/musicbrainz.py

+39-29
Original file line numberDiff line numberDiff line change
@@ -108,48 +108,58 @@
108108
'entity', 'name', 'text', 'type'
109109
],
110110
'area': [
111-
'aid', 'area', 'alias', 'begin', 'comment', 'end', 'ended',
112-
'iso', 'iso1', 'iso2', 'iso3', 'type'
111+
'aid', 'alias', 'area', 'areaaccent', 'begin', 'comment', 'end',
112+
'ended', 'iso', 'iso1', 'iso2', 'iso3', 'sortname', 'tag', 'type'
113113
],
114114
'artist': [
115-
'arid', 'artist', 'artistaccent', 'alias', 'begin', 'comment',
116-
'country', 'end', 'ended', 'gender', 'ipi', 'sortname', 'tag', 'type',
117-
'area', 'beginarea', 'endarea'
115+
'alias', 'area', 'arid', 'artist', 'artistaccent', 'begin', 'beginarea',
116+
'comment', 'country', 'end', 'endarea', 'ended', 'gender',
117+
'ipi', 'isni', 'primary_alias', 'sortname', 'tag', 'type'
118+
],
119+
'event': [
120+
'aid', 'alias', 'area', 'arid', 'artist', 'begin', 'comment', 'eid',
121+
'end', 'ended', 'event', 'eventaccent', 'pid', 'place', 'tag', 'type'
122+
],
123+
'instrument': [
124+
'alias', 'comment', 'description', 'iid', 'instrument',
125+
'instrumentaccent', 'tag', 'type'
118126
],
119127
'label': [
120-
'alias', 'begin', 'code', 'comment', 'country', 'end', 'ended',
121-
'ipi', 'label', 'labelaccent', 'laid', 'sortname', 'type', 'tag',
122-
'area'
128+
'alias', 'area', 'begin', 'code', 'comment', 'country', 'end', 'ended',
129+
'ipi', 'label', 'labelaccent', 'laid', 'release_count', 'sortname',
130+
'tag', 'type'
123131
],
124-
'recording': [
125-
'arid', 'artist', 'artistname', 'creditname', 'comment',
126-
'country', 'date', 'dur', 'format', 'isrc', 'number',
127-
'position', 'primarytype', 'qdur', 'recording',
128-
'recordingaccent', 'reid', 'release', 'rgid', 'rid',
129-
'secondarytype', 'status', 'tnum', 'tracks', 'tracksrelease',
130-
'tag', 'type', 'video'
132+
'place': [
133+
'address', 'alias', 'area', 'begin', 'comment', 'end', 'ended', 'lat', 'long',
134+
'pid', 'place', 'placeaccent', 'type'
131135
],
136+
'recording': [
137+
'alias', 'arid', 'artist', 'artistname', 'comment', 'country',
138+
'creditname', 'date', 'dur', 'format', 'isrc', 'number', 'position',
139+
'primarytype', 'qdur', 'recording', 'recordingaccent', 'reid',
140+
'release', 'rgid', 'rid', 'secondarytype', 'status', 'tag', 'tid',
141+
'tnum', 'tracks', 'tracksrelease', 'type', 'video'],
142+
132143
'release-group': [
133-
'arid', 'artist', 'artistname', 'comment', 'creditname',
134-
'primarytype', 'rgid', 'releasegroup', 'releasegroupaccent',
135-
'releases', 'release', 'reid', 'secondarytype', 'status',
136-
'tag', 'type'
144+
'alias', 'arid', 'artist', 'artistname', 'comment', 'creditname',
145+
'primarytype', 'reid', 'release', 'releasegroup', 'releasegroupaccent',
146+
'releases', 'rgid', 'secondarytype', 'status', 'tag', 'type'
137147
],
138148
'release': [
139-
'arid', 'artist', 'artistname', 'asin', 'barcode', 'creditname',
140-
'catno', 'comment', 'country', 'creditname', 'date', 'discids',
141-
'discidsmedium', 'format', 'laid', 'label', 'lang', 'mediums',
142-
'primarytype', 'quality', 'reid', 'release', 'releaseaccent',
143-
'rgid', 'script', 'secondarytype', 'status', 'tag', 'tracks',
144-
'tracksmedium', 'type'
149+
'alias', 'arid', 'artist', 'artistname', 'asin', 'barcode', 'catno',
150+
'comment', 'country', 'creditname', 'date', 'discids', 'discidsmedium',
151+
'format', 'label', 'laid', 'lang', 'mediums', 'primarytype', 'quality',
152+
'reid', 'release', 'releaseaccent', 'rgid', 'script', 'secondarytype',
153+
'status', 'tag', 'tracks', 'tracksmedium', 'type'
145154
],
146155
'series': [
147-
'alias', 'comment', 'sid', 'series', 'type'
156+
'alias', 'comment', 'orderingattribute', 'series', 'seriesaccent',
157+
'sid', 'tag', 'type'
148158
],
149159
'work': [
150-
'alias', 'arid', 'artist', 'comment', 'iswc', 'lang', 'tag',
151-
'type', 'wid', 'work', 'workaccent'
152-
],
160+
'alias', 'arid', 'artist', 'comment', 'iswc', 'lang', 'recording',
161+
'recording_count', 'rid', 'tag', 'type', 'wid', 'work', 'workaccent'
162+
]
153163
}
154164

155165
# Constants

Diff for: test/test_mbxml_search.py

+8-45
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,11 @@
11
import unittest
22
import os
3-
import musicbrainzngs
43
from musicbrainzngs import mbxml
5-
from test import _common
64

75

86
DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
97

108

11-
class UrlTest(unittest.TestCase):
12-
""" Test that the correct URL is generated when a search query is made """
13-
14-
def setUp(self):
15-
self.opener = _common.FakeOpener("<response/>")
16-
musicbrainzngs.compat.build_opener = lambda *args: self.opener
17-
18-
musicbrainzngs.set_useragent("a", "1")
19-
musicbrainzngs.set_rate_limit(False)
20-
21-
def testSearchArtist(self):
22-
musicbrainzngs.search_artists("Dynamo Go")
23-
self.assertEqual("http://musicbrainz.org/ws/2/artist/?query=Dynamo+Go", self.opener.get_url())
24-
25-
def testSearchEvent(self):
26-
musicbrainzngs.search_events("woodstock")
27-
self.assertEqual("http://musicbrainz.org/ws/2/event/?query=woodstock", self.opener.get_url())
28-
29-
def testSearchLabel(self):
30-
musicbrainzngs.search_labels("Waysafe")
31-
self.assertEqual("http://musicbrainz.org/ws/2/label/?query=Waysafe", self.opener.get_url())
32-
33-
def testSearchPlace(self):
34-
musicbrainzngs.search_places("Fillmore")
35-
self.assertEqual("http://musicbrainz.org/ws/2/place/?query=Fillmore", self.opener.get_url())
36-
37-
def testSearchRelease(self):
38-
musicbrainzngs.search_releases("Affordable Pop Music")
39-
self.assertEqual("http://musicbrainz.org/ws/2/release/?query=Affordable+Pop+Music", self.opener.get_url())
40-
41-
def testSearchReleaseGroup(self):
42-
musicbrainzngs.search_release_groups("Affordable Pop Music")
43-
self.assertEqual("http://musicbrainz.org/ws/2/release-group/?query=Affordable+Pop+Music", self.opener.get_url())
44-
45-
def testSearchRecording(self):
46-
musicbrainzngs.search_recordings("Thief of Hearts")
47-
self.assertEqual("http://musicbrainz.org/ws/2/recording/?query=Thief+of+Hearts", self.opener.get_url())
48-
49-
def testSearchWork(self):
50-
musicbrainzngs.search_works("Fountain City")
51-
self.assertEqual("http://musicbrainz.org/ws/2/work/?query=Fountain+City", self.opener.get_url())
52-
53-
549
class SearchArtistTest(unittest.TestCase):
5510
def testFields(self):
5611
fn = os.path.join(DATA_DIR, "search-artist.xml")
@@ -64,6 +19,7 @@ def testFields(self):
6419
# so check for it here
6520
self.assertEqual("100", one["ext:score"])
6621

22+
6723
class SearchReleaseTest(unittest.TestCase):
6824
def testFields(self):
6925
fn = os.path.join(DATA_DIR, "search-release.xml")
@@ -79,6 +35,7 @@ def testFields(self):
7935
self.assertEqual(1, one["medium-count"])
8036
self.assertEqual("CD", one["medium-list"][0]["format"])
8137

38+
8239
class SearchReleaseGroupTest(unittest.TestCase):
8340
def testFields(self):
8441
fn = os.path.join(DATA_DIR, "search-release-group.xml")
@@ -89,6 +46,7 @@ def testFields(self):
8946
one = res["release-group-list"][0]
9047
self.assertEqual("100", one["ext:score"])
9148

49+
9250
class SearchWorkTest(unittest.TestCase):
9351
def testFields(self):
9452
fn = os.path.join(DATA_DIR, "search-work.xml")
@@ -99,6 +57,7 @@ def testFields(self):
9957
one = res["work-list"][0]
10058
self.assertEqual("100", one["ext:score"])
10159

60+
10261
class SearchLabelTest(unittest.TestCase):
10362
def testFields(self):
10463
fn = os.path.join(DATA_DIR, "search-label.xml")
@@ -109,6 +68,7 @@ def testFields(self):
10968
one = res["label-list"][0]
11069
self.assertEqual("100", one["ext:score"])
11170

71+
11272
class SearchRecordingTest(unittest.TestCase):
11373
def testFields(self):
11474
fn = os.path.join(DATA_DIR, "search-recording.xml")
@@ -119,6 +79,7 @@ def testFields(self):
11979
one = res["recording-list"][0]
12080
self.assertEqual("100", one["ext:score"])
12181

82+
12283
class SearchInstrumentTest(unittest.TestCase):
12384
def testFields(self):
12485
fn = os.path.join(DATA_DIR, "search-instrument.xml")
@@ -131,6 +92,7 @@ def testFields(self):
13192
end = res["instrument-list"][-1]
13293
self.assertEqual("29", end["ext:score"])
13394

95+
13496
class SearchPlaceTest(unittest.TestCase):
13597
def testFields(self):
13698
fn = os.path.join(DATA_DIR, "search-place.xml")
@@ -144,6 +106,7 @@ def testFields(self):
144106
self.assertEqual("63", two["ext:score"])
145107
self.assertEqual("Southampton", two["disambiguation"])
146108

109+
147110
class SearchEventTest(unittest.TestCase):
148111
def testFields(self):
149112
fn = os.path.join(DATA_DIR, "search-event.xml")

Diff for: test/test_search.py

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import unittest
2+
3+
import musicbrainzngs
4+
from test import _common
5+
6+
7+
class SearchUrlTest(unittest.TestCase):
8+
""" Test that the correct URL is generated when a search query is made """
9+
10+
def setUp(self):
11+
self.opener = _common.FakeOpener("<response/>")
12+
musicbrainzngs.compat.build_opener = lambda *args: self.opener
13+
14+
musicbrainzngs.set_useragent("a", "1")
15+
musicbrainzngs.set_rate_limit(False)
16+
17+
def test_search_annotations(self):
18+
musicbrainzngs.search_annotations("Pieds")
19+
self.assertEquals("http://musicbrainz.org/ws/2/annotation/?query=Pieds", self.opener.get_url())
20+
21+
# Query fields
22+
musicbrainzngs.search_annotations(entity="bdb24cb5-404b-4f60-bba4-7b730325ae47")
23+
# TODO: We escape special characters and then urlencode all query parameters, which may
24+
# not be necessary, but MusicBrainz accepts it and appears to return the same value as without
25+
expected_query = 'entity:(bdb24cb5\-404b\-4f60\-bba4\-7b730325ae47)'
26+
expected = 'http://musicbrainz.org/ws/2/annotation/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
27+
self.assertEquals(expected, self.opener.get_url())
28+
29+
# Invalid query field
30+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
31+
musicbrainzngs.search_annotations(foo="value")
32+
33+
def test_search_artists(self):
34+
musicbrainzngs.search_artists("Dynamo Go")
35+
self.assertEqual("http://musicbrainz.org/ws/2/artist/?query=Dynamo+Go", self.opener.get_url())
36+
37+
musicbrainzngs.search_artists(artist="Dynamo Go")
38+
expected_query = 'artist:(dynamo go)'
39+
expected = 'http://musicbrainz.org/ws/2/artist/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
40+
self.assertEquals(expected, self.opener.get_url())
41+
42+
# Invalid query field
43+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
44+
musicbrainzngs.search_artists(foo="value")
45+
46+
def test_search_events(self):
47+
musicbrainzngs.search_events("woodstock")
48+
self.assertEqual("http://musicbrainz.org/ws/2/event/?query=woodstock", self.opener.get_url())
49+
50+
musicbrainzngs.search_events(event="woodstock")
51+
expected_query = 'event:(woodstock)'
52+
expected = 'http://musicbrainz.org/ws/2/event/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
53+
self.assertEquals(expected, self.opener.get_url())
54+
55+
# Invalid query field
56+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
57+
musicbrainzngs.search_events(foo="value")
58+
59+
def test_search_labels(self):
60+
musicbrainzngs.search_labels("Waysafe")
61+
self.assertEqual("http://musicbrainz.org/ws/2/label/?query=Waysafe", self.opener.get_url())
62+
63+
musicbrainzngs.search_labels(label="Waysafe")
64+
expected_query = 'label:(waysafe)'
65+
expected = 'http://musicbrainz.org/ws/2/label/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
66+
self.assertEquals(expected, self.opener.get_url())
67+
68+
# Invalid query field
69+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
70+
musicbrainzngs.search_labels(foo="value")
71+
72+
def test_search_places(self):
73+
musicbrainzngs.search_places("Fillmore")
74+
self.assertEqual("http://musicbrainz.org/ws/2/place/?query=Fillmore", self.opener.get_url())
75+
76+
musicbrainzngs.search_places(place="Fillmore")
77+
expected_query = 'place:(fillmore)'
78+
expected = 'http://musicbrainz.org/ws/2/place/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
79+
self.assertEquals(expected, self.opener.get_url())
80+
81+
# Invalid query field
82+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
83+
musicbrainzngs.search_places(foo="value")
84+
85+
def test_search_releases(self):
86+
musicbrainzngs.search_releases("Affordable Pop Music")
87+
self.assertEqual("http://musicbrainz.org/ws/2/release/?query=Affordable+Pop+Music", self.opener.get_url())
88+
89+
musicbrainzngs.search_releases(release="Affordable Pop Music")
90+
expected_query = 'release:(affordable pop music)'
91+
expected = 'http://musicbrainz.org/ws/2/release/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
92+
self.assertEquals(expected, self.opener.get_url())
93+
94+
# Invalid query field
95+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
96+
musicbrainzngs.search_releases(foo="value")
97+
98+
def test_search_release_groups(self):
99+
musicbrainzngs.search_release_groups("Affordable Pop Music")
100+
self.assertEqual("http://musicbrainz.org/ws/2/release-group/?query=Affordable+Pop+Music", self.opener.get_url())
101+
102+
musicbrainzngs.search_release_groups(releasegroup="Affordable Pop Music")
103+
expected_query = 'releasegroup:(affordable pop music)'
104+
expected = 'http://musicbrainz.org/ws/2/release-group/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
105+
self.assertEquals(expected, self.opener.get_url())
106+
107+
# Invalid query field
108+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
109+
musicbrainzngs.search_release_groups(foo="value")
110+
111+
def test_search_recordings(self):
112+
musicbrainzngs.search_recordings("Thief of Hearts")
113+
self.assertEqual("http://musicbrainz.org/ws/2/recording/?query=Thief+of+Hearts", self.opener.get_url())
114+
115+
musicbrainzngs.search_recordings(recording="Thief of Hearts")
116+
expected_query = 'recording:(thief of hearts)'
117+
expected = 'http://musicbrainz.org/ws/2/recording/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
118+
self.assertEquals(expected, self.opener.get_url())
119+
120+
# Invalid query field
121+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
122+
musicbrainzngs.search_recordings(foo="value")
123+
124+
def test_search_works(self):
125+
musicbrainzngs.search_works("Fountain City")
126+
self.assertEqual("http://musicbrainz.org/ws/2/work/?query=Fountain+City", self.opener.get_url())
127+
128+
musicbrainzngs.search_works(work="Fountain City")
129+
expected_query = 'work:(fountain city)'
130+
expected = 'http://musicbrainz.org/ws/2/work/?query=%s' % musicbrainzngs.compat.quote_plus(expected_query)
131+
self.assertEquals(expected, self.opener.get_url())
132+
133+
# Invalid query field
134+
with self.assertRaises(musicbrainzngs.InvalidSearchFieldError):
135+
musicbrainzngs.search_works(foo="value")

0 commit comments

Comments
 (0)