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
|
from functools import wraps
import cherrypy
from ..tools import TaskManager
from ._helpers import _get_function_params
class Task:
def __init__(self, name, metadata, wait_for=5.0, exception_handler=None):
self.name = name
if isinstance(metadata, list):
self.metadata = {e[1:-1]: e for e in metadata}
else:
self.metadata = metadata
self.wait_for = wait_for
self.exception_handler = exception_handler
def _gen_arg_map(self, func, args, kwargs):
arg_map = {}
params = _get_function_params(func)
args = args[1:] # exclude self
for idx, param in enumerate(params):
if idx < len(args):
arg_map[param['name']] = args[idx]
else:
if param['name'] in kwargs:
arg_map[param['name']] = kwargs[param['name']]
else:
assert not param['required'], "{0} is required".format(param['name'])
arg_map[param['name']] = param['default']
if param['name'] in arg_map:
# This is not a type error. We are using the index here.
arg_map[idx+1] = arg_map[param['name']]
return arg_map
def _get_metadata(self, arg_map):
metadata = {}
for k, v in self.metadata.items():
if isinstance(v, str) and v and v[0] == '{' and v[-1] == '}':
param = v[1:-1]
try:
pos = int(param)
metadata[k] = arg_map[pos]
except ValueError:
if param.find('.') == -1:
metadata[k] = arg_map[param]
else:
path = param.split('.')
metadata[k] = arg_map[path[0]]
for i in range(1, len(path)):
metadata[k] = metadata[k][path[i]]
else:
metadata[k] = v
return metadata
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
arg_map = self._gen_arg_map(func, args, kwargs)
metadata = self._get_metadata(arg_map)
task = TaskManager.run(self.name, metadata, func, args, kwargs,
exception_handler=self.exception_handler)
try:
status, value = task.wait(self.wait_for)
except Exception as ex:
if task.ret_value:
# exception was handled by task.exception_handler
if 'status' in task.ret_value:
status = task.ret_value['status']
else:
status = getattr(ex, 'status', 500)
cherrypy.response.status = status
return task.ret_value
raise ex
if status == TaskManager.VALUE_EXECUTING:
cherrypy.response.status = 202
return {'name': self.name, 'metadata': metadata}
return value
return wrapper
|