mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-08 16:53:23 +00:00
Compare commits
3 Commits
v4.4.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.errors import UnhandledHTTPRequestError
|
||||
from vcr.patch import force_reset
|
||||
from vcr.matchers import path, method, query, host
|
||||
from vcr.stubs import VCRHTTPSConnection
|
||||
|
||||
|
||||
@@ -294,3 +295,18 @@ def test_use_as_decorator_on_generator():
|
||||
assert httplib.HTTPConnection is not original_http_connetion
|
||||
yield 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
|
||||
|
||||
|
||||
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():
|
||||
# Regression test for #199
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import sys
|
||||
import inspect
|
||||
import logging
|
||||
import operator
|
||||
import sys
|
||||
|
||||
import wrapt
|
||||
|
||||
@@ -145,9 +146,33 @@ class CassetteContextDecorator(object):
|
||||
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):
|
||||
"""A container for recorded requests and responses"""
|
||||
|
||||
max_playcount = 1
|
||||
|
||||
@classmethod
|
||||
def load(cls, **kwargs):
|
||||
"""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',
|
||||
match_on=(uri, method), before_record_request=None,
|
||||
before_record_response=None, custom_patches=(),
|
||||
inject=False):
|
||||
before_record_response=None, custom_patches=(), inject=False,
|
||||
similarity_scorer_factory=None):
|
||||
|
||||
self._path = path
|
||||
self._serializer = serializer
|
||||
self._match_on = match_on
|
||||
self._before_record_request = before_record_request 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.record_mode = record_mode
|
||||
self.custom_patches = custom_patches
|
||||
@@ -211,6 +237,8 @@ class Cassette(object):
|
||||
if not request:
|
||||
return
|
||||
response = self._before_record_response(response)
|
||||
if response is None:
|
||||
return
|
||||
self.data.append((request, response))
|
||||
self.dirty = True
|
||||
|
||||
@@ -227,6 +255,20 @@ class Cassette(object):
|
||||
if requests_match(request, stored_request, self._match_on):
|
||||
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):
|
||||
request = self._before_record_request(request)
|
||||
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
|
||||
"""
|
||||
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
|
||||
return response
|
||||
# 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(
|
||||
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(
|
||||
"No match for the request (%r) was found. "
|
||||
"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.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
|
||||
|
||||
Reference in New Issue
Block a user