mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-09 17:15:35 +00:00
handle pytest-asyncio async def coroutines
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def aiohttp_request(session, method, url, as_text, **kwargs):
|
def aiohttp_request(loop, method, url, as_text, **kwargs):
|
||||||
response = yield from session.request(method, url, **kwargs) # NOQA: E999
|
with aiohttp.ClientSession(loop=loop) as session:
|
||||||
return response, (yield from response.text()) if as_text else (yield from response.json()) # NOQA: E999
|
response = yield from session.request(method, url, **kwargs) # NOQA: E999
|
||||||
|
if as_text:
|
||||||
|
content = yield from response.text() # NOQA: E999
|
||||||
|
else:
|
||||||
|
content = yield from response.json() # NOQA: E999
|
||||||
|
return response, content
|
||||||
|
|||||||
13
tests/integration/async_def.py
Normal file
13
tests/integration/async_def.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import aiohttp
|
||||||
|
import pytest
|
||||||
|
import vcr
|
||||||
|
|
||||||
|
|
||||||
|
@vcr.use_cassette()
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_http(): # noqa: E999
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
url = 'https://httpbin.org/get'
|
||||||
|
params = {'ham': 'spam'}
|
||||||
|
resp = await session.get(url, params=params) # noqa: E999
|
||||||
|
assert (await resp.json())['args'] == {'ham': 'spam'} # noqa: E999
|
||||||
@@ -1,28 +1,40 @@
|
|||||||
import pytest
|
import pytest
|
||||||
aiohttp = pytest.importorskip("aiohttp")
|
aiohttp = pytest.importorskip("aiohttp")
|
||||||
|
|
||||||
import asyncio # NOQA
|
import asyncio # noqa: E402
|
||||||
import sys # NOQA
|
import contextlib # noqa: E402
|
||||||
|
|
||||||
import aiohttp # NOQA
|
import pytest # noqa: E402
|
||||||
import pytest # NOQA
|
import vcr # noqa: E402
|
||||||
import vcr # NOQA
|
|
||||||
|
|
||||||
from .aiohttp_utils import aiohttp_request # NOQA
|
from .aiohttp_utils import aiohttp_request # noqa: E402
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .async_def import test_http # noqa: F401
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def run_in_loop(fn):
|
||||||
|
with contextlib.closing(asyncio.new_event_loop()) as loop:
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
task = loop.create_task(fn(loop))
|
||||||
|
return loop.run_until_complete(task)
|
||||||
|
|
||||||
|
|
||||||
|
def request(method, url, as_text=True, **kwargs):
|
||||||
|
def run(loop):
|
||||||
|
return aiohttp_request(loop, method, url, as_text, **kwargs)
|
||||||
|
|
||||||
|
return run_in_loop(run)
|
||||||
|
|
||||||
|
|
||||||
def get(url, as_text=True, **kwargs):
|
def get(url, as_text=True, **kwargs):
|
||||||
loop = asyncio.get_event_loop()
|
return request('GET', url, as_text, **kwargs)
|
||||||
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):
|
def post(url, as_text=True, **kwargs):
|
||||||
loop = asyncio.get_event_loop()
|
return request('POST', url, as_text, **kwargs)
|
||||||
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"])
|
@pytest.fixture(params=["https", "http"])
|
||||||
|
|||||||
22
tests/integration/test_http
Normal file
22
tests/integration/test_http
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
interactions:
|
||||||
|
- request:
|
||||||
|
body: null
|
||||||
|
headers: {}
|
||||||
|
method: GET
|
||||||
|
uri: https://httpbin.org/get?ham=spam
|
||||||
|
response:
|
||||||
|
body: {string: "{\n \"args\": {\n \"ham\": \"spam\"\n }, \n \"headers\"\
|
||||||
|
: {\n \"Accept\": \"*/*\", \n \"Accept-Encoding\": \"gzip, deflate\"\
|
||||||
|
, \n \"Connection\": \"close\", \n \"Host\": \"httpbin.org\", \n \
|
||||||
|
\ \"User-Agent\": \"Python/3.5 aiohttp/2.0.1\"\n }, \n \"origin\": \"213.86.221.35\"\
|
||||||
|
, \n \"url\": \"https://httpbin.org/get?ham=spam\"\n}\n"}
|
||||||
|
headers: {Access-Control-Allow-Credentials: 'true', Access-Control-Allow-Origin: '*',
|
||||||
|
Connection: keep-alive, Content-Length: '299', Content-Type: application/json,
|
||||||
|
Date: 'Wed, 22 Mar 2017 20:08:29 GMT', Server: gunicorn/19.7.1, Via: 1.1 vegur}
|
||||||
|
status: {code: 200, message: OK}
|
||||||
|
url: !!python/object/new:yarl.URL
|
||||||
|
state: !!python/tuple
|
||||||
|
- !!python/object/new:urllib.parse.SplitResult [https, httpbin.org, /get, ham=spam,
|
||||||
|
'']
|
||||||
|
- false
|
||||||
|
version: 1
|
||||||
1
tox.ini
1
tox.ini
@@ -39,6 +39,7 @@ deps =
|
|||||||
boto: boto
|
boto: boto
|
||||||
boto3: boto3
|
boto3: boto3
|
||||||
aiohttp: aiohttp
|
aiohttp: aiohttp
|
||||||
|
aiohttp: pytest-asyncio
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
max_line_length = 110
|
max_line_length = 110
|
||||||
|
|||||||
7
vcr/_handle_coroutine.py
Normal file
7
vcr/_handle_coroutine.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def handle_coroutine(vcr, fn):
|
||||||
|
with vcr as cassette:
|
||||||
|
return (yield from fn(cassette)) # noqa: E999
|
||||||
@@ -12,6 +12,16 @@ from .serializers import yamlserializer
|
|||||||
from .persisters.filesystem import FilesystemPersister
|
from .persisters.filesystem import FilesystemPersister
|
||||||
from .util import partition_dict
|
from .util import partition_dict
|
||||||
|
|
||||||
|
try:
|
||||||
|
from asyncio import iscoroutinefunction
|
||||||
|
from ._handle_coroutine import handle_coroutine
|
||||||
|
except ImportError:
|
||||||
|
def iscoroutinefunction(*args, **kwargs):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_coroutine(*args, **kwags):
|
||||||
|
raise NotImplementedError('Not implemented on Python 2')
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -96,18 +106,25 @@ class CassetteContextDecorator(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _execute_function(self, function, args, kwargs):
|
def _execute_function(self, function, args, kwargs):
|
||||||
if inspect.isgeneratorfunction(function):
|
def handle_function(cassette):
|
||||||
handler = self._handle_coroutine
|
if cassette.inject:
|
||||||
else:
|
return function(cassette, *args, **kwargs)
|
||||||
handler = self._handle_function
|
else:
|
||||||
return handler(function, args, kwargs)
|
return function(*args, **kwargs)
|
||||||
|
|
||||||
def _handle_coroutine(self, function, args, kwargs):
|
if iscoroutinefunction(function):
|
||||||
"""Wraps a coroutine so that we're inside the cassette context for the
|
return handle_coroutine(vcr=self, fn=handle_function)
|
||||||
duration of the coroutine.
|
if inspect.isgeneratorfunction(function):
|
||||||
|
return self._handle_generator(fn=handle_function)
|
||||||
|
|
||||||
|
return self._handle_function(fn=handle_function)
|
||||||
|
|
||||||
|
def _handle_generator(self, fn):
|
||||||
|
"""Wraps a generator so that we're inside the cassette context for the
|
||||||
|
duration of the generator.
|
||||||
"""
|
"""
|
||||||
with self as cassette:
|
with self as cassette:
|
||||||
coroutine = self.__handle_function(cassette, function, args, kwargs)
|
coroutine = fn(cassette)
|
||||||
# We don't need to catch StopIteration. The caller (Tornado's
|
# We don't need to catch StopIteration. The caller (Tornado's
|
||||||
# gen.coroutine, for example) will handle that.
|
# gen.coroutine, for example) will handle that.
|
||||||
to_yield = next(coroutine)
|
to_yield = next(coroutine)
|
||||||
@@ -119,15 +136,9 @@ class CassetteContextDecorator(object):
|
|||||||
else:
|
else:
|
||||||
to_yield = coroutine.send(to_send)
|
to_yield = coroutine.send(to_send)
|
||||||
|
|
||||||
def __handle_function(self, cassette, function, args, kwargs):
|
def _handle_function(self, fn):
|
||||||
if cassette.inject:
|
|
||||||
return function(cassette, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
return function(*args, **kwargs)
|
|
||||||
|
|
||||||
def _handle_function(self, function, args, kwargs):
|
|
||||||
with self as cassette:
|
with self as cassette:
|
||||||
return self.__handle_function(cassette, function, args, kwargs)
|
return fn(cassette)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_function_name(function):
|
def get_function_name(function):
|
||||||
|
|||||||
Reference in New Issue
Block a user