Как документировать и тестировать интерфейсы, необходимые для формальных параметров в Python 2?

Чтобы задать свой очень конкретный вопрос, мне кажется, мне нужно довольно подробное введение, чтобы мотивировать и объяснить это – я обещаю, что в конце есть правильный вопрос!

При чтении части большой кодовой базы Python иногда приходит код, где интерфейс, требуемый для аргумента, не является очевидным из «ближайшего» кода в том же модуле или пакете. В качестве примера:

def make_factory(schema): entity = schema.get_entity() ... 

Может быть много «схем» и «фабрик», с которыми имеет дело код, и «def get_entity ()» может быть довольно распространенным (или, возможно, функция не вызывает никаких методов в схеме, а просто передает ее другой функции ). Поэтому быстрый grep не всегда помогает узнать больше о том, что такое «схема» (и то же самое относится к типу возврата). Хотя «утиная набивка» является приятной особенностью Python, иногда неопределенность в понимании читателя о интерфейсе аргументов, передаваемых в виде «схемы», мешает быстро понять код (и то же самое касается неопределенности в отношении типичного бетона классы, реализующие интерфейс). Рассмотрение автоматизированных тестов может помочь, но явная документация может быть лучше, потому что ее быстрее читать. Любая такая документация лучше всего, когда она сама может быть протестирована, чтобы она не устаревала.

Doctests – один из возможных подходов к решению этой проблемы, но об этом не говорит.

Python 3 имеет функцию «аннотации параметров» (часть функции аннотации функций, определенная в PEP 3107). Использования, для которых эта функция может быть помещена, не определяются языком, но могут быть использованы для этой цели. Это может выглядеть так:

 def make_factory(schema: "xml_schema"): ... 

Здесь «xml_schema» идентифицирует интерфейс Python, который должен поддерживать аргумент, передаваемый этой функции. В другом месте был бы код, который определяет этот интерфейс с точки зрения атрибутов, методов и их сигнатур аргументов и т. Д. И кода, который позволяет интроспекции проверять, предоставляют ли определенные объекты интерфейс (возможно, реализованы с использованием чего-то типа zope.interface / zope.schema). Обратите внимание, что это не обязательно означает, что интерфейс проверяется каждый раз, когда передается аргумент, и что статический анализ не выполняется. Скорее, мотивация определения интерфейса заключается в том, чтобы предоставить способы написания автоматических тестов, которые подтверждают, что эта документация не устарела (это могут быть довольно общие тесты, так что вам не нужно писать новый тест для каждой функции, которая использует параметры, или вы можете включить проверку интерфейса во время выполнения, но только при выполнении ваших модульных тестов). Вы можете пойти дальше и аннотировать интерфейс возвращаемого значения, которое я не буду проиллюстрировать.

Итак, вопрос:

Я хочу сделать именно это, но используя Python 2 вместо Python 3. Python 2 не имеет функции аннотации функций. Что такое «самая близкая вещь» в Python 2? Ясно, что существует несколько способов сделать это, но я подозреваю, что существует один (относительно) очевидный способ сделать это.

Дополнительные баллы: назовите библиотеку, которая реализует один очевидный способ.

Взгляните на plac который использует аннотации для определения интерфейса командной строки для скрипта. На Python 2.x он использует декоратор plac.annotations() .

Ближайшая вещь, я считаю, представляет собой аннотационную библиотеку под названием PyAnno .

На веб-странице проекта:

«Аннотации Pyanno имеют две функции:

  • Предоставьте структурированный способ документирования кода Python
  • Выполняйте ограниченную проверку времени выполнения "