ty/docs
Micha Reiser 4bd25b710b
Some checks are pending
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / Check generated files unedited (push) Waiting to run
Use environment.root instead of src.root in README (#694)
2025-06-24 14:53:00 +02:00
..
reference Document python.ty.disableLanguageServices (#668) 2025-06-18 11:58:43 +05:30
README.md Use environment.root instead of src.root in README (#694) 2025-06-24 14:53:00 +02:00

ty

Installation | Module discovery | Python version | Excluding files | Editor integration | Rules | Suppressions | Configuration | Exit codes | Reference

Getting started

For a quick guide on getting started, see the top-level README.

Installation

Adding ty to your project

Use uv (or your project manager of choice) to add ty as a development dependency:

uv add --dev ty

Adding ty as a dependency ensures that all developers on the project are using the same version of ty.

Then, use uv run to invoke ty:

uv run ty

Installing globally

Install ty globally with uv:

uv tool install ty@latest

Or, pipx:

pipx install ty

Installing with pip

Install ty into your current Python environment with pip:

pip install ty

Usage

Run ty check, in your project's top-level directory, to check the project for type errors using ty's default configuration.

If this provokes a cascade of errors, and you are using the standard library venv module to provide your virtual environment, add the venv directory to your .gitignore or .ignore file and then retry.

Module discovery

First-party modules

First-party modules are Python files that are part of your project source code.

By default, ty searches for first-party modules in the project's root directory or the src directory, if present.

If your project uses a different layout, configure the project's environment.root in your pyproject.toml or ty.toml. For example, if your project's code is in an app/ directory:

example-pkg
├── README.md
├── pyproject.toml
└── app
    └── example_pkg
        └── __init__.py

then set environment.root in your pyproject.toml to ["./app"]:

[tool.ty.environment]
root = ["./app"]

Third-party modules

Third-party modules are Python packages that are not part of your project or the standard library. These are usually declared as dependencies in a pyproject.toml or requirements.txt file and installed using a package manager like uv or pip. Examples of popular third-party modules are requests, numpy and django.

ty searches for third-party modules in the configured Python environment.

Python environment

The Python environment is used for discovery of third-party modules.

By default, ty will attempt to discover a virtual environment.

First, ty checks for an active virtual environment using the VIRTUAL_ENV environment variable. If not set, ty will search for a .venv directory in the project root or working directory. ty only supports discovery of virtual environments at this time.

Note

When using project management tools, such as uv or Poetry, the run command usually automatically activates the virtual environment and will be detected by ty.

The Python environment may be explicitly configured using the environment.python setting or --python flag.

When setting the environment explicitly, non-virtual environments can be provided.

Python version

The Python version affects allowed syntax, type definitions of the standard library, and type definitions of first- and third-party modules that are conditional on the Python version.

For example, Python 3.10 introduced support for match statements and added the sys.stdlib_module_names symbol to the standard library. Syntactic features always need to be available in the lowest supported Python version, but symbols may be used in a sys.version_info conditional branch:

import sys

# `invalid-syntax` error if `python-version` is set to 3.9 or lower:
match "echo hello".split():
    case ["echo", message]:
        print(message)
    case _:
        print("unknown command")

# `unresolved-attribute` error if `python-version` is set to 3.9 or lower:
print(sys.stdlib_module_names)

if sys.version_info >= (3, 10):
    # ok, because the usage is guarded by a version check:
    print(sys.stdlib_module_names)

By default, the lower bound of the project's requires-python field (from the pyproject.toml) is used as the target Python version, ensuring that features and symbols only available in newer Python versions are not used.

If the requires-python field is not available but a virtual environment has been configured or detected, ty will try to infer the Python version being used from the virtual environment's metadata.

If no virtual environment is present or inferring the Python version from the metadata fails, ty will fall back to the latest stable Python version supported by ty (currently 3.13).

The Python version may also be explicitly specified using the python-version setting or the --python-version flag.

Excluding files

ty automatically discovers all Python files in your project. You can customize where ty searches by using the src.include and src.exclude settings.

For example, with the following configuration, ty checks all Python files in the src and tests directories except those in the src/generated directory:

[tool.ty.src]
include = ["src", "tests"]
exclude = ["src/generated"]

By default, ty excludes a variety of commonly ignored directories. If you want to include one of these directories, you can do so by adding a negative exclude:

[tool.ty.src]
# Remove `build` from the excluded directories.
exclude = ["!**/build/"]

By default, ty ignores files listed in an .ignore or .gitignore file. To disable this functionality, set respect-ignore-files to false.

You may also explicitly pass the paths that ty should check, e.g.:

ty check src scripts/benchmark.py

Paths that are passed as positional arguments to ty check are included even if they would otherwise be ignored through exclude filters or an ignore-file.

Include and exclude syntax

Both include and exclude support gitignore like glob patterns:

  • src/ matches a directory (including its contents) named src.
  • src matches a file or directory (including its contents) named src.
  • * matches any (possibly empty) sequence of characters (except /).
  • ** matches zero or more path components. This sequence must form a single path component, so both ./**a and ./b**/ are invalid and will result in an error. A sequence of more than two consecutive * characters is also invalid.
  • ? matches any single character except /
  • [abc] matches any character inside the brackets. Character sequences can also specify ranges of characters, as ordered by Unicode, so e.g. [0-9] specifies any character between 0 and 9 inclusive. An unclosed bracket is invalid.

All patterns are anchored: The pattern src only includes <project_root>/src but not something like <project_root>/test/src. To include any directory named src, use the prefix match **/src. The same applies for exclude patterns where src only excludes <project_root>/src but not something like <project_root>/test/src.

Note

A prefix include pattern like **/src can notably slow down the Python file discovery.

All fields accepting patterns use the reduced portable glob syntax from PEP 639, with the addition that characters can be escaped with a backslash.

Editor integration

ty can be integrated with various editors to provide a seamless development experience.

VS Code

The Astral team maintains an official VS Code extension.

Install the ty extension from the VS Code Marketplace.

See the extension's README for more details on usage.

Other editors

ty can be used with any editor that supports the language server protocol.

To start the language server, use the server subcommand:

ty server

Refer to your editor's documentation to learn how to connect to an LSP server.

See the editor settings for more details on configuring the language server.

Neovim

For Neovim 0.10 or earlier (with nvim-lspconfig):

require('lspconfig').ty.setup({
  init_options = {
    settings = {
      -- ty language server settings go here
    }
  }
})

For Neovim 0.11+ (with vim.lsp.config):

-- Optional: Only required if you need to update the language server settings
vim.lsp.config('ty', {
  init_options = {
    settings = {
      -- ty language server settings go here
    }
  }
})

-- Required: Enable the language server
vim.lsp.enable('ty')

Rules

Rules are individual checks that ty performs to detect common issues in your code, such as incompatible assignments, missing imports, or invalid type annotations. Each rule focuses on a specific pattern and can be turned on or off depending on your projects needs.

See rules for an enumeration of all supported rules.

Rule levels

Each rule has a configurable level:

  • error: violations are reported as errors and ty exits with an exit code of 1 if there's any.
  • warn: violations are reported as warnings. Depending on your configuration, ty exits with an exit code of 0 if there are only warning violations (default) or 1 when using --error-on-warning.
  • ignore: the rule is turned off

You can configure the level for each rule on the command line using the --warn, --error, and --ignore flags. For example:


ty check \
    --warn unused-ignore-comment \          # Make `unused-ignore-comment` a warning
    --ignore redundant-cast \               # Disable `redundant-cast`
    --error possibly-unbound-attribute \    # Error on `possibly-unbound-attribute`
    --error possibly-unbound-import         # Error on `possibly-unbound-import`

The options can be repeated. Subsequent options override earlier options.

Rule levels can also be changed in the rules section of a configuration file.

For example, the following is equivalent to the command above:

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

Suppressions

Rules can also be ignored in specific locations in your code (instead of disabling the rule entirely) to silence false positives or permissible violations.

Note

To disable a rule entirely, set it to the ignore level as described in rule levels.

ty suppression comments

To suppress a rule violation inline add a # ty: ignore[<rule>] comment at the end of the line:

a = 10 + "test"  # ty: ignore[unsupported-operator]

Rule violations spanning multiple lines can be suppressed by adding the comment at the end of the violation's first or last line:

def add_three(a: int, b: int, c: int): ...

# on the first line

add_three(  # ty: ignore[missing-argument]
    3,
    2
)

# or, on the last line

add_three(
    3,
    2
)  # ty: ignore[missing-argument]

To suppress multiple violations on a single line, enumerate each rule separated by a comma:

add_three("one", 5)  # ty: ignore[missing-argument, invalid-argument-type]

Note

Enumerating rule names (e.g., [rule1, rule2]) is optional. However, we strongly recommend including suppressing specific rules to avoid accidental suppression of other errors.

Standard suppression comments

ty supports the standard type:ignore comment format introduced by PEP 484.

ty handles these similarly to ty: ignore comments, but suppresses all violations on that line, even when type: ignore[code] is used.

# Ignore all typing errors on the next line
add_three("one", 5)  # type: ignore

Unused suppression comments

If the unused-ignore-comment rule is enabled, ty will report unused ty: ignore and type: ignore comments.

unused-ignore-comment violations can only be suppressed using # ty: ignore[unused-ignore-comment]. They cannot be suppressed using # ty: ignore without a rule code or # type: ignore.

@no_type_check directive

ty supports the @no_type_check decorator to suppress all violations inside a function.

from typing import no_type_check

def add_three(a: int, b: int, c: int):
    a + b + c

@no_type_check
def main():
    add_three(3, 4)

Decorating a class with @no_type_check isn't supported.

Configuration

Configuration files

ty supports persistent configuration files at both the project- and user-level.

Specifically, ty will search for a pyproject.toml or ty.toml file in the current directory, or in the nearest parent directory.

If a pyproject.toml file is found, ty will read configuration from the [tool.ty] table. For example, to ignore the index-out-of-bounds rule, add the following to a pyproject.toml:

pyproject.toml:

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

(If there is no tool.ty table, the pyproject.toml file will be ignored, and ty will continue searching in the directory hierarchy.)

ty will also search for ty.toml files, which follow an identical structure, but omit the [tool.ty] prefix. For example:

ty.toml:

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

Note

ty.toml files take precedence over pyproject.toml files, so if both ty.toml and pyproject.toml files are present in a directory, configuration will be read from ty.toml, and the [tool.ty] section in the accompanying pyproject.toml will be ignored.

ty will also discover user-level configuration at ~/.config/ty/ty.toml (or $XDG_CONFIG_HOME/ty/ty.toml) on macOS and Linux, or %APPDATA%\ty\ty.toml on Windows. User-level configuration must use the ty.toml format, rather than the pyproject.toml format, as a pyproject.toml is intended to define a Python project.

If project- and user-level configuration files are found, the settings will be merged, with project-level configuration taking precedence over the user-level configuration.

For example, if a string, number, or boolean is present in both the project- and user-level configuration tables, the project-level value will be used, and the user-level value will be ignored. If an array is present in both tables, the arrays will be merged, with the project-level settings appearing later in the merged array.

Settings provided via command line take precedence over persistent configuration.

See the configuration reference for an enumeration of the available settings.

Exit codes

  • 0 if no violations with severity error or higher were found.
  • 1 if any violations with severity error were found.
  • 2 if ty terminates abnormally due to invalid CLI options.
  • 101 if ty terminates abnormally due to an internal error.

ty supports two command line arguments that change how exit codes work:

  • --exit-zero: ty will exit with 0 even if violations were found.
  • --error-on-warning: ty will exit with 1 if it finds any violations with severity warning or higher.

Reference

For more details, see the reference documentation: