Skip to content

Commit

Permalink
Merge 8f7f4bd into 539fdf8
Browse files Browse the repository at this point in the history
  • Loading branch information
peldszus committed Mar 8, 2018
2 parents 539fdf8 + 8f7f4bd commit 9cdd25e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 5 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: python
python:
- pypy
- 2.6
- 2.7
- 3.4
# command to install dependencies
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: Implementation :: PyPy',
]
Expand Down
41 changes: 39 additions & 2 deletions supercell/requesthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import inspect

from schematics.models import Model
from schematics.types.compound import ListType
from schematics.exceptions import BaseError
from tornado import gen, iostream
from tornado.concurrent import is_future
Expand Down Expand Up @@ -71,12 +72,12 @@ class RequestHandler(rq):

@property
def environment(self):
"""Convinience method for accessing the environment."""
"""Convenience method for accessing the environment."""
return self.application.environment

@property
def config(self):
"""Convinience method for accessing the configuration."""
"""Convenience method for accessing the configuration."""
return self.application.config

@property
Expand Down Expand Up @@ -279,3 +280,39 @@ def write_error(self, status_code, **kwargs):
provider_class().error(status_code, self._reason, self)
except NoProviderFound:
super(RequestHandler, self).write_error(status_code, **kwargs)

def load_model_from_arguments(self, model_cls, validate=True, **kwargs):
"""
Convenience method for instantiating a model from the request's url
query arguments. Supports ListType model fields for multi parameters.
Kwargs can specify defaults for fields not provided in the request.
:param model_cls: A model class (instance of schematics.models.Model).
:param validate : Allows to switch off validation (default is True).
:param kwargs : Optional arguments that are used as default if there
is no adequate parameter in request.
:return: A model instance.
"""
assert issubclass(model_cls, Model)

raw_data = dict(kwargs)
fields = model_cls._fields # noqa

arguments = {
key: self.get_arguments(key)
for key in self.request.query_arguments
}

raw_data.update({
key: (
values
if isinstance(fields.get(key, None), ListType)
else values[0]
)
for key, values in arguments.items() if values
})
model = model_cls(raw_data)
if validate:
model.validate()
return model
60 changes: 59 additions & 1 deletion test/test_requesthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from schematics.models import Model
from schematics.types import StringType
from schematics.types import IntType
from schematics.types.compound import ModelType
from schematics.types.compound import ListType
from schematics.types.compound import ModelType

from tornado.ioloop import IOLoop
from tornado.testing import AsyncHTTPTestCase
Expand Down Expand Up @@ -353,3 +353,61 @@ def test_provide_partial_model_with_complex_partial_true(self):
self.assertEqual('{"messages": [{"doc_id": "test123"}]}',
json.dumps(json.loads(response.body.decode('utf8')),
sort_keys=True))


class SimpleModel(Model):
name = StringType()
numbers = ListType(IntType())

class Options:
serialize_when_none = False


class TestLoadModelFromArguments(AsyncHTTPTestCase):

def get_app(self):

@provides(s.MediaType.ApplicationJson, default=True)
class MyHandler(RequestHandler):

@s.async
def get(self, *args, **kwargs):
model = self.load_model_from_arguments(
SimpleModel, name="default")
raise s.Return(model)

env = Environment()
env.add_handler('/test', MyHandler)
return env.get_application()

def test_load_model_default_is_used(self):
response = self.fetch(
'/test',
headers={'Accept': s.MediaType.ApplicationJson})
self.assertEqual(response.code, 200)
body = json.loads(response.body.decode('utf8'))
self.assertEqual(body, {"name": "default"})

def test_load_model_default_is_overwritten(self):
response = self.fetch(
'/test?name=Peter',
headers={'Accept': s.MediaType.ApplicationJson})
self.assertEqual(response.code, 200)
body = json.loads(response.body.decode('utf8'))
self.assertEqual(body, {"name": "Peter"})

def test_load_model_list_type_single_entries(self):
response = self.fetch(
'/test?name=Peter&numbers=1',
headers={'Accept': s.MediaType.ApplicationJson})
self.assertEqual(response.code, 200)
body = json.loads(response.body.decode('utf8'))
self.assertEqual(body, {"name": "Peter", "numbers": [1]})

def test_load_model_list_type_multiple_entries(self):
response = self.fetch(
'/test?name=Peter&numbers=1&numbers=2&numbers=3',
headers={'Accept': s.MediaType.ApplicationJson})
self.assertEqual(response.code, 200)
body = json.loads(response.body.decode('utf8'))
self.assertEqual(body, {"name": "Peter", "numbers": [1, 2, 3]})

0 comments on commit 9cdd25e

Please sign in to comment.