2016-06-22 3 views
1

Я хочу использовать аннотации, чтобы иметь лучшее автозаполнение в IDE и, возможно, более позднее тестирование типов в автоматизированных тестах. Но как вы можете добавлять аннотации типов ко многим методам без введения большого количества дополнительного кода?Использование аннотаций типа на уровне пакета

Например, представьте, что у вас есть большая база кода, которая использует структуру Django, включая около 200 методов с аргументом request; добавление аннотаций типа 200 раз раздувало бы код.

Моей идеей является включение аннотаций типа на уровне пакета: в setup.py (или в другом месте). Я определяю правило, которое говорит «каждый раз, когда используется переменная request, она имеет тип django.http.HttpRequest«. Для случаев ребер, где переменная с именем request указывает на другой тип, должны быть сделаны явные аннотации, но их очень мало.

Как это можно реализовать? Существуют ли другие способы достижения общей цели?

ответ

5

Если я правильно понимаю, это звучит как потребительная случае для окурка файлов, которые, как описано в PEP 484:

Ста файлы представляют собой файлы, содержащие намеки типа, которые предназначены для использования только по типу проверки, а не во время выполнения.

Файлы-заглушки в значительной степени удовлетворяют вашему требованию отделять код от аннотаций типа, тем самым избегая эффекта вздутия и запутывания сложных подсказок типа. Они имеют префикс .pyi, и если проверка типов, реализованная IDE, которая хочет соответствовать PEP 484, должна быть проверена проверяющим тип, если они существуют.

Они в основном состоят из аннотированных сигнатур функций с телом, содержащим один многоточием ...


Один из способов вы можете идти об этом используют вспомогательную функцию, чтобы записать ваши .pyi, или, по крайней мере, основная его часть. Вероятно, есть много способов сделать это, и лучший из них - это, вероятно, еще один вопрос.

В качестве примера способа сделать это, я напишу способ аннотировать каждую функцию в модуле inspect, который имеет параметр с именем object и не начинается с подчеркивания. Я набираю этот специальный модуль, так как я также буду использовать его для идентификации функций и захвата их подписи.

От модуля inspect, я буду использовать функции getmembers, isfunction и signature.

# gets members of inspect module {member_name: member_type} dict. 
members = getmembers(inspect) 

# loop through members 
for name, type in members: 

    # grab functions that don't start with an underscore 
    if isfunction(type) and not name.startswith('_'): 

     # grab its signature and 
     # check if it has a parameter named object 
     sig = signature(type) 
     if 'object' in sig.parameters: 

      # add the annotation to the object parameter 
      param = sig.parameter['object'] 
      s = sig.replace(parameters = [param.replace(annotation="object")]) 

      # here you normally write to .pyi file 
      print('def {0} {1}: ...'.format(name, s)) 

Эта логика может быть расширена до method с, других типов параметров и так далее. Кроме того, важное примечание, файл .pyi должен иметь то же имя, что и модуль, который вы аннотируете, поэтому в этом случае он должен быть inspect.pyi.

На данный момент, это просто выводит все функции, которые имеют параметр с именем object с «аннотацией» (object) мы поставили:

def findsource(object:'object'): ... 
def formatannotationrelativeto(object:'object'): ... 
def getabsfile(object:'object'): ... 
def getcomments(object:'object'): ... 
def getdoc(object:'object'): ... 
def getfile(object:'object'): ... 
def getmembers(object:'object'): ... 
def getmodule(object:'object'): ... 
def getsource(object:'object'): ... 
# .. and so on.. 

большинство производства готовых шашек будет читать этот .pyi файл и обеспечивают функциональные возможности тебе нужно.

+1

Спасибо за подробный ответ. Вы получаете щедрость! – guettli

0

Вы можете использовать пользовательские middleware (непроверенные):

from django.http import HttpRequest 

class RequireHttpRequest(): 
    def process_view(request, view_func, view_args, view_kwargs): 
     require_http_request = view_kwargs.get('require_http_request', True) 
     if require_http_request and type(h) != HttpRequest: 
      raise SomeException 
     return None 

По умолчанию, это ПО промежуточного слоя будет влиять на все URL-адреса. Для нескольких URL-адресов, на которые вы не хотите, чтобы проверить тип request, добавить параметр в соответствующих строках urls.py:

url(r'^foo/$', views.your_view, require_http_request=False) 

и поставить конкретные аннотации в определении my_view().

+0

Я думаю, мой вопрос был слишком расплывчатым. Я добавил следующее: я хочу, чтобы аннотации имели лучшее автоматическое завершение в IDE. Возможно (позднее) тестирование типа в автоматизированных тестах. – guettli

Смежные вопросы