After Ruff and uv, the Astral team is back with another Rust-based tool called ty, short for type check. This new tool delivers a lightning-fast static type-checking experience in Python, aiming to outpace existing tools in both performance and convenience. By incorporating ty into your daily workflow, you’ll catch type-related bugs earlier and get clearer feedback.
But is ty suitable for you? Take a look at the table below to make a quick decision:
| Use Case | Pick ty |
Pick Other Tools |
|---|---|---|
| Development or experimentation | ✅ | ❌ |
| Production use | ❌ | ✅ |
At the time of writing, ty is available as an early preview release with hundreds of open issues. Despite being actively developed and boasting over ten thousand stars on GitHub, it’s still missing essential features and might occasionally fail.
As such, it’s not ready for full adoption in production yet, nor is it going to be a drop-in replacement for any of its competitors. Bugs can take you by surprise in unexpected ways! Additionally, because ty’s implementation is moving fast, some of the information you’ll find in this tutorial may become outdated over time.
If you’d like to get familiar with a new, robust, and promising type checker in your personal projects, then by all means give ty a try! Ready to dive in? Click the link below to grab the sample code you’ll be working with in this tutorial:
Get Your Code: Click here to download the free sample code that you’ll use to learn about Astral’s ty.
Take the Quiz: Test your knowledge with our interactive “Astral's ty Type Checker for Python” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Astral's ty Type Checker for PythonTest your knowledge of Astral's ty—a blazing-fast, Rust-powered Python type checker. You'll cover installation, usage, rule configuration, and the tool's current limitations.
Start Using ty in Python Now
Python is a dynamically typed language, so it requires third-party tools to perform type checking and other kinds of static code analysis. Recently, ty joined the club of external type-checking tools for Python. Despite being created by a private company, Astral, the tool itself remains open source and MIT-licensed.
Although ty is mostly written in Rust, you don’t need the Rust compiler or its execution environment to type check your Python projects with it. To quickly get started with ty, you can install it directly from PyPI with pip, preferably within an activated virtual environment:
(venv) $ python -m pip install ty
As long as you’re on one of the three major operating systems—Windows, macOS, or Linux—this command will bring a hefty binary script called ty into your virtual environment. The script is already compiled to machine code suitable for your platform with all the necessary dependencies baked in, so you can run it directly, just like any other command-line program.
To verify the installation, run the following command in your terminal emulator app:
(venv) $ ty --version
ty 0.0.1-alpha.21
You should see a version number similar to the one above appear in the output. Alternatively, if that doesn’t work, then try to execute ty as a Python module using the interpreter’s -m option:
(venv) $ python -m ty --version
ty 0.0.1-alpha.21
When you do, Python runs a tiny wrapper script that looks for the ty binary executable in your path and invokes it for you.
Note that the pip install command only installs ty into the given virtual environment, which is usually associated with a specific project. To make ty available globally from any folder on your computer, you’ll need to use a different approach. Check out the official documentation for more installation options.
Note: If Visual Studio Code is your code editor of choice, then you’ll benefit from installing the official ty extension. This extension integrates ty directly into VS Code, letting you work without ever touching the command line. Unfortunately, users of PyCharm and other popular IDEs must wait until plugins for their tools catch up.
If your editor supports the Language Server Protocol, then you could leverage the ty server subcommand. For PyCharm, this requires installing the LSP4IJ plugin first, though this tutorial won’t cover its configuration.
Finally, if none of this works for you, then you may want to run the ty check subcommand with the optional --watch switch. This will have ty automatically rerun the checks for instant feedback whenever changes are detected upon saving one of the files in your project.
From now on, you won’t see the virtual environment’s name (venv) in the command prompts for the rest of this tutorial. To keep the code blocks concise, it’ll be assumed that ty is already installed globally and available in your system’s path.
Alright. It’s time for the fun part: letting ty scrutinize some Python code to catch bugs before they sneak in.
Catch Typing Errors With ty
The command-line interface of ty is pretty minimal and straightforward, as you’ll notice when you run ty without providing any subcommands or options:
$ ty
An extremely fast Python type checker.
Usage: ty <COMMAND>
Commands:
check Check a project for type errors
server Start the language server
version Display ty's version
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
The highlighted line indicates the only subcommand you really need to care about: ty check. It runs a number of type checks against your codebase using a comprehensive set of built-in rules, which you can fine-tune later to match your preferences.
To reveal more details about the ty check subcommand, use the --help flag as follows:
$ ty check --help
Check a project for type errors
Usage: ty check [OPTIONS] [PATH]...
Arguments:
[PATH]...
List of files or directories to check [default: the project root]
Options:
--project <PROJECT>
Run the command within the given project directory.
(...)
This displays a ton of options, which might feel a bit intimidating at first. Fortunately, you can ignore all of them for now by relying on ty’s sensible defaults and a clever discovery of Python code. The help page above will become more useful as you gain some experience with ty.
When you run the bare ty check command without any options from the root folder of your project, it’ll recursively scan all the files and directories within that project. For starters, you can try running it against the source code of the popular Django framework to see how ty works in a real-world scenario.
You can use Git to clone Django’s source code from GitHub if you haven’t already. Don’t forget to install Django and its dependencies into a virtual environment afterward:
$ git clone git@github.com:django/django.git
$ cd django/
$ python -m venv .venv/ --prompt django
$ source .venv/bin/activate
(django) $ python -m pip install .
(django) $ deactivate
Now, while you’re still in the top-level django/ folder, run the ty check command as follows:
$ ty check
WARN ty is pre-release software and not ready for production use.
⮑ Expect to encounter bugs, missing features, and fatal errors.
Checking ----------------------------------------------------- 2871/2871 files
(...)
Found 14249 diagnostics
Notice the prominent warning message that ty displays up top, serving as a reminder that this tool isn’t yet suitable for production environments. In this case, ty issued numerous errors and warnings, collectively called diagnostics, which have been omitted for brevity.
By the way, it’s worth appreciating how ty checks 2,871 Python files—averaging 175 lines of code each—in just a few seconds. Some of this time is actually spent printing the diagnostic messages on the screen. When you use ty’s silent mode (-qq), the measured time drops even further:
$ time ty check -qq
real 0m3.804s
user 0m12.224s
sys 0m1.531s
The discrepancy between the real and user times reported by the time command is a good thing. It indicates that ty leverages your multi-core processor architecture for parallel execution.
And here’s what a sample error message displayed by ty looks like by default:
1error[missing-argument]: No arguments provided for required parameters `year`, `month`, `day` of function `__new__`
2 --> django/utils/dateparse.py:78:20
3 |
476 | if match := date_re.match(value):
577 | kw = {k: int(v) for k, v in match.groupdict().items()}
678 | return datetime.date(**kw)
7 | ^^^^^^^^^^^^^^^^^^^
8 |
9info: rule `missing-argument` is enabled by default
On most terminals, this output is colorful and resembles Ruff’s, which ty is based upon. In fact, the new type checker includes Ruff as a submodule on GitHub, meaning much of ty’s core implementation is developed within the Ruff codebase.
The structure of the above error message is the following:
- Line 1 contains the severity level, which can be
error,warning, orinfo, followed by a rule name in square brackets identifying the type of issue. The line ends with a human-readable description. - Line 2 indicates the location consisting of the file path, line number, and column number, which tell you exactly where the issue was found.
- The following lines reveal a line-numbered code snippet, which shows a few surrounding lines of code for context. The caret symbol (^) highlights the exact code segment related to the issue.
- Line 9 contains additional notes, such as why a particular rule was triggered.
Sometimes, this might be too much information shown at once. To reduce the noise, you can tell ty to use a more concise format:
$ ty check --output-format concise
WARN ty is pre-release software and not ready for production use.
⮑ Expect to encounter bugs, missing features, and fatal errors.
Checking ----------------------------------------------------- 2846/2846 files
django/apps/config.py:197:27: error[invalid-argument-type] Argument to function `issubclass` is incorrect: Expected `type`, found `None | (@Todo & ~None) | Unknown`
django/apps/registry.py:87:26: error[not-iterable] Object of type `Unknown | None` may not be iterable
⋮
tests/xor_lookups/tests.py:86:13: error[unresolved-attribute] Type `<class 'Number'>` has no attribute `objects`