1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-09 01:03:24 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Kevin McCarthy
57a934d14b version bump to 1.10.0 2016-08-14 10:41:25 -10:00
Kevin McCarthy
f9d7ccd33e Merge pull request #266 from lamenezes/aiohttp-support
Aiohttp support
2016-08-14 10:37:14 -10:00
Luiz Menezes
265a158fe7 remove py26-flakes test 2016-08-12 13:50:29 -03:00
Luiz Menezes
c65ff0e7b3 fix flake8: ignore yield from syntax errors 2016-08-11 19:48:40 -03:00
Luiz Menezes
066752aa0b rename file 2016-08-11 08:32:47 -03:00
Luiz Menezes
9a5214888b fix tox's flakes tests 2016-08-11 00:58:18 -03:00
Luiz Menezes
609d8e35be fix test_aiohttp 2016-08-10 18:12:38 -03:00
Luiz Menezes
ce14de8251 fix tests 2016-08-10 15:56:19 -03:00
Luiz Menezes
574b22a62a remove async/await from aiohttp_stubs to support python 3.4 2016-08-10 15:51:11 -03:00
Luiz Menezes
1167b9ea4e fix .travis.yml 2016-08-04 14:03:42 -03:00
Luiz Menezes
77ae99bfda add aiohttp to tests config 2016-08-04 13:44:11 -03:00
Luiz Menezes
8851571ba7 add integration tests for aiohttp 2016-08-04 13:40:04 -03:00
Luiz Menezes
f71d28d10e fix aiohttp_stubs.vcr_request error message 2016-08-04 13:39:46 -03:00
Luiz Menezes
3355bd01eb fix aiohttp response closing 2016-08-04 13:39:09 -03:00
Luiz Menezes
17afa82bf4 remove CIMultiDictProxy from aiohttp_stubs.vcr_request 2016-08-04 13:37:55 -03:00
Luiz Menezes
f98684e8aa add support for aiohttp 2016-08-04 00:21:49 -03:00
Kevin McCarthy
5a85e88a39 Merge pull request #265 from adamchainz/readthedocs.io
Convert readthedocs links for their .org -> .io migration for hosted projects
2016-07-16 09:08:29 -10:00
Kevin McCarthy
d2368eb2c4 fix flaky test 2016-07-16 08:58:07 -10:00
Adam Chainz
37665581e0 Convert readthedocs links for their .org -> .io migration for hosted projects
As per [their blog post of the 27th April](https://blog.readthedocs.com/securing-subdomains/) ‘Securing subdomains’:

> Starting today, Read the Docs will start hosting projects from subdomains on the domain readthedocs.io, instead of on readthedocs.org. This change addresses some security concerns around site cookies while hosting user generated data on the same domain as our dashboard.

Test Plan: Manually visited all the links I’ve modified.
2016-07-13 23:24:04 +01:00
12 changed files with 228 additions and 9 deletions

View File

@@ -22,11 +22,14 @@ env:
- TOX_SUFFIX="urllib3110"
- TOX_SUFFIX="tornado3"
- TOX_SUFFIX="tornado4"
- TOX_SUFFIX="aiohttp"
matrix:
allow_failures:
- env: TOX_SUFFIX="boto"
- env: TOX_SUFFIX="boto3"
exclude:
- env: TOX_SUFFIX="flakes"
python: 2.6
- env: TOX_SUFFIX="boto"
python: 3.3
- env: TOX_SUFFIX="boto"
@@ -35,6 +38,16 @@ matrix:
python: 3.4
- env: TOX_SUFFIX="requests1"
python: 3.5
- env: TOX_SUFFIX="aiohttp"
python: 2.6
- env: TOX_SUFFIX="aiohttp"
python: 2.7
- env: TOX_SUFFIX="aiohttp"
python: 3.3
- env: TOX_SUFFIX="aiohttp"
python: pypy
- env: TOX_SUFFIX="aiohttp"
python: pypy3
python:
- 2.6
- 2.7

View File

@@ -13,7 +13,7 @@ Source code
https://github.com/kevin1024/vcrpy
Documentation
https://vcrpy.readthedocs.org/
https://vcrpy.readthedocs.io/
Rationale
---------
@@ -41,6 +41,20 @@ VCR.py will detect the absence of a cassette file and once again record
all HTTP interactions, which will update them to correspond to the new
API.
Support
-------
VCR.py works great with the following HTTP clients:
- requests
- aiohttp
- urllib3
- tornado
- urllib2
- boto
- boto3
License
=======

View File

@@ -1,5 +1,6 @@
Changelog
---------
- 1.10.0 Add support for aiohttp (thanks @lamenezes)
- 1.9.0 Add support for boto3 (thanks @desdm, @foorbarna). Fix deepcopy issue
for response headers when `decode_compressed_response` is enabled (thanks
@nickdirienzo)

View File

@@ -110,7 +110,7 @@ todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages.
# https://read-the-docs.readthedocs.org/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs
# https://read-the-docs.readthedocs.io/en/latest/theme.html#how-do-i-use-this-locally-and-on-read-the-docs
if 'READTHEDOCS' not in os.environ:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'

View File

@@ -19,7 +19,7 @@ that has ``requests`` installed.
Also, in order for the boto tests to run, you will need an AWS key.
Refer to the `boto
documentation <http://boto.readthedocs.org/en/latest/getting_started.html>`__
documentation <https://boto.readthedocs.io/en/latest/getting_started.html>`__
for how to set this up. I have marked the boto tests as optional in
Travis so you don't have to worry about them failing if you submit a
pull request.

View File

@@ -51,7 +51,7 @@ except Exception:
setup(
name='vcrpy',
version='1.9.0',
version='1.10.0',
description=(
"Automatically mock your HTTP interactions to simplify and "
"speed up testing"

View File

@@ -0,0 +1,7 @@
import asyncio
@asyncio.coroutine
def aiohttp_request(session, method, url, as_text, **kwargs):
response = yield from session.request(method, url, **kwargs) # NOQA: E999
return response, (yield from response.text()) if as_text else (yield from response.json()) # NOQA: E999

View File

@@ -0,0 +1,87 @@
import pytest
aiohttp = pytest.importorskip("aiohttp")
import asyncio # NOQA
import sys # NOQA
import aiohttp # NOQA
import pytest # NOQA
import vcr # NOQA
from .aiohttp_utils import aiohttp_request # NOQA
def get(url, as_text=True, **kwargs):
loop = asyncio.get_event_loop()
with aiohttp.ClientSession() as session:
task = loop.create_task(aiohttp_request(session, 'GET', url, as_text, **kwargs))
return loop.run_until_complete(task)
def post(url, as_text=True, **kwargs):
loop = asyncio.get_event_loop()
with aiohttp.ClientSession() as session:
task = loop.create_task(aiohttp_request(session, 'POST', url, as_text, **kwargs))
return loop.run_until_complete(task)
@pytest.fixture(params=["https", "http"])
def scheme(request):
'''Fixture that returns both http and https.'''
return request.param
def test_status(tmpdir, scheme):
url = scheme + '://httpbin.org'
with vcr.use_cassette(str(tmpdir.join('status.yaml'))):
response, _ = get(url)
with vcr.use_cassette(str(tmpdir.join('status.yaml'))) as cassette:
cassette_response, _ = get(url)
assert cassette_response.status == response.status
assert cassette.play_count == 1
def test_headers(tmpdir, scheme):
url = scheme + '://httpbin.org'
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))):
response, _ = get(url)
with vcr.use_cassette(str(tmpdir.join('headers.yaml'))) as cassette:
cassette_response, _ = get(url)
assert cassette_response.headers == response.headers
assert cassette.play_count == 1
def test_text(tmpdir, scheme):
url = scheme + '://httpbin.org'
with vcr.use_cassette(str(tmpdir.join('text.yaml'))):
_, response_text = get(url)
with vcr.use_cassette(str(tmpdir.join('text.yaml'))) as cassette:
_, cassette_response_text = get(url)
assert cassette_response_text == response_text
assert cassette.play_count == 1
def test_json(tmpdir, scheme):
url = scheme + '://httpbin.org/get'
with vcr.use_cassette(str(tmpdir.join('json.yaml'))):
_, response_json = get(url, as_text=False)
with vcr.use_cassette(str(tmpdir.join('json.yaml'))) as cassette:
_, cassette_response_json = get(url, as_text=False)
assert cassette_response_json == response_json
assert cassette.play_count == 1
def test_post(tmpdir, scheme):
data = {'key1': 'value1', 'key2': 'value2'}
url = scheme + '://httpbin.org/post'
with vcr.use_cassette(str(tmpdir.join('post.yaml'))):
_, response_json = post(url, data=data)
with vcr.use_cassette(str(tmpdir.join('post.yaml'))) as cassette:
_, cassette_response_json = post(url, data=data)
assert cassette_response_json == response_json
assert cassette.play_count == 1

View File

@@ -67,8 +67,8 @@ def test_original_decoded_response_is_not_modified(tmpdir, httpbin):
assert 'gzip' == inside.headers['content-encoding']
# They should effectively be the same response.
inside_headers = (h for h in inside.headers.items() if h[0] != 'Date')
outside_headers = (h for h in outside.getheaders() if h[0] != 'Date')
inside_headers = (h for h in inside.headers.items() if h[0].lower() != 'date')
outside_headers = (h for h in outside.getheaders() if h[0].lower() != 'date')
assert set(inside_headers) == set(outside_headers)
inside = zlib.decompress(inside.read(), 16+zlib.MAX_WBITS)
outside = zlib.decompress(outside.read(), 16+zlib.MAX_WBITS)

View File

@@ -1,11 +1,11 @@
[tox]
envlist = {py26,py27,py33,py34,pypy,pypy3}-{flakes,requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib317,urllib319,urllib3110,tornado3,tornado4,boto,boto3}
envlist = {py26,py27,py33,py34,pypy,pypy3}-{flakes,requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib317,urllib319,urllib3110,tornado3,tornado4,boto,boto3,aiohttp}
[testenv:flakes]
skipsdist = True
commands =
flake8 --version
flake8 --exclude="./docs/conf.py"
flake8 --exclude=./docs/conf.py,./.tox/
pyflakes ./docs/conf.py
deps = flake8
@@ -38,6 +38,7 @@ deps =
{py26,py27,py33,py34}-tornado4: pycurl
boto: boto
boto3: boto3
aiohttp: aiohttp
[flake8]
max_line_length = 110

View File

@@ -80,6 +80,13 @@ else:
_CurlAsyncHTTPClient_fetch_impl = \
tornado.curl_httpclient.CurlAsyncHTTPClient.fetch_impl
try:
import aiohttp.client
except ImportError: # pragma: no cover
pass
else:
_AiohttpClientSessionRequest = aiohttp.client.ClientSession._request
class CassettePatcherBuilder(object):
@@ -98,7 +105,7 @@ class CassettePatcherBuilder(object):
def build(self):
return itertools.chain(
self._httplib(), self._requests(), self._boto3(), self._urllib3(),
self._httplib2(), self._boto(), self._tornado(),
self._httplib2(), self._boto(), self._tornado(), self._aiohttp(),
self._build_patchers_from_mock_triples(
self._cassette.custom_patches
),
@@ -273,6 +280,19 @@ class CassettePatcherBuilder(object):
)
yield curl.CurlAsyncHTTPClient, 'fetch_impl', new_fetch_impl
@_build_patchers_from_mock_triples_decorator
def _aiohttp(self):
try:
import aiohttp.client as client
except ImportError: # pragma: no cover
pass
else:
from .stubs.aiohttp_stubs import vcr_request
new_request = vcr_request(
self._cassette, _AiohttpClientSessionRequest
)
yield client.ClientSession, '_request', new_request
def _urllib3_patchers(self, cpool, stubs):
http_connection_remover = ConnectionRemover(
self._get_cassette_subclass(stubs.VCRRequestsHTTPConnection)

View File

@@ -0,0 +1,76 @@
'''Stubs for aiohttp HTTP clients'''
from __future__ import absolute_import
import asyncio
import functools
import json
from aiohttp import ClientResponse
from vcr.request import Request
class MockClientResponse(ClientResponse):
# TODO: get encoding from header
@asyncio.coroutine
def json(self, *, encoding='utf-8', loads=json.loads): # NOQA: E999
return loads(self.content.decode(encoding))
@asyncio.coroutine
def text(self, encoding='utf-8'):
return self.content.decode(encoding)
@asyncio.coroutine
def release(self):
pass
def vcr_request(cassette, real_request):
@functools.wraps(real_request)
@asyncio.coroutine
def new_request(self, method, url, **kwargs):
headers = kwargs.get('headers')
headers = self._prepare_headers(headers)
data = kwargs.get('data')
vcr_request = Request(method, url, data, headers)
if cassette.can_play_response_for(vcr_request):
vcr_response = cassette.play_response(vcr_request)
response = MockClientResponse(method, vcr_response.get('url'))
response.status = vcr_response['status']['code']
response.content = vcr_response['body']['string']
response.reason = vcr_response['status']['message']
response.headers = vcr_response['headers']
response.close()
return response
if cassette.write_protected and cassette.filter_request(vcr_request):
response = MockClientResponse(method, url)
response.status = 599
msg = ("No match for the request {!r} was found. Can't overwrite "
"existing cassette {!r} in your current record mode {!r}.")
msg = msg.format(vcr_request, cassette._path, cassette.record_mode)
response.content = msg.encode()
response.close()
return response
response = yield from real_request(self, method, url, **kwargs) # NOQA: E999
vcr_response = {
'status': {
'code': response.status,
'message': response.reason,
},
'headers': dict(response.headers),
'body': {'string': (yield from response.text())}, # NOQA: E999
'url': response.url,
}
cassette.append(vcr_request, vcr_response)
return response
return new_request