1# -*- coding: utf-8 -*- 2import re 3import six 4from json import dumps 5 6from webtest.compat import urlencode 7 8 9class NoDefault(object): 10 """Sentinel to uniquely represent no default value.""" 11 12 def __repr__(self): 13 return '<NoDefault>' 14 15NoDefault = NoDefault() 16 17 18def json_method(method): 19 """Do a %(method)s request. Very like the 20 :class:`~webtest.TestApp.%(lmethod)s` method. 21 22 ``params`` are dumped to json and put in the body of the request. 23 Content-Type is set to ``application/json``. 24 25 Returns a :class:`webtest.TestResponse` object. 26 """ 27 28 def wrapper(self, url, params=NoDefault, **kw): 29 content_type = 'application/json' 30 if params is not NoDefault: 31 params = dumps(params, cls=self.JSONEncoder) 32 kw.update( 33 params=params, 34 content_type=content_type, 35 upload_files=None, 36 ) 37 return self._gen_request(method, url, **kw) 38 39 subst = dict(lmethod=method.lower(), method=method) 40 wrapper.__doc__ = json_method.__doc__ % subst 41 wrapper.__name__ = str('%(lmethod)s_json' % subst) 42 43 return wrapper 44 45 46def stringify(value): 47 if isinstance(value, six.text_type): 48 return value 49 elif isinstance(value, six.binary_type): 50 return value.decode('utf8') 51 else: 52 return str(value) 53 54 55entity_pattern = re.compile(r"&(\w+|#\d+|#[xX][a-fA-F0-9]+);") 56 57 58def encode_params(params, content_type): 59 if params is NoDefault: 60 return '' 61 if isinstance(params, dict) or hasattr(params, 'items'): 62 params = list(params.items()) 63 if isinstance(params, (list, tuple)): 64 if content_type: 65 content_type = content_type.lower() 66 if 'charset=' in content_type: 67 charset = content_type.split('charset=')[1] 68 charset = charset.strip('; ').lower() 69 encoded_params = [] 70 for k, v in params: 71 if isinstance(v, six.text_type): 72 v = v.encode(charset) 73 encoded_params.append((k, v)) 74 params = encoded_params 75 params = urlencode(params, doseq=True) 76 return params 77 78 79def make_pattern(pat): 80 """Find element pattern can be a regex or a callable.""" 81 if pat is None: 82 return None 83 if isinstance(pat, six.binary_type): 84 pat = pat.decode('utf8') 85 if isinstance(pat, six.text_type): 86 pat = re.compile(pat) 87 if hasattr(pat, 'search'): 88 return pat.search 89 if hasattr(pat, '__call__'): 90 return pat 91 raise ValueError( 92 "Cannot make callable pattern object out of %r" % pat) 93 94 95class _RequestCookieAdapter(object): 96 """ 97 cookielib.CookieJar support for webob.Request 98 """ 99 def __init__(self, request): 100 self._request = request 101 self.origin_req_host = request.host 102 103 def is_unverifiable(self): 104 return True # sure? Why not? 105 106 @property 107 def unverifiable(self): # NOQA 108 # This is undocumented method that Python 3 cookielib uses 109 return True 110 111 def get_full_url(self): 112 return self._request.url 113 114 def get_host(self): 115 return self.origin_req_host 116 get_origin_req_host = get_host 117 118 def add_unredirected_header(self, key, header): 119 self._request.headers[key] = header 120 121 def has_header(self, key): 122 return key in self._request.headers 123 124 def get_type(self): 125 return self._request.scheme 126 127 @property 128 def type(self): # NOQA 129 # This is undocumented method that Python 3 cookielib uses 130 return self.get_type() 131 132 def header_items(self): # pragma: no cover 133 # This is unused on most python versions 134 return self._request.headers.items() 135 136 137class _ResponseCookieAdapter(object): 138 """ 139 cookielib.CookieJar support for webob.Response 140 """ 141 def __init__(self, response): 142 self._response = response 143 144 def info(self): 145 return self 146 147 def getheaders(self, header): 148 return self._response.headers.getall(header) 149 150 def get_all(self, headers, default): # NOQA 151 # This is undocumented method that Python 3 cookielib uses 152 return self._response.headers.getall(headers) 153