Merge "Avoid UnhashableKeyWarning in api.nova.novaclient"
This commit is contained in:
commit
610eab4ba4
|
@ -81,3 +81,36 @@ class MemoizedTests(test.TestCase):
|
|||
self.assertEqual(output2[position], leader)
|
||||
# check that some_other_func returned a memoized list.
|
||||
self.assertIs(output1, output2)
|
||||
|
||||
def test_memoized_with_argcnv(self):
|
||||
value_list = []
|
||||
|
||||
def converter(*args, **kwargs):
|
||||
new_args = tuple(reversed(args))
|
||||
new_kwargs = dict((k, v + 1) for k, v in kwargs.items())
|
||||
return new_args, new_kwargs
|
||||
|
||||
@memoized.memoized_with_argconv(converter)
|
||||
def target_func(*args, **kwargs):
|
||||
value_list.append(1)
|
||||
return args, kwargs
|
||||
|
||||
for i in range(3):
|
||||
ret_args, ret_kwargs = target_func(1, 2, 3)
|
||||
self.assertEqual((3, 2, 1), ret_args)
|
||||
self.assertEqual({}, ret_kwargs)
|
||||
self.assertEqual(1, len(value_list))
|
||||
|
||||
value_list = []
|
||||
for i in range(3):
|
||||
ret_args, ret_kwargs = target_func(a=1, b=2, c=3)
|
||||
self.assertEqual(tuple(), ret_args)
|
||||
self.assertEqual({'a': 2, 'b': 3, 'c': 4}, ret_kwargs)
|
||||
self.assertEqual(1, len(value_list))
|
||||
|
||||
value_list = []
|
||||
for i in range(3):
|
||||
ret_args, ret_kwargs = target_func(1, 2, a=3, b=4)
|
||||
self.assertEqual((2, 1), ret_args)
|
||||
self.assertEqual({'a': 4, 'b': 5}, ret_kwargs)
|
||||
self.assertEqual(1, len(value_list))
|
||||
|
|
|
@ -178,3 +178,31 @@ def memoized_with_request(request_func, request_index=0):
|
|||
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
||||
|
||||
def memoized_with_argconv(convert_func):
|
||||
"""Decorator for caching functions which receive unhashable arguments
|
||||
|
||||
This decorator is a generalized version of memoized_with_request.
|
||||
There are cases where argument(s) other than 'request' are also unhashable.
|
||||
For such cases, such arguments also need to be converted into hashable
|
||||
variables.
|
||||
|
||||
'convert_func' is responsible for replacing unhashable arguments
|
||||
into corresponding hashable variables.
|
||||
|
||||
'convert_func' receives original arguments as its arguments and
|
||||
it must return a full arguments including converted arguments.
|
||||
|
||||
See openstack_dashboard.api.nova as an example.
|
||||
"""
|
||||
def wrapper(func):
|
||||
memoized_func = memoized(func)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
args, kwargs = convert_func(*args, **kwargs)
|
||||
return memoized_func(*args, **kwargs)
|
||||
|
||||
return wrapped
|
||||
return wrapper
|
||||
|
|
|
@ -36,8 +36,7 @@ from novaclient.v2 import servers as nova_servers
|
|||
|
||||
from horizon import exceptions as horizon_exceptions
|
||||
from horizon.utils import functions as utils
|
||||
from horizon.utils.memoized import memoized
|
||||
from horizon.utils.memoized import memoized_with_request
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard.api import microversions
|
||||
|
@ -58,7 +57,7 @@ INSECURE = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
|||
CACERT = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
|
||||
|
||||
@memoized
|
||||
@memoized.memoized
|
||||
def get_microversion(request, features):
|
||||
client = novaclient(request)
|
||||
min_ver, max_ver = api_versions._get_server_version_range(client)
|
||||
|
@ -267,7 +266,14 @@ def get_auth_params_from_request(request):
|
|||
)
|
||||
|
||||
|
||||
@memoized_with_request(get_auth_params_from_request)
|
||||
def _argconv_for_novaclient(request, version=None):
|
||||
req_param = get_auth_params_from_request(request)
|
||||
if isinstance(version, api_versions.APIVersion):
|
||||
version = version.get_string()
|
||||
return (req_param, version), {}
|
||||
|
||||
|
||||
@memoized.memoized_with_argconv(_argconv_for_novaclient)
|
||||
def novaclient(request_auth_params, version=None):
|
||||
(
|
||||
username,
|
||||
|
@ -361,7 +367,7 @@ def flavor_get(request, flavor_id, get_extras=False):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized
|
||||
@memoized.memoized
|
||||
def flavor_list(request, is_public=True, get_extras=False):
|
||||
"""Get the list of available instance sizes (flavors)."""
|
||||
flavors = novaclient(request).flavors.list(is_public=is_public)
|
||||
|
@ -397,7 +403,7 @@ def update_pagination(entities, page_size, marker, sort_dir, sort_key,
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized
|
||||
@memoized.memoized
|
||||
def flavor_list_paged(request, is_public=True, get_extras=False, marker=None,
|
||||
paginate=False, sort_key="name", sort_dir="desc",
|
||||
reversed_order=False):
|
||||
|
@ -427,7 +433,7 @@ def flavor_list_paged(request, is_public=True, get_extras=False, marker=None,
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized
|
||||
@memoized.memoized
|
||||
def flavor_access_list(request, flavor=None):
|
||||
"""Get the list of access instance sizes (flavors)."""
|
||||
return novaclient(request).flavor_access.list(flavor=flavor)
|
||||
|
@ -1060,7 +1066,7 @@ def interface_detach(request, server, port_id):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized_with_request(novaclient)
|
||||
@memoized.memoized_with_request(novaclient)
|
||||
def list_extensions(nova_api):
|
||||
"""List all nova extensions, except the ones in the blacklist."""
|
||||
blacklist = set(getattr(settings,
|
||||
|
@ -1080,7 +1086,7 @@ def _list_extensions_wrap(request):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized_with_request(_list_extensions_wrap, 1)
|
||||
@memoized.memoized_with_request(_list_extensions_wrap, 1)
|
||||
def extension_supported(extension_name, supported_ext_names):
|
||||
"""Determine if nova supports a given extension name.
|
||||
|
||||
|
|
Loading…
Reference in New Issue