merge
This commit is contained in:
commit
31b5e0d23d
@ -1,7 +1,8 @@
|
|||||||
from wsme.api import expose, validate
|
from wsme.api import sig, expose, validate
|
||||||
from wsme.root import WSRoot
|
from wsme.root import WSRoot
|
||||||
from wsme.types import wsattr, wsproperty, Unset
|
from wsme.types import wsattr, wsproperty, Unset
|
||||||
|
|
||||||
__all__ = ['expose', 'validate',
|
__all__ = [
|
||||||
|
'expose', 'validate', 'sig',
|
||||||
'WSRoot',
|
'WSRoot',
|
||||||
'wsattr', 'wsproperty', 'Unset']
|
'wsattr', 'wsproperty', 'Unset']
|
||||||
|
69
wsme/api.py
69
wsme/api.py
@ -26,6 +26,10 @@ def scan_api(controller, path=[]):
|
|||||||
yield i
|
yield i
|
||||||
|
|
||||||
|
|
||||||
|
def iswsmefunction(f):
|
||||||
|
return hasattr(f, '_wsme_definition')
|
||||||
|
|
||||||
|
|
||||||
class FunctionArgument(object):
|
class FunctionArgument(object):
|
||||||
"""
|
"""
|
||||||
An argument definition of an api entry
|
An argument definition of an api entry
|
||||||
@ -47,34 +51,6 @@ class FunctionArgument(object):
|
|||||||
self.datatype = registry.resolve_type(self.datatype)
|
self.datatype = registry.resolve_type(self.datatype)
|
||||||
|
|
||||||
|
|
||||||
def funcproxy(func):
|
|
||||||
"""
|
|
||||||
A very simple wrapper for exposed function.
|
|
||||||
|
|
||||||
It will carry the FunctionDefinition in place of the
|
|
||||||
decorared function so that a same function can be exposed
|
|
||||||
several times (for example a parent function can be exposed
|
|
||||||
in different ways in the children classes).
|
|
||||||
|
|
||||||
The returned function also carry a ``_original_func`` attribute
|
|
||||||
so that it can be inspected if needed.
|
|
||||||
"""
|
|
||||||
def newfunc(*args, **kw):
|
|
||||||
return func(*args, **kw)
|
|
||||||
newfunc._is_wsme_funcproxy = True
|
|
||||||
newfunc._original_func = func
|
|
||||||
newfunc.__doc__ = func.__doc__
|
|
||||||
newfunc.__name__ = func.__name__
|
|
||||||
return newfunc
|
|
||||||
|
|
||||||
|
|
||||||
def isfuncproxy(func):
|
|
||||||
"""
|
|
||||||
Returns True if ``func`` is already a function proxy.
|
|
||||||
"""
|
|
||||||
return getattr(func, '_is_wsme_funcproxy', False)
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionDefinition(object):
|
class FunctionDefinition(object):
|
||||||
"""
|
"""
|
||||||
An api entry definition
|
An api entry definition
|
||||||
@ -92,6 +68,9 @@ class FunctionDefinition(object):
|
|||||||
#: The function arguments (list of :class:`FunctionArgument`)
|
#: The function arguments (list of :class:`FunctionArgument`)
|
||||||
self.arguments = []
|
self.arguments = []
|
||||||
|
|
||||||
|
#: If the body carry the datas of a single argument, its type
|
||||||
|
self.body_type = None
|
||||||
|
|
||||||
#: True if this function is exposed by a protocol and not in
|
#: True if this function is exposed by a protocol and not in
|
||||||
#: the api tree, which means it is not part of the api.
|
#: the api tree, which means it is not part of the api.
|
||||||
self.protocol_specific = False
|
self.protocol_specific = False
|
||||||
@ -108,12 +87,11 @@ class FunctionDefinition(object):
|
|||||||
"""
|
"""
|
||||||
Returns the :class:`FunctionDefinition` of a method.
|
Returns the :class:`FunctionDefinition` of a method.
|
||||||
"""
|
"""
|
||||||
if not isfuncproxy(func):
|
if not hasattr(func, '_wsme_definition'):
|
||||||
fd = FunctionDefinition(func)
|
fd = FunctionDefinition(func)
|
||||||
func = funcproxy(func)
|
|
||||||
func._wsme_definition = fd
|
func._wsme_definition = fd
|
||||||
|
|
||||||
return func, func._wsme_definition
|
return func._wsme_definition
|
||||||
|
|
||||||
def get_arg(self, name):
|
def get_arg(self, name):
|
||||||
"""
|
"""
|
||||||
@ -143,26 +121,39 @@ class expose(object):
|
|||||||
def getint(self):
|
def getint(self):
|
||||||
return 1
|
return 1
|
||||||
"""
|
"""
|
||||||
def __init__(self, return_type=None, **options):
|
def __init__(self, return_type=None, body=None, **options):
|
||||||
self.return_type = return_type
|
self.return_type = return_type
|
||||||
|
self.body_type = body
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
func, fd = FunctionDefinition.get(func)
|
fd = FunctionDefinition.get(func)
|
||||||
if fd.extra_options is not None:
|
if fd.extra_options is not None:
|
||||||
raise ValueError("This function is already exposed")
|
raise ValueError("This function is already exposed")
|
||||||
fd.return_type = self.return_type
|
fd.return_type = self.return_type
|
||||||
|
fd.body_type = self.body_type
|
||||||
fd.extra_options = self.options
|
fd.extra_options = self.options
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
||||||
|
class sig(object):
|
||||||
|
def __init__(self, return_type, *param_types, **options):
|
||||||
|
self.expose = expose(return_type, **options)
|
||||||
|
self.validate = validate(*param_types)
|
||||||
|
|
||||||
|
def __call__(self, func):
|
||||||
|
func = self.expose(func)
|
||||||
|
func = self.validate(func)
|
||||||
|
return func
|
||||||
|
|
||||||
|
|
||||||
class pexpose(object):
|
class pexpose(object):
|
||||||
def __init__(self, return_type=None, contenttype=None):
|
def __init__(self, return_type=None, contenttype=None):
|
||||||
self.return_type = return_type
|
self.return_type = return_type
|
||||||
self.contenttype = contenttype
|
self.contenttype = contenttype
|
||||||
|
|
||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
func, fd = FunctionDefinition.get(func)
|
fd = FunctionDefinition.get(func)
|
||||||
fd.return_type = self.return_type
|
fd.return_type = self.return_type
|
||||||
fd.protocol_specific = True
|
fd.protocol_specific = True
|
||||||
fd.contenttype = self.contenttype
|
fd.contenttype = self.contenttype
|
||||||
@ -186,13 +177,15 @@ class validate(object):
|
|||||||
self.param_types = param_types
|
self.param_types = param_types
|
||||||
|
|
||||||
def __call__(self, func):
|
def __call__(self, func):
|
||||||
func, fd = FunctionDefinition.get(func)
|
fd = FunctionDefinition.get(func)
|
||||||
args, varargs, keywords, defaults = inspect.getargspec(
|
args, varargs, keywords, defaults = inspect.getargspec(func)
|
||||||
func._original_func)
|
|
||||||
if args[0] == 'self':
|
if args[0] == 'self':
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
|
param_types = list(self.param_types)
|
||||||
|
if fd.body_type is not None:
|
||||||
|
param_types.append(fd.body_type)
|
||||||
for i, argname in enumerate(args):
|
for i, argname in enumerate(args):
|
||||||
datatype = self.param_types[i]
|
datatype = param_types[i]
|
||||||
mandatory = defaults is None or i < (len(args) - len(defaults))
|
mandatory = defaults is None or i < (len(args) - len(defaults))
|
||||||
default = None
|
default = None
|
||||||
if not mandatory:
|
if not mandatory:
|
||||||
|
76
wsme/pecan.py
Normal file
76
wsme/pecan.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import inspect
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import xml.etree.ElementTree as et
|
||||||
|
|
||||||
|
import wsme
|
||||||
|
import wsme.protocols.commons
|
||||||
|
import wsme.protocols.restjson
|
||||||
|
import wsme.protocols.restxml
|
||||||
|
|
||||||
|
pecan = sys.modules['pecan']
|
||||||
|
|
||||||
|
|
||||||
|
class JSonRenderer(object):
|
||||||
|
def __init__(self, path, extra_vars):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def render(self, template_path, namespace):
|
||||||
|
data = wsme.protocols.restjson.tojson(
|
||||||
|
namespace['datatype'],
|
||||||
|
namespace['result']
|
||||||
|
)
|
||||||
|
return json.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
|
class XMLRenderer(object):
|
||||||
|
def __init__(self, path, extra_vars):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def render(self, template_path, namespace):
|
||||||
|
data = wsme.protocols.restxml.toxml(
|
||||||
|
namespace['datatype'],
|
||||||
|
'result',
|
||||||
|
namespace['result']
|
||||||
|
)
|
||||||
|
return et.tostring(data)
|
||||||
|
|
||||||
|
pecan.templating._builtin_renderers['wsmejson'] = JSonRenderer
|
||||||
|
pecan.templating._builtin_renderers['wsmexml'] = XMLRenderer
|
||||||
|
|
||||||
|
|
||||||
|
def wsexpose(*args, **kwargs):
|
||||||
|
pecan_json_decorate = pecan.expose(
|
||||||
|
template='wsmejson:',
|
||||||
|
content_type='application/json',
|
||||||
|
generic=False)
|
||||||
|
pecan_xml_decorate = pecan.expose(
|
||||||
|
template='wsmexml:',
|
||||||
|
content_type='application/xml',
|
||||||
|
generic=False
|
||||||
|
)
|
||||||
|
sig = wsme.sig(*args, **kwargs)
|
||||||
|
|
||||||
|
def decorate(f):
|
||||||
|
sig(f)
|
||||||
|
funcdef = wsme.api.FunctionDefinition.get(f)
|
||||||
|
|
||||||
|
def callfunction(self, *args, **kwargs):
|
||||||
|
args, kwargs = wsme.protocols.commons.get_args(
|
||||||
|
funcdef, args, kwargs,
|
||||||
|
pecan.request.body, pecan.request.content_type
|
||||||
|
)
|
||||||
|
result = f(self, *args, **kwargs)
|
||||||
|
return dict(
|
||||||
|
datatype=funcdef.return_type,
|
||||||
|
result=result
|
||||||
|
)
|
||||||
|
|
||||||
|
pecan_json_decorate(callfunction)
|
||||||
|
pecan_xml_decorate(callfunction)
|
||||||
|
pecan.util._cfg(callfunction)['argspec'] = inspect.getargspec(f)
|
||||||
|
return callfunction
|
||||||
|
|
||||||
|
return decorate
|
@ -8,7 +8,6 @@ from wsme.types import iscomplex, list_attributes, Unset
|
|||||||
from wsme.types import UserType, ArrayType, DictType, File
|
from wsme.types import UserType, ArrayType, DictType, File
|
||||||
from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime
|
from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime
|
||||||
|
|
||||||
|
|
||||||
ARRAY_MAX_SIZE = 1000
|
ARRAY_MAX_SIZE = 1000
|
||||||
|
|
||||||
|
|
||||||
@ -112,3 +111,35 @@ def dict_from_params(datatype, params, path, hit_paths):
|
|||||||
(key, from_params(datatype.value_type,
|
(key, from_params(datatype.value_type,
|
||||||
params, '%s[%s]' % (path, key), hit_paths))
|
params, '%s[%s]' % (path, key), hit_paths))
|
||||||
for key in keys))
|
for key in keys))
|
||||||
|
|
||||||
|
|
||||||
|
def get_args(funcdef, args, kwargs, body, mimetype):
|
||||||
|
from wsme.protocols import restjson
|
||||||
|
from wsme.protocols import restxml
|
||||||
|
|
||||||
|
newargs = []
|
||||||
|
for argdef, arg in zip(funcdef.arguments[:len(args)], args):
|
||||||
|
newargs.append(from_param(argdef.datatype, arg))
|
||||||
|
newkwargs = {}
|
||||||
|
for argname, value in kwargs.items():
|
||||||
|
newkwargs[argname] = from_param(funcdef.get_arg(argname), value)
|
||||||
|
if funcdef.body_type is not None:
|
||||||
|
bodydata = None
|
||||||
|
if mimetype in restjson.RestJsonProtocol.content_types:
|
||||||
|
if hasattr(body, 'read'):
|
||||||
|
jsonbody = restjson.json.load(body)
|
||||||
|
else:
|
||||||
|
jsonbody = restjson.json.loads(body)
|
||||||
|
bodydata = restjson.fromjson(funcdef.body_type, jsonbody)
|
||||||
|
elif mimetype in restxml.RestXmlProtocol.content_types:
|
||||||
|
if hasattr(body, 'read'):
|
||||||
|
xmlbody = restxml.et.parse(body)
|
||||||
|
else:
|
||||||
|
xmlbody = restxml.et.fromstring(body)
|
||||||
|
bodydata = restxml.fromxml(funcdef.body_type, xmlbody)
|
||||||
|
if bodydata:
|
||||||
|
if len(newargs) < len(funcdef.arguments):
|
||||||
|
newkwargs[funcdef.arguments[-1].name] = bodydata
|
||||||
|
else:
|
||||||
|
newargs[-1] = bodydata
|
||||||
|
return newargs, newkwargs
|
||||||
|
@ -314,13 +314,12 @@ class FunctionDocumenter(autodoc.MethodDocumenter):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def can_document_member(cls, member, membername, isattr, parent):
|
def can_document_member(cls, member, membername, isattr, parent):
|
||||||
return isinstance(parent, ServiceDocumenter) \
|
return isinstance(parent, ServiceDocumenter) \
|
||||||
and wsme.api.isfuncproxy(member)
|
and wsme.api.iswsmefunction(member)
|
||||||
|
|
||||||
def import_object(self):
|
def import_object(self):
|
||||||
ret = super(FunctionDocumenter, self).import_object()
|
ret = super(FunctionDocumenter, self).import_object()
|
||||||
self.directivetype = 'function'
|
self.directivetype = 'function'
|
||||||
self.object, self.wsme_fd = \
|
self.wsme_fd = wsme.api.FunctionDefinition.get(self.object)
|
||||||
wsme.api.FunctionDefinition.get(self.object)
|
|
||||||
self.retann = self.wsme_fd.return_type.__name__
|
self.retann = self.wsme_fd.return_type.__name__
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ def test_pexpose():
|
|||||||
def ufunc(self):
|
def ufunc(self):
|
||||||
return u("<p>\xc3\xa9</p>")
|
return u("<p>\xc3\xa9</p>")
|
||||||
|
|
||||||
func, fd = FunctionDefinition.get(Proto.func)
|
fd = FunctionDefinition.get(Proto.func)
|
||||||
assert fd.return_type is None
|
assert fd.return_type is None
|
||||||
assert fd.protocol_specific
|
assert fd.protocol_specific
|
||||||
assert fd.contenttype == "text/xml"
|
assert fd.contenttype == "text/xml"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user