diff options
Diffstat (limited to 'mojo/public/python/mojo_bindings/reflection.py')
-rw-r--r-- | mojo/public/python/mojo_bindings/reflection.py | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/mojo/public/python/mojo_bindings/reflection.py b/mojo/public/python/mojo_bindings/reflection.py deleted file mode 100644 index 5432691..0000000 --- a/mojo/public/python/mojo_bindings/reflection.py +++ /dev/null @@ -1,569 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""The metaclasses used by the mojo python bindings.""" - -import itertools -import logging -import sys - -# pylint: disable=F0401 -import mojo_bindings.messaging as messaging -import mojo_bindings.promise as promise -import mojo_bindings.serialization as serialization - - -class MojoEnumType(type): - """Meta class for enumerations. - - Usage: - class MyEnum(object): - __metaclass__ = MojoEnumType - VALUES = [ - ('A', 0), - 'B', - ('C', 5), - ] - - This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5. - """ - - def __new__(mcs, name, bases, dictionary): - dictionary['__slots__'] = () - dictionary['__new__'] = None - for value in dictionary.pop('VALUES', []): - if not isinstance(value, tuple): - raise ValueError('incorrect value: %r' % value) - key, enum_value = value - if isinstance(key, str) and isinstance(enum_value, int): - dictionary[key] = enum_value - else: - raise ValueError('incorrect value: %r' % value) - return type.__new__(mcs, name, bases, dictionary) - - def __setattr__(cls, key, value): - raise AttributeError('can\'t set attribute') - - def __delattr__(cls, key): - raise AttributeError('can\'t delete attribute') - - -class MojoStructType(type): - """Meta class for structs. - - Usage: - class MyStruct(object): - __metaclass__ = MojoStructType - DESCRIPTOR = { - 'constants': { - 'C1': 1, - 'C2': 2, - }, - 'enums': { - 'ENUM1': [ - ('V1', 1), - 'V2', - ], - 'ENUM2': [ - ('V1', 1), - 'V2', - ], - }, - 'fields': [ - SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0), - ], - } - - This will define an struct, with: - - 2 constants 'C1' and 'C2'; - - 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and - 'V2'; - - 1 int32 field named 'x'. - """ - - def __new__(mcs, name, bases, dictionary): - dictionary['__slots__'] = ('_fields') - descriptor = dictionary.pop('DESCRIPTOR', {}) - - # Add constants - dictionary.update(descriptor.get('constants', {})) - - # Add enums - enums = descriptor.get('enums', {}) - for key in enums: - dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] }) - - # Add fields - groups = descriptor.get('fields', []) - - fields = list( - itertools.chain.from_iterable([group.descriptors for group in groups])) - fields.sort(key=lambda f: f.index) - for field in fields: - dictionary[field.name] = _BuildProperty(field) - - # Add init - dictionary['__init__'] = _StructInit(fields) - - # Add serialization method - serialization_object = serialization.Serialization(groups) - def Serialize(self, handle_offset=0): - return serialization_object.Serialize(self, handle_offset) - dictionary['Serialize'] = Serialize - - # pylint: disable=W0212 - def AsDict(self): - return self._fields - dictionary['AsDict'] = AsDict - - def Deserialize(cls, context): - result = cls.__new__(cls) - fields = {} - serialization_object.Deserialize(fields, context) - result._fields = fields - return result - dictionary['Deserialize'] = classmethod(Deserialize) - - dictionary['__eq__'] = _StructEq(fields) - dictionary['__ne__'] = _StructNe - - return type.__new__(mcs, name, bases, dictionary) - - # Prevent adding new attributes, or mutating constants. - def __setattr__(cls, key, value): - raise AttributeError('can\'t set attribute') - - # Prevent deleting constants. - def __delattr__(cls, key): - raise AttributeError('can\'t delete attribute') - - -class MojoInterfaceType(type): - """Meta class for interfaces. - - Usage: - class MyInterface(object): - __metaclass__ = MojoInterfaceType - DESCRIPTOR = { - 'client': MyInterfaceClient, - 'methods': [ - { - 'name': 'FireAndForget', - 'ordinal': 0, - 'parameters': [ - SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0), - ] - }, - { - 'name': 'Ping', - 'ordinal': 1, - 'parameters': [ - SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0), - ], - 'responses': [ - SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0), - ], - }, - ], - } - """ - - def __new__(mcs, name, bases, dictionary): - # If one of the base class is already an interface type, do not edit the - # class. - for base in bases: - if isinstance(base, mcs): - return type.__new__(mcs, name, bases, dictionary) - - descriptor = dictionary.pop('DESCRIPTOR', {}) - - methods = [_MethodDescriptor(x) for x in descriptor.get('methods', [])] - for method in methods: - dictionary[method.name] = _NotImplemented - client_class_getter = descriptor.get('client', None) - - interface_manager = InterfaceManager(name, methods, client_class_getter) - dictionary.update({ - 'client': None, - 'manager': None, - '_interface_manager': interface_manager, - }) - - interface_class = type.__new__(mcs, name, bases, dictionary) - interface_manager.interface_class = interface_class - return interface_class - - @property - def manager(cls): - return cls._interface_manager - - # Prevent adding new attributes, or mutating constants. - def __setattr__(cls, key, value): - raise AttributeError('can\'t set attribute') - - # Prevent deleting constants. - def __delattr__(cls, key): - raise AttributeError('can\'t delete attribute') - - -class InterfaceProxy(object): - """ - A proxy allows to access a remote interface through a message pipe. - """ - pass - - -class InterfaceRequest(object): - """ - An interface request allows to send a request for an interface to a remote - object and start using it immediately. - """ - - def __init__(self, handle): - self._handle = handle - - def IsPending(self): - return self._handle.IsValid() - - def PassMessagePipe(self): - result = self._handle - self._handle = None - return result - - -class InterfaceManager(object): - """ - Manager for an interface class. The manager contains the operation that allows - to bind an implementation to a pipe, or to generate a proxy for an interface - over a pipe. - """ - - def __init__(self, name, methods, client_class_getter): - self.name = name - self.methods = methods - self.interface_class = None - self._client_class_getter = client_class_getter - self._client_manager = None - self._client_manager_computed = False - self._proxy_class = None - self._stub_class = None - - @property - def client_manager(self): - if not self._client_manager_computed: - self._client_manager_computed = True - if self._client_class_getter: - self._client_manager = self._client_class_getter().manager - return self._client_manager - - def Proxy(self, handle): - router = messaging.Router(handle) - error_handler = _ProxyErrorHandler() - router.SetErrorHandler(error_handler) - router.Start() - return self._InternalProxy(router, error_handler) - - # pylint: disable=W0212 - def Bind(self, impl, handle): - router = messaging.Router(handle) - router.SetIncomingMessageReceiver(self._Stub(impl)) - error_handler = _ProxyErrorHandler() - router.SetErrorHandler(error_handler) - - # Retain the router, until an error happen. - retainer = _Retainer(router) - def Cleanup(_): - retainer.release() - error_handler.AddCallback(Cleanup) - - if self.client_manager: - impl.client = self.client_manager._InternalProxy(router, error_handler) - - # Give an instance manager to the implementation to allow it to close - # the connection. - impl.manager = InstanceManager(router) - - router.Start() - - def _InternalProxy(self, router, error_handler): - if not self._proxy_class: - dictionary = { - '__module__': __name__, - '__init__': _ProxyInit, - } - if self.client_manager: - dictionary['client'] = property(_ProxyGetClient, _ProxySetClient) - dictionary['manager'] = None - dictionary['_client_manager'] = self.client_manager - for method in self.methods: - dictionary[method.name] = _ProxyMethodCall(method) - self._proxy_class = type('%sProxy' % self.name, - (self.interface_class, InterfaceProxy), - dictionary) - - proxy = self._proxy_class(router, error_handler) - # Give an instance manager to the proxy to allow to close the connection. - proxy.manager = InstanceManager(router) - return proxy - - def _Stub(self, impl): - if not self._stub_class: - accept_method = _StubAccept(self.methods) - dictionary = { - '__module__': __name__, - '__init__': _StubInit, - 'Accept': accept_method, - 'AcceptWithResponder': accept_method, - } - self._stub_class = type('%sStub' % self.name, - (messaging.MessageReceiverWithResponder,), - dictionary) - return self._stub_class(impl) - - -class InstanceManager(object): - """ - Manager for the implementation of an interface or a proxy. The manager allows - to control the connection over the pipe. - """ - def __init__(self, router): - self.router = router - - def Close(self): - self.router.Close() - - def PassMessagePipe(self): - return self.router.PassMessagePipe() - - -class _MethodDescriptor(object): - def __init__(self, descriptor): - self.name = descriptor['name'] - self.ordinal = descriptor['ordinal'] - self.parameters_struct = _ConstructParameterStruct( - descriptor['parameters'], self.name, "Parameters") - self.response_struct = _ConstructParameterStruct( - descriptor.get('responses'), self.name, "Responses") - - -def _ConstructParameterStruct(descriptor, name, suffix): - if descriptor is None: - return None - parameter_dictionary = { - '__metaclass__': MojoStructType, - '__module__': __name__, - 'DESCRIPTOR': descriptor, - } - return MojoStructType( - '%s%s' % (name, suffix), - (object,), - parameter_dictionary) - - -class _ProxyErrorHandler(messaging.ConnectionErrorHandler): - def __init__(self): - messaging.ConnectionErrorHandler.__init__(self) - self._callbacks = set() - - def OnError(self, result): - exception = messaging.MessagingException('Mojo error: %d' % result) - for callback in list(self._callbacks): - callback(exception) - self._callbacks = None - - def AddCallback(self, callback): - if self._callbacks is not None: - self._callbacks.add(callback) - - def RemoveCallback(self, callback): - if self._callbacks: - self._callbacks.remove(callback) - - -class _Retainer(object): - - # Set to force instances to be retained. - _RETAINED = set() - - def __init__(self, retained): - self._retained = retained - _Retainer._RETAINED.add(self) - - def release(self): - self._retained = None - _Retainer._RETAINED.remove(self) - - -def _StructInit(fields): - def _Init(self, *args, **kwargs): - if len(args) + len(kwargs) > len(fields): - raise TypeError('__init__() takes %d argument (%d given)' % - (len(fields), len(args) + len(kwargs))) - self._fields = {} - for f, a in zip(fields, args): - self.__setattr__(f.name, a) - remaining_fields = set(x.name for x in fields[len(args):]) - for name in kwargs: - if not name in remaining_fields: - if name in (x.name for x in fields[:len(args)]): - raise TypeError( - '__init__() got multiple values for keyword argument %r' % name) - raise TypeError('__init__() got an unexpected keyword argument %r' % - name) - self.__setattr__(name, kwargs[name]) - return _Init - - -def _BuildProperty(field): - """Build the property for the given field.""" - - # pylint: disable=W0212 - def Get(self): - if field.name not in self._fields: - self._fields[field.name] = field.GetDefaultValue() - return self._fields[field.name] - - # pylint: disable=W0212 - def Set(self, value): - self._fields[field.name] = field.field_type.Convert(value) - - return property(Get, Set) - - -def _StructEq(fields): - def _Eq(self, other): - if type(self) is not type(other): - return False - for field in fields: - if getattr(self, field.name) != getattr(other, field.name): - return False - return True - return _Eq - -def _StructNe(self, other): - return not self.__eq__(other) - - -def _ProxyInit(self, router, error_handler): - self._router = router - self._error_handler = error_handler - self._client = None - - -# pylint: disable=W0212 -def _ProxyGetClient(self): - return self._client - - -# pylint: disable=W0212 -def _ProxySetClient(self, client): - self._client = client - stub = self._client_manager._Stub(client) - self._router.SetIncomingMessageReceiver(stub) - - -# pylint: disable=W0212 -def _ProxyMethodCall(method): - flags = messaging.NO_FLAG - if method.response_struct: - flags = messaging.MESSAGE_EXPECTS_RESPONSE_FLAG - def _Call(self, *args, **kwargs): - def GenerationMethod(resolve, reject): - message = _GetMessage(method, flags, *args, **kwargs) - if method.response_struct: - def Accept(message): - try: - assert message.header.message_type == method.ordinal - payload = message.payload - response = method.response_struct.Deserialize( - serialization.RootDeserializationContext(payload.data, - payload.handles)) - as_dict = response.AsDict() - if len(as_dict) == 1: - value = as_dict.values()[0] - if not isinstance(value, dict): - response = value - resolve(response) - return True - except Exception as e: - # Adding traceback similarly to python 3.0 (pep-3134) - e.__traceback__ = sys.exc_info()[2] - reject(e) - return False - finally: - self._error_handler.RemoveCallback(reject) - - self._error_handler.AddCallback(reject) - if not self._router.AcceptWithResponder( - message, messaging.ForwardingMessageReceiver(Accept)): - self._error_handler.RemoveCallback(reject) - reject(messaging.MessagingException("Unable to send message.")) - else: - if (self._router.Accept(message)): - resolve(None) - else: - reject(messaging.MessagingException("Unable to send message.")) - return promise.Promise(GenerationMethod) - return _Call - - -def _GetMessage(method, flags, *args, **kwargs): - if flags == messaging.MESSAGE_IS_RESPONSE_FLAG: - struct = method.response_struct(*args, **kwargs) - else: - struct = method.parameters_struct(*args, **kwargs) - header = messaging.MessageHeader(method.ordinal, flags) - data = header.Serialize() - (payload, handles) = struct.Serialize() - data.extend(payload) - return messaging.Message(data, handles, header) - - -def _StubInit(self, impl): - self.impl = impl - - -def _StubAccept(methods): - methods_by_ordinal = dict((m.ordinal, m) for m in methods) - def Accept(self, message, responder=None): - try: - header = message.header - assert header.expects_response == bool(responder) - assert header.message_type in methods_by_ordinal - method = methods_by_ordinal[header.message_type] - payload = message.payload - parameters = method.parameters_struct.Deserialize( - serialization.RootDeserializationContext( - payload.data, payload.handles)).AsDict() - response = getattr(self.impl, method.name)(**parameters) - if header.expects_response: - def SendResponse(response): - if isinstance(response, dict): - response_message = _GetMessage(method, - messaging.MESSAGE_IS_RESPONSE_FLAG, - **response) - else: - response_message = _GetMessage(method, - messaging.MESSAGE_IS_RESPONSE_FLAG, - response) - response_message.header.request_id = header.request_id - responder.Accept(response_message) - p = promise.Promise.Resolve(response).Then(SendResponse) - if self.impl.manager: - # Close the connection in case of error. - p.Catch(lambda _: self.impl.manager.Close()) - return True - # pylint: disable=W0702 - except: - # Close the connection in case of error. - logging.warning( - 'Error occured in accept method. Connection will be closed.') - if self.impl.manager: - self.impl.manager.Close() - return False - return Accept - - -def _NotImplemented(*_1, **_2): - raise NotImplementedError() |