summaryrefslogtreecommitdiffstats
path: root/openstack/common
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2012-11-28 11:47:03 +0000
committerMark McLoughlin <markmc@redhat.com>2012-11-29 17:44:35 +0000
commit1e4753263fd8fad9db57558f6db7d6206da33439 (patch)
tree765b6d2e0c57cb330a9c2ef5bb361549c536781a /openstack/common
parent0ac56f54542ac2068d7881c1befbea4b86075f86 (diff)
downloadoslo-1e4753263fd8fad9db57558f6db7d6206da33439.tar.gz
oslo-1e4753263fd8fad9db57558f6db7d6206da33439.tar.xz
oslo-1e4753263fd8fad9db57558f6db7d6206da33439.zip
Add a CLI argument validation utility
blueprint oslo-cliutils In nova-manage and cinder-manage, we allow command arguments to be passed as optional or positional arguments. e.g. $> nova-manage floating create 10.0.0.1/28 $> nova-manage floating create --ip_range 10.0.0.1/28 are equivalent. Once nova-manage has collected those arguments, it calls the appropriate command function with them as positional and keyword arguments. If the user forgets to supply a required argument, they merely get a TypeError with little useful information. Improve the usability of these commands using a new utility function to check that the required arguments have been supplied and raise a useful exception if not. Change-Id: If6e4a9f222a30472bbfbcd06859865bd4e37e139
Diffstat (limited to 'openstack/common')
-rw-r--r--openstack/common/cliutils.py66
1 files changed, 66 insertions, 0 deletions
diff --git a/openstack/common/cliutils.py b/openstack/common/cliutils.py
new file mode 100644
index 0000000..8f4dc44
--- /dev/null
+++ b/openstack/common/cliutils.py
@@ -0,0 +1,66 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Red Hat, Inc.
+#
+# 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 inspect
+import string
+
+
+class MissingArgs(Exception):
+
+ def __init__(self, missing):
+ self.missing = missing
+
+ def __str__(self):
+ if len(self.missing) == 1:
+ return ("An argument is missing: %(missing)s" %
+ dict(missing=self.missing[0]))
+ else:
+ return ("%(num)d arguments are missing: %(missing)s" %
+ dict(num=len(self.missing),
+ missing=string.join(self.missing, ', ')))
+
+
+def validate_args(fn, *args, **kwargs):
+ """Check that the supplied args are sufficient for calling a function.
+
+ >>> validate_args(lambda a: None)
+ Traceback (most recent call last):
+ ...
+ MissingArgs: An argument is missing: a
+ >>> validate_args(lambda a, b, c, d: None, 0, c=1)
+ Traceback (most recent call last):
+ ...
+ MissingArgs: 2 arguments are missing: b, d
+
+ :param fn: the function to check
+ :param arg: the positional arguments supplied
+ :param kwargs: the keyword arguments supplied
+ """
+ argspec = inspect.getargspec(fn)
+
+ num_defaults = len(argspec.defaults or [])
+ required_args = argspec.args[:len(argspec.args) - num_defaults]
+
+ def isbound(method):
+ return getattr(method, 'im_self', None) is not None
+
+ if isbound(fn):
+ required_args.pop(0)
+
+ missing = [arg for arg in required_args if arg not in kwargs]
+ missing = missing[len(args):]
+ if missing:
+ raise MissingArgs(missing)