The decorators now wrap the exposed function so that children classes can expose the parent functions with different signatures

This commit is contained in:
Christophe de Vienne
2011-10-27 20:00:05 +02:00
parent ebd9a27e48
commit a05ff59e33
2 changed files with 42 additions and 11 deletions

View File

@@ -72,6 +72,32 @@ class FunctionArgument(object):
self.default = default
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
return newfunc
def isfuncproxy(func):
"""
Returns True if ``func`` is already a function proxy.
"""
return getattr(func, '_is_wsme_funcproxy', False)
class FunctionDefinition(object):
"""
An api entry definition
@@ -105,11 +131,12 @@ class FunctionDefinition(object):
"""
Returns the :class:`FunctionDefinition` of a method.
"""
fd = getattr(func, '_wsme_definition', None)
if fd is None:
if not isfuncproxy(func):
fd = FunctionDefinition(func)
func = funcproxy(func)
func._wsme_definition = fd
return fd
return func, func._wsme_definition
def get_arg(self, name):
"""
@@ -157,7 +184,9 @@ class expose(object):
register_type(return_type)
def __call__(self, func):
fd = FunctionDefinition.get(func)
func, fd = FunctionDefinition.get(func)
if fd.return_type is not None:
raise ValueError("This function is already exposed")
fd.return_type = self.return_type
fd.extra_options = self.options
return func
@@ -170,7 +199,7 @@ class pexpose(object):
register_type(return_type)
def __call__(self, func):
fd = FunctionDefinition.get(func)
func, fd = FunctionDefinition.get(func)
fd.return_type = self.return_type
fd.protocol_specific = True
fd.contenttype = self.contenttype
@@ -194,8 +223,9 @@ class validate(object):
self.param_types = param_types
def __call__(self, func):
fd = FunctionDefinition.get(func)
args, varargs, keywords, defaults = inspect.getargspec(func)
func, fd = FunctionDefinition.get(func)
args, varargs, keywords, defaults = inspect.getargspec(
func._original_func)
if args[0] == 'self':
args = args[1:]
for i, argname in enumerate(args):
@@ -289,7 +319,7 @@ class WSRoot(object):
raise exc.ClientSideError(
u'The %s protocol was unable to extract a function '
u'path from the request' % protocol.name)
context.func, context.funcdef = self._lookup_function(context.path)
kw = protocol.read_arguments(context)

View File

@@ -63,9 +63,10 @@ def test_pexpose():
def ufunc(self):
return u"<p>é</p>"
assert FunctionDefinition.get(Proto.func).return_type is None
assert FunctionDefinition.get(Proto.func).protocol_specific
assert FunctionDefinition.get(Proto.func).contenttype == "text/xml"
func, fd = FunctionDefinition.get(Proto.func)
assert fd.return_type is None
assert fd.protocol_specific
assert fd.contenttype == "text/xml"
p = Proto()
r = WSRoot()