1  """Functions for generating and parsing HTTP Accept: headers for 
  2  supporting server-directed content negotiation. 
  3  """ 
  4   
  6      """Generate an accept header value 
  7   
  8      [str or (str, float)] -> str 
  9      """ 
 10      parts = [] 
 11      for element in elements: 
 12          if type(element) is str: 
 13              qs = "1.0" 
 14              mtype = element 
 15          else: 
 16              mtype, q = element 
 17              q = float(q) 
 18              if q > 1 or q <= 0: 
 19                  raise ValueError('Invalid preference factor: %r' % q) 
 20   
 21              qs = '%0.1f' % (q,) 
 22   
 23          parts.append((qs, mtype)) 
 24   
 25      parts.sort() 
 26      chunks = [] 
 27      for q, mtype in parts: 
 28          if q == '1.0': 
 29              chunks.append(mtype) 
 30          else: 
 31              chunks.append('%s; q=%s' % (mtype, q)) 
 32   
 33      return ', '.join(chunks) 
  34   
 36      """Parse an accept header, ignoring any accept-extensions 
 37   
 38      returns a list of tuples containing main MIME type, MIME subtype, 
 39      and quality markdown. 
 40   
 41      str -> [(str, str, float)] 
 42      """ 
 43      chunks = [chunk.strip() for chunk in value.split(',')] 
 44      accept = [] 
 45      for chunk in chunks: 
 46          parts = [s.strip() for s in chunk.split(';')] 
 47   
 48          mtype = parts.pop(0) 
 49          if '/' not in mtype: 
 50               
 51              continue 
 52   
 53          main, sub = mtype.split('/', 1) 
 54   
 55          for ext in parts: 
 56              if '=' in ext: 
 57                  k, v = ext.split('=', 1) 
 58                  if k == 'q': 
 59                      try: 
 60                          q = float(v) 
 61                          break 
 62                      except ValueError: 
 63                           
 64                          pass 
 65          else: 
 66              q = 1.0 
 67   
 68          accept.append((q, main, sub)) 
 69   
 70      accept.sort() 
 71      accept.reverse() 
 72      return [(main, sub, q) for (q, main, sub) in accept] 
  73   
 75      """Given the result of parsing an Accept: header, and the 
 76      available MIME types, return the acceptable types with their 
 77      quality markdowns. 
 78   
 79      For example: 
 80   
 81      >>> acceptable = parseAcceptHeader('text/html, text/plain; q=0.5') 
 82      >>> matchTypes(acceptable, ['text/plain', 'text/html', 'image/jpeg']) 
 83      [('text/html', 1.0), ('text/plain', 0.5)] 
 84   
 85   
 86      Type signature: ([(str, str, float)], [str]) -> [(str, float)] 
 87      """ 
 88      if not accept_types: 
 89           
 90          default = 1 
 91      else: 
 92          default = 0 
 93   
 94      match_main = {} 
 95      match_sub = {} 
 96      for (main, sub, q) in accept_types: 
 97          if main == '*': 
 98              default = max(default, q) 
 99              continue 
100          elif sub == '*': 
101              match_main[main] = max(match_main.get(main, 0), q) 
102          else: 
103              match_sub[(main, sub)] = max(match_sub.get((main, sub), 0), q) 
104   
105      accepted_list = [] 
106      order_maintainer = 0 
107      for mtype in have_types: 
108          main, sub = mtype.split('/') 
109          if (main, sub) in match_sub: 
110              q = match_sub[(main, sub)] 
111          else: 
112              q = match_main.get(main, default) 
113   
114          if q: 
115              accepted_list.append((1 - q, order_maintainer, q, mtype)) 
116              order_maintainer += 1 
117   
118      accepted_list.sort() 
119      return [(mtype, q) for (_, _, q, mtype) in accepted_list] 
 120   
122      """Parse the accept header and return a list of available types in 
123      preferred order. If a type is unacceptable, it will not be in the 
124      resulting list. 
125   
126      This is a convenience wrapper around matchTypes and 
127      parseAcceptHeader. 
128   
129      (str, [str]) -> [str] 
130      """ 
131      accepted = parseAcceptHeader(accept_header) 
132      preferred = matchTypes(accepted, have_types) 
133      return [mtype for (mtype, _) in preferred] 
 134