def __init__(self): self.objects = {} self.services = ServiceCollection() self.__obj_lock = Lock() self.interpreter = Interpreter(self)
class Registrar(object): """ The Registrar defines a collection where services and objects can be registered. Other classes can then use and listen for those services and objects. """ class _RepoSvc(object): # pylint: disable-msg=R0903 """ Repository Service Consists of the service function, a grammar that defines how a POS tagged query is to be turned into the service's arguments (structure defined in interpreter.py), a lock that controls concurrent access to the service, and an optional namespace to prevent plugins offering similar/same services from stepping on each others' toes. """ def __init__(self, name, svc, grammar=None, usage='', namespace=None): self.name = name self.svc = svc self.grammar = grammar self.usage = usage self.namespace = namespace self.lock = Lock() class _RepoObj(object): # pylint: disable-msg=R0903 """ Repository Object Consists of an object placed into the repository and an event that handles alerting interested parties of changes to the object. The object itself should only change upon calls to register_object(). Any changes to complex types may not produce a change_event signal. """ def __init__(self, obj): self.obj = obj self.change_event = Event() def __init__(self): self.objects = {} self.services = ServiceCollection() self.__obj_lock = Lock() self.interpreter = Interpreter(self) def find_best_service(self, query): """Use the interpreter to find the single best (service, namespace, arguments) triplet for the given query. """ return self.interpreter.best_interpretation(query) def find_services(self, query): """Use the interpreter to turn the query into a list of (service, namespace, arguments) triplets. """ return self.interpreter.interpret(query) def register_service(self, svc_name, svc_func, grammar=None, usage='', namespace=None): """Register a function to be made available to clients and plugins. Keyword arguments: svc_name -- the name the service is registered under (may be a duplicate of an existing service) svc_func -- the function called when the service is requested grammar -- the grammar (defined in the Interpreter) that describes how keyword arguments for svc_func are assembled (default None) usage -- a string quickly defining how to use the service. Any occurrance of '%s' in the usage will be replaced with the name of the service. (default '') namespace -- any hashable object (preferably a string). When combined with svc_name, it is used to uniquely identify a specific implementation of a service. If both the svc_name and namespace collide, the service is overwritten. (default None) """ usage = usage.replace('%s', svc_name) name = svc_name.lower() self.services.add(name, namespace, self._RepoSvc( name=name, svc=svc_func, grammar=grammar, usage=usage, namespace=namespace)) def unregister_service(self, svc_name, namespace=None): """Remove the registered service with the provided name and (optional) namespace. """ svc_name = svc_name.lower() svc = self.services.get(svc_name, namespace) if svc: with locked(svc.lock): self.services.remove(svc_name, namespace) def request_service(self, svc_name, namespace=None, argdict=None, **kwargs): """Call the service registered to svc_name with the specified (optional) namespace and given kwargs. """ svc_name = svc_name.lower() if not self.services.get(svc_name, namespace): raise ServiceDoesNotExist("Service does not exist.") service = self.services.get(svc_name, namespace) with locked(service.lock): if argdict: try: kwargs.update(argdict) except AttributeError: pass return service.svc(**kwargs) def register_object(self, obj_name, obj): """Create a shallow copy of the provided object and register it. WARNING: Anything beyond simple objects may be changed without warning by other plugins. """ obj_name = obj_name.lower() with locked(self.__obj_lock): if obj_name not in self.objects: self.objects[obj_name] = self._RepoObj(_copy(obj)) else: self.objects[obj_name].obj = obj # Prevents the handler from needing a call to get_object self.objects[obj_name].change_event.fire(obj) def remove_object(self, obj_name): """Remove a registered object from the internal cache.""" obj_name = obj_name.lower() with locked(self.__obj_lock): del self.objects[obj_name] def register_object_listener(self, obj_name, callback): """Register a callback to be executed whenever an object with the specified name is registered. Callback should take one argument - the new object """ obj_name = obj_name.lower() if obj_name not in self.objects: self.objects[obj_name] = self._RepoObj(None) self.objects[obj_name].change_event += callback def remove_object_listener(self, obj_name, callback): """Remove the given callback from being run when the object registered under obj_name is updated. Must be called with the same function the listener was registered with. """ obj_name = obj_name.lower() if obj_name in self.objects: self.objects[obj_name].change_event -= callback def get_object(self, obj_name): """Return a shallow copy of the object in the repository. WARNING: Anything beyond simple objects may be changed without warning by other plugins. """ obj_name = obj_name.lower() if obj_name not in self.objects or self.objects[obj_name] is None: raise ObjectDoesNotExist(obj_name) return _copy(self.objects[obj_name].obj)
def __init__(self): self.local_registrar = Registrar() self.remote_registrars = defaultdict(dict) self.interpreter = Interpreter(self)
class Registrar(object): """ The Registrar defines a collection where services and objects can be registered. Other classes can then use and listen for those services and objects. """ class _RepoSvc(object): # pylint: disable-msg=R0903 """ Repository Service Consists of the service function, a grammar that defines how a POS tagged query is to be turned into the service's arguments (structure defined in interpreter.py), a lock that controls concurrent access to the service, and an optional namespace to prevent plugins offering similar/same services from stepping on each others' toes. """ def __init__(self, name, svc, grammar=None, usage='', namespace=None): self.name = name self.svc = svc self.grammar = grammar self.usage = usage self.namespace = namespace self.lock = Lock() class _RepoObj(object): # pylint: disable-msg=R0903 """ Repository Object Consists of an object placed into the repository and an event that handles alerting interested parties of changes to the object. The object itself should only change upon calls to register_object(). Any changes to complex types may not produce a change_event signal. """ def __init__(self, obj): self.obj = obj self.change_event = Event() def __init__(self): self.objects = {} self.services = ServiceCollection() self.__obj_lock = Lock() self.interpreter = Interpreter(self) def find_best_service(self, query): """Use the interpreter to find the single best (service, namespace, arguments) triplet for the given query. """ return self.interpreter.best_interpretation(query) def find_services(self, query): """Use the interpreter to turn the query into a list of (service, namespace, arguments) triplets. """ return self.interpreter.interpret(query) def register_service(self, svc_name, svc_func, grammar=None, usage='', namespace=None): """Register a function to be made available to clients and plugins. Keyword arguments: svc_name -- the name the service is registered under (may be a duplicate of an existing service) svc_func -- the function called when the service is requested grammar -- the grammar (defined in the Interpreter) that describes how keyword arguments for svc_func are assembled (default None) usage -- a string quickly defining how to use the service. Any occurrance of '%s' in the usage will be replaced with the name of the service. (default '') namespace -- any hashable object (preferably a string). When combined with svc_name, it is used to uniquely identify a specific implementation of a service. If both the svc_name and namespace collide, the service is overwritten. (default None) """ usage = usage.replace('%s', svc_name) name = svc_name.lower() self.services.add( name, namespace, self._RepoSvc(name=name, svc=svc_func, grammar=grammar, usage=usage, namespace=namespace)) def unregister_service(self, svc_name, namespace=None): """Remove the registered service with the provided name and (optional) namespace. """ svc_name = svc_name.lower() svc = self.services.get(svc_name, namespace) if svc: with locked(svc.lock): self.services.remove(svc_name, namespace) def request_service(self, svc_name, namespace=None, argdict=None, **kwargs): """Call the service registered to svc_name with the specified (optional) namespace and given kwargs. """ svc_name = svc_name.lower() if not self.services.get(svc_name, namespace): raise ServiceDoesNotExist("Service does not exist.") service = self.services.get(svc_name, namespace) with locked(service.lock): if argdict: try: kwargs.update(argdict) except AttributeError: pass return service.svc(**kwargs) def register_object(self, obj_name, obj): """Create a shallow copy of the provided object and register it. WARNING: Anything beyond simple objects may be changed without warning by other plugins. """ obj_name = obj_name.lower() with locked(self.__obj_lock): if obj_name not in self.objects: self.objects[obj_name] = self._RepoObj(_copy(obj)) else: self.objects[obj_name].obj = obj # Prevents the handler from needing a call to get_object self.objects[obj_name].change_event.fire(obj) def remove_object(self, obj_name): """Remove a registered object from the internal cache.""" obj_name = obj_name.lower() with locked(self.__obj_lock): del self.objects[obj_name] def register_object_listener(self, obj_name, callback): """Register a callback to be executed whenever an object with the specified name is registered. Callback should take one argument - the new object """ obj_name = obj_name.lower() if obj_name not in self.objects: self.objects[obj_name] = self._RepoObj(None) self.objects[obj_name].change_event += callback def remove_object_listener(self, obj_name, callback): """Remove the given callback from being run when the object registered under obj_name is updated. Must be called with the same function the listener was registered with. """ obj_name = obj_name.lower() if obj_name in self.objects: self.objects[obj_name].change_event -= callback def get_object(self, obj_name): """Return a shallow copy of the object in the repository. WARNING: Anything beyond simple objects may be changed without warning by other plugins. """ obj_name = obj_name.lower() if obj_name not in self.objects or self.objects[obj_name] is None: raise ObjectDoesNotExist(obj_name) return _copy(self.objects[obj_name].obj)