1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-08 16:53:23 +00:00

Add HeadersDict, and mark add_header deprecated.

HeadersDict is a subclass of CaseInsensitiveDict with two new features:

  1. Preserve the case of the header key from the first time it was set.
     This means that later munging won't modify the key case. (You can
     force picking up the new case with `del` followed by setting.)

  2. If the value is a list or tuple, unpack it and store the first
     element. This is the same as how `Request.add_header()` used to work.

For backward compatibility this commit preserves `Request.add_header()` but
marks it deprecated.
This commit is contained in:
Aron Griffis
2015-08-24 22:14:38 -04:00
parent 646d12df94
commit 7312229aef
4 changed files with 79 additions and 35 deletions

View File

@@ -1,3 +1,4 @@
import warnings
from six import BytesIO, text_type
from six.moves.urllib.parse import urlparse, parse_qsl
from .util import CaseInsensitiveDict
@@ -6,23 +7,6 @@ from .util import CaseInsensitiveDict
class Request(object):
"""
VCR's representation of a request.
There is a weird quirk in HTTP. You can send the same header twice. For
this reason, headers are represented by a dict, with lists as the values.
However, it appears that HTTPlib is completely incapable of sending the
same header twice. This puts me in a weird position: I want to be able to
accurately represent HTTP headers in cassettes, but I don't want the extra
step of always having to do [0] in the general case, i.e.
request.headers['key'][0]
In addition, some servers sometimes send the same header more than once,
and httplib *can* deal with this situation.
Futhermore, I wanted to keep the request and response cassette format as
similar as possible.
For this reason, in cassettes I keep a dict with lists as keys, but once
deserialized into VCR, I keep them as plain, naked dicts.
"""
def __init__(self, method, uri, body, headers):
@@ -33,9 +17,7 @@ class Request(object):
self.body = body.read()
else:
self.body = body
self.headers = CaseInsensitiveDict()
for key, value in headers.items():
self.add_header(key, value)
self.headers = headers
@property
def headers(self):
@@ -43,8 +25,8 @@ class Request(object):
@headers.setter
def headers(self, value):
if not isinstance(value, CaseInsensitiveDict):
value = CaseInsensitiveDict(value)
if not isinstance(value, HeadersDict):
value = HeadersDict(value)
self._headers = value
@property
@@ -58,11 +40,10 @@ class Request(object):
self._body = value
def add_header(self, key, value):
# see class docstring for an explanation
if isinstance(value, (tuple, list)):
self.headers[key] = value[0]
else:
self.headers[key] = value
warnings.warn("Request.add_header is deprecated. "
"Please assign to request.headers instead.",
DeprecationWarning)
self.headers[key] = value
@property
def scheme(self):
@@ -116,3 +97,35 @@ class Request(object):
@classmethod
def _from_dict(cls, dct):
return Request(**dct)
class HeadersDict(CaseInsensitiveDict):
"""
There is a weird quirk in HTTP. You can send the same header twice. For
this reason, headers are represented by a dict, with lists as the values.
However, it appears that HTTPlib is completely incapable of sending the
same header twice. This puts me in a weird position: I want to be able to
accurately represent HTTP headers in cassettes, but I don't want the extra
step of always having to do [0] in the general case, i.e.
request.headers['key'][0]
In addition, some servers sometimes send the same header more than once,
and httplib *can* deal with this situation.
Futhermore, I wanted to keep the request and response cassette format as
similar as possible.
For this reason, in cassettes I keep a dict with lists as keys, but once
deserialized into VCR, I keep them as plain, naked dicts.
"""
def __setitem__(self, key, value):
if isinstance(value, (tuple, list)):
value = value[0]
# Preserve the case from the first time this key was set.
old = self._store.get(key.lower())
if old:
key = old[0]
super(HeadersDict, self).__setitem__(key, value)