TY — не thank you, а быстрый type checker для Python

от автора

Всем привет! Меня зовут Иван, я программирую на Python, а в свободное время пишу для блога МТС. В прошлый раз поделился опытом, как я осваивал Go и с чем у меня были сложности. Спасибо всем, кто читал и комментировал! Сегодня хочу обсудить мегабыстрый инструмент для проверки типов данных Python — ty: как он устанавливается и используется, какие есть правила и нюансы, а еще посмотрим, как можно его применять. Приступим!

Что это за покемон?

Начнем с базы: ty — это проект Astral. Как пишут разработчики на GitHub, это супер-пупер быстрый инструмент для проверки типов данных Python, а еще — языковой сервер, написанный на Rust. Про Rust неудивительно, ведь и другие продукты Astral — uv и ruff — тоже написаны с его помощью. Возможно, и следующий проект будет сделан на нем.

У ty уже есть небольшая документация. Функциональность можно изучить онлайн в песочнице, установка на ПК не нужна.

А вот и информация по проекту:

Параметр

Описание

Особенности

Быстрый, написан на Rust, не готов к проду

Количество звезд на GitHub

10,6 тыс.

Открытых Issues

310

Версия

0.0.1-alpha.14

Год релиза

2025

Pull Requests (PRs)

0 открытых и 162 закрытых

Участие в разработке

Разработчики проекта, комьюнити

Лицензия

MIT

Почему он вообще меня заинтересовал? В 2024 году Astral выпустила быстрый пакетный менеджер uv, и он моментально стал популярным. Сейчас у проекта 61 тысяча звезд на GitHub. Подробно о uv и его преимуществах не так давно писал Леша Жиряков из MWS, очень рекомендую почитать: тык.  Так почему бы внимательнее не присмотреться к ty?

Возможно, это тоже что-нибудь революционное и в плане скорости, и в плане удобства использования. В целом есть ощущение, что разработчики Astral стремятся создать свою небольшую экосистему инструментов для Python, и наблюдать за этим очень интересно.

Но вернемся к ty. Как я уже сказал выше, это инструмент для проверки типов данных Python и языковой сервер. Давайте немного определений:

Type checker (англ. type — тип, checker — контролер) — это инструмент, который проверяет использование различных типов данных в коде в соответствии с правилами определенного языка программирования. Он помогает убедиться, что действия выполняются с подходящими типами данных. Например, в Python нельзя сложить строку и целое число, в результате выведется ошибка “TypeError: unsupported operand type(s) for +: ‘int’ and ‘str’ “).

Language server (с англ. «языковой сервер») — программа, которая предоставляет редакторам кода и IDE специфичные для языка программирования возможности. Это могут быть:

  • подсветка синтаксиса;

  • проверка ошибок;

  • завершение кода, например, при импорте модуля выводятся подсказки — доступные модули для импорта.

Есть стандартизированный протокол для обеспечения языковых возможностей для редакторов кода и IDE — это LSP (Language Server Protocol).

Галопом по (Европам) ty

Установка

Есть несколько способов:

# 1. pip pip install ty  # 2. pipx pipx install ty  # 3. uv uv tool install ty@latest

Запуск и доступные команды

Используется ty так:

ty <КОМАНДА>

Доступно четыре команды:

  • check — проверяет проект на ошибки типов данных (type errors);

  • server — запускает языковой сервер;

  • version — выводит версию ty;

  • help — выводит сообщение с информацией о поддерживаемых командах и опциях или вспомогательную информацию об одной из четырех команд.

И две опции:

  • -h, —help — выводит вспомогательную информацию;

  • -V, —version — выводит версию.

Конфигурация

Для ty можно указать конфигурацию при помощи файла pyproject.toml:

[tool.ty.rules] index-out-of-bounds = "ignore"

Или ty.toml:

[rules] index-out-of-bounds = "ignore"

Причем важно заметить, что если в проекте будет два вышеуказанных файла, то приоритет будет у ty.toml. Настройки ty, указанные в pyproject.toml, будут проигнорированы.

Правила и их уровни

В рамках ty правила — это индивидуальные проверки для обнаружения типичных проблем в коде. Каждое правило сфокусировано на определенном паттерне и может быть включено или выключено при необходимости.

У правила есть уровни, которые можно настроить. Всего их три:

  • Error (с англ. «ошибка») — нарушения регистрируются как ошибки, и ty завершается с кодом выхода (exit code) 1.

  • Warn (с англ. «предупреждать») — нарушения регистрируются как предупреждения, и ty завершается с кодом выхода 0. Но если используется опция —error-on-warning, код выхода будет равен 1.

  • Ignore (с англ. «игнорировать») — правило отключено.

Есть два способа настройки правил:

1. В файле:

[tool.ty.rules] unused-ignore-comment = "warn" redundant-cast = "ignore" possibly-unbound-attribute = "error" possibly-unbound-import = "error"

2. В командной строке:

ty check \  --warn unused-ignore-comment \  --ignore redundant-cast \  --error possibly-unbound-attribute \  --error possibly-unbound-import

В документации я насчитал 66 правил. Вот одно из них:

Подавление

Вместо того чтобы полностью отключать правило (уровень ignore), можно сделать это точечно для определенных участков кода.

Один из способов — указание комментария формата # ty: ignore[<rule>]:

a = 42 + "hello"  # ty: ignore[unsupported-operator]

Если нарушение правила происходит на нескольких строках, можно указать комментарий на первой или последней строке:

# Создадим функцию def sum_three(a: int, b: int, c: int) -> int:      ...   # Так как указано три аргумента, а передается два, то сработает правило. # Проигнорируем его. sum_three(    5,    6 )   ### Вариант с первой строкой  sum_three(  # ty: ignore[missing-argument]    5,    6 )   ### Вариант с последней строкой  sum_three(    5,    6 )  # ty: ignore[missing-argument]

Нарушается несколько правил? Тогда можно перечислить их в квадратных скобках:

sum_three("hello", 3)  # ty: ignore[missing-argument, invalid-argument-type]

И еще кое-что из интересного — декоратор @no_type_check, который позволяет игнорировать все нарушения внутри функции:

from typing import no_type_check  @no_type_check def main():    sum_three(5, 6)

Интеграция с редакторами кода

ty можно встроить в программы для редактирования кода. Сейчас командой разработчиков Astral поддерживается официальный плагин для VS Code, у этого расширения есть документация на GitHub.

Еще ty может взаимодействовать с Neovim — для этого нужно добавить определенные строки в конфигурацию. В качестве примера для версии редактора 0.10 или более ранней с помощью nvim-lspconfig нужно будет указать:

require('lspconfig').ty.setup({  init_options = {    settings = {      -- Здесь располагаются настройки языкового сервера ty    }  } })

Что касается других редакторов кода, к ним можно подключить ty, если они поддерживают протокол языкового сервера.

Версия Python

Для ty важно, какая версия Python используется. От этого зависит обнаружение ошибок в коде. Самый яркий пример — это выражение match и атрибут stdlib_module_names для модуля sys:

import sys  # Если версия Python 3.9 или ниже, то выведется ошибка `invalid-syntax` match "echo Hello,Habr!".split():    case ["echo", message]:        print(message)    case _:        print("you used unknown command")   # То же условие про версию. Ошибка `unresolved-attribute` print(sys.stdlib_module_names)  # Однако можно добавить проверку на версию if sys.version_info >= (3, 10):    # Ошибки не возникнет, так как выполняется проверка версии    print(sys.stdlib_module_names)

Как работает проверка (check)

При выполнении команды:

ty check

Осуществляется проверка всех файлов как в текущей, так и в дочерних директориях. Но если ty используется в рамках проекта, запуск будет выполняться начиная с каталога, в котором расположен файл pyproject.toml.

Еще можно указать конкретный файл:

ty check something.py

ty самостоятельно обнаружит установленные модули в активной виртуальной среде одним из двух путей:

  • при помощи переменных окружения VIRTUAL_ENV или CONDA_PREFIX;

  • будет искать директорию .venv в корне проекта или текущем каталоге.

Если же ty выполняется не в рамках виртуальной среды, придется указывать путь к пакетам вручную при помощи опции —python:

ty check --python .venv/bin/python3 something.py

ty по умолчанию игнорирует файлы, указанные в .ignore или .gitignore. Но эту опцию можно отключить, указав —no-respect-gitignore:

ty check --no-respect-gitignore

Пример использования

Допустим, у нас небольшой проект на FastAPI. Есть файл main.py:

from fastapi import FastAPI  from app.models import User  app = FastAPI()  def old_enough(age: int = None) -> bool:    return True if age >= 18 else False  @app.get("/") async def root():    return {"hello!": "hello"}  @app.post("/user/") def user(data: User) -> User:    data.is_adult = old_enough(data.age)    return data

И models.py:

from pydantic import BaseModel, ConfigDict  class User(BaseModel):    model_config = ConfigDict(extra=”allow”)    name: str    age: int

Теперь выполним проверку:

(venv) Ivans-PC:test iglebov$ ty check WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. error[invalid-parameter-default]: Default value of type `None` is not assignable to annotated parameter type `int`  --> app/main.py:7:16   | 5 | app = FastAPI() 6 | 7 | def old_enough(age: int = None) -> bool:   |                ^^^^^^^^^^^^^^^ 8 |     return True if age >= 18 else False   | info: rule `invalid-parameter-default` is enabled by default  error[unresolved-attribute]: Unresolved attribute `is_adult` on type `User`.   --> app/main.py:16:5    | 14 | @app.post("/user/") 15 | def user(data: User) -> User: 16 |     data.is_adult = old_enough(data.age)    |     ^^^^^^^^^^^^^ 17 |     return data    | info: rule `unresolved-attribute` is enabled by default

Found 2 diagnosticsty обнаружил целых две ошибки. Посмотрим подробнее:

1. Default value of type None is not assignable to annotated parameter type int

Тут указано, что нельзя присвоить None для аргумента с типом данных int.

Исправим функцию old_enough:

def old_enough(age: int = 18) -> bool:    return True if age >= 18 else False

2. Unresolved attribute is_adult on type User

Для модели User не удалось определить атрибут is_adult. В ней он не описан, но в конфигурации модели указывается extra=”allow”, что позволяет добавлять атрибут «на ходу».

Если логика кода правильная, но ошибка возникает, можно добавить игнорирование при помощи комментария:

@app.post("/user/") def user(data: User) -> User:    data.is_adult = old_enough(data.age)  # ty: ignore[unresolved-attribute]    return data

Снова запустим проверку:

(venv) Ivans-PC:test iglebov$ ty check WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors. All checks passed!

Ура, все успешно! На такой позитивной ноте перехожу к заключению.

Что в итоге

Мы посмотрели новый проект от компании Astral — ty. Пока он только набирает обороты, но его сильные стороны уже очевидны. В первую очередь это:

  • простота использования: установить, добавить файлик ty.toml или pyproject.toml и let’s go;

  • скорость: проверка выполняется довольно быстро;

  • интеграция с редакторами кода и даже плагин для VS Code.

А как ваши впечатления? Поделитесь, используете ли ty или ждете более стабильную версию? С удовольствием почитаю. И спасибо за внимание!


ссылка на оригинал статьи https://habr.com/ru/articles/935858/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *