summaryrefslogtreecommitdiffstats
path: root/openstack
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-06-12 18:30:29 +0000
committerGerrit Code Review <review@openstack.org>2013-06-12 18:30:29 +0000
commit151d027b2002c5d9b188006ef05515c615d72419 (patch)
tree20ebf76071dfc70d5a848a7855f885af7623ca55 /openstack
parent706fa4b31d1e13ab8774bcd10a917849d14033d9 (diff)
parentd7970343cfd880817ac7985e328c9a8fe5cf6b73 (diff)
downloadoslo-151d027b2002c5d9b188006ef05515c615d72419.tar.gz
oslo-151d027b2002c5d9b188006ef05515c615d72419.tar.xz
oslo-151d027b2002c5d9b188006ef05515c615d72419.zip
Merge "Add a funcutils file for working with functions."
Diffstat (limited to 'openstack')
-rw-r--r--openstack/common/funcutils.py76
1 files changed, 76 insertions, 0 deletions
diff --git a/openstack/common/funcutils.py b/openstack/common/funcutils.py
new file mode 100644
index 0000000..b04d58f
--- /dev/null
+++ b/openstack/common/funcutils.py
@@ -0,0 +1,76 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack Foundation.
+# All Rights Reserved.
+#
+# 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.
+
+"""Utility methods for working with functions/decorators."""
+
+import inspect
+
+
+def get_wrapped_function(function):
+ """Get the method at the bottom of a stack of decorators."""
+
+ if not hasattr(function, 'func_closure') or not function.func_closure:
+ return function
+
+ def _get_wrapped_function(function):
+ if not hasattr(function, 'func_closure') or not function.func_closure:
+ return None
+
+ for closure in function.func_closure:
+ func = closure.cell_contents
+
+ deeper_func = _get_wrapped_function(func)
+ if deeper_func:
+ return deeper_func
+ elif hasattr(closure.cell_contents, '__call__'):
+ return closure.cell_contents
+
+ return _get_wrapped_function(function)
+
+
+def getcallargs(function, *args, **kwargs):
+ """This is a simplified inspect.getcallargs (2.7+).
+
+ It should be replaced when python >= 2.7 is standard.
+ """
+
+ keyed_args = {}
+ argnames, varargs, keywords, defaults = inspect.getargspec(function)
+
+ keyed_args.update(kwargs)
+
+ # NOTE(alaski) the implicit 'self' or 'cls' argument shows up in
+ # argnames but not in args or kwargs. Uses 'in' rather than '==' because
+ # some tests use 'self2'.
+ if 'self' in argnames[0] or 'cls' == argnames[0]:
+ # The function may not actually be a method or have im_self.
+ # Typically seen when it's stubbed with mox.
+ if inspect.ismethod(function) and hasattr(function, 'im_self'):
+ keyed_args[argnames[0]] = function.im_self
+ else:
+ keyed_args[argnames[0]] = None
+
+ remaining_argnames = filter(lambda x: x not in keyed_args, argnames)
+ keyed_args.update(dict(zip(remaining_argnames, args)))
+
+ if defaults:
+ num_defaults = len(defaults)
+ for argname, value in zip(argnames[-num_defaults:], defaults):
+ if argname not in keyed_args:
+ keyed_args[argname] = value
+
+ return keyed_args