Pyramid supports a concept of a “view mapper”. See Using a View Mapper for general information about view mappers. You can use a view mapper to support an alternate convenience calling convention in which you allow view callables to name extra required and optional arguments which are taken from the request.params dictionary. So, for example, instead of:
1 2 3 4 5 | @view_config()
def aview(request):
name = request.params['name']
value = request.params.get('value', 'default')
...
|
With a special view mapper you can define this as:
@view_config(mapper=MapplyViewMapper)
def aview(request, name, value='default'):
...
The below code implements the MapplyViewMapper. It works as a mapper for function view callables and method view callables:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | import inspect
import sys
from pyramid.view import view_config
from pyramid.response import Response
from pyramid.config import Configurator
from waitress import serve
PY3 = sys.version_info[0] == 3
if PY3:
im_func = '__func__'
func_defaults = '__defaults__'
func_code = '__code__'
else:
im_func = 'im_func'
func_defaults = 'func_defaults'
func_code = 'func_code'
def mapply(ob, positional, keyword):
f = ob
im = False
if hasattr(f, im_func):
im = True
if im:
f = getattr(f, im_func)
c = getattr(f, func_code)
defaults = getattr(f, func_defaults)
names = c.co_varnames[1:c.co_argcount]
else:
defaults = getattr(f, func_defaults)
c = getattr(f, func_code)
names = c.co_varnames[:c.co_argcount]
nargs = len(names)
args = []
if positional:
positional = list(positional)
if len(positional) > nargs:
raise TypeError('too many arguments')
args = positional
get = keyword.get
nrequired = len(names) - (len(defaults or ()))
for index in range(len(args), len(names)):
name = names[index]
v = get(name, args)
if v is args:
if index < nrequired:
raise TypeError('argument %s was omitted' % name)
else:
v = defaults[index-nrequired]
args.append(v)
args = tuple(args)
return ob(*args)
class MapplyViewMapper(object):
def __init__(self, **kw):
self.attr = kw.get('attr')
def __call__(self, view):
def wrapper(context, request):
keywords = dict(request.params.items())
if inspect.isclass(view):
inst = view(request)
meth = getattr(inst, self.attr)
response = mapply(meth, (), keywords)
else:
# it's a function
response = mapply(view, (request,), keywords)
return response
return wrapper
@view_config(name='function', mapper=MapplyViewMapper)
def view_function(request, one, two=False):
return Response('one: %s, two: %s' % (one, two))
class ViewClass(object):
__view_mapper__ = MapplyViewMapper
def __init__(self, request):
self.request = request
@view_config(name='method')
def view_method(self, one, two=False):
return Response('one: %s, two: %s' % (one, two))
if __name__ == '__main__':
config = Configurator()
config.scan('.')
app = config.make_wsgi_app()
serve(app)
# http://localhost:8080/function --> (exception; no "one" arg supplied)
# http://localhost:8080/function?one=1 --> one: '1', two: False
# http://localhost:8080/function?one=1&two=2 --> one: '1', two: '2'
# http://localhost:8080/method --> (exception; no "one" arg supplied)
# http://localhost:8080/method?one=1 --> one: '1', two: False
# http://localhost:8080/method?one=1&two=2 --> one: '1', two: '2'
|