mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-09 01:03:24 +00:00
Tornado support
This commit is contained in:
@@ -16,6 +16,7 @@ env:
|
|||||||
- WITH_LIB="urllib31.7"
|
- WITH_LIB="urllib31.7"
|
||||||
- WITH_LIB="urllib31.9"
|
- WITH_LIB="urllib31.9"
|
||||||
- WITH_LIB="urllib31.10"
|
- WITH_LIB="urllib31.10"
|
||||||
|
- WITH_LIB="tornado"
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: WITH_LIB="boto"
|
- env: WITH_LIB="boto"
|
||||||
@@ -45,4 +46,5 @@ install:
|
|||||||
- if [ $WITH_LIB = "urllib31.7" ] ; then pip install certifi urllib3==1.7.1; fi
|
- if [ $WITH_LIB = "urllib31.7" ] ; then pip install certifi urllib3==1.7.1; fi
|
||||||
- if [ $WITH_LIB = "urllib31.9" ] ; then pip install certifi urllib3==1.9.1; fi
|
- if [ $WITH_LIB = "urllib31.9" ] ; then pip install certifi urllib3==1.9.1; fi
|
||||||
- if [ $WITH_LIB = "urllib31.10" ] ; then pip install certifi urllib3==1.10.2; fi
|
- if [ $WITH_LIB = "urllib31.10" ] ; then pip install certifi urllib3==1.10.2; fi
|
||||||
|
- if [ $WITH_LIB = "tornado" ] ; then pip install tornado==4.2 pytest-tornado pycurl; fi
|
||||||
script: python setup.py test
|
script: python setup.py test
|
||||||
|
|||||||
205
tests/integration/test_tornado.py
Normal file
205
tests/integration/test_tornado.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''Test requests' interaction with vcr'''
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import vcr
|
||||||
|
|
||||||
|
from assertions import assert_cassette_empty, assert_is_json
|
||||||
|
|
||||||
|
|
||||||
|
http = pytest.importorskip("tornado.httpclient")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(params=['simple', 'curl', 'default'])
|
||||||
|
def get_client(request):
|
||||||
|
if request.param == 'simple':
|
||||||
|
from tornado import simple_httpclient as simple
|
||||||
|
return (lambda: simple.SimpleAsyncHTTPClient())
|
||||||
|
elif request.param == 'curl':
|
||||||
|
curl = pytest.importorskip("tornado.curl_httpclient")
|
||||||
|
return (lambda: curl.CurlAsyncHTTPClient())
|
||||||
|
else:
|
||||||
|
return (lambda: http.AsyncHTTPClient())
|
||||||
|
|
||||||
|
|
||||||
|
def get(client, url, **kwargs):
|
||||||
|
raise_error = kwargs.pop('raise_error', True)
|
||||||
|
return client.fetch(
|
||||||
|
http.HTTPRequest(url, method='GET', **kwargs),
|
||||||
|
raise_error=raise_error,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def post(client, url, data=None, **kwargs):
|
||||||
|
if data:
|
||||||
|
kwargs['body'] = json.dumps(data)
|
||||||
|
return client.fetch(http.HTTPRequest(url, method='POST', **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(params=["https", "http"])
|
||||||
|
def scheme(request):
|
||||||
|
'''Fixture that returns both http and https.'''
|
||||||
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_status_code(get_client, scheme, tmpdir):
|
||||||
|
'''Ensure that we can read the status code'''
|
||||||
|
url = scheme + '://httpbin.org/'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))):
|
||||||
|
status_code = (yield get(get_client(), url)).code
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('atts.yaml'))) as cass:
|
||||||
|
assert status_code == (yield get(get_client(), url)).code
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_headers(get_client, scheme, tmpdir):
|
||||||
|
'''Ensure that we can read the headers back'''
|
||||||
|
url = scheme + '://httpbin.org/'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
|
||||||
|
headers = (yield get(get_client(), url)).headers
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cass:
|
||||||
|
assert headers == (yield get(get_client(), url)).headers
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_body(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure the responses are all identical enough'''
|
||||||
|
|
||||||
|
url = scheme + '://httpbin.org/bytes/1024'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('body.yaml'))):
|
||||||
|
content = (yield get(get_client(), url)).body
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('body.yaml'))) as cass:
|
||||||
|
assert content == (yield get(get_client(), url)).body
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_auth(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure that we can handle basic auth'''
|
||||||
|
auth = ('user', 'passwd')
|
||||||
|
url = scheme + '://httpbin.org/basic-auth/user/passwd'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
|
||||||
|
one = yield get(
|
||||||
|
get_client(), url, auth_username=auth[0], auth_password=auth[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))) as cass:
|
||||||
|
two = yield get(
|
||||||
|
get_client(), url, auth_username=auth[0], auth_password=auth[1]
|
||||||
|
)
|
||||||
|
assert one.body == two.body
|
||||||
|
assert one.code == two.code
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_auth_failed(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure that we can save failed auth statuses'''
|
||||||
|
auth = ('user', 'wrongwrongwrong')
|
||||||
|
url = scheme + '://httpbin.org/basic-auth/user/passwd'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||||
|
# Ensure that this is empty to begin with
|
||||||
|
assert_cassette_empty(cass)
|
||||||
|
one = yield get(
|
||||||
|
get_client(),
|
||||||
|
url,
|
||||||
|
auth_username=auth[0],
|
||||||
|
auth_password=auth[1],
|
||||||
|
raise_error=False
|
||||||
|
)
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
|
||||||
|
two = yield get(
|
||||||
|
get_client(),
|
||||||
|
url,
|
||||||
|
auth_username=auth[0],
|
||||||
|
auth_password=auth[1],
|
||||||
|
raise_error=False
|
||||||
|
)
|
||||||
|
assert one.body == two.body
|
||||||
|
assert one.code == two.code == 401
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_post(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure that we can post and cache the results'''
|
||||||
|
data = {'key1': 'value1', 'key2': 'value2'}
|
||||||
|
url = scheme + '://httpbin.org/post'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||||
|
req1 = (yield post(get_client(), url, data)).body
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))) as cass:
|
||||||
|
req2 = (yield post(get_client(), url, data)).body
|
||||||
|
|
||||||
|
assert req1 == req2
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_redirects(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure that we can handle redirects'''
|
||||||
|
url = scheme + '://httpbin.org/redirect-to?url=bytes/1024'
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))):
|
||||||
|
content = (yield get(get_client(), url)).body
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('requests.yaml'))) as cass:
|
||||||
|
assert content == (yield get(get_client(), url)).body
|
||||||
|
assert cass.play_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_cross_scheme(get_client, tmpdir, scheme):
|
||||||
|
'''Ensure that requests between schemes are treated separately'''
|
||||||
|
# First fetch a url under http, and then again under https and then
|
||||||
|
# ensure that we haven't served anything out of cache, and we have two
|
||||||
|
# requests / response pairs in the cassette
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||||
|
yield get(get_client(), 'https://httpbin.org/')
|
||||||
|
yield get(get_client(), 'http://httpbin.org/')
|
||||||
|
assert cass.play_count == 0
|
||||||
|
assert len(cass) == 2
|
||||||
|
|
||||||
|
# Then repeat the same requests and ensure both were replayed.
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('cross_scheme.yaml'))) as cass:
|
||||||
|
yield get(get_client(), 'https://httpbin.org/')
|
||||||
|
yield get(get_client(), 'http://httpbin.org/')
|
||||||
|
assert cass.play_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_gzip(get_client, tmpdir, scheme):
|
||||||
|
'''
|
||||||
|
Ensure that httpclient is able to automatically decompress the response
|
||||||
|
body
|
||||||
|
'''
|
||||||
|
url = scheme + '://httpbin.org/gzip'
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))):
|
||||||
|
response = yield get(get_client(), url, decompress_response=True)
|
||||||
|
assert_is_json(response.body)
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join('gzip.yaml'))) as cass:
|
||||||
|
response = yield get(get_client(), url, decompress_response=True)
|
||||||
|
assert_is_json(response.body)
|
||||||
|
assert 1 == cass.play_count
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gen_test
|
||||||
|
def test_https_with_cert_validation_disabled(get_client, tmpdir):
|
||||||
|
cass_path = str(tmpdir.join('cert_validation_disabled.yaml'))
|
||||||
|
|
||||||
|
with vcr.use_cassette(cass_path):
|
||||||
|
yield get(get_client(), 'https://httpbin.org', validate_cert=False)
|
||||||
|
|
||||||
|
with vcr.use_cassette(cass_path) as cass:
|
||||||
|
yield get(get_client(), 'https://httpbin.org', validate_cert=False)
|
||||||
|
assert 1 == cass.play_count
|
||||||
5
tox.ini
5
tox.ini
@@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = {py26,py27,py33,py34,pypy}-{requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib317,urllib319,urllib3110,boto}
|
envlist = {py26,py27,py33,py34,pypy}-{requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib317,urllib319,urllib3110,tornado,boto}
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands =
|
commands =
|
||||||
@@ -26,4 +26,7 @@ deps =
|
|||||||
urllib317: urllib3==1.7.1
|
urllib317: urllib3==1.7.1
|
||||||
urllib319: urllib3==1.9.1
|
urllib319: urllib3==1.9.1
|
||||||
urllib3110: urllib3==1.10.2
|
urllib3110: urllib3==1.10.2
|
||||||
|
tornado: tornado
|
||||||
|
tornado: pytest-tornado
|
||||||
|
tornado: pycurl
|
||||||
boto: boto
|
boto: boto
|
||||||
|
|||||||
62
vcr/patch.py
62
vcr/patch.py
@@ -52,6 +52,25 @@ else:
|
|||||||
_CertValidatingHTTPSConnection = boto.https_connection.CertValidatingHTTPSConnection
|
_CertValidatingHTTPSConnection = boto.https_connection.CertValidatingHTTPSConnection
|
||||||
|
|
||||||
|
|
||||||
|
# Try to save the original types for Tornado
|
||||||
|
try:
|
||||||
|
import tornado.httpclient
|
||||||
|
import tornado.simple_httpclient
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
_AsyncHTTPClient = tornado.httpclient.AsyncHTTPClient
|
||||||
|
_SimpleAsyncHTTPClient = tornado.simple_httpclient.SimpleAsyncHTTPClient
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tornado.curl_httpclient
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
_CurlAsyncHTTPClient = tornado.curl_httpclient.CurlAsyncHTTPClient
|
||||||
|
|
||||||
|
|
||||||
class CassettePatcherBuilder(object):
|
class CassettePatcherBuilder(object):
|
||||||
|
|
||||||
def _build_patchers_from_mock_triples_decorator(function):
|
def _build_patchers_from_mock_triples_decorator(function):
|
||||||
@@ -68,10 +87,11 @@ class CassettePatcherBuilder(object):
|
|||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
return itertools.chain(
|
return itertools.chain(
|
||||||
self._httplib(), self._requests(), self._urllib3(), self._httplib2(),
|
self._httplib(), self._requests(), self._urllib3(),
|
||||||
self._boto(), self._build_patchers_from_mock_triples(
|
self._httplib2(), self._boto(), self._tornado(),
|
||||||
|
self._build_patchers_from_mock_triples(
|
||||||
self._cassette.custom_patches
|
self._cassette.custom_patches
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def _build_patchers_from_mock_triples(self, mock_triples):
|
def _build_patchers_from_mock_triples(self, mock_triples):
|
||||||
@@ -205,6 +225,27 @@ class CassettePatcherBuilder(object):
|
|||||||
from .stubs.boto_stubs import VCRCertValidatingHTTPSConnection
|
from .stubs.boto_stubs import VCRCertValidatingHTTPSConnection
|
||||||
yield cpool, 'CertValidatingHTTPSConnection', VCRCertValidatingHTTPSConnection
|
yield cpool, 'CertValidatingHTTPSConnection', VCRCertValidatingHTTPSConnection
|
||||||
|
|
||||||
|
@_build_patchers_from_mock_triples_decorator
|
||||||
|
def _tornado(self):
|
||||||
|
try:
|
||||||
|
import tornado.httpclient as http
|
||||||
|
import tornado.simple_httpclient as simple
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
from .stubs.tornado_stubs import VCRAsyncHTTPClient
|
||||||
|
from .stubs.tornado_stubs import VCRSimpleAsyncHTTPClient
|
||||||
|
|
||||||
|
yield http, 'AsyncHTTPClient', VCRAsyncHTTPClient
|
||||||
|
yield simple, 'SimpleAsyncHTTPClient', VCRSimpleAsyncHTTPClient
|
||||||
|
try:
|
||||||
|
import tornado.curl_httpclient as curl
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
from .stubs.tornado_stubs import VCRCurlAsyncHTTPClient
|
||||||
|
yield curl, 'CurlAsyncHTTPClient', VCRCurlAsyncHTTPClient
|
||||||
|
|
||||||
def _urllib3_patchers(self, cpool, stubs):
|
def _urllib3_patchers(self, cpool, stubs):
|
||||||
http_connection_remover = ConnectionRemover(
|
http_connection_remover = ConnectionRemover(
|
||||||
self._get_cassette_subclass(stubs.VCRRequestsHTTPConnection)
|
self._get_cassette_subclass(stubs.VCRRequestsHTTPConnection)
|
||||||
@@ -320,6 +361,21 @@ def reset_patchers():
|
|||||||
yield mock.patch.object(cpool, 'CertValidatingHTTPSConnection',
|
yield mock.patch.object(cpool, 'CertValidatingHTTPSConnection',
|
||||||
_CertValidatingHTTPSConnection)
|
_CertValidatingHTTPSConnection)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tornado.httpclient as http
|
||||||
|
import tornado.simple_httpclient as simple
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
yield mock.patch.object(http, 'AsyncHTTPClient', _AsyncHTTPClient)
|
||||||
|
yield mock.patch.object(simple, 'SimpleAsyncHTTPClient', _SimpleAsyncHTTPClient)
|
||||||
|
try:
|
||||||
|
import tornado.curl_httpclient as curl
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
yield mock.patch.object(curl, 'CurlAsyncHTTPClient', _CurlAsyncHTTPClient)
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def force_reset():
|
def force_reset():
|
||||||
|
|||||||
147
vcr/stubs/tornado_stubs.py
Normal file
147
vcr/stubs/tornado_stubs.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
'''Stubs for tornado HTTP clients'''
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from six import BytesIO
|
||||||
|
|
||||||
|
from tornado import httputil
|
||||||
|
from tornado.httpclient import AsyncHTTPClient
|
||||||
|
from tornado.httpclient import HTTPResponse
|
||||||
|
from tornado.simple_httpclient import SimpleAsyncHTTPClient
|
||||||
|
|
||||||
|
from vcr.errors import CannotOverwriteExistingCassetteException
|
||||||
|
from vcr.request import Request
|
||||||
|
|
||||||
|
|
||||||
|
class _VCRAsyncClient(object):
|
||||||
|
cassette = None
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
from vcr.patch import force_reset
|
||||||
|
with force_reset():
|
||||||
|
return super(_VCRAsyncClient, cls).__new__(cls, *args, **kwargs)
|
||||||
|
|
||||||
|
def initialize(self, *args, **kwargs):
|
||||||
|
from vcr.patch import force_reset
|
||||||
|
with force_reset():
|
||||||
|
self.real_client = self._baseclass(*args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def io_loop(self):
|
||||||
|
return self.real_client.io_loop
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _closed(self):
|
||||||
|
return self.real_client._closed
|
||||||
|
|
||||||
|
@property
|
||||||
|
def defaults(self):
|
||||||
|
return self.real_client.defaults
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
from vcr.patch import force_reset
|
||||||
|
with force_reset():
|
||||||
|
self.real_client.close()
|
||||||
|
|
||||||
|
def fetch_impl(self, request, callback):
|
||||||
|
headers = dict(request.headers)
|
||||||
|
if request.user_agent:
|
||||||
|
headers.setdefault('User-Agent', request.user_agent)
|
||||||
|
|
||||||
|
# TODO body_producer, header_callback, and streaming_callback are not
|
||||||
|
# yet supported.
|
||||||
|
|
||||||
|
unsupported_call = (
|
||||||
|
request.body_producer is not None or
|
||||||
|
request.header_callback is not None or
|
||||||
|
request.streaming_callback is not None
|
||||||
|
)
|
||||||
|
if unsupported_call:
|
||||||
|
response = HTTPResponse(
|
||||||
|
request,
|
||||||
|
599,
|
||||||
|
error=Exception(
|
||||||
|
"The request (%s) uses AsyncHTTPClient functionality "
|
||||||
|
"that is not yet supported by VCR.py. Please make the "
|
||||||
|
"request outside a VCR.py context." % repr(request)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
vcr_request = Request(
|
||||||
|
request.method,
|
||||||
|
request.url,
|
||||||
|
request.body,
|
||||||
|
headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.cassette.can_play_response_for(vcr_request):
|
||||||
|
vcr_response = self.cassette.play_response(vcr_request)
|
||||||
|
headers = httputil.HTTPHeaders()
|
||||||
|
|
||||||
|
recorded_headers = vcr_response['headers']
|
||||||
|
if isinstance(recorded_headers, dict):
|
||||||
|
recorded_headers = recorded_headers.items()
|
||||||
|
for k, vs in recorded_headers:
|
||||||
|
for v in vs:
|
||||||
|
headers.add(k, v)
|
||||||
|
response = HTTPResponse(
|
||||||
|
request,
|
||||||
|
code=vcr_response['status']['code'],
|
||||||
|
reason=vcr_response['status']['message'],
|
||||||
|
headers=headers,
|
||||||
|
buffer=BytesIO(vcr_response['body']['string']),
|
||||||
|
)
|
||||||
|
callback(response)
|
||||||
|
else:
|
||||||
|
if self.cassette.write_protected and self.cassette.filter_request(
|
||||||
|
vcr_request
|
||||||
|
):
|
||||||
|
response = HTTPResponse(
|
||||||
|
request,
|
||||||
|
599,
|
||||||
|
error=CannotOverwriteExistingCassetteException(
|
||||||
|
"No match for the request (%r) was found. "
|
||||||
|
"Can't overwrite existing cassette (%r) in "
|
||||||
|
"your current record mode (%r)."
|
||||||
|
% (vcr_request, self.cassette._path,
|
||||||
|
self.cassette.record_mode)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
callback(response)
|
||||||
|
|
||||||
|
def new_callback(response):
|
||||||
|
headers = [
|
||||||
|
(k, response.headers.get_list(k))
|
||||||
|
for k in response.headers.keys()
|
||||||
|
]
|
||||||
|
|
||||||
|
vcr_response = {
|
||||||
|
'status': {
|
||||||
|
'code': response.code,
|
||||||
|
'message': response.reason,
|
||||||
|
},
|
||||||
|
'headers': headers,
|
||||||
|
'body': {'string': response.body},
|
||||||
|
}
|
||||||
|
self.cassette.append(vcr_request, vcr_response)
|
||||||
|
callback(response)
|
||||||
|
|
||||||
|
from vcr.patch import force_reset
|
||||||
|
with force_reset():
|
||||||
|
self.real_client.fetch_impl(request, new_callback)
|
||||||
|
|
||||||
|
|
||||||
|
class VCRAsyncHTTPClient(_VCRAsyncClient, AsyncHTTPClient):
|
||||||
|
_baseclass = AsyncHTTPClient
|
||||||
|
|
||||||
|
|
||||||
|
class VCRSimpleAsyncHTTPClient(_VCRAsyncClient, SimpleAsyncHTTPClient):
|
||||||
|
_baseclass = SimpleAsyncHTTPClient
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from tornado.curl_httpclient import CurlAsyncHTTPClient
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
VCRCurlAsyncHTTPClient = None
|
||||||
|
else:
|
||||||
|
class VCRCurlAsyncHTTPClient(_VCRAsyncClient, CurlAsyncHTTPClient):
|
||||||
|
_baseclass = CurlAsyncHTTPClient
|
||||||
Reference in New Issue
Block a user