A pre-commit hook for running ty quickly over your whole Python project.
When ty is invoked by this hook, dependencies declared in your project's pyproject.toml will automatically be resolvable by ty. This means your project configuration remains the single source of truth: you do not need to duplicate type-checking dependencies in the hook's additional_dependencies setting. Any additional dependencies listed in the hook's additional_dependencies setting will not be resolvable by ty.
Under the hood, the hook runs uv's preview uv check command. Each hook revision pins both the corresponding ty version and the latest uv version that was available when that ty version was released. New ty releases trigger ty-pre-commit releases; new uv releases do not trigger releases on their own. The full uv command invoked by the hook can be found in .pre-commit-hooks.yaml.
Configure ty in your project's pyproject.toml or ty.toml: see ty's configuration reference.
To run ty via pre-commit, add the following to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ty-pre-commit
# ty version.
rev: v0.0.50
hooks:
- id: tyIf you prefer using prek instead of pre-commit, you can define a prek.toml file with your hooks:
[[repos]]
repo = "https://github.com/astral-sh/ty-pre-commit"
rev = "v0.0.50" # ty version.
hooks = [
{ id = "ty" },
]By default, the ty hook uses uv's normal behavior with regards to locking and synchronizing projects. The hook's default behavior may therefore create or update a uv.lock file, create a local virtual environment if one does not exist, and/or install or update dependencies into a local virtual environment.
However, the ty hook accepts all additional arguments accepted by uv check. If you do not want the hook to create or update your project's uv lockfile or local virtual environment, use uv's isolated mode:
hooks:
- id: ty
args: [--isolated]Other options can also be used to further increase the idempotency of the hook, if desired:
hooks:
- id: ty
args: [--isolated, --no-python-downloads, --no-cache]See the uv check reference documentation for an exhaustive list of options available.
Many pre-commit hooks pass a list of all files modified in that commit to the underlying tool. This can be an effective optimization in many cases, as it can allow a hook to only perform checks on the files that changed in that commit.
Unfortunately, this is not a good model for a pre-commit hook that invokes a type checker. The reason is that a commit that only changes a.py can easily cause new diagnostics to appear in b.py, even if the commit made no edits to b.py (b.py might import a.py!). As such, this hook does not pass filenames to ty; instead, ty checks the full project according to your ty configuration. You can customize which files ty emits diagnostics for using the src.include and src.exclude settings in your ty configuration.
Do not try to override this behavior by setting pass_filenames: true in your pre-commit configuration for this hook. uv check does not accept positional arguments, so the hook will error if pre-commit or prek attempts to pass filenames to the hook.
By default, the hook runs on every commit. This ensures that the hook will run even on commits that only delete Python files. However, it also has the drawback that the hook will run even on commits that do not add, modify or delete any Python files. (pre-commit and prek do not provide ways of distinguishing between commits that delete Python files and commits that only delete non-Python files.)
This behavior can be overridden in your pre-commit configuration by setting always_run: false:
hooks:
- id: ty
always_run: falseAs well as your project's base dependencies, uv will also install any dependencies listed in your project's default dependency groups (which includes the dev group). The tool.uv.default-groups pyproject.toml setting can be used to customize your project's default groups.
The hook also accepts uv's standard CLI arguments, which can all be passed as args to further customize uv's behavior here. For example:
hooks:
- id: ty
# to avoid uv installing the `dev` group,
# but ensure that dependencies in the `typechecking` group are installed:
args: [--no-default-groups, --group=typechecking]See the uv check reference documentation for a full list of supported flags.
ty-pre-commit works well with a variety of pre-commit/prek runners in CI. For GitHub Actions, any of the following example jobs should invoke the hook without issue:
pre-commit-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: actions/setup-python@v6.2.0
- uses: pre-commit/action@v3.0.1
prek-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: j178/prek-action@v2.0.4
pre-commit-standalone:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: astral-sh/setup-uv@v8.2.0
- run: uvx pre-commit run --all-files
prek-standalone:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: astral-sh/setup-uv@v8.2.0
- run: uvx prek run --all-filesAny of the above can also be combined with pre-commit-ci-lite to enable autofixes to be pushed to PRs.
Unfortunately, ty-pre-commit does not work with the pre-commit.ci runner. ty-pre-commit requires network access, which is disabled by pre-commit.ci during invocation of hooks. If you use pre-commit.ci as your pre-commit runner in CI, we recommend adding this to your .pre-commit-config.yaml file:
ci:
skip: [ty]and then invoking ty separately in CI -- for example, in GitHub Actions, assuming you have ty pinned in your pyproject.toml file:
ty:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.3
- uses: astral-sh/setup-uv@v8.2.0
- run: uv run ty checkty-pre-commit is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in ty-pre-commit by you, as defined in the Apache-2.0 license, shall be dually licensed as above, without any additional terms or conditions.