diff --git a/README.rst b/README.rst index 82ddda0..da20cc3 100644 --- a/README.rst +++ b/README.rst @@ -62,7 +62,7 @@ Main features - Extensible : easy to add more protocols or more base types. - Framework independance : adapters are provided to easily integrate your API in any web framework, for example a wsgi container, - Pecan_, TurboGears_, cornice_... + Pecan_, TurboGears_, Flask_, cornice_... - Very few runtime dependencies: webob, simplegeneric. Optionnaly lxml and simplejson if you need better performances. - Integration in `Sphinx`_ for making clean documentation with @@ -70,6 +70,7 @@ Main features .. _Pecan: http://pecanpy.org/ .. _TurboGears: http://www.turbogears.org/ +.. _Flask: http://flask.pocoo.org/ .. _cornice: http://pypi.python.org/pypi/cornice Install diff --git a/doc/changes.rst b/doc/changes.rst index 3037faf..a24b462 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -4,6 +4,8 @@ Changes next ---- +* New Flask adapter: wsmeext.flask + * Fix: Submodules of wsmeext were missing in the packages. * Fix: The demo app was still depending on the WSME-Soap package (which has diff --git a/doc/integrate.rst b/doc/integrate.rst index 00d2720..2a95fa7 100644 --- a/doc/integrate.rst +++ b/doc/integrate.rst @@ -110,6 +110,44 @@ Example print("Got a message: %s" % info.message) +.. _adapter-flask: + +Flask +----- + + *"Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. And before you ask: It's BSD licensed! "* + + +.. warning:: + + Flask support is limited to function signature handling. It does not + support additional protocols. This is a temporary limitation, if you have + needs on that matter please tell us at python-wsme@googlegroups.com. + + +:mod:`wsmeext.flask` -- Flask adapter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. module:: wsmeext.flask + +.. function:: signature(return_type, \*arg_types, \*\*options) + + See @\ :func:`signature` for parameters documentation. + + Can be used on a function before routing it with flask. + +Example +~~~~~~~ + +.. code-block:: python + + from wsmeext.flask import signature + + @app.route('/multiply') + @signature(int, int, int) + def multiply(a, b): + return a * b + .. _adapter-pecan: Pecan diff --git a/tests/test_flask.py b/tests/test_flask.py index b1702b9..da9e1c6 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -9,6 +9,11 @@ class Model(Base): name = text +class Criterion(Base): + op = text + attr = text + value = text + test_app = Flask(__name__) @@ -25,9 +30,13 @@ def divide_by_zero(): @test_app.route('/models') -@signature([Model]) -def list_models(): - return [Model(name='first')] +@signature([Model], [Criterion]) +def list_models(q=None): + if q: + name = q[0].value + else: + name = 'first' + return [Model(name=name)] @test_app.route('/models/') @@ -63,6 +72,14 @@ class FlaskrTestCase(unittest.TestCase): resp = self.app.get('/models') assert resp.status_code == 200 + def test_array_parameter(self): + resp = self.app.get('/models?q.op=%3D&q.attr=name&q.value=second') + assert resp.status_code == 200 + print resp.data + self.assertEquals( + resp.data, '[{"name": "second"}]' + ) + def test_post_model(self): resp = self.app.post('/models', data={"body.name": "test"}) assert resp.status_code == 200 diff --git a/wsme/rest/args.py b/wsme/rest/args.py index f88ec3b..7769e18 100644 --- a/wsme/rest/args.py +++ b/wsme/rest/args.py @@ -81,11 +81,19 @@ def from_params(datatype, params, path, hit_paths): @from_params.when_type(ArrayType) def array_from_params(datatype, params, path, hit_paths): + if hasattr(params, 'getall'): + # webob multidict + def getall(params, path): + return params.getall(path) + elif hasattr(params, 'getlist'): + # werkzeug multidict + def getall(params, path): # noqa + return params.getlist(path) if path in params: hit_paths.add(path) return [ from_param(datatype.item_type, value) - for value in params.getall(path)] + for value in getall(params, path)] if iscomplex(datatype.item_type): attributes = set() @@ -99,7 +107,7 @@ def array_from_params(datatype, params, path, hit_paths): for attrdef in list_attributes(datatype.item_type): attrpath = '%s.%s' % (path, attrdef.key) hit_paths.add(attrpath) - attrvalues = params.getall(attrpath) + attrvalues = getall(params, attrpath) if len(value) < len(attrvalues): value[-1:] = [ datatype.item_type() @@ -158,7 +166,9 @@ def args_from_args(funcdef, args, kwargs): newargs.append(from_param(argdef.datatype, arg)) newkwargs = {} for argname, value in kwargs.items(): - newkwargs[argname] = from_param(funcdef.get_arg(argname).datatype, value) + newkwargs[argname] = from_param( + funcdef.get_arg(argname).datatype, value + ) return newargs, newkwargs