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

Compare commits

...

18 Commits

Author SHA1 Message Date
Luiz Menezes
1b474c0510 Fix deprecation warnings 2019-04-06 00:37:36 -03:00
Luiz Menezes
114fcd29b4 Merge pull request #416 from davidwilemski/util-warnings
Fix collections.abc DeprecationWarning
2019-04-06 00:17:32 -03:00
David Wilemski
4e990db32e Fix collections.abc DeprecationWarning
In versions of Python from 3.8 and forward, importing Mapping and
MutableMapping from the collections module will no longer work. This
change will try to import from the collections.abc module, which was
added in Python 3.3, and fall back to the collections module on older
versions of Python.
2019-01-01 15:23:51 -08:00
Luiz Menezes
c74a857aa4 Merge pull request #409 from jxltom/pin-requires-version-for-python34
Pin yarl and multidict version for python34
2018-11-14 09:59:39 -03:00
jxltom
c3705dae9f Fix flake8 in python3 2018-11-14 10:27:38 +08:00
jxltom
6c166482d9 Pin yarl and multidict version for python34 2018-11-14 09:48:49 +08:00
Thomas Grainger
cc9fabf2d9 Merge pull request #379 from adamchainz/patch-1
Update docs on before_record_* callbacks
2018-10-15 04:05:16 +01:00
Thomas Grainger
f77442d87b Merge pull request #400 from felixonmars/patch-1
Fix a typo in vcr/request.py
2018-10-15 04:04:32 +01:00
Thomas Grainger
602112cd87 Merge pull request #404 from kevin1024/text-encoding-errors-kwarg
support ClientResponse.text(errors=) kwarg
2018-10-15 04:04:15 +01:00
Thomas Grainger
4ef5205094 support ClientResponse.text(errors=) kwarg 2018-10-15 03:00:19 +01:00
Felix Yan
0d2f49fe8a Fix a typo in vcr/request.py 2018-10-06 17:21:42 +08:00
Luiz Menezes
8fdc6dbb68 Merge pull request #397 from stj/master
ClientResponse.release isn't a coroutine
2018-10-04 12:04:05 -03:00
Stefan Tjarks
ffc4dca502 ClientResponse.release isn't a coroutine
Therefore it should not be one in the MockClientResponse class.

d0af887e31/aiohttp/client_reqrep.py (L832)
2018-09-26 00:30:11 -07:00
Luiz Menezes
e42746fa88 Bump version to 2.0.1 2018-09-23 15:25:04 -03:00
Luiz Menezes
03b1dd9faa Merge pull request #395 from kevin1024/fix-py34
Fix py34
2018-09-22 23:16:14 -03:00
Luiz Menezes
f2a79d3fcc Add py34 to CI builds 2018-09-22 17:30:21 -03:00
Luiz Menezes
287ea4b06e Fix cassette module to work with py34 2018-09-22 17:29:08 -03:00
Adam Johnson
a9e75a545e Update docs on before_record_* callbacks
Make them a bit more consistent and obvious that returning `None` ignores the request/response.
2018-07-31 09:54:29 +01:00
13 changed files with 54 additions and 32 deletions

View File

@@ -43,6 +43,8 @@ matrix:
- env: TOX_SUFFIX="boto3" - env: TOX_SUFFIX="boto3"
- env: TOX_SUFFIX="aiohttp" - env: TOX_SUFFIX="aiohttp"
python: "pypy3.5-5.9.0" python: "pypy3.5-5.9.0"
- env: TOX_SUFFIX="aiohttp"
python: 3.4
exclude: exclude:
# Only run flakes on a single Python 2.x and a single 3.x # Only run flakes on a single Python 2.x and a single 3.x
- env: TOX_SUFFIX="flakes" - env: TOX_SUFFIX="flakes"
@@ -59,6 +61,7 @@ matrix:
python: pypy python: pypy
python: python:
- 2.7 - 2.7
- 3.4
- 3.5 - 3.5
- 3.6 - 3.6
- pypy - pypy

View File

@@ -221,24 +221,25 @@ Custom Request filtering
~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~
If none of these covers your request filtering needs, you can register a If none of these covers your request filtering needs, you can register a
callback that will manipulate the HTTP request before adding it to the callback with the ``before_record_request`` configuration option to
cassette. Use the ``before_record_request`` configuration option to so this. manipulate the HTTP request before adding it to the cassette, or return
Here is an example that will never record requests to the /login ``None`` to ignore it entirely. Here is an example that will never record
endpoint. requests to the ``'/login'`` path:
.. code:: python .. code:: python
def before_record_cb(request): def before_record_cb(request):
if request.path != '/login': if request.path == '/login':
return request return None
return request
my_vcr = vcr.VCR( my_vcr = vcr.VCR(
before_record_request = before_record_cb, before_record_request=before_record_cb,
) )
with my_vcr.use_cassette('test.yml'): with my_vcr.use_cassette('test.yml'):
# your http code here # your http code here
You can also mutate the response using this callback. For example, you You can also mutate the request using this callback. For example, you
could remove all query parameters from any requests to the ``'/login'`` could remove all query parameters from any requests to the ``'/login'``
path. path.
@@ -246,7 +247,7 @@ path.
def scrub_login_request(request): def scrub_login_request(request):
if request.path == '/login': if request.path == '/login':
request.uri, _ = urllib.splitquery(response.uri) request.uri, _ = urllib.splitquery(request.uri)
return request return request
my_vcr = vcr.VCR( my_vcr = vcr.VCR(
@@ -258,9 +259,12 @@ path.
Custom Response Filtering Custom Response Filtering
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
VCR.py also suports response filtering with the You can also do response filtering with the
``before_record_response`` keyword argument. It's usage is similar to ``before_record_response`` configuration option. Its usage is
that of ``before_record``: similar to the above ``before_record_request`` - you can
mutate the response, or return ``None`` to avoid recording
the request and response altogether. For example to hide
sensitive data from the request body:
.. code:: python .. code:: python
@@ -302,8 +306,8 @@ in a few ways:
or 0.0.0.0. or 0.0.0.0.
- Set the ``ignore_hosts`` configuration option to a list of hosts to - Set the ``ignore_hosts`` configuration option to a list of hosts to
ignore ignore
- Add a ``before_record`` callback that returns None for requests you - Add a ``before_record_request`` or ``before_record_response`` callback
want to ignore that returns ``None`` for requests you want to ignore (see above).
Requests that are ignored by VCR will not be saved in a cassette, nor Requests that are ignored by VCR will not be saved in a cassette, nor
played back from a cassette. VCR will completely ignore those requests played back from a cassette. VCR will completely ignore those requests

View File

@@ -1,5 +1,6 @@
Changelog Changelog
--------- ---------
- 2.0.1 - Fix bug when using vcrpy with python 3.4
- 2.0.0 - Support python 3.7 (fix httplib2 and urllib2, thanks @felixonmars) - 2.0.0 - Support python 3.7 (fix httplib2 and urllib2, thanks @felixonmars)
[#356] Fixes `before_record_response` so the original response isn't changed (thanks @kgraves) [#356] Fixes `before_record_response` so the original response isn't changed (thanks @kgraves)
Fix requests stub when using proxy (thanks @samuelfekete @daneoshiga) Fix requests stub when using proxy (thanks @samuelfekete @daneoshiga)

View File

@@ -28,7 +28,9 @@ install_requires = [
'six>=1.5', 'six>=1.5',
'contextlib2; python_version=="2.7"', 'contextlib2; python_version=="2.7"',
'mock; python_version=="2.7"', 'mock; python_version=="2.7"',
'yarl; python_version>="3.4"', 'yarl; python_version>"3.4"',
'yarl<1.0.0; python_version=="3.4"',
'multidict<4.0.0,>=2.0; python_version=="3.4"'
] ]
excluded_packages = ["tests*"] excluded_packages = ["tests*"]
@@ -37,7 +39,7 @@ if sys.version_info[0] == 2:
setup( setup(
name='vcrpy', name='vcrpy',
version='2.0.0', version='2.0.1',
description=( description=(
"Automatically mock your HTTP interactions to simplify and " "Automatically mock your HTTP interactions to simplify and "
"speed up testing" "speed up testing"

View File

@@ -168,6 +168,8 @@ def test_aiohttp_test_client(aiohttp_client, tmpdir):
assert response.status == 200 assert response.status == 200
response_text = loop.run_until_complete(response.text()) response_text = loop.run_until_complete(response.text())
assert response_text == 'hello' assert response_text == 'hello'
response_text = loop.run_until_complete(response.text(errors='replace'))
assert response_text == 'hello'
with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette: with vcr.use_cassette(str(tmpdir.join('get.yaml'))) as cassette:
response = loop.run_until_complete(client.get(url)) response = loop.run_until_complete(client.get(url))

View File

@@ -22,9 +22,9 @@ def test_try_migrate_with_yaml(tmpdir):
shutil.copy('tests/fixtures/migration/old_cassette.yaml', cassette) shutil.copy('tests/fixtures/migration/old_cassette.yaml', cassette)
assert vcr.migration.try_migrate(cassette) assert vcr.migration.try_migrate(cassette)
with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f: with open('tests/fixtures/migration/new_cassette.yaml', 'r') as f:
expected_yaml = yaml.load(f) expected_yaml = yaml.load(f, Loader=yaml.FullLoader)
with open(cassette, 'r') as f: with open(cassette, 'r') as f:
actual_yaml = yaml.load(f) actual_yaml = yaml.load(f, Loader=yaml.FullLoader)
assert actual_yaml == expected_yaml assert actual_yaml == expected_yaml

View File

@@ -1,5 +1,5 @@
[tox] [tox]
envlist = {py27,py35,py36,py37,pypy}-{flakes,requests27,httplib2,urllib3121,tornado4,boto3,aiohttp} envlist = {py27,py34,py35,py36,py37,pypy}-{flakes,requests27,httplib2,urllib3121,tornado4,boto3,aiohttp}
[testenv:flakes] [testenv:flakes]
skipsdist = True skipsdist = True

View File

@@ -16,11 +16,13 @@ from .util import partition_dict
try: try:
from asyncio import iscoroutinefunction from asyncio import iscoroutinefunction
from ._handle_coroutine import handle_coroutine
except ImportError: except ImportError:
def iscoroutinefunction(*args, **kwargs): def iscoroutinefunction(*args, **kwargs):
return False return False
if sys.version_info[:2] >= (3, 5):
from ._handle_coroutine import handle_coroutine
else:
def handle_coroutine(*args, **kwags): def handle_coroutine(*args, **kwags):
raise NotImplementedError('Not implemented on Python 2') raise NotImplementedError('Not implemented on Python 2')

View File

@@ -1,5 +1,4 @@
import copy import copy
import collections
import functools import functools
import inspect import inspect
import os import os
@@ -14,6 +13,11 @@ from .util import compose, auto_decorate
from . import matchers from . import matchers
from . import filters from . import filters
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
class VCR(object): class VCR(object):
@@ -175,7 +179,7 @@ class VCR(object):
if decode_compressed_response: if decode_compressed_response:
filter_functions.append(filters.decode_response) filter_functions.append(filters.decode_response)
if before_record_response: if before_record_response:
if not isinstance(before_record_response, collections.Iterable): if not isinstance(before_record_response, Iterable):
before_record_response = (before_record_response,) before_record_response = (before_record_response,)
filter_functions.extend(before_record_response) filter_functions.extend(before_record_response)
@@ -241,7 +245,7 @@ class VCR(object):
filter_functions.append(self._build_ignore_hosts(hosts_to_ignore)) filter_functions.append(self._build_ignore_hosts(hosts_to_ignore))
if before_record_request: if before_record_request:
if not isinstance(before_record_request, collections.Iterable): if not isinstance(before_record_request, Iterable):
before_record_request = (before_record_request,) before_record_request = (before_record_request,)
filter_functions.extend(before_record_request) filter_functions.extend(before_record_request)

View File

@@ -112,7 +112,7 @@ class HeadersDict(CaseInsensitiveDict):
In addition, some servers sometimes send the same header more than once, In addition, some servers sometimes send the same header more than once,
and httplib *can* deal with this situation. and httplib *can* deal with this situation.
Futhermore, I wanted to keep the request and response cassette format as Furthermore, I wanted to keep the request and response cassette format as
similar as possible. similar as possible.
For this reason, in cassettes I keep a dict with lists as keys, but once For this reason, in cassettes I keep a dict with lists as keys, but once

View File

@@ -25,5 +25,5 @@ def serialize(cassette_dict):
original.end, original.end,
original.args[-1] + error_message original.args[-1] + error_message
) )
except TypeError as original: # py3 except TypeError: # py3
raise TypeError(error_message) raise TypeError(error_message)

View File

@@ -28,13 +28,13 @@ class MockClientResponse(ClientResponse):
async def json(self, *, encoding='utf-8', loads=json.loads, **kwargs): # NOQA: E999 async def json(self, *, encoding='utf-8', loads=json.loads, **kwargs): # NOQA: E999
return loads(self._body.decode(encoding)) return loads(self._body.decode(encoding))
async def text(self, encoding='utf-8'): async def text(self, encoding='utf-8', errors='strict'):
return self._body.decode(encoding) return self._body.decode(encoding, errors=errors)
async def read(self): async def read(self):
return self._body return self._body
async def release(self): def release(self):
pass pass

View File

@@ -1,13 +1,17 @@
import collections
import types import types
try:
from collections.abc import Mapping, MutableMapping
except ImportError:
from collections import Mapping, MutableMapping
# Shamelessly stolen from https://github.com/kennethreitz/requests/blob/master/requests/structures.py # Shamelessly stolen from https://github.com/kennethreitz/requests/blob/master/requests/structures.py
class CaseInsensitiveDict(collections.MutableMapping): class CaseInsensitiveDict(MutableMapping):
""" """
A case-insensitive ``dict``-like object. A case-insensitive ``dict``-like object.
Implements all methods and operations of Implements all methods and operations of
``collections.MutableMapping`` as well as dict's ``copy``. Also ``collections.abc.MutableMapping`` as well as dict's ``copy``. Also
provides ``lower_items``. provides ``lower_items``.
All keys are expected to be strings. The structure remembers the All keys are expected to be strings. The structure remembers the
case of the last key to be set, and ``iter(instance)``, case of the last key to be set, and ``iter(instance)``,
@@ -57,7 +61,7 @@ class CaseInsensitiveDict(collections.MutableMapping):
) )
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, collections.Mapping): if isinstance(other, Mapping):
other = CaseInsensitiveDict(other) other = CaseInsensitiveDict(other)
else: else:
return NotImplemented return NotImplemented