Всем привет! Меня зовут Иван, я программирую на 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 или ждете более стабильную версию? С удовольствием почитаю. И спасибо за внимание!

Комментарии (2)


  1. Andrey_Solomatin
    11.08.2025 09:02

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

    Довольно круто.


  1. Antra
    11.08.2025 09:02

    Интересно было бы взглянуть на ваш шаблон для нового проекта.

    pyproject.toml, .ruff.toml, ty.toml, может pytest.ini и т.п.