Source code for spyne.application
#
# spyne - Copyright (C) Spyne contributors.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#
import logging
logger = logging.getLogger(__name__)
from spyne.model.fault import Fault
from spyne.interface import Interface
from spyne._base import EventManager
from spyne.util.appreg import register_application
def get_fault_string_from_exception(e):
return str(e)
def return_traceback_in_unhandled_exceptions():
[docs] """Call this function first thing in your main function to return tracebacks
to your clients in case of unhandled exceptions.
"""
global get_fault_string_from_exception
import traceback
def _get_fault_string_from_exception(e):
return traceback.format_exc()
get_fault_string_from_exception = _get_fault_string_from_exception
class Application(object):
[docs] '''The Application class is the glue between one or more service
definitions, input and output protocols.
:param services: An iterable of ServiceBase subclasses that define
the exposed services.
:param tns: The targetNamespace attribute of the exposed
service.
:param name: The optional name attribute of the exposed service.
The default is the name of the application class
which is by default 'Application'.
:param in_protocol: A ProtocolBase instance that denotes the input
protocol. It's only optional for NullServer transport.
:param out_protocol: A ProtocolBase instance that denotes the output
protocol. It's only optional for NullServer transport.
:param interface: Ignored. Kept for backwards-compatibility purposes.
Supported events:
* method_call:
Called right before the service method is executed
* method_return_object:
Called right after the service method is executed
* method_exception_object:
Called when an exception occurred in a service method, before the
exception is serialized.
* method_context_constructed:
Called from the constructor of the MethodContext instance.
* method_context_destroyed:
Called from the destructor of the MethodContext instance.
'''
transport = None
def __init__(self, services, tns, name=None,
in_protocol=None, out_protocol=None, interface=None):
self.services = services
self.tns = tns
self.name = name
if self.name is None:
self.name = self.__class__.__name__.split('.')[-1]
self.event_manager = EventManager(self)
self.error_handler = None
self.interface = Interface(self)
self.in_protocol = in_protocol
self.out_protocol = out_protocol
self.in_protocol.set_app(self)
self.out_protocol.set_app(self)
register_application(self)
self.reinitialize()
def process_request(self, ctx):
[docs] """Takes a MethodContext instance. Returns the response to the request
as a native python object. If the function throws an exception, it
returns None and sets the exception object to ctx.out_error.
Overriding this method would break event management. So this is not
meant to be overridden unless you know what you're doing.
"""
try:
# fire events
self.event_manager.fire_event('method_call', ctx)
ctx.service_class.event_manager.fire_event('method_call', ctx)
# call the method
ctx.out_object = self.call_wrapper(ctx)
# out object is always an iterable of return values. see
# MethodContext docstrings for more info
if len(ctx.descriptor.out_message._type_info) == 0:
ctx.out_object = [None]
elif len(ctx.descriptor.out_message._type_info) == 1:
# otherwise, the return value should already be wrapped in an
# iterable.
ctx.out_object = [ctx.out_object]
# fire events
self.event_manager.fire_event('method_return_object', ctx)
ctx.service_class.event_manager.fire_event(
'method_return_object', ctx)
except Fault, e:
logger.exception(e)
ctx.out_error = e
# fire events
self.event_manager.fire_event('method_exception_object', ctx)
if ctx.service_class != None:
ctx.service_class.event_manager.fire_event(
'method_exception_object', ctx)
except Exception, e:
logger.exception(e)
ctx.out_error = Fault('Server', get_fault_string_from_exception(e))
# fire events
self.event_manager.fire_event('method_exception_object', ctx)
if ctx.service_class != None:
ctx.service_class.event_manager.fire_event(
'method_exception_object', ctx)
def call_wrapper(self, ctx):
[docs] """This method calls the call_wrapper method in the service definition.
This can be overridden to make an application-wide custom exception
management.
"""
return ctx.service_class.call_wrapper(ctx)
def _has_callbacks(self):
return self.interface._has_callbacks()
def reinitialize(self):
from spyne.server import ServerBase
server = ServerBase(self)
aux_memo = set()
for s,d in self.interface.method_id_map.values():
if d.aux is not None and not id(d.aux) in aux_memo:
d.aux.initialize(server)
aux_memo.add(id(d.aux))
def __hash__(self):
return hash(tuple([id(s) for s in self.services]))