File: docs/features/diagnostics.md
Diagnostics
ty provides diagnostics that include snippets of your source code, annotations and helpful
explanations. It will sometimes also provide suggestions on how to fix the reported issues.
Example: Typed dictionaries
In this first example, ty detected an invalid assignment to a TypedDict key. Notice how the
diagnostic includes both the context around the line with the error, as well as the reference to theage item in the TypedDict definition:
When a TypedDict key is misspelled, ty will suggest the correct spelling. If you are using an
editor with language server support, you can also apply this suggestion as a quick fix:
Example: Invalid arguments
Here, a file has been opened for writing in text mode, but we are trying to write bytes to it.
The diagnostic points out the type mismatch and also includes the corresponding parameter in the
function definition for write:
Example: Backwards compatibility
Instead of just telling you that tomllib can not be found, ty will tell you why it is not
available for your project. In this case, your project is targeting Python 3.10, but tomllib was
only added in Python 3.11:
File: docs/features/language-server.md
Language server
You can generally expect ty to be a fully-featured language server for Python.
This page describes some of the key features provided by ty's IDE integration and includes
a reference table of supported LSP features at the end.
See the editor integration guide for instructions on how to set up ty
with your editor.
Diagnostics
ty reports type errors and other diagnostics directly in your editor. Diagnostics
are updated as you type. You can use thediagnosticMode setting to control if you want to
see diagnostics for open files only, or for your entire workspace.
!!! info
ty supports both the "pull" and "push" diagnostic models. Most modern editors will use the "pull" model
for better performance, where diagnostics are fetched on demand rather than pushed after every
change.Code navigation
ty powers several language server features that allow you to navigate a Python codebase:
- Go to Definition: Jump to where a symbol is defined. ty resolves imports, function calls,
class references, and more. - Go to Declaration: Navigate to the declaration site of a symbol, which can differ from its
definition (could be in a stub file). - Go to Type Definition: Navigate to the type of a symbol. For example, this takes you to the class
Person
when invoked on a variableuser: Person. - Go to Implementation: Find known implementations of a class or class member, including subclasses
and method overrides. - Find all references: Find every usage of a function, class, or variable across your entire workspace.
- Document and workspace symbols: See an outline of symbols in the current file, or search through symbols across your entire workspace.
Code completions
ty provides intelligent code completions as you type, offering suggestions for variables, functions, classes, and modules that are in scope.
For symbols that are not yet imported, ty suggests auto-import actions to add the necessary import statements.
Code actions and refactorings
ty offers quick fixes and other code actions to help you resolve issues:
- Add import: Automatically add missing import statements
- Quick fixes: Some diagnostics come with quick fix suggestions to resolve the issue
- Rename symbol: Safely rename symbols across your entire codebase
- Selection range: Expand or shrink the text selection in your editor based on ty's understanding of Python syntax
Contextual information
ty surfaces useful contextual information as you code:
- Hover: Hover over any symbol to see its type, documentation, function signatures, and other
useful information like the variance of type parameters. - Inlay hints: Display inline type hints for variables without explicit annotations, as well as
parameter names at call sites. Type hints can also be double-clicked
to insert the type annotations into your source code. You can also click on parts of the inlay
hints for go-to-definition navigation. - Signature help: When calling a function, ty displays the function's parameters and their
types. This appears automatically when you type(and updates as you navigate between arguments. - Document highlight: When the cursor is on a symbol, ty highlights all occurrences of that
symbol in the current file. - Semantic highlighting: Syntax highlighting based on the underlying semantics and types.
Code folding
ty provides Python specific code folding ranges to LSP clients upon request. This includes tagging
docstrings as comments, which supports editor actions like "fold all comment blocks."
Notebook support
ty supports Jupyter notebooks (.ipynb files) with language server features. Each cell is
analyzed in context, with diagnostics, completions, and other features working across cells.
Fine-grained incrementality
ty's architecture is designed for low-latency updates of diagnostics and other language server features.
When you make a change in your editor, ty incrementally updates only the affected parts of the
codebase, rather than re-analyzing everything from scratch. This happens at a fine-grained level,
down to individual definitions. This incrementality means that you get instant feedback as you type, i.e.,
within a few milliseconds, even on large projects.
!!! info
Fine-grained dependencies also allow ty to skip large parts of 3rd-party dependencies when they are not relevant
to your codebase.Feature reference
LSP extensions
ty also supports various nonstandard extensions to the Language Server Protocol. These extensions are a best-effort contract between the server and its clients; when in doubt, consult the implementation.
Client capabilities for these extensions are advertised through the experimental field of ClientCapabilities.
Full diagnostic output
Experimental client capability: { "fullDiagnosticOutput": boolean }
When this capability is true, ty includes a human-readable multiline rendering of a diagnostic in the diagnostic's data field. The rendering uses only ANSI Select Graphic Rendition (SGR) escape sequences for color and text styling; clients are expected to interpret or strip these sequences before displaying the output.
interface Diagnostic {
// Standard LSP fields omitted.
data?: {
/** A human-readable multiline rendering of the diagnostic, including ANSI SGR styles. */
rendered?: string;
/** The original ty diagnostic identifier, such as `invalid-argument-type`. */
diagnostic_id?: string;
// Other ty-specific fields may also be present.
};
}For diagnostics that support this extension, rendered and diagnostic_id are either both present or both absent. Clients may use diagnostic_id to preserve the original identifier if they replace Diagnostic.code with a link to the rendered output. Clients must preserve Diagnostic.data when returning a diagnostic in a textDocument/codeAction request so that code actions continue to work.
File: docs/features/type-system.md
Type system
You can generally expect ty to support all typing features that are described and specified in the
Python typing documentation (for a detailed overview, please refer to the
type system features tracking issue). This page
highlights some of the unique features that ty's type system provides.
Redeclarations
ty allows you to reuse the same symbol with a different type. The following example shows how thepaths parameter is redeclared as a list of strings:
def split_paths(paths: str) -> list[Path]:
paths: list[str] = paths.split(":")
return [Path(p) for p in paths](Full example in the playground)
Intersection types
ty has first-class support for intersection types. In contrast to a union type A | B, which means
"either A or B", an intersection type A & B means "both A and B". Type narrowing in ty is
based on intersections. For example, notice how we can call obj.serialize_json() and access the.version property in the following function:
def output_as_json(obj: Serializable) -> str:
if isinstance(obj, Versioned):
reveal_type(obj) # reveals: Serializable & Versioned
return str({"data": obj.serialize_json(), "version": obj.version})
else:
return obj.serialize_json()(Full example in the playground)
Intersections can also be built using gradual types like Any or its implicit counterpartUnknown. For example, imagine you call into untyped (third party) code that returns an object of
type Unknown. Narrowing the type of that object using isinstance will result in an intersection
type Unknown & Iterable. This type allows you to use obj as an iterable. But more importantly,
it still gives you access to attributes defined on the original unknown type (.description, in this
example):
def print_content(data: bytes):
obj = untyped_library.deserialize(data)
if isinstance(obj, Iterable):
print(obj.description)
for part in obj:
print("*", part.description)
else:
print(obj.description)(Full example in the playground)
Intersection types are also used in hasattr narrowing. Take a look at the following example where
we narrow a type of Person | Animal | None using hasattr(โฆ, "name"). Person is preserved in
the narrowed union type because it has a name attribute. Animal is intersected with a synthetic
protocol, accounting for the possibility of subclasses of Animal that add a name member.None is excluded completely since it is a final type that has no name attribute:
class Person:
name: str
class Animal:
species: str
def greet(being: Person | Animal | None):
if hasattr(being, "name"):
# `being` is now of type `Person | (Animal & <Protocol with members 'name'>)`
print(f"Hello, {being.name}!")
else:
print("Hello there!")(Full example in the playground)
!!! info
If you run into a situation like this and would like `Animal` to be excluded from the narrowed
type as well, you can make `Animal` a `@final` class. This also allows ty to infer a more precise
type for `being.name` (`str` instead of `object`).If ty is the only type checker you use, you can also make direct use of intersection types in
annotations by importing Intersection from the special ty_extensions module that is (currently)
only available at type-checking time:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ty_extensions import Intersection
type SerializableVersioned = Intersection[Serializable, Versioned]
def output_as_json(obj: SerializableVersioned) -> str: ...(Full example in the playground)
Top and bottom materializations
Gradual types generally have two special materializations. The top materialization represents the
"largest" type that a gradual type can materialize to: the union of all possible materializations.
For example, the top materialization of Any is object, and the top materialization ofAny & int is int. For invariant generic classes, the top materialization cannot be expressed in
Python's type system, but it is a useful type that ty intersects with when isinstance checks
involve generic classes (when analysis.strict-generic-narrowing
is enabled). For example, when checking isinstance(โฆ, list), ty intersects with the top materialization
of list[Unknown]:
@final
class Item: ...
def process(items: Item | list[Item]):
if isinstance(items, list):
# reveals: list[Item]
reveal_type(items)(Full example in the playground)
!!! info
You might wonder why `Item` is declared `@final` here. If we remove the `@final` decorator, the
inferred type in the `if` branch becomes `(Item & Top[list[Unknown]]) | list[Item]` instead.
This accounts for the possibility of classes that inherit from both `Item` *and* `list`! If
you run into this situation and want to rule out this case, you can also perform the `isinstance`
check against `Item` instead. The `else` branch will then have a narrowed type of
`list[Item] & ~Item`, which effectively acts like `list[Item]`.Reachability based on types
Reachability analysis in ty is based on type inference. This allows ty to detect unreachable
branches in many more situations compared to approaches which match on a few known patterns (e.g.sys.version_info >= (3, 10) checks). This has useful practical applications. Consider a case
where you are writing code that needs to be compatible with two major versions of a dependency.
The following code can be successfully type-checked with either pydantic 1.x installed, or pydantic
2.x installed. In both cases, ty will only consider the corresponding branch to be reachable, and
will not emit any type errors for the other branch. This works becausepydantic.__version__.startswith("2.") can be evaluated to True or False at type-checking time:
import pydantic
from pydantic import BaseModel
PYDANTIC_V2 = pydantic.__version__.startswith("2.")
class Person(BaseModel):
name: str
def to_json(person: Person):
if PYDANTIC_V2:
return person.model_dump_json() # no error here when checking with 1.x
else:
return person.json()(Full example in the playground)
File: docs/reference/cli.md
CLI Reference
ty
An extremely fast Python type checker.
Usage
ty <COMMAND>Commands
- [`ty check`](#ty-check)
- Check a project for type errors
- [`ty server`](#ty-server)
- Start the language server
- [`ty version`](#ty-version)
- Display ty's version
- [`ty explain`](#ty-explain)
- Explain rules and other parts of ty
- [`ty help`](#ty-help)
- Print this message or the help of the given subcommand(s)
ty check
Check a project for type errors
Usage
ty check [OPTIONS] [PATH]...Arguments
- [`PATHS`](#ty-check--paths)
- List of files or directories to check [default: the project root]
Options
- [`--add-ignore`](#ty-check--add-ignore)
- Adds `ty: ignore` comments to suppress all rule diagnostics
- [`--color`](#ty-check--color) *when*
- Control when colored output is used
Possible values:
- `auto`: Display colors if the output goes to an interactive terminal
- `always`: Always display colors
- `never`: Never display colors
- [`--config`](#ty-check--config), `-c` *config-option*
- A TOML `<KEY> = <VALUE>` pair (such as you might find in a `ty.toml` configuration file) overriding a specific configuration option. Overrides of individual settings using this option always take precedence over all configuration files.
- [`--config-file`](#ty-check--config-file) *path*
- The path to a `ty.toml` file to use for configuration. While ty configuration can be included in a `pyproject.toml` file, it is not allowed in this context. May also be set with the `TY_CONFIG_FILE` environment variable.
- [`--error`](#ty-check--error) *rule*
- Treat the given rule as having severity 'error'. Can be specified multiple times. Use 'all' to apply to all rules.
- [`--error-on-warning`](#ty-check--error-on-warning)
- Use exit code 1 if there are any warning-level diagnostics. Cannot be used in combination with `--exit-zero` or `--exit-zero-on-warning`.
- [`--exclude`](#ty-check--exclude) *exclude*
- Glob patterns for files to exclude from type checking. Uses gitignore-style syntax to exclude files and directories from type checking. Supports patterns like `tests/`, `*.tmp`, `**/__pycache__/**`.
- [`--exclude-scripts`](#ty-check--exclude-scripts)
- Exclude files containing PEP 723 inline script metadata unless passed explicitly. Use `--include-scripts` to disable
- [`--exit-zero`](#ty-check--exit-zero)
- Always use exit code 0, even when there are error-level diagnostics. Cannot be used in combination with `--error-on-warning`.
- [`--exit-zero-on-warning`](#ty-check--exit-zero-on-warning)
- Use exit code 0 if there are no error-level diagnostics. Cannot be used in combination with `--error-on-warning`.
- [`--extra-search-path`](#ty-check--extra-search-path) *path*
- Additional path to use as a module-resolution source (can be passed multiple times). This is an advanced option that should usually only be used for first-party or third-party modules that are not installed into your Python environment in a conventional way. Use `--python` to point ty to your Python environment if it is in an unusual location.
- [`--fix`](#ty-check--fix)
- Apply fixes to resolve errors
- [`--force-exclude`](#ty-check--force-exclude)
- Enforce exclusions, even for paths passed to ty directly on the command-line. Use `--no-force-exclude` to disable
- [`--help`](#ty-check--help), `-h`
- Print help (see a summary with '-h')
- [`--ignore`](#ty-check--ignore) *rule*
- Disables the rule. Can be specified multiple times. Use 'all' to apply to all rules.
- [`--no-progress`](#ty-check--no-progress)
- Hide all progress outputs. For example, spinners or progress bars.
- [`--output-format`](#ty-check--output-format) *output-format*
- The format to use for printing diagnostic messages
May also be set with the `TY_OUTPUT_FORMAT` environment variable.Possible values:
- `full`: Print diagnostics verbosely, with context and helpful hints (default)
- `concise`: Print diagnostics concisely, one per line
- `gitlab`: Print diagnostics in the JSON format expected by GitLab Code Quality reports
- `github`: Print diagnostics in the format used by GitHub Actions workflow error annotations
- `junit`: Print diagnostics as a JUnit-style XML report
- [`--project`](#ty-check--project) *project*
- Run the command within the given project directory. All `pyproject.toml` files will be discovered by walking up the directory tree from the given project directory, as will the project's virtual environment (`.venv`) unless the `venv-path` option is set. Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.
- [`--python`](#ty-check--python), `--venv` *path*
- Path to your project's Python environment or interpreter.
ty uses your Python environment to resolve third-party imports in your code.
This can be a path to:
- A Python interpreter, e.g. `.venv/bin/python3` - A virtual environment directory, e.g. `.venv` - A system Python [`sys.prefix`](https://docs.python.org/3/library/sys.html#sys.prefix) directory, e.g. `/usr`
If you're using a project management tool such as uv or you have an activated Conda or virtual environment, you should not generally need to specify this option.
- [`--python-platform`](#ty-check--python-platform), `--platform` *platform*
- Target platform to assume when resolving types. This is used to specialize the type of `sys.platform` and will affect the visibility of platform-specific functions and attributes. If the value is set to `all`, no assumptions are made about the target platform. If unspecified, the current system's platform will be used.
- [`--python-version`](#ty-check--python-version), `--target-version` *version*
- Python version to assume when resolving types.
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.
If a version is not specified on the command line or in a configuration file, ty will try the following techniques in order of preference to determine a value: 1. Check for the `project.requires-python` setting in a `pyproject.toml` file and use the minimum version from the specified range 2. Check for an activated or configured Python environment and attempt to infer the Python version of that environment 3. Fall back to the latest stable Python version supported by ty (see `ty check --help` output)
Possible values:
- `3.7`
- `3.8`
- `3.9`
- `3.10`
- `3.11`
- `3.12`
- `3.13`
- `3.14`
- `3.15`
- [`--quiet`](#ty-check--quiet), `-q`
- Use quiet output (or `-qq` for silent output)
- [`--respect-ignore-files`](#ty-check--respect-ignore-files)
- Respect file exclusions via `.gitignore` and other standard ignore files. Use `--no-respect-ignore-files` to disable
- [`--typeshed`](#ty-check--typeshed), `--custom-typeshed-dir` *path*
- Custom directory to use for stdlib typeshed stubs
- [`--verbose`](#ty-check--verbose), `-v`
- Use verbose output (or `-vv` and `-vvv` for more verbose output)
- [`--warn`](#ty-check--warn) *rule*
- Treat the given rule as having severity 'warn'. Can be specified multiple times. Use 'all' to apply to all rules.
- [`--watch`](#ty-check--watch), `-W`
- Watch files for changes and recheck files related to the changed files
ty server
Start the language server
Usage
ty serverOptions
- [`--help`](#ty-server--help), `-h`
- Print help
ty version
Display ty's version
Usage
ty version [OPTIONS]Options
- [`--help`](#ty-version--help), `-h`
- Print help
- [`--output-format`](#ty-version--output-format) *output-format*
- The format in which to display the version information
[default: text]Possible values:
- `text`
- `json`
ty generate-shell-completion
Generate shell completion
Usage
ty generate-shell-completion <SHELL>Arguments
- [`SHELL`](#ty-generate-shell-completion--shell)
Options
- [`--help`](#ty-generate-shell-completion--help), `-h`
- Print help
ty explain
Explain rules and other parts of ty
Usage
ty explain <COMMAND>Commands
- [`ty explain rule`](#ty-explain-rule)
- Explain a rule (or all rules)
- [`ty explain help`](#ty-explain-help)
- Print this message or the help of the given subcommand(s)
ty explain rule
Explain a rule (or all rules)
Usage
ty explain rule [OPTIONS] [RULE]Arguments
- [`RULE`](#ty-explain-rule--rule)
- Rule to explain Defaults to all rules if omitted.
Options
- [`--help`](#ty-explain-rule--help), `-h`
- Print help (see a summary with '-h')
- [`--output-format`](#ty-explain-rule--output-format) *output-format*
- Output format
[default: text]Possible values:
- `text`
- `json`
ty explain help
Print this message or the help of the given subcommand(s)
Usage
ty explain help [COMMAND]ty help
Print this message or the help of the given subcommand(s)
Usage
ty help [COMMAND]File: docs/reference/configuration.md
Configuration
`rules`
Configures the enabled rules and their severity.
The keys are either rule names or all to set a default severity for all rules.
See the rules documentation for a list of all available rules.
Valid severities are:
ignore: Disable the rule.warn: Enable the rule and create a warning diagnostic.error: Enable the rule and create an error diagnostic.
By default, ty exits with code 1 if it emits any warning or error diagnostics.
Set terminal.error-on-warning to false to exit with code 0 if all diagnostics have warning severity.
Default value: {...}
Type: dict[RuleName | "all", "ignore" | "warn" | "error"]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.rules]
possibly-unresolved-reference = "warn"
division-by-zero = "ignore"
```=== "ty.toml"
```toml
[rules]
possibly-unresolved-reference = "warn"
division-by-zero = "ignore"
````analysis`
`allowed-unresolved-imports`
A list of module glob patterns for which unresolved-import diagnostics should be suppressed.
Details on supported glob patterns:
*matches zero or more characters except.. For example,foo.*matchesfoo.barbut
notfoo.bar.baz;foo*matchesfooandfoobarbut notfoo.barorbarfoo; and*foo
matchesfooandbarfoobut notfoo.barorfoobar.**matches any number of module components (e.g.,foo.**matchesfoo,foo.bar, etc.)- Prefix a pattern with
!to exclude matching modules
When multiple patterns match, later entries take precedence.
Glob patterns can be used in combinations with each other. For example, to suppress errors for
any module where the first component contains the substring test, use *test*.**.
Default value: []
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
# Suppress errors for all `test` modules except `test.foo`
allowed-unresolved-imports = ["test.**", "!test.foo"]
```=== "ty.toml"
```toml
[analysis]
# Suppress errors for all `test` modules except `test.foo`
allowed-unresolved-imports = ["test.**", "!test.foo"]
````replace-imports-with-any`
A list of module glob patterns whose imports should be replaced with typing.Any.
Unlike allowed-unresolved-imports, this setting replaces the module's type information
with typing.Any even if the module can be resolved. Import diagnostics are
unconditionally suppressed for matching modules.
- Prefix a pattern with
!to exclude matching modules
When multiple patterns match, later entries take precedence.
Glob patterns can be used in combinations with each other. For example, to suppress errors for
any module where the first component contains the substring test, use *test*.**.
When multiple patterns match, later entries take precedence.
Default value: []
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
# Replace all pandas and numpy imports with Any
replace-imports-with-any = ["pandas.**", "numpy.**"]
```=== "ty.toml"
```toml
[analysis]
# Replace all pandas and numpy imports with Any
replace-imports-with-any = ["pandas.**", "numpy.**"]
````respect-type-ignore-comments`
Whether ty should respect type: ignore comments.
When set to false, type: ignore comments are treated like any other normal
comment and can't be used to suppress ty errors (you have to use ty: ignore instead).
Setting this option can be useful when using ty alongside other type checkers or when
you prefer using ty: ignore over type: ignore.
Defaults to true.
Default value: true
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
# Disable support for `type: ignore` comments
respect-type-ignore-comments = false
```=== "ty.toml"
```toml
[analysis]
# Disable support for `type: ignore` comments
respect-type-ignore-comments = false
````return-type-inference`
This setting controls when ty infers return types for functions without an explicit
return type annotation.
"never": Do not infer return types from function bodies. Unannotated functions
will have an inferred return type ofUnknown."always": Infer return types for unannotated functions and methods.
Enabling return type inference will never override explicit return type annotations.
Lambda functions are not affected by this setting and their return type will always
be inferred.
Return types for generator functions and asynchronous functions are currently not
inferred, but we plan to change this soon.
Functions in stubs and if TYPE_CHECKING blocks are never considered for return type
inference.
Default value: "never"
Type: "never" | "always"
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
return-type-inference = "always"
```=== "ty.toml"
```toml
[analysis]
return-type-inference = "always"
````strict-equality-semantics`
Configure ty's behavior regarding type inference and narrowing of equality
checks. Defaults to false.
By default, ty makes various assumptions about equality checks that match the
intuitions of most Python programmers, but may not be fully sound in all situations.
Enabling this option makes ty more conservative about these assumptions, making it
less likely to infer Literal[True] or Literal[False] as the result of an
equality check. This has various effects on type checking, including fewer type
narrowing opportunities and more conservative assumptions regarding control flow.
One way in which ty will by default make unsound assumptions is by narrowing an
object x of type str to Literal["a"] after an if x == "a" check. This is
unsound because a subclass of str with value "a" will (by default) compare equal
to "a", but will not be of type Literal["a"]:
>>> # `Literal["a"]` can only be inhabited by instances of exactly `str`, not
>>> # subclasses, but str subclasses compare equal by default:
>>> class StringSubclass(str): ...
...
>>> StringSubclass("a") == "a"
True
>>>
>>> # This also applies to `StrEnum`s:
>>> from enum import StrEnum
>>> class MyEnum(StrEnum):
... A = "a"
...
>>> MyEnum.A == "a"
TrueEnabling this option prevents the unsound narrowing of x to Literal["a"],
and instead keeps it as str:
from typing import Literal
def parse(value: str) -> Literal["a"] | None:
# with `strict-equality-semantics = true`, no narrowing will occur here,
# and an error will be emitted on the `return` statement.
if value == "a":
return value
return NoneAnother assumption ty makes by default is that subclasses will never override __eq__ or__ne__. This allows ty to narrow the following union based on an equality check, despite
the fact that an instance of a subclass of Foo could compare equal to None, and it's
perfectly valid to pass an instance of a subclass into the x parameter of this function:
def narrow(x: Foo | None, other: Foo) -> None:
if x == other:
# with this option enabled, `x` will still have type `Foo | None` here,
# since it is legal to subclass `Foo` and override its `__eq__` method.
reveal_type(x)Many operations in Python implicitly call __eq__ under the hood; enabling this option
will also impact those operations. For example, this option will also impact narrowing fromin checks, and narrowing in match statements that use value patterns:
def narrow_in(x: Foo | None, other: list[Foo]) -> None:
if x in other:
# with this option enabled, `x` will still have type `Foo | None` here,
# since the `in` operator implicitly calls `__eq__` on each element of `other`.
reveal_type(x)
def narrow_match(x: str) -> None:
match x:
case "a":
# with this option enabled, `x` will still have type `str` here,
# since this `case` branch will be taken by any object that compares
# equal to `"a"`, including subclasses of `str`.
reveal_type(x)Default value: false
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
# Preserve broad builtin types instead of narrowing them to literals
strict-equality-semantics = true
```=== "ty.toml"
```toml
[analysis]
# Preserve broad builtin types instead of narrowing them to literals
strict-equality-semantics = true
````strict-generic-narrowing`
Whether ty should use strict narrowing for unspecialized generic classes inisinstance() and issubclass() checks, match class patterns, and TypeIs checks.
When enabled, ty narrows to the top materialization of the class. For example,isinstance(value, list) narrows a value of type object to Top[list[Unknown]],
representing the (infinite) union of all possible list specializations. Iterating
over the list would yield values of type object.
When disabled, ty uses gradual generic narrowing, preserving compatible type
arguments from the original type where possible. For example,isinstance(value, list) narrows a value of type Sequence[int] to list[int].
If no specialization is available, the same check narrows a value of type object
to list[Unknown]; items of any type can then be appended to the list. Class
patterns such as case list(): follow the same behavior.
Defaults to false.
Default value: false
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.analysis]
# Use the top materialization when narrowing to an unspecialized generic class
strict-generic-narrowing = true
```=== "ty.toml"
```toml
[analysis]
# Use the top materialization when narrowing to an unspecialized generic class
strict-generic-narrowing = true
````environment`
`extra-paths`
User-provided paths that should take first priority in module resolution.
This is an advanced option that should usually only be used for first-party or third-party
modules that are not installed into your Python environment in a conventional way.
Use the python option to specify the location of your Python environment.
This option is similar to mypy's MYPYPATH environment variable and pyright's stubPath
configuration setting.
Default value: []
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
extra-paths = ["./shared/my-search-path"]
```=== "ty.toml"
```toml
[environment]
extra-paths = ["./shared/my-search-path"]
````python`
Path to your project's Python environment or interpreter.
ty uses the site-packages directory of your project's Python environment
to resolve third-party (and, in some cases, first-party) imports in your code.
This can be a path to:
- A Python interpreter, e.g.
.venv/bin/python3 - A virtual environment directory, e.g.
.venv - A system Python
sys.prefixdirectory, e.g./usr
If you're using a project management tool such as uv, you should not generally need to
specify this option, as commands such as uv run will set the VIRTUAL_ENV environment
variable to point to your project's virtual environment. ty can also infer the location of
your environment from an activated Conda environment, and will look for a .venv directory
in the project root if none of the above apply. Failing that, ty will look for a python3
or python binary available in PATH.
Scripts with inline metadata use their own Python environment. They can use an explicitly
configured environment, an activated environment, or an environment selected by the editor.
Unlike projects, they do not automatically use a .venv directory.
Default value: null
Type: str
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
python = "./custom-venv-location/.venv"
```=== "ty.toml"
```toml
[environment]
python = "./custom-venv-location/.venv"
````python-platform`
Specifies the target platform that will be used to analyze the source code.
If specified, ty will understand conditions based on comparisons with sys.platform, such
as are commonly found in typeshed to reflect the differing contents of the standard library across platforms.
If all is specified, ty will assume that the source code can run on any platform.
If no platform is specified, ty will use the current platform:
win32for Windowsdarwinfor macOSandroidfor Androidiosfor iOSlinuxfor everything else
Default value: <current-platform>
Type: "win32" | "darwin" | "android" | "ios" | "linux" | "all" | str
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
# Tailor type stubs and conditionalized type definitions to windows.
python-platform = "win32"
```=== "ty.toml"
```toml
[environment]
# Tailor type stubs and conditionalized type definitions to windows.
python-platform = "win32"
````python-version`
Specifies the version of Python that will be used to analyze the source code.
The version should be specified as a string in the format M.m where M is the major version
and m is the minor (e.g. "3.7" or "3.12").
If a version is provided, ty will generate errors if the source code makes use of language features
that are not supported in that version.
ty officially supports type checking code that targets Python 3.10 and later. Python 3.7
through 3.9 can still be selected, but ty may produce false positives or false negatives for
standard-library APIs because its bundled stubs do not fully describe those versions.
If a version is not specified, ty will try the following techniques in order of preference
to determine a value:
- Check for the
project.requires-pythonsetting in apyproject.tomlfile
and use the minimum version from the specified range - Check for an activated or configured Python environment
and attempt to infer the Python version of that environment - Fall back to the default value (see below)
Scripts with inline metadata use their requires-python field instead ofproject.requires-python. They do not inherit the Python version of the enclosing project.
For some language features, ty can also understand conditionals based on comparisons
with sys.version_info. These are commonly found in typeshed, for example,
to reflect the differing contents of the standard library across Python versions.
Default value: "3.15"
Type: "3.7" | "3.8" | "3.9" | "3.10" | "3.11" | "3.12" | "3.13" | "3.14" | "3.15"
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
python-version = "3.12"
```=== "ty.toml"
```toml
[environment]
python-version = "3.12"
````root`
The root paths of the project, used for finding first-party modules.
Accepts a list of directory paths searched in priority order (first has highest priority).
If left unspecified, ty will try to detect common project layouts and initialize root accordingly.
The project root (.) is always included. Additionally, the following directories are included
if they exist and are not packages (i.e. they do not contain __init__.py or __init__.pyi files):
./src./(if a.//directory exists)./python
Scripts with inline metadata have no first-party roots by default because they are
single-file programs. Set root = ["."] to allow importing local modules.
Default value: null
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
# Multiple directories (priority order)
root = ["./src", "./lib", "./vendor"]
```=== "ty.toml"
```toml
[environment]
# Multiple directories (priority order)
root = ["./src", "./lib", "./vendor"]
````typeshed`
Optional path to a "typeshed" directory on disk for us to use for standard-library types.
If this is not provided, we will fallback to our vendored typeshed stubs for the stdlib,
bundled as a zip file in the binary
Default value: null
Type: str
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.environment]
typeshed = "/path/to/custom/typeshed"
```=== "ty.toml"
```toml
[environment]
typeshed = "/path/to/custom/typeshed"
````overrides`
Configuration override that applies to specific files based on glob patterns.
An override allows you to apply different rule configurations to specific
files or directories. Multiple overrides can match the same file, with
later overrides take precedence. Override rules take precedence over global
rules for matching files.
For example, to relax enforcement of rules in test files:
[[tool.ty.overrides]]
include = ["tests/**", "**/test_*.py"]
[tool.ty.overrides.rules]
possibly-unresolved-reference = "warn"Or, to ignore a rule in generated files but retain enforcement in an important file:
[[tool.ty.overrides]]
include = ["generated/**"]
exclude = ["generated/important.py"]
[tool.ty.overrides.rules]
possibly-unresolved-reference = "ignore"`exclude`
A list of file and directory patterns to exclude from this override.
Patterns follow a syntax similar to .gitignore.
Exclude patterns take precedence over include patterns within the same override.
If not specified, defaults to [] (excludes no files).
Default value: null
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
exclude = [
"generated",
"*.proto",
"tests/fixtures/**",
"!tests/fixtures/important.py" # Include this one file
]
```=== "ty.toml"
```toml
[[overrides]]
exclude = [
"generated",
"*.proto",
"tests/fixtures/**",
"!tests/fixtures/important.py" # Include this one file
]
````include`
A list of file and directory patterns to include for this override.
The include option follows a similar syntax to .gitignore but reversed:
Including a file or directory will make it so that it (and its contents)
are affected by this override.
If not specified, defaults to ["**"] (matches all files).
Default value: null
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = [
"src",
"tests",
]
```=== "ty.toml"
```toml
[[overrides]]
include = [
"src",
"tests",
]
````rules`
Rule overrides for files matching the include/exclude patterns.
These rules will be merged with the global rules, with override rules
taking precedence for matching files. You can set rules to different
severity levels or disable them entirely.
Default value: {...}
Type: dict[RuleName | "all", "ignore" | "warn" | "error"]
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.rules]
possibly-unresolved-reference = "ignore"
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.rules]
possibly-unresolved-reference = "ignore"
````overrides.analysis`
`allowed-unresolved-imports`
A list of module glob patterns for which unresolved-import diagnostics should be suppressed.
Details on supported glob patterns:
*matches zero or more characters except.. For example,foo.*matchesfoo.barbut
notfoo.bar.baz;foo*matchesfooandfoobarbut notfoo.barorbarfoo; and*foo
matchesfooandbarfoobut notfoo.barorfoobar.**matches any number of module components (e.g.,foo.**matchesfoo,foo.bar, etc.)- Prefix a pattern with
!to exclude matching modules
When multiple patterns match, later entries take precedence.
Glob patterns can be used in combinations with each other. For example, to suppress errors for
any module where the first component contains the substring test, use *test*.**.
Default value: []
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
# Suppress errors for all `test` modules except `test.foo`
allowed-unresolved-imports = ["test.**", "!test.foo"]
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
# Suppress errors for all `test` modules except `test.foo`
allowed-unresolved-imports = ["test.**", "!test.foo"]
````replace-imports-with-any`
A list of module glob patterns whose imports should be replaced with typing.Any.
Unlike allowed-unresolved-imports, this setting replaces the module's type information
with typing.Any even if the module can be resolved. Import diagnostics are
unconditionally suppressed for matching modules.
- Prefix a pattern with
!to exclude matching modules
When multiple patterns match, later entries take precedence.
Glob patterns can be used in combinations with each other. For example, to suppress errors for
any module where the first component contains the substring test, use *test*.**.
When multiple patterns match, later entries take precedence.
Default value: []
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
# Replace all pandas and numpy imports with Any
replace-imports-with-any = ["pandas.**", "numpy.**"]
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
# Replace all pandas and numpy imports with Any
replace-imports-with-any = ["pandas.**", "numpy.**"]
````respect-type-ignore-comments`
Whether ty should respect type: ignore comments.
When set to false, type: ignore comments are treated like any other normal
comment and can't be used to suppress ty errors (you have to use ty: ignore instead).
Setting this option can be useful when using ty alongside other type checkers or when
you prefer using ty: ignore over type: ignore.
Defaults to true.
Default value: true
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
# Disable support for `type: ignore` comments
respect-type-ignore-comments = false
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
# Disable support for `type: ignore` comments
respect-type-ignore-comments = false
````return-type-inference`
This setting controls when ty infers return types for functions without an explicit
return type annotation.
"never": Do not infer return types from function bodies. Unannotated functions
will have an inferred return type ofUnknown."always": Infer return types for unannotated functions and methods.
Enabling return type inference will never override explicit return type annotations.
Lambda functions are not affected by this setting and their return type will always
be inferred.
Return types for generator functions and asynchronous functions are currently not
inferred, but we plan to change this soon.
Functions in stubs and if TYPE_CHECKING blocks are never considered for return type
inference.
Default value: "never"
Type: "never" | "always"
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
return-type-inference = "always"
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
return-type-inference = "always"
````strict-equality-semantics`
Configure ty's behavior regarding type inference and narrowing of equality
checks. Defaults to false.
By default, ty makes various assumptions about equality checks that match the
intuitions of most Python programmers, but may not be fully sound in all situations.
Enabling this option makes ty more conservative about these assumptions, making it
less likely to infer Literal[True] or Literal[False] as the result of an
equality check. This has various effects on type checking, including fewer type
narrowing opportunities and more conservative assumptions regarding control flow.
One way in which ty will by default make unsound assumptions is by narrowing an
object x of type str to Literal["a"] after an if x == "a" check. This is
unsound because a subclass of str with value "a" will (by default) compare equal
to "a", but will not be of type Literal["a"]:
>>> # `Literal["a"]` can only be inhabited by instances of exactly `str`, not
>>> # subclasses, but str subclasses compare equal by default:
>>> class StringSubclass(str): ...
...
>>> StringSubclass("a") == "a"
True
>>>
>>> # This also applies to `StrEnum`s:
>>> from enum import StrEnum
>>> class MyEnum(StrEnum):
... A = "a"
...
>>> MyEnum.A == "a"
TrueEnabling this option prevents the unsound narrowing of x to Literal["a"],
and instead keeps it as str:
from typing import Literal
def parse(value: str) -> Literal["a"] | None:
# with `strict-equality-semantics = true`, no narrowing will occur here,
# and an error will be emitted on the `return` statement.
if value == "a":
return value
return NoneAnother assumption ty makes by default is that subclasses will never override __eq__ or__ne__. This allows ty to narrow the following union based on an equality check, despite
the fact that an instance of a subclass of Foo could compare equal to None, and it's
perfectly valid to pass an instance of a subclass into the x parameter of this function:
def narrow(x: Foo | None, other: Foo) -> None:
if x == other:
# with this option enabled, `x` will still have type `Foo | None` here,
# since it is legal to subclass `Foo` and override its `__eq__` method.
reveal_type(x)Many operations in Python implicitly call __eq__ under the hood; enabling this option
will also impact those operations. For example, this option will also impact narrowing fromin checks, and narrowing in match statements that use value patterns:
def narrow_in(x: Foo | None, other: list[Foo]) -> None:
if x in other:
# with this option enabled, `x` will still have type `Foo | None` here,
# since the `in` operator implicitly calls `__eq__` on each element of `other`.
reveal_type(x)
def narrow_match(x: str) -> None:
match x:
case "a":
# with this option enabled, `x` will still have type `str` here,
# since this `case` branch will be taken by any object that compares
# equal to `"a"`, including subclasses of `str`.
reveal_type(x)Default value: false
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
# Preserve broad builtin types instead of narrowing them to literals
strict-equality-semantics = true
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
# Preserve broad builtin types instead of narrowing them to literals
strict-equality-semantics = true
````strict-generic-narrowing`
Whether ty should use strict narrowing for unspecialized generic classes inisinstance() and issubclass() checks, match class patterns, and TypeIs checks.
When enabled, ty narrows to the top materialization of the class. For example,isinstance(value, list) narrows a value of type object to Top[list[Unknown]],
representing the (infinite) union of all possible list specializations. Iterating
over the list would yield values of type object.
When disabled, ty uses gradual generic narrowing, preserving compatible type
arguments from the original type where possible. For example,isinstance(value, list) narrows a value of type Sequence[int] to list[int].
If no specialization is available, the same check narrows a value of type object
to list[Unknown]; items of any type can then be appended to the list. Class
patterns such as case list(): follow the same behavior.
Defaults to false.
Default value: false
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[[tool.ty.overrides]]
include = ["src"]
[tool.ty.overrides.analysis]
# Use the top materialization when narrowing to an unspecialized generic class
strict-generic-narrowing = true
```=== "ty.toml"
```toml
[[overrides]]
include = ["src"]
[overrides.analysis]
# Use the top materialization when narrowing to an unspecialized generic class
strict-generic-narrowing = true
````src`
`exclude`
A list of file and directory patterns to exclude from type checking.
Patterns follow a syntax similar to .gitignore:
./src/matches only a directory./srcmatches both files and directoriessrcmatches files or directories namedsrc*matches any (possibly empty) sequence of characters (except/).**matches zero or more path components.
This sequence must form a single path component, so both**aandb**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 between0and9inclusive. An unclosed bracket is invalid.!patternnegates a pattern (undoes the exclusion of files that would otherwise be excluded)
All paths are anchored relative to the project root (src only
matches /src and not /test/src).
To exclude any directory or file named src, use **/src instead.
By default, ty excludes commonly ignored directories:
**/.bzr/**/.direnv/**/.eggs/**/.git/**/.git-rewrite/**/.hg/**/.mypy_cache/**/.nox/**/.pants.d/**/.pytype/**/.ruff_cache/**/.svn/**/.tox/**/.venv/**/__pypackages__/**/_build/**/buck-out/**/dist/**/node_modules/**/venv/
You can override any default exclude by using a negated pattern. For example,
to re-include dist use exclude = ["!dist"]
Default value: null
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.src]
exclude = [
"generated",
"*.proto",
"tests/fixtures/**",
"!tests/fixtures/important.py" # Include this one file
]
```=== "ty.toml"
```toml
[src]
exclude = [
"generated",
"*.proto",
"tests/fixtures/**",
"!tests/fixtures/important.py" # Include this one file
]
````exclude-scripts`
Whether to exclude files containing PEP 723 inline script metadata unless they are
explicitly passed on the command line.
Default value: false
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.src]
exclude-scripts = true
```=== "ty.toml"
```toml
[src]
exclude-scripts = true
````include`
A list of files and directories to check. The include option
follows a similar syntax to .gitignore but reversed:
Including a file or directory will make it so that it (and its contents)
are type checked.
./src/matches only a directory./srcmatches both files and directoriessrcmatches a file or directory namedsrc*matches any (possibly empty) sequence of characters (except/).**matches zero or more path components.
This sequence must form a single path component, so both**aandb**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 between0and9inclusive. An unclosed bracket is invalid.
All paths are anchored relative to the project root (src only
matches /src and not /test/src).
exclude takes precedence over include.
Default value: null
Type: list[str]
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.src]
include = [
"src",
"tests",
]
```=== "ty.toml"
```toml
[src]
include = [
"src",
"tests",
]
````respect-ignore-files`
Whether to automatically exclude files that are ignored by .ignore,.gitignore, .git/info/exclude, and global gitignore files.
Enabled by default.
Default value: true
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.src]
respect-ignore-files = false
```=== "ty.toml"
```toml
[src]
respect-ignore-files = false
````terminal`
`error-on-warning`
Use exit code 1, even if all diagnostics only had warning severity.
Defaults to true.
Default value: true
Type: bool
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.terminal]
# Exit with code 0 if all diagnostics had `warning` severity.
error-on-warning = false
```=== "ty.toml"
```toml
[terminal]
# Exit with code 0 if all diagnostics had `warning` severity.
error-on-warning = false
````output-format`
The format to use for printing diagnostic messages.
Defaults to full.
Default value: full
Type: full | concise | github | gitlab | junit
Example usage:
=== "pyproject.toml"
```toml
[tool.ty.terminal]
output-format = "concise"
```=== "ty.toml"
```toml
[terminal]
output-format = "concise"
```File: docs/reference/editor-settings.md
Editor settings
The editor settings supported by ty's language server, as well as the settings specific to ty's VS
Code extension.
`configuration`
In-editor configuration of ty's settings. The inline settings always take precedence over the settings from configuration files,
including the configuration specified with configurationFile.
Consult the configuration reference for a list of all supported configuration options.
Default value: null
Type: object
Example usage:
=== "VS Code"
```json
{
"ty.configuration": {
"rules": {
"unresolved-reference": "warn"
}
}
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
configuration = {
rules = {
["unresolved-reference"] = "warn"
}
}
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
configuration = {
rules = {
["unresolved-reference"] = "warn"
}
}
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"configuration": {
"rules": {
"unresolved-reference": "warn"
}
}
}
}
}
}
````configurationFile`
The path to a ty.toml configuration file. ty will use the specified configuration over any automatically discovered configuration.
ty will expand a tilde ~ at the start of a string to the user's home directory, as well as variables like $A or ${A}.
!!! info
While ty configuration can be included in a `pyproject.toml` file, it is not allowed in this context.Default value: null
Type: string
Example usage:
=== "VS Code"
```json
{
"ty.configurationFile": "./.config/ty.toml"
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
configurationFile = "./.config/ty.toml"
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
configurationFile = "./.config/ty.toml"
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"configurationFile": "./.config/ty.toml"
}
}
}
}
````disableLanguageServices`
Whether to disable the language services for the ty language server like code completion, hover,
go to definition, etc.
This is useful if you want to use ty exclusively for type checking and want to use another language
server for features like code completion, hover, go to definition, etc.
Default value: false
Type: boolean
Example usage:
=== "VS Code"
```json
{
"ty.disableLanguageServices": true
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
disableLanguageServices = true,
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
disableLanguageServices = true,
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"disableLanguageServices": true
}
}
}
}
````diagnosticMode`
Determines the scope of the diagnostics reported by the language server.
Setting this to off is useful if you want to use ty exclusively for the language server features
like code completion, hover, go to definition, etc.
off: Diagnostics are disabled.openFilesOnly: Diagnostics are reported only for files that are currently open in the editor.workspace: Diagnostics are reported for all files in the workspace.
Default value: "openFilesOnly"
Type: "off" | "workspace" | "openFilesOnly"
Example usage:
=== "VS Code"
```json
{
"ty.diagnosticMode": "workspace"
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
diagnosticMode = 'workspace',
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
diagnosticMode = 'workspace',
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"diagnosticMode": "workspace"
}
}
}
}
````showSyntaxErrors`
Whether to show syntax error diagnostics.
This is useful when using ty with other language servers, allowing the user to refer to syntax errors
from only one source.
Default value: true
Type: bool
Example usage:
=== "VS Code"
```json
{
"ty.showSyntaxErrors": false
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
showSyntaxErrors = false,
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
showSyntaxErrors = false,
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"showSyntaxErrors": false
}
}
}
}
````inlayHints`
These settings control the inline hints that ty provides in an editor.
`variableTypes`
Whether to show the types of variables as inline hints.
Default value: true
Type: boolean
Example usage:
=== "VS Code"
```json
{
"ty.inlayHints.variableTypes": false
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
inlayHints = {
variableTypes = false,
},
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
inlayHints = {
variableTypes = false,
},
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"inlayHints": {
"variableTypes": false
}
}
}
}
}
````callArgumentNames`
Whether to show argument names in call expressions as inline hints.
Default value: true
Type: boolean
Example usage:
=== "VS Code"
```json
{
"ty.inlayHints.callArgumentNames": false
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
inlayHints = {
callArgumentNames = false,
},
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
inlayHints = {
callArgumentNames = false,
},
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"inlayHints": {
"callArgumentNames": false
}
}
}
}
}
````completions`
These settings control how code completions offered by ty work.
`autoImport`
Whether to include auto-import suggestions in code completions. That is, code completions will
include symbols not currently in scope but available in your environment.
Default value: true
Type: boolean
Example usage:
=== "VS Code"
```json
{
"ty.completions.autoImport": true
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
completions = {
autoImport = true,
},
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
completions = {
autoImport = true,
},
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"completions": {
"autoImport": true
}
}
}
}
}
````completeFunctionParentheses`
Whether accepting a function, method, or class completion also inserts parentheses and places the
cursor inside them.
Default value: false
Type: boolean
Example usage:
=== "VS Code"
```json
{
"ty.completions.completeFunctionParentheses": true
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
settings = {
ty = {
completions = {
completeFunctionParentheses = true,
},
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
settings = {
ty = {
completions = {
completeFunctionParentheses = true,
},
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"settings": {
"completions": {
"completeFunctionParentheses": true
}
}
}
}
}
```VS Code specific
The following settings are specific to ty's VS Code extension.
`importStrategy`
Strategy for loading the ty executable.
fromEnvironmentfinds ty in the environment, falling back to the bundled versionuseBundleduses the version bundled with the extension
Default value: "fromEnvironment"
Type: "fromEnvironment" | "useBundled"
Example usage:
{
"ty.importStrategy": "useBundled"
}`interpreter`
A list of paths to Python interpreters. Even though this is a list, only the first interpreter is
used.
The interpreter path is used to find the ty executable whenty.importStrategy is set to fromEnvironment.
Default value: []
Type: string[]
Example usage:
{
"ty.interpreter": ["/home/user/.local/bin/python"]
}`path`
A list of path to ty executables.
The extension uses the first executable that exists. This setting takes precedence over thety.importStrategy setting.
Default value: []
Type: string[]
Example usage:
{
"ty.path": ["/home/user/.local/bin/ty"]
}`trace.server`
The detail level at which messages between the language server and the editor (client) are logged.
This setting is useful for debugging issues with the language server. Refer to the troubleshooting
guide
in ty's VS Code extension for more information.
Default value: "off"
Type: "off" | "messages" | "verbose"
Example usage:
{
"ty.trace.server": "messages"
}Initialization options
The following settings are required when ty is initialized in an editor. These settings are
static so changing them requires restarting the editor to take effect.
For VS Code users, most of these settings are defined in the ty.* namespace as usual, but for other
editors, they would need to be provided in a separate field of the configuration that corresponds to
the initialization options. Refer to the examples below for how to set these options in different
editors.
`experimental.useUv`
Control how ty uses uv:
off: Do not use uv.scripts: Use uv to create and update environments for standalone scripts with
PEP 723 inline metadata.on: Use uv for project discovery and standalone script environments.
This feature is experimental and may change. Enabling it requires
uv 0.12.3 or later. All uv integrations are disabled whenuntrustedWorkspace is true.
Default value: null
Type: "off" | "scripts" | "on"
Example usage:
=== "VS Code"
```json
{
"ty.experimental.useUv": "scripts"
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
init_options = {
experimental = {
useUv = 'scripts',
},
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
init_options = {
experimental = {
useUv = 'scripts',
},
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"initialization_options": {
"experimental": {
"useUv": "scripts"
}
}
}
}
}
````logFile`
Path to the file to which the language server writes its log messages. By default, ty writes log messages to stderr.
Default value: null
Type: string
Example usage:
=== "VS Code"
```json
{
"ty.logFile": "/path/to/ty.log"
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
init_options = {
logFile = '/path/to/ty.log',
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
init_options = {
logFile = '/path/to/ty.log',
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"initialization_options": {
"logFile": "/path/to/ty.log"
}
}
}
}
````logLevel`
The log level to use for the language server.
Default value: "info"
Type: "trace" | "debug" | "info" | "warn" | "error"
Example usage:
=== "VS Code"
```json
{
"ty.logLevel": "debug"
}
```=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
init_options = {
logLevel = 'debug',
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
init_options = {
logLevel = 'debug',
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"initialization_options": {
"logLevel": "debug"
}
}
}
}
````untrustedWorkspace`
Whether the language server should treat the workspace as untrusted. When true, ty does not run
external commands. This disables all uv integrations.
Default value: false
Type: boolean
Example usage:
=== "VS Code"
The extension sets this option automatically based on
[Workspace Trust](https://code.visualstudio.com/docs/editing/workspaces/workspace-trust).
There is no `ty.untrustedWorkspace` setting. Open the workspace in Restricted Mode to mark it
as untrusted.=== "Neovim"
```lua
-- Neovim >=0.11:
vim.lsp.config('ty', {
init_options = {
untrustedWorkspace = true,
},
})
-- Neovim <0.11:
require('lspconfig').ty.setup({
init_options = {
untrustedWorkspace = true,
},
})
```=== "Zed"
```json
{
"lsp": {
"ty": {
"initialization_options": {
"untrustedWorkspace": true
}
}
}
}
```File: docs/reference/environment.md
Environment variables
ty defines and respects the following environment variables:
`TY_CONFIG_FILE`
Path to a ty.toml configuration file to use.
When set, ty will use this file for configuration instead of
discovering configuration files automatically.
Equivalent to the --config-file command-line argument.
`TY_LOG`
If set, ty will use this value as the log level for its --verbose output.
Accepts any filter compatible with the tracing_subscriber crate.
For example:
TY_LOG=ty=debugis the equivalent of-vvto the command lineTY_LOG=tracewill enable all trace-level logging.
See the tracing documentation
for more.
`TY_LOG_PROFILE`
If set to "1" or "true", ty will enable flamegraph profiling.
This creates a tracing.folded file that can be used to generate flame graphs
for performance analysis.
`TY_MAX_PARALLELISM`
Specifies an upper limit for the number of tasks ty is allowed to run in parallel.
For example, how many files should be checked in parallel.
This isn't the same as a thread limit. ty may spawn additional threads
when necessary, e.g. to watch for file system changes or a dedicated UI thread.
`TY_OUTPUT_FORMAT`
The format to use for printing diagnostic messages.
When set, ty will use this format for output instead of the default.
Accepts the same values as the --output-format command-line argument.
Externally-defined variables
ty also reads the following externally defined environment variables:
`CONDA_DEFAULT_ENV`
Used to determine the name of the active Conda environment.
`CONDA_PREFIX`
Used to detect the path of an active Conda environment.
If both VIRTUAL_ENV and CONDA_PREFIX are present, VIRTUAL_ENV will be preferred.
`PYTHONPATH`
Adds additional directories to ty's search paths.
The format is the same as the shellโs PATH:
one or more directory pathnames separated by os appropriate pathsep
(e.g. colons on Unix or semicolons on Windows).
`RAYON_NUM_THREADS`
Specifies an upper limit for the number of threads ty uses when performing work in parallel.
Equivalent to TY_MAX_PARALLELISM.
This is a standard Rayon environment variable.
`VIRTUAL_ENV`
Used to detect an activated virtual environment.
`XDG_CONFIG_HOME`
Path to user-level configuration directory on Unix systems.
`_CONDA_ROOT`
Used to determine the root install path of Conda.
File: docs/reference/exit-codes.md
Exit codes
The ty command line interface uses the following exit codes:
| Exit code | Description |
|---|---|
0 |
no violations with severity warning or higher were found |
1 |
violations with severity warning or higher were found |
2 |
invalid CLI options, invalid configuration, or IO errors |
101 |
internal error |
ty supports three command line arguments that change how exit codes work:
--exit-zero: ty will exit with0even if violations were found.--error-on-warning: ty will exit with1if it finds any violations with severitywarningor
higher.--exit-zero-on-warning: ty will only exit with1if it finds violations with severityerroror higher.
--error-on-warning cannot be supplied at the same time as --exit-zero or --exit-zero-on-warning.