Как приводить значения параметров на основе их аннотаций в функциях python?
Рассмотрите возможность создания рабочего, который выполняет задачи из очереди задач. Я пытаюсь построить веб-интерфейс на django, чтобы запускать эти задачи вручную.
Пока что для некоторых встроенных типов данных я поступаю примерно так:
# tasks.py
@app.task
def add(a: int, b: int) -> int:
return a+b
# views.py
TYPE_TO_FIELD_MAPPING = {
str: forms.CharField,
int: forms.IntegerField,
float: forms.FloatField,
datetime: forms.DateTimeField,
# ...
}
class TaskTriggerView(View):
def get(self, request):
tasks = {}
for task in app.tasks:
tasks[task.name] = self.make_task_parameter_form(task)()
return render(request, 'template.html', context={'tasks': tasks}
def make_task_parameter_form(self, task):
# every task has a signature property which
# is an inspect.Signature object.
task_signature: inspect.Signature = task.signature
# Initialize a django form with fields made out of
# task's function signature, where the form field
# is based on it's annotation if annotation is in
# `TYPE_TO_FIELD_MAPPING` else forms.CharField.
# initial value comes from parameter's default value
# if it is not parameter.empty.
parameter_form = type(
'ParameterForm', (forms.Form,),
{param_name: TYPE_TO_FIELD_MAPPING.get(param.annotation, str)(
initial=None if param.default is param.empty else param.default
)
for param_name, param in signature.parameters.items()})
return parameter_form
def post(self, request):
task_name = request.POST.get('task_name')
task = app.get_task_by_name(task_name)
form_class = self.make_task_parameter_form(task)
form = form_class(request.POST)
if form.is_valid()
# this sends the task to the queue
task.send(**form.cleaned_data)
return JsonResponse({'success': True})
else:
return JsonResponse({'success': False, 'errors': form.errors})
Мой вопрос заключается в том, как мне следует деконструировать более сложную аннотацию, например: List[str]
из примера ниже?
@app.task
def concat_lists_of_names(a: List[str], b: List[str]):
return a+b
В идеале я хотел бы иметь возможность различать parameter_type = list
, component_type = str
. А затем сопоставить его с пользовательским ListField(component_type=component_type)
, который будет проверять и приводить каждый компонент списка.