1 """ This module define the base API classes. 4 from urllib
import urlencode, urlopen
5 from contextlib
import contextmanager
10 import simplejson
as json
12 from lxml
import etree
15 import xml.etree.cElementTree
as etree
18 import xml.etree.ElementTree
as etree
21 import cElementTree
as etree
23 import elementtree.ElementTree
as etree
25 __license__ = musixmatch.__license__
26 __author__ = musixmatch.__author__
28 class Error(Exception):
29 """Base musiXmatch API error. 32 >>> raise musixmatch.api.Error('Error message') 33 Traceback (most recent call last): 38 return ': '.join(map(str, self.args))
41 name = self.__class__.__name__
42 return '%s%r' % (name, self.args)
45 """Represents errors occurred while parsing the response messages.""" 47 class ResponseStatusCode(int):
49 Represents response message status code. Casting a 50 :py:class:`ResponseStatusCode` to :py:class:`str` returns the message 51 associated with the status code: 53 >>> from musixmatch.api import ResponseStatusCode 54 >>> str(ResponseStatusCode(200)) 55 'The request was successful.' 56 >>> str(ResponseStatusCode(401)) 57 'Authentication failed, probably because of a bad API key.' 59 The status code to description mapping is: 61 +------+-----------------------------------------------------------+ 62 | Code | Description | 63 +======+===========================================================+ 64 | 200 | The request was successful. | 65 +------+-----------------------------------------------------------+ 66 | 400 | The request had bad syntax or was inherently | 67 | | impossible to be satisfied. | 68 +------+-----------------------------------------------------------+ 69 | 401 | Authentication failed, probably because of a bad API key. | 70 +------+-----------------------------------------------------------+ 71 | 402 | A limit was reached, either you exceeded per hour | 72 | | requests limits or your balance is insufficient. | 73 +------+-----------------------------------------------------------+ 74 | 403 | You are not authorized to perform this operation or | 75 | | the api version you're trying to use has been shut down. | 76 +------+-----------------------------------------------------------+ 77 | 404 | Requested resource was not found. | 78 +------+-----------------------------------------------------------+ 79 | 405 | Requested method was not found. | 80 +------+-----------------------------------------------------------+ 82 Any other status code will produce a default message: 84 >>> from musixmatch.api import ResponseStatusCode 85 >>> str(ResponseStatusCode(666)) 86 'Unknown status code 666!' 88 Casting a :py:class:`ResponseStatusCode` to :py:class:`bool` returns True if 89 status code is 200, False otherwise: 91 >>> from musixmatch.api import ResponseStatusCode 92 >>> bool(ResponseStatusCode(200)) 94 >>> bool(ResponseStatusCode(400)) 96 >>> bool(ResponseStatusCode(666)) 101 200:
"The request was successful.",
102 400:
"The request had bad syntax or was inherently " + \
103 "impossible to be satisfied.",
104 401:
"Authentication failed, probably because of a bad API key.",
105 402:
"A limit was reached, either you exceeded per hour " + \
106 "requests limits or your balance is insufficient.",
107 403:
"You are not authorized to perform this operation or " + \
108 "the api version you're trying to use has been shut down.",
109 404:
"Requested resource was not found.",
110 405:
"Requested method was not found.",
114 return self.__status__.get(self,
'Unknown status code %i!' % self)
117 return 'ResponseStatusCode(%i)' % self
124 Abstract class which provides a base class for formatted response. 127 raise NotImplementedError
132 Is the :py:class:`ResponseStatusCode` object representing the 135 :raises: :py:exc:`ValueError` if not set. 137 raise NotImplementedError
140 return "%s('...')" % type(self).__name__
144 A :py:class:`ResponseMessage` subclass which behaves like a 145 :py:class:`dict` to expose the Json structure contained in the response 146 message. Parses the Json response message and build a proper python 147 :py:class:`dict` containing all the information. Also, setup a 148 :py:class:`ResponseStatusCode` by querying the :py:class:`dict` for the 149 *['header']['status_code']* item. 153 parsed = json.load(response)
156 self.update(parsed[
'message'])
159 s = json.dumps({
'message': self }, sort_keys=
True, indent=4)
160 return '\n'.join([l.rstrip()
for l
in s.splitlines()])
164 """Overload :py:meth:`ResponseMessage.status_code`""" 169 A :py:class:`ResponseMessage` subclass which exposes 170 :py:class:`ElementTree` methods to handle XML response 171 messages. Parses the XML response message and build a 172 :py:class:`ElementTree` instance. Also setup the a 173 :py:class:`ResponseStatusCode` by querying the *status_code* tag content. 175 Casting a :py:class:`XMLResponseMessage` returns (actually re-builds) a 176 pretty printed string representing the XML API response message. 180 etree.ElementTree.__init__(self,
None, response)
189 """Overload :py:meth:`ResponseMessage.status_code`""" 194 A class representing the keyword arguments to be used in HTTP requests as 195 query string. Takes a :py:class:`dict` of keywords, and encode values 196 using utf-8. Also, the query string is sorted by keyword name, so that its 197 string representation is always the same, thus can be used in hashes. 199 Casting a :py:class:`QueryString` to :py:class:`str` returns the urlencoded 202 >>> from musixmatch.api import QueryString 203 >>> str(QueryString({ 'country': 'it', 'page': 1, 'page_size': 3 })) 204 'country=it&page=1&page_size=3' 206 Using :py:func:`repr` on :py:class:`QueryString` returns an evaluable 207 representation of the current instance, excluding apikey value: 209 >>> from musixmatch.api import QueryString 210 >>> repr(QueryString({ 'country': 'it', 'page': 1, 'apikey': 'whatever'})) 211 "QueryString({'country': 'it', 'page': '1'})" 214 dict.__init__(self, items, **keywords)
216 self[k] = str(self[k]).encode(
'utf-8')
219 return urlencode(self)
223 if 'apikey' in query:
225 return 'QueryString(%r)' % query
229 Returns an iterator method which will yield keys sorted by name. 230 Sorting allow the query strings to be used (reasonably) as caching key. 232 keys = dict.keys(self)
238 """Overloads :py:meth:`dict.values` using :py:meth:`__iter__`.""" 239 return tuple(self[k]
for k
in self)
242 """Overloads :py:meth:`dict.keys` using :py:meth:`__iter__`.""" 243 return tuple(k
for k
in self)
246 """Overloads :py:meth:`dict.item` using :py:meth:`__iter__`.""" 247 return tuple((k, self[k])
for k
in self)
250 return hash(str(self))
257 Utility class to build API methods name and call them as functions. 259 :py:class:`Method` has custom attribute access to build method names like 260 those specified in the API. Each attribute access builds a new Method with 263 Calling a :py:class:`Method` as a function with keyword arguments, 264 builds a :py:class:`Request`, runs it and returns the result. If **apikey** 265 is undefined, environment variable **musixmatch_apikey** will be used. If 266 **format** is undefined, environment variable **musixmatch_format** will be 267 used. If **musixmatch_format** is undefined, jason format will be used. 269 >>> import musixmatch 270 >>> artist = musixmatch.api.Method('artist') 273 ... chart = artist.chart.get(country='it', page=1, page_size=3) 274 ... except musixmatch.api.Error, e: 280 if name.startswith(
'_'):
283 return Method(self.__separator__.join([self, name]))
285 def __call__ (self, apikey=None, format=None, **query):
286 query[
'apikey'] = apikey
or musixmatch.apikey
287 query[
'format'] = format
or musixmatch.format
288 return Request(self, query).response
291 return "Method('%s')" % self
295 This is the main API class. Given a :py:class:`Method` or a method name, a 296 :py:class:`QueryString` or a :py:class:`dict`, it can build the API query 297 URL, run the request and return the response either as a string or as a 298 :py:class:`ResponseMessage` subclass. Assuming the default web services 299 location, this class try to build a proper request: 301 >>> from musixmatch.api import Request, Method, QueryString 302 >>> method_name = 'artist.chart.get' 303 >>> method = Method(method_name) 304 >>> keywords = { 'country': 'it', 'page': 1, 'page_size': 3 } 305 >>> query_string = QueryString(keywords) 307 >>> r1 = Request(method_name, keywords) 308 >>> r2 = Request(method_name, **keywords) 309 >>> r3 = Request(method_name, query_string) 310 >>> r4 = Request(method, keywords) 311 >>> r5 = Request(method, **keywords) 312 >>> r6 = Request(method, query_string) 314 If **method** is string, try to cast it into a :py:class:`Method`. If 315 **query_string** is a :py:class:`dict`, try to cast it into a 316 :py:class:`QueryString`. If **query_string** is not specified, try to 317 use **keywords** arguments as a :py:class:`dict` and cast it into a 318 :py:class:`QueryString`. 320 Turning the :py:class:`Request` into a :py:class:`str` returns the URL 321 representing the API request: 323 >>> str(Request('artist.chart.get', { 'country': 'it', 'page': 1 })) 324 'http://api.musixmatch.com/ws/1.1/artist.chart.get?country=it&page=1' 326 def __init__ (self, api_method, query=(), **keywords):
327 self.
__api_method = isinstance(api_method, Method)
and \
328 api_method
or Method(api_method)
331 self.__query_string.update(keywords)
336 """The :py:class:`Method` instance.""" 341 """The :py:class:`QueryString` instance.""" 346 """A context manager to handle url opening""" 348 response = urlopen(str(self))
356 The :py:class:`ResponseMessage` based on the **format** key in the 357 :py:class:`QueryString`. 361 format = self.query_string.get(
'format')
362 ResponseMessageClass = {
363 'json': JsonResponseMessage,
364 'xml': XMLResponseMessage,
367 if not ResponseMessageClass:
371 self.
__response = ResponseMessageClass(response)
379 return '%(ws_location)s/%(api_method)s?%(query_string)s' % {
380 'ws_location': musixmatch.ws.location,
386 return hash(str(self))
static int hash(int head, const int add)
Hash function adding character.
def __init__(self, items=(), keywords)
def __getattribute__(self, name)
def __init__(self, api_method, query=(), keywords)
def __init__(self, response)
static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, const int size, const int h, int ref_index, int src_index, me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags)
compares a block (either a full macroblock or a partition thereof) against a proposed motion-compensa...
def __init__(self, response)
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip please avoid problems through this extra level of scrutiny For cosmetics only commits you should get(almost) empty output from git diff-w-b< filename(s)> Also check the output of git status to make sure you don't have untracked files or deletions.git add[-i|-p|-A]< filenames/dirnames > Make sure you have told git your name and email address
def __call__(self, apikey=None, format=None, query)
def __init__(self, response)