mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-09 01:03:24 +00:00
Compare commits
3 Commits
v6.0.0
...
better_log
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f821fed418 | ||
|
|
50246791e3 | ||
|
|
8a5bf23d34 |
@@ -10,6 +10,7 @@ from vcr.compat import mock, contextlib
|
|||||||
from vcr.cassette import Cassette
|
from vcr.cassette import Cassette
|
||||||
from vcr.errors import UnhandledHTTPRequestError
|
from vcr.errors import UnhandledHTTPRequestError
|
||||||
from vcr.patch import force_reset
|
from vcr.patch import force_reset
|
||||||
|
from vcr.matchers import path, method, query, host
|
||||||
from vcr.stubs import VCRHTTPSConnection
|
from vcr.stubs import VCRHTTPSConnection
|
||||||
|
|
||||||
|
|
||||||
@@ -294,3 +295,18 @@ def test_use_as_decorator_on_generator():
|
|||||||
assert httplib.HTTPConnection is not original_http_connetion
|
assert httplib.HTTPConnection is not original_http_connetion
|
||||||
yield 2
|
yield 2
|
||||||
assert list(test_function()) == [1, 2]
|
assert list(test_function()) == [1, 2]
|
||||||
|
|
||||||
|
|
||||||
|
def test_similar_requests(tmpdir):
|
||||||
|
# WIP needs to be finished
|
||||||
|
@Cassette.use(inject=True, match_on=(path, query, host, method))
|
||||||
|
def test_function(cassette):
|
||||||
|
conn = httplib.HTTPConnection("www.python.org")
|
||||||
|
conn.request("GET", "/index.html?test=1")
|
||||||
|
|
||||||
|
conn = httplib.HTTPConnection("www.python.org")
|
||||||
|
conn.request("GET", "/index.html?test=0")
|
||||||
|
|
||||||
|
conn = httplib.HTTPConnection("www.cool.org")
|
||||||
|
conn.request("GET", "/index.html?test=0")
|
||||||
|
cassette.similar_requests()
|
||||||
|
|||||||
@@ -100,6 +100,21 @@ def test_vcr_before_record_response_iterable():
|
|||||||
assert mock_filter.call_count == 1
|
assert mock_filter.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_before_record_response_as_filter():
|
||||||
|
request = Request('GET', '/', '', {})
|
||||||
|
response = object() # just can't be None
|
||||||
|
|
||||||
|
# Prevent actually saving the cassette
|
||||||
|
with mock.patch('vcr.cassette.save_cassette'):
|
||||||
|
|
||||||
|
filter_all = mock.Mock(return_value=None)
|
||||||
|
vcr = VCR(before_record_response=filter_all)
|
||||||
|
with vcr.use_cassette('test') as cassette:
|
||||||
|
cassette.append(request, response)
|
||||||
|
assert cassette.data == []e
|
||||||
|
assert not cassette.dirty
|
||||||
|
|
||||||
|
|
||||||
def test_vcr_path_transformer():
|
def test_vcr_path_transformer():
|
||||||
# Regression test for #199
|
# Regression test for #199
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import sys
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import operator
|
||||||
|
import sys
|
||||||
|
|
||||||
import wrapt
|
import wrapt
|
||||||
|
|
||||||
@@ -145,9 +146,33 @@ class CassetteContextDecorator(object):
|
|||||||
return new_args_getter
|
return new_args_getter
|
||||||
|
|
||||||
|
|
||||||
|
class SimilarityScorer(object):
|
||||||
|
|
||||||
|
def __init__(self, matchers, request, ascending=False):
|
||||||
|
self._matchers = matchers
|
||||||
|
self._request = request
|
||||||
|
self._ascending = False
|
||||||
|
|
||||||
|
def score(self, candidate, play_count):
|
||||||
|
value = 1
|
||||||
|
total = 0
|
||||||
|
if play_count < 1:
|
||||||
|
total += value
|
||||||
|
if self._ascending:
|
||||||
|
value *= 2
|
||||||
|
for matcher in self._matchers[::-1]:
|
||||||
|
if matcher(self._request, candidate):
|
||||||
|
total += value
|
||||||
|
if self._ascending:
|
||||||
|
value *= 2
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
class Cassette(object):
|
class Cassette(object):
|
||||||
"""A container for recorded requests and responses"""
|
"""A container for recorded requests and responses"""
|
||||||
|
|
||||||
|
max_playcount = 1
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls, **kwargs):
|
def load(cls, **kwargs):
|
||||||
"""Instantiate and load the cassette stored at the specified path."""
|
"""Instantiate and load the cassette stored at the specified path."""
|
||||||
@@ -165,14 +190,15 @@ class Cassette(object):
|
|||||||
|
|
||||||
def __init__(self, path, serializer=yamlserializer, record_mode='once',
|
def __init__(self, path, serializer=yamlserializer, record_mode='once',
|
||||||
match_on=(uri, method), before_record_request=None,
|
match_on=(uri, method), before_record_request=None,
|
||||||
before_record_response=None, custom_patches=(),
|
before_record_response=None, custom_patches=(), inject=False,
|
||||||
inject=False):
|
similarity_scorer_factory=None):
|
||||||
|
|
||||||
self._path = path
|
self._path = path
|
||||||
self._serializer = serializer
|
self._serializer = serializer
|
||||||
self._match_on = match_on
|
self._match_on = match_on
|
||||||
self._before_record_request = before_record_request or (lambda x: x)
|
self._before_record_request = before_record_request or (lambda x: x)
|
||||||
self._before_record_response = before_record_response or (lambda x: x)
|
self._before_record_response = before_record_response or (lambda x: x)
|
||||||
|
self._similarity_scorer_factory = similarity_scorer_factory or SimilarityScorer
|
||||||
self.inject = inject
|
self.inject = inject
|
||||||
self.record_mode = record_mode
|
self.record_mode = record_mode
|
||||||
self.custom_patches = custom_patches
|
self.custom_patches = custom_patches
|
||||||
@@ -211,6 +237,8 @@ class Cassette(object):
|
|||||||
if not request:
|
if not request:
|
||||||
return
|
return
|
||||||
response = self._before_record_response(response)
|
response = self._before_record_response(response)
|
||||||
|
if response is None:
|
||||||
|
return
|
||||||
self.data.append((request, response))
|
self.data.append((request, response))
|
||||||
self.dirty = True
|
self.dirty = True
|
||||||
|
|
||||||
@@ -227,6 +255,20 @@ class Cassette(object):
|
|||||||
if requests_match(request, stored_request, self._match_on):
|
if requests_match(request, stored_request, self._match_on):
|
||||||
yield index, response
|
yield index, response
|
||||||
|
|
||||||
|
def failing_matchers(self, a, b):
|
||||||
|
return [matcher for matcher in self._match_on if not matcher(a, b)]
|
||||||
|
|
||||||
|
def similar_requests(self, request):
|
||||||
|
scorer = self._similarity_scorer_factory(self._match_on, request).score
|
||||||
|
scored_requests = [
|
||||||
|
(
|
||||||
|
stored_request,
|
||||||
|
scorer(stored_request, self.play_counts[index])
|
||||||
|
)
|
||||||
|
for index, (stored_request, response) in enumerate(self.data)
|
||||||
|
]
|
||||||
|
return sorted(scored_requests, key=operator.itemgetter(1), reverse=True)
|
||||||
|
|
||||||
def can_play_response_for(self, request):
|
def can_play_response_for(self, request):
|
||||||
request = self._before_record_request(request)
|
request = self._before_record_request(request)
|
||||||
return request and request in self and \
|
return request and request in self and \
|
||||||
@@ -239,7 +281,7 @@ class Cassette(object):
|
|||||||
hasn't been played back before, and mark it as played
|
hasn't been played back before, and mark it as played
|
||||||
"""
|
"""
|
||||||
for index, response in self._responses(request):
|
for index, response in self._responses(request):
|
||||||
if self.play_counts[index] == 0:
|
if self.play_counts[index] < self.max_playcount:
|
||||||
self.play_counts[index] += 1
|
self.play_counts[index] += 1
|
||||||
return response
|
return response
|
||||||
# The cassette doesn't contain the request asked for.
|
# The cassette doesn't contain the request asked for.
|
||||||
|
|||||||
@@ -227,12 +227,26 @@ class VCRConnection(object):
|
|||||||
if self.cassette.write_protected and self.cassette.filter_request(
|
if self.cassette.write_protected and self.cassette.filter_request(
|
||||||
self._vcr_request
|
self._vcr_request
|
||||||
):
|
):
|
||||||
|
most_similar_request = None
|
||||||
|
failing_matchers = None
|
||||||
|
most_similar_request_info = None
|
||||||
|
try:
|
||||||
|
most_similar_request_info = self.cassette.similar_requests(self._vcr_request)
|
||||||
|
most_similar_request = most_similar_request_info[0][0]
|
||||||
|
failing_matchers = self.cassette.failing_matchers(
|
||||||
|
self._vcr_request, most_similar_request
|
||||||
|
)
|
||||||
|
except Exception as err:
|
||||||
|
print "XXXX {0}".format(err)
|
||||||
|
import ipdb; ipdb.set_trace()
|
||||||
raise CannotOverwriteExistingCassetteException(
|
raise CannotOverwriteExistingCassetteException(
|
||||||
"No match for the request (%r) was found. "
|
"No match for the request (%r) was found. "
|
||||||
"Can't overwrite existing cassette (%r) in "
|
"Can't overwrite existing cassette (%r) in "
|
||||||
"your current record mode (%r)."
|
"your current record mode (%r). Most similar request was (%r). "
|
||||||
|
"It differed from the request according to (%r). \n\n\n(%r)"
|
||||||
% (self._vcr_request, self.cassette._path,
|
% (self._vcr_request, self.cassette._path,
|
||||||
self.cassette.record_mode)
|
self.cassette.record_mode, most_similar_request,
|
||||||
|
failing_matchers, most_similar_request_info)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Otherwise, we should send the request, then get the response
|
# Otherwise, we should send the request, then get the response
|
||||||
|
|||||||
Reference in New Issue
Block a user