From 7e19131bfd4cd1dc860a46a6dfd18b44d3b356cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Tr=C4=99bski?= Date: Fri, 21 Jul 2017 09:13:41 +0200 Subject: [PATCH] Bringing back backward compatybility Removing *args in 94c5223f022eed38282541a7ce7a5a5da94593ad, turned out to break projects that are using monascaclient. Following code adds it back with the note about the deprecation. Change-Id: If2664b5054d668f5e088699ae1493c54692a2e8c --- monascaclient/client.py | 69 ++++++++++++++- monascaclient/tests/test_client.py | 138 +++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 4 deletions(-) create mode 100644 monascaclient/tests/test_client.py diff --git a/monascaclient/client.py b/monascaclient/client.py index f6c981b..1c0dfa6 100644 --- a/monascaclient/client.py +++ b/monascaclient/client.py @@ -14,6 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import warnings + from keystoneauth1 import identity from keystoneauth1 import session @@ -21,7 +23,12 @@ from monascaclient.osc import migration from monascaclient import version -def Client(api_version, **kwargs): +_NO_VALUE_MARKER = object() + + +def Client(api_version, *args, **kwargs): + + handle_deprecated(args, kwargs) auth = _get_auth_handler(kwargs) sess = _get_session(auth, kwargs) @@ -36,15 +43,69 @@ def Client(api_version, **kwargs): return client +def handle_deprecated(args, kwargs): + """Handles all deprecations + + Method goes through passed args and kwargs + and handles all values that are invalid from POV + of current client but: + + * has their counterparts + * are candidates to be dropped + + """ + kwargs.update(_handle_deprecated_args(args)) + _handle_deprecated_kwargs(kwargs) + + +def _handle_deprecated_kwargs(kwargs): + + depr_map = { + 'tenant_name': ('project_name', lambda x: x), + 'insecure': ('verify', lambda x: not x) + } + + for key, new_key_transform in depr_map.items(): + val = kwargs.get(key, _NO_VALUE_MARKER) + if val != _NO_VALUE_MARKER: + new_key = new_key_transform[0] + new_handler = new_key_transform[1] + + warnings.warn( + 'Usage of {old_key} has been deprecated in favour ' + 'of {new_key}. monascaclient will place value of {old_key} ' + 'under {new_key}'.format(old_key=key, new_key=new_key), + DeprecationWarning + ) + + kwargs[new_key] = new_handler(val) + del kwargs[key] + + +def _handle_deprecated_args(args): + kwargs_update = {} + if args is not None and len(args) > 0: + warnings.warn( + 'Usage or args is deprecated for the sake of ' + 'explicit configuration of the client using ' + 'named arguments (**kwargs). ' + 'That argument will be removed in future releases.', + DeprecationWarning + ) + # have all permissible args set here + kwargs_update.update({ + 'endpoint': args[0] + }) + return kwargs_update + + def _get_session(auth, kwargs): return session.Session(auth=auth, app_name='monascaclient', app_version=version.version_string, cert=kwargs.get('cert', None), timeout=kwargs.get('timeout', None), - verify=kwargs.get('verify', - not kwargs.get('insecure', - False))) + verify=kwargs.get('verify', True)) def _get_auth_handler(kwargs): diff --git a/monascaclient/tests/test_client.py b/monascaclient/tests/test_client.py new file mode 100644 index 0000000..7c63521 --- /dev/null +++ b/monascaclient/tests/test_client.py @@ -0,0 +1,138 @@ +# (C) Copyright 2014-2017 Hewlett Packard Enterprise Development LP +# Copyright 2017 FUJITSU LIMITED +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import warnings + +import mock +from oslotest import base + +from monascaclient import client + + +class TestMonascaClient(base.BaseTestCase): + + @mock.patch('monascaclient.client.migration') + @mock.patch('monascaclient.client._get_auth_handler') + @mock.patch('monascaclient.client._get_session') + def test_should_warn_when_passing_args(self, _, __, ___): + + api_version = mock.Mock() + endpoint = mock.Mock() + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + + client.Client(api_version, endpoint) + + self.assertEqual(1, len(w)) + self.assertEqual(DeprecationWarning, w[0].category) + self.assertRegex( + str(w[0].message), + 'explicit configuration of the client using' + ) + + @mock.patch('monascaclient.client.migration') + @mock.patch('monascaclient.client._get_auth_handler') + @mock.patch('monascaclient.client._get_session') + def test_should_not_warn_when_passing_no_args(self, _, __, ___): + api_version = mock.Mock() + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + client.Client(api_version) + self.assertEqual(0, len(w)) + + @mock.patch('monascaclient.client.migration') + @mock.patch('monascaclient.client._get_auth_handler') + @mock.patch('monascaclient.client._get_session') + def test_should_override_endpoint_if_passed_as_arg(self, get_session, + get_auth, _): + api_version = mock.Mock() + endpoint = mock.Mock() + endpoint_fake = mock.Mock() + auth_val = mock.Mock() + + get_auth.return_value = auth_val + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + client.Client(api_version, endpoint, endpoint=endpoint_fake) + self.assertEqual(1, len(w)) + + get_auth.assert_called_once_with({ + 'endpoint': endpoint + }) + get_session.assert_called_once_with(auth_val, { + 'endpoint': endpoint + }) + + @mock.patch('monascaclient.client.migration') + @mock.patch('monascaclient.client._get_auth_handler') + @mock.patch('monascaclient.client._get_session') + def test_should_override_tenant_name_with_project_name(self, + _, + get_auth, + __): + api_version = mock.Mock() + auth_val = mock.Mock() + tenant_name = mock.Mock() + project_name = tenant_name + + get_auth.return_value = auth_val + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + client.Client(api_version, tenant_name=tenant_name) + + self.assertEqual(1, len(w)) + self.assertEqual(DeprecationWarning, w[0].category) + self.assertRegex( + str(w[0].message), + 'Usage of tenant_name has been deprecated in favour ' + ) + + get_auth.assert_called_once_with({ + 'project_name': project_name + }) + + @mock.patch('monascaclient.client.migration') + @mock.patch('monascaclient.client._get_auth_handler') + @mock.patch('monascaclient.client._get_session') + def test_should_override_insecure_with_negated_verify(self, + _, + get_auth, + __): + api_version = mock.Mock() + auth_val = mock.Mock() + get_auth.return_value = auth_val + + for insecure in [True, False]: + warnings.resetwarnings() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + client.Client(api_version, insecure=insecure) + + self.assertEqual(1, len(w)) + self.assertEqual(DeprecationWarning, w[0].category) + self.assertRegex( + str(w[0].message), + 'Usage of insecure has been deprecated in favour of' + ) + + get_auth.assert_called_once_with({ + 'verify': not insecure + }) + get_auth.reset_mock()