From 7749c1f75781cd5fb2367b089c31a92e127b07b1 Mon Sep 17 00:00:00 2001 From: Guillermo Arribas Date: Mon, 16 Nov 2020 18:20:33 +1100 Subject: [PATCH] Fix failures with latest responses library (0.12.1) (#3466) * Fix failures with latest responses library (0.12.1) * Detect version of responses library and supply a compatible monkey patch depending on version * Seperate responses_mock._find_match monkey patchs depending on reponses lib version to improve readability Co-authored-by: Guillermo Arribas --- moto/core/models.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/moto/core/models.py b/moto/core/models.py index d8de6b29f..2cd67188a 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import functools import inspect import os +import pkg_resources import re import six import types @@ -14,6 +15,7 @@ from collections import defaultdict from botocore.config import Config from botocore.handlers import BUILTIN_HANDLERS from botocore.awsrequest import AWSResponse +from distutils.version import LooseVersion from six.moves.urllib.parse import urlparse from werkzeug.wrappers import Request @@ -28,6 +30,7 @@ from .utils import ( ) ACCOUNT_ID = os.environ.get("MOTO_ACCOUNT_ID", "123456789012") +RESPONSES_VERSION = pkg_resources.get_distribution("responses").version class BaseMockAWS(object): @@ -251,7 +254,7 @@ responses_mock = responses._default_mock responses_mock.add_passthru("http") -def _find_first_match(self, request): +def _find_first_match_legacy(self, request): for i, match in enumerate(self._matches): if match.matches(request): return match @@ -259,12 +262,29 @@ def _find_first_match(self, request): return None +def _find_first_match(self, request): + match_failed_reasons = [] + for i, match in enumerate(self._matches): + match_result, reason = match.matches(request) + if match_result: + return match, match_failed_reasons + else: + match_failed_reasons.append(reason) + + return None, match_failed_reasons + + # Modify behaviour of the matcher to only/always return the first match # Default behaviour is to return subsequent matches for subsequent requests, which leads to https://github.com/spulec/moto/issues/2567 # - First request matches on the appropriate S3 URL # - Same request, executed again, will be matched on the subsequent match, which happens to be the catch-all, not-yet-implemented, callback # Fix: Always return the first match -responses_mock._find_match = types.MethodType(_find_first_match, responses_mock) +if LooseVersion(RESPONSES_VERSION) < LooseVersion("0.12.1"): + responses_mock._find_match = types.MethodType( + _find_first_match_legacy, responses_mock + ) +else: + responses_mock._find_match = types.MethodType(_find_first_match, responses_mock) BOTOCORE_HTTP_METHODS = ["GET", "DELETE", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]