How Can I Type Convert Many Arguments Of A Function In Place?
Solution 1:
This is only documented in the changelog but since 2016 with cherrypy >= 6.2.0
there is a @cherrypy.tools.params
tool doing exactly what you want (provided that you use a Python 3 version supporting type annotations):
import cherrypy
@cherrypy.tools.params()defyour_http_handler(
a: float = 0, b: float = 0,
c: float = 0, d: float = 0,
e: float = 0, f: float = 0,
g: float = 0,
):
returnstr(a + b + c + d + e + f + g)
The PR that added it is PR #1442 — you can explore the usage by looking at the tests there.
If your Python is old for some reason, you could do:
import cherrypy
defyour_http_handler(**kwargs):
# Validate that the right query args are present in the HTTP request:if kwargs.keys() ^ {'a', 'b', 'c', 'd', 'e', 'f', 'g'}:
raise cherrypy.HTTPError(400, message='Got invalid args!')
numbers = (float(num) for num in kwargs.values()) # generator expression won't raise conversion errors heretry:
returnstr(sum(numbers)) # this will actually call those `float()` conversions so we need to catch a `ValueError`except ValueError as val_err:
raise cherrypy.HTTPError(
400,
message='All args should be valid numbers: {exc!s}'.format(exc=val_err),
)
P.S. In your initial post you use return print(...)
which is wrong. print()
always returns None
so you'd be sending "None"
back to the HTTP client while the argument of print(arg)
would be just printed out in your terminal where you run the server.
Solution 2:
Here's a @convert
decorator I've used before for something similar (originally inspired by https://stackoverflow.com/a/28268292/4597523):
import functools, inspect
defconvert(*to_convert, to):
defactual_convert(fn):
arg_names = inspect.signature(fn).parameters.keys()
@functools.wraps(fn)defwrapper(*args, **kwargs):
args_converted = [to(arg) if arg_name in to_convert else arg
for arg, arg_name inzip(args, arg_names)]
kwargs_converted = {kw_name: to(val) if kw_name in to_convert else val
for kw_name, val in kwargs.items()}
return fn(*args_converted, **kwargs_converted)
return wrapper
return actual_convert
@convert('a', 'c', 'd', to=str)deff(a, b, c=5, *, d, e=0):
return a, b, c, d, e
print(f(1, 2, d=7))
# Output: ('1', 2, 5, '7', 0)# Passed params `a` and `d` got changed to `str`,# however `c` used the default value without conversion
It uses inspect.signature
to get the non-keyword arg names. I am not sure how CherryPy passes the params or how it gets the names, but this might be a solid start. Using functools.wraps
is important - it makes sure the original signature function signature is preserved, which seems to be important for CherryPy.
Post a Comment for "How Can I Type Convert Many Arguments Of A Function In Place?"