mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-11 18:06:10 +00:00
better logging on cassettenotfound
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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."""
|
||||||
@@ -166,13 +191,14 @@ 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
|
||||||
@@ -227,6 +253,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 +279,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