diff options
author | ZhiQiang Fan <aji.zqfan@gmail.com> | 2016-01-19 23:33:04 +0800 |
---|---|---|
committer | ZhiQiang Fan <aji.zqfan@gmail.com> | 2016-01-19 23:37:01 +0800 |
commit | 242a429f0d5c3922b6c46e74267cb738de9aa119 (patch) | |
tree | 761231d25d77938ffbd801ee82bb9c79958f9b9d | |
parent | e9d11380ca956a3d87ea63813d1366fce78b5551 (diff) | |
download | python-ceilometerclient-242a429f0d5c3922b6c46e74267cb738de9aa119.tar.gz |
drop oslo-incubator modules: cliutils and uuidutils
* uuidutils has been ported to oslo.utils.uuidutils, so use the new one.
* port cliutils to ceilometerclient.common.utils
Change-Id: Ic5d3be140957510ed5d01f25552f2713845c4fdc
-rw-r--r-- | ceilometerclient/common/utils.py | 53 | ||||
-rw-r--r-- | ceilometerclient/openstack/common/apiclient/utils.py | 2 | ||||
-rw-r--r-- | ceilometerclient/openstack/common/cliutils.py | 272 | ||||
-rw-r--r-- | ceilometerclient/openstack/common/uuidutils.py | 37 | ||||
-rw-r--r-- | ceilometerclient/shell.py | 7 |
5 files changed, 52 insertions, 319 deletions
diff --git a/ceilometerclient/common/utils.py b/ceilometerclient/common/utils.py index 8e27fff..6841485 100644 --- a/ceilometerclient/common/utils.py +++ b/ceilometerclient/common/utils.py @@ -15,6 +15,7 @@ from __future__ import print_function +import os import textwrap from oslo_serialization import jsonutils @@ -24,7 +25,6 @@ import prettytable import six from ceilometerclient import exc -from ceilometerclient.openstack.common import cliutils # Decorator for cli-args @@ -44,7 +44,22 @@ def arg(*args, **kwargs): return _decorator -def print_list(objs, fields, field_labels, formatters={}, sortby=0): +def print_list(objs, fields, field_labels, formatters=None, sortby=0): + """Print a list of objects as a table, one row per object. + + :param objs: Iterable of :class:`Resource` + :param fields: Attributes that correspond to columns, in order + :param field_labels: Labels to use in the heading of the table, default to + fields. + :param formatters: `dict` of callables for field formatting + :param sortby: Index of the field for sorting table rows + """ + formatters = formatters or {} + + if len(field_labels) != len(fields): + raise ValueError(("Field labels list %(labels)s has different number " + "of elements than fields list %(fields)s"), + {'labels': field_labels, 'fields': fields}) def _make_default_formatter(field): return lambda o: getattr(o, field, '') @@ -56,9 +71,25 @@ def print_list(objs, fields, field_labels, formatters={}, sortby=0): else: new_formatters[field_label] = _make_default_formatter(field) - cliutils.print_list(objs, field_labels, - formatters=new_formatters, - sortby_index=sortby) + kwargs = {} if sortby is None else {'sortby': field_labels[sortby]} + pt = prettytable.PrettyTable(field_labels) + pt.align = 'l' + + for o in objs: + row = [] + for field in field_labels: + if field in new_formatters: + row.append(new_formatters[field](o)) + else: + field_name = field.lower().replace(' ', '_') + data = getattr(o, field_name, '') + row.append(data) + pt.add_row(row) + + if six.PY3: + print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode()) + else: + print(encodeutils.safe_encode(pt.get_string(**kwargs))) def nested_list_of_dict_formatter(field, column_names): @@ -164,3 +195,15 @@ def merge_nested_dict(dest, source, depth=0): depth=(depth - 1)) else: dest[key] = value + + +def env(*args, **kwargs): + """Returns the first environment variable set. + + If all are empty, defaults to '' or keyword arg `default`. + """ + for arg in args: + value = os.environ.get(arg) + if value: + return value + return kwargs.get('default', '') diff --git a/ceilometerclient/openstack/common/apiclient/utils.py b/ceilometerclient/openstack/common/apiclient/utils.py index 7b9d56b..f1ac6fa 100644 --- a/ceilometerclient/openstack/common/apiclient/utils.py +++ b/ceilometerclient/openstack/common/apiclient/utils.py @@ -25,11 +25,11 @@ ######################################################################## from oslo_utils import encodeutils +from oslo_utils import uuidutils import six from ceilometerclient.openstack.common._i18n import _ from ceilometerclient.openstack.common.apiclient import exceptions -from ceilometerclient.openstack.common import uuidutils def find_resource(manager, name_or_id, **find_args): diff --git a/ceilometerclient/openstack/common/cliutils.py b/ceilometerclient/openstack/common/cliutils.py deleted file mode 100644 index 643faf1..0000000 --- a/ceilometerclient/openstack/common/cliutils.py +++ /dev/null @@ -1,272 +0,0 @@ -# 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. - -# W0603: Using the global statement -# W0621: Redefining name %s from outer scope -# pylint: disable=W0603,W0621 - -from __future__ import print_function - -import getpass -import inspect -import os -import sys -import textwrap - -from oslo_utils import encodeutils -from oslo_utils import strutils -import prettytable -import six -from six import moves - -from ceilometerclient.openstack.common._i18n import _ - - -class MissingArgs(Exception): - """Supplied arguments are not sufficient for calling a function.""" - def __init__(self, missing): - self.missing = missing - msg = _("Missing arguments: %s") % ", ".join(missing) - super(MissingArgs, self).__init__(msg) - - -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: Missing argument(s): a - >>> validate_args(lambda a, b, c, d: None, 0, c=1) - Traceback (most recent call last): - ... - MissingArgs: Missing argument(s): 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, '__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) - - -def arg(*args, **kwargs): - """Decorator for CLI args. - - Example: - - >>> @arg("name", help="Name of the new entity") - ... def entity_create(args): - ... pass - """ - def _decorator(func): - add_arg(func, *args, **kwargs) - return func - return _decorator - - -def env(*args, **kwargs): - """Returns the first environment variable set. - - If all are empty, defaults to '' or keyword arg `default`. - """ - for arg in args: - value = os.environ.get(arg) - if value: - return value - return kwargs.get('default', '') - - -def add_arg(func, *args, **kwargs): - """Bind CLI arguments to a shell.py `do_foo` function.""" - - if not hasattr(func, 'arguments'): - func.arguments = [] - - # NOTE(sirp): avoid dups that can occur when the module is shared across - # tests. - if (args, kwargs) not in func.arguments: - # Because of the semantics of decorator composition if we just append - # to the options list positional options will appear to be backwards. - func.arguments.insert(0, (args, kwargs)) - - -def unauthenticated(func): - """Adds 'unauthenticated' attribute to decorated function. - - Usage: - - >>> @unauthenticated - ... def mymethod(f): - ... pass - """ - func.unauthenticated = True - return func - - -def isunauthenticated(func): - """Checks if the function does not require authentication. - - Mark such functions with the `@unauthenticated` decorator. - - :returns: bool - """ - return getattr(func, 'unauthenticated', False) - - -def print_list(objs, fields, formatters=None, sortby_index=0, - mixed_case_fields=None, field_labels=None): - """Print a list of objects as a table, one row per object. - - :param objs: iterable of :class:`Resource` - :param fields: attributes that correspond to columns, in order - :param formatters: `dict` of callables for field formatting - :param sortby_index: index of the field for sorting table rows - :param mixed_case_fields: fields corresponding to object attributes that - have mixed case names (e.g., 'serverId') - :param field_labels: Labels to use in the heading of the table, default to - fields. - """ - formatters = formatters or {} - mixed_case_fields = mixed_case_fields or [] - field_labels = field_labels or fields - if len(field_labels) != len(fields): - raise ValueError(_("Field labels list %(labels)s has different number " - "of elements than fields list %(fields)s"), - {'labels': field_labels, 'fields': fields}) - - if sortby_index is None: - kwargs = {} - else: - kwargs = {'sortby': field_labels[sortby_index]} - pt = prettytable.PrettyTable(field_labels) - pt.align = 'l' - - for o in objs: - row = [] - for field in fields: - if field in formatters: - row.append(formatters[field](o)) - else: - if field in mixed_case_fields: - field_name = field.replace(' ', '_') - else: - field_name = field.lower().replace(' ', '_') - data = getattr(o, field_name, '') - row.append(data) - pt.add_row(row) - - if six.PY3: - print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode()) - else: - print(encodeutils.safe_encode(pt.get_string(**kwargs))) - - -def print_dict(dct, dict_property="Property", wrap=0, dict_value='Value'): - """Print a `dict` as a table of two columns. - - :param dct: `dict` to print - :param dict_property: name of the first column - :param wrap: wrapping for the second column - :param dict_value: header label for the value (second) column - """ - pt = prettytable.PrettyTable([dict_property, dict_value]) - pt.align = 'l' - for k, v in sorted(dct.items()): - # convert dict to str to check length - if isinstance(v, dict): - v = six.text_type(v) - if wrap > 0: - v = textwrap.fill(six.text_type(v), wrap) - # if value has a newline, add in multiple rows - # e.g. fault with stacktrace - if v and isinstance(v, six.string_types) and r'\n' in v: - lines = v.strip().split(r'\n') - col1 = k - for line in lines: - pt.add_row([col1, line]) - col1 = '' - else: - pt.add_row([k, v]) - - if six.PY3: - print(encodeutils.safe_encode(pt.get_string()).decode()) - else: - print(encodeutils.safe_encode(pt.get_string())) - - -def get_password(max_password_prompts=3): - """Read password from TTY.""" - verify = strutils.bool_from_string(env("OS_VERIFY_PASSWORD")) - pw = None - if hasattr(sys.stdin, "isatty") and sys.stdin.isatty(): - # Check for Ctrl-D - try: - for __ in moves.range(max_password_prompts): - pw1 = getpass.getpass("OS Password: ") - if verify: - pw2 = getpass.getpass("Please verify: ") - else: - pw2 = pw1 - if pw1 == pw2 and pw1: - pw = pw1 - break - except EOFError: - pass - return pw - - -def service_type(stype): - """Adds 'service_type' attribute to decorated function. - - Usage: - - .. code-block:: python - - @service_type('volume') - def mymethod(f): - ... - """ - def inner(f): - f.service_type = stype - return f - return inner - - -def get_service_type(f): - """Retrieves service type from function.""" - return getattr(f, 'service_type', None) - - -def pretty_choice_list(l): - return ', '.join("'%s'" % i for i in l) - - -def exit(msg=''): - if msg: - print (msg, file=sys.stderr) - sys.exit(1) diff --git a/ceilometerclient/openstack/common/uuidutils.py b/ceilometerclient/openstack/common/uuidutils.py deleted file mode 100644 index 234b880..0000000 --- a/ceilometerclient/openstack/common/uuidutils.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2012 Intel Corporation. -# 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. - -""" -UUID related utilities and helper functions. -""" - -import uuid - - -def generate_uuid(): - return str(uuid.uuid4()) - - -def is_uuid_like(val): - """Returns validation of a value as a UUID. - - For our purposes, a UUID is a canonical form string: - aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa - - """ - try: - return str(uuid.UUID(val)) == val - except (TypeError, ValueError, AttributeError): - return False diff --git a/ceilometerclient/shell.py b/ceilometerclient/shell.py index 565bd45..1a8293e 100644 --- a/ceilometerclient/shell.py +++ b/ceilometerclient/shell.py @@ -27,7 +27,6 @@ import ceilometerclient from ceilometerclient import client as ceiloclient from ceilometerclient.common import utils from ceilometerclient import exc -from ceilometerclient.openstack.common import cliutils def _positive_non_zero_int(argument_value): @@ -70,7 +69,7 @@ class CeilometerShell(object): version=ceilometerclient.__version__) parser.add_argument('-d', '--debug', - default=bool(cliutils.env('CEILOMETERCLIENT_DEBUG') + default=bool(utils.env('CEILOMETERCLIENT_DEBUG') ), action='store_true', help='Defaults to env[CEILOMETERCLIENT_DEBUG].') @@ -86,7 +85,7 @@ class CeilometerShell(object): parser.add_argument('--ceilometer-url', metavar='<CEILOMETER_URL>', dest='os_endpoint', - default=cliutils.env('CEILOMETER_URL'), + default=utils.env('CEILOMETER_URL'), help=("DEPRECATED, use --os-endpoint instead. " "Defaults to env[CEILOMETER_URL].")) @@ -95,7 +94,7 @@ class CeilometerShell(object): help=argparse.SUPPRESS) parser.add_argument('--ceilometer-api-version', - default=cliutils.env( + default=utils.env( 'CEILOMETER_API_VERSION', default='2'), help='Defaults to env[CEILOMETER_API_VERSION] ' 'or 2.') |