-
Notifications
You must be signed in to change notification settings - Fork 389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CannotOverwriteExistingCassetteException with no matchers failed #533
Comments
I have the same issue except that it is intermittent. From one invocation to the next, without overwriting the same cassette file, I can't predict whether I will get the error or not.
What it looks like is that it's precisely the same request. |
Is it possible that this is a case where there is incomplete feedback in the case of reuse of a request inside a cassette? I circumvented my problem by enabling |
I have the exact same issue as tylergannon |
I'm having this issue as well. It seems to be a problem here: Lines 230 to 233 in c79a06f
|
+1, but in my scenario, I indeed need to make multiple identical requests. |
+1, I am having this issue as well, but I am using the |
I'm having the same issue, and I see it successfully finding the response the first time, unfortunately in python3.9/site-packages/urllib3/connectionpool.py I see it trying again:
So because buffering doesn't work, it tries again, but now that response that request has already been marked as played... |
I was also ran into this issue today. However i use pytest-vcr. this means i cannot set For this i wrote a hacky fix/patch to fix it for me. from vcr.cassette import Cassette, CassetteContextDecorator
from vcr.errors import UnhandledHTTPRequestError
from vcr.matchers import requests_match
class VCRRepeatPlayback:
# This class is a hacky way to turn a dict into a class
def __init__(self, **kwargs):
for k,v in kwargs.items():
setattr(self, k, v)
class PatchedCassette(Cassette):
"""
Array which contains all the matchers which got configured, if these match then
allow this specific request to be replayed
"""
allow_playback_repeats_matches = [
VCRRepeatPlayback(method='GET', path='/foo/bar', query=[], any_other_matcher_you_configured='foo'),
]
def __init__(self, *args, playback_repeats_on_match=None, **kwargs):
self.playback_repeats_on_match = playback_repeats_on_match or dict()
super().__init__(*args, **kwargs)
def _load(self):
super()._load()
self._populate_playback_repeats_on_match()
def _populate_playback_repeats_on_match(self):
"""
Initial population for the cassette that gets loaded.
Will check every cassette entry request, if it matches with any self.allow_playback_repeats_matches
Then it will be treated as if self.allow_playback_repeats=True for this request only
:return:
"""
# Prevent executing this multiple times
if len(self.playback_repeats_on_match) > 0:
return
for allow_playback_match in self.allow_playback_repeats_matches:
for index, (stored_request, response) in enumerate(self.data):
# Prevent overwriting entry which was already matched before
if self.playback_repeats_on_match.get(index, False):
continue
# This check is very hacky, requests_match techinally expects a request object
# However we just feed it a class which copies its attributes from a dict
self.playback_repeats_on_match[index] = requests_match(
allow_playback_match, stored_request, self._match_on
)
def play_response(self, request):
"""
Get the response corresponding to a request, but only if it
hasn't been played back before, and mark it as played
"""
for index, response in self._responses(request):
# Added allow_playback will replay if it is marked as allowed to replay
if self.play_counts[index] == 0 or self.allow_playback_repeats or self.playback_repeats_on_match[index]:
self.play_counts[index] += 1
return response
# The cassette doesn't contain the request asked for.
raise UnhandledHTTPRequestError(
"The cassette (%r) doesn't contain the request (%r) asked for" % (self._path, request)
)
def __contains__(self, request):
"""Return whether or not a request has been stored"""
for index, response in self._responses(request):
# Added allow_playback will replay if it is marked as allowed to replay
if self.play_counts[index] == 0 or self.allow_playback_repeats or self.playback_repeats_on_match[index]:
return True
return False
# This changes which class gets used as the Cassette class.
vcr_allow_playback_repeats_class = PatchedCassette
def apply_patch():
"""
patch methods/functions where Cassette class gets applied by vcr.
together with the new methods which replace the methods which get patched
:return:
"""
@classmethod
def patch_replace_class_use(cls, **kwargs):
return CassetteContextDecorator.from_args(vcr_allow_playback_repeats_class or cls, **kwargs)
@classmethod
def patch_replace_class_use_arg_getter(cls, arg_getter):
return CassetteContextDecorator(vcr_allow_playback_repeats_class or cls, arg_getter)
Cassette.use = patch_replace_class_use
Cassette.use_arg_getter = patch_replace_class_use_arg_getter Cant guarantee it fixes it and might be version specific (we use 4.1.1) |
I was having the exact same problem, but I am using vcrpy-unittest, which is the recommended library for integration with unittest: https://vcrpy.readthedocs.io/en/latest/usage.html#unittest-integration. I was able to fix it by setting allow_playback_repeats = True as suggested by @tylergannon (thanks for the workaround!). def setUp(self):
super(MyTestClass, self).setUp()
# Workaround for vcrpy issue #533
self.cassette.allow_playback_repeats = True |
The trick for me to avoid this error was to check the response body and not write it if it had already been modified, even if there shouldn't be any change (django/unittest with a JSON response):
EDIT: Only works when editing responses, not requests |
I tried to reproduce this error. Here are the steps I performed.
import vcr
import requests
@vcr.use_cassette()
def test_iana():
requests.get('http://www.iana.org/domains/reserved')
requests.get('http://www.iana.org/domains/reserved')
|
This PR combined with the following
|
Indeed, |
👋🏾 I'm coming back to Pythonland after being out for a number of years and still trying to get my bearings. I also came across this with code very similar to the original poster's. I found this to actually work for me after modifying the response string. I have not looked into this enough to be able to tell you why though 😅 . response['body']['string'] = bytes(json.dumps(json_body), 'utf8') |
Hey folks! Found this issue after having spent half an hour trying to figure out the mysterious case with "no matchers failed". Turns out that indeed there was an unwanted repeat-request in my code. Having a more helpful failure message would have saved me a bit of head-scratching. Would it make sense to change the message that prints out the fact that the request was repeated and even suggests turning on |
For pytest-vcr users, a The For example: @pytest.fixture(scope="module")
def vcr_config():
# For any live API requests, do not record the API-token
# See https://vcrpy.readthedocs.io/en/latest/advanced.html
return {
"record_mode": "new_episodes",
"filter_query_parameters": [("key", "APIKeyXXX")],
"filter_headers": [("x-api-key", "X-API-KEY-XXX")]
}
@pytest.fixture(scope='module')
def vcr(vcr):
vcr.register_matcher('my_matcher', my_matcher)
vcr.match_on = ['my_matcher'] # This can also go into vcr_config or marker kwargs
return vcr |
I am having the same issue and it seems to be intermittent. I have also tried setting allow_playback_repeats to true, which does not work for me, and setting RecordMode to NEW_EPISODES (which results in the test attempting to make the API call again, rather than using the cassette). My workaround is to mock the API call that needs to be called twice in the test and was creating the issue. |
Might not be helpful to you anymore but using @pytest.mark.vcr(allow_playback_repeats=True)
def test_func() -> None:
... |
Thanks for sharing, this worked for me. EDIT: I spoke too soon. This causes the API to be fired again, as noted by @klarich. The suggestion from @prettyirrelevant sadly made no difference for me. |
I'm trying to remove access tokens from the response body of some http transactions that are being recorded so that I can check the sanitized cassettes into source control so I've added a
before_record_request
to the vcr.It runs successfully the first run and correctly removes the field from the body, but then on subsequent runs, I get an error when requesting that request.
I don't understand why the two requests aren't matching if all of the matchers matched. It seems odd that the requests aren't matching because I'm modifying the reponse. I originally thought that it was because of the content length not matching, but it still occurs after that addition.
I don't think this is a duplicate of #516 since there aren't two identical requests in the error message.
The text was updated successfully, but these errors were encountered: