## 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 the
`age` 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](../editors.md) guide for instructions on how to set up ty
with your editor.

## Diagnostics

<figure markdown="span">
  
  <figcaption>Example of an inline diagnostic with code-span annotations</figcaption>
</figure>

ty reports type errors and other [diagnostics](./diagnostics.md) directly in your editor. Diagnostics
are updated as you type. You can use the
[`diagnosticMode`](../reference/editor-settings.md#diagnosticmode) 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

<figure markdown="span">
  
  <figcaption>"Find references" shows usages across the entire workspace</figcaption>
</figure>

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 variable `user: 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

<figure markdown="span">
  { width="500" }
  <figcaption>Accepting this completion will automatically add a `subprocess` import at the top of the file.</figcaption>
</figure>

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

<figure markdown="span">
  { width="700" }
  <figcaption>ty offers to remove the unused suppression comment</figcaption>
</figure>

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

<figure markdown="span">
  
  <figcaption>Gray inlay hints and on-hover information (signature, docstring)</figcaption>
</figure>

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



| Feature                                               | Status           | Notes                                                         |
| ----------------------------------------------------- | ---------------- | ------------------------------------------------------------- |
| [`callHierarchy/*`][callhierarchy]                    | ✅ Supported     |                                                               |
| [`notebookDocument/*`][notebookdocument]              | ✅ Supported     |                                                               |
| [`textDocument/codeAction`][codeaction]               | ✅ Supported     | Quick fixes                                                   |
| [`textDocument/codeLens`][codelens]                   | ❌ Not supported |                                                               |
| [`textDocument/completion`][completion]               | ✅ Supported     |                                                               |
| [`textDocument/declaration`][declaration]             | ✅ Supported     |                                                               |
| [`textDocument/definition`][definition]               | ✅ Supported     |                                                               |
| [`textDocument/diagnostic`][diagnostic]               | ✅ Supported     |                                                               |
| [`textDocument/documentColor`][documentcolor]         | ❌ Not supported |                                                               |
| [`textDocument/documentHighlight`][documenthighlight] | ✅ Supported     |                                                               |
| [`textDocument/documentLink`][documentlink]           | ❌ Not supported |                                                               |
| [`textDocument/documentSymbol`][documentsymbol]       | ✅ Supported     |                                                               |
| [`textDocument/foldingRange`][foldingrange]           | ✅ Supported     |                                                               |
| [`textDocument/formatting`][formatting]               | —                | Use [Ruff] for formatting                                     |
| [`textDocument/hover`][hover]                         | ✅ Supported     |                                                               |
| [`textDocument/implementation`][implementation]       | ✅ Supported     |                                                               |
| [`textDocument/inlayHint`][inlayhint]                 | ✅ Supported     |                                                               |
| [`textDocument/onTypeFormatting`][ontypeformatting]   | —                | [Ruff #16829](https://github.com/astral-sh/ruff/issues/16829) |
| [`textDocument/prepareRename`][preparerename]         | ✅ Supported     |                                                               |
| [`textDocument/rangeFormatting`][rangeformatting]     | —                | Use [Ruff] for formatting                                     |
| [`textDocument/references`][references]               | ✅ Supported     |                                                               |
| [`textDocument/rename`][rename]                       | ✅ Supported     |                                                               |
| [`textDocument/selectionRange`][selectionrange]       | ✅ Supported     |                                                               |
| [`textDocument/semanticTokens`][semantictokens]       | ✅ Supported     |                                                               |
| [`textDocument/signatureHelp`][signaturehelp]         | ✅ Supported     |                                                               |
| [`textDocument/typeDefinition`][typedefinition]       | ✅ Supported     |                                                               |
| [`typeHierarchy/*`][typehierarchy]                    | ✅ Supported     |                                                               |
| [`workspace/diagnostic`][workspacediagnostic]         | ✅ Supported     |                                                               |
| [`workspace/symbol`][workspacesymbol]                 | ✅ Supported     |                                                               |
| [`workspace/willRenameFiles`][willrenamefiles]        | ❌ Not supported | [#1560]                                                       |

## 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`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#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.

```ts
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.

[#1560]: https://github.com/astral-sh/ty/issues/1560
[callhierarchy]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#callHierarchy_incomingCalls
[codeaction]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction
[codelens]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeLens
[completion]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
[declaration]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_declaration
[definition]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition
[diagnostic]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_diagnostic
[documentcolor]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentColor
[documenthighlight]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentHighlight
[documentlink]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentLink
[documentsymbol]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol
[foldingrange]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_foldingRange
[formatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting
[hover]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover
[implementation]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation
[inlayhint]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlayHint
[language server]: https://microsoft.github.io/language-server-protocol/
[notebookdocument]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_synchronization
[ontypeformatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_onTypeFormatting
[preparerename]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_prepareRename
[rangeformatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rangeFormatting
[references]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references
[rename]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename
[ruff]: https://docs.astral.sh/ruff/
[selectionrange]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_selectionRange
[semantictokens]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens
[signaturehelp]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_signatureHelp
[typedefinition]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_typeDefinition
[typehierarchy]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#typeHierarchy_supertypes
[willrenamefiles]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_willRenameFiles
[workspacediagnostic]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_diagnostic
[workspacesymbol]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol

---

## 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](https://github.com/astral-sh/ty/issues/1889)). 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 the
`paths` parameter is redeclared as a list of strings:

```py
def split_paths(paths: str) -> list[Path]:
    paths: list[str] = paths.split(":")
    return [Path(p) for p in paths]
```

(Full example in the [playground](https://play.ty.dev/80a74c95-a43e-4a3d-8c26-f88e879d7dcb))

## 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:

```py
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](https://play.ty.dev/39241435-5e78-4ce9-817f-ce65be73a6ed))

Intersections can also be built using gradual types like `Any` or its implicit counterpart
`Unknown`. 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):

```py
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](https://play.ty.dev/8f98820e-7306-4d69-b572-56d69a92b90f))

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:

```py
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](https://play.ty.dev/31f2c718-516a-4a85-80e0-2a4682b818f1))

!!! 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:

```py
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](https://play.ty.dev/f003e901-0e45-4f45-9759-d6db9d5e5f66))

## 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 of
`Any & 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`](../reference/configuration.md#strict-generic-narrowing)
is enabled). For example, when checking `isinstance(…, list)`, ty intersects with the top materialization
of `list[Unknown]`:

```py
@final
class Item: ...


def process(items: Item | list[Item]):
    if isinstance(items, list):
        # reveals: list[Item]
        reveal_type(items)
```

(Full example in the [playground](https://play.ty.dev/d2759832-101c-410d-b721-50805729bc68))

!!! 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 because
`pydantic.__version__.startswith("2.")` can be evaluated to `True` or `False` at type-checking time:

```py
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](https://play.ty.dev/34a227bb-93d5-405e-86c3-72f57ec5642e))

[materializations]: https://typing.python.org/en/latest/spec/concepts.html#materialization
[python typing documentation]: https://typing.python.org/en/latest/spec/index.html

---

## File: docs/reference/cli.md

# CLI Reference

## ty

An extremely fast Python type checker.

<h3 class="cli-reference">Usage</h3>

```
ty <COMMAND>
```

<h3 class="cli-reference">Commands</h3>

<dl class="cli-reference"><dt>[`ty check`](#ty-check)</dt><dd>Check a project for type errors</dd>
<dt>[`ty server`](#ty-server)</dt><dd>Start the language server</dd>
<dt>[`ty version`](#ty-version)</dt><dd>Display ty's version</dd>
<dt>[`ty explain`](#ty-explain)</dt><dd>Explain rules and other parts of ty</dd>
<dt>[`ty help`](#ty-help)</dt><dd>Print this message or the help of the given subcommand(s)</dd>
</dl>

## ty check

Check a project for type errors

<h3 class="cli-reference">Usage</h3>

```
ty check [OPTIONS] [PATH]...
```

<h3 class="cli-reference">Arguments</h3>

<dl class="cli-reference"><dt id="ty-check--paths">[`PATHS`](#ty-check--paths)</dt><dd>List of files or directories to check [default: the project root]
</dd></dl>

<h3 class="cli-reference">Options</h3>

<dl class="cli-reference"><dt id="ty-check--add-ignore">[`--add-ignore`](#ty-check--add-ignore)</dt><dd>Adds `ty: ignore` comments to suppress all rule diagnostics
</dd><dt id="ty-check--color">[`--color`](#ty-check--color) *when*</dt><dd>Control when colored output is used
Possible values:

<li>`auto`:  Display colors if the output goes to an interactive terminal</li>
<li>`always`:  Always display colors</li>
<li>`never`:  Never display colors</li>
</dd><dt id="ty-check--config">[`--config`](#ty-check--config), `-c` *config-option*</dt><dd>A TOML `&lt;KEY&gt; = &lt;VALUE&gt;` 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.
</dd><dt id="ty-check--config-file">[`--config-file`](#ty-check--config-file) *path*</dt><dd>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.</dd><dt id="ty-check--error">[`--error`](#ty-check--error) *rule*</dt><dd>Treat the given rule as having severity 'error'. Can be specified multiple times. Use 'all' to apply to all rules.
</dd><dt id="ty-check--error-on-warning">[`--error-on-warning`](#ty-check--error-on-warning)</dt><dd>Use exit code 1 if there are any warning-level diagnostics.
Cannot be used in combination with `--exit-zero` or `--exit-zero-on-warning`.
</dd><dt id="ty-check--exclude">[`--exclude`](#ty-check--exclude) *exclude*</dt><dd>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__/**`.
</dd><dt id="ty-check--exclude-scripts">[`--exclude-scripts`](#ty-check--exclude-scripts)</dt><dd>Exclude files containing PEP 723 inline script metadata unless passed explicitly. Use `--include-scripts` to disable
</dd><dt id="ty-check--exit-zero">[`--exit-zero`](#ty-check--exit-zero)</dt><dd>Always use exit code 0, even when there are error-level diagnostics.
Cannot be used in combination with `--error-on-warning`.
</dd><dt id="ty-check--exit-zero-on-warning">[`--exit-zero-on-warning`](#ty-check--exit-zero-on-warning)</dt><dd>Use exit code 0 if there are no error-level diagnostics.
Cannot be used in combination with `--error-on-warning`.
</dd><dt id="ty-check--extra-search-path">[`--extra-search-path`](#ty-check--extra-search-path) *path*</dt><dd>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.
</dd><dt id="ty-check--fix">[`--fix`](#ty-check--fix)</dt><dd>Apply fixes to resolve errors
</dd><dt id="ty-check--force-exclude">[`--force-exclude`](#ty-check--force-exclude)</dt><dd>Enforce exclusions, even for paths passed to ty directly on the command-line. Use `--no-force-exclude` to disable
</dd><dt id="ty-check--help">[`--help`](#ty-check--help), `-h`</dt><dd>Print help (see a summary with '-h')
</dd><dt id="ty-check--ignore">[`--ignore`](#ty-check--ignore) *rule*</dt><dd>Disables the rule. Can be specified multiple times. Use 'all' to apply to all rules.
</dd><dt id="ty-check--no-progress">[`--no-progress`](#ty-check--no-progress)</dt><dd>Hide all progress outputs.
For example, spinners or progress bars.
</dd><dt id="ty-check--output-format">[`--output-format`](#ty-check--output-format) *output-format*</dt><dd>The format to use for printing diagnostic messages
May also be set with the `TY_OUTPUT_FORMAT` environment variable.Possible values:

<li>`full`:  Print diagnostics verbosely, with context and helpful hints (default)</li>
<li>`concise`:  Print diagnostics concisely, one per line</li>
<li>`gitlab`:  Print diagnostics in the JSON format expected by GitLab Code Quality reports</li>
<li>`github`:  Print diagnostics in the format used by GitHub Actions workflow error annotations</li>
<li>`junit`:  Print diagnostics as a JUnit-style XML report</li>
</dd><dt id="ty-check--project">[`--project`](#ty-check--project) *project*</dt><dd>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.
</dd><dt id="ty-check--python">[`--python`](#ty-check--python), `--venv` *path*</dt><dd>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:

<li>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`</li>

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.

</dd><dt id="ty-check--python-platform">[`--python-platform`](#ty-check--python-platform), `--platform` *platform*</dt><dd>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.
</dd><dt id="ty-check--python-version">[`--python-version`](#ty-check--python-version), `--target-version` *version*</dt><dd>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:

<li>`3.7`</li>
<li>`3.8`</li>
<li>`3.9`</li>
<li>`3.10`</li>
<li>`3.11`</li>
<li>`3.12`</li>
<li>`3.13`</li>
<li>`3.14`</li>
<li>`3.15`</li>
</dd><dt id="ty-check--quiet">[`--quiet`](#ty-check--quiet), `-q`</dt><dd>Use quiet output (or `-qq` for silent output)
</dd><dt id="ty-check--respect-ignore-files">[`--respect-ignore-files`](#ty-check--respect-ignore-files)</dt><dd>Respect file exclusions via `.gitignore` and other standard ignore files. Use `--no-respect-ignore-files` to disable
</dd><dt id="ty-check--typeshed">[`--typeshed`](#ty-check--typeshed), `--custom-typeshed-dir` *path*</dt><dd>Custom directory to use for stdlib typeshed stubs
</dd><dt id="ty-check--verbose">[`--verbose`](#ty-check--verbose), `-v`</dt><dd>Use verbose output (or `-vv` and `-vvv` for more verbose output)
</dd><dt id="ty-check--warn">[`--warn`](#ty-check--warn) *rule*</dt><dd>Treat the given rule as having severity 'warn'. Can be specified multiple times. Use 'all' to apply to all rules.
</dd><dt id="ty-check--watch">[`--watch`](#ty-check--watch), `-W`</dt><dd>Watch files for changes and recheck files related to the changed files
</dd></dl>

## ty server

Start the language server

<h3 class="cli-reference">Usage</h3>

```
ty server
```

<h3 class="cli-reference">Options</h3>

<dl class="cli-reference"><dt id="ty-server--help">[`--help`](#ty-server--help), `-h`</dt><dd>Print help
</dd></dl>

## ty version

Display ty's version

<h3 class="cli-reference">Usage</h3>

```
ty version [OPTIONS]
```

<h3 class="cli-reference">Options</h3>

<dl class="cli-reference"><dt id="ty-version--help">[`--help`](#ty-version--help), `-h`</dt><dd>Print help
</dd><dt id="ty-version--output-format">[`--output-format`](#ty-version--output-format) *output-format*</dt><dd>The format in which to display the version information
[default: text]Possible values:

<li>`text`</li>
<li>`json`</li>
</dd></dl>

## ty generate-shell-completion

Generate shell completion

<h3 class="cli-reference">Usage</h3>

```
ty generate-shell-completion <SHELL>
```

<h3 class="cli-reference">Arguments</h3>

<dl class="cli-reference"><dt id="ty-generate-shell-completion--shell">[`SHELL`](#ty-generate-shell-completion--shell)</dt></dl>

<h3 class="cli-reference">Options</h3>

<dl class="cli-reference"><dt id="ty-generate-shell-completion--help">[`--help`](#ty-generate-shell-completion--help), `-h`</dt><dd>Print help
</dd></dl>

## ty explain

Explain rules and other parts of ty

<h3 class="cli-reference">Usage</h3>

```
ty explain <COMMAND>
```

<h3 class="cli-reference">Commands</h3>

<dl class="cli-reference"><dt>[`ty explain rule`](#ty-explain-rule)</dt><dd>Explain a rule (or all rules)</dd>
<dt>[`ty explain help`](#ty-explain-help)</dt><dd>Print this message or the help of the given subcommand(s)</dd>
</dl>

### ty explain rule

Explain a rule (or all rules)

<h3 class="cli-reference">Usage</h3>

```
ty explain rule [OPTIONS] [RULE]
```

<h3 class="cli-reference">Arguments</h3>

<dl class="cli-reference"><dt id="ty-explain-rule--rule">[`RULE`](#ty-explain-rule--rule)</dt><dd>Rule to explain
Defaults to all rules if omitted.
</dd></dl>

<h3 class="cli-reference">Options</h3>

<dl class="cli-reference"><dt id="ty-explain-rule--help">[`--help`](#ty-explain-rule--help), `-h`</dt><dd>Print help (see a summary with '-h')
</dd><dt id="ty-explain-rule--output-format">[`--output-format`](#ty-explain-rule--output-format) *output-format*</dt><dd>Output format
[default: text]Possible values:

<li>`text`</li>
<li>`json`</li>
</dd></dl>

### ty explain help

Print this message or the help of the given subcommand(s)

<h3 class="cli-reference">Usage</h3>

```
ty explain help [COMMAND]
```

## ty help

Print this message or the help of the given subcommand(s)

<h3 class="cli-reference">Usage</h3>

```
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](https://ty.dev/rules) 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.*` matches `foo.bar` but
  not `foo.bar.baz`; `foo*` matches `foo` and `foobar` but not `foo.bar` or `barfoo`; and `*foo`
  matches `foo` and `barfoo` but not `foo.bar` or `foobar`.
- `**` matches any number of module components (e.g., `foo.**` matches `foo`, `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 of `Unknown`.
- `"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"]`:

```pycon
>>> # `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"
True
```

Enabling this option prevents the unsound narrowing of `x` to `Literal["a"]`,
and instead keeps it as `str`:

```python
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 None
```

Another 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:

```python
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 from
`in` checks, and narrowing in `match` statements that use value patterns:

```python
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 in
`isinstance()` 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.prefix`] directory, 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.

[`sys.prefix`]: https://docs.python.org/3/library/sys.html#sys.prefix

**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:
- `win32` for Windows
- `darwin` for macOS
- `android` for Android
- `ios` for iOS
- `linux` for 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:
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 default value (see below)

Scripts with inline metadata use their `requires-python` field instead of
`project.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:

```toml
[[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:

```toml
[[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.*` matches `foo.bar` but
  not `foo.bar.baz`; `foo*` matches `foo` and `foobar` but not `foo.bar` or `barfoo`; and `*foo`
  matches `foo` and `barfoo` but not `foo.bar` or `foobar`.
- `**` matches any number of module components (e.g., `foo.**` matches `foo`, `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 of `Unknown`.
- `"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"]`:

```pycon
>>> # `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"
True
```

Enabling this option prevents the unsound narrowing of `x` to `Literal["a"]`,
and instead keeps it as `str`:

```python
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 None
```

Another 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:

```python
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 from
`in` checks, and narrowing in `match` statements that use value patterns:

```python
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 in
`isinstance()` 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
- `./src` matches both files and directories
- `src` matches files or directories 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.
- `!pattern` negates 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
- `./src` matches both files and directories
- `src` matches a file or directory 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 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][ty-vscode].

## `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`](#configurationfile).

Consult [the configuration reference](../configuration.md) 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][ty-vscode].

### `importStrategy`

Strategy for loading the `ty` executable.

- `fromEnvironment` finds ty in the environment, falling back to the bundled version
- `useBundled` uses the version bundled with the extension

**Default value**: `"fromEnvironment"`

**Type**: `"fromEnvironment" | "useBundled"`

**Example usage**:

```json
{
  "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 when
[`ty.importStrategy`](#importstrategy) is set to `fromEnvironment`.

**Default value**: `[]`

**Type**: `string[]`

**Example usage**:

```json
{
  "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 the
[`ty.importStrategy`](#importstrategy) setting.

**Default value**: `[]`

**Type**: `string[]`

**Example usage**:

```json
{
  "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](https://github.com/astral-sh/ty-vscode/blob/6cf16b4e87342a49f2bec1310a730cde8229e1d9/TROUBLESHOOTING.md)
in [ty's VS Code extension][ty-vscode] for more information.

**Default value**: `"off"`

**Type**: `"off" | "messages" | "verbose"`

**Example usage**:

```json
{
  "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](https://docs.astral.sh/uv/):

- `off`: Do not use uv.
- `scripts`: Use uv to create and update environments for standalone scripts with
    [PEP 723 inline metadata](https://peps.python.org/pep-0723/).
- `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](https://docs.astral.sh/uv/getting-started/installation/). All uv integrations are disabled when
[`untrustedWorkspace`](#untrustedworkspace) 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
          }
        }
      }
    }
    ```

[ty-vscode]: https://marketplace.visualstudio.com/items?itemName=astral-sh.ty

---

## 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=debug` is the equivalent of `-vv` to the command line
- `TY_LOG=trace` will enable all trace-level logging.

See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
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 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.
- `--exit-zero-on-warning`: ty will only exit with `1` if it finds violations with severity `error` or higher.

`--error-on-warning` cannot be supplied at the same time as `--exit-zero` or `--exit-zero-on-warning`.