From 51bfa030b1d14eeeb9f23e3663c5a4b60db89806 Mon Sep 17 00:00:00 2001 From: Eric Fried Date: Tue, 12 Jun 2018 10:48:39 -0500 Subject: [PATCH] raise_exc default in Adapter It can be annoying to have to say raise_exc=False (or use try/except) on every call when talking to an API where 4xx response codes are useful/normal/informative or where the preferred coding style is to use conditionals rather than try/except. With this change, the Adapter constructor takes a new kwarg, raise_exc. It defaults to None, and the existing behavior is unchanged. If set to a boolean value, that is used as the default for requests. Specifying raise_exc to the primitives (get, head, put, post, patch, delete, request) at any point along the chain will still take precedence. Change-Id: Ie291c3cb891467728d8ca33cf62afdab37c82f34 Closes-Bug: #1776501 --- keystoneauth1/adapter.py | 10 ++++++++- keystoneauth1/tests/unit/test_session.py | 27 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/keystoneauth1/adapter.py b/keystoneauth1/adapter.py index 11ce2287..13ec12e6 100644 --- a/keystoneauth1/adapter.py +++ b/keystoneauth1/adapter.py @@ -88,6 +88,10 @@ class Adapter(object): should be retried (optional, defaults to HTTP 503, has no effect when status_code_retries is 0). + :param bool raise_exc: If True, requests returning failing HTTP responses + will raise an exception; if False, the response is + returned. This can be overridden on a per-request + basis via the kwarg of the same name. """ client_name = None @@ -102,7 +106,7 @@ class Adapter(object): global_request_id=None, min_version=None, max_version=None, default_microversion=None, status_code_retries=None, - retriable_status_codes=None): + retriable_status_codes=None, raise_exc=None): if version and (min_version or max_version): raise TypeError( "version is mutually exclusive with min_version and" @@ -131,6 +135,7 @@ class Adapter(object): self.default_microversion = default_microversion self.status_code_retries = status_code_retries self.retriable_status_codes = retriable_status_codes + self.raise_exc = raise_exc self.global_request_id = global_request_id @@ -202,6 +207,9 @@ class Adapter(object): kwargs.setdefault('headers', {}).setdefault( "X-OpenStack-Request-ID", self.global_request_id) + if self.raise_exc is not None: + kwargs.setdefault('raise_exc', self.raise_exc) + return self.session.request(url, method, **kwargs) def get_token(self, auth=None): diff --git a/keystoneauth1/tests/unit/test_session.py b/keystoneauth1/tests/unit/test_session.py index 29047bc1..09c7cd5e 100644 --- a/keystoneauth1/tests/unit/test_session.py +++ b/keystoneauth1/tests/unit/test_session.py @@ -1580,6 +1580,33 @@ class AdapterTest(utils.TestCase): validate({'default_microversion': '1.2'}, {'microversion': '1.5'}, {'microversion': '1.5'}) + def test_raise_exc_override(self): + sess = client_session.Session() + url = 'http://url' + + def validate(adap_kwargs, get_kwargs, exp_kwargs): + with mock.patch.object(sess, 'request') as m: + adapter.Adapter(sess, **adap_kwargs).get(url, **get_kwargs) + m.assert_called_once_with(url, 'GET', endpoint_filter={}, + **exp_kwargs) + + # No raise_exc in Adapter or get() + validate({}, {}, {}) + + # Set in Adapter, unset in get() + validate({'raise_exc': True}, {}, {'raise_exc': True}) + validate({'raise_exc': False}, {}, {'raise_exc': False}) + + # Unset in Adapter, set in get() + validate({}, {'raise_exc': True}, {'raise_exc': True}) + validate({}, {'raise_exc': False}, {'raise_exc': False}) + + # Setting in get() overrides the one in Adapter + validate({'raise_exc': True}, {'raise_exc': False}, + {'raise_exc': False}) + validate({'raise_exc': False}, {'raise_exc': True}, + {'raise_exc': True}) + class TCPKeepAliveAdapterTest(utils.TestCase):