def contrail_error_handler(f):
    def wrapper(*args, **kwargs):
    def plugin_class(self):
    def make(self, host="localhost", port=8082, protocol="http", base_uri="", os_auth_type="http", **kwargs):
    def register_argparse_arguments(self, parser):
def load_from_argparse_arguments(options):
def register_argparse_arguments(parser):
    def __init__(self, host="localhost", port=8082, protocol="http", base_uri='', **kwargs):
    def user(self):
    def base_url(self):
    def make_url(self, uri):
    def get_json(self, url, **kwargs):
    def delete(self, *args, **kwargs):
    def post_json(self, url, data, cls=None, **kwargs):
    def put_json(self, url, data, cls=None, **kwargs):
    def fqname_to_id(self, fq_name, type):
    def id_to_fqname(self, uuid, type=None):
    def add_ref(self, r1, r2, attr=None):
    def remove_ref(self, r1, r2):
    def _ref_update(self, r1, r2, action, attr=None):
    def search_kv_store(self, key):
    def get_kv_store(self):
    def add_kv_store(self, key, value):
    def remove_kv_store(self, key):
class SessionLoader(loading.session.Session):
class ContrailAPISession(Session): class Path(PurePosixPath):
    _flavour = APIFlavour()

    @classmethod
    def _from_parsed_parts(cls, drv, root, parts, init=True):
        if parts:
            parts = [root] + os.path.relpath(os.path.join(*parts),
                                             start=root).split(os.path.sep)
            parts = [p for p in parts if p not in (".", "")]
        return super(cls, Path)._from_parsed_parts(drv, root, parts, init)

    def __init__(self, *args):
        self.meta = {}

    @property
    def base(self):
        try:
            return self.parts[1]
        except IndexError:
            pass
        return ''

    @property
    def is_root(self):
        return len(self.parts) == 1 and self.root == "/"

    @property
    def is_fq_name(self):
        return not self.is_uuid

    @property
    def is_uuid(self):
        try:
            UUID(self.name, version=4)
        except (ValueError, IndexError):
            return False
        return True

    @property
    def is_resource(self):
        """The path is a resource if it is not a Collection

        :raises AbsPathRequired: path doesn't start with '/'
        """
        return not self.is_collection

    @property
    def is_collection(self):
        """The path is a Collection if there is only one part in the path. Be
        careful, the root is a Collection.

        :raises AbsPathRequired: path doesn't start with '/'
        """
        if not self.is_absolute():
            raise AbsPathRequired()
        return self.base == self.name

    def relative_to(self, path):
        try:
            return PurePosixPath.relative_to(self, path)
        except ValueError:
            return self class FQName(collections.Sequence):

    def __init__(self, init=None):
        if isinstance(init, string_types):
            self._data = init.split(':')
        elif isinstance(init, list):
            self._data = init
        elif isinstance(init, FQName):
            self._data = init._data
        else:
            self._data = []

    def __getitem__(self, idx):
        return self._data[idx]

    def __len__(self):
        return len(self._data)

    def __eq__(self, other):
        if isinstance(other, FQName):
            return self._data == other._data
        return self._data == other

    def __ne__(self, other):
        if isinstance(other, FQName):
            return self._data != other._data
        return self._data != other

    def __repr__(self):
        return repr(self._data)

    def __str__(self):
        return ':'.join(self._data)

    def __bytes__(self):
        return b(':'.join(self._data))

    def __lt__(self, b):
        return len(text_type(self)) < len(text_type(b))

    def __gt__(self, b):
        return not self.__lt__(b) class Context(object):
    _schema = None
    _shell = ShellContext
    _session = None

    @property
    def schema(self):
        if self._schema is None:
            raise SchemaNotInitialized("The schema must be first initialized")
        else:
            return self._schema

    @schema.setter
    def schema(self, schema):
        self._schema = schema

    @property
    def session(self):
        if self._session is None:
            raise SessionNotInitialized("The session must be first initialized")
        else:
            return self._session

    @session.setter
    def session(self, session):
        self._session = session

    @property
    def shell(self):
        return self._shell class Resource(ResourceBase, UserDict):
    """Class for interacting with an API resource

    >>> from contrail_api_cli.resource import Resource
    >>> r = Resource('virtual-network',
                     uuid='4c45e89b-7780-4b78-8508-314fe04a7cbd',
                     fetch=True)
    >>> r['display_name'] = 'foo'
    >>> r.save()

    >>> p = Resource('project', fq_name='default-domain:admin')
    >>> r = Resource('virtual-network', fq_name='default-domain:admin:net1',
                     parent=p)
    >>> r.save()

    :param type: type of the resource
    :type type: str
    :param fetch: immediately fetch resource from the server
    :type fetch: bool
    :param uuid: uuid of the resource
    :type uuid: v4UUID str
    :param fq_name: fq name of the resource
    :type fq_name: str (domain:project:identifier)
                   or list ['domain', 'project', 'identifier']
    :param check: check that the resource exists
    :type check: bool
    :param parent: parent resource
    :type parent: Resource
    :param recursive: level of recursion
    :type recursive: int

    :raises ResourceNotFound: bad uuid or fq_name is given
    :raises HttpError: when save(), fetch() or delete() fail

    .. note::

        Either fq_name or uuid must be provided.
    """

    def __init__(self, type, fetch=False, check=False,
                 parent=None, recursive=1, session=None, **kwargs):
        assert('fq_name' in kwargs or 'uuid' in kwargs or 'to' in kwargs)
        super(Resource, self).__init__(session=session)
        self.type = type

        UserDict.__init__(self, kwargs)
        self.from_dict(self.data)

        if parent:
            self.parent = parent

        if check:
            self.check()

        if fetch:
            self.fetch(recursive=recursive)

        self.properties = {prop.key: prop for prop in self.schema.properties}
        self.emit('created', self)

    def __getattr__(self, attr):
        if attr in self.properties:
            return self.get(attr, self.properties[attr].default)
        msg = "'{0}' object has no attribute '{1}'"
        raise AttributeError(msg.format(type(self).__name__, attr))

    def __dir__(self):
        return sorted(set(dir(type(self)) + list(self.__dict__) +
                      self.properties.keys()))

    def __eq__(self, other):
        if not isinstance(other, Resource) or not self.type == other.type:
            return False
        if self.uuid != other.uuid:
            return False
        if self.fq_name != other.fq_name:
            return False
        return True

    def __hash__(self):
        return hash((self.type, self.uuid, str(self.fq_name)))

    @property
    def schema(self):
        return Context().schema.resource(self.type)

    def check(self):
        """Check that the resource exists.

        :raises ResourceNotFound: if the resource doesn't exists
        """
        if self.fq_name:
            self['uuid'] = self._check_fq_name(self.fq_name)
        elif self.uuid:
            self['fq_name'] = self._check_uuid(self.uuid)
        return True

    @http_error_handler
    def _check_uuid(self, uuid):
        return self.session.id_to_fqname(uuid, type=self.type)['fq_name']

    @http_error_handler
    def _check_fq_name(self, fq_name):
        return self.session.fqname_to_id(fq_name, self.type)

    @property
    def exists(self):
        """Returns True if the resource exists on the API server,
        or returns False.

        :rtype: bool
        """
        try:
            self.check()
        except ResourceNotFound:
            return False
        return True

    @property
    def uuid(self):
        """Return UUID of the resource

        :rtype: str
        """
        return self.get('uuid', super(Resource, self).uuid)

    @property
    def fq_name(self):
        """Return FQDN of the resource

        :rtype: FQName
        """
        return self.get('fq_name', self.get('to', super(Resource, self).fq_name))

    @property
    def parent(self):
        """Return parent resource

        :rtype: Resource
        :raises ResourceNotFound: parent resource doesn't exists
        :raises ResourceMissing: parent resource is not defined
        """
        try:
            return Resource(self['parent_type'], uuid=self['parent_uuid'], check=True)
        except KeyError:
            raise ResourceMissing('%s has no parent resource' % self)

    @parent.setter
    def parent(self, resource):
        """Set parent resource

        :param resource: parent resource
        :type resource: Resource

        :raises ResourceNotFound: resource not found on the API
        """
        resource.check()
        self['parent_type'] = resource.type
        self['parent_uuid'] = resource.uuid

    @property
    def created(self):
        """Return creation date

        :rtype: datetime
        :raises ResourceNotFound: resource not found on the API
        """
        if 'id_perms' not in self:
            self.fetch()
        created = self['id_perms']['created']
        return datetime.strptime(created, '%Y-%m-%dT%H:%M:%S.%f')

    @http_error_handler
    def save(self):
        """Save the resource to the API server

        If the resource doesn't have a uuid the resource will be created.
        If uuid is present the resource is updated.

        :rtype: Resource
        """
        if self.path.is_collection:
            self.session.post_json(self.href,
                                   {self.type: dict(self.data)},
                                   cls=ResourceEncoder)
        else:
            self.session.put_json(self.href,
                                  {self.type: dict(self.data)},
                                  cls=ResourceEncoder)
        return self.fetch(exclude_children=True, exclude_back_refs=True)

    @http_error_handler
    def delete(self):
        """Delete resource from the API server
        """
        res = self.session.delete(self.href)
        self.emit('deleted', self)
        return res

    @http_error_handler
    def fetch(self, recursive=1, exclude_children=False, exclude_back_refs=False):
        """Fetch resource from the API server

        :param recursive: level of recursion for fetching resources
        :type recursive: int
        :param exclude_children: don't get children references
        :type exclude_children: bool
        :param exclude_back_refs: don't get back_refs references
        :type exclude_back_refs: bool

        :rtype: Resource
        """
        if not self.path.is_resource and not self.path.is_uuid:
            self.check()
        params = {}
        # even if the param is False the API will exclude resources
        if exclude_children:
            params['exclude_children'] = True
        if exclude_back_refs:
            params['exclude_back_refs'] = True
        data = self.session.get_json(self.href, **params)[self.type]
        self.from_dict(data)
        return self

    def from_dict(self, data, recursive=1):
        """Populate the resource from a python dict

        :param recursive: level of recursion for fetching resources
        :type recursive: int
        """
        # Find other linked resources
        data = self._encode_resource(data, recursive=recursive)
        self.data = data

    def _encode_resource(self, data, recursive=1):
        for attr in ('fq_name', 'to'):
            if attr in data:
                data[attr] = FQName(data[attr])
        data = self.refs.encode(data, recursive)
        data = self.back_refs.encode(data, recursive)
        data = self.children.encode(data, recursive)
        return data

    @property
    def refs(self):
        """Return refs resources of the resource

        :rtype: LinkedResources
        """
        return LinkedResources(LinkType.REF, self)

    @property
    def back_refs(self):
        """Return back_refs resources of the resource

        :rtype: LinkedResources
        """
        return LinkedResources(LinkType.BACK_REF, self)

    @property
    def children(self):
        """Return children resources of the resource

        :rtype: LinkedResources
        """
        return LinkedResources(LinkType.CHILDREN, self)

    def remove_ref(self, ref):
        """Remove reference from self to ref

        >>> iip = Resource('instance-ip',
                           uuid='30213cf9-4b03-4afc-b8f9-c9971a216978',
                           fetch=True)
        >>> for vmi in iip['virtual_machine_interface_refs']:
                iip.remove_ref(vmi)
        >>> iip['virtual_machine_interface_refs']
        KeyError: u'virtual_machine_interface_refs'

        :param ref: reference to remove
        :type ref: Resource

        :rtype: Resource
        """
        self.session.remove_ref(self, ref)
        return self.fetch()

    def remove_back_ref(self, back_ref):
        """Remove reference from back_ref to self

        :param back_ref: back_ref to remove
        :type back_ref: Resource

        :rtype: Resource
        """
        back_ref.remove_ref(self)
        return self.fetch()

    def set_ref(self, ref, attr=None):
        """Set reference to resource

        Can be used to set references on a resource
        that is not already created.

        :param ref: reference to add
        :type ref: Resource

        :rtype: Resource
        """
        ref_attr = '%s_refs' % ref.type.replace('-', '_')
        ref = {
            'to': ref.fq_name,
            'uuid': ref.uuid,
        }
        if ref_attr in self:
            self[ref_attr].append(ref)
        else:
            self[ref_attr] = [ref]
        return self

    def add_ref(self, ref, attr=None):
        """Add reference to resource

        :param ref: reference to add
        :type ref: Resource

        :rtype: Resource
        """
        self.session.add_ref(self, ref, attr)
        return self.fetch()

    def add_back_ref(self, back_ref, attr=None):
        """Add reference from back_ref to self

        :param back_ref: back_ref to add
        :type back_ref: Resource

        :rtype: Resource
        """
        back_ref.add_ref(self, attr)
        return self.fetch()

    def json(self):
        """Return JSON representation of the resource
        """
        return to_json(self.data, cls=ResourceEncoder) class Collection(ResourceBase, UserList):
    """Class for interacting with an API collection

    >>> from contrail_api_cli.resource import Collection
    >>> c = Collection('virtual-network', fetch=True)
    >>> # iterate over the resources
    >>> for r in c:
    >>>     print(r.path)
    >>> # filter support
    >>> c.filter("router_external", False)
    >>> c.fetch()
    >>> assert all([r.get('router_external') for r in c]) == False

    :param type: name of the collection
    :type type: str
    :param fetch: immediately fetch collection from the server
    :type fetch: bool
    :param recursive: level of recursion
    :type recursive: int
    :param fields: list of field names to fetch
    :type fields: [str]
    :param filters: list of filters
    :type filters: [(name, value), ...]
    :param parent_uuid: filter by parent_uuid
    :type parent_uuid: v4UUID str or list of v4UUID str
    :param back_ref_uuid: filter by back_ref_uuid
    :type back_ref_uuid: v4UUID str or list of v4UUID str
    :param data: initial resources of the collection
    :type data: [Resource]
    """

    def __init__(self, type, fetch=False, recursive=1,
                 fields=None, detail=None, filters=None,
                 parent_uuid=None, back_refs_uuid=None,
                 data=None, session=None):
        super(Collection, self).__init__(session=session)
        UserList.__init__(self, initlist=data)
        self.type = type
        self.fields = fields or []
        self.filters = filters or []
        self.parent_uuid = list(self._sanitize_uuid(parent_uuid))
        self.back_refs_uuid = list(self._sanitize_uuid(back_refs_uuid))
        self.detail = detail
        if fetch:
            self.fetch(recursive=recursive)
        self.emit('created', self)

    @http_error_handler
    def __len__(self):
        """Return the number of items of the collection

        :rtype: int
        """
        if not self.data:
            params = self._format_fetch_params()
            res = self.session.get_json(self.href, count=True, **params)
            try:
                return res[self._contrail_name]['count']
            except KeyError:
                return 0
        return super(Collection, self).__len__()

    def __hash__(self):
        return hash(self.type)

    @property
    def _contrail_name(self):
        if self.type:
            return self.type + 's'
        return self.type

    def _sanitize_uuid(self, uuid):
        if uuid is None:
            raise StopIteration
        if isinstance(uuid, string_types):
            uuid = [uuid]
        for u in uuid:
            try:
                UUID(u, version=4)
            except ValueError:
                continue
            yield u

    def filter(self, field_name, field_value):
        """Add permanent filter on the collection

        :param field_name: name of the field to filter on
        :type field_name: str
        :param field_value: value to filter on

        :rtype: Collection
        """
        self.filters.append((field_name, field_value))
        return self

    def _format_fetch_params(self, fields=[], detail=False, filters=[],
                             parent_uuid=None, back_refs_uuid=None):
        params = {}
        detail = detail or self.detail
        fields_str = ",".join(self._fetch_fields(fields))
        filters_str = ",".join(['%s==%s' % (f, json.dumps(v))
                                for f, v in self._fetch_filters(filters)])
        parent_uuid_str = ",".join(self._fetch_parent_uuid(parent_uuid))
        back_refs_uuid_str = ",".join(self._fetch_back_refs_uuid(back_refs_uuid))
        if detail is True:
            params['detail'] = detail
        elif fields_str:
            params['fields'] = fields_str
        if filters_str:
            params['filters'] = filters_str
        if parent_uuid_str:
            params['parent_id'] = parent_uuid_str
        if back_refs_uuid_str:
            params['back_ref_id'] = back_refs_uuid_str

        return params

    def _fetch_parent_uuid(self, parent_uuid=None):
        return self.parent_uuid + list(self._sanitize_uuid(parent_uuid))

    def _fetch_back_refs_uuid(self, back_refs_uuid=None):
        return self.back_refs_uuid + list(self._sanitize_uuid(back_refs_uuid))

    def _fetch_filters(self, filters=None):
        return self.filters + (filters or [])

    def _fetch_fields(self, fields=None):
        return self.fields + (fields or [])

    @http_error_handler
    def fetch(self, recursive=1, fields=None, detail=None,
              filters=None, parent_uuid=None, back_refs_uuid=None):
        """
        Fetch collection from API server

        :param recursive: level of recursion
        :type recursive: int
        :param fields: fetch only listed fields.
                       contrail 3.0 required
        :type fields: [str]
        :param detail: fetch all fields
        :type detail: bool
        :param filters: list of filters
        :type filters: [(name, value), ...]
        :param parent_uuid: filter by parent_uuid
        :type parent_uuid: v4UUID str or list of v4UUID str
        :param back_refs_uuid: filter by back_refs_uuid
        :type back_refs_uuid: v4UUID str or list of v4UUID str

        :rtype: Collection
        """

        params = self._format_fetch_params(fields=fields, detail=detail, filters=filters,
                                           parent_uuid=parent_uuid, back_refs_uuid=back_refs_uuid)
        data = self.session.get_json(self.href, **params)

        if not self.type:
            self.data = [Collection(col["link"]["name"],
                                    fetch=recursive - 1 > 0,
                                    recursive=recursive - 1,
                                    fields=self._fetch_fields(fields),
                                    detail=detail or self.detail,
                                    filters=self._fetch_filters(filters),
                                    parent_uuid=self._fetch_parent_uuid(parent_uuid),
                                    back_refs_uuid=self._fetch_back_refs_uuid(back_refs_uuid))
                         for col in data['links']
                         if col["link"]["rel"] == "collection"]
        else:
            # when detail=False, res == {resource_attrs}
            # when detail=True, res == {'type': {resource_attrs}}
            self.data = [Resource(self.type,
                                  fetch=recursive - 1 > 0,
                                  recursive=recursive - 1,
                                  **res.get(self.type, res))
                         for res_type, res_list in data.items()
                         for res in res_list]

        return self class ResourceNotFound(NotFound):

    def __str__(self):
        if self.r is None:
            return "Resource not found"
        return "Resource %s not found" % self.r.path \
            if self.r.path.is_uuid \
            else "Resource %s/%s not found" % \
            (self.r.type, text_type(self.r.fq_name)) class CommandError(Exception):
    pass def create_schema_from_version(version):
    """Provide a version of the schema to create it. Use
    list_available_schema_version to discover available versions.

    """
    schema_directory = _get_schema_version_path(version)
    return create_schema_from_xsd_directory(schema_directory, version) class DummySchema(object):

    def __init__(self):
        DummyResourceSchema()

    @property
    def version(self):
        return "dummy"

    def resource(self, resource_name):
        if resource_name not in self.all_resources():
            raise ResourceNotDefined(resource_name)
        return DummyResourceSchema()

    def all_resources(self):
        return DummyResourceSchema().children class CommandManager(object):

    def __init__(self, load_default=True):
        """Load commands from namespace

        :param load_default: tell the manager to load the default
                             namespace for commands (contrail_api_cli.command).
                             (True by default)
        :type load_default: bool
        """
        self.mgrs = []
        if load_default is True:
            self.load_namespace('contrail_api_cli.command')

    def load_namespace(self, ns):
        """Load commands from namespace.

        :param ns: namespace name
        :type ns: str
        """
        mgr = extension.ExtensionManager(namespace=ns,
                                         verify_requirements=True,
                                         on_load_failure_callback=self._on_failure)
        # Load commands from ns
        for ext in mgr.extensions:
            try:
                obj = ext.plugin(ext.name)
            except Exception as err:
                self._on_failure(self, ext, err)
                obj = None
            ext.obj = obj

        self.mgrs.append(mgr)

    def unload_namespace(self, ns):
        self.mgrs = [mgr for mgr in self.mgrs if not mgr.namespace == ns]

    def _on_failure(self, mgr, entrypoint, exc):
        print('Cannot load command %s: %s' % (entrypoint.name,
                                              exc))

    def get(self, name):
        """Return command instance of loaded
        commands by name

        :param name: name of the command
        :type name: str
        """
        for cmd_name, cmd in self.list:
            if cmd_name == name:
                return cmd
        raise CommandNotFound('Command %s not found. Type help for all commands' % name)

    @property
    def extensions(self):
        return itertools.chain(*[mgr.extensions for mgr in self.mgrs])

    @property
    def list(self):
        """Generator of command instances

        :rtype: (name, Command)
        """
        for ext in self.extensions:
            # don't return ext that failed
            # to load earlier
            if ext.obj is None:
                continue
            yield (ext.name, ext.obj)

    def add(self, name, cmd):
        ext = extension.Extension(name, None, cmd.__class__, cmd)
        self.mgrs[0].extensions.append(ext)

    @classmethod
    def register_argparse_commands(cls, parser, argv):
        in_parser = argparse.ArgumentParser(add_help=False)
        for p in (parser, in_parser):
            p.add_argument('--ns',
                           help='Command namespaces to load (default: %(default)s)',
                           metavar='COMMAND_NAMESPACE',
                           action='append',
                           default=[])
        options, _ = in_parser.parse_known_args(argv)
        mgr = CommandManager()
        for ns in options.ns:
            mgr.load_namespace(ns)
        subparsers = parser.add_subparsers(dest='subcmd')
        for cmd_name, cmd in mgr.list:
            subparser = subparsers.add_parser(cmd_name, help=cmd.description)
            cmd.add_arguments_to_parser(subparser)
        return mgr

    def get_completions(self, word_before_cursor, context, option=None):
        for cmd_name, cmd in self.list:
            if cmd_name.startswith(word_before_cursor):
                yield Completion(cmd_name,
                                 -len(word_before_cursor),
                                 display_meta=cmd.description) class CLITest(unittest.TestCase):

    @mock.patch('contrail_api_cli.resource.Context.session')
    def setUp(self, mock_session):
        self.maxDiff = None
        self.BASE = "http://localhost:8082"
        mock_session.configure_mock(base_url=self.BASE)
        mock_session.get_json.return_value = {
            "href": self.BASE,
            "links": [
                {"link": {"href": self.BASE + "/foos",
                          "name": "foo",
                          "rel": "collection"}},
                {"link": {"href": self.BASE + "/bars",
                          "name": "bar",
                          "rel": "collection"}},
                {"link": {"href": self.BASE + "/foobars",
                          "name": "foobar",
                          "rel": "collection"}}
            ]
        }
        DummyResourceSchema()
        Context().schema = DummySchema()

    def tearDown(self):
        Context().schema = None
import sys
import unittest
import uuid
import io
    import mock
    import unittest.mock as mock
import contrail_api_cli.command as cmds
from contrail_api_cli import client
from contrail_api_cli.utils import Path, FQName
from contrail_api_cli.context import Context
from contrail_api_cli.resource import Resource, Collection
from contrail_api_cli.exceptions import ResourceNotFound, CommandError
from contrail_api_cli.schema import create_schema_from_version, DummySchema
from contrail_api_cli.manager import CommandManager
from .utils import CLITest
from __future__ import unicode_literals
try:
except ImportError:




class Cmd(cmds.Command):
    description = "Not a real command"

    def __call__(self):
        if self._is_piped:
            return "piped"
        else:
            return "not piped"


class ArgTest(cmds.Command):
    arg = cmds.Arg()

    def __call__(self, arg=None):
        return arg


class TestCommand(CLITest):

    def setUp(self):

        CLITest.setUp(self)