summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrabi <ramishra@redhat.com>2016-11-04 13:33:12 +0530
committerrabi <ramishra@redhat.com>2016-11-12 19:15:40 +0530
commitb25baa9108bb37e0ece20895d464acf00ab2706c (patch)
treeb1699411a3c4f5933a364ed03390c1fe47df4158
parentea03fa2254a471edef0a655a63c42d7039428323 (diff)
downloadpython-heatclient-b25baa9108bb37e0ece20895d464acf00ab2706c.tar.gz
Move required modules from oslo-incubator
Move the required module to heatclient/common. - heatclient/openstack/common/apiclient/base.py It also moves some required functions and exceptions from heatclient/openstack/common/cliutils.py and heatclient/openstack/common/exceptions.py. Change-Id: I68704c7fab9417492d8390ad05a9797f78d46907
-rw-r--r--heatclient/common/base.py (renamed from heatclient/openstack/common/apiclient/base.py)34
-rw-r--r--heatclient/common/utils.py93
-rw-r--r--heatclient/exc.py4
-rw-r--r--heatclient/openstack/common/cliutils.py272
-rw-r--r--heatclient/tests/unit/test_openstack_common.py2
-rw-r--r--heatclient/v1/actions.py2
-rw-r--r--heatclient/v1/build_info.py2
-rw-r--r--heatclient/v1/events.py2
-rw-r--r--heatclient/v1/resource_types.py2
-rw-r--r--heatclient/v1/resources.py2
-rw-r--r--heatclient/v1/services.py2
-rw-r--r--heatclient/v1/software_configs.py2
-rw-r--r--heatclient/v1/software_deployments.py2
-rw-r--r--heatclient/v1/stacks.py2
-rw-r--r--heatclient/v1/template_versions.py2
15 files changed, 107 insertions, 318 deletions
diff --git a/heatclient/openstack/common/apiclient/base.py b/heatclient/common/base.py
index b99f51b..902b86b 100644
--- a/heatclient/openstack/common/apiclient/base.py
+++ b/heatclient/common/base.py
@@ -19,24 +19,6 @@
"""
Base utilities to build API operation managers and objects on top of.
"""
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-oslo-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-
-# E1102: %s is not callable
-# pylint: disable=E1102
-
import abc
import copy
import logging
@@ -46,8 +28,9 @@ from oslo_utils import strutils
import six
from six.moves.urllib import parse
-from heatclient._i18n import _, _LW
-from heatclient.openstack.common.apiclient import exceptions
+from heatclient._i18n import _
+from heatclient._i18n import _LW
+from heatclient import exc as exceptions
LOG = logging.getLogger(__name__)
@@ -279,14 +262,12 @@ class CrudManager(BaseManager):
"""Base manager class for manipulating entities.
Children of this class are expected to define a `collection_key` and `key`.
-
- `collection_key`: Usually a plural noun by convention (e.g. `entities`);
used to refer collections in both URL's (e.g. `/v3/entities`) and JSON
objects containing a list of member resources (e.g. `{'entities': [{},
{}, {}]}`).
- `key`: Usually a singular noun by convention (e.g. `entity`); used to
refer to an individual member of the collection.
-
"""
collection_key = None
key = None
@@ -296,16 +277,11 @@ class CrudManager(BaseManager):
Given an example collection where `collection_key = 'entities'` and
`key = 'entity'`, the following URL's could be generated.
-
By default, the URL will represent a collection of entities, e.g.::
-
/entities
-
If kwargs contains an `entity_id`, then the URL will represent a
specific member, e.g.::
-
/entities/{entity_id}
-
:param base_url: if provided, the generated URL will be appended to it
"""
url = base_url if base_url is not None else ''
@@ -446,7 +422,6 @@ class Resource(object):
This is pretty much just a bag for attributes.
"""
-
HUMAN_ID = False
NAME_ATTR = 'name'
@@ -472,8 +447,7 @@ class Resource(object):
@property
def human_id(self):
- """Human-readable ID which can be used for bash completion.
- """
+ """Human-readable ID which can be used for bash completion. """
if self.HUMAN_ID:
name = getattr(self, self.NAME_ATTR, None)
if name is not None:
diff --git a/heatclient/common/utils.py b/heatclient/common/utils.py
index 91410ac..bc6f716 100644
--- a/heatclient/common/utils.py
+++ b/heatclient/common/utils.py
@@ -32,7 +32,6 @@ import yaml
from heatclient._i18n import _
from heatclient._i18n import _LE
from heatclient import exc
-from heatclient.openstack.common import cliutils
LOG = logging.getLogger(__name__)
@@ -42,10 +41,94 @@ supported_formats = {
"yaml": yaml.safe_dump
}
-# Using common methods from oslo cliutils
-arg = cliutils.arg
-env = cliutils.env
-print_list = cliutils.print_list
+
+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 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 link_formatter(links):
diff --git a/heatclient/exc.py b/heatclient/exc.py
index b5de2cc..cc640da 100644
--- a/heatclient/exc.py
+++ b/heatclient/exc.py
@@ -122,6 +122,10 @@ class HTTPNotFound(NotFound):
pass
+class NoUniqueMatch(HTTPException):
+ pass
+
+
class HTTPMethodNotAllowed(HTTPException):
code = 405
diff --git a/heatclient/openstack/common/cliutils.py b/heatclient/openstack/common/cliutils.py
deleted file mode 100644
index 8089a29..0000000
--- a/heatclient/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 heatclient._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/heatclient/tests/unit/test_openstack_common.py b/heatclient/tests/unit/test_openstack_common.py
index 3375c83..95c38c0 100644
--- a/heatclient/tests/unit/test_openstack_common.py
+++ b/heatclient/tests/unit/test_openstack_common.py
@@ -15,7 +15,7 @@
import testtools
-from heatclient.openstack.common.apiclient import base
+from heatclient.common import base
from heatclient.v1 import events
from heatclient.v1 import stacks
diff --git a/heatclient/v1/actions.py b/heatclient/v1/actions.py
index 85a539a..0331866 100644
--- a/heatclient/v1/actions.py
+++ b/heatclient/v1/actions.py
@@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from heatclient.openstack.common.apiclient import base
+from heatclient.common import base
from heatclient.v1 import stacks
DEFAULT_PAGE_SIZE = 20
diff --git a/heatclient/v1/build_info.py b/heatclient/v1/build_info.py
index 1a5598e..3dda853 100644
--- a/heatclient/v1/build_info.py
+++ b/heatclient/v1/build_info.py
@@ -13,8 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
class BuildInfo(base.Resource):
diff --git a/heatclient/v1/events.py b/heatclient/v1/events.py
index 5e98aa0..2951712 100644
--- a/heatclient/v1/events.py
+++ b/heatclient/v1/events.py
@@ -18,8 +18,8 @@ from oslo_utils import encodeutils
import six
from six.moves.urllib import parse
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
from heatclient.v1 import stacks
DEFAULT_PAGE_SIZE = 20
diff --git a/heatclient/v1/resource_types.py b/heatclient/v1/resource_types.py
index ef29cdc..86d09b8 100644
--- a/heatclient/v1/resource_types.py
+++ b/heatclient/v1/resource_types.py
@@ -15,8 +15,8 @@ from oslo_utils import encodeutils
import six
from six.moves.urllib import parse
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
class ResourceType(base.Resource):
diff --git a/heatclient/v1/resources.py b/heatclient/v1/resources.py
index 0d80596..ca229ef 100644
--- a/heatclient/v1/resources.py
+++ b/heatclient/v1/resources.py
@@ -17,8 +17,8 @@ from oslo_utils import encodeutils
import six
from six.moves.urllib import parse
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
from heatclient.v1 import stacks
DEFAULT_PAGE_SIZE = 20
diff --git a/heatclient/v1/services.py b/heatclient/v1/services.py
index f833585..ac8b41b 100644
--- a/heatclient/v1/services.py
+++ b/heatclient/v1/services.py
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from heatclient.openstack.common.apiclient import base
+from heatclient.common import base
class Service(base.Resource):
diff --git a/heatclient/v1/software_configs.py b/heatclient/v1/software_configs.py
index ac7423b..79fbddd 100644
--- a/heatclient/v1/software_configs.py
+++ b/heatclient/v1/software_configs.py
@@ -13,8 +13,8 @@
import six
from six.moves.urllib import parse
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
class SoftwareConfig(base.Resource):
diff --git a/heatclient/v1/software_deployments.py b/heatclient/v1/software_deployments.py
index 2152919..ae3ae30 100644
--- a/heatclient/v1/software_deployments.py
+++ b/heatclient/v1/software_deployments.py
@@ -12,8 +12,8 @@
from six.moves.urllib import parse
+from heatclient.common import base
from heatclient.common import utils
-from heatclient.openstack.common.apiclient import base
class SoftwareDeployment(base.Resource):
diff --git a/heatclient/v1/stacks.py b/heatclient/v1/stacks.py
index 5b1c6b1..2f02825 100644
--- a/heatclient/v1/stacks.py
+++ b/heatclient/v1/stacks.py
@@ -17,9 +17,9 @@ import six
from six.moves.urllib import parse
from heatclient._i18n import _
+from heatclient.common import base
from heatclient.common import utils
from heatclient import exc
-from heatclient.openstack.common.apiclient import base
class Stack(base.Resource):
diff --git a/heatclient/v1/template_versions.py b/heatclient/v1/template_versions.py
index 325cc96..f6adefb 100644
--- a/heatclient/v1/template_versions.py
+++ b/heatclient/v1/template_versions.py
@@ -14,7 +14,7 @@
from oslo_utils import encodeutils
from six.moves.urllib import parse
-from heatclient.openstack.common.apiclient import base
+from heatclient.common import base
class TemplateVersion(base.Resource):