1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-09 17:15:35 +00:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Kevin McCarthy
1bd3fbd2c6 bump version 2014-09-01 15:50:25 -10:00
Kevin McCarthy
cd715f37c6 Fix requests stub. Closes #94 2014-09-01 15:48:57 -10:00
Kevin McCarthy
9a1147196a getheader() in stubs should be case-insensitive 2014-08-01 16:28:21 -10:00
Kevin McCarthy
a23c5d8508 Merge pull request #87 from hartsock/master
Python 3: print_function
2014-07-24 18:10:24 -10:00
Shawn Hartsock
868a974900 Python 3: print_function
Use print function if you must print, this lets us use the
library in python 3 environments.

partial: https://github.com/kevin1024/vcrpy/issues/86
2014-07-24 16:33:47 -04:00
Kevin McCarthy
c56de472cd Remove extra colon in README
Closes #82
2014-07-07 16:02:29 -10:00
Kevin McCarthy
c6590f2caf bump version 2014-05-17 13:09:10 -10:00
Kevin McCarthy
70abc5058c requests 2.3 compat 2014-05-17 12:58:31 -10:00
Kevin McCarthy
0c1f1e2479 Version bump to 1.0.1 2014-05-17 09:44:02 -10:00
Kevin McCarthy
8d90dba16c Ignore requests before trying to play them
Closes #79
2014-05-17 09:34:50 -10:00
Kevin McCarthy
3072c56ed2 Update README.md 2014-05-12 09:22:09 -10:00
12 changed files with 228 additions and 70 deletions

View File

@@ -5,7 +5,9 @@ env:
- secure: AifoKzwhjV94cmcQZrdQmqRu/9rkZZvWpwBv1daeAQpLOKFPGsOm3D+x2cSw9+iCfkgDZDfqQVv1kCaFVxTll8v8jTq5SJdqEY0NmGWbj/UkNtShh609oRDsuzLxAEwtVKYjf/h8K2BRea+bl1tGkwZ2vtmYS6dxNlAijjWOfds=
- secure: LBSEg/gMj4u4Hrpo3zs6Y/1mTpd2RtcN49mZIFgTdbJ9IhpiNPqcEt647Lz94F9Eses2x2WbNuKqZKZZReY7QLbEzU1m0nN5jlaKrjcG5NR5clNABfFFyhgc0jBikyS4abAG8jc2efeaTrFuQwdoF4sE8YiVrkiVj2X5Xoi6sBk=
matrix:
- WITH_LIB="requests2.x"
- WITH_LIB="requests2.2"
- WITH_LIB="requests2.3"
- WITH_LIB="requests2.4"
- WITH_LIB="requests1.x"
- WITH_LIB="httplib2"
- WITH_LIB="boto"
@@ -15,15 +17,22 @@ matrix:
exclude:
- env: WITH_LIB="boto"
python: 3.3
- env: WITH_LIB="boto"
python: 3.4
- env: WITH_LIB="requests1.x"
python: 3.4
python:
- 2.6
- 2.7
- 3.3
- 3.4
- pypy
install:
- pip install PyYAML pytest pytest-localserver --use-mirrors
- if [ $WITH_LIB = "requests1.x" ] ; then pip install requests==1.2.3; fi
- if [ $WITH_LIB = "requests2.x" ] ; then pip install requests; fi
- if [ $WITH_LIB = "requests2.2" ] ; then pip install requests==2.2.1; fi
- if [ $WITH_LIB = "requests2.3" ] ; then pip install requests==2.3.0; fi
- if [ $WITH_LIB = "requests2.4" ] ; then pip install requests==2.4.0; fi
- if [ $WITH_LIB = "httplib2" ] ; then pip install httplib2; fi
- if [ $WITH_LIB = "boto" ] ; then pip install boto; fi
script: python setup.py test

View File

@@ -51,7 +51,7 @@ You can also use VCR.py as a decorator. The same request above would look like
this:
```python
@vcr.use_cassette('fixtures/vcr_cassettes/synopsis.yaml'):
@vcr.use_cassette('fixtures/vcr_cassettes/synopsis.yaml')
def test_iana():
response = urllib2.urlopen('http://www.iana.org/domains/reserved').read()
assert 'Example domains' in response
@@ -423,14 +423,21 @@ API in version 1.0.x
## Changelog
* 1.0.3: Fix an issue with requests 2.4 and make sure case sensitivity is
consistent across python versions
* 1.0.2: Fix an issue with requests 2.3
* 1.0.1: Fix a bug with the new ignore requests feature and the once
record mode
* 1.0.0: _BACKWARDS INCOMPATIBLE_: Please see the 'upgrade' section in the
README. Add support for filtering sensitive data from requests, matching
query strings after the order changes and improving the built-in matchers,
(thanks to @mshytikov), support for ignoring requests to certain hosts,
bump supported Python3 version to 3.4, fix some bugs with Boto support
(thanks @marusich), fix error with URL field capitalization in README
(thanks @simon-weber), added some log messages to help with debugging,
added `all_played` property on cassette (thanks @mshytikov)
README. Take a look at the matcher section as well, you might want to
update your `match_on` settings. Add support for filtering sensitive
data from requests, matching query strings after the order changes and
improving the built-in matchers, (thanks to @mshytikov), support for
ignoring requests to certain hosts, bump supported Python3 version to
3.4, fix some bugs with Boto support (thanks @marusich), fix error with
URL field capitalization in README (thanks @simon-weber), added some log
messages to help with debugging, added `all_played` property on cassette
(thanks @mshytikov)
* 0.7.0: VCR.py now supports Python 3! (thanks @asundg) Also I refactored
the stub connections quite a bit to add support for the putrequest and
putheader calls. This version also adds support for httplib2 (thanks

View File

@@ -20,7 +20,7 @@ class PyTest(TestCommand):
setup(
name='vcrpy',
version='1.0.0',
version='1.0.3',
description=(
"Automatically mock your HTTP interactions to simplify and "
"speed up testing"

View File

@@ -39,3 +39,17 @@ def test_ignore_localhost_and_httpbin(tmpdir, httpserver):
urlopen('http://httpbin.org')
urlopen(httpserver.url)
assert len(cass) == 0
def test_ignore_localhost_twice(tmpdir, httpserver):
httpserver.serve_content('Hello!')
cass_file = str(tmpdir.join('filter_qs.yaml'))
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
urlopen(httpserver.url)
assert len(cass) == 0
urlopen('http://httpbin.org')
assert len(cass) == 1
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
assert len(cass) == 1
urlopen(httpserver.url)
urlopen('http://httpbin.org')
assert len(cass) == 1

View File

@@ -145,3 +145,7 @@ def test_session_and_connection_close(tmpdir, scheme):
resp = session.get('http://httpbin.org/get', headers={'Connection': 'close'})
resp = session.get('http://httpbin.org/get', headers={'Connection': 'close'})
def test_https_with_cert_validation_disabled(tmpdir):
with vcr.use_cassette(str(tmpdir.join('cert_validation_disabled.yaml'))):
requests.get('https://httpbin.org', verify=False)

View File

@@ -0,0 +1,26 @@
import vcr
import six.moves.http_client as httplib
def _headers_are_case_insensitive():
conn = httplib.HTTPConnection('httpbin.org')
conn.request('GET', "/cookies/set?k1=v1")
r1 = conn.getresponse()
cookie_data1 = r1.getheader('set-cookie')
conn = httplib.HTTPConnection('httpbin.org')
conn.request('GET', "/cookies/set?k1=v1")
r2 = conn.getresponse()
cookie_data2 = r2.getheader('Set-Cookie')
return cookie_data1 == cookie_data2
def test_case_insensitivity(tmpdir):
testfile = str(tmpdir.join('case_insensitivity.yml'))
# check if headers are case insensitive outside of vcrpy
outside = _headers_are_case_insensitive()
with vcr.use_cassette(testfile):
# check if headers are case insensitive inside of vcrpy
inside = _headers_are_case_insensitive()
# check if headers are case insensitive after vcrpy deserializes headers
inside2 = _headers_are_case_insensitive()
# behavior should be the same both inside and outside
assert outside == inside == inside2

153
tox.ini
View File

@@ -10,15 +10,22 @@ envlist =
py33,
py34,
pypy,
py26requests,
py27requests,
py34requests,
pypyrequests,
py26oldrequests,
py27oldrequests,
py33oldrequests,
py34oldrequests,
pypyoldrequests,
py26requests24,
py27requests24,
py34requests24,
pypyrequests24,
py26requests23,
py27requests23,
py34requests23,
pypyrequests23,
py26requests22,
py27requests22,
py34requests22,
pypyrequests22,
py26requests1,
py27requests1,
py33requests1,
pypyrequests1,
py26httplib2,
py27httplib2,
py33httplib2,
@@ -34,7 +41,7 @@ deps =
pytest-localserver
PyYAML
[testenv:py26oldrequests]
[testenv:py26requests1]
basepython = python2.6
deps =
mock
@@ -43,7 +50,7 @@ deps =
PyYAML
requests==1.2.3
[testenv:py27oldrequests]
[testenv:py27requests1]
basepython = python2.7
deps =
mock
@@ -52,7 +59,7 @@ deps =
PyYAML
requests==1.2.3
[testenv:py33oldrequests]
[testenv:py33requests1]
basepython = python3.3
deps =
mock
@@ -61,16 +68,7 @@ deps =
PyYAML
requests==1.2.3
[testenv:py34oldrequests]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests==1.2.3
[testenv:pypyoldrequests]
[testenv:pypyrequests1]
basepython = pypy
deps =
mock
@@ -79,50 +77,141 @@ deps =
PyYAML
requests==1.2.3
[testenv:py26requests]
[testenv:py26requests24]
basepython = python2.6
deps =
mock
pytest
pytest-localserver
PyYAML
requests
requests==2.4.0
[testenv:py27requests]
[testenv:py27requests24]
basepython = python2.7
deps =
mock
pytest
pytest-localserver
PyYAML
requests
requests==2.4.0
[testenv:py33requests]
[testenv:py33requests24]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests
requests==2.4.0
[testenv:py34requests]
[testenv:py34requests24]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests
requests==2.4.0
[testenv:pypyrequests]
[testenv:pypyrequests24]
basepython = pypy
deps =
mock
pytest
pytest-localserver
PyYAML
requests
requests==2.4.0
[testenv:py26requests23]
basepython = python2.6
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.3.0
[testenv:py27requests23]
basepython = python2.7
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.3.0
[testenv:py33requests23]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.3.0
[testenv:py34requests23]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.3.0
[testenv:pypyrequests23]
basepython = pypy
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.3.0
[testenv:py26requests22]
basepython = python2.6
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.2.1
[testenv:py27requests22]
basepython = python2.7
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.2.1
[testenv:py33requests22]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.2.1
[testenv:py34requests22]
basepython = python3.4
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.2.1
[testenv:pypyrequests22]
basepython = pypy
deps =
mock
pytest
pytest-localserver
PyYAML
requests==2.2.1
[testenv:py26httplib2]
basepython = python2.6

View File

@@ -80,15 +80,18 @@ class Cassette(ContextDecorator):
return self.rewound and self.record_mode == 'once' or \
self.record_mode == 'none'
def append(self, request, response):
'''Add a request, response pair to this cassette'''
request = filter_request(
def _filter_request(self, request):
return filter_request(
request=request,
filter_headers=self._filter_headers,
filter_query_parameters=self._filter_query_parameters,
before_record=self._before_record,
ignore_hosts=self._ignore_hosts
)
def append(self, request, response):
'''Add a request, response pair to this cassette'''
request = self._filter_request(request)
if not request:
return
self.data.append((request, response))
@@ -99,19 +102,19 @@ class Cassette(ContextDecorator):
internal API, returns an iterator with all responses matching
the request.
"""
request = filter_request(
request=request,
filter_headers=self._filter_headers,
filter_query_parameters=self._filter_query_parameters,
before_record=self._before_record,
ignore_hosts=self._ignore_hosts
)
request = self._filter_request(request)
if not request:
return
for index, (stored_request, response) in enumerate(self.data):
if requests_match(request, stored_request, self._match_on):
yield index, response
def can_play_response_for(self, request):
request = self._filter_request(request)
return request and request in self and \
self.record_mode != 'all' and \
self.rewound
def play_response(self, request):
'''
Get the response corresponding to a request, but only if it

View File

@@ -1,3 +1,4 @@
from __future__ import print_function
from operator import itemgetter
from heapq import nlargest
from itertools import repeat, ifilter
@@ -189,5 +190,5 @@ class Counter(dict):
if __name__ == '__main__':
import doctest
print doctest.testmod()
print(doctest.testmod())

View File

@@ -56,15 +56,16 @@ def install(cassette):
# patch requests v1.x
try:
import requests.packages.urllib3.connectionpool as cpool
from .stubs.requests_stubs import VCRVerifiedHTTPSConnection
cpool.VerifiedHTTPSConnection = VCRVerifiedHTTPSConnection
from .stubs.requests_stubs import VCRRequestsHTTPConnection, VCRRequestsHTTPSConnection
cpool.VerifiedHTTPSConnection = VCRRequestsHTTPSConnection
cpool.HTTPConnection = VCRRequestsHTTPConnection
cpool.VerifiedHTTPSConnection.cassette = cassette
cpool.HTTPConnection = VCRHTTPConnection
cpool.HTTPConnection.cassette = cassette
# patch requests v2.x
cpool.HTTPConnectionPool.ConnectionCls = VCRHTTPConnection
cpool.HTTPConnectionPool.ConnectionCls = VCRRequestsHTTPConnection
cpool.HTTPConnectionPool.cassette = cassette
cpool.HTTPSConnectionPool.ConnectionCls = VCRHTTPSConnection
cpool.HTTPSConnectionPool.ConnectionCls = VCRRequestsHTTPSConnection
cpool.HTTPSConnectionPool.cassette = cassette
except ImportError: # pragma: no cover
pass

View File

@@ -111,8 +111,8 @@ class VCRHTTPResponse(HTTPResponse):
return compat.get_header_items(message)
def getheader(self, header, default=None):
headers = dict(((k, v) for k, v in self.getheaders()))
return headers.get(header, default)
headers = dict(((k.lower(), v) for k, v in self.getheaders()))
return headers.get(header.lower(), default)
class VCRConnection:
@@ -204,9 +204,7 @@ class VCRConnection:
'''Retrieve a the response'''
# Check to see if the cassette has a response for this request. If so,
# then return it
if self._vcr_request in self.cassette and \
self.cassette.record_mode != "all" and \
self.cassette.rewound:
if self.cassette.can_play_response_for(self._vcr_request):
log.info(
"Playing response for {0} from cassette".format(
self._vcr_request
@@ -215,7 +213,7 @@ class VCRConnection:
response = self.cassette.play_response(self._vcr_request)
return VCRHTTPResponse(response)
else:
if self.cassette.write_protected:
if self.cassette.write_protected and self.cassette._filter_request(self._vcr_request):
raise CannotOverwriteExistingCassetteException(
"Can't overwrite existing cassette (%r) in "
"your current record mode (%r)."
@@ -264,9 +262,7 @@ class VCRConnection:
"""
if hasattr(self, '_vcr_request') and \
self._vcr_request in self.cassette and \
self.cassette.record_mode != "all" and \
self.cassette.rewound:
self.cassette.can_play_response_for(self._vcr_request):
# We already have a response we are going to play, don't
# actually connect
return
@@ -289,6 +285,9 @@ class VCRConnection:
self.real_connection.sock = value
def __init__(self, *args, **kwargs):
if six.PY3:
kwargs.pop('strict', None) # apparently this is gone in py3
# need to temporarily reset here because the real connection
# inherits from the thing that we are mocking out. Take out
# the reset if you want to see what I mean :)

View File

@@ -1,8 +1,13 @@
'''Stubs for requests'''
from requests.packages.urllib3.connectionpool import VerifiedHTTPSConnection
from ..stubs import VCRHTTPSConnection
from requests.packages.urllib3.connectionpool import HTTPConnection, VerifiedHTTPSConnection
from ..stubs import VCRHTTPConnection, VCRHTTPSConnection
# urllib3 defines its own HTTPConnection classes, which requests goes ahead and assumes
# you're using. It includes some polyfills for newer features missing in older pythons.
class VCRVerifiedHTTPSConnection(VCRHTTPSConnection, VerifiedHTTPSConnection):
class VCRRequestsHTTPConnection(VCRHTTPConnection, HTTPConnection):
_baseclass = HTTPConnection
class VCRRequestsHTTPSConnection(VCRHTTPSConnection, VerifiedHTTPSConnection):
_baseclass = VerifiedHTTPSConnection