annotate requests/cookies.py @ 15:0a3943480712

planemo upload for repository https://toolrepo.galaxytrakr.org/view/jpayne/bioproject_to_srr_2/556cac4fb538
author jpayne
date Tue, 21 May 2024 01:05:30 -0400
parents 5eb2d5e3bf22
children
rev   line source
jpayne@7 1 """
jpayne@7 2 requests.cookies
jpayne@7 3 ~~~~~~~~~~~~~~~~
jpayne@7 4
jpayne@7 5 Compatibility code to be able to use `cookielib.CookieJar` with requests.
jpayne@7 6
jpayne@7 7 requests.utils imports from here, so be careful with imports.
jpayne@7 8 """
jpayne@7 9
jpayne@7 10 import calendar
jpayne@7 11 import copy
jpayne@7 12 import time
jpayne@7 13
jpayne@7 14 from ._internal_utils import to_native_string
jpayne@7 15 from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse
jpayne@7 16
jpayne@7 17 try:
jpayne@7 18 import threading
jpayne@7 19 except ImportError:
jpayne@7 20 import dummy_threading as threading
jpayne@7 21
jpayne@7 22
jpayne@7 23 class MockRequest:
jpayne@7 24 """Wraps a `requests.Request` to mimic a `urllib2.Request`.
jpayne@7 25
jpayne@7 26 The code in `cookielib.CookieJar` expects this interface in order to correctly
jpayne@7 27 manage cookie policies, i.e., determine whether a cookie can be set, given the
jpayne@7 28 domains of the request and the cookie.
jpayne@7 29
jpayne@7 30 The original request object is read-only. The client is responsible for collecting
jpayne@7 31 the new headers via `get_new_headers()` and interpreting them appropriately. You
jpayne@7 32 probably want `get_cookie_header`, defined below.
jpayne@7 33 """
jpayne@7 34
jpayne@7 35 def __init__(self, request):
jpayne@7 36 self._r = request
jpayne@7 37 self._new_headers = {}
jpayne@7 38 self.type = urlparse(self._r.url).scheme
jpayne@7 39
jpayne@7 40 def get_type(self):
jpayne@7 41 return self.type
jpayne@7 42
jpayne@7 43 def get_host(self):
jpayne@7 44 return urlparse(self._r.url).netloc
jpayne@7 45
jpayne@7 46 def get_origin_req_host(self):
jpayne@7 47 return self.get_host()
jpayne@7 48
jpayne@7 49 def get_full_url(self):
jpayne@7 50 # Only return the response's URL if the user hadn't set the Host
jpayne@7 51 # header
jpayne@7 52 if not self._r.headers.get("Host"):
jpayne@7 53 return self._r.url
jpayne@7 54 # If they did set it, retrieve it and reconstruct the expected domain
jpayne@7 55 host = to_native_string(self._r.headers["Host"], encoding="utf-8")
jpayne@7 56 parsed = urlparse(self._r.url)
jpayne@7 57 # Reconstruct the URL as we expect it
jpayne@7 58 return urlunparse(
jpayne@7 59 [
jpayne@7 60 parsed.scheme,
jpayne@7 61 host,
jpayne@7 62 parsed.path,
jpayne@7 63 parsed.params,
jpayne@7 64 parsed.query,
jpayne@7 65 parsed.fragment,
jpayne@7 66 ]
jpayne@7 67 )
jpayne@7 68
jpayne@7 69 def is_unverifiable(self):
jpayne@7 70 return True
jpayne@7 71
jpayne@7 72 def has_header(self, name):
jpayne@7 73 return name in self._r.headers or name in self._new_headers
jpayne@7 74
jpayne@7 75 def get_header(self, name, default=None):
jpayne@7 76 return self._r.headers.get(name, self._new_headers.get(name, default))
jpayne@7 77
jpayne@7 78 def add_header(self, key, val):
jpayne@7 79 """cookielib has no legitimate use for this method; add it back if you find one."""
jpayne@7 80 raise NotImplementedError(
jpayne@7 81 "Cookie headers should be added with add_unredirected_header()"
jpayne@7 82 )
jpayne@7 83
jpayne@7 84 def add_unredirected_header(self, name, value):
jpayne@7 85 self._new_headers[name] = value
jpayne@7 86
jpayne@7 87 def get_new_headers(self):
jpayne@7 88 return self._new_headers
jpayne@7 89
jpayne@7 90 @property
jpayne@7 91 def unverifiable(self):
jpayne@7 92 return self.is_unverifiable()
jpayne@7 93
jpayne@7 94 @property
jpayne@7 95 def origin_req_host(self):
jpayne@7 96 return self.get_origin_req_host()
jpayne@7 97
jpayne@7 98 @property
jpayne@7 99 def host(self):
jpayne@7 100 return self.get_host()
jpayne@7 101
jpayne@7 102
jpayne@7 103 class MockResponse:
jpayne@7 104 """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
jpayne@7 105
jpayne@7 106 ...what? Basically, expose the parsed HTTP headers from the server response
jpayne@7 107 the way `cookielib` expects to see them.
jpayne@7 108 """
jpayne@7 109
jpayne@7 110 def __init__(self, headers):
jpayne@7 111 """Make a MockResponse for `cookielib` to read.
jpayne@7 112
jpayne@7 113 :param headers: a httplib.HTTPMessage or analogous carrying the headers
jpayne@7 114 """
jpayne@7 115 self._headers = headers
jpayne@7 116
jpayne@7 117 def info(self):
jpayne@7 118 return self._headers
jpayne@7 119
jpayne@7 120 def getheaders(self, name):
jpayne@7 121 self._headers.getheaders(name)
jpayne@7 122
jpayne@7 123
jpayne@7 124 def extract_cookies_to_jar(jar, request, response):
jpayne@7 125 """Extract the cookies from the response into a CookieJar.
jpayne@7 126
jpayne@7 127 :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar)
jpayne@7 128 :param request: our own requests.Request object
jpayne@7 129 :param response: urllib3.HTTPResponse object
jpayne@7 130 """
jpayne@7 131 if not (hasattr(response, "_original_response") and response._original_response):
jpayne@7 132 return
jpayne@7 133 # the _original_response field is the wrapped httplib.HTTPResponse object,
jpayne@7 134 req = MockRequest(request)
jpayne@7 135 # pull out the HTTPMessage with the headers and put it in the mock:
jpayne@7 136 res = MockResponse(response._original_response.msg)
jpayne@7 137 jar.extract_cookies(res, req)
jpayne@7 138
jpayne@7 139
jpayne@7 140 def get_cookie_header(jar, request):
jpayne@7 141 """
jpayne@7 142 Produce an appropriate Cookie header string to be sent with `request`, or None.
jpayne@7 143
jpayne@7 144 :rtype: str
jpayne@7 145 """
jpayne@7 146 r = MockRequest(request)
jpayne@7 147 jar.add_cookie_header(r)
jpayne@7 148 return r.get_new_headers().get("Cookie")
jpayne@7 149
jpayne@7 150
jpayne@7 151 def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
jpayne@7 152 """Unsets a cookie by name, by default over all domains and paths.
jpayne@7 153
jpayne@7 154 Wraps CookieJar.clear(), is O(n).
jpayne@7 155 """
jpayne@7 156 clearables = []
jpayne@7 157 for cookie in cookiejar:
jpayne@7 158 if cookie.name != name:
jpayne@7 159 continue
jpayne@7 160 if domain is not None and domain != cookie.domain:
jpayne@7 161 continue
jpayne@7 162 if path is not None and path != cookie.path:
jpayne@7 163 continue
jpayne@7 164 clearables.append((cookie.domain, cookie.path, cookie.name))
jpayne@7 165
jpayne@7 166 for domain, path, name in clearables:
jpayne@7 167 cookiejar.clear(domain, path, name)
jpayne@7 168
jpayne@7 169
jpayne@7 170 class CookieConflictError(RuntimeError):
jpayne@7 171 """There are two cookies that meet the criteria specified in the cookie jar.
jpayne@7 172 Use .get and .set and include domain and path args in order to be more specific.
jpayne@7 173 """
jpayne@7 174
jpayne@7 175
jpayne@7 176 class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
jpayne@7 177 """Compatibility class; is a cookielib.CookieJar, but exposes a dict
jpayne@7 178 interface.
jpayne@7 179
jpayne@7 180 This is the CookieJar we create by default for requests and sessions that
jpayne@7 181 don't specify one, since some clients may expect response.cookies and
jpayne@7 182 session.cookies to support dict operations.
jpayne@7 183
jpayne@7 184 Requests does not use the dict interface internally; it's just for
jpayne@7 185 compatibility with external client code. All requests code should work
jpayne@7 186 out of the box with externally provided instances of ``CookieJar``, e.g.
jpayne@7 187 ``LWPCookieJar`` and ``FileCookieJar``.
jpayne@7 188
jpayne@7 189 Unlike a regular CookieJar, this class is pickleable.
jpayne@7 190
jpayne@7 191 .. warning:: dictionary operations that are normally O(1) may be O(n).
jpayne@7 192 """
jpayne@7 193
jpayne@7 194 def get(self, name, default=None, domain=None, path=None):
jpayne@7 195 """Dict-like get() that also supports optional domain and path args in
jpayne@7 196 order to resolve naming collisions from using one cookie jar over
jpayne@7 197 multiple domains.
jpayne@7 198
jpayne@7 199 .. warning:: operation is O(n), not O(1).
jpayne@7 200 """
jpayne@7 201 try:
jpayne@7 202 return self._find_no_duplicates(name, domain, path)
jpayne@7 203 except KeyError:
jpayne@7 204 return default
jpayne@7 205
jpayne@7 206 def set(self, name, value, **kwargs):
jpayne@7 207 """Dict-like set() that also supports optional domain and path args in
jpayne@7 208 order to resolve naming collisions from using one cookie jar over
jpayne@7 209 multiple domains.
jpayne@7 210 """
jpayne@7 211 # support client code that unsets cookies by assignment of a None value:
jpayne@7 212 if value is None:
jpayne@7 213 remove_cookie_by_name(
jpayne@7 214 self, name, domain=kwargs.get("domain"), path=kwargs.get("path")
jpayne@7 215 )
jpayne@7 216 return
jpayne@7 217
jpayne@7 218 if isinstance(value, Morsel):
jpayne@7 219 c = morsel_to_cookie(value)
jpayne@7 220 else:
jpayne@7 221 c = create_cookie(name, value, **kwargs)
jpayne@7 222 self.set_cookie(c)
jpayne@7 223 return c
jpayne@7 224
jpayne@7 225 def iterkeys(self):
jpayne@7 226 """Dict-like iterkeys() that returns an iterator of names of cookies
jpayne@7 227 from the jar.
jpayne@7 228
jpayne@7 229 .. seealso:: itervalues() and iteritems().
jpayne@7 230 """
jpayne@7 231 for cookie in iter(self):
jpayne@7 232 yield cookie.name
jpayne@7 233
jpayne@7 234 def keys(self):
jpayne@7 235 """Dict-like keys() that returns a list of names of cookies from the
jpayne@7 236 jar.
jpayne@7 237
jpayne@7 238 .. seealso:: values() and items().
jpayne@7 239 """
jpayne@7 240 return list(self.iterkeys())
jpayne@7 241
jpayne@7 242 def itervalues(self):
jpayne@7 243 """Dict-like itervalues() that returns an iterator of values of cookies
jpayne@7 244 from the jar.
jpayne@7 245
jpayne@7 246 .. seealso:: iterkeys() and iteritems().
jpayne@7 247 """
jpayne@7 248 for cookie in iter(self):
jpayne@7 249 yield cookie.value
jpayne@7 250
jpayne@7 251 def values(self):
jpayne@7 252 """Dict-like values() that returns a list of values of cookies from the
jpayne@7 253 jar.
jpayne@7 254
jpayne@7 255 .. seealso:: keys() and items().
jpayne@7 256 """
jpayne@7 257 return list(self.itervalues())
jpayne@7 258
jpayne@7 259 def iteritems(self):
jpayne@7 260 """Dict-like iteritems() that returns an iterator of name-value tuples
jpayne@7 261 from the jar.
jpayne@7 262
jpayne@7 263 .. seealso:: iterkeys() and itervalues().
jpayne@7 264 """
jpayne@7 265 for cookie in iter(self):
jpayne@7 266 yield cookie.name, cookie.value
jpayne@7 267
jpayne@7 268 def items(self):
jpayne@7 269 """Dict-like items() that returns a list of name-value tuples from the
jpayne@7 270 jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a
jpayne@7 271 vanilla python dict of key value pairs.
jpayne@7 272
jpayne@7 273 .. seealso:: keys() and values().
jpayne@7 274 """
jpayne@7 275 return list(self.iteritems())
jpayne@7 276
jpayne@7 277 def list_domains(self):
jpayne@7 278 """Utility method to list all the domains in the jar."""
jpayne@7 279 domains = []
jpayne@7 280 for cookie in iter(self):
jpayne@7 281 if cookie.domain not in domains:
jpayne@7 282 domains.append(cookie.domain)
jpayne@7 283 return domains
jpayne@7 284
jpayne@7 285 def list_paths(self):
jpayne@7 286 """Utility method to list all the paths in the jar."""
jpayne@7 287 paths = []
jpayne@7 288 for cookie in iter(self):
jpayne@7 289 if cookie.path not in paths:
jpayne@7 290 paths.append(cookie.path)
jpayne@7 291 return paths
jpayne@7 292
jpayne@7 293 def multiple_domains(self):
jpayne@7 294 """Returns True if there are multiple domains in the jar.
jpayne@7 295 Returns False otherwise.
jpayne@7 296
jpayne@7 297 :rtype: bool
jpayne@7 298 """
jpayne@7 299 domains = []
jpayne@7 300 for cookie in iter(self):
jpayne@7 301 if cookie.domain is not None and cookie.domain in domains:
jpayne@7 302 return True
jpayne@7 303 domains.append(cookie.domain)
jpayne@7 304 return False # there is only one domain in jar
jpayne@7 305
jpayne@7 306 def get_dict(self, domain=None, path=None):
jpayne@7 307 """Takes as an argument an optional domain and path and returns a plain
jpayne@7 308 old Python dict of name-value pairs of cookies that meet the
jpayne@7 309 requirements.
jpayne@7 310
jpayne@7 311 :rtype: dict
jpayne@7 312 """
jpayne@7 313 dictionary = {}
jpayne@7 314 for cookie in iter(self):
jpayne@7 315 if (domain is None or cookie.domain == domain) and (
jpayne@7 316 path is None or cookie.path == path
jpayne@7 317 ):
jpayne@7 318 dictionary[cookie.name] = cookie.value
jpayne@7 319 return dictionary
jpayne@7 320
jpayne@7 321 def __contains__(self, name):
jpayne@7 322 try:
jpayne@7 323 return super().__contains__(name)
jpayne@7 324 except CookieConflictError:
jpayne@7 325 return True
jpayne@7 326
jpayne@7 327 def __getitem__(self, name):
jpayne@7 328 """Dict-like __getitem__() for compatibility with client code. Throws
jpayne@7 329 exception if there are more than one cookie with name. In that case,
jpayne@7 330 use the more explicit get() method instead.
jpayne@7 331
jpayne@7 332 .. warning:: operation is O(n), not O(1).
jpayne@7 333 """
jpayne@7 334 return self._find_no_duplicates(name)
jpayne@7 335
jpayne@7 336 def __setitem__(self, name, value):
jpayne@7 337 """Dict-like __setitem__ for compatibility with client code. Throws
jpayne@7 338 exception if there is already a cookie of that name in the jar. In that
jpayne@7 339 case, use the more explicit set() method instead.
jpayne@7 340 """
jpayne@7 341 self.set(name, value)
jpayne@7 342
jpayne@7 343 def __delitem__(self, name):
jpayne@7 344 """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s
jpayne@7 345 ``remove_cookie_by_name()``.
jpayne@7 346 """
jpayne@7 347 remove_cookie_by_name(self, name)
jpayne@7 348
jpayne@7 349 def set_cookie(self, cookie, *args, **kwargs):
jpayne@7 350 if (
jpayne@7 351 hasattr(cookie.value, "startswith")
jpayne@7 352 and cookie.value.startswith('"')
jpayne@7 353 and cookie.value.endswith('"')
jpayne@7 354 ):
jpayne@7 355 cookie.value = cookie.value.replace('\\"', "")
jpayne@7 356 return super().set_cookie(cookie, *args, **kwargs)
jpayne@7 357
jpayne@7 358 def update(self, other):
jpayne@7 359 """Updates this jar with cookies from another CookieJar or dict-like"""
jpayne@7 360 if isinstance(other, cookielib.CookieJar):
jpayne@7 361 for cookie in other:
jpayne@7 362 self.set_cookie(copy.copy(cookie))
jpayne@7 363 else:
jpayne@7 364 super().update(other)
jpayne@7 365
jpayne@7 366 def _find(self, name, domain=None, path=None):
jpayne@7 367 """Requests uses this method internally to get cookie values.
jpayne@7 368
jpayne@7 369 If there are conflicting cookies, _find arbitrarily chooses one.
jpayne@7 370 See _find_no_duplicates if you want an exception thrown if there are
jpayne@7 371 conflicting cookies.
jpayne@7 372
jpayne@7 373 :param name: a string containing name of cookie
jpayne@7 374 :param domain: (optional) string containing domain of cookie
jpayne@7 375 :param path: (optional) string containing path of cookie
jpayne@7 376 :return: cookie.value
jpayne@7 377 """
jpayne@7 378 for cookie in iter(self):
jpayne@7 379 if cookie.name == name:
jpayne@7 380 if domain is None or cookie.domain == domain:
jpayne@7 381 if path is None or cookie.path == path:
jpayne@7 382 return cookie.value
jpayne@7 383
jpayne@7 384 raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
jpayne@7 385
jpayne@7 386 def _find_no_duplicates(self, name, domain=None, path=None):
jpayne@7 387 """Both ``__get_item__`` and ``get`` call this function: it's never
jpayne@7 388 used elsewhere in Requests.
jpayne@7 389
jpayne@7 390 :param name: a string containing name of cookie
jpayne@7 391 :param domain: (optional) string containing domain of cookie
jpayne@7 392 :param path: (optional) string containing path of cookie
jpayne@7 393 :raises KeyError: if cookie is not found
jpayne@7 394 :raises CookieConflictError: if there are multiple cookies
jpayne@7 395 that match name and optionally domain and path
jpayne@7 396 :return: cookie.value
jpayne@7 397 """
jpayne@7 398 toReturn = None
jpayne@7 399 for cookie in iter(self):
jpayne@7 400 if cookie.name == name:
jpayne@7 401 if domain is None or cookie.domain == domain:
jpayne@7 402 if path is None or cookie.path == path:
jpayne@7 403 if toReturn is not None:
jpayne@7 404 # if there are multiple cookies that meet passed in criteria
jpayne@7 405 raise CookieConflictError(
jpayne@7 406 f"There are multiple cookies with name, {name!r}"
jpayne@7 407 )
jpayne@7 408 # we will eventually return this as long as no cookie conflict
jpayne@7 409 toReturn = cookie.value
jpayne@7 410
jpayne@7 411 if toReturn:
jpayne@7 412 return toReturn
jpayne@7 413 raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
jpayne@7 414
jpayne@7 415 def __getstate__(self):
jpayne@7 416 """Unlike a normal CookieJar, this class is pickleable."""
jpayne@7 417 state = self.__dict__.copy()
jpayne@7 418 # remove the unpickleable RLock object
jpayne@7 419 state.pop("_cookies_lock")
jpayne@7 420 return state
jpayne@7 421
jpayne@7 422 def __setstate__(self, state):
jpayne@7 423 """Unlike a normal CookieJar, this class is pickleable."""
jpayne@7 424 self.__dict__.update(state)
jpayne@7 425 if "_cookies_lock" not in self.__dict__:
jpayne@7 426 self._cookies_lock = threading.RLock()
jpayne@7 427
jpayne@7 428 def copy(self):
jpayne@7 429 """Return a copy of this RequestsCookieJar."""
jpayne@7 430 new_cj = RequestsCookieJar()
jpayne@7 431 new_cj.set_policy(self.get_policy())
jpayne@7 432 new_cj.update(self)
jpayne@7 433 return new_cj
jpayne@7 434
jpayne@7 435 def get_policy(self):
jpayne@7 436 """Return the CookiePolicy instance used."""
jpayne@7 437 return self._policy
jpayne@7 438
jpayne@7 439
jpayne@7 440 def _copy_cookie_jar(jar):
jpayne@7 441 if jar is None:
jpayne@7 442 return None
jpayne@7 443
jpayne@7 444 if hasattr(jar, "copy"):
jpayne@7 445 # We're dealing with an instance of RequestsCookieJar
jpayne@7 446 return jar.copy()
jpayne@7 447 # We're dealing with a generic CookieJar instance
jpayne@7 448 new_jar = copy.copy(jar)
jpayne@7 449 new_jar.clear()
jpayne@7 450 for cookie in jar:
jpayne@7 451 new_jar.set_cookie(copy.copy(cookie))
jpayne@7 452 return new_jar
jpayne@7 453
jpayne@7 454
jpayne@7 455 def create_cookie(name, value, **kwargs):
jpayne@7 456 """Make a cookie from underspecified parameters.
jpayne@7 457
jpayne@7 458 By default, the pair of `name` and `value` will be set for the domain ''
jpayne@7 459 and sent on every request (this is sometimes called a "supercookie").
jpayne@7 460 """
jpayne@7 461 result = {
jpayne@7 462 "version": 0,
jpayne@7 463 "name": name,
jpayne@7 464 "value": value,
jpayne@7 465 "port": None,
jpayne@7 466 "domain": "",
jpayne@7 467 "path": "/",
jpayne@7 468 "secure": False,
jpayne@7 469 "expires": None,
jpayne@7 470 "discard": True,
jpayne@7 471 "comment": None,
jpayne@7 472 "comment_url": None,
jpayne@7 473 "rest": {"HttpOnly": None},
jpayne@7 474 "rfc2109": False,
jpayne@7 475 }
jpayne@7 476
jpayne@7 477 badargs = set(kwargs) - set(result)
jpayne@7 478 if badargs:
jpayne@7 479 raise TypeError(
jpayne@7 480 f"create_cookie() got unexpected keyword arguments: {list(badargs)}"
jpayne@7 481 )
jpayne@7 482
jpayne@7 483 result.update(kwargs)
jpayne@7 484 result["port_specified"] = bool(result["port"])
jpayne@7 485 result["domain_specified"] = bool(result["domain"])
jpayne@7 486 result["domain_initial_dot"] = result["domain"].startswith(".")
jpayne@7 487 result["path_specified"] = bool(result["path"])
jpayne@7 488
jpayne@7 489 return cookielib.Cookie(**result)
jpayne@7 490
jpayne@7 491
jpayne@7 492 def morsel_to_cookie(morsel):
jpayne@7 493 """Convert a Morsel object into a Cookie containing the one k/v pair."""
jpayne@7 494
jpayne@7 495 expires = None
jpayne@7 496 if morsel["max-age"]:
jpayne@7 497 try:
jpayne@7 498 expires = int(time.time() + int(morsel["max-age"]))
jpayne@7 499 except ValueError:
jpayne@7 500 raise TypeError(f"max-age: {morsel['max-age']} must be integer")
jpayne@7 501 elif morsel["expires"]:
jpayne@7 502 time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
jpayne@7 503 expires = calendar.timegm(time.strptime(morsel["expires"], time_template))
jpayne@7 504 return create_cookie(
jpayne@7 505 comment=morsel["comment"],
jpayne@7 506 comment_url=bool(morsel["comment"]),
jpayne@7 507 discard=False,
jpayne@7 508 domain=morsel["domain"],
jpayne@7 509 expires=expires,
jpayne@7 510 name=morsel.key,
jpayne@7 511 path=morsel["path"],
jpayne@7 512 port=None,
jpayne@7 513 rest={"HttpOnly": morsel["httponly"]},
jpayne@7 514 rfc2109=False,
jpayne@7 515 secure=bool(morsel["secure"]),
jpayne@7 516 value=morsel.value,
jpayne@7 517 version=morsel["version"] or 0,
jpayne@7 518 )
jpayne@7 519
jpayne@7 520
jpayne@7 521 def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
jpayne@7 522 """Returns a CookieJar from a key/value dictionary.
jpayne@7 523
jpayne@7 524 :param cookie_dict: Dict of key/values to insert into CookieJar.
jpayne@7 525 :param cookiejar: (optional) A cookiejar to add the cookies to.
jpayne@7 526 :param overwrite: (optional) If False, will not replace cookies
jpayne@7 527 already in the jar with new ones.
jpayne@7 528 :rtype: CookieJar
jpayne@7 529 """
jpayne@7 530 if cookiejar is None:
jpayne@7 531 cookiejar = RequestsCookieJar()
jpayne@7 532
jpayne@7 533 if cookie_dict is not None:
jpayne@7 534 names_from_jar = [cookie.name for cookie in cookiejar]
jpayne@7 535 for name in cookie_dict:
jpayne@7 536 if overwrite or (name not in names_from_jar):
jpayne@7 537 cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
jpayne@7 538
jpayne@7 539 return cookiejar
jpayne@7 540
jpayne@7 541
jpayne@7 542 def merge_cookies(cookiejar, cookies):
jpayne@7 543 """Add cookies to cookiejar and returns a merged CookieJar.
jpayne@7 544
jpayne@7 545 :param cookiejar: CookieJar object to add the cookies to.
jpayne@7 546 :param cookies: Dictionary or CookieJar object to be added.
jpayne@7 547 :rtype: CookieJar
jpayne@7 548 """
jpayne@7 549 if not isinstance(cookiejar, cookielib.CookieJar):
jpayne@7 550 raise ValueError("You can only merge into CookieJar")
jpayne@7 551
jpayne@7 552 if isinstance(cookies, dict):
jpayne@7 553 cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False)
jpayne@7 554 elif isinstance(cookies, cookielib.CookieJar):
jpayne@7 555 try:
jpayne@7 556 cookiejar.update(cookies)
jpayne@7 557 except AttributeError:
jpayne@7 558 for cookie_in_jar in cookies:
jpayne@7 559 cookiejar.set_cookie(cookie_in_jar)
jpayne@7 560
jpayne@7 561 return cookiejar