Source code for caspia.meadow.lookup

# pylint: disable=redefined-builtin
import functools

import caspia.meadow


[docs]class ActiveNamespace: def __init__(self, lookup, path): self.lookup = lookup self.path = path @property def full_path(self): if self.parent is None: return self.path else: return self.parent.full_path + '.' + self.path def __enter__(self): self.parent = self.lookup.active_namespace self.lookup.active_namespace = self return self def __exit__(self, *args): self.lookup.active_namespace = self.parent self.parent = None
[docs]class Lookup: """ This class works as a collection of known services. """ def __init__(self, create=None, prepare=None): self.active_namespace = None self.services = dict() self.create_hooks = [create] if create else [] self.prepare_hooks = [prepare] if prepare else [] def _create_service(self, name): for hook in self.create_hooks: instance = hook(name) if instance: return instance from caspia.meadow.client import get_consumer_class stype, _ = caspia.meadow.name.split(name) return get_consumer_class(stype)(name) def _prepare_service(self, service): for hook in self.prepare_hooks: hook(service)
[docs] def add(self, service): """ Register given service within this lookup instance. """ self.services[service.name] = service self._prepare_service(service)
[docs] def add_prepare_hook(self, func): """ Register a hook (function) to be called with every new service instance added to this lookup. :param func: The function hook with signature func(new_service). """ self.prepare_hooks.append(func)
[docs] def add_create_hook(self, func): """ Register a new service creator. When user requests a service from this lookup and the service is not known, the lookup tries to create it registered creators. Creator is a callable creator(service_type, service_name) -> None|Service. """ self.create_hooks.append(func)
[docs] def find(self, name, type=None): # pylint: disable=redefined-builtin """ Find service with given name (and optionally type). """ if type: name = caspia.meadow.name.update(name, type=type) full_name = self.resolve_name(name) if full_name in self.services: return self.services[full_name] return None
[docs] def get(self, name, type=None, create=True): """ Get service of a given type and name. Try to create it, if ``create`` is True """ if type: name = caspia.meadow.name.update(name, type=type) full_name = self.resolve_name(name) instance = self.find(name) if instance is not None: return instance elif create: instance = self._create_service(full_name) self.services[full_name] = instance self._prepare_service(instance) return instance else: return None
[docs] def namespace(self, path): """ Return object, which if used as a context manager enables use of relative names. :Example: with lookup.namespace('basement'): lookup.get('light', '.light') # gets service named basement.light """ return ActiveNamespace(self, path)
[docs] def resolve_name(self, name): """ Resolve name with respect to active namespaces. """ if self.active_namespace: type, path = caspia.meadow.name.split(name, strict=False) path = caspia.meadow.namespace.resolve_relative(path, self.active_namespace.full_path) return caspia.meadow.name.update(path, type=type) else: return name
def __getitem__(self, key): return functools.partial(self.get, type=key) def __getattr__(self, attr): return functools.partial(self.get, type=attr)