1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-08 16:53:23 +00:00

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Allisson Azevedo
2018-02-17 11:51:04 -03:00
21 changed files with 116 additions and 85 deletions

View File

@@ -32,10 +32,7 @@ matrix:
- env: TOX_SUFFIX="boto"
- env: TOX_SUFFIX="boto3"
exclude:
- env: TOX_SUFFIX="flakes"
python: 2.6
- env: TOX_SUFFIX="flakes"
python: 2.7
# Only run flakes on a single Python 2.x and a single 3.x
- env: TOX_SUFFIX="flakes"
python: 3.4
- env: TOX_SUFFIX="flakes"
@@ -43,30 +40,28 @@ matrix:
- env: TOX_SUFFIX="flakes"
python: pypy
- env: TOX_SUFFIX="flakes"
python: pypy3
python: "pypy3.5-5.9.0"
- env: TOX_SUFFIX="boto"
python: 3.6
# Requests 1.x only supports Python <= 3.3
- env: TOX_SUFFIX="requests1"
python: 3.4
- env: TOX_SUFFIX="requests1"
python: 3.5
- env: TOX_SUFFIX="requests1"
python: 3.6
- env: TOX_SUFFIX="aiohttp"
python: 2.6
- env: TOX_SUFFIX="requests1"
python: "pypy3.5-5.9.0"
- env: TOX_SUFFIX="aiohttp"
python: 2.7
- env: TOX_SUFFIX="aiohttp"
python: pypy
- env: TOX_SUFFIX="aiohttp"
python: pypy3
python:
- 2.6
- 2.7
- 3.5
- 3.6
- pypy
- pypy3
- "pypy3.5-5.9.0"
install:
- pip install tox-travis
- if [[ $TOX_SUFFIX != 'flakes' ]]; then python setup.py install ; fi

View File

@@ -1,4 +1,4 @@
|PyPI| |Build Status| |Waffle Ready| |Gitter|
|PyPI| |Python versions| |Build Status| |Waffle Ready| |Gitter|
VCR.py
======
@@ -63,6 +63,8 @@ more details
.. |PyPI| image:: https://img.shields.io/pypi/v/vcrpy.svg
:target: https://pypi.python.org/pypi/vcrpy-unittest
.. |Python versions| image:: https://img.shields.io/pypi/pyversions/vcrpy-unittest.svg
:target: https://pypi.python.org/pypi/vcrpy-unittest
.. |Build Status| image:: https://secure.travis-ci.org/kevin1024/vcrpy.png?branch=master
:target: http://travis-ci.org/kevin1024/vcrpy
.. |Waffle Ready| image:: https://badge.waffle.io/kevin1024/vcrpy.png?label=ready&title=waffle

View File

@@ -9,7 +9,7 @@ with pip::
Compatibility
-------------
VCR.py supports Python 2.6 and 2.7, 3.3, 3.4, and
VCR.py supports Python 2.7 and 3.4+, and
`pypy <http://pypy.org>`__.
The following http libraries are supported:
@@ -40,7 +40,7 @@ rebuilding pyyaml.
brew install libyaml # Mac with Homebrew
apt-get install libyaml-dev # Ubuntu
dnf install libyaml-dev # Fedora
dnf install libyaml-devel # Fedora
3. Rebuild pyyaml with libyaml::

View File

@@ -28,9 +28,7 @@ install_requires = ['PyYAML', 'wrapt', 'six>=1.5']
extras_require = {
':python_version in "2.4, 2.5, 2.6"':
['contextlib2', 'backport_collections', 'mock'],
':python_version in "2.7, 3.1, 3.2"': ['contextlib2', 'mock'],
':python_version in "2.7"': ['contextlib2', 'mock'],
':python_version in "3.4, 3.5, 3.6"': ['yarl'],
}
@@ -66,6 +64,7 @@ setup(
author_email='me@kevinmccarthy.org',
url='https://github.com/kevin1024/vcrpy',
packages=find_packages(exclude=excluded_packages),
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
install_requires=install_requires,
extras_require=extras_require,
license='MIT',
@@ -75,7 +74,14 @@ setup(
'Environment :: Console',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development :: Testing',
'Topic :: Internet :: WWW/HTTP',
'License :: OSI Approved :: MIT License',

View File

@@ -26,9 +26,9 @@ def test_ignore_localhost(tmpdir, httpbin):
with overridden_dns({'httpbin.org': '127.0.0.1'}):
cass_file = str(tmpdir.join('filter_qs.yaml'))
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
urlopen('http://localhost:{0}/'.format(httpbin.port))
urlopen('http://localhost:{}/'.format(httpbin.port))
assert len(cass) == 0
urlopen('http://httpbin.org:{0}/'.format(httpbin.port))
urlopen('http://httpbin.org:{}/'.format(httpbin.port))
assert len(cass) == 1
@@ -39,9 +39,9 @@ def test_ignore_httpbin(tmpdir, httpbin):
cass_file,
ignore_hosts=['httpbin.org']
) as cass:
urlopen('http://httpbin.org:{0}/'.format(httpbin.port))
urlopen('http://httpbin.org:{}/'.format(httpbin.port))
assert len(cass) == 0
urlopen('http://localhost:{0}/'.format(httpbin.port))
urlopen('http://localhost:{}/'.format(httpbin.port))
assert len(cass) == 1
@@ -53,8 +53,8 @@ def test_ignore_localhost_and_httpbin(tmpdir, httpbin):
ignore_hosts=['httpbin.org'],
ignore_localhost=True
) as cass:
urlopen('http://httpbin.org:{0}'.format(httpbin.port))
urlopen('http://localhost:{0}'.format(httpbin.port))
urlopen('http://httpbin.org:{}'.format(httpbin.port))
urlopen('http://localhost:{}'.format(httpbin.port))
assert len(cass) == 0
@@ -62,12 +62,12 @@ def test_ignore_localhost_twice(tmpdir, httpbin):
with overridden_dns({'httpbin.org': '127.0.0.1'}):
cass_file = str(tmpdir.join('filter_qs.yaml'))
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
urlopen('http://localhost:{0}'.format(httpbin.port))
urlopen('http://localhost:{}'.format(httpbin.port))
assert len(cass) == 0
urlopen('http://httpbin.org:{0}'.format(httpbin.port))
urlopen('http://httpbin.org:{}'.format(httpbin.port))
assert len(cass) == 1
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
assert len(cass) == 1
urlopen('http://localhost:{0}'.format(httpbin.port))
urlopen('http://httpbin.org:{0}'.format(httpbin.port))
urlopen('http://localhost:{}'.format(httpbin.port))
urlopen('http://httpbin.org:{}'.format(httpbin.port))
assert len(cass) == 1

View File

@@ -10,10 +10,25 @@ import vcr
from vcr.persisters.filesystem import FilesystemPersister
class CustomFilesystemPersister(object):
'''Behaves just like default FilesystemPersister but adds .test extension
to the cassette file'''
@staticmethod
def load_cassette(cassette_path, serializer):
cassette_path += '.test'
return FilesystemPersister.load_cassette(cassette_path, serializer)
@staticmethod
def save_cassette(cassette_path, cassette_dict, serializer):
cassette_path += '.test'
FilesystemPersister.save_cassette(cassette_path, cassette_dict,
serializer)
def test_save_cassette_with_custom_persister(tmpdir, httpbin):
'''Ensure you can save a cassette using custom persister'''
my_vcr = vcr.VCR()
my_vcr.register_persister(FilesystemPersister)
my_vcr.register_persister(CustomFilesystemPersister)
# Check to make sure directory doesnt exist
assert not os.path.exists(str(tmpdir.join('nonexistent')))
@@ -23,7 +38,7 @@ def test_save_cassette_with_custom_persister(tmpdir, httpbin):
urlopen(httpbin.url).read()
# Callback should have made the file and the directory
assert os.path.exists(str(tmpdir.join('nonexistent', 'cassette.yml')))
assert os.path.exists(str(tmpdir.join('nonexistent', 'cassette.yml.test')))
def test_load_cassette_with_custom_persister(tmpdir, httpbin):
@@ -31,9 +46,9 @@ def test_load_cassette_with_custom_persister(tmpdir, httpbin):
Ensure you can load a cassette using custom persister
'''
my_vcr = vcr.VCR()
my_vcr.register_persister(FilesystemPersister)
my_vcr.register_persister(CustomFilesystemPersister)
test_fixture = str(tmpdir.join('synopsis.json'))
test_fixture = str(tmpdir.join('synopsis.json.test'))
with my_vcr.use_cassette(test_fixture, serializer='json'):
response = urlopen(httpbin.url).read()

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
'''Test requests' interaction with vcr'''
import platform
import pytest
import sys
import vcr
from assertions import assert_cassette_empty, assert_is_json
@@ -115,6 +117,9 @@ def test_post_chunked_binary(tmpdir, httpbin):
@pytest.mark.xfail('sys.version_info >= (3, 6)', strict=True, raises=ConnectionError)
@pytest.mark.xfail((3, 5) < sys.version_info < (3, 6) and
platform.python_implementation() == 'CPython',
reason='Fails on CPython 3.5')
def test_post_chunked_binary_secure(tmpdir, httpbin_secure):
'''Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str.'''
data1 = iter([b'data', b'to', b'send'])
@@ -249,10 +254,8 @@ def test_nested_cassettes_with_session_created_before_nesting(httpbin_both, tmpd
def test_post_file(tmpdir, httpbin_both):
'''Ensure that we handle posting a file.'''
url = httpbin_both + '/post'
with vcr.use_cassette(str(tmpdir.join('post_file.yaml'))) as cass:
# Don't use 2.7+ only style ',' separated with here because we support python 2.6
with open('tox.ini') as f:
original_response = requests.post(url, f).content
with vcr.use_cassette(str(tmpdir.join('post_file.yaml'))) as cass, open('tox.ini') as f:
original_response = requests.post(url, f).content
# This also tests that we do the right thing with matching the body when they are files.
with vcr.use_cassette(str(tmpdir.join('post_file.yaml')),

View File

@@ -56,7 +56,7 @@ def test_body(tmpdir, httpbin_both, verify_pool_mgr):
def test_auth(tmpdir, httpbin_both, verify_pool_mgr):
'''Ensure that we can handle basic auth'''
auth = ('user', 'passwd')
headers = urllib3.util.make_headers(basic_auth='{0}:{1}'.format(*auth))
headers = urllib3.util.make_headers(basic_auth='{}:{}'.format(*auth))
url = httpbin_both.url + '/basic-auth/user/passwd'
with vcr.use_cassette(str(tmpdir.join('auth.yaml'))):
one = verify_pool_mgr.request('GET', url, headers=headers)
@@ -70,7 +70,7 @@ def test_auth(tmpdir, httpbin_both, verify_pool_mgr):
def test_auth_failed(tmpdir, httpbin_both, verify_pool_mgr):
'''Ensure that we can save failed auth statuses'''
auth = ('user', 'wrongwrongwrong')
headers = urllib3.util.make_headers(basic_auth='{0}:{1}'.format(*auth))
headers = urllib3.util.make_headers(basic_auth='{}:{}'.format(*auth))
url = httpbin_both.url + '/basic-auth/user/passwd'
with vcr.use_cassette(str(tmpdir.join('auth-failed.yaml'))) as cass:
# Ensure that this is empty to begin with

View File

@@ -1,5 +1,6 @@
import multiprocessing
import pytest
from six.moves import xmlrpc_client
from six.moves import xmlrpc_client, xmlrpc_server
requests = pytest.importorskip("requests")
@@ -80,13 +81,27 @@ def test_amazon_doctype(tmpdir):
assert 'html' in r.text
def test_xmlrpclib(tmpdir):
@pytest.yield_fixture(scope='session')
def rpc_server():
httpd = xmlrpc_server.SimpleXMLRPCServer(('', 0))
httpd.register_function(pow)
proxy_process = multiprocessing.Process(
target=httpd.serve_forever,
)
try:
proxy_process.start()
yield 'http://{}:{}'.format(*httpd.server_address)
finally:
proxy_process.terminate()
def test_xmlrpclib(tmpdir, rpc_server):
with vcr.use_cassette(str(tmpdir.join('xmlrpcvideo.yaml'))):
roundup_server = xmlrpc_client.ServerProxy('http://bugs.python.org/xmlrpc', allow_none=True)
original_schema = roundup_server.schema()
roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True)
original_schema = roundup_server.pow(2, 4)
with vcr.use_cassette(str(tmpdir.join('xmlrpcvideo.yaml'))):
roundup_server = xmlrpc_client.ServerProxy('http://bugs.python.org/xmlrpc', allow_none=True)
second_schema = roundup_server.schema()
roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True)
second_schema = roundup_server.pow(2, 4)
assert original_schema == second_schema

View File

@@ -22,7 +22,7 @@ def assert_matcher(matcher_name):
matcher = getattr(matchers, matcher_name)
for k1, k2 in itertools.permutations(REQUESTS, 2):
matched = matcher(REQUESTS[k1], REQUESTS[k2])
if matcher_name in set((k1, k2)):
if matcher_name in {k1, k2}:
assert not matched
else:
assert matched
@@ -31,7 +31,7 @@ def assert_matcher(matcher_name):
def test_uri_matcher():
for k1, k2 in itertools.permutations(REQUESTS, 2):
matched = matchers.uri(REQUESTS[k1], REQUESTS[k2])
if set((k1, k2)) != set(('base', 'method')):
if {k1, k2} != {'base', 'method'}:
assert not matched
else:
assert matched

View File

@@ -319,11 +319,11 @@ def test_additional_matchers():
@vcr.use_cassette
def function_defaults(cassette):
assert set(cassette._match_on) == set([vcr.matchers['uri']])
assert set(cassette._match_on) == {vcr.matchers['uri']}
@vcr.use_cassette(additional_matchers=('body',))
def function_additional(cassette):
assert set(cassette._match_on) == set([vcr.matchers['uri'], vcr.matchers['body']])
assert set(cassette._match_on) == {vcr.matchers['uri'], vcr.matchers['body']}
function_defaults()
function_additional()

17
tox.ini
View File

@@ -1,5 +1,5 @@
[tox]
envlist = {py26,py27,py35,py36,pypy,pypy3}-{flakes,requests218,requests216,requests213,requests211,requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib319,urllib3110,urllib3121,tornado3,tornado4,boto,boto3,aiohttp}
envlist = {py27,py35,py36,pypy}-{flakes,requests218,requests216,requests213,requests211,requests27,requests26,requests25,requests24,requests23,requests22,requests1,httplib2,urllib319,urllib3110,urllib3121,tornado3,tornado4,boto,boto3,aiohttp}
[testenv:flakes]
skipsdist = True
@@ -13,8 +13,7 @@ deps = flake8
commands =
./runtests.sh {posargs}
deps =
# httpbin fails with latest Flask, so we pin it
Flask==0.10.1
Flask
mock
pytest
pytest-httpbin
@@ -34,12 +33,12 @@ deps =
urllib319: urllib3==1.9.1
urllib3110: urllib3==1.10.2
urllib3121: urllib3==1.21.1
{py26,py27,py35,py36,pypy}-tornado3: tornado>=3,<4
{py26,py27,py35,py36,pypy}-tornado4: tornado>=4,<5
{py26,py27,py35,py36,pypy}-tornado3: pytest-tornado
{py26,py27,py35,py36,pypy}-tornado4: pytest-tornado
{py26,py27,py35,py36}-tornado3: pycurl
{py26,py27,py35,py36}-tornado4: pycurl
{py27,py35,py36,pypy}-tornado3: tornado>=3,<4
{py27,py35,py36,pypy}-tornado4: tornado>=4,<5
{py27,py35,py36,pypy}-tornado3: pytest-tornado
{py27,py35,py36,pypy}-tornado4: pytest-tornado
{py27,py35,py36}-tornado3: pycurl
{py27,py35,py36}-tornado4: pycurl
boto: boto
boto3: boto3
aiohttp: aiohttp

View File

@@ -1,10 +1,11 @@
import collections
import sys
import inspect
import logging
import wrapt
from .compat import contextlib, collections
from .compat import contextlib
from .errors import UnhandledHTTPRequestError
from .matchers import requests_match, uri, method
from .patch import CassettePatcherBuilder
@@ -303,7 +304,7 @@ class Cassette(object):
pass
def __str__(self):
return "<Cassette containing {0} recorded response(s)>".format(
return "<Cassette containing {} recorded response(s)>".format(
len(self)
)

View File

@@ -11,8 +11,4 @@ else:
if not hasattr(contextlib, 'ExitStack'):
import contextlib2 as contextlib
import collections
if not hasattr(collections, 'Counter'):
import backport_collections as collections
__all__ = ['mock', 'contextlib', 'collections']
__all__ = ['mock', 'contextlib']

View File

@@ -1,4 +1,5 @@
import copy
import collections
import functools
import inspect
import os
@@ -6,7 +7,6 @@ import types
import six
from .compat import collections
from .cassette import Cassette
from .serializers import yamlserializer, jsonserializer
from .persisters.filesystem import FilesystemPersister
@@ -78,7 +78,7 @@ class VCR(object):
serializer = self.serializers[serializer_name]
except KeyError:
raise KeyError(
"Serializer {0} doesn't exist or isn't registered".format(
"Serializer {} doesn't exist or isn't registered".format(
serializer_name
)
)
@@ -91,7 +91,7 @@ class VCR(object):
matchers.append(self.matchers[m])
except KeyError:
raise KeyError(
"Matcher {0} doesn't exist or isn't registered".format(m)
"Matcher {} doesn't exist or isn't registered".format(m)
)
return matchers
@@ -145,6 +145,7 @@ class VCR(object):
merged_config = {
'serializer': self._get_serializer(serializer_name),
'persister': self.persister,
'match_on': self._get_matchers(
tuple(matcher_names) + tuple(additional_matchers)
),

View File

@@ -90,12 +90,12 @@ def _log_matches(r1, r2, matches):
differences = [m for m in matches if not m[0]]
if differences:
log.debug(
"Requests {0} and {1} differ according to "
"the following matchers: {2}".format(r1, r2, differences)
"Requests {} and {} differ according to "
"the following matchers: {}".format(r1, r2, differences)
)
def requests_match(r1, r2, matchers):
matches = [(m(r1, r2), m) for m in matchers]
_log_matches(r1, r2, matches)
return all([m[0] for m in matches])
return all(m[0] for m in matches)

View File

@@ -59,7 +59,7 @@ def build_uri(**parts):
port = parts['port']
scheme = parts['protocol']
default_port = {'https': 443, 'http': 80}[scheme]
parts['port'] = ':{0}'.format(port) if port != default_port else ''
parts['port'] = ':{}'.format(port) if port != default_port else ''
return "{protocol}://{host}{port}{path}".format(**parts)
@@ -161,7 +161,7 @@ def main():
for file_path in files:
migrated = try_migrate(file_path)
status = 'OK' if migrated else 'FAIL'
sys.stderr.write("[{0}] {1}\n".format(status, file_path))
sys.stderr.write("[{}] {}\n".format(status, file_path))
sys.stderr.write("Done.\n")

View File

@@ -169,7 +169,7 @@ class CassettePatcherBuilder(object):
bases = (base_class,)
if not issubclass(base_class, object): # Check for old style class
bases += (object,)
return type('{0}{1}'.format(base_class.__name__, self._cassette._path),
return type('{}{}'.format(base_class.__name__, self._cassette._path),
bases, dict(cassette=self._cassette))
@_build_patchers_from_mock_triples_decorator

View File

@@ -81,7 +81,7 @@ class Request(object):
return self.scheme
def __str__(self):
return "<Request ({0}) {1}>".format(self.method, self.uri)
return "<Request ({}) {}>".format(self.method, self.uri)
def __repr__(self):
return self.__str__()

View File

@@ -132,11 +132,11 @@ class VCRConnection(object):
"""
port = self.real_connection.port
default_port = {'https': 443, 'http': 80}[self._protocol]
return ':{0}'.format(port) if port != default_port else ''
return ':{}'.format(port) if port != default_port else ''
def _uri(self, url):
"""Returns request absolute URI"""
uri = "{0}://{1}{2}{3}".format(
uri = "{}://{}{}{}".format(
self._protocol,
self.real_connection.host,
self._port_postfix(),
@@ -146,7 +146,7 @@ class VCRConnection(object):
def _url(self, uri):
"""Returns request selector url from absolute URI"""
prefix = "{0}://{1}{2}".format(
prefix = "{}://{}{}".format(
self._protocol,
self.real_connection.host,
self._port_postfix(),
@@ -161,7 +161,7 @@ class VCRConnection(object):
body=body,
headers=headers or {}
)
log.debug('Got {0}'.format(self._vcr_request))
log.debug('Got {}'.format(self._vcr_request))
# Note: The request may not actually be finished at this point, so
# I'm not sending the actual request until getresponse(). This
@@ -180,7 +180,7 @@ class VCRConnection(object):
body="",
headers={}
)
log.debug('Got {0}'.format(self._vcr_request))
log.debug('Got {}'.format(self._vcr_request))
def putheader(self, header, *values):
self._vcr_request.headers[header] = values
@@ -214,7 +214,7 @@ class VCRConnection(object):
# then return it
if self.cassette.can_play_response_for(self._vcr_request):
log.info(
"Playing response for {0} from cassette".format(
"Playing response for {} from cassette".format(
self._vcr_request
)
)
@@ -236,7 +236,7 @@ class VCRConnection(object):
# and return it.
log.info(
"{0} not in cassette, sending to real server".format(
"{} not in cassette, sending to real server".format(
self._vcr_request
)
)

View File

@@ -13,9 +13,7 @@ class VCRHTTPConnectionWithTimeout(VCRHTTPConnection,
HTTPConnection.__init__.'''
# Delete the keyword arguments that HTTPConnection would not recognize
safe_keys = set(
('host', 'port', 'strict', 'timeout', 'source_address')
)
safe_keys = {'host', 'port', 'strict', 'timeout', 'source_address'}
unknown_keys = set(kwargs.keys()) - safe_keys
safe_kwargs = kwargs.copy()
for kw in unknown_keys:
@@ -33,7 +31,7 @@ class VCRHTTPSConnectionWithTimeout(VCRHTTPSConnection,
def __init__(self, *args, **kwargs):
# Delete the keyword arguments that HTTPSConnection would not recognize
safe_keys = set((
safe_keys = {
'host',
'port',
'key_file',
@@ -42,7 +40,7 @@ class VCRHTTPSConnectionWithTimeout(VCRHTTPSConnection,
'timeout',
'source_address',
'ca_certs',
))
}
unknown_keys = set(kwargs.keys()) - safe_keys
safe_kwargs = kwargs.copy()
for kw in unknown_keys: