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 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 Observable(object):

    def __new__(cls, *args, **kwargs):
        return super(Observable, cls).__new__(cls)

    @classmethod
    def register(cls, event, callback):
        logger.debug("registering %s to %s" % (event, callback))
        if not hasattr(cls, "observers"):
            cls.observers = {}
        if event not in cls.observers:
            cls.observers[event] = []
        cls.observers[event].append(callback)

    @classmethod
    def unregister(cls, event, callback):
        try:
            cls.observers[event].remove(callback)
        except (ValueError, KeyError):
            pass

    @classmethod
    def emit(cls, event, data):
        logger.debug("emiting event %s with %s" % (event, repr(data)))
        if not hasattr(cls, "observers"):
            cls.observers = {}
        [cbk(data)
         for evt, cbks in cls.observers.items()
         for cbk in cbks
         if evt == event] def to_json(resource_dict, cls=None):
    return json.dumps(resource_dict,
                      indent=2,
                      sort_keys=True,
                      skipkeys=True,
                      cls=cls) 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 ResourceMissing(Exception):
    pass class CollectionNotFound(NotFound):

    def __str__(self):
        if self.c is None:
            return "Collection not found"
        return "Collection %s not found" % self.c.path class ChildrenExists(Exists):

    def __str__(self):
        return "Children %s exists" % self._paths class BackRefsExists(Exists):

    def __str__(self):
        return "Back references from %s exists" % self._paths class IsSystemResource(Exists):

    def __str__(self):
        return "System resources %s cannot be changed" % self._paths 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
import json
import string
import re
import itertools
import logging
import datrie
from uuid import UUID
from six import string_types, text_type
from functools import wraps
from datetime import datetime
    from UserDict import UserDict
    from UserList import UserList
    from collections import UserDict, UserList
from keystoneauth1.exceptions.http import HttpError
from prompt_toolkit.completion import Completion
from .utils import FQName, Path, Observable, to_json
from .exceptions import ResourceNotFound, ResourceMissing, \
    CollectionNotFound, ChildrenExists, BackRefsExists, IsSystemResource
from .context import Context
from __future__ import unicode_literals
try:
except ImportError:




logger = logging.getLogger(__name__)


def http_error_handler(f):
    """Handle 404 errors returned by the API server
    """

    def hrefs_to_resources(hrefs):
        for href in hrefs.replace(',', '').split():
            type, uuid = href.split('/')[-2:]
            yield Resource(type, uuid=uuid)

    def hrefs_list_to_resources(hrefs_list):
        for href in eval(hrefs_list):
            type, uuid = href.split('/')[-2:]
            yield Resource(type, uuid=uuid)

    @wraps(f)
    def wrapper(self, *args, **kwargs):
        try:
            return f(self, *args, **kwargs)
        except HttpError as e:
            if e.http_status == 404:
                # remove previously created resource
                # from the cache
                self.emit('deleted', self)
                if isinstance(self, Resource):

                    raise ResourceNotFound(resource=self)