Merge "Replace @memoized_with_* with @memoized"
This commit is contained in:
commit
123269dce7
|
@ -35,82 +35,3 @@ class MemoizedTests(test.TestCase):
|
|||
for x in range(0, 5):
|
||||
cache_calls(1)
|
||||
self.assertEqual(1, len(values_list))
|
||||
|
||||
def test_memoized_with_request_call(self):
|
||||
|
||||
chorus = [
|
||||
"I",
|
||||
"Love",
|
||||
"Rock 'n' Roll",
|
||||
"put another coin",
|
||||
"in the Jukebox Baby."
|
||||
]
|
||||
|
||||
leader = 'Joan Jett'
|
||||
group = 'Blackhearts'
|
||||
|
||||
for position, chorus_line in enumerate(chorus):
|
||||
|
||||
changed_args = False
|
||||
|
||||
def some_func(some_param):
|
||||
if not changed_args:
|
||||
self.assertEqual(some_param, chorus_line)
|
||||
else:
|
||||
self.assertNotEqual(some_param, chorus_line)
|
||||
self.assertEqual(some_param, group)
|
||||
return leader
|
||||
|
||||
@memoized.memoized_with_request(some_func, position)
|
||||
def some_other_func(*args):
|
||||
return args
|
||||
|
||||
# check chorus_copy[position] is replaced by some_func's
|
||||
# output
|
||||
output1 = some_other_func(*chorus)
|
||||
self.assertEqual(output1[position], leader)
|
||||
|
||||
# Change args used to call the function
|
||||
chorus_copy = list(chorus)
|
||||
chorus_copy[position] = group
|
||||
changed_args = True
|
||||
# check that some_func is called with a different parameter, and
|
||||
# that check chorus_copy[position] is replaced by some_func's
|
||||
# output and some_other_func still called with the same parameters
|
||||
output2 = some_other_func(*chorus_copy)
|
||||
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))
|
||||
|
|
|
@ -110,99 +110,3 @@ def memoized(func):
|
|||
# it doesn't keep the instances in memory forever. We might want to separate
|
||||
# them in the future, however.
|
||||
memoized_method = memoized
|
||||
|
||||
|
||||
def memoized_with_request(request_func, request_index=0):
|
||||
"""Decorator for caching functions which receive a request argument
|
||||
|
||||
memoized functions with a request argument are memoized only during the
|
||||
rendering of a single view because the request argument is a new request
|
||||
instance on each view.
|
||||
|
||||
If you want a function to be memoized for multiple views use this
|
||||
decorator.
|
||||
|
||||
It replaces the request argument in the call to the decorated function
|
||||
with the result of calling request_func on that request object.
|
||||
|
||||
request_function is a function which will receive the request argument.
|
||||
|
||||
request_index indicates which argument of the decorated function is the
|
||||
request object to pass into request_func, which will also be replaced
|
||||
by the result of request_func being called.
|
||||
|
||||
your memoized function will instead receive request_func(request)
|
||||
passed as argument at the request_index.
|
||||
|
||||
The intent of that function is to extract the information needed from the
|
||||
request, and thus the memoizing will operate just on that part of the
|
||||
request that is relevant to the function being memoized.
|
||||
|
||||
short example::
|
||||
|
||||
@memoized
|
||||
def _get_api_client(username, token_id, project_id, auth_url)
|
||||
return api_client.Client(username, token_id, project_id, auth_url)
|
||||
|
||||
def get_api_client(request):
|
||||
return _api_client(request.user.username,
|
||||
request.user.token.id,
|
||||
request.user.tenant_id)
|
||||
|
||||
@memoized_with_request(get_api_client)
|
||||
def some_api_function(api_client, *args, **kwargs):
|
||||
# is like returning get_api_client(
|
||||
# request).some_method(*args, **kwargs)
|
||||
# but with memoization.
|
||||
return api_client.some_method(*args, **kwargs)
|
||||
|
||||
@memoized_with_request(get_api_client, 1)
|
||||
def some_other_funt(param, api_client, other_param):
|
||||
# The decorated function will be called this way:
|
||||
# some_other_funt(param, request, other_param)
|
||||
# but will be called behind the scenes this way:
|
||||
# some_other_funt(param, get_api_client(request), other_param)
|
||||
return api_client.some_method(param, other_param)
|
||||
|
||||
See openstack_dashboard.api.nova for a complete example.
|
||||
"""
|
||||
def wrapper(func):
|
||||
memoized_func = memoized(func)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
args = list(args)
|
||||
request = args.pop(request_index)
|
||||
args.insert(request_index, request_func(request))
|
||||
return memoized_func(*args, **kwargs)
|
||||
|
||||
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
|
||||
|
|
|
@ -34,7 +34,6 @@ from cinderclient.v2.contrib import list_extensions as cinder_list_extensions
|
|||
from horizon import exceptions
|
||||
from horizon.utils import functions as utils
|
||||
from horizon.utils.memoized import memoized
|
||||
from horizon.utils.memoized import memoized_with_request
|
||||
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard.api import microversions
|
||||
|
@ -209,15 +208,16 @@ def get_auth_params_from_request(request):
|
|||
)
|
||||
|
||||
|
||||
@memoized_with_request(get_auth_params_from_request)
|
||||
def cinderclient(request_auth_params, version=None):
|
||||
@memoized
|
||||
def cinderclient(request, version=None):
|
||||
if version is None:
|
||||
api_version = VERSIONS.get_active_version()
|
||||
version = api_version['version']
|
||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
|
||||
username, token_id, tenant_id, cinder_urls, auth_url = request_auth_params
|
||||
(username, token_id, tenant_id, cinder_urls,
|
||||
auth_url) = get_auth_params_from_request(request)
|
||||
version = base.Version(version)
|
||||
if version == 2:
|
||||
service_names = ('volumev2', 'volume')
|
||||
|
@ -1015,15 +1015,16 @@ def availability_zone_list(request, detailed=False):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized_with_request(cinderclient)
|
||||
def list_extensions(cinder_api):
|
||||
@memoized
|
||||
def list_extensions(request):
|
||||
cinder_api = cinderclient(request)
|
||||
return tuple(cinder_list_extensions.ListExtManager(cinder_api).show_all())
|
||||
|
||||
|
||||
@memoized_with_request(list_extensions)
|
||||
def extension_supported(extensions, extension_name):
|
||||
@memoized
|
||||
def extension_supported(request, extension_name):
|
||||
"""This method will determine if Cinder supports a given extension name."""
|
||||
for extension in extensions:
|
||||
for extension in list_extensions(request):
|
||||
if extension.name == extension_name:
|
||||
return True
|
||||
return False
|
||||
|
|
|
@ -35,7 +35,6 @@ import six
|
|||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
from horizon.utils.memoized import memoized
|
||||
from horizon.utils.memoized import memoized_with_request
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard.api import nova
|
||||
from openstack_dashboard.contrib.developer.profiler import api as profiler
|
||||
|
@ -806,9 +805,9 @@ def get_auth_params_from_request(request):
|
|||
)
|
||||
|
||||
|
||||
@memoized_with_request(get_auth_params_from_request)
|
||||
def neutronclient(request_auth_params):
|
||||
token_id, neutron_url, auth_url = request_auth_params
|
||||
@memoized
|
||||
def neutronclient(request):
|
||||
token_id, neutron_url, auth_url = get_auth_params_from_request(request)
|
||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
c = neutron_client.Client(token=token_id,
|
||||
|
@ -1785,12 +1784,13 @@ def _server_get_addresses(request, server, ports, floating_ips, network_names):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized_with_request(neutronclient)
|
||||
def list_extensions(neutron_api):
|
||||
@memoized
|
||||
def list_extensions(request):
|
||||
"""List neutron extensions.
|
||||
|
||||
:param request: django request object
|
||||
"""
|
||||
neutron_api = neutronclient(request)
|
||||
try:
|
||||
extensions_list = neutron_api.list_extensions()
|
||||
except exceptions.ServiceCatalogException:
|
||||
|
|
|
@ -266,15 +266,14 @@ def get_auth_params_from_request(request):
|
|||
)
|
||||
|
||||
|
||||
def _argconv_for_novaclient(request, version=None):
|
||||
req_param = get_auth_params_from_request(request)
|
||||
def novaclient(request, version=None):
|
||||
if isinstance(version, api_versions.APIVersion):
|
||||
version = version.get_string()
|
||||
return (req_param, version), {}
|
||||
return cached_novaclient(request, version)
|
||||
|
||||
|
||||
@memoized.memoized_with_argconv(_argconv_for_novaclient)
|
||||
def novaclient(request_auth_params, version=None):
|
||||
@memoized.memoized
|
||||
def cached_novaclient(request, version=None):
|
||||
(
|
||||
username,
|
||||
token_id,
|
||||
|
@ -282,7 +281,7 @@ def novaclient(request_auth_params, version=None):
|
|||
project_domain_id,
|
||||
nova_url,
|
||||
auth_url
|
||||
) = request_auth_params
|
||||
) = get_auth_params_from_request(request)
|
||||
if version is None:
|
||||
version = VERSIONS.get_active_version()['version']
|
||||
c = nova_client.Client(version,
|
||||
|
@ -1066,11 +1065,12 @@ def interface_detach(request, server, port_id):
|
|||
|
||||
|
||||
@profiler.trace
|
||||
@memoized.memoized_with_request(novaclient)
|
||||
def list_extensions(nova_api):
|
||||
@memoized.memoized
|
||||
def list_extensions(request):
|
||||
"""List all nova extensions, except the ones in the blacklist."""
|
||||
blacklist = set(getattr(settings,
|
||||
'OPENSTACK_NOVA_EXTENSIONS_BLACKLIST', []))
|
||||
nova_api = novaclient(request)
|
||||
return tuple(
|
||||
extension for extension in
|
||||
nova_list_extensions.ListExtManager(nova_api).show_all()
|
||||
|
@ -1078,22 +1078,15 @@ def list_extensions(nova_api):
|
|||
)
|
||||
|
||||
|
||||
# NOTE(amotoki): In Python 3, a tuple of the Extension classes
|
||||
# is not hashable. The return value must be a known premitive.
|
||||
# This converts the return value to a tuple of a string.
|
||||
def _list_extensions_wrap(request):
|
||||
return tuple(e.name for e in list_extensions(request))
|
||||
|
||||
|
||||
@profiler.trace
|
||||
@memoized.memoized_with_request(_list_extensions_wrap, 1)
|
||||
def extension_supported(extension_name, supported_ext_names):
|
||||
@memoized.memoized
|
||||
def extension_supported(extension_name, request):
|
||||
"""Determine if nova supports a given extension name.
|
||||
|
||||
Example values for the extension_name include AdminActions, ConsoleOutput,
|
||||
etc.
|
||||
"""
|
||||
for ext in supported_ext_names:
|
||||
for ext in list_extensions(request):
|
||||
if ext == extension_name:
|
||||
return True
|
||||
return False
|
||||
|
|
Loading…
Reference in New Issue