def apiserving_method_decorator(api_method): """Decorator for ProtoRPC method that configures Google's API server. Args: api_method: Original method being wrapped. Returns: 'remote.invoke_remote_method' function responsible for actual invocation. Assigns the following attributes to invocation function: remote: Instance of RemoteInfo, contains remote method information. remote.request_type: Expected request type for remote method. remote.response_type: Response type returned from remote method. method_info: Instance of _MethodInfo, api method configuration. It is also assigned attributes corresponding to the aforementioned kwargs. Raises: TypeError: if the request_type or response_type parameters are not proper subclasses of messages.Message. """ remote_decorator = remote.method(request_message, response_message) remote_method = remote_decorator(api_method) remote_method.method_info = _MethodInfo( name=name or api_method.__name__, path=path or '', http_method=http_method or DEFAULT_HTTP_METHOD, cache_control=cache_control, scopes=scopes, audiences=audiences, allowed_client_ids=allowed_client_ids) return remote_method
def define_service(service_descriptor, module): """Define a new service proxy. Args: service_descriptor: ServiceDescriptor class that describes the service. module: Module to add service to. Request and response types are found relative to this module. Returns: Service class proxy capable of communicating with a remote server. """ class_dict = {'__module__': module.__name__} class_name = service_descriptor.name.encode('utf-8') for method_descriptor in service_descriptor.methods or []: request_definition = messages.find_definition( method_descriptor.request_type, module) response_definition = messages.find_definition( method_descriptor.response_type, module) method_name = method_descriptor.name.encode('utf-8') def remote_method(self, request): """Actual service method.""" raise NotImplementedError('Method is not implemented') remote_method.__name__ = method_name remote_method_decorator = remote.method(request_definition, response_definition) class_dict[method_name] = remote_method_decorator(remote_method) service_class = type(class_name, (remote.Service,), class_dict) return service_class
def define_service(service_descriptor, module): """Define a new service proxy. Args: service_descriptor: ServiceDescriptor class that describes the service. module: Module to add service to. Request and response types are found relative to this module. Returns: Service class proxy capable of communicating with a remote server. """ class_dict = {'__module__': module.__name__} class_name = service_descriptor.name.encode('utf-8') for method_descriptor in service_descriptor.methods or []: request_definition = messages.find_definition( method_descriptor.request_type, module) response_definition = messages.find_definition( method_descriptor.response_type, module) method_name = method_descriptor.name.encode('utf-8') def remote_method(self, request): """Actual service method.""" raise NotImplementedError('Method is not implemented') remote_method.__name__ = method_name remote_method_decorator = remote.method(request_definition, response_definition) class_dict[method_name] = remote_method_decorator(remote_method) service_class = type(class_name, (remote.Service, ), class_dict) return service_class
def _remote_method(method): ''' ''' # wrap responder wrapped = premote.method(request_klass, response_klass)(method) # make things transparent wrapped.__name__, wrapped.__doc__, wrapped.__inner__ = ( method.__name__, method.__doc__, method ) def _respond(self, _request_message): ''' ''' if isinstance(request, type) and issubclass(request, model.Model): # convert incoming message to model result = wrapped(self, request.from_message(_request_message)) else: # we're using regular messages always result = wrapped(self, _request_message) # convert outgoing message to model if it isn't already if isinstance(result, model.Model): return result.to_message() return result _respond.__inner__ = wrapped # quack quack _respond.__name__, _respond.__doc__, _respond.remote = ( method.__name__, method.__doc__, wrapped.remote ) # just for backup wrapped.__remote_name__, wrapped.__remote_doc__, wrapped.__remote__ = ( method.__name__, method.__doc__, wrapped.remote ) return _respond
def apiserving_method_decorator(api_method): """Decorator for ProtoRPC method that configures Google's API server. Args: api_method: Original method being wrapped. Returns: Function responsible for actual invocation. Assigns the following attributes to invocation function: remote: Instance of RemoteInfo, contains remote method information. remote.request_type: Expected request type for remote method. remote.response_type: Response type returned from remote method. method_info: Instance of _MethodInfo, api method configuration. It is also assigned attributes corresponding to the aforementioned kwargs. Raises: TypeError: if the request_type or response_type parameters are not proper subclasses of messages.Message. """ remote_decorator = remote.method(request_message, response_message) remote_method = remote_decorator(api_method) def invoke_remote(service_instance, request): users_id_token._maybe_set_current_user_vars(invoke_remote) return remote_method(service_instance, request) local_scopes = scopes if local_scopes is None: local_scopes = ['https://www.googleapis.com/auth/userinfo.email'] invoke_remote.remote = remote_method.remote invoke_remote.method_info = _MethodInfo( name=name or api_method.__name__, path=path or '', http_method=http_method or DEFAULT_HTTP_METHOD, cache_control=cache_control, scopes=local_scopes, audiences=audiences, allowed_client_ids=allowed_client_ids) invoke_remote.__name__ = invoke_remote.method_info.name return invoke_remote
def method(request_message=message_types.VoidMessage, response_message=message_types.VoidMessage, name=None, path=None, http_method='POST', scopes=None, audiences=None, allowed_client_ids=None, auth_level=None, api_key_required=None, metric_costs=None, use_request_uri=None): """Method decorator for API endpoint. Note that the path attribute _must_ match the name of the decorated method. https://github.com/cloudendpoints/endpoints-python/blob/9da60817aefbb0f2a4b9145c17ee39b9115067b0/endpoints/api_config.py#L1263 """ return remote.method(request_type=request_message, response_type=response_message)
def _remote_method_responder(method): ''' ''' def _respond(self, _request_message): ''' ''' if isinstance(request, type) and issubclass(request, model.Model): # convert incoming message to model result = method(self, request.from_message(_request_message)) else: # we're using regular messages always result = method(self, _request_message) # convert outgoing message to model if it isn't already if isinstance(result, model.Model): return result.to_message() return result # wrap responder return premote.method(request_klass, response_klass)(_respond)
def _remote_method_responder(method): ''' ''' def _respond(self, _request_message): ''' ''' if isinstance(request, type) and issubclass( request, model.Model): # convert incoming message to model result = method( self, request.from_message(_request_message)) else: # we're using regular messages always result = method(self, _request_message) # convert outgoing message to model if it isn't already if isinstance(result, model.Model): return result.to_message() return result # wrap responder return premote.method(request_klass, response_klass)(_respond)
def __call__(self, api_method): # Append the API path to the docstring if api_method.__doc__ is None: api_method.__doc__ = "" api_method.__doc__ += " ( /{0} )".format(self.path or api_method.__name__) if isinstance(self.request_message, endpoints.ResourceContainer): remote_decorator = remote.method( self.request_message.combined_message_class, self.response_message) else: remote_decorator = remote.method(self.request_message, self.response_message) remote_method = remote_decorator(api_method) def invoke_remote(service_instance, request): endpoints.users_id_token._maybe_set_current_user_vars( invoke_remote, api_info=getattr(service_instance, 'api_info', None), request=request) try: for middleware in self.pre_middlewares: resp = middleware(service_instance, request) if resp: return resp response = remote_method(service_instance, request) for middleware in self.post_middlewares: resp = middleware(service_instance, request, response) if resp: response = resp return response except Exception as e: for middleware in self.error_middlewares: resp = middleware(service_instance, request, e) if resp: return resp raise invoke_remote.remote = remote_method.remote if isinstance(self.request_message, endpoints.ResourceContainer): endpoints.ResourceContainer.add_to_cache(invoke_remote.remote, self.request_message) invoke_remote.method_info = _MethodInfo( name=self.name or api_method.__name__, path=self.path or api_method.__name__, http_method=self.http_method or "POST", scopes=self.scopes, audiences=self.audiences, allowed_client_ids=self.allowed_client_ids, auth_level=self.auth_level) invoke_remote.method_info.relative_path = self.path invoke_remote.api_method = api_method invoke_remote.__name__ = invoke_remote.method_info.name invoke_remote.__doc__ = api_method.__doc__ # for sphinx docs return invoke_remote
def _remote_method(method): """ Closure to wrap the target ``method`` at construction time with appropriate tooling to execute remote RPCs. :param method: Remote-capable method to be wrapped. :returns: Wrapped closure ``_respond`` that, when called, dispatches the target ``method``. """ def _respond(self, _request_message): """ Inner closure designed to wrap the raw remote ``method`` and enforce validation/conversion of ProtoRPC types to native Python ones. Also handles conversion in/out of Canteen models, if the remote method so chooses, by binding to ``canteen.Model`` subclasses instead of ProtoRPC ``message.Message``s. :param _request_message: Remotely-submitted ``request`` to (potentially) be converted and submitted to inner service ``method``. :returns: Result of calling ``method`` with ``_request_message`` as the originating request, so long as the request was successfully executed and passed all client-related constraints. """ if isinstance(request, type) and issubclass(request, model.Model): # convert incoming message to model result = method(self, request.from_message(_request_message)) else: # we're using regular messages always result = method(self, _request_message) # convert outgoing message to model if it isn't already if isinstance(result, model.Model): return result.to_message() return result # wrap responder wrapped = premote.method(request_klass, response_klass)(_respond) # make things transparent wrapped.__name__, wrapped.__doc__, wrapped.__inner__ = ( method.__name__, method.__doc__, method) _respond.__inner__ = wrapped # quack quack _respond.__name__, _respond.__doc__, _respond.remote = ( method.__name__, method.__doc__, wrapped.remote) # just for backup wrapped.__remote_name__, wrapped.__remote_doc__ = ( method.__name__, method.__doc__,) # add remote info wrapped.__remote__ = wrapped.remote return _respond