def import_services(self, service_list): # Fix that eliminates the need for exec() # contributed by: Tamás Gulácsi for service in service_list: m = __import__(service) sfile = inspect.getsourcefile(m) for skey, smi in global_service_collection().services.items(): for method_name, lmi in list(smi.methods.items()): task_rtype = getattr(lmi, '_task_rtype', None) if task_rtype != None: if skey[0] == sfile: cls = getattr(m, skey[1]) setattr(cls, "%s_progress" % method_name, tt.taskProgress) lmi.sinfo.add_method( tt.taskProgress, *(int, ), **dict( list(tt.taskProgress_kw.items()) + [('override_method_name', "%s_progress" % method_name)])) setattr(cls, "%s_result" % method_name, tt.taskResult) lmi.sinfo.add_method( tt.taskResult, *(int, ), **{ 'override_method_name': "%s_result" % method_name, 'rtype': task_rtype }) setattr( cls, "_task_%s" % method_name, copyFunction(getattr(cls, method_name), "_task_%s" % method_name)) setattr(cls, method_name, copyFunction(tt.taskStarter, method_name))
def NamedServiceView(service_name,interface,request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' service_search = global_service_collection().services_by_name(service_name) if not len(service_search): return getJSResponse(u'Service "%s" has not been exposed' % service_name) else: sinst = service_search[0] return ServiceInstanceView(request,sinst,interface)
def NamedServiceView(service_name, interface, request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' service_search = global_service_collection().services_by_name(service_name) if not len(service_search): return getJSResponse(u'Service "%s" has not been exposed' % service_name) else: sinst = service_search[0] return ServiceInstanceView(request, sinst, interface)
def NamedSoapView(service_name,request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' service_search = global_service_collection().services_by_name(service_name) if not len(service_search): return getJSResponse(u'Service "%s" has not been exposed' % service_name) else: sinst = service_search[0] service_info = generate_service(sinst) ex = DJANGO_MODEL and '_django' or '' return render_to_response('service_index%s.html'%ex, RequestContext(request,service_info))
def NamedSoapView(service_name, request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' service_search = global_service_collection().services_by_name(service_name) if not len(service_search): return getJSResponse(u'Service "%s" has not been exposed' % service_name) else: sinst = service_search[0] service_info = generate_service(sinst) ex = DJANGO_MODEL and '_django' or '' return render_to_response('service_index%s.html' % ex, RequestContext(request, service_info))
def decorator(f): def injector(*args,**kw): """ The Ladon inner injection function is called from the dispatcher. It does run-time type checking against the types registered with the service method. If everything is OK the user method is called. The result of the userspace-method is then checked before it is passed back to the dispatcher. """ # Get the LadonMethodInfo object generated at parsetime which is stored as a member # on the function object lmi = injector._ladon_method_info # Reference the incomming arguments in callargs (filter out the function reference) callargs = args[1:] for argidx in range(len(callargs)): # Check the type of each argument against the type which the method has been # registered to take in the order-wise corresponding argument if not validate_type(lmi._arg_types[argidx],callargs[argidx]): # Raise ArgTypeMismatch raise ArgTypeMismatch( lmi.sinfo, lmi._func_name, lmi._arg_names[argidx], lmi._arg_types[argidx], type(callargs[argidx])) # Call the userspace service method (**kw will be used to transport Ladon info # and tools all the way to userspace of the service method. I.e. the TypeConverter # is passed with the keyword "LADON_METHOD_TC") res = f(*args,**kw) # Check the return type if not validate_type(lmi._rtype,res): # Raise Arg-type mismatch raise ReturnTypeMismatch(lmi.sinfo,lmi._func_name,lmi._rtype,type(res)) # Return the result to the dispatcher return res # Register the service method and all the types required by it ladon_method_info = global_service_collection().add_service_method(f,*def_args,**def_kw) # store the LadonMethodInfo object directly on the fuction object injector._ladon_method_info = ladon_method_info injector.__doc__ = ladon_method_info._doc injector.func_name = ladon_method_info._func_name return injector
def decorator(f): def injector(*args, **kw): """ The Ladon inner injection function is called from the dispatcher. It does run-time type checking against the types registered with the service method. If everything is OK the user method is called. The result of the userspace-method is then checked before it is passed back to the dispatcher. """ # Get the LadonMethodInfo object generated at parsetime which is stored as a member # on the function object lmi = injector._ladon_method_info # Reference the incomming arguments in callargs (filter out the function reference) callargs = args[1:] for argidx in range(len(callargs)): # Check the type of each argument against the type which the method has been # registered to take in the order-wise corresponding argument if not validate_type(lmi._arg_types[argidx], callargs[argidx]): # Raise ArgTypeMismatch raise ArgTypeMismatch(lmi.sinfo, lmi._func_name, lmi._arg_names[argidx], lmi._arg_types[argidx], type(callargs[argidx])) # Call the userspace service method (**kw will be used to transport Ladon info # and tools all the way to userspace of the service method. I.e. the TypeConverter # is passed with the keyword "LADON_METHOD_TC") res = f(*args, **kw) # Check the return type if not validate_type(lmi._rtype, res): # Raise Arg-type mismatch raise ReturnTypeMismatch(lmi.sinfo, lmi._func_name, lmi._rtype, type(res)) # Return the result to the dispatcher return res # Register the service method and all the types required by it ladon_method_info = global_service_collection().add_service_method( f, *def_args, **def_kw) # store the LadonMethodInfo object directly on the fuction object injector._ladon_method_info = ladon_method_info injector.__doc__ = ladon_method_info._doc injector.func_name = ladon_method_info._func_name return injector
def ServiceList(request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' services = global_service_collection().services catalog_name = u"PyWebSV Web服务接口" catalog_desc = u'''1. 一个在python (Django或Mole) 环境下快速构建 webservice 的工具库<br><br> 2. 同时提供 SOAP 和 JSON 的支持,前端即可通过JS来调用,JSON调用<a href='/rpc_static/demo1.jpg'>Demo</a>,SOAP调用<a href='/rpc_static/demo2.jpg'>Demo</a><br><br> 3. 打开调试模式即可在线在web界面调用接口方法 ( 通过js走Json通道 )<br><br> ''' catalog_info = { 'catalog_name': catalog_name, 'catalog_desc': catalog_desc, 'charset': 'utf-8', 'services': services.values() } ex = DJANGO_MODEL and '_django' or '' return render_to_response('service_list%s.html'%ex, RequestContext(request,catalog_info))
def ServiceList(request=request): from ladon.ladonizer.collection import global_service_collection '''获取请求的service实例''' services = global_service_collection().services catalog_name = u"PyWebSV Web服务接口" catalog_desc = u'''1. 一个在python (Django或Mole) 环境下快速构建 webservice 的工具库<br><br> 2. 同时提供 SOAP 和 JSON 的支持,前端即可通过JS来调用,JSON调用<a href='/rpc_static/demo1.jpg'>Demo</a>,SOAP调用<a href='/rpc_static/demo2.jpg'>Demo</a><br><br> 3. 打开调试模式即可在线在web界面调用接口方法 ( 通过js走Json通道 )<br><br> ''' catalog_info = { 'catalog_name': catalog_name, 'catalog_desc': catalog_desc, 'charset': 'utf-8', 'services': services.values() } ex = DJANGO_MODEL and '_django' or '' return render_to_response('service_list%s.html' % ex, RequestContext(request, catalog_info))
def __call__(self, environ, start_response): status = '200 OK' response_headers = [] content_type = 'text/plain' output = '' charset = probe_charset(environ, default='UTF-8') languages = probe_language(environ, default=['en']) try: fault_hint = 'Processing request (further details)' sname, ifname, action, multipart, boundary = self.parse_environ( environ) client_path = probe_client_path(environ) query = parse_qs(environ['QUERY_STRING']) if sname in self.reserved_roots: fault_hint = 'Attempting to fetch server-side static skin-data at location: "%s"' % environ[ 'PATH_INFO'] if sname == 'skins': data = read_data_file(start_response, environ['PATH_INFO'], self.path_list) return [data] sinst = ifclass = None if ifname: fault_hint = 'Searching for the interface called "%s"' % ifname ifclass = name_to_interface(ifname) if not ifclass: raise UndefinedInterfaceName( ifname, 'The interface name "%s" has not been defined' % ifname) if sname: fault_hint = 'Searching for the service-class: "%s"' % sname service_search = global_service_collection().services_by_name( sname) if not len(service_search): raise UndefinedService( ifname, 'Service "%s" has not been exposed' % sname) sinst = service_search[0] dispatcher = None if sinst and ifclass: fault_hint = 'Instantiating dispatcher for "%s"' % sname dispatcher = Dispatcher(sinst, ifclass, charset, languages, self.logging) elif not sname: fault_hint = 'Generating service catalog' content_type = 'text/html' skin = query.get('skin', [None])[0] output = self.generate_catalog_html( global_service_collection().services, client_path, self.catalog_name, self.catalog_desc, charset, languages, skin) elif sinst and not ifname: fault_hint = 'Generating service API HTML for "%s"' % sname content_type = 'text/html' skin = query.get('skin', [None])[0] output = self.generate_service_html(sinst, client_path, charset, languages, skin) if dispatcher and dispatcher.iface: if action == 'description': fault_hint = 'Generating "%s" description for "%s"' % ( ifname, sname) content_type = dispatcher.iface.description_content_type() service_url = client_path[0:client_path.find('/description' )] output += dispatcher.iface.description( service_url, charset, **dict(map(lambda x: (x[0], x[1][0]), query.items()))) else: fault_hint = 'Checking method call request via "%s" on "%s"' % ( ifname, sname) allowed_methods = ['POST'] if environ[ 'REQUEST_METHOD'] not in allowed_methods or not environ.get( 'CONTENT_LENGTH', ''): message = 'Requests for %s %s interface must be posted' % ( sname, ifname) status = '405 %s' % message response_headers.append( ('Allow', ','.join(allowed_methods))) output += message else: fault_hint = 'Preparing "%s" call to "%s"' % (ifname, sname) content_type = dispatcher.iface.response_content_type() content_length = int(environ['CONTENT_LENGTH']) if multipart and boundary: fault_hint = 'Parsing incoming multipart request and attachments' mph = MultiPartReader(20000, boundary.encode(charset), environ['wsgi.input'], content_length) mph.read_chunk() while not mph.eos: mph.read_chunk() encapsulated_charset = probe_charset( mph.interface_request_headers, default=None) request_data = mph.interface_request if encapsulated_charset: # If a specific charset is/usr/local/bin/rdesktop specified for the interface request multipart # let this charset superseed the charset globally specified for the request. dispatcher.response_encoding = encapsulated_charset environ['attachments'] = mph.attachments environ[ 'attachments_by_id'] = mph.attachments_by_id else: request_data = environ['wsgi.input'].read( content_length) fault_hint = 'Passing request on to the dispatcher' response_part = dispatcher.dispatch_request( request_data, environ) if isinstance(response_part, CustomResponse): response_headers += response_part.response_headers( ) start_response(status, response_headers) return response_part.response_data() elif len(environ['response_attachments']. attachments_by_cid): # Attachments present - Send multipart response response_temp_fname = tempfile.mktemp() temp_buffer = open(response_temp_fname, 'wb') mpw = MultiPartWriter(temp_buffer, header_encoding=charset) mpw.add_attachment( response_part, '%s, charset=%s' % (content_type, charset), 'rpc-part') for cid, a in environ[ 'response_attachments'].attachments_by_cid.items( ): mpw.add_attachment(a, 'application/octet-stream', cid, a.headers) mpw.done() temp_buffer.close() content_length = str( os.stat(response_temp_fname).st_size) output = open(response_temp_fname, 'rb') if sys.version_info[0] == 2: content_type = "multipart/related; boundary=" + mpw.boundary elif sys.version_info[0] >= 3: content_type = "multipart/related; boundary=" + str( mpw.boundary, 'iso-8859-1') else: # No attachments - Send normal response output = response_part if 'attachments' in environ: for a_id, a_info in environ['attachments'].items(): if os.path.exists(a_info['path']): os.unlink(a_info['path']) except Exception as e: status = '500 An Error occured while processing the request' content_type = 'text/plain' strio = StringIO() traceback.print_exc(file=strio) output = strio.getvalue() output += "\nHint: " + fault_hint if not hasattr(output, 'read'): # not file-like object content_length = str(len(output)) response_headers += [('Content-Type', "%s; charset=%s" % (content_type, charset)), ('Content-Length', content_length)] start_response(status, response_headers) if hasattr(output, 'read'): # File-like object block_size = 4096 if 'wsgi.file_wrapper' in environ: return environ['wsgi.file_wrapper'](output, block_size) else: return iter(lambda: output.read(block_size), '') if sys.version_info[0] >= 3: # Python 3 support if type(output) == str: output = bytes(output, charset) return [output]
def __call__(self,environ, start_response): ''' wsgi 应用执行 ''' status = '200 OK' response_headers = [] content_type = 'text/plain' output = '' charset = probe_charset(environ,default='UTF-8') try: self.import_services(self.service_list) ''' 得到客户端请求的信息 ''' sname,ifname,action,multipart,boundary = self.parse_environ(environ) client_path = probe_client_path(environ) print 'Jone@-------',sname,ifname,action,multipart,boundary print 'Jone@-------',client_path sinst = ifclass = None if ifname: '''检验请求的协议是否合法 soap/jsonwsp''' ifclass = name_to_interface(ifname) if not ifclass: raise UndefinedInterfaceName(ifname,'The interface name "%s" has not been defined' % ifname) if sname: '''获取请求的service实例''' service_search = global_service_collection().services_by_name(sname) if not len(service_search): raise UndefinedService(ifname,'Service "%s" has not been exposed' % sname) sinst = service_search[0] '''{'doc_lines': ['This service does the math, and serves as example for new potential Ladon users.'], 'methods': {'add': <ladon.ladonizer.collection.LadonMethodInfo object at 0x01069EB0>}, 'servicename': 'Calculator', 'sourcefile': 'E:\\open-source\\ladon-0.7.0\\jone_demo\\examples\\services\\calculator.py'}''' dispatcher = None if sinst and ifclass: dispatcher = Dispatcher(sinst,ifclass,charset) elif not sname: ''' 首页''' content_type = 'text/html' output = self.generate_catalog_html( global_service_collection().services, client_path, self.catalog_name, self.catalog_desc,charset) elif sinst and not ifname: '''service 实例首页''' content_type = 'text/html' query = parse_qs(urlparse(client_path).query) skin = query.get('skin', [None])[0] output = self.generate_service_html(sinst,client_path,charset,skin) if dispatcher and dispatcher.iface: if action=='description': content_type = dispatcher.iface.description_content_type() service_url = client_path[0:client_path.find('/description')] output += dispatcher.iface.description(service_url,charset) else: allowed_methods = ['POST'] if environ['REQUEST_METHOD'] not in allowed_methods or not environ.get('CONTENT_LENGTH', ''): message = 'Requests for %s %s interface must be posted' % (sname,ifname) status = '405 %s' % message response_headers.append(('Allow', ','.join(allowed_methods))) output += message else: content_type = dispatcher.iface.response_content_type() content_length = int(environ['CONTENT_LENGTH']) if multipart and boundary: mph = MultiPartReader(20000,boundary.encode(charset),environ['wsgi.input'],content_length) mph.read_chunk() while not mph.eos: mph.read_chunk() encapsulated_charset = probe_charset(mph.interface_request_headers,default=None) request_data = mph.interface_request if encapsulated_charset: # If a specific charset is/usr/local/bin/rdesktop specified for the interface request multipart # let this charset superseed the charset globally specified for the request. dispatcher.response_encoding = encapsulated_charset environ['attachments'] = mph.attachments environ['attachments_by_id'] = mph.attachments_by_id else: request_data = environ['wsgi.input'].read(content_length) response_part = dispatcher.dispatch_request(request_data,environ) if isinstance(response_part,CustomResponse): print 'AAAAAAAAAAAAAAA' response_headers += response_part.response_headers() start_response(status, response_headers) return response_part.response_data() elif len(environ['response_attachments'].attachments_by_cid): print 'BBBBBBBBBBBBBBB' # Attachments present - Send multipart response response_temp_fname = tempfile.mktemp() temp_buffer = open(response_temp_fname,'wb') mpw = MultiPartWriter(temp_buffer) mpw.add_attachment(response_part,'%s, charset=%s' % (content_type,charset),'rpc-part') for cid,a in environ['response_attachments'].attachments_by_cid.items(): mpw.add_attachment(a,'application/octet-stram',cid,a.headers) mpw.done() temp_buffer.close() content_length = str(os.stat(response_temp_fname).st_size) output = open(response_temp_fname,'rb') if sys.version_info[0]==2: content_type = "multipart/related; boundary=" + mpw.boundary elif sys.version_info[0]>=3: content_type = "multipart/related; boundary=" + str(mpw.boundary,'iso-8859-1') else: print 'CCCCCCCCCCCCCCCCCCC' # No attachments - Send normal response output = response_part except Exception as e: status = '500 An Error occured while processing the request' content_type = 'text/plain' strio = StringIO() traceback.print_exc(file=strio) output = strio.getvalue() if 'attachments_by_id' in environ: for a_id,a_info in environ['attachments_by_id'].items(): os.unlink(a_info['path']) if not hasattr(output,'read'): # not file-like object content_length = str(len(output)) response_headers += [ ('Content-Type', "%s; charset=%s" % (content_type,charset)), ('Content-Length', content_length) ] start_response(status, response_headers) if hasattr(output,'read'): # File-like object block_size = 4096 if 'wsgi.file_wrapper' in environ: return environ['wsgi.file_wrapper'](output, block_size) else: return iter(lambda: output.read(block_size), '') if sys.version_info[0]>=3: # Python 3 support if type(output)==str: output = bytes(output,charset) return [output]
def __call__(self, environ, start_response): ''' wsgi 应用执行 ''' status = '200 OK' response_headers = [] content_type = 'text/plain' output = '' charset = probe_charset(environ, default='UTF-8') try: self.import_services(self.service_list) ''' 得到客户端请求的信息 ''' sname, ifname, action, multipart, boundary = self.parse_environ( environ) client_path = probe_client_path(environ) print 'Jone@-------', sname, ifname, action, multipart, boundary print 'Jone@-------', client_path sinst = ifclass = None if ifname: '''检验请求的协议是否合法 soap/jsonwsp''' ifclass = name_to_interface(ifname) if not ifclass: raise UndefinedInterfaceName( ifname, 'The interface name "%s" has not been defined' % ifname) if sname: '''获取请求的service实例''' service_search = global_service_collection().services_by_name( sname) if not len(service_search): raise UndefinedService( ifname, 'Service "%s" has not been exposed' % sname) sinst = service_search[0] '''{'doc_lines': ['This service does the math, and serves as example for new potential Ladon users.'], 'methods': {'add': <ladon.ladonizer.collection.LadonMethodInfo object at 0x01069EB0>}, 'servicename': 'Calculator', 'sourcefile': 'E:\\open-source\\ladon-0.7.0\\jone_demo\\examples\\services\\calculator.py'}''' dispatcher = None if sinst and ifclass: dispatcher = Dispatcher(sinst, ifclass, charset) elif not sname: ''' 首页''' content_type = 'text/html' output = self.generate_catalog_html( global_service_collection().services, client_path, self.catalog_name, self.catalog_desc, charset) elif sinst and not ifname: '''service 实例首页''' content_type = 'text/html' query = parse_qs(urlparse(client_path).query) skin = query.get('skin', [None])[0] output = self.generate_service_html(sinst, client_path, charset, skin) if dispatcher and dispatcher.iface: if action == 'description': content_type = dispatcher.iface.description_content_type() service_url = client_path[0:client_path.find('/description' )] output += dispatcher.iface.description( service_url, charset) else: allowed_methods = ['POST'] if environ[ 'REQUEST_METHOD'] not in allowed_methods or not environ.get( 'CONTENT_LENGTH', ''): message = 'Requests for %s %s interface must be posted' % ( sname, ifname) status = '405 %s' % message response_headers.append( ('Allow', ','.join(allowed_methods))) output += message else: content_type = dispatcher.iface.response_content_type() content_length = int(environ['CONTENT_LENGTH']) if multipart and boundary: mph = MultiPartReader(20000, boundary.encode(charset), environ['wsgi.input'], content_length) mph.read_chunk() while not mph.eos: mph.read_chunk() encapsulated_charset = probe_charset( mph.interface_request_headers, default=None) request_data = mph.interface_request if encapsulated_charset: # If a specific charset is/usr/local/bin/rdesktop specified for the interface request multipart # let this charset superseed the charset globally specified for the request. dispatcher.response_encoding = encapsulated_charset environ['attachments'] = mph.attachments environ[ 'attachments_by_id'] = mph.attachments_by_id else: request_data = environ['wsgi.input'].read( content_length) response_part = dispatcher.dispatch_request( request_data, environ) if isinstance(response_part, CustomResponse): print 'AAAAAAAAAAAAAAA' response_headers += response_part.response_headers( ) start_response(status, response_headers) return response_part.response_data() elif len(environ['response_attachments']. attachments_by_cid): print 'BBBBBBBBBBBBBBB' # Attachments present - Send multipart response response_temp_fname = tempfile.mktemp() temp_buffer = open(response_temp_fname, 'wb') mpw = MultiPartWriter(temp_buffer) mpw.add_attachment( response_part, '%s, charset=%s' % (content_type, charset), 'rpc-part') for cid, a in environ[ 'response_attachments'].attachments_by_cid.items( ): mpw.add_attachment(a, 'application/octet-stram', cid, a.headers) mpw.done() temp_buffer.close() content_length = str( os.stat(response_temp_fname).st_size) output = open(response_temp_fname, 'rb') if sys.version_info[0] == 2: content_type = "multipart/related; boundary=" + mpw.boundary elif sys.version_info[0] >= 3: content_type = "multipart/related; boundary=" + str( mpw.boundary, 'iso-8859-1') else: print 'CCCCCCCCCCCCCCCCCCC' # No attachments - Send normal response output = response_part except Exception as e: status = '500 An Error occured while processing the request' content_type = 'text/plain' strio = StringIO() traceback.print_exc(file=strio) output = strio.getvalue() if 'attachments_by_id' in environ: for a_id, a_info in environ['attachments_by_id'].items(): os.unlink(a_info['path']) if not hasattr(output, 'read'): # not file-like object content_length = str(len(output)) response_headers += [('Content-Type', "%s; charset=%s" % (content_type, charset)), ('Content-Length', content_length)] start_response(status, response_headers) if hasattr(output, 'read'): # File-like object block_size = 4096 if 'wsgi.file_wrapper' in environ: return environ['wsgi.file_wrapper'](output, block_size) else: return iter(lambda: output.read(block_size), '') if sys.version_info[0] >= 3: # Python 3 support if type(output) == str: output = bytes(output, charset) return [output]
def decorator(f): def injector(*args, **kw): """ The Ladon inner injection function is called from the dispatcher. It does run-time type checking against the types registered with the service method. If everything is OK the user method is called. The result of the userspace-method is then checked before it is passed back to the dispatcher. """ if def_kw.get('tasktype', False) == True: return f(*args, **kw) # Get the LadonMethodInfo object generated at parsetime which is stored as a member # on the function object lmi = injector._ladon_method_info # Reference the incomming arguments in callargs (filter out the function reference) callargs = args[1:] for argidx in range(len(callargs)): # Check the type of each argument against the type which the method has been # registered to take in the order-wise corresponding argument if not validate_type(lmi._arg_types[argidx], callargs[argidx]): # Raise ArgTypeMismatch raise ArgTypeMismatch(lmi.sinfo, lmi._func_name, lmi._arg_names[argidx], lmi._arg_types[argidx], type(callargs[argidx])) # Call the userspace service method (**kw will be used to transport Ladon info # and tools all the way to userspace of the service method. I.e. the TypeConverter # is passed with the keyword "LADON_METHOD_TC") debug_mode = log.get_loglevel() >= 6 if debug_mode: # Build a request_dict for debugging req_dict = {} for argidx in range(len(callargs)): req_dict[lmi._arg_names[argidx]] = expand_value( callargs[argidx], lmi._arg_types[argidx], service_name=lmi.sinfo.servicename, method_name=lmi._func_name) log_line = [ 'Method:%s.%s' % (lmi.sinfo.servicename, lmi._func_name), 'RequestArgs:%s' % str(req_dict), 'RequestKeywordArgs:%s' % str(kw) ] if debug_mode: try: start = time.time() res = f(*args, **kw) log_line.insert( 0, 'ExecutionTime:%s' % str(time.time() - start)) except Exception as e: log_line += ['Exception:%s' % str((log.get_traceback(), ))] log.debug('\t%s' % ('\t'.join(log_line))) raise e log_line += ['ReturnValue:%s' % str(result_to_dict(lmi, res))] log.debug('\t%s' % ('\t'.join(log_line))) else: res = f(*args, **kw) # Check the return type if not validate_type(lmi._rtype, res): # Raise Arg-type mismatch raise ReturnTypeMismatch(lmi.sinfo, lmi._func_name, lmi._rtype, type(res)) # Return the result to the dispatcher return res # Register the service method and all the types required by it ladon_method_info = global_service_collection().add_service_method( f, *def_args, **def_kw) # store the LadonMethodInfo object directly on the fuction object injector._ladon_method_info = ladon_method_info injector.__doc__ = ladon_method_info._doc injector.func_name = ladon_method_info._func_name return injector