mypy, Pyrefly, Pyright, ty, Zuban — и это ещё не конец списка. Как поддерживать библиотеку когда каждый чекер хочет свои аннотации.
Короткий ответ: не нужно гонять все пять по исходникам. Нужно гонять их по тестам.
Когда вы запускаете тайп-чекер на внутреннем коде — вы проверяете свою логику. Каким чекером пользоваться внутри — ваш выбор.
Но каким чекером пользуются ваши пользователи — не ваш выбор. Они придут с mypy, кто-то с Pyright, кто-то уже перешёл на ty. И все они будут взаимодействовать с вашим публичным API.
Запускайте как можно больше чекеров на тестах → убедитесь что публичный API работает для всех.
Пример из Polars
Вот во что превращается код когда пытаешься угодить всем чекерам сразу в исходниках:
@overload # type: ignore[override]
def __eq__( # pyrefly: ignore[bad-override]
self, other: pl.DataTypeExpr
) -> pl.Expr: ...
@overload
def __eq__(self, other: PolarsDataType) -> bool: ...
def __eq__( # ty: ignore[invalid-method-override]
# pyright: ignore[reportIncompatibleMethodOverride]
self, other: pl.DataTypeExpr | PolarsDataType
) -> pl.Expr | bool:
4 разных type-ignore комментария на 7 строк. Кодовая база быстро превращается в кашу.
А вот тест на тот же метод — все 5 чекеров проходят его без единой ошибки:
def test_dtype_time_units() -> None:
for time_unit in DTYPE_TEMPORAL_UNITS:
assert pl.Datetime == pl.Datetime(time_unit)
assert pl.Duration == pl.Duration(time_unit)
Чекеры расходятся в том как должна быть написана реализация, но соглашаются в том как API ведёт себя снаружи. А пользователям важно именно это.
Практический совет
✳️ Тесты → запускайте максимум чекеров
✳️ Исходники → выберите один, который вам нравится
✳️ Для строгой проверки → Pyrefly (быстрый, соответствует спецификации)
✳️ Для постепенного добавления типов → mypy в мягком режиме
📍 Навигация: Вакансии • Задачи • Собесы
Библиотека питониста
#буст