/usr/lib/python2.7/dist-packages/spyne/application.py is in python-spyne 2.12.11-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | #
# 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__)
logger_client = logging.getLogger('.'.join([__name__, 'client']))
logger_server = logging.getLogger('.'.join([__name__, 'server']))
from spyne import BODY_STYLE_EMPTY
from spyne import BODY_STYLE_BARE
from spyne import BODY_STYLE_WRAPPED
from spyne.error import Fault, Redirect
from spyne.interface import Interface
from spyne import EventManager
from spyne.util.appreg import register_application
from spyne.error import RespawnError
def get_fault_string_from_exception(e):
# haha.
return "Internal Error"
def return_traceback_in_unhandled_exceptions():
"""Call this function first thing in your main function to return original
python errors 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):
"""The Application class is the glue between one or more service
definitions, input and output protocols.
:param services: An iterable of ServiceBase subclasses that defines
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 config: An arbitrary python object to store random global data.
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_created``:
Called from the constructor of the MethodContext instance.
* ``method_context_closed``:
Called from the ``close()`` function of the MethodContext instance,
which in turn is called by the transport when the response is fully
sent to the client (or in the client case, the response is fully
received from server).
"""
transport = None
def __init__(self, services, tns, name=None,
in_protocol=None, out_protocol=None, config=None):
self.services = tuple(services)
self.tns = tns
self.name = name
self.config = config
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
if self.in_protocol is None:
from spyne.protocol import ProtocolBase
self.in_protocol = ProtocolBase()
self.in_protocol.set_app(self)
# FIXME: this normally is another parameter to set_app but it's kept
# separate for backwards compatibility reasons.
self.in_protocol.message = self.in_protocol.REQUEST
if self.out_protocol is None:
from spyne.protocol import ProtocolBase
self.out_protocol = ProtocolBase()
self.out_protocol.set_app(self)
# FIXME: this normally is another parameter to set_app but it's kept
# separate for backwards compatibility reasons.
self.out_protocol.message = self.out_protocol.RESPONSE
register_application(self)
def process_request(self, ctx):
"""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)
if ctx.service_class is not None:
ctx.service_class.event_manager.fire_event('method_call', ctx)
# in object is always a sequence of incoming values. We need to fix
# that for bare mode.
if ctx.descriptor.body_style is BODY_STYLE_BARE:
ctx.in_object = [ctx.in_object]
elif ctx.descriptor.body_style is BODY_STYLE_EMPTY:
ctx.in_object = []
# call user method
ctx.out_object = self.call_wrapper(ctx)
# out object is always a sequence of return values. see
# MethodContext docstrings for more info
if ctx.descriptor.body_style is not BODY_STYLE_WRAPPED or \
len(ctx.descriptor.out_message._type_info) <= 1:
# if it's not a wrapped method, OR there's just one return type
# we wrap it ourselves
ctx.out_object = [ctx.out_object]
# Now that the processing is switched to the outgoing message,
# point ctx.protocol to ctx.out_protocol
ctx.protocol = ctx.outprot_ctx
# fire events
self.event_manager.fire_event('method_return_object', ctx)
if ctx.service_class is not None:
ctx.service_class.event_manager.fire_event(
'method_return_object', ctx)
except Redirect as e:
try:
e.do_redirect()
ctx.out_object = [None]
# Now that the processing is switched to the outgoing message,
# point ctx.protocol to ctx.out_protocol
ctx.protocol = ctx.outprot_ctx
# fire events
self.event_manager.fire_event('method_redirect', ctx)
if ctx.service_class is not None:
ctx.service_class.event_manager.fire_event(
'method_redirect', ctx)
except Exception as e:
logger_server.exception(e)
ctx.out_error = Fault('Server',
get_fault_string_from_exception(e))
# fire events
self.event_manager.fire_event('method_redirect_exception', ctx)
if ctx.service_class is not None:
ctx.service_class.event_manager.fire_event(
'method_redirect_exception', ctx)
except Fault as e:
if e.faultcode == 'Client' or e.faultcode.startswith('Client.'):
logger_client.exception(e)
else:
logger.exception(e)
ctx.out_error = e
# fire events
self.event_manager.fire_event('method_exception_object', ctx)
if ctx.service_class is not None:
ctx.service_class.event_manager.fire_event(
'method_exception_object', ctx)
# we don't catch BaseException because we're not interested in
# "system-exiting" exceptions. See:
# https://docs.python.org/2/library/exceptions.html#exceptions.Exception
except Exception as e:
logger_server.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 is not None:
ctx.service_class.event_manager.fire_event(
'method_exception_object', ctx)
def call_wrapper(self, ctx):
"""This method calls the call_wrapper method in the service definition.
This can be overridden to make an application-wide custom exception
management.
"""
retval = None
# service rpc
if ctx.descriptor.no_self:
retval = ctx.descriptor.service_class.call_wrapper(ctx)
# class rpc
else:
cls = ctx.descriptor.parent_class
if cls.__orig__ is not None:
cls = cls.__orig__
inst = cls.__respawn__(ctx)
if inst is None:
raise RespawnError('{%s}%s' %
(cls.get_namespace(), cls.get_type_name()))
in_cls = ctx.descriptor.in_message
args = ctx.in_object
if args is None:
args = []
elif ctx.descriptor.body_style is BODY_STYLE_WRAPPED and \
len(in_cls.get_flat_type_info(in_cls)) <= 1:
args = []
else:
args = args[1:]
if ctx.descriptor.service_class is not None:
ctx.in_object = [inst, ctx]
ctx.in_object.extend(args)
# hack to make sure inst goes first
ctx.descriptor.no_ctx = True
retval = ctx.descriptor.service_class.call_wrapper(ctx)
elif ctx.function is not None:
if ctx.descriptor.no_ctx:
retval = ctx.function(inst, *args)
else:
retval = ctx.function(inst, ctx, *args)
return retval
def _has_callbacks(self):
return self.interface._has_callbacks()
def reinitialize(self, server):
"""This is normally called on transport instantiation by ServerBase"""
seen = set()
from spyne import MethodDescriptor
for d in self.interface.method_id_map.values():
assert isinstance(d, MethodDescriptor)
if d.aux is not None and not id(d.aux) in seen:
d.aux.initialize(server)
seen.add(id(d.aux))
if d.service_class is not None and not id(d.service_class) in seen:
d.service_class.initialize(server)
seen.add(id(d.service_class))
def __hash__(self):
return hash(tuple((id(s) for s in self.services)))
|