Full Code of astral-sh/ty for AI

main 876233049afc cached
68 files
616.9 KB
177.2k tokens
17 symbols
1 requests
Download .txt
Showing preview only (643K chars total). Download the full file or copy to clipboard to get everything.
Repository: astral-sh/ty
Branch: main
Commit: 876233049afc
Files: 68
Total size: 616.9 KB

Directory structure:
gitextract_pe4vyql8/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1_bug_report.yaml
│   │   ├── 2_question.yaml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── actionlint.yaml
│   ├── renovate.json5
│   ├── workflows/
│   │   ├── build-binaries.yml
│   │   ├── build-docker.yml
│   │   ├── ci.yaml
│   │   ├── daily_property_tests.yml
│   │   ├── publish-docs.yml
│   │   ├── publish-mirror.yml
│   │   ├── publish-pypi.yml
│   │   └── release.yml
│   └── zizmor.yml
├── .gitignore
├── .gitmodules
├── .markdownlint.yaml
├── .pre-commit-config.yaml
├── .python-version
├── BENCHMARKS.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── SECURITY.md
├── _typos.toml
├── assets/
│   └── badge/
│       └── v0.json
├── dist-workspace.toml
├── docs/
│   ├── .overrides/
│   │   ├── main.html
│   │   └── partials/
│   │       └── integrations/
│   │           └── analytics/
│   │               └── fathom.html
│   ├── configuration.md
│   ├── editors.md
│   ├── exclusions.md
│   ├── features/
│   │   ├── diagnostics.md
│   │   ├── language-server.md
│   │   └── type-system.md
│   ├── index.md
│   ├── installation.md
│   ├── js/
│   │   └── extra.js
│   ├── modules.md
│   ├── python-version.md
│   ├── reference/
│   │   ├── cli.md
│   │   ├── configuration.md
│   │   ├── editor-settings.md
│   │   ├── environment.md
│   │   ├── exit-codes.md
│   │   ├── rules.md
│   │   └── typing-faq.md
│   ├── requirements.in
│   ├── requirements.txt
│   ├── rules.md
│   ├── stylesheets/
│   │   └── extra.css
│   ├── suppression.md
│   └── type-checking.md
├── mkdocs.yml
├── pyproject.toml
├── python/
│   └── ty/
│       ├── __init__.py
│       ├── __main__.py
│       ├── _find_ty.py
│       └── py.typed
└── scripts/
    ├── autogenerate_files.sh
    ├── release.sh
    ├── transform_readme.py
    └── update_schemastore.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# Check http://editorconfig.org for more information
# This is the main config file for this project:
root = true

[*]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
indent_style = space
insert_final_newline = true
indent_size = 2

[*.{rs,py,pyi,toml}]
indent_size = 4

[*.md]
max_line_length = 100


================================================
FILE: .gitattributes
================================================
* text=auto eol=lf

docs/reference/cli.md linguist-generated=true
docs/reference/configuration.md linguist-generated=true
docs/reference/rules.md linguist-generated=true


================================================
FILE: .github/ISSUE_TEMPLATE/1_bug_report.yaml
================================================
name: Bug report
description: Report an error or unexpected behavior
body:
  - type: markdown
    attributes:
      value: |
        Thank you for taking the time to report an issue! We're glad to have you involved with ty.

        **Before reporting, please make sure to search through [existing issues](https://github.com/astral-sh/ty/issues?q=is:issue+is:open+label:bug) (including [closed](https://github.com/astral-sh/ty/issues?q=is:issue%20state:closed%20label:bug)).**<br>
        **In particular, check out the list of [frequently encountered problems](https://github.com/astral-sh/ty/issues/445).**

  - type: textarea
    attributes:
      label: Summary
      description: |
        A clear and concise description of the bug, including a minimal reproducible example.

        Be sure to include the command you invoked (e.g., `ty check`) and
        the current ty settings (e.g., relevant sections from your `pyproject.toml`).

        If possible, try to include the [playground](https://play.ty.dev) link that reproduces this issue.

    validations:
      required: true

  - type: input
    attributes:
      label: Version
      description: What version of ty are you using? (see `ty version`)
      placeholder: e.g., ty 0.0.1 (ff9000864 2025-05-06)
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/2_question.yaml
================================================
name: Question
description: Ask a question about ty
labels: ["question"]
body:
  - type: textarea
    attributes:
      label: Question
      description: Describe your question in detail.
    validations:
      required: true

  - type: input
    attributes:
      label: Version
      description: What version of ty are you using? (see `ty version`)
      placeholder: e.g., ty 0.0.1 (ff9000864 2025-05-06)
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: Documentation
    url: https://github.com/astral-sh/ty/blob/main/README.md
    about: Please consult the documentation before creating an issue.
  - name: Community
    url: https://discord.com/invite/astral-sh
    about: Join our Discord community to ask questions and collaborate.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--
Thank you for contributing to ty! To help us out with reviewing, please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->


================================================
FILE: .github/actionlint.yaml
================================================
# Configuration for the actionlint tool, which we run via prek
# to verify the correctness of the syntax in our GitHub Actions workflows.

self-hosted-runner:
  # Various runners we use that aren't recognized out-of-the-box by actionlint:
  labels:
    - depot-ubuntu-latest-8
    - depot-ubuntu-22.04-16
    - depot-ubuntu-22.04-32
    - github-windows-2025-x86_64-8
    - github-windows-2025-x86_64-16


================================================
FILE: .github/renovate.json5
================================================
{
  $schema: "https://docs.renovatebot.com/renovate-schema.json",
  dependencyDashboard: true,
  suppressNotifications: ["prEditedNotification"],
  extends: ["github>astral-sh/renovate-config"],
  labels: ["internal"],
  schedule: ["before 4am on Monday"],
  semanticCommits: "disabled",
  separateMajorMinor: false,
  prHourlyLimit: 10,
  enabledManagers: ["github-actions", "pre-commit"],
  "pre-commit": {
    enabled: true,
  },
  packageRules: [
    // Pin GitHub Actions to immutable SHAs.
    {
      matchDepTypes: ["action"],
      pinDigests: true,
    },
    // Annotate GitHub Actions SHAs with a SemVer version.
    {
      extends: ["helpers:pinGitHubActionDigests"],
      extractVersion: "^(?<version>v?\\d+\\.\\d+\\.\\d+)$",
      versioning: "regex:^v?(?<major>\\d+)(\\.(?<minor>\\d+)\\.(?<patch>\\d+))?$",
    },
    {
      // Group upload/download artifact updates, the versions are dependent
      groupName: "Artifact GitHub Actions dependencies",
      matchManagers: ["github-actions"],
      matchDatasources: ["gitea-tags", "github-tags"],
      matchPackageNames: ["actions/upload-artifact", "actions/download-artifact"],
      description: "Weekly update of artifact-related GitHub Actions dependencies",
    },
    {
      // This package rule disables updates for GitHub runners:
      // we'd only pin them to a specific version
      // if there was a deliberate reason to do so
      groupName: "GitHub runners",
      matchManagers: ["github-actions"],
      matchDatasources: ["github-runners"],
      description: "Disable PRs updating GitHub runners (e.g. 'runs-on: macos-14')",
      enabled: false,
    },
    {
      groupName: "prek dependencies",
      matchManagers: ["pre-commit"],
      description: "Weekly update of prek dependencies",
    }
  ],
  vulnerabilityAlerts: {
    commitMessageSuffix: "",
    labels: ["internal", "security"],
  },
}


================================================
FILE: .github/workflows/build-binaries.yml
================================================
# Build ty on all platforms.
#
# Generates both wheels (for PyPI) and archived binaries (for GitHub releases).
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
# artifacts job within `cargo-dist`.
name: "Build binaries"

on:
  workflow_call:
    inputs:
      plan:
        required: true
        type: string
  pull_request:
    paths:
      # When we change pyproject.toml, we want to ensure that the maturin builds still work.
      - pyproject.toml
      # And when we change this workflow itself...
      - .github/workflows/build-binaries.yml

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

env:
  PACKAGE_NAME: ty
  MODULE_NAME: ty
  PYTHON_VERSION: "3.13"
  CARGO_INCREMENTAL: 0
  CARGO_NET_RETRY: 10
  CARGO_TERM_COLOR: always
  RUSTUP_MAX_RETRIES: 10

jobs:
  sdist:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build sdist"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          command: sdist
          args: --out dist
      - name: "Test sdist"
        run: |
          pip install dist/"${PACKAGE_NAME}"-*.tar.gz --force-reinstall
          "${MODULE_NAME}" version
          "${MODULE_NAME}" --help
          python -m "${MODULE_NAME}" --help
      - name: "Upload sdist"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-sdist
          path: dist

  macos-x86_64:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: macos-14
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: x64
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels - x86_64"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: x86_64
          args: --release --locked --out dist --compatibility pypi
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-macos-x86_64
          path: dist
      - name: "Archive binary"
        run: |
          TARGET=x86_64-apple-darwin
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-macos-x86_64
          path: |
            *.tar.gz
            *.sha256

  macos-aarch64:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: macos-14
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: arm64
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels - aarch64"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: aarch64
          args: --release --locked --out dist --compatibility pypi
      - name: "Test wheel - aarch64"
        run: |
          pip install dist/"${PACKAGE_NAME}"-*.whl --force-reinstall
          ty --help
          python -m ty --help
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-aarch64-apple-darwin
          path: dist
      - name: "Archive binary"
        run: |
          TARGET=aarch64-apple-darwin
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-aarch64-apple-darwin
          path: |
            *.tar.gz
            *.sha256

  windows:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: windows-latest
    strategy:
      matrix:
        platform:
          - target: x86_64-pc-windows-msvc
            arch: x64
          - target: i686-pc-windows-msvc
            arch: x86
          - target: aarch64-pc-windows-msvc
            arch: x64
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: ${{ matrix.platform.arch }}
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: ${{ matrix.platform.target }}
          args: --release --locked --out dist --compatibility pypi
        env:
          # aarch64 build fails, see https://github.com/PyO3/maturin/issues/2110
          XWIN_VERSION: 16
      - name: "Test wheel"
        if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
        shell: bash
        run: |
          python -m pip install dist/"${PACKAGE_NAME}"-*.whl --force-reinstall
          "${MODULE_NAME}" version
          "${MODULE_NAME}" --help
          python -m "${MODULE_NAME}" --help
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.platform.target }}
          path: dist
      - name: "Archive binary"
        shell: bash
        run: |
          ARCHIVE_FILE=ty-${{ matrix.platform.target }}.zip
          7z a $ARCHIVE_FILE ./ruff/target/${{ matrix.platform.target }}/release/ty.exe
          sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-${{ matrix.platform.target }}
          path: |
            *.zip
            *.sha256

  linux:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target:
          - x86_64-unknown-linux-gnu
          - i686-unknown-linux-gnu
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: x64
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: ${{ matrix.target }}
          manylinux: 2_17
          args: --release --locked --out dist --compatibility pypi
      - name: "Test wheel"
        if: ${{ startsWith(matrix.target, 'x86_64') }}
        run: |
          pip install dist/"${PACKAGE_NAME}"-*.whl --force-reinstall
          "${MODULE_NAME}" version
          "${MODULE_NAME}" --help
          python -m "${MODULE_NAME}" --help
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.target }}
          path: dist
      - name: "Archive binary"
        shell: bash
        run: |
          set -euo pipefail

          TARGET=${{ matrix.target }}
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-${{ matrix.target }}
          path: |
            *.tar.gz
            *.sha256

  linux-cross:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        platform:
          - target: aarch64-unknown-linux-gnu
            arch: aarch64
            manylinux: 2_17
            # see https://github.com/astral-sh/ruff/issues/3791
            # and https://github.com/gnzlbg/jemallocator/issues/170#issuecomment-1503228963
            maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
          - target: armv7-unknown-linux-gnueabihf
            arch: armv7
            manylinux: 2_17
          - target: s390x-unknown-linux-gnu
            arch: s390x
            manylinux: 2_17
          - target: powerpc64le-unknown-linux-gnu
            arch: ppc64le
            manylinux: 2_17
            # see https://github.com/astral-sh/ruff/issues/10073
            maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
          - target: arm-unknown-linux-musleabihf
            # Use the cross container, but tag as `linux_armv6l`
            manylinux: auto
            arch: arm

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: ${{ matrix.platform.target }}
          manylinux: ${{ matrix.platform.manylinux }}
          docker-options: ${{ matrix.platform.maturin_docker_options }}
          args: --release --locked --out dist --compatibility pypi
      - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
        if: ${{ matrix.platform.arch != 'ppc64le'}}
        name: Test wheel
        with:
          arch: ${{ matrix.platform.arch == 'arm' && 'armv6' || matrix.platform.arch }}
          distro: ${{ matrix.platform.arch == 'arm' && 'bullseye' || 'ubuntu20.04' }}
          githubToken: ${{ github.token }}
          install: |
            apt-get update
            apt-get install -y --no-install-recommends python3 python3-pip
            pip3 install -U pip
          run: |
            pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
            ty --help
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.platform.target }}
          path: dist
      - name: "Archive binary"
        shell: bash
        run: |
          set -euo pipefail

          TARGET=${{ matrix.platform.target }}
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-${{ matrix.platform.target }}
          path: |
            *.tar.gz
            *.sha256

  musllinux:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target:
          - x86_64-unknown-linux-musl
          - i686-unknown-linux-musl
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: x64
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: ${{ matrix.target }}
          manylinux: musllinux_1_2
          args: --release --locked --out dist --compatibility pypi
      - name: "Test wheel"
        if: matrix.target == 'x86_64-unknown-linux-musl'
        run: |
          docker run --rm -v ${{ github.workspace }}:/io -w /io --env MODULE_NAME --env PACKAGE_NAME alpine:latest sh -c "
            apk add python3;
            python -m venv .venv;
            .venv/bin/pip3 install ${PACKAGE_NAME} --no-index --find-links dist/ --force-reinstall;
            .venv/bin/${MODULE_NAME} --help;
            "
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.target }}
          path: dist
      - name: "Archive binary"
        shell: bash
        run: |
          set -euo pipefail

          TARGET=${{ matrix.target }}
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-${{ matrix.target }}
          path: |
            *.tar.gz
            *.sha256

  musllinux-cross:
    if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        platform:
          - target: aarch64-unknown-linux-musl
            arch: aarch64
            maturin_docker_options: -e JEMALLOC_SYS_WITH_LG_PAGE=16
          - target: armv7-unknown-linux-musleabihf
            arch: armv7

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - name: "Prep README.md"
        run: python scripts/transform_readme.py
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          maturin-version: v1.11.5
          target: ${{ matrix.platform.target }}
          manylinux: musllinux_1_2
          args: --release --locked --out dist --compatibility pypi
          docker-options: ${{ matrix.platform.maturin_docker_options }}
      - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
        name: Test wheel
        with:
          arch: ${{ matrix.platform.arch }}
          distro: alpine_latest
          githubToken: ${{ github.token }}
          install: |
            apk add python3
          run: |
            python -m venv .venv
            .venv/bin/pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
            .venv/bin/${{ env.MODULE_NAME }} --help
      - name: "Upload wheels"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.platform.target }}
          path: dist
      - name: "Archive binary"
        shell: bash
        run: |
          set -euo pipefail

          TARGET=${{ matrix.platform.target }}
          ARCHIVE_NAME=ty-$TARGET
          ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz

          mkdir -p $ARCHIVE_NAME
          cp ruff/target/$TARGET/release/ty $ARCHIVE_NAME/ty
          tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
          shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
      - name: "Upload binary"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: artifacts-${{ matrix.platform.target }}
          path: |
            *.tar.gz
            *.sha256


================================================
FILE: .github/workflows/build-docker.yml
================================================
# Build and publish a Docker image.
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local
# artifacts job within `cargo-dist`.
#
# TODO(charlie): Ideally, the publish step would happen as a publish job within `cargo-dist`, but
# sharing the built image as an artifact between jobs is challenging.
name: "Build Docker image"

on:
  workflow_call:
    inputs:
      plan:
        required: true
        type: string
  pull_request:
    paths:
      - .github/workflows/build-docker.yml

env:
  TY_BASE_IMG: ghcr.io/${{ github.repository_owner }}/ty

permissions:
  contents: read
  # TODO(zanieb): Ideally, this would be `read` on dry-run but that will require
  # significant changes to the workflow.
  packages: write # zizmor: ignore[excessive-permissions]

jobs:
  docker-build:
    name: Build Docker image (ghcr.io/astral-sh/ty) for ${{ matrix.platform }}
    runs-on: ubuntu-latest
    environment:
      name: release
    strategy:
      fail-fast: false
      matrix:
        platform:
          - linux/amd64
          - linux/arm64
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          submodules: recursive
          persist-credentials: false

      - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

      - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Check tag consistency
        if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
        env:
          TAG: ${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }}
        run: |
          version=$(grep -m 1 "^version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g')
          if [ "${TAG}" != "${version}" ]; then
            echo "The input tag does not match the version from pyproject.toml:" >&2
            echo "${TAG}" >&2
            echo "${version}" >&2
            exit 1
          else
            echo "Releasing ${version}"
          fi

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
        with:
          images: ${{ env.TY_BASE_IMG }}
          # Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name
          tags: |
            type=raw,value=dry-run,enable=${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }}
            type=pep440,pattern={{ version }},value=${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }},enable=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}

      - name: Normalize Platform Pair (replace / with -)
        run: |
          platform=${{ matrix.platform }}
          echo "PLATFORM_TUPLE=${platform//\//-}" >> "$GITHUB_ENV"

      # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
        with:
          context: .
          platforms: ${{ matrix.platform }}
          cache-from: type=gha,scope=ty-${{ env.PLATFORM_TUPLE }}
          cache-to: type=gha,mode=min,scope=ty-${{ env.PLATFORM_TUPLE }}
          labels: ${{ steps.meta.outputs.labels }}
          outputs: type=image,name=${{ env.TY_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}

      - name: Export digests
        env:
          digest: ${{ steps.build.outputs.digest }}
        run: |
          mkdir -p /tmp/digests
          touch "/tmp/digests/${digest#sha256:}"

      - name: Upload digests
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: digests-${{ env.PLATFORM_TUPLE }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  docker-publish:
    name: Publish Docker image (ghcr.io/astral-sh/ty)
    runs-on: ubuntu-latest
    environment:
      name: release
    needs:
      - docker-build
    if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
    permissions:
      attestations: write
      id-token: write
      packages: write
    steps:
      - name: Download digests
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true

      - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
        with:
          images: ${{ env.TY_BASE_IMG }}
          # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
          tags: |
            type=pep440,pattern={{ version }},value=${{ fromJson(inputs.plan).announcement_tag }}
            type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}

      - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
      - name: Create manifest list and push
        working-directory: /tmp/digests
        # The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array
        # The printf will expand the base image with the `<TY_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
        # The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <TY_BASE_IMG>@sha256:<sha256_1> <TY_BASE_IMG>@sha256:<sha256_2> ...`
        run: |
          # shellcheck disable=SC2046
          docker buildx imagetools create \
            $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf "${TY_BASE_IMG}@sha256:%s " *)

      - name: Export manifest digest
        id: manifest-digest
        env:
          IMAGE: ${{ env.TY_BASE_IMG }}
          VERSION: ${{ steps.meta.outputs.version }}
        run: |
          digest="$(
            docker buildx imagetools inspect \
              "${IMAGE}:${VERSION}" \
              --format '{{json .Manifest}}' \
            | jq -r '.digest'
          )"
          echo "digest=${digest}" >> "$GITHUB_OUTPUT"

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
        with:
          subject-name: ${{ env.TY_BASE_IMG }}
          subject-digest: ${{ steps.manifest-digest.outputs.digest }}

  docker-publish-extra:
    name: Publish additional Docker image based on ${{ matrix.image-mapping }}
    runs-on: ubuntu-latest
    environment:
      name: release
    needs:
      - docker-publish
    if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
    permissions:
      attestations: write
      id-token: write
      packages: write
    strategy:
      fail-fast: false
      matrix:
        # Mapping of base image followed by a comma followed by one or more base tags (comma separated)
        # Note, org.opencontainers.image.version label will use the first base tag (use the most specific tag first)
        image-mapping:
          - alpine:3.23,alpine3.23,alpine
          - debian:trixie-slim,trixie-slim,debian-slim
          - buildpack-deps:trixie,trixie,debian
    steps:
      - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

      - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Generate Dynamic Dockerfile Tags
        shell: bash
        env:
          TAG_VALUE: ${{ fromJson(inputs.plan).announcement_tag }}
        run: |
          set -euo pipefail

          # Extract the image and tags from the matrix variable
          IFS=',' read -r BASE_IMAGE BASE_TAGS <<< "${{ matrix.image-mapping }}"

          # Generate Dockerfile content
          cat <<EOF > Dockerfile
          FROM ${BASE_IMAGE}
          COPY --from=${TY_BASE_IMG}:latest /ty /usr/local/bin/ty
          ENTRYPOINT []
          CMD ["/usr/local/bin/ty"]
          EOF

          # Initialize a variable to store all tag docker metadata patterns
          TAG_PATTERNS=""

          # Loop through all base tags and append its docker metadata pattern to the list
          # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
          IFS=','; for TAG in ${BASE_TAGS}; do
            TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ version }},suffix=-${TAG},value=${TAG_VALUE}\n"
            TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ major }}.{{ minor }},suffix=-${TAG},value=${TAG_VALUE}\n"
            TAG_PATTERNS="${TAG_PATTERNS}type=raw,value=${TAG}\n"
          done

          # Remove the trailing newline from the pattern list
          TAG_PATTERNS="${TAG_PATTERNS%\\n}"

          # Export image cache name
          echo "IMAGE_REF=${BASE_IMAGE//:/-}" >> "$GITHUB_ENV"

          # Export tag patterns using the multiline env var syntax
          {
            echo "TAG_PATTERNS<<EOF"
            echo -e "${TAG_PATTERNS}"
            echo EOF
          } >> "$GITHUB_ENV"

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
        # ghcr.io prefers index level annotations
        env:
          DOCKER_METADATA_ANNOTATIONS_LEVELS: index
        with:
          images: ${{ env.TY_BASE_IMG }}
          flavor: |
            latest=false
          tags: |
            ${{ env.TAG_PATTERNS }}

      - name: Build and push
        id: build-and-push
        uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          # We do not really need to cache here as the Dockerfile is tiny
          #cache-from: type=gha,scope=ty-${{ env.IMAGE_REF }}
          #cache-to: type=gha,mode=min,scope=ty-${{ env.IMAGE_REF }}
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          annotations: ${{ steps.meta.outputs.annotations }}

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
        with:
          subject-name: ${{ env.TY_BASE_IMG }}
          subject-digest: ${{ steps.build-and-push.outputs.digest }}

  # This is effectively a duplicate of `docker-publish` to make https://github.com/astral-sh/ty/pkgs/container/ty
  # show the ty base image first since GitHub always shows the last updated image digests
  # This works by annotating the original digests (previously non-annotated) which triggers an update to ghcr.io
  docker-republish:
    name: Annotate Docker image (ghcr.io/astral-sh/ty)
    runs-on: ubuntu-latest
    environment:
      name: release
    needs:
      - docker-publish-extra
    if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
    permissions:
      attestations: write
      id-token: write
      packages: write
    steps:
      - name: Download digests
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true

      - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
        env:
          DOCKER_METADATA_ANNOTATIONS_LEVELS: index
        with:
          images: ${{ env.TY_BASE_IMG }}
          # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
          tags: |
            type=pep440,pattern={{ version }},value=${{ fromJson(inputs.plan).announcement_tag }}
            type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}

      - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
      - name: Create manifest list and push
        working-directory: /tmp/digests
        # The readarray part is used to make sure the quoting and special characters are preserved on expansion (e.g. spaces)
        # The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array
        # The printf will expand the base image with the `<TY_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
        # The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <TY_BASE_IMG>@sha256:<sha256_1> <TY_BASE_IMG>@sha256:<sha256_2> ...`
        run: |
          readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done

          # shellcheck disable=SC2046
          docker buildx imagetools create \
            "${annotations[@]}" \
            $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf "${TY_BASE_IMG}@sha256:%s " *)

      - name: Export manifest digest
        id: manifest-digest
        env:
          IMAGE: ${{ env.TY_BASE_IMG }}
          VERSION: ${{ steps.meta.outputs.version }}
        run: |
          digest="$(
            docker buildx imagetools inspect \
              "${IMAGE}:${VERSION}" \
              --format '{{json .Manifest}}' \
            | jq -r '.digest'
          )"
          echo "digest=${digest}" >> "$GITHUB_OUTPUT"

      - name: Generate artifact attestation
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
        with:
          subject-name: ${{ env.TY_BASE_IMG }}
          subject-digest: ${{ steps.manifest-digest.outputs.digest }}


================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI

permissions:
  contents: read

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

env:
  CARGO_INCREMENTAL: 0
  CARGO_NET_RETRY: 10
  CARGO_TERM_COLOR: always
  RUSTUP_MAX_RETRIES: 10
  PACKAGE_NAME: ty

jobs:
  python-package:
    name: "python package"
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          submodules: recursive
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          architecture: x64
      - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
      - name: "Build wheels"
        uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          args: --out dist
      - name: "Test wheel"
        run: |
          pip install --force-reinstall --find-links dist "${PACKAGE_NAME}" --pre
          ty --help
          python -m ty --help
      - name: "Remove wheels from cache"
        run: rm -rf target/wheels

  prek:
    name: "prek"
    runs-on: depot-ubuntu-22.04-16
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
      - name: "Cache prek"
        uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
        with:
          path: ~/.cache/prek
          key: prek-${{ hashFiles('.pre-commit-config.yaml') }}
      - name: "Run prek"
        run: |
          echo '```console' > "$GITHUB_STEP_SUMMARY"
          # Enable color output for prek and remove it for the summary
          # Use --hook-stage=manual to enable slower hooks that are skipped by default
          SKIP=cargo-fmt,clippy,dev-generate-all uvx prek run --all-files --show-diff-on-failure --color always --hook-stage manual | \
            tee >(sed -E 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g' >> "$GITHUB_STEP_SUMMARY") >&1
          exit_code="${PIPESTATUS[0]}"
          echo '```' >> "$GITHUB_STEP_SUMMARY"
          exit "$exit_code"

  generated-check:
    name: "Check generated files unedited"
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          submodules: recursive

      - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0

      - name: "Run auto generation scripts"
        run: |
          ./scripts/autogenerate_files.sh

      - name: "Check for uncommitted changes"
        run: |
          if [[ -n "$(git status --porcelain)" ]]; then
            echo "Error: Auto-generated files were manually edited."
            echo "Files with changes:"
            git status --porcelain
            exit 1
          fi

  docs:
    timeout-minutes: 10
    name: "mkdocs"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false
      - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0

      - name: "Build docs"
        run: uvx --with-requirements docs/requirements.txt mkdocs build --strict -f mkdocs.yml


================================================
FILE: .github/workflows/daily_property_tests.yml
================================================
name: Daily property test run

on:
  workflow_dispatch:
  schedule:
    - cron: "0 12 * * *"
  pull_request:
    paths:
      - ".github/workflows/daily_property_tests.yml"

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

env:
  CARGO_INCREMENTAL: 0
  CARGO_NET_RETRY: 10
  CARGO_TERM_COLOR: always
  RUSTUP_MAX_RETRIES: 10
  FORCE_COLOR: 1

jobs:
  property_tests:
    name: Property tests
    runs-on: ubuntu-latest
    timeout-minutes: 20
    # Don't run the cron job on forks:
    if: ${{ github.repository == 'astral-sh/ty' || github.event_name != 'schedule' }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          repository: astral-sh/ruff
      - name: "Install Rust toolchain"
        run: rustup show
      - name: "Install mold"
        uses: rui314/setup-mold@725a8794d15fc7563f59595bd9556495c0564878 # v1
      - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
      - name: Build ty
        # A release build takes longer (2 min vs 1 min), but the property tests run much faster in release
        # mode (1.5 min vs 14 min), so the overall time is shorter with a release build.
        run: cargo build --locked --release --package ty_python_semantic --tests
      - name: Run property tests
        shell: bash
        run: |
          export QUICKCHECK_TESTS=100000
          for _ in {1..5}; do
            cargo test --locked --release --package ty_python_semantic -- --ignored list::property_tests
            cargo test --locked --release --package ty_python_semantic -- --ignored types::property_tests::stable
          done

  create-issue-on-failure:
    name: Create an issue if the daily property test run surfaced any bugs
    runs-on: ubuntu-latest
    needs: property_tests
    if: ${{ github.repository == 'astral-sh/ty' && always() && github.event_name == 'schedule' && needs.property_tests.result == 'failure' }}
    permissions:
      issues: write
    steps:
      - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            await github.rest.issues.create({
              owner: "astral-sh",
              repo: "ty",
              title: `Daily property test run failed on ${new Date().toDateString()}`,
              body: "Run listed here: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
              labels: ["bug", "type properties"],
            })


================================================
FILE: .github/workflows/publish-docs.yml
================================================
# Publish the ty documentation.
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a post-announce
# job within `cargo-dist`.
name: mkdocs

on:
  workflow_dispatch:
    inputs:
      ref:
        description: "The commit SHA, tag, or branch to publish. Uses the default branch if not specified."
        default: ""
        type: string
  workflow_call:
    inputs:
      plan:
        required: true
        type: string

permissions:
  contents: read

jobs:
  mkdocs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ inputs.ref }}
          persist-credentials: true

      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: 3.14

      - name: "Set docs version"
        env:
          version: ${{ (inputs.plan != '' && fromJson(inputs.plan).announcement_tag) || inputs.ref }}
        run: |
          # if version is missing, use 'latest'
          if [ -z "$version" ]; then
            echo "Using 'latest' as version"
            version="latest"
          fi

          # Use version as display name for now
          display_name="$version"

          echo "version=$version" >> "$GITHUB_ENV"
          echo "display_name=$display_name" >> "$GITHUB_ENV"

      - name: "Set branch name"
        run: |
          timestamp="$(date +%s)"

          # create branch_display_name from display_name by replacing all
          # characters disallowed in git branch names with hyphens
          branch_display_name="$(echo "${display_name}" | tr -c '[:alnum:]._' '-' | tr -s '-')"

          echo "branch_name=update-docs-$branch_display_name-$timestamp" >> "$GITHUB_ENV"
          echo "timestamp=$timestamp" >> "$GITHUB_ENV"

      - name: "Install dependencies"
        run: pip install -r docs/requirements.txt

      - name: "Build docs"
        run: mkdocs build --strict -f mkdocs.yml

      - name: "Clone docs repo"
        run: git clone https://${{ secrets.ASTRAL_DOCS_PAT }}@github.com/astral-sh/docs.git astral-docs

      - name: "Copy docs"
        run: rm -rf astral-docs/site/ty && mkdir -p astral-docs/site && cp -r site/ty astral-docs/site/

      - name: "Commit docs"
        working-directory: astral-docs
        run: |
          git config user.name "astral-docs-bot"
          git config user.email "176161322+astral-docs-bot@users.noreply.github.com"

          git checkout -b "${branch_name}"
          git add site/ty
          git commit -m "Update ty documentation for $version"

      - name: "Create Pull Request"
        working-directory: astral-docs
        env:
          GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }}
        run: |
          # set the PR title
          pull_request_title="Update ty documentation for ${display_name}"

          # Delete any existing pull requests that are open for this version
          # by checking against pull_request_title because the new PR will
          # supersede the old one.
          gh pr list --state open --json title --jq '.[] | select(.title == "$pull_request_title") | .number' | \
            xargs -I {} gh pr close {}

          # push the branch to GitHub
          git push origin "${branch_name}"

          # create the PR
          gh pr create \
            --base=main \
            --head="${branch_name}" \
            --title="${pull_request_title}" \
            --body="Automated documentation update for ${display_name}" \
            --label="documentation"

      - name: "Merge Pull Request"
        if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
        working-directory: astral-docs
        env:
          GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }}
        run: |
          # auto-merge the PR if the build was triggered by a release. Manual builds should be reviewed by a human.
          # give the PR a few seconds to be created before trying to auto-merge it
          sleep 10
          gh pr merge --squash "${branch_name}"


================================================
FILE: .github/workflows/publish-mirror.yml
================================================
# Publish ty releases to a mirror
#
# Assumed to run as a subworkflow of .github/workflows/release.yml as a custom publish job
name: publish-mirror

on:
  workflow_call:
    inputs:
      plan:
        required: true
        type: string

permissions: {}

jobs:
  publish-mirror:
    runs-on: ubuntu-latest
    environment:
      name: release
    env:
      VERSION: ${{ fromJson(inputs.plan).announcement_tag }}
    steps:
      - name: "Download GitHub Artifacts"
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          pattern: artifacts-*
          path: artifacts
          merge-multiple: true
      - name: "Upload to R2"
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.MIRROR_R2_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.MIRROR_R2_SECRET_ACCESS_KEY }}
          AWS_ENDPOINT_URL: https://${{ secrets.MIRROR_R2_CLOUDFLARE_ACCOUNT_ID }}.r2.cloudflarestorage.com
          AWS_DEFAULT_REGION: auto
          R2_BUCKET: ${{ secrets.MIRROR_R2_BUCKET_NAME }}
          PROJECT: ty
        run: |
          aws s3 cp --recursive --output table --color on \
            --exclude '*' \
            --include '*.zip' --include '*.zip.sha256' \
            --include '*.tar.gz' --include '*.tar.gz.sha256' \
            --include sha256.sum --include '*.ps1' --include '*.sh' \
            --cache-control "public, max-age=31536000, immutable" \
            artifacts/ \
            "s3://${R2_BUCKET}/github/${PROJECT}/releases/download/${VERSION}/"


================================================
FILE: .github/workflows/publish-pypi.yml
================================================
# Publish a release to PyPI.
#
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a publish job
# within `cargo-dist`.
name: "Publish to PyPI"

on:
  workflow_call:
    inputs:
      plan:
        required: true
        type: string

jobs:
  pypi-publish:
    name: Upload to PyPI
    runs-on: ubuntu-latest
    environment:
      name: release
    permissions:
      # For PyPI's trusted publishing.
      id-token: write
    steps:
      - name: "Install uv"
        uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
      - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
        with:
          pattern: wheels-*
          path: wheels
          merge-multiple: true
      - name: Publish to PyPi
        run: uv publish -v wheels/*


================================================
FILE: .github/workflows/release.yml
================================================
# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist
#
# Copyright 2022-2024, axodotdev
# SPDX-License-Identifier: MIT or Apache-2.0
#
# CI that:
#
# * checks for a Git Tag that looks like a release
# * builds artifacts with dist (archives, installers, hashes)
# * uploads those artifacts to temporary workflow zip
# * on success, uploads the artifacts to a GitHub Release
#
# Note that the GitHub Release will be created with a generated
# title/body based on your changelogs.

name: Release
permissions:
  "contents": "write"

# This task will run whenever you workflow_dispatch with a tag that looks like a version
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
# must be a Cargo-style SemVer Version (must have at least major.minor.patch).
#
# If PACKAGE_NAME is specified, then the announcement will be for that
# package (erroring out if it doesn't have the given version or isn't dist-able).
#
# If PACKAGE_NAME isn't specified, then the announcement will be for all
# (dist-able) packages in the workspace with that version (this mode is
# intended for workspaces with only one dist-able package, or with all dist-able
# packages versioned/released in lockstep).
#
# If you push multiple tags at once, separate instances of this workflow will
# spin up, creating an independent announcement for each one. However, GitHub
# will hard limit this to 3 tags per commit, as it will assume more tags is a
# mistake.
#
# If there's a prerelease-style suffix to the version, then the release(s)
# will be marked as a prerelease.
on:
  pull_request:
  workflow_dispatch:
    inputs:
      tag:
        description: Release Tag
        required: true
        default: dry-run
        type: string

jobs:
  # Run 'dist plan' (or host) to determine what tasks we need to do
  plan:
    runs-on: "depot-ubuntu-latest-4"
    outputs:
      val: ${{ steps.plan.outputs.manifest }}
      tag: ${{ (inputs.tag != 'dry-run' && inputs.tag) || '' }}
      tag-flag: ${{ inputs.tag && inputs.tag != 'dry-run' && format('--tag={0}', inputs.tag) || '' }}
      publishing: ${{ inputs.tag && inputs.tag != 'dry-run' }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false
          submodules: recursive
      - name: Install dist
        # we specify bash to get pipefail; it guards against the `curl` command
        # failing. otherwise `sh` won't catch that `curl` returned non-0
        shell: bash
        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh"
      - name: Cache dist
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/dist
      # sure would be cool if github gave us proper conditionals...
      # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
      # functionality based on whether this is a pull_request, and whether it's from a fork.
      # (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
      # but also really annoying to build CI around when it needs secrets to work right.)
      - id: plan
        run: |
          dist ${{ (inputs.tag && inputs.tag != 'dry-run' && format('host --steps=create --tag={0}', inputs.tag)) || 'plan' }} --output-format=json > plan-dist-manifest.json
          echo "dist ran successfully"
          cat plan-dist-manifest.json
          echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
      - name: "Upload dist-manifest.json"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
        with:
          name: artifacts-plan-dist-manifest
          path: plan-dist-manifest.json

  custom-build-binaries:
    needs:
      - plan
    if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
    uses: ./.github/workflows/build-binaries.yml
    with:
      plan: ${{ needs.plan.outputs.val }}
    secrets: inherit

  custom-build-docker:
    needs:
      - plan
    if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }}
    uses: ./.github/workflows/build-docker.yml
    with:
      plan: ${{ needs.plan.outputs.val }}
    secrets: inherit
    permissions:
      "attestations": "write"
      "contents": "read"
      "id-token": "write"
      "packages": "write"

  # Build and package all the platform-agnostic(ish) things
  build-global-artifacts:
    needs:
      - plan
      - custom-build-binaries
      - custom-build-docker
    runs-on: "depot-ubuntu-latest-4"
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
    steps:
      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false
          submodules: recursive
      - name: Install cached dist
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/
      - run: chmod +x ~/.cargo/bin/dist
      # Get all the local artifacts for the global tasks to use (for e.g. checksums)
      - name: Fetch local artifacts
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          pattern: artifacts-*
          path: target/distrib/
          merge-multiple: true
      - id: cargo-dist
        shell: bash
        run: |
          dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
          echo "dist ran successfully"

          # Parse out what we just built and upload it to scratch storage
          echo "paths<<EOF" >> "$GITHUB_OUTPUT"
          jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
          echo "EOF" >> "$GITHUB_OUTPUT"

          cp dist-manifest.json "$BUILD_MANIFEST_NAME"
      - name: "Upload artifacts"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
        with:
          name: artifacts-build-global
          path: |
            ${{ steps.cargo-dist.outputs.paths }}
            ${{ env.BUILD_MANIFEST_NAME }}
  # Determines if we should publish/announce
  host:
    needs:
      - plan
      - custom-build-binaries
      - custom-build-docker
      - build-global-artifacts
    # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine)
    if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    runs-on: "depot-ubuntu-latest-4"
    outputs:
      val: ${{ steps.host.outputs.manifest }}
    steps:
      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false
          submodules: recursive
      - name: Install cached dist
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          name: cargo-dist-cache
          path: ~/.cargo/bin/
      - run: chmod +x ~/.cargo/bin/dist
      # Fetch artifacts from scratch-storage
      - name: Fetch artifacts
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          pattern: artifacts-*
          path: target/distrib/
          merge-multiple: true
      # This is a harmless no-op for GitHub Releases, hosting for that happens in "announce"
      - id: host
        shell: bash
        run: |
          dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
          echo "artifacts uploaded and released successfully"
          cat dist-manifest.json
          echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
      - name: "Upload dist-manifest.json"
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
        with:
          # Overwrite the previous copy
          name: artifacts-dist-manifest
          path: dist-manifest.json

  custom-publish-pypi:
    needs:
      - plan
      - host
    if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
    uses: ./.github/workflows/publish-pypi.yml
    with:
      plan: ${{ needs.plan.outputs.val }}
    secrets: inherit
    # publish jobs get escalated permissions
    permissions:
      "id-token": "write"
      "packages": "write"

  # Create a GitHub Release while uploading all files to it
  announce:
    needs:
      - plan
      - host
      - custom-publish-pypi
    # use "always() && ..." to allow us to wait for all publish jobs while
    # still allowing individual publish jobs to skip themselves (for prereleases).
    # "host" however must run to completion, no skipping allowed!
    if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') }}
    runs-on: "depot-ubuntu-latest-4"
    permissions:
      "attestations": "write"
      "contents": "write"
      "id-token": "write"
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
        with:
          persist-credentials: false
          submodules: recursive
      # Create a GitHub Release while uploading all files to it
      - name: "Download GitHub Artifacts"
        uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3
        with:
          pattern: artifacts-*
          path: artifacts
          merge-multiple: true
      - name: Cleanup
        run: |
          # Remove the granular manifests
          rm -f artifacts/*-dist-manifest.json
      - name: Attest
        uses: actions/attest-build-provenance@00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8
        with:
          subject-path: |
            artifacts/*.json
            artifacts/*.sh
            artifacts/*.ps1
            artifacts/*.zip
            artifacts/*.tar.gz
      - name: Create GitHub Release
        env:
          PRERELEASE_FLAG: "${{ fromJson(needs.host.outputs.val).announcement_is_prerelease && '--prerelease' || '' }}"
          ANNOUNCEMENT_TITLE: "${{ fromJson(needs.host.outputs.val).announcement_title }}"
          ANNOUNCEMENT_BODY: "${{ fromJson(needs.host.outputs.val).announcement_github_body }}"
          RELEASE_COMMIT: "${{ github.sha }}"
        run: |
          # Write and read notes from a file to avoid quoting breaking things
          echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt

          gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*

  custom-publish-docs:
    needs:
      - plan
      - announce
    uses: ./.github/workflows/publish-docs.yml
    with:
      plan: ${{ needs.plan.outputs.val }}
    secrets: inherit

  custom-publish-mirror:
    needs:
      - plan
      - announce
    uses: ./.github/workflows/publish-mirror.yml
    with:
      plan: ${{ needs.plan.outputs.val }}
    secrets: inherit
    permissions:
      "contents": "read"


================================================
FILE: .github/zizmor.yml
================================================
rules:
  secrets-outside-env:
    ignore:
      # TODO: move the ASTRAL_DOCS_PAT secret to the release environment
      - publish-docs.yml


================================================
FILE: .gitignore
================================================
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# Virtual environments
.venv


================================================
FILE: .gitmodules
================================================
[submodule "ruff"]
	path = ruff
	url = https://github.com/astral-sh/ruff


================================================
FILE: .markdownlint.yaml
================================================
# default to true for all rules
default: true

# MD007/unordered-list-indent
MD007:
  indent: 4

# MD033/no-inline-html
MD033: false

# MD041/first-line-h1
MD041: false

# MD013/line-length
MD013: false

# MD014/commands-show-output
MD014: false

# MD024/no-duplicate-heading
MD024:
  # Allow when nested under different parents e.g. CHANGELOG.md
  siblings_only: true

# MD046/code-block-style
#
# Ignore this because it conflicts with the code block style used in content
# tabs of mkdocs-material which is to add a blank line after the content title.
#
# Ref: https://github.com/astral-sh/ruff/pull/15011#issuecomment-2544790854
MD046: false

# Link text should be descriptive
# Disallows link text like *here* which is annoying.
MD059: false


================================================
FILE: .pre-commit-config.yaml
================================================
fail_fast: false

exclude: |
  (?x)^(
    .github/workflows/release.yml|
    ruff/.*|
    docs/reference/(cli|configuration|rules|environment).md
  )$

repos:
  # Priority 0: Read-only hooks; hooks that modify disjoint file types.
  - repo: https://github.com/astral-sh/uv-pre-commit
    rev: 0.10.9
    hooks:
      - id: uv-lock
        priority: 0

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: check-merge-conflict
        priority: 0

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.15.5
    hooks:
      - id: ruff-format
        priority: 0
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]
        types_or: [python, pyi]
        require_serial: true
        priority: 1

  - repo: https://github.com/abravalheri/validate-pyproject
    rev: v0.25
    hooks:
      - id: validate-pyproject
        priority: 0

  - repo: https://github.com/executablebooks/mdformat
    rev: 1.0.0
    hooks:
      - id: mdformat
        language: python # means renovate will also update `additional_dependencies`
        additional_dependencies:
          - mdformat-mkdocs==5.1.4
          - mdformat-footnote==0.1.3
        priority: 0

  - repo: https://github.com/igorshubovych/markdownlint-cli
    rev: v0.48.0
    hooks:
      - id: markdownlint-fix
        priority: 1

  - repo: https://github.com/crate-ci/typos
    rev: v1.44.0
    hooks:
      - id: typos
        priority: 0

  # Prettier
  - repo: https://github.com/rbubley/mirrors-prettier
    rev: v3.8.1
    hooks:
      - id: prettier
        types: [yaml]
        priority: 0

  # zizmor detects security vulnerabilities in GitHub Actions workflows.
  # Additional configuration for the tool is found in `.github/zizmor.yml`
  - repo: https://github.com/zizmorcore/zizmor-pre-commit
    rev: v1.23.1
    hooks:
      - id: zizmor
        priority: 0

  - repo: https://github.com/shellcheck-py/shellcheck-py
    rev: v0.11.0.1
    hooks:
      - id: shellcheck
        priority: 0

  - repo: https://github.com/python-jsonschema/check-jsonschema
    rev: 0.37.0
    hooks:
      - id: check-github-workflows
        priority: 0

  # `actionlint` hook, for verifying correct syntax in GitHub Actions workflows.
  # Some additional configuration for `actionlint` can be found in `.github/actionlint.yaml`.
  - repo: https://github.com/rhysd/actionlint
    rev: v1.7.11
    hooks:
      - id: actionlint
        stages:
          # This hook is disabled by default, since it's quite slow.
          # To run all hooks *including* this hook, use `uvx pre-commit run -a --hook-stage=manual`.
          # To run *just* this hook, use `uvx pre-commit run -a actionlint --hook-stage=manual`.
          - manual
        args:
          - "-ignore=SC2129" # ignorable stylistic lint from shellcheck
          - "-ignore=SC2016" # another shellcheck lint: seems to have false positives?
        language: golang # means renovate will also update `additional_dependencies`
        additional_dependencies:
          # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions
          # and checks these with shellcheck. This is arguably its most useful feature,
          # but the integration only works if shellcheck is installed
          - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1"
        priority: 0


================================================
FILE: .python-version
================================================
3.13


================================================
FILE: BENCHMARKS.md
================================================
# Benchmarks

All benchmarks were computed on macOS (Apple M4 Pro 14, 48 GB) with the following tool versions:

- [Pyrefly](https://pypi.org/project/pyrefly/) 0.45.2
- [Pyright](https://www.npmjs.com/package/pyright) 1.1.407
- [mypy](https://pypi.org/project/mypy/) \<=1.19.0
- [ty](https://pypi.org/project/ty/) 0.0.2

Benchmark performance may vary across operating systems, and from project to project. This document
includes benchmarks from a variety of projects to provide a representative example of real-world
usage: [Black](https://github.com/psf/black), [discord.py](https://github.com/Rapptz/discord.py),
[Home Assistant](https://github.com/home-assistant/core), [isort](https://github.com/pycqa/isort),
[Jinja](https://github.com/pallets/jinja), [pandas](https://github.com/pandas-dev/pandas),
[pandas-stubs](https://github.com/pandas-dev/pandas-stubs),
[Prefect](https://github.com/PrefectHQ/prefect), and [PyTorch](https://github.com/pytorch/pytorch).

For instructions on running the benchmarks, see
[`ty_benchmark/README.md`](https://github.com/astral-sh/ruff/blob/7f7485d608d2da19a0632a1238f2d4be551f612f/scripts/ty_benchmark/README.md).

## CLI

```text
black
-----

Benchmark 1: ty
  Time (mean ± σ):      53.8 ms ±   1.6 ms    [User: 344.9 ms, System: 36.3 ms]
  Range (min … max):    51.4 ms …  57.9 ms    49 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     167.4 ms ±   5.2 ms    [User: 648.8 ms, System: 157.8 ms]
  Range (min … max):   159.3 ms … 177.0 ms    18 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):      1.197 s ±  0.008 s    [User: 1.144 s, System: 0.051 s]
  Range (min … max):    1.186 s …  1.212 s    10 runs

Benchmark 4: Pyright
  Time (mean ± σ):      1.193 s ±  0.020 s    [User: 13.264 s, System: 0.808 s]
  Range (min … max):    1.173 s …  1.240 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    3.11 ± 0.13 times faster than Pyrefly
   22.16 ± 0.74 times faster than Pyright
   22.25 ± 0.66 times faster than mypy

-------------------------------------------------------------------------------

discord.py
----------

Benchmark 1: ty
  Time (mean ± σ):     272.3 ms ±   1.4 ms    [User: 1436.3 ms, System: 99.3 ms]
  Range (min … max):   270.5 ms … 275.6 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     312.7 ms ±  23.9 ms    [User: 2585.5 ms, System: 244.1 ms]
  Range (min … max):   283.4 ms … 367.9 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):      6.617 s ±  0.212 s    [User: 6.521 s, System: 0.091 s]
  Range (min … max):    6.233 s …  6.852 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 4: Pyright
  Time (mean ± σ):      2.874 s ±  0.078 s    [User: 35.269 s, System: 1.710 s]
  Range (min … max):    2.753 s …  2.964 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    1.15 ± 0.09 times faster than Pyrefly
   10.55 ± 0.29 times faster than Pyright
   24.30 ± 0.79 times faster than mypy

-------------------------------------------------------------------------------

homeassistant
-------------

Benchmark 1: ty
  Time (mean ± σ):      2.186 s ±  0.083 s    [User: 23.139 s, System: 2.920 s]
  Range (min … max):    2.067 s …  2.355 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):      5.320 s ±  0.020 s    [User: 25.054 s, System: 33.545 s]
  Range (min … max):    5.294 s …  5.365 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     45.662 s ±  0.224 s    [User: 43.882 s, System: 1.767 s]
  Range (min … max):   45.328 s … 46.009 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 4: Pyright
  Time (mean ± σ):     19.623 s ±  0.425 s    [User: 227.040 s, System: 21.942 s]
  Range (min … max):   19.255 s … 20.748 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    2.43 ± 0.09 times faster than Pyrefly
    8.98 ± 0.39 times faster than Pyright
   20.89 ± 0.80 times faster than mypy

-------------------------------------------------------------------------------

isort
-----

Benchmark 1: ty
  Time (mean ± σ):      39.0 ms ±   1.1 ms    [User: 161.0 ms, System: 21.0 ms]
  Range (min … max):    36.2 ms …  41.2 ms    67 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     138.5 ms ±   2.8 ms    [User: 462.0 ms, System: 82.2 ms]
  Range (min … max):   132.2 ms … 143.8 ms    21 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     581.2 ms ±   2.2 ms    [User: 547.8 ms, System: 31.2 ms]
  Range (min … max):   578.4 ms … 584.9 ms    10 runs

Benchmark 4: Pyright
  Time (mean ± σ):      2.453 s ±  0.032 s    [User: 13.608 s, System: 0.743 s]
  Range (min … max):    2.402 s …  2.504 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    3.55 ± 0.13 times faster than Pyrefly
   14.91 ± 0.44 times faster than mypy
   62.90 ± 2.02 times faster than Pyright

-------------------------------------------------------------------------------

jinja
-----

Benchmark 1: ty
  Time (mean ± σ):     110.2 ms ±   3.3 ms    [User: 326.8 ms, System: 27.6 ms]
  Range (min … max):   107.0 ms … 119.0 ms    26 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     134.5 ms ±   1.7 ms    [User: 444.8 ms, System: 87.5 ms]
  Range (min … max):   131.5 ms … 137.8 ms    21 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     700.9 ms ±  13.2 ms    [User: 665.5 ms, System: 33.0 ms]
  Range (min … max):   693.7 ms … 737.7 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 4: Pyright
  Time (mean ± σ):      1.099 s ±  0.014 s    [User: 12.235 s, System: 0.736 s]
  Range (min … max):    1.081 s …  1.127 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    1.22 ± 0.04 times faster than Pyrefly
    6.36 ± 0.23 times faster than mypy
    9.97 ± 0.33 times faster than Pyright

-------------------------------------------------------------------------------

pandas
------

Benchmark 1: ty
  Time (mean ± σ):     551.5 ms ±  56.7 ms    [User: 4906.6 ms, System: 222.6 ms]
  Range (min … max):   467.6 ms … 614.8 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):      1.174 s ±  0.012 s    [User: 11.917 s, System: 1.035 s]
  Range (min … max):    1.149 s …  1.186 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     21.366 s ±  0.083 s    [User: 21.112 s, System: 0.247 s]
  Range (min … max):   21.234 s … 21.539 s    10 runs

Benchmark 4: Pyright
  Time (mean ± σ):      6.878 s ±  0.082 s    [User: 80.281 s, System: 3.504 s]
  Range (min … max):    6.749 s …  7.001 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    2.13 ± 0.22 times faster than Pyrefly
   12.47 ± 1.29 times faster than Pyright
   38.74 ± 3.99 times faster than mypy

-------------------------------------------------------------------------------

pandas-stubs
------------

Benchmark 1: ty
  Time (mean ± σ):      83.2 ms ±   2.8 ms    [User: 377.9 ms, System: 50.1 ms]
  Range (min … max):    75.3 ms …  87.1 ms    36 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     253.6 ms ±   6.0 ms    [User: 853.5 ms, System: 322.0 ms]
  Range (min … max):   245.2 ms … 264.2 ms    11 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):      5.290 s ±  0.028 s    [User: 5.150 s, System: 0.135 s]
  Range (min … max):    5.248 s …  5.332 s    10 runs

Benchmark 4: Pyright
  Time (mean ± σ):      1.792 s ±  0.030 s    [User: 17.300 s, System: 1.199 s]
  Range (min … max):    1.760 s …  1.843 s    10 runs

Summary
  ty ran
    3.05 ± 0.12 times faster than Pyrefly
   21.55 ± 0.80 times faster than Pyright
   63.61 ± 2.15 times faster than mypy

-------------------------------------------------------------------------------

prefect
-------

Benchmark 1: ty
  Time (mean ± σ):      92.4 ms ±   1.1 ms    [User: 524.8 ms, System: 70.1 ms]
  Range (min … max):    90.8 ms …  95.1 ms    30 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):     322.3 ms ±   7.9 ms    [User: 1061.7 ms, System: 691.8 ms]
  Range (min … max):   305.0 ms … 330.5 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     742.5 ms ±   3.4 ms    [User: 702.0 ms, System: 38.1 ms]
  Range (min … max):   737.6 ms … 749.0 ms    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 4: Pyright
  Time (mean ± σ):      3.545 s ±  0.042 s    [User: 41.849 s, System: 2.252 s]
  Range (min … max):    3.507 s …  3.641 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    3.49 ± 0.10 times faster than Pyrefly
    8.03 ± 0.10 times faster than mypy
   38.35 ± 0.64 times faster than Pyright

-------------------------------------------------------------------------------

pytorch
-------

Benchmark 1: ty
  Time (mean ± σ):      1.160 s ±  0.115 s    [User: 11.200 s, System: 1.344 s]
  Range (min … max):    1.034 s …  1.314 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 2: Pyrefly
  Time (mean ± σ):      2.084 s ±  0.029 s    [User: 19.660 s, System: 4.377 s]
  Range (min … max):    2.051 s …  2.143 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 3: mypy
  Time (mean ± σ):     30.157 s ±  0.155 s    [User: 29.776 s, System: 0.373 s]
  Range (min … max):   29.956 s … 30.454 s    10 runs

  Warning: Ignoring non-zero exit code.

Benchmark 4: Pyright
  Time (mean ± σ):     12.770 s ±  0.294 s    [User: 149.537 s, System: 8.990 s]
  Range (min … max):   12.357 s … 13.175 s    10 runs

  Warning: Ignoring non-zero exit code.

Summary
  ty ran
    1.80 ± 0.18 times faster than Pyrefly
   11.01 ± 1.12 times faster than Pyright
   26.01 ± 2.59 times faster than mypy
```

## LSP

### Incremental edit

```shell
----------------------------------------------------------------------------------------- benchmark 'black': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                             Min                 Max                Mean            StdDev              Median               IQR            Outliers       OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[black-ty]            8.8965 (1.0)        9.4442 (1.0)        9.1480 (1.0)      0.1953 (1.0)        9.1324 (1.0)      0.3284 (1.0)           4;0  109.3131 (1.0)          10           1
test_incremental_edit[black-pyrefly]     181.7555 (20.43)    192.5020 (20.38)    186.0771 (20.34)    4.5209 (23.15)    183.9968 (20.15)    8.1744 (24.89)         2;0    5.3741 (0.05)         10           1
test_incremental_edit[black-pyright]     418.8096 (47.08)    436.1230 (46.18)    430.3303 (47.04)    5.7802 (29.60)    432.2938 (47.34)    7.9072 (24.08)         3;0    2.3238 (0.02)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'discord.py': 3 tests -----------------------------------------------------------------------------------------
Name (time in ms)                                  Min                 Max                Mean             StdDev              Median                IQR            Outliers      OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[discord.py-ty]           11.0239 (1.0)       11.4890 (1.0)       11.2585 (1.0)       0.1475 (1.0)       11.3125 (1.0)       0.2244 (1.0)           4;0  88.8216 (1.0)          10           1
test_incremental_edit[discord.py-pyrefly]     404.7799 (36.72)    540.6511 (47.06)    480.9133 (42.72)    39.8237 (269.90)   486.0451 (42.97)    36.0575 (160.67)        3;1   2.0794 (0.02)         10           1
test_incremental_edit[discord.py-pyright]     438.0625 (39.74)    459.7234 (40.01)    454.7564 (40.39)     7.2835 (49.36)    458.2917 (40.51)     9.2910 (41.40)         2;0   2.1990 (0.02)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------- benchmark 'homeassistant': 3 tests ---------------------------------------------------------------------------------------------
Name (time in ms)                                       Min                   Max                  Mean             StdDev                Median                IQR            Outliers      OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[homeassistant-ty]             26.2820 (1.0)         26.8146 (1.0)         26.5646 (1.0)       0.1786 (1.0)         26.5610 (1.0)       0.2392 (1.0)           4;0  37.6440 (1.0)          10           1
test_incremental_edit[homeassistant-pyright]       492.1233 (18.72)      513.8475 (19.16)      499.2279 (18.79)     6.6173 (37.05)      497.2621 (18.72)     6.0271 (25.20)         3;1   2.0031 (0.05)         10           1
test_incremental_edit[homeassistant-pyrefly]     1,858.6557 (70.72)    1,979.7762 (73.83)    1,923.3550 (72.40)    38.1201 (213.43)   1,917.0547 (72.18)    48.3089 (201.99)        4;0   0.5199 (0.01)         10           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------- benchmark 'isort': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                             Min                 Max                Mean            StdDev              Median               IQR            Outliers      OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[isort-ty]            9.9467 (1.0)       10.3084 (1.0)       10.1385 (1.0)      0.1117 (1.0)       10.1680 (1.0)      0.1633 (1.0)           3;0  98.6339 (1.0)          10           1
test_incremental_edit[isort-pyrefly]     116.1576 (11.68)    128.3192 (12.45)    122.6576 (12.10)    3.7490 (33.56)    123.0442 (12.10)    5.8752 (35.97)         3;0   8.1528 (0.08)         10           1
test_incremental_edit[isort-pyright]     383.3340 (38.54)    400.4724 (38.85)    390.9956 (38.57)    5.0222 (44.95)    389.3690 (38.29)    6.7132 (41.10)         3;0   2.5576 (0.03)         10           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------- benchmark 'jinja': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                             Min                 Max                Mean            StdDev              Median               IQR            Outliers      OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[jinja-ty]           43.7648 (1.0)       45.4928 (1.0)       44.3021 (1.0)      0.4960 (1.0)       44.2532 (1.0)      0.4335 (1.0)           2;1  22.5723 (1.0)          10           1
test_incremental_edit[jinja-pyrefly]     182.0870 (4.16)     194.4938 (4.28)     189.2674 (4.27)     4.0190 (8.10)     190.3916 (4.30)     2.8280 (6.52)          3;2   5.2835 (0.23)         10           1
test_incremental_edit[jinja-pyright]     424.4407 (9.70)     439.2709 (9.66)     432.3523 (9.76)     5.2093 (10.50)    432.5269 (9.77)     8.0710 (18.62)         4;0   2.3129 (0.10)         10           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------- benchmark 'pandas': 3 tests ----------------------------------------------------------------------------------------------
Name (time in ms)                                Min                   Max                  Mean              StdDev                Median                 IQR            Outliers      OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[pandas-ty]             69.6266 (1.0)         93.7763 (1.0)         81.3957 (1.0)        7.0073 (1.0)         81.2143 (1.0)        6.5060 (1.0)           3;0  12.2857 (1.0)          10           1
test_incremental_edit[pandas-pyright]       434.3018 (6.24)       540.0721 (5.76)       467.1337 (5.74)      34.8674 (4.98)       457.4263 (5.63)      46.5595 (7.16)          1;0   2.1407 (0.17)         10           1
test_incremental_edit[pandas-pyrefly]     3,756.2226 (53.95)    4,757.2635 (50.73)    4,377.4530 (53.78)    367.8468 (52.49)    4,486.5002 (55.24)    714.0047 (109.74)        5;0   0.2284 (0.02)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------- benchmark 'prefect': 3 tests ----------------------------------------------------------------------------------------------
Name (time in ms)                                 Min                   Max                  Mean              StdDev                Median                 IQR            Outliers       OPS            Rounds  Iterations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[prefect-ty]              4.7899 (1.0)          5.3654 (1.0)          5.0291 (1.0)        0.1827 (1.0)          4.9726 (1.0)        0.2836 (1.0)           3;0  198.8408 (1.0)          10           1
test_incremental_edit[prefect-pyright]       537.4210 (112.20)     555.0903 (103.46)     543.9572 (108.16)     5.3413 (29.24)      543.2359 (109.25)     7.0621 (24.90)         4;0    1.8384 (0.01)         10           1
test_incremental_edit[prefect-pyrefly]     2,486.7581 (519.17)   3,972.1852 (740.34)   3,280.6660 (652.33)   500.2204 (>1000.0)  3,231.6573 (649.90)   706.5563 (>1000.0)       3;0    0.3048 (0.00)         10           1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------- benchmark 'pytorch': 3 tests ----------------------------------------------------------------------------------------------
Name (time in ms)                                 Min                   Max                  Mean              StdDev                Median                 IQR            Outliers       OPS            Rounds  Iterations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_incremental_edit[pytorch-ty]              4.3493 (1.0)          4.6291 (1.0)          4.4956 (1.0)        0.0940 (1.0)          4.4831 (1.0)        0.1323 (1.0)           4;0  222.4377 (1.0)          10           1
test_incremental_edit[pytorch-pyright]       367.6819 (84.54)      374.5961 (80.92)      370.4936 (82.41)      2.2878 (24.35)      370.5413 (82.65)      3.5865 (27.12)         2;0    2.6991 (0.01)         10           1
test_incremental_edit[pytorch-pyrefly]     2,333.3450 (536.48)   2,889.9276 (624.30)   2,604.7441 (579.39)   202.1562 (>1000.0)  2,582.8069 (576.12)   380.2684 (>1000.0)       4;0    0.3839 (0.00)         10           1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```

### Fetch diagnostics

```shell
----------------------------------------------------------------------------------------- benchmark 'black': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                              Min                 Max                Mean            StdDev              Median               IQR            Outliers      OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[black-ty]           40.5680 (1.0)       45.9828 (1.0)       43.4315 (1.0)      1.9415 (3.59)      43.4317 (1.0)      3.6550 (5.37)          5;0  23.0247 (1.0)          10           1
test_fetch_diagnostics[black-pyrefly]     131.4388 (3.24)     133.1042 (2.89)     132.3125 (3.05)     0.5407 (1.0)      132.2801 (3.05)     0.6808 (1.0)           3;0   7.5579 (0.33)         10           1
test_fetch_diagnostics[black-pyright]     234.5532 (5.78)     261.0507 (5.68)     241.2080 (5.55)     7.5489 (13.96)    238.8710 (5.50)     3.9942 (5.87)          1;1   4.1458 (0.18)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------- benchmark 'discord.py': 3 tests -----------------------------------------------------------------------------------------
Name (time in ms)                                   Min                 Max                Mean            StdDev              Median               IQR            Outliers      OPS            Rounds  Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[discord.py-ty]           88.1260 (1.0)       91.9354 (1.0)       89.9785 (1.0)      1.2617 (1.0)       89.8813 (1.0)      1.9953 (1.33)          3;0  11.1138 (1.0)          10           1
test_fetch_diagnostics[discord.py-pyrefly]     438.9406 (4.98)     462.2016 (5.03)     442.3538 (4.92)     7.0283 (5.57)     439.9846 (4.90)     1.4996 (1.0)           1;1   2.2606 (0.20)         10           1
test_fetch_diagnostics[discord.py-pyright]     488.1340 (5.54)     501.5540 (5.46)     493.6927 (5.49)     3.7678 (2.99)     493.7276 (5.49)     3.5742 (2.38)          3;1   2.0256 (0.18)         10           1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'homeassistant': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                                      Min                 Max                Mean             StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[homeassistant-ty]          109.6321 (1.0)      112.8913 (1.0)      111.4661 (1.0)       1.1174 (1.0)      111.4080 (1.0)      1.7967 (1.0)           5;0  8.9713 (1.0)          10           1
test_fetch_diagnostics[homeassistant-pyrefly]     218.1328 (1.99)     238.8827 (2.12)     222.4006 (2.00)      6.7033 (6.00)     219.6265 (1.97)     4.9113 (2.73)          2;1  4.4964 (0.50)         10           1
test_fetch_diagnostics[homeassistant-pyright]     888.3600 (8.10)     938.0845 (8.31)     901.1896 (8.08)     18.2062 (16.29)    893.4438 (8.02)     5.7174 (3.18)          2;2  1.1096 (0.12)         10           1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'isort': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                              Min                 Max                Mean            StdDev              Median               IQR            Outliers      OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[isort-ty]           41.8193 (1.0)       47.1411 (1.0)       43.6068 (1.0)      1.7622 (1.0)       43.1409 (1.0)      2.2658 (1.0)           3;0  22.9322 (1.0)          10           1
test_fetch_diagnostics[isort-pyrefly]     103.6808 (2.48)     110.2636 (2.34)     105.9967 (2.43)     2.6978 (1.53)     104.5978 (2.42)     5.5226 (2.44)          3;0   9.4343 (0.41)         10           1
test_fetch_diagnostics[isort-pyright]     297.8888 (7.12)     327.5334 (6.95)     306.2138 (7.02)     8.7235 (4.95)     304.5766 (7.06)     6.0185 (2.66)          1;1   3.2657 (0.14)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'jinja': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                              Min                 Max                Mean            StdDev              Median                IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[jinja-ty]          114.6546 (1.0)      129.8110 (1.0)      120.6856 (1.0)      5.6731 (3.75)     119.8813 (1.0)       9.1737 (7.27)          3;0  8.2860 (1.0)          10           1
test_fetch_diagnostics[jinja-pyrefly]     134.1455 (1.17)     139.0428 (1.07)     136.2655 (1.13)     1.5126 (1.0)      135.7366 (1.13)      1.2612 (1.0)           3;1  7.3386 (0.89)         10           1
test_fetch_diagnostics[jinja-pyright]     280.1174 (2.44)     305.6963 (2.35)     287.5077 (2.38)     8.9505 (5.92)     283.8312 (2.37)     10.0400 (7.96)          2;0  3.4782 (0.42)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------- benchmark 'pandas': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                               Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[pandas-ty]          289.0480 (1.0)      294.6924 (1.0)      292.1341 (1.0)      1.6226 (1.0)      292.2783 (1.0)      2.4183 (2.01)          2;0  3.4231 (1.0)          10           1
test_fetch_diagnostics[pandas-pyrefly]     522.8750 (1.81)     529.1068 (1.80)     524.6167 (1.80)     1.9387 (1.19)     524.1335 (1.79)     1.2023 (1.0)           2;2  1.9062 (0.56)         10           1
test_fetch_diagnostics[pandas-pyright]     928.4370 (3.21)     949.3941 (3.22)     941.8812 (3.22)     5.6550 (3.49)     943.2703 (3.23)     4.2351 (3.52)          2;1  1.0617 (0.31)         10           1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'prefect': 3 tests ----------------------------------------------------------------------------------------
Name (time in ms)                                Min                 Max                Mean             StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[prefect-ty]          123.5941 (1.0)      127.0129 (1.0)      125.3534 (1.0)       1.0498 (1.02)     125.1861 (1.0)      1.4461 (1.10)          3;0  7.9774 (1.0)          10           1
test_fetch_diagnostics[prefect-pyrefly]     437.5048 (3.54)     441.0088 (3.47)     438.7041 (3.50)      1.0287 (1.0)      438.4152 (3.50)     1.3126 (1.0)           2;0  2.2794 (0.29)         10           1
test_fetch_diagnostics[prefect-pyright]     828.5065 (6.70)     884.9894 (6.97)     845.3657 (6.74)     14.9587 (14.54)    842.5912 (6.73)     8.1088 (6.18)          2;1  1.1829 (0.15)         10           1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------- benchmark 'pytorch': 3 tests -----------------------------------------------------------------------------------------
Name (time in ms)                                Min                 Max                Mean            StdDev              Median                IQR            Outliers      OPS            Rounds  Iterations
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_fetch_diagnostics[pytorch-ty]           51.7146 (1.0)       59.2463 (1.0)       54.3685 (1.0)      2.2254 (2.06)      54.3844 (1.0)       3.0549 (2.12)          2;0  18.3930 (1.0)          10           1
test_fetch_diagnostics[pytorch-pyrefly]     174.7057 (3.38)     178.1138 (3.01)     175.7364 (3.23)     1.0824 (1.0)      175.5052 (3.23)      1.4398 (1.0)           1;0   5.6903 (0.31)         10           1
test_fetch_diagnostics[pytorch-pyright]     447.4101 (8.65)     474.9993 (8.02)     460.5399 (8.47)     9.8641 (9.11)     461.9636 (8.49)     18.7404 (13.02)         3;0   2.1714 (0.12)         10           1
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
```


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## 0.0.24

Released on 2026-03-19.

### Bug fixes

- Ensure `TypedDict` subscripts for unknown keys return `Unknown` ([#23926](https://github.com/astral-sh/ruff/pull/23926))
- Fix overflow with recursive `TypeIs` ([#23784](https://github.com/astral-sh/ruff/pull/23784))
- Fix variance of frozen dataclass-transform models ([#23931](https://github.com/astral-sh/ruff/pull/23931))

### LSP server

- Improve [semantic token](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens) classification for attribute access on union types ([#23841](https://github.com/astral-sh/ruff/pull/23841))

### Core type checking

- Improve performance and correctness by avoiding inferring intersection types for call arguments as a result of bidirectional inference ([#23933](https://github.com/astral-sh/ruff/pull/23933))
- Narrow keyword arguments when unpacking dictionary instances ([#23436](https://github.com/astral-sh/ruff/pull/23436))
- Discover `/usr/local/lib` dist-packages on Debian/Ubuntu ([#23797](https://github.com/astral-sh/ruff/pull/23797))
- Sync vendored typeshed stubs ([#23963](https://github.com/astral-sh/ruff/pull/23963)). [Typeshed diff](https://github.com/python/typeshed/compare/fa659b1def704dea3dc8e25c7857b23eac69df4d...f8f0794d0fe249c06dc9f31a004d85be6cca6ced)

## Performance

- Introduce fast path for protocol non-assignability ([#23952](https://github.com/astral-sh/ruff/pull/23952))
- Improved generic-solver performance in cases involving overload sets ([#23881](https://github.com/astral-sh/ruff/pull/23881))

### Contributors

- [@Geo5](https://github.com/Geo5)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@charliermarsh](https://github.com/charliermarsh)
- [@dcreager](https://github.com/dcreager)
- [@ollema](https://github.com/ollema)
- [@sharkdp](https://github.com/sharkdp)

## 0.0.23

Released on 2026-03-13.

### Bug fixes

- Fix false-positive diagnostics for PEP-604 union annotations on attribute targets on Python 3.9 when `from __future__ import annotations` is active ([#23915](https://github.com/astral-sh/ruff/pull/23915))
- `dataclass_transform`: Respect `kw_only` overwrites in dataclasses ([#23930](https://github.com/astral-sh/ruff/pull/23930))
- Fix too-many-cycle panics when inferring loop variables with `Literal` types ([#23875](https://github.com/astral-sh/ruff/pull/23875))

### Server

- Fix [folding range](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_foldingRange) classification of lines starting with `#` ([#23831](https://github.com/astral-sh/ruff/pull/23831))
- Fix [folding ranges](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_foldingRange) for notebooks ([#23830](https://github.com/astral-sh/ruff/pull/23830))

### Core type checking

- Split errors for possibly missing submodules into a new `possibly-missing-submodule` error code (enabled by default), and make `possibly-missing-attribute` ignored by default ([#23918](https://github.com/astral-sh/ruff/pull/23918))
- Improve handling of bidirectional inference when ([#23844](https://github.com/astral-sh/ruff/pull/23844))
- Fix inference of conditionally defined properties ([#23925](https://github.com/astral-sh/ruff/pull/23925))

### Improvements to diagnostics

- Clarify in diagnostics that `from __future__ import annotations` only stringifies type annotations ([#23928](https://github.com/astral-sh/ruff/pull/23928))

### Performance improvements

- Avoid duplicated work during multi-inference ([#23923](https://github.com/astral-sh/ruff/pull/23923))

### Contributors

- [@ibraheemdev](https://github.com/ibraheemdev)
- [@sharkdp](https://github.com/sharkdp)
- [@oconnor663](https://github.com/oconnor663)
- [@mtshiba](https://github.com/mtshiba)
- [@MichaReiser](https://github.com/MichaReiser)
- [@carljm](https://github.com/carljm)
- [@AlexWaygood](https://github.com/AlexWaygood)

## 0.0.22

Released on 2026-03-12.

### Bug fixes

- Fix issue where variables could be inferred as `Divergent` if they were assigned using tuple unpacking in loops ([#23812](https://github.com/astral-sh/ruff/pull/23812))
- Allow `error = "all"` in a root `pyproject.toml` file to be overridden using `tool.ty.overrides` in a subdirectory's `pyproject.toml` file ([#23712](https://github.com/astral-sh/ruff/pull/23712))
- Only unsoundly upcast `type[]` types to their constructor `Callable` type during assignability checks, not during redundancy/subtyping checks ([#23834](https://github.com/astral-sh/ruff/pull/23834), [#23901](https://github.com/astral-sh/ruff/pull/23901))
- Fix stack overflow that could occur with certain recursive protocols ([#23870](https://github.com/astral-sh/ruff/pull/23870))

### LSP server

- Improve syntax highlighting by fixing [semantic token](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens) classification for generic class members in annotations ([#23811](https://github.com/astral-sh/ruff/pull/23811))

### CLI

- Add `ty explain <RULE>` CLI command ([#23766](https://github.com/astral-sh/ruff/pull/23766))

### Core type checking

- Add validation for type parameters with defaults after `TypeVarTuple` parameters ([#23807](https://github.com/astral-sh/ruff/pull/23807))
- Allow subtypes of `LiteralString` to be narrowed using equality checks ([#23794](https://github.com/astral-sh/ruff/pull/23794))
- Detect invalid partially stringified PEP-604 unions ([#23285](https://github.com/astral-sh/ruff/pull/23285))
- Disambiguate duplicate-looking overloaded callables in union display ([#23907](https://github.com/astral-sh/ruff/pull/23907))
- Don't promote module-literal types to `types.ModuleType` ([#23786](https://github.com/astral-sh/ruff/pull/23786))
- Improve type context support for `__setitem__` dunder calls ([#23800](https://github.com/astral-sh/ruff/pull/23800))
- Infer `t | {"foo": int}` as `TD` if `t` is an instance of a TypedDict `td` with a `foo: int` key ([#23806](https://github.com/astral-sh/ruff/pull/23806))
- Narrow `T` to `T & str` rather than `str` if `T` is a constrained TypeVar with `str` as one of its constraints ([#23850](https://github.com/astral-sh/ruff/pull/23850))
- Promote `None` to `None | Unknown` in invariant contexts ([#23790](https://github.com/astral-sh/ruff/pull/23790))
- Reject `type[Callable]` in type annotations ([#23753](https://github.com/astral-sh/ruff/pull/23753))
- Support enum member access through enum instances and members ([#23772](https://github.com/astral-sh/ruff/pull/23772))
- Eagerly narrow the type associated with keys of heterogeneous dict literals even when a dict literal appears as a subexpression inside a list or tuple literals ([#23569](https://github.com/astral-sh/ruff/pull/23569))
- Ensure that `T & ~S` is always inferred as a subtype of `U` during generic inference if `T` is understood as a subtype of `U` ([#23728](https://github.com/astral-sh/ruff/pull/23728))
- Optimize and improve cycle recovery by preventing "tainted" unions in cycle normalization ([#23563](https://github.com/astral-sh/ruff/pull/23563))

### Installer

- Prefer downloading releases from Astral's mirror over GitHub ([#2980](https://github.com/astral-sh/ty/pull/2980))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@MichaReiser](https://github.com/MichaReiser)
- [@mtshiba](https://github.com/mtshiba)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@ntBre](https://github.com/ntBre)
- [@oconnor663](https://github.com/oconnor663)
- [@zsol](https://github.com/zsol)

## 0.0.21

Released on 2026-03-05.

### Bug fixes

- Avoid stack overflow with recursive typevar ([#23652](https://github.com/astral-sh/ruff/pull/23652))
- Fix panic on incomplete except handlers ([#23708](https://github.com/astral-sh/ruff/pull/23708))
- Allow unions of different-length iterables in `*args` unpacking into optional positional parameters ([#23124](https://github.com/astral-sh/ruff/pull/23124))
- Don't replace `Any` attributes with `object` after `isinstance` narrowing ([#23725](https://github.com/astral-sh/ruff/pull/23725))

### LSP server

- Exclude decorators from class/def code folding ([#23543](https://github.com/astral-sh/ruff/pull/23543))
- Fix handling of non-Python text documents ([#23704](https://github.com/astral-sh/ruff/pull/23704))

### Configuration

- Add `all` selector to `ty.json` schema ([#23721](https://github.com/astral-sh/ruff/pull/23721))
- Fix precedence of `all` selector in TOML configurations ([#23723](https://github.com/astral-sh/ruff/pull/23723))
- Make `all` selector case-sensitive ([#23713](https://github.com/astral-sh/ruff/pull/23713))

### Type checking

- Add `invalid-enum-member-annotation` lint rule ([#23648](https://github.com/astral-sh/ruff/pull/23648))
- Add a diagnostic for an unused awaitable ([#23650](https://github.com/astral-sh/ruff/pull/23650))
- Add a diagnostic if a `TypeVar` is used to specialize a `ParamSpec`, or vice versa ([#23738](https://github.com/astral-sh/ruff/pull/23738))
- Add more type-variable default validation ([#23639](https://github.com/astral-sh/ruff/pull/23639))
- Add unbound type variable detection in annotations ([#23641](https://github.com/astral-sh/ruff/pull/23641))
- Apply narrowing to walrus values ([#23687](https://github.com/astral-sh/ruff/pull/23687))
- Do not union `Unknown` into unannotated container types ([#23718](https://github.com/astral-sh/ruff/pull/23718))
- Avoid inferring generics with negative intersections ([#23750](https://github.com/astral-sh/ruff/pull/23750))
- More precise types for `name` and `value` of an enum ([#23683](https://github.com/astral-sh/ruff/pull/23683))
- Better preserve user-provided union order in inferred specializations ([#23715](https://github.com/astral-sh/ruff/pull/23715))
- Support narrowing in ternary expressions ([#23726](https://github.com/astral-sh/ruff/pull/23726))
- Validate bare ParamSpec usage in type annotations, and support stringified ParamSpecs as the first argument to `Callable` ([#23625](https://github.com/astral-sh/ruff/pull/23625))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@zsol](https://github.com/zsol)
- [@Gankra](https://github.com/Gankra)
- [@MichaReiser](https://github.com/MichaReiser)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@rizzip](https://github.com/rizzip)
- [@iksuddle](https://github.com/iksuddle)
- [@dcreager](https://github.com/dcreager)
- [@BurntSushi](https://github.com/BurntSushi)
- [@carljm](https://github.com/carljm)
- [@oconnor663](https://github.com/oconnor663)

## 0.0.20

Released on 2026-03-02.

### Bug fixes

- Disallow negative narrowing for `isinstance()` or `issubclass()` checks involving `type[]` types ([#23598](https://github.com/astral-sh/ruff/pull/23598))
- Fix binary operations between an instance of a `NewType` of `float` and an instance of `Any`/`Unknown` ([#23620](https://github.com/astral-sh/ruff/pull/23620))
- Fix bug where ty would think that a `Callable` with a variadic positional parameter could be a subtype of a `Callable` with a positional-or-keyword parameter ([#23610](https://github.com/astral-sh/ruff/pull/23610))
- Fix inference of `t.__mro__` if `t` is an instance of `type[Any]` ([#23632](https://github.com/astral-sh/ruff/pull/23632))
- Fix overloaded callable assignability for unary `Callable` targets ([#23277](https://github.com/astral-sh/ruff/pull/23277))
- Limit recursion depth when displaying self-referential function types ([#23647](https://github.com/astral-sh/ruff/pull/23647))
- Ensure that `python -m ty` works even when ty was installed into an ephemeral virtual environment ([#2852](https://github.com/astral-sh/ty/pull/2852))

### LSP server

- Add support for the LSP protocol's "type hierarchy" feature ([#23566](https://github.com/astral-sh/ruff/pull/23566))

### Type checking

- Add more ParamSpec validation for `P.args` and `P.kwargs` ([#23640](https://github.com/astral-sh/ruff/pull/23640))
- Ban nested `Required`/`NotRequired`, and ban them both outside of `TypedDict` fields ([#23627](https://github.com/astral-sh/ruff/pull/23627))
- Detect inconsistent generic base class specializations that appear in the same MRO ([#23615](https://github.com/astral-sh/ruff/pull/23615))
- Detect invalid uses of `@final` on non-methods ([#23604](https://github.com/astral-sh/ruff/pull/23604))
- Add partial support and validation for `Unpack` when used with tuple types ([#23651](https://github.com/astral-sh/ruff/pull/23651))
- Recurse into tuples and nested tuples when applying special-cased validation of arguments passed to `isinstance()` and `issubclass()` ([#23607](https://github.com/astral-sh/ruff/pull/23607))
- Reject ellipsis literals in odd places in type/annotation expressions ([#23611](https://github.com/astral-sh/ruff/pull/23611))
- Reject functions with PEP-695 type parameters that shadow type parameters from enclosing scopes ([#23619](https://github.com/astral-sh/ruff/pull/23619))
- Reject generic metaclasses parameterized by type variables ([#23628](https://github.com/astral-sh/ruff/pull/23628))
- Treat `dataclass_transform` dataclasses as neither frozen nor non-frozen ([#23366](https://github.com/astral-sh/ruff/pull/23366))
- Validate that type variable defaults don't reference later type parameters or type parameters out of scope ([#23623](https://github.com/astral-sh/ruff/pull/23623))

### Typeshed

- Sync vendored typeshed stubs ([#23642](https://github.com/astral-sh/ruff/pull/23642)). [Typeshed diff](https://github.com/python/typeshed/compare/1b3cec156330a93f6bb22b6636bca38c27f8f721...843c1fd5a148da85e523c1b4ee680226f89986aa)

### Contributors

- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@zanieb](https://github.com/zanieb)
- [@sharkdp](https://github.com/sharkdp)
- [@mtshiba](https://github.com/mtshiba)
- [@carljm](https://github.com/carljm)
- [@charliermarsh](https://github.com/charliermarsh)
- [@sinon](https://github.com/sinon)
- [@BurntSushi](https://github.com/BurntSushi)
- [@oconnor663](https://github.com/oconnor663)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@zsol](https://github.com/zsol)

## 0.0.19

Released on 2026-02-26.

### Bug fixes

- Fix panic in diagnostic rendering when attempting to render a code frame pointing to leading whitespace ([#23458](https://github.com/astral-sh/ruff/pull/23458))
- Fix panics and incorrect inference stemming from incorrectly considering overloads in another file as being associated with a function in the file being checked ([#21977](https://github.com/astral-sh/ruff/pull/21977))
- Fix panic when attempting to narrow the type of a dictionary key that was assigned using a multi-target assignment, e.g. `x = y = {"a": 1}` ([#23523](https://github.com/astral-sh/ruff/pull/23523))
- Fix infinite hang on mutually recursive `TypeAliasType` definitions ([#23397](https://github.com/astral-sh/ruff/pull/23397))

### LSP server

- Fix inlay hints for starred unpacking targets ([#23454](https://github.com/astral-sh/ruff/pull/23454))

### Core type checking

- Fix assignability, subtyping and equivalence checks relating to `typing.Generator` prior to Python 3.13 ([#23386](https://github.com/astral-sh/ruff/pull/23386))
- Understand that a scope's control flow terminates after `await foo()` if `foo` returns `typing.Awaitable[typing.Never]` or similar ([#23479](https://github.com/astral-sh/ruff/pull/23479))
- Implement stricter handling of calls to instances of `type[T]` types ([#23472](https://github.com/astral-sh/ruff/pull/23472))
- Support basic type narrowing for `case {...}:` patterns in `match` statements ([#23462](https://github.com/astral-sh/ruff/pull/23462))
- Fix bugs that could manifest in incorrect overload evaluation, false-positive complaints regarding `assert_type` calls or false-positive `redundant-cast` diagnostics by reimplementing the equivalence type relation as mutual subtyping of top and bottom materializations ([#23428](https://github.com/astral-sh/ruff/pull/23428))
- Fix equality and `__contains__` narrowing with PEP-695 type aliases ([#23545](https://github.com/astral-sh/ruff/pull/23545))
- Support `_value_` annotations on enum classes ([#22228](https://github.com/astral-sh/ruff/pull/22228))

### Improvements to diagnostics

- Improve diagnostics when attempting to specialize non-generic types ([#23516](https://github.com/astral-sh/ruff/pull/23516))
- Render subdiagnostics when `--output-format=github` is specified ([#23455](https://github.com/astral-sh/ruff/pull/23455))

### Performance

- Add a cached method for calculating the intersection of two types ([#23547](https://github.com/astral-sh/ruff/pull/23547))
- Add a cached method for calculating the union of two types ([#23565](https://github.com/astral-sh/ruff/pull/23565))
- Reduce the threshold above which `Literal` types in unions are upcasted to nominal-instance types in situations where the union type is recursively defined ([#23521](https://github.com/astral-sh/ruff/pull/23521))
- Control flow: isolate the calculation of "loop header reachability" in a dedicated, cached function ([#23520](https://github.com/astral-sh/ruff/pull/23520))

### Contributors

- [@AlexWaygood](https://github.com/AlexWaygood)
- [@silamon](https://github.com/silamon)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@charliermarsh](https://github.com/charliermarsh)
- [@knutwannheden](https://github.com/knutwannheden)
- [@oconnor663](https://github.com/oconnor663)
- [@carljm](https://github.com/carljm)
- [@mtshiba](https://github.com/mtshiba)

## 0.0.18

Released on 2026-02-20.

### Bug fixes

- Support classes dynamically created via `type(...)` with cyclic bases ([#22792](https://github.com/astral-sh/ruff/pull/22792))
- Fix incorrect types inferred when unpacking mixed tuples ([#23437](https://github.com/astral-sh/ruff/pull/23437))
- Fix stack overflow for self-referential `TypeOf` in annotations ([#23407](https://github.com/astral-sh/ruff/pull/23407))
- Fix several server panics that could occur when computing semantic tokens for the current file ([#23403](https://github.com/astral-sh/ruff/pull/23403)), [#23398](https://github.com/astral-sh/ruff/pull/23398), [#23401](https://github.com/astral-sh/ruff/pull/23401))

### LSP server

- Add code folding support ([#23393](https://github.com/astral-sh/ruff/pull/23393))
- Add warning message when running `ty server` interactively ([#23416](https://github.com/astral-sh/ruff/pull/23416))
- Exclude test-related symbols from non-first-party packages in auto-import completions ([#23252](https://github.com/astral-sh/ruff/pull/23252))
- Fix bug where diagnostics could disappear after opening an external file ([#23447](https://github.com/astral-sh/ruff/pull/23447))
- Remove spurious destination for Go-To Definition on variables defined in a loop ([#23391](https://github.com/astral-sh/ruff/pull/23391))
- Use the fully qualified name when "baking" an inlay hint into the source code if the scope already contains a variable with the same name as the unqualified name ([#23265](https://github.com/astral-sh/ruff/pull/23265))
- Resolve TypeVars in `call_signature_details` parameter types ([#23149](https://github.com/astral-sh/ruff/pull/23149))

### CLI

- Add `--output-format` to `ty version` ([#23387](https://github.com/astral-sh/ruff/pull/23387))

### Configuration

- Add `replace-imports-with-any` option ([#23122](https://github.com/astral-sh/ruff/pull/23122))
- Support shellexpand for configuration paths ([#23274](https://github.com/astral-sh/ruff/pull/23274))

### Type checking

- Add a new diagnostic to detect invalid class patterns in `match` statements ([#22939](https://github.com/astral-sh/ruff/pull/22939))
- Allow `Self` in `ClassVar` type annotations ([#23362](https://github.com/astral-sh/ruff/pull/23362))
- Consider synthesized methods and `ClassVar`-qualified declarations when determining whether an abstract method has been overridden in a subclass ([#23381](https://github.com/astral-sh/ruff/pull/23381))
- Add a diagnostic when combining `Final` and `ClassVar` ([#23365](https://github.com/astral-sh/ruff/pull/23365))
- Fix return type of `assert_never` ([#23389](https://github.com/astral-sh/ruff/pull/23389))
- Fix `assert_type` diagnostic messages ([#23342](https://github.com/astral-sh/ruff/pull/23342))
- Ban PEP-613 type alias values from containing type-qualifier special forms ([#23444](https://github.com/astral-sh/ruff/pull/23444))
- Infer `LiteralString` for `f"{literal_str_a} {literal_str_b}"` ([#23346](https://github.com/astral-sh/ruff/pull/23346))
- Infer precise types for bit-shift operations on integer literals ([#23301](https://github.com/astral-sh/ruff/pull/23301))
- Make `[abstract-method-in-final-class]` diagnostics less verbose for classes with many abstract methods ([#23379](https://github.com/astral-sh/ruff/pull/23379))
- Improve diagnostics for abstract `@final` classes ([#23376](https://github.com/astral-sh/ruff/pull/23376))
- Only perform literal promotion for implicitly inferred literals ([#23107](https://github.com/astral-sh/ruff/pull/23107))
- Parenthesize callable types when they appear in the return annotation of other callable types ([#23327](https://github.com/astral-sh/ruff/pull/23327))
- Consider a call to a generic function returning `Never` to terminate control flow ([#23419](https://github.com/astral-sh/ruff/pull/23419))
- Support calls to intersection types ([#22469](https://github.com/astral-sh/ruff/pull/22469))
- Validate annotated assignments to attributes on self ([#23388](https://github.com/astral-sh/ruff/pull/23388))
- Treat a bytes-literal type as a subtype of `Sequence[<constituent integers in the bytestring>]` ([#23329](https://github.com/astral-sh/ruff/pull/23329))
- Allow a string-literal argument to match against an `Iterable` parameter in type variable inference. ([#23326](https://github.com/astral-sh/ruff/pull/23326))
- Support narrowing from a `Callable` type returning a `TypeGuard` type ([#23280](https://github.com/astral-sh/ruff/pull/23280))

### Performance

- Consider all code paths as being ambiguously reachable in cases with pathologically large control-flow graphs ([#23399](https://github.com/astral-sh/ruff/pull/23399))

### Typeshed

- Sync vendored typeshed stubs ([#23279](https://github.com/astral-sh/ruff/pull/23279), [Typeshed diff](https://github.com/python/typeshed/compare/fa659b1def704dea3dc8e25c7857b23eac69df4d...1b3cec156330a93f6bb22b6636bca38c27f8f721))

### Contributors

- [@toby-bro](https://github.com/toby-bro)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@MatthewMckee4](https://github.com/MatthewMckee4)
- [@BurntSushi](https://github.com/BurntSushi)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@knutwannheden](https://github.com/knutwannheden)
- [@Glyphack](https://github.com/Glyphack)
- [@charliermarsh](https://github.com/charliermarsh)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@abhijeetbodas2001](https://github.com/abhijeetbodas2001)
- [@carljm](https://github.com/carljm)
- [@sharkdp](https://github.com/sharkdp)

## 0.0.17

Released on 2026-02-13.

### Bug fixes

- Avoid `Literal` promotion for constrained `TypeVar`s with `Literal` bounds ([#23209](https://github.com/astral-sh/ruff/pull/23209))
- Fix false positives in `TypeVar` shadowing checks ([#23222](https://github.com/astral-sh/ruff/pull/23222))

### Core type checking

- Support generic protocols ([#21902](https://github.com/astral-sh/ruff/pull/21902))
- Perform control-flow analysis in loops ([#22794](https://github.com/astral-sh/ruff/pull/22794))
- Support `typing.Self` in attribute annotations ([#23108](https://github.com/astral-sh/ruff/pull/23108))
- Support type narrowing in situations with calls to `NoReturn` functions ([#23109](https://github.com/astral-sh/ruff/pull/23109))
- Support type narrowing and reachability analysis based on `os.name` checks ([#23230](https://github.com/astral-sh/ruff/pull/23230))
- Detect overrides of `Final` class variables in subclasses ([#23180](https://github.com/astral-sh/ruff/pull/23180))
- Fix bound method access on `None` ([#23246](https://github.com/astral-sh/ruff/pull/23246))
- Fix method calls on subclasses of `Any` ([#23248](https://github.com/astral-sh/ruff/pull/23248))
- Disallow type variables within PEP-695 type variable bounds and constraints ([#22982](https://github.com/astral-sh/ruff/pull/22982))
- Emit error for attribute access on union where some elements lack the attribute ([#23042](https://github.com/astral-sh/ruff/pull/23042))
- Emit error for invalid typevar defaults ([#23194](https://github.com/astral-sh/ruff/pull/23194))
- Improve display of `ParamSpec`s in some situations ([#23211](https://github.com/astral-sh/ruff/pull/23211))

### LSP server

- Add hover and go-to-declaration support for subscript literals ([#22837](https://github.com/astral-sh/ruff/pull/22837))
- Assign lower completion ranking to deprecated names in auto import ([#23188](https://github.com/astral-sh/ruff/pull/23188))
- Improve spans of references to submodules imported in an `__init__.py` ([#21795](https://github.com/astral-sh/ruff/pull/21795))
- Include conditional symbols (like `datetime.UTC`) in auto-import in more cases ([#23249](https://github.com/astral-sh/ruff/pull/23249))
- Support auto-import for symbols in inlay hints ([#22111](https://github.com/astral-sh/ruff/pull/22111))
- Include overload declarations in find-references ([#23215](https://github.com/astral-sh/ruff/pull/23215))

### Performance

- Avoid `UnionBuilder` overhead when creating a new union from the filtered elements of an existing union ([#22352](https://github.com/astral-sh/ruff/pull/22352))

### Other changes

- Allow discovering dependencies in system Python environments ([#22994](https://github.com/astral-sh/ruff/pull/22994))
- Apply workspace settings to virtual files ([#23228](https://github.com/astral-sh/ruff/pull/23228))
- Add support for `--output-format=junit` ([#22125](https://github.com/astral-sh/ruff/pull/22125))
- Use a smaller diagnostic range for `inconsistent-mro` diagnostics ([#23213](https://github.com/astral-sh/ruff/pull/23213))

### Contributors

- [@carljm](https://github.com/carljm)
- [@BurntSushi](https://github.com/BurntSushi)
- [@charliermarsh](https://github.com/charliermarsh)
- [@Glyphack](https://github.com/Glyphack)
- [@cetanu](https://github.com/cetanu)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@joelostblom](https://github.com/joelostblom)
- [@Gankra](https://github.com/Gankra)
- [@mtshiba](https://github.com/mtshiba)
- [@MatthewMckee4](https://github.com/MatthewMckee4)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@sharkdp](https://github.com/sharkdp)
- [@alex](https://github.com/alex)
- [@dcreager](https://github.com/dcreager)
- [@oconnor663](https://github.com/oconnor663)

## 0.0.16

Released on 2026-02-10.

### Bug fixes

- Allow stringified argument in PEP-613 alias to `Optional` ([#23200](https://github.com/astral-sh/ruff/pull/23200))
- Fix fuzzer panic on slice expression in unclosed comprehension ([#23146](https://github.com/astral-sh/ruff/pull/23146))
- Fix combinatorial explosion due to fixed-length tuple expansion in overload matching ([#23190](https://github.com/astral-sh/ruff/pull/23190))
- Respect `@no_type_check` when combined with other decorators ([#23177](https://github.com/astral-sh/ruff/pull/23177))
- Fix diagnostic location for an incorrect sub-call to a specialized ParamSpec ([#23036](https://github.com/astral-sh/ruff/pull/23036))

### LSP server

- Assign lower completions ranking to deprecated functions and classes ([#23089](https://github.com/astral-sh/ruff/pull/23089))
- Change goto-def for class constructors to always go to class definition ([#23071](https://github.com/astral-sh/ruff/pull/23071))
- Ensure diagnostic mode is consistent across projects inside the LSP server ([#23121](https://github.com/astral-sh/ruff/pull/23121))
- Don't include the class `Foo` in autocomplete suggestions when the user is typing out `Foo`'s bases ([#23141](https://github.com/astral-sh/ruff/pull/23141))
- Fix parameter references across files via keyword args ([#23012](https://github.com/astral-sh/ruff/pull/23012))
- Fix wrong inlay hints for overloaded function arguments ([#23179](https://github.com/astral-sh/ruff/pull/23179))
- Support diagnostics in newly created files inside neovim ([#23095](https://github.com/astral-sh/ruff/pull/23095))
- Exclude already-included classes when providing completion suggestions for class bases ([#23085](https://github.com/astral-sh/ruff/pull/23085))

### CLI

- Add support for `TY_OUTPUT_FORMAT` environment variable ([#23123](https://github.com/astral-sh/ruff/pull/23123))
- Fall back to `python3` found in `$PATH` if no environment is found ([#22843](https://github.com/astral-sh/ruff/pull/22843))

### Type checking

- Add `inconsistent-mro` autofix to move `Generic[]` to the end of the bases list ([#22998](https://github.com/astral-sh/ruff/pull/22998))
- Add precise return-type inference for `struct.unpack` ([#22562](https://github.com/astral-sh/ruff/pull/22562), [#23130](https://github.com/astral-sh/ruff/pull/23130))
- Disallow TypeVars within ClassVars ([#23184](https://github.com/astral-sh/ruff/pull/23184))
- Emit diagnostic on unbound call to abstract `@classmethod` or `@staticmethod` ([#23182](https://github.com/astral-sh/ruff/pull/23182))
- Fix false-positive diagnostics when providing the `total=` keyword to `TypedDict` classes that had PEP-695 type parameters ([#23114](https://github.com/astral-sh/ruff/pull/23114))
- Narrow both left- and right-hand operands where possible ([#23084](https://github.com/astral-sh/ruff/pull/23084))
- Narrow chained operators ([#23093](https://github.com/astral-sh/ruff/pull/23093))
- Narrow equality subscripts on either operand ([#23104](https://github.com/astral-sh/ruff/pull/23104))
- Recognize `__dataclass_transform__` to support SQLModel ([#23070](https://github.com/astral-sh/ruff/pull/23070))
- Relax the attribute narrowing condition to support deeper-nested attribute type narrowing ([#22440](https://github.com/astral-sh/ruff/pull/22440))
- Support constrained TypeVar compatibility across function boundaries ([#23103](https://github.com/astral-sh/ruff/pull/23103))
- Support comparison methods (`__gt__`, etc.) where a parameter is annotated with a `Literal` type ([#23100](https://github.com/astral-sh/ruff/pull/23100))
- Support partially specialized type context ([#22748](https://github.com/astral-sh/ruff/pull/22748))
- Use type context when inferring constructor argument types ([#23139](https://github.com/astral-sh/ruff/pull/23139))
- Validate `TypedDict` constructor calls for generic aliases and `type[...]` targets ([#23113](https://github.com/astral-sh/ruff/pull/23113))

### Performance

- Conservative narrowing places optimization ([#22734](https://github.com/astral-sh/ruff/pull/22734))

### Contributors

- [@rbange](https://github.com/rbange)
- [@rayzeller](https://github.com/rayzeller)
- [@charliermarsh](https://github.com/charliermarsh)
- [@11happy](https://github.com/11happy)
- [@figsoda](https://github.com/figsoda)
- [@mtshiba](https://github.com/mtshiba)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@ngnpope](https://github.com/ngnpope)
- [@sakgoyal](https://github.com/sakgoyal)
- [@oconnor663](https://github.com/oconnor663)
- [@ericmarkmartin](https://github.com/ericmarkmartin)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@Glyphack](https://github.com/Glyphack)
- [@sharkdp](https://github.com/sharkdp)
- [@carljm](https://github.com/carljm)
- [@BurntSushi](https://github.com/BurntSushi)

## 0.0.15

Released on 2026-02-04.

### Bug fixes

- Add support for resolving imports of packages installed into Debian/Ubuntu `dist-packages` directories ([#22466](https://github.com/astral-sh/ruff/pull/22466))
- Avoid `not-iterable` false positives when iterating over an instance of an intersection type with only negated elements ([#22089](https://github.com/astral-sh/ruff/pull/22089))
- Fix support for stringized annotations in very large files ([#22913](https://github.com/astral-sh/ruff/pull/22913))
- Don't emit Liskov diagnostics for methods with mangled names ([#23062](https://github.com/astral-sh/ruff/pull/23062))
- Enforce that a `Final` symbol cannot be reassigned even after a conditional binding ([#22986](https://github.com/astral-sh/ruff/pull/22986))
- Fix TypedDict construction from existing TypedDict values ([#22904](https://github.com/astral-sh/ruff/pull/22904))
- Fix `Self` resolution for classes nested within methods ([#22964](https://github.com/astral-sh/ruff/pull/22964))
- Fix bidirectional inference with PEP 695 union type aliases ([#22988](https://github.com/astral-sh/ruff/pull/22988))
- Fix edge-case bugs when narrowing tagged unions in `match` statements ([#22870](https://github.com/astral-sh/ruff/pull/22870))
- Fix false-positive diagnostics when iterating over an instance of an intersection that includes a TypeVar of which the upper bound is a union where the union includes a non-iterable type ([#22117](https://github.com/astral-sh/ruff/pull/22117))
- Fix lookup of `__contains__` to respect descriptors ([#23056](https://github.com/astral-sh/ruff/pull/23056))
- Fix narrowing of `nonlocal` variables with conditional assignments ([#22966](https://github.com/astral-sh/ruff/pull/22966))
- Fix several bugs that could affect `NewType`s of `NewType`s of `float` ([#22997](https://github.com/astral-sh/ruff/pull/22997))
- Fix several type narrowing bugs involving PEP-695 type aliases ([#22894](https://github.com/astral-sh/ruff/pull/22894))
- Fix spurious query cycles in decorated functions with parameter defaults, for improved performance and improved determinism ([#23014](https://github.com/astral-sh/ruff/pull/23014))
- Fix unary and comparison operators for TypeVars with union bounds ([#22925](https://github.com/astral-sh/ruff/pull/22925))
- Understand functions as method descriptors even if they are decorated with a decorator annotated as returning a PEP-695 alias to a `Callable` type ([#22902](https://github.com/astral-sh/ruff/pull/22902))
- `dataclass_transform`: Fix visibility of field specifiers when models are nested inside methods ([#23069](https://github.com/astral-sh/ruff/pull/23069))

### LSP server

- Fix hover showing `Unknown` for bare `Final` instance attributes ([#23003](https://github.com/astral-sh/ruff/pull/23003))
- Improve support for goto-type, goto-declaration, hover, and highlighting of string annotations ([#22878](https://github.com/astral-sh/ruff/pull/22878))
- Include setters and deleters when renaming properties ([#22999](https://github.com/astral-sh/ruff/pull/22999))
- Show type qualifiers like `Final` in on-hover hints ([#23005](https://github.com/astral-sh/ruff/pull/23005))

### Configuration

- Add new `unused-type-ignore-comment` rule ([#22790](https://github.com/astral-sh/ruff/pull/22790))
- Add a mechanism to ignore/warn/select all rules ([#22832](https://github.com/astral-sh/ruff/pull/22832))
- Support multiple workspace folders in a single ty LSP server instance ([#22953](https://github.com/astral-sh/ruff/pull/22953))
- Only add `./src` as a search path if `./src/__init__.py(i)` does not exist ([#22851](https://github.com/astral-sh/ruff/pull/22851))

### Type checking

- Add a diagnostic detecting if a variable is declared as `Final` but never has any bindings ([#23001](https://github.com/astral-sh/ruff/pull/23001))
- Add a diagnostic detecting overridden comparison dunder methods on `order=True` dataclasses ([#22689](https://github.com/astral-sh/ruff/pull/22689))
- Add a hint to `invalid-argument-type` and `invalid-assignment` diagnostics if a variable is annotated with a type from the `numbers` module ([#22931](https://github.com/astral-sh/ruff/pull/22931), [#22938](https://github.com/astral-sh/ruff/pull/22938))
- Add diagnostic hint on `unresolved-reference` to suggest using "list" instead of "List" ([#22827](https://github.com/astral-sh/ruff/pull/22827))
- Add new diagnostic for invalid dataclass field orders ([#19825](https://github.com/astral-sh/ruff/pull/19825))
- Allow a subclass method with a positional-only parameter to override a superclass method without that parameter if the parameter in the subclass method has a default value ([#23037](https://github.com/astral-sh/ruff/pull/23037))
- Allow self-referential imports outside the global scope ([#22963](https://github.com/astral-sh/ruff/pull/22963))
- Ban `...` in odd places inside tuple specializations ([#22889](https://github.com/astral-sh/ruff/pull/22889))
- Ban `Required`, `NotRequired` and `ReadOnly` in parameter annotations ([#22888](https://github.com/astral-sh/ruff/pull/22888))
- Ban legacy `TypeVar` bounds or constraints from containing type variables ([#22949](https://github.com/astral-sh/ruff/pull/22949))
- Ban multiple unpacked variadic tuples in a `tuple` specialization ([#22884](https://github.com/astral-sh/ruff/pull/22884))
- Detect generic `Callable`s in the return type of function signatures ([#22954](https://github.com/astral-sh/ruff/pull/22954))
- Detect invalid `isinstance()` and `issubclass()` calls against `TypedDict` classes ([#22887](https://github.com/astral-sh/ruff/pull/22887))
- Detect invalid `issubclass()` calls against `Protocol` classes with non-method members ([#22896](https://github.com/astral-sh/ruff/pull/22896))
- Detect invalid attempts to subclass `Protocol[]` and `Generic[]` simultaneously ([#22948](https://github.com/astral-sh/ruff/pull/22948))
- Emit a diagnostic on incorrect applications of the legacy convention for specifying positional-only parameters ([#22943](https://github.com/astral-sh/ruff/pull/22943))
- Emit an error if a `TypeVarTuple` is used to subscript `Generic` or `Protocol` without being unpacked ([#22952](https://github.com/astral-sh/ruff/pull/22952))
- Fallback to metaclass `__getattr__` or `__getattribute__` when looking up attributes on class objects ([#22985](https://github.com/astral-sh/ruff/pull/22985))
- Fix a bug where an overridden type in a dataclass subclass would not be respected if the dataclass subclass field had a default value but the superclass field did not ([#22965](https://github.com/astral-sh/ruff/pull/22965))
- Improve bidirectional type inference involving PEP-695 type aliases ([#22989](https://github.com/astral-sh/ruff/pull/22989))
- Improve detection of invalid `NewType`s with generic bases ([#22961](https://github.com/astral-sh/ruff/pull/22961))
- Improve reachability analysis when evaluating the truthiness of expressions that involve variables that may not be bound in all code paths ([#22971](https://github.com/astral-sh/ruff/pull/22971))
- Improve the error message if `**` is used with a non-mapping in the context of a call to an overloaded function ([#22921](https://github.com/astral-sh/ruff/pull/22921))
- Infer `ParamSpec` from class constructors for callable protocols ([#22853](https://github.com/astral-sh/ruff/pull/22853))
- Move the location of some `invalid-overload` diagnostics ([#22933](https://github.com/astral-sh/ruff/pull/22933))
- Point to an overload with an invalid `@final` decorator when emitting `invalid-overload` errors for invalid `@final` decorators ([#22893](https://github.com/astral-sh/ruff/pull/22893))
- Avoid false positives when iterating over an instance of an intersection with only negated elements by preserving "pure negation" types in descriptor lookups ([#22907](https://github.com/astral-sh/ruff/pull/22907))
- Promote `Literal` types when inferring elements for very large unannotated tuples, for improved performance ([#22841](https://github.com/astral-sh/ruff/pull/22841))
- Recognize functions with stub bodies in `Protocol` classes as implicitly abstract ([#22838](https://github.com/astral-sh/ruff/pull/22838))
- Reduce false positives involving heterogeneous dicts by tracking dictionary literal keys as individual places ([#22882](https://github.com/astral-sh/ruff/pull/22882))
- Reduce false positives when subscripting classes generic over `TypeVarTuple`s ([#22950](https://github.com/astral-sh/ruff/pull/22950))
- Remove special handling for `Any()` in `match` class patterns ([#23011](https://github.com/astral-sh/ruff/pull/23011))
- Support `type[None]` in type expressions ([#22892](https://github.com/astral-sh/ruff/pull/22892))
- Support legacy namespace packages declared using `pkg_resources.declare_namespace` ([#22987](https://github.com/astral-sh/ruff/pull/22987))
- Sync vendored typeshed stubs ([#23006](https://github.com/astral-sh/ruff/pull/23006)), [Typeshed diff](https://github.com/python/typeshed/compare/cd8b26b0ceef26cd84ab614088140d48680ac7f7...fa659b1def704dea3dc8e25c7857b23eac69df4d)
- Validate signatures of dataclass `__post_init__` methods ([#22730](https://github.com/astral-sh/ruff/pull/22730))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@stefanvanburen](https://github.com/stefanvanburen)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@abhijeetbodas2001](https://github.com/abhijeetbodas2001)
- [@MichaReiser](https://github.com/MichaReiser)
- [@dcreager](https://github.com/dcreager)
- [@PrettyWood](https://github.com/PrettyWood)
- [@sharkdp](https://github.com/sharkdp)
- [@oconnor663](https://github.com/oconnor663)
- [@Feiyang472](https://github.com/Feiyang472)
- [@denyszhak](https://github.com/denyszhak)
- [@mtshiba](https://github.com/mtshiba)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@11happy](https://github.com/11happy)
- [@BurntSushi](https://github.com/BurntSushi)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)
- [@MentalMegalodon](https://github.com/MentalMegalodon)
- [@thejchap](https://github.com/thejchap)

## 0.0.14

Released on 2026-01-26.

### Bug fixes

- Consider keyword arguments when unpacking a variadic argument ([#22796](https://github.com/astral-sh/ruff/pull/22796))
- Fix binary operator false-positive for constrained TypeVars ([#22782](https://github.com/astral-sh/ruff/pull/22782))
- Fix docstring rendering for literal blocks after doctests ([#22676](https://github.com/astral-sh/ruff/pull/22676))
- Fix false-positive `unsupported-operator` for "symmetric" TypeVars ([#22756](https://github.com/astral-sh/ruff/pull/22756))
- Fix panic when overriding a final method using an assignment ([#22831](https://github.com/astral-sh/ruff/pull/22831))
- Fix unary operator false-positive for constrained TypeVars ([#22783](https://github.com/astral-sh/ruff/pull/22783))
- Fix generic functions with a generic (ParamSpec) decorator ([#22544](https://github.com/astral-sh/ruff/pull/22544))
- Fix `memo.changed_at` assertion panics ([#22498](https://github.com/astral-sh/ruff/pull/22498))

### LSP server

- Look up attributes on metaclasses for Go to Definition ([#22758](https://github.com/astral-sh/ruff/pull/22758))
- Suppress type inlay hints for leading-underscore assignments ([#22855](https://github.com/astral-sh/ruff/pull/22855))

### Configuration

- Add `allowed-unresolved-imports` setting ([#22800](https://github.com/astral-sh/ruff/pull/22800))

### Other changes

- Add `assert-type-unspellable-subtype` diagnostic, for failed `assert_type()` where the actual type is a subtype of the named type that can't be spelled in a type expression ([#22815](https://github.com/astral-sh/ruff/pull/22815))
- Add a new `empty-body` return code for functions with stub bodies that have non-`None` return annotations ([#22846](https://github.com/astral-sh/ruff/pull/22846))
- Add diagnostic disambiguation for different type aliases with the same name ([#22852](https://github.com/astral-sh/ruff/pull/22852))
- Add support for dict literals and dict() calls as default values for parameters with TypedDict types ([#22161](https://github.com/astral-sh/ruff/pull/22161))
- Add support for subscripts on intersections ([#22654](https://github.com/astral-sh/ruff/pull/22654))
- Avoid duplicate syntax errors for `await` outside functions ([#22826](https://github.com/astral-sh/ruff/pull/22826))
- Emit an error if the same type parameter appears more than once in a `Generic[]` subscript ([#22738](https://github.com/astral-sh/ruff/pull/22738))
- Emit diagnostic for unimplemented abstract method on @final class ([#22753](https://github.com/astral-sh/ruff/pull/22753))
- Fix GitLab Code Quality output format for empty diagnostics ([#22833](https://github.com/astral-sh/ruff/pull/22833))
- Fix assignment in decorated method causing `Unknown` fallback ([#22778](https://github.com/astral-sh/ruff/pull/22778))
- Fix false negative when using a non-runtime-checkable protocol in a `match` class pattern ([#22836](https://github.com/astral-sh/ruff/pull/22836))
- Improve completion rankings for raise-from/except contexts ([#22775](https://github.com/astral-sh/ruff/pull/22775))
- Improve invalid assignment diagnostics with type context ([#22643](https://github.com/astral-sh/ruff/pull/22643))
- Improve support for kwarg splats in dictionary literals ([#22781](https://github.com/astral-sh/ruff/pull/22781))
- Infer `TypedDict` types with >=1 required key as being always truthy ([#22808](https://github.com/astral-sh/ruff/pull/22808))
- Point to an overload with an invalid `@final` decoator when emitting `invalid-overload` errors for invalid `@final` decorators ([#22812](https://github.com/astral-sh/ruff/pull/22812))
- Require both `*args` and `**kwargs` when calling a `ParamSpec` callable ([#22820](https://github.com/astral-sh/ruff/pull/22820))
- Stricter validation of `TypedDict` definitions ([#22811](https://github.com/astral-sh/ruff/pull/22811))
- Support recursive and stringified annotations in functional `typing.NamedTuple`s ([#22718](https://github.com/astral-sh/ruff/pull/22718))
- Support solving generics involving PEP 695 type aliases ([#22678](https://github.com/astral-sh/ruff/pull/22678))
- Use a more lenient fallback type for failed `namedtuple()` and `NamedTuple` calls ([#22765](https://github.com/astral-sh/ruff/pull/22765))
- Use type context from augmented assignment dunder calls ([#22540](https://github.com/astral-sh/ruff/pull/22540))
- Check that starred arguments in function calls are iterable ([#22805](https://github.com/astral-sh/ruff/pull/22805))

### Contributors

- [@AlexWaygood](https://github.com/AlexWaygood)
- [@maifeeulasad](https://github.com/maifeeulasad)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@ntBre](https://github.com/ntBre)
- [@Imbuzi](https://github.com/Imbuzi)
- [@dhruvmanila](https://github.com/dhruvmanila)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@carljm](https://github.com/carljm)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@charliermarsh](https://github.com/charliermarsh)
- [@MichaReiser](https://github.com/MichaReiser)
- [@bxff](https://github.com/bxff)
- [@felixscherz](https://github.com/felixscherz)
- [@denyszhak](https://github.com/denyszhak)

## 0.0.13

Released on 2026-01-21.

### Bug fixes

- Fix `--force-exclude` when excluding entire directories ([#22595](https://github.com/astral-sh/ruff/pull/22595))
- Fix missing syntax highlighting for aliased import names ([#22675](https://github.com/astral-sh/ruff/pull/22675))
- Highlight interpolated-parts in t-strings ([#22674](https://github.com/astral-sh/ruff/pull/22674))
- Fix the inferred MRO of functional namedtuple classes ([#22722](https://github.com/astral-sh/ruff/pull/22722))
- Make special cases for subscript inference exhaustive, ensuring that the special casing for tuple subscripts is applied when a union of tuples or an alias to a tuple type is subscripted ([#22035](https://github.com/astral-sh/ruff/pull/22035))

### LSP server

- Improve completion suggestions inside class definitions ([#22571](https://github.com/astral-sh/ruff/pull/22571))
- Improve performance of completions ([#22630](https://github.com/astral-sh/ruff/pull/22630))
- Remove completion suggestions for redundant re-exports that share the same top-most module ([#22581](https://github.com/astral-sh/ruff/pull/22581))

### Core type checking

- Add basic support for overloads in `ParamSpec` ([#21946](https://github.com/astral-sh/ruff/pull/21946))
- Allow `...` as a default value for any parameter if the function is in an `if TYPE_CHECKING` block ([#22624](https://github.com/astral-sh/ruff/pull/22624))
- Allow `if type(x) is Y` narrowing for types other than class-literal types ([#22729](https://github.com/astral-sh/ruff/pull/22729))
- Avoid overload errors when detecting dataclass-on-tuple ([#22687](https://github.com/astral-sh/ruff/pull/22687))
- Avoid reporting overload errors for successful union variants ([#22688](https://github.com/astral-sh/ruff/pull/22688))
- Ban `NewType`s with generic bases ([#22653](https://github.com/astral-sh/ruff/pull/22653))
- Fix PEP 695 type aliases not expanding in overload resolution ([#22589](https://github.com/astral-sh/ruff/pull/22589))
- Fix the return type for synthesized `NamedTuple.__new__` methods ([#22625](https://github.com/astral-sh/ruff/pull/22625))
- Emit diagnostics for `NamedTuple`, `TypedDict`, `Enum` or `Protocol` classes decorated with `@dataclass` ([#22672](https://github.com/astral-sh/ruff/pull/22672))
- Emit `invalid-type-form` diagnostics for stringified annotations where the quoted expression is invalid ([#22752](https://github.com/astral-sh/ruff/pull/22752))
- Infer the implicit type of `cls` in `__new__` methods ([#22584](https://github.com/astral-sh/ruff/pull/22584))
- Make `ModuleType` and `object` attributes available on namespace packages ([#22606](https://github.com/astral-sh/ruff/pull/22606))
- Make `NamedTuple(...)` and `namedtuple(...)` calls stricter ([#22601](https://github.com/astral-sh/ruff/pull/22601))
- Narrow on bool and byte subscripts ([#22684](https://github.com/astral-sh/ruff/pull/22684))
- Narrow on negative subscript indexing ([#22682](https://github.com/astral-sh/ruff/pull/22682))
- Override `__file__` to `str` when applicable on imported modules ([#22333](https://github.com/astral-sh/ruff/pull/22333))
- Add bidirectional inference for comprehensions ([#22564](https://github.com/astral-sh/ruff/pull/22564))
- Recognize string-literal types as subtypes of `Sequence[Literal[chars]]` ([#22415](https://github.com/astral-sh/ruff/pull/22415))
- Add right-hand-side narrowing for `if Foo is type(x)` expressions ([#22608](https://github.com/astral-sh/ruff/pull/22608))
- Add simple syntactic validation for the right-hand side of PEP-613 type aliases ([#22652](https://github.com/astral-sh/ruff/pull/22652))
- Add support for passing `typename` and `field_names` by keyword argument to `collections.namedtuple()` calls ([#22660](https://github.com/astral-sh/ruff/pull/22660))
- Add support for starred unpacking in class bases ([#22591](https://github.com/astral-sh/ruff/pull/22591))
- Validate constructor arguments when a class is used as a decorator ([#22377](https://github.com/astral-sh/ruff/pull/22377))
- Validate field names for `typing.NamedTuple(...)` ([#22599](https://github.com/astral-sh/ruff/pull/22599))
- Add diagnostic on overridden `__setattr__` and `__delattr__` in frozen dataclasses ([#21430](https://github.com/astral-sh/ruff/pull/21430))
- Fix unary operators on `NewType`s of `float` or `complex` ([#22605](https://github.com/astral-sh/ruff/pull/22605))

### Configuration

- Support overriding `respect-type-ignore-comments` ([#22615](https://github.com/astral-sh/ruff/pull/22615))

### Diagnostics

- Don't add a subdiagnostic pointing to the TypeVar definition if the TypeVar is `Self` ([#22646](https://github.com/astral-sh/ruff/pull/22646))
- Show final search path instead of "and 1 more paths" ([#22776](https://github.com/astral-sh/ruff/pull/22776))
- Group `type[]` elements together when displaying union types ([#22592](https://github.com/astral-sh/ruff/pull/22592))

### Performance

- Cache `ClassType::nearest_disjoint_base` ([#22065](https://github.com/astral-sh/ruff/pull/22065))

### Other changes

- Sync vendored typeshed stubs ([#22590](https://github.com/astral-sh/ruff/pull/22590), [Typeshed diff](https://github.com/python/typeshed/compare/d1d5fe58664b30a0c2dde3cd5c3dc8091f0f16ae...cd8b26b0ceef26cd84ab614088140d48680ac7f7)

### Contributors

- [@bxff](https://github.com/bxff)
- [@jhartum](https://github.com/jhartum)
- [@thejchap](https://github.com/thejchap)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@charliermarsh](https://github.com/charliermarsh)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@mswart](https://github.com/mswart)
- [@MatthewMckee4](https://github.com/MatthewMckee4)
- [@11happy](https://github.com/11happy)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@sinon](https://github.com/sinon)
- [@MichaReiser](https://github.com/MichaReiser)
- [@carljm](https://github.com/carljm)
- [@BurntSushi](https://github.com/BurntSushi)
- [@dhruvmanila](https://github.com/dhruvmanila)
- [@oconnor663](https://github.com/oconnor663)
- [@zanieb](https://github.com/zanieb)

## 0.0.12

Released on 2026-01-14.

### Bug fixes

- Avoid panic that could occur when `cast`ing an object to a TypedDict or union of TypedDicts ([#22509](https://github.com/astral-sh/ruff/pull/22509))
- Fix incorrect narrowing for `if type(x) == y` ([#22531](https://github.com/astral-sh/ruff/pull/22531))
- Fix stack overflow with recursive type aliases containing tuple types ([#22543](https://github.com/astral-sh/ruff/pull/22543))
- `functools.total_ordering`: ensure the signatures of generated methods reflect the signature of the user-provided method ([#22496](https://github.com/astral-sh/ruff/pull/22496))
- Support `dataclass_transform` as a function call ([#22378](https://github.com/astral-sh/ruff/pull/22378))
- Use the top materialization of classes for `if type(x) is y` narrowing. For example, `if type(x) is tuple` will cause the type of `x` to be intersected with `tuple[object, ...]` rather than `tuple[Unknown, ...]`. ([#22553](https://github.com/astral-sh/ruff/pull/22553))
- Avoid emitting Liskov violations with respect to a grandparent class if such violations could not be fixed without introducing Liskov violations with respect to a parent class ([#22484](https://github.com/astral-sh/ruff/pull/22484))
- Fix interaction between classmethod, contextmanager, and Self ([#22407](https://github.com/astral-sh/ruff/pull/22407))
- Check contravariant type variable bounds contravariantly in specialization inference ([#22488](https://github.com/astral-sh/ruff/pull/22488))
- Fix false positive for bounded type parameters with NewType ([#22542](https://github.com/astral-sh/ruff/pull/22542))

### Core type checking

- Add support for dynamic `type()` classes ([#22291](https://github.com/astral-sh/ruff/pull/22291), [#22499](https://github.com/astral-sh/ruff/pull/22499), [#22537](https://github.com/astral-sh/ruff/pull/22537), [#22480](https://github.com/astral-sh/ruff/pull/22480))
- Add support for functional `namedtuple` creation ([#22327](https://github.com/astral-sh/ruff/pull/22327), [#22573](https://github.com/astral-sh/ruff/pull/22573), [#22575](https://github.com/astral-sh/ruff/pull/22575), [#22574](https://github.com/astral-sh/ruff/pull/22574))
- Add a diagnostic for non-decorator uses of `final` ([#22555](https://github.com/astral-sh/ruff/pull/22555))
- Add diagnostic to catch generic enums ([#22482](https://github.com/astral-sh/ruff/pull/22482))
- Add diagnostics for `__init_subclass__` argument mismatch ([#22185](https://github.com/astral-sh/ruff/pull/22185))
- Add diagnostics to validate `TypeIs` and `TypeGuard` definitions ([#22300](https://github.com/astral-sh/ruff/pull/22300))
- Apply type narrowing to walrus targets ([#22369](https://github.com/astral-sh/ruff/pull/22369))
- Detect invalid `@total_ordering` applications in non-decorator contexts ([#22486](https://github.com/astral-sh/ruff/pull/22486))
- Fix `@Todo` type for starred expressions ([#22503](https://github.com/astral-sh/ruff/pull/22503))
- Improve disambiguation of types in diagnostics ([#22547](https://github.com/astral-sh/ruff/pull/22547))
- Include type parameters in the display for generic `Callable` types ([#22435](https://github.com/astral-sh/ruff/pull/22435))
- Infer `type[Unknown]` for calls to `type()` when overload evaluation is ambiguous ([#22569](https://github.com/astral-sh/ruff/pull/22569))
- Support assignment to unions of `TypedDict`s ([#22294](https://github.com/astral-sh/ruff/pull/22294))
- Use the key and value parameter types as type context for `__setitem__` dunder calls ([#22148](https://github.com/astral-sh/ruff/pull/22148))
- Narrow the right-hand side of `==`, `!=`, `is` and `is not` conditions when the left-hand side is not narrowable ([#22511](https://github.com/astral-sh/ruff/pull/22511))

### LSP server

- Fix `__file__` type in completions to show `str` instead of `str | None` when the inferred type is `str` ([#22510](https://github.com/astral-sh/ruff/pull/22510))
- Improve rendering of ReST directives in docstrings ([#22512](https://github.com/astral-sh/ruff/pull/22512))

### Contributors

- [@eclbg](https://github.com/eclbg)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@carljm](https://github.com/carljm)
- [@drbh](https://github.com/drbh)
- [@AryanBagade](https://github.com/AryanBagade)
- [@bxff](https://github.com/bxff)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@charliermarsh](https://github.com/charliermarsh)
- [@AlexWaygood](https://github.com/AlexWaygood)

## 0.0.11

Released on 2026-01-09.

### Bug fixes

- Fix `super()` with TypeVar-annotated `self` and `cls` parameter ([#22208](https://github.com/astral-sh/ruff/pull/22208))
- Only consider fully static pivots when deriving transitive constraints ([#22444](https://github.com/astral-sh/ruff/pull/22444))

### LSP server

- Don't show diagnostics for excluded files ([#22455](https://github.com/astral-sh/ruff/pull/22455))
- Fix goto definition for relative imports in third-party files ([#22457](https://github.com/astral-sh/ruff/pull/22457))
- Improve completion ranking based on origin and exact match ([#22460](https://github.com/astral-sh/ruff/pull/22460))
- Rank top-level module symbols above most other symbols ([#22465](https://github.com/astral-sh/ruff/pull/22465))

### Configuration

- Enable `unused-ignore-comment` by default ([#22474](https://github.com/astral-sh/ruff/pull/22474))

### Performance

- Improve `UnionBuilder` performance by changing `Type::is_subtype_of` calls to `Type::is_redundant_with` ([#22337](https://github.com/astral-sh/ruff/pull/22337))
- Optimize union building for unions with many enum-literal members ([#22363](https://github.com/astral-sh/ruff/pull/22363))-

### Other changes

- Declare support for Python 3.14 ([#2407](https://github.com/astral-sh/ty/pull/2407))
- Remove dark-mode handling from PyPI-uploaded README ([#2422](https://github.com/astral-sh/ty/pull/2422))

### Contributors

- [@dhruvmanila](https://github.com/dhruvmanila)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@charliermarsh](https://github.com/charliermarsh)
- [@BurntSushi](https://github.com/BurntSushi)
- [@MichaReiser](https://github.com/MichaReiser)
- [@dcreager](https://github.com/dcreager)

## 0.0.10

Released on 2026-01-07.

### Bug fixes

- Fix stack overflow due to too small stack size ([#22433](https://github.com/astral-sh/ruff/pull/22433))
- Fix stale semantic tokens after opening the same document with new content ([#22414](https://github.com/astral-sh/ruff/pull/22414))
- Fix handling of `ParamSpec` in overloaded functions ([#22416](https://github.com/astral-sh/ruff/pull/22416))
- Fix comparisons and arithmetic with `NewType`s of `float` ([#22105](https://github.com/astral-sh/ruff/pull/22105))
- Fix several issues with unannotated function return types ([#22425](https://github.com/astral-sh/ruff/pull/22425))
- Fix handling of subclasses in Callables ([#22411](https://github.com/astral-sh/ruff/pull/22411))

### LSP server

- Add support for explicit markdown code fences in docstring rendering ([#22373](https://github.com/astral-sh/ruff/pull/22373), [#22408](https://github.com/astral-sh/ruff/pull/22408))
- Offer completions for `T` when a value has type `Unknown | T` ([#22436](https://github.com/astral-sh/ruff/pull/22436))
- Sort keyword argument completions higher ([#22297](https://github.com/astral-sh/ruff/pull/22297))

### Core type checking

- Add support for `@total_ordering` ([#22181](https://github.com/astral-sh/ruff/pull/22181), [#22183](https://github.com/astral-sh/ruff/pull/22183))
- Better simplification of intersections of tuples ([#22094](https://github.com/astral-sh/ruff/pull/22094))
- Support comparisons between variable-length tuples ([#21824](https://github.com/astral-sh/ruff/pull/21824))
- Emit diagnostics for method definitions and other invalid statements in `TypedDict` class bodies ([#22351](https://github.com/astral-sh/ruff/pull/22351))
- Improve type-narrowing in calls to `len()` ([#22330](https://github.com/astral-sh/ruff/pull/22330))

### CLI

- Add `--add-ignore` CLI option ([#21696](https://github.com/astral-sh/ruff/pull/21696))

### Configuration

- `include = ["myscript"]` will now check `myscript` even though it doesn't have a Python extension ([#22243](https://github.com/astral-sh/ruff/pull/22243))

### Performance

- Optimize intersections with a single negated element ([#22344](https://github.com/astral-sh/ruff/pull/22344))
- Optimize negated types ([#22402](https://github.com/astral-sh/ruff/pull/22402))

### Documentation

- Link to `Callable` `__name__` FAQ directly from `unresolved-attribute` diagnostic ([#22437](https://github.com/astral-sh/ruff/pull/22437))

### Contributors

- [@dhruvmanila](https://github.com/dhruvmanila)
- [@charliermarsh](https://github.com/charliermarsh)
- [@oconnor663](https://github.com/oconnor663)
- [@BurntSushi](https://github.com/BurntSushi)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)
- [@MichaReiser](https://github.com/MichaReiser)
- [@AlexWaygood](https://github.com/AlexWaygood)

## 0.0.9

Released on 2026-01-05.

### Bug fixes

- Emit a diagnostic if a class decorator is not a callable accepting a type ([#22375](https://github.com/astral-sh/ruff/pull/22375))
- Fix exhaustiveness inference for unions that include enums ([#22290](https://github.com/astral-sh/ruff/pull/22290))

### Core type checking

- Support `typing.TypeGuard` ([#20974](https://github.com/astral-sh/ruff/pull/20974))
- Treat `__setattr__` as fallback-only ([#22014](https://github.com/astral-sh/ruff/pull/22014))
- Don't expand type aliases via type mappings unless necessary. This means that the displayed signature of a bound methods will no longer eagerly expand type aliases into their aliased types ([#22241](https://github.com/astral-sh/ruff/pull/22241))
- Narrow `TypedDict` unions with `not in` ([#22349](https://github.com/astral-sh/ruff/pull/22349))
- Don't including `property` in subclasses properties ([#22088](https://github.com/astral-sh/ruff/pull/22088))
- Narrow tagged unions of `TypedDict`s in `match` statements ([#22299](https://github.com/astral-sh/ruff/pull/22299))
- Teach bidirectional inference about subtyping. This allows `x` to be inferred as `list[int]` for `x: Iterable[int] = [42]` ([#21930](https://github.com/astral-sh/ruff/pull/21930))
- Support narrowing for tagged unions of tuples where one element of the tuple is a `Literal` type ([#22303](https://github.com/astral-sh/ruff/pull/22303))

### LSP server

- Add autocomplete suggestions for keyword arguments in `class` statements ([#22110](https://github.com/astral-sh/ruff/pull/22110))
- Avoid showing misleading inlay hint for unpacked tuple arguments ([#22286](https://github.com/astral-sh/ruff/pull/22286))

### Other changes

- Sync vendored typeshed stubs ([#22302](https://github.com/astral-sh/ruff/pull/22302), [#22321](https://github.com/astral-sh/ruff/pull/22321), [#22324](https://github.com/astral-sh/ruff/pull/22324)). [Typeshed diff](https://github.com/python/typeshed/compare/3c2dbb1fde8e8d1d59b10161c8bf5fd06c0011cd...d1d5fe58664b30a0c2dde3cd5c3dc8091f0f16ae)

### Contributors

- [@RasmusNygren](https://github.com/RasmusNygren)
- [@ericmarkmartin](https://github.com/ericmarkmartin)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@charliermarsh](https://github.com/charliermarsh)
- [@felixscherz](https://github.com/felixscherz)
- [@MatthewMckee4](https://github.com/MatthewMckee4)
- [@mtshiba](https://github.com/mtshiba)

## 0.0.8

Released on 2025-12-29.

### Breaking changes

- Rename `non-subscriptable` rule to `not-subscriptable` ([#22193](https://github.com/astral-sh/ruff/pull/22193))

### Core type checking

- Promote float and complex when promoting literals ([#22215](https://github.com/astral-sh/ruff/pull/22215))
- Callable type of a type object is not function-like ([#22226](https://github.com/astral-sh/ruff/pull/22226))
- Fix and simplify callable type materializations ([#22213](https://github.com/astral-sh/ruff/pull/22213))

### LSP server

- Add option to disable syntax errors ([#22217](https://github.com/astral-sh/ruff/pull/22217))
- Fix completion in decorators with missing declaration ([#22177](https://github.com/astral-sh/ruff/pull/22177))
- Better completions context detection when typing in decorator positions ([#22224](https://github.com/astral-sh/ruff/pull/22224))
- Limit the returned completions to reduce lag ([#22240](https://github.com/astral-sh/ruff/pull/22240))

### Diagnostics

- Improve wording of `unsupported-base` sub-diagnostic ([#22194](https://github.com/astral-sh/ruff/pull/22194))
- Preserve the invalid assignment diagnostic message when implicitly shadowing a definition ([#22219](https://github.com/astral-sh/ruff/pull/22219))

### Other changes

- Update docker image to use alpine 3.23 and trixie ([#2217](https://github.com/astral-sh/ty/pull/2217))

### Contributors

- [@RasmusNygren](https://github.com/RasmusNygren)
- [@samypr100](https://github.com/samypr100)
- [@silamon](https://github.com/silamon)
- [@carljm](https://github.com/carljm)
- [@MichaReiser](https://github.com/MichaReiser)
- [@MatthewMckee4](https://github.com/MatthewMckee4)

## 0.0.7

Released on 2025-12-24.

### Bug fixes

- Fix classification of modules in `import x as y` for semantic syntax highlighting ([#22175](https://github.com/astral-sh/ruff/pull/22175))
- Fix module resolution on network drives ([#22173](https://github.com/astral-sh/ruff/pull/22173))
- Render the entire diagnostic message in all output formats ([#22164](https://github.com/astral-sh/ruff/pull/22164))

### Other changes

- Add a dedicated diagnostic for TypedDict deletions ([#22123](https://github.com/astral-sh/ruff/pull/22123))
- Check `__delitem__` instead of `__getitem__` for `del x[k]` ([#22121](https://github.com/astral-sh/ruff/pull/22121))
- Fix `@staticmethod` combined with other decorators incorrectly binding `self` ([#22128](https://github.com/astral-sh/ruff/pull/22128))
- Fix implementation of `Top[Callable[..., object]]` ([#22145](https://github.com/astral-sh/ruff/pull/22145))
- Improve diagnostic when `callable` is used in a type expression instead of `collections.abc.Callable` or `typing.Callable` ([#22180](https://github.com/astral-sh/ruff/pull/22180))
- Improve diagnostic when a user tries to access a function attribute on a `Callable` type ([#22182](https://github.com/astral-sh/ruff/pull/22182))
- Include the specialization of a generic `TypedDict` as part of its display ([#22174](https://github.com/astral-sh/ruff/pull/22174))
- Support tuple narrowing based on member checks ([#22167](https://github.com/astral-sh/ruff/pull/22167))
- Synthesize `__delitem__` for TypedDict to allow deleting non-required keys ([#22122](https://github.com/astral-sh/ruff/pull/22122))

### Contributors

- [@MichaReiser](https://github.com/MichaReiser)
- [@ntBre](https://github.com/ntBre)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@charliermarsh](https://github.com/charliermarsh)

## 0.0.6

Released on 2025-12-23.

### Bug fixes

- FIx panic from unexpanded type aliases in implicit tuple aliases ([#22015](https://github.com/astral-sh/ruff/pull/22015))
- Support `type[T]` where `T` is a type alias to a union of types ([#22115](https://github.com/astral-sh/ruff/pull/22115))
- Support `==` narrowing for tuples in unions with disjoint types ([#22129](https://github.com/astral-sh/ruff/pull/22129))
- Respect debug text interpolation in f-strings ([#22151](https://github.com/astral-sh/ruff/pull/22151))
- Fix panic from unstable union-type ordering in fixed-point iteration ([#22070](https://github.com/astral-sh/ruff/pull/22070))

### LSP server

- Add `ty.configuration` and `ty.configurationFile` options ([#22053](https://github.com/astral-sh/ruff/pull/22053))
- Add `diagnosticMode: off` to disable diagnostics while retaining Go To Definition, etc. ([#22073](https://github.com/astral-sh/ruff/pull/22073))
- Set flag to avoid `type[T@f]` being inserted when you double-click on the inlay ([#22139](https://github.com/astral-sh/ruff/pull/22139))
- Use Markdown for completions documentation if the LSP client supports it ([#21752](https://github.com/astral-sh/ruff/pull/21752))

### CLI

- Abort printing diagnostics when pressing `Ctrl+C` ([#22083](https://github.com/astral-sh/ruff/pull/22083))

### Configuration

- Add `respect-type-ignore-comments` configuration option ([#22137](https://github.com/astral-sh/ruff/pull/22137))
- Support custom builtins via `__builtins__.pyi` ([#22021](https://github.com/astral-sh/ruff/pull/22021))

### Other changes

- Bind self with instance in `__get__` ([#22155](https://github.com/astral-sh/ruff/pull/22155))
- Support type inference between protocol instances ([#22120](https://github.com/astral-sh/ruff/pull/22120))
- Synthesize a precise `_fields` attribute for NamedTuples ([#22163](https://github.com/astral-sh/ruff/pull/22163))
- Synthesize a precise `_replace` method for NamedTuples ([#22153](https://github.com/astral-sh/ruff/pull/22153))
- Narrow "tagged unions" of `TypedDict`s ([#22104](https://github.com/astral-sh/ruff/pull/22104))

### Contributors

- [@mtshiba](https://github.com/mtshiba)
- [@charliermarsh](https://github.com/charliermarsh)
- [@Wizzerinus](https://github.com/Wizzerinus)
- [@oconnor663](https://github.com/oconnor663)
- [@MichaReiser](https://github.com/MichaReiser)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@MatthewMckee4](https://github.com/MatthewMckee4)

## 0.0.5

Released on 2025-12-20.

### Bug fixes

- Fix debug-mode server panic when a user typed a class definition by ensuring class arguments are visited in source order for semantic tokens ([#22063](https://github.com/astral-sh/ruff/pull/22063))

### LSP server

- Classify docstrings in semantic tokens during syntax highlighting ([#22031](https://github.com/astral-sh/ruff/pull/22031))

### CLI

- Add `--force-exclude` option ([#22076](https://github.com/astral-sh/ruff/pull/22076))
- Only clear output between two successful checks ([#22078](https://github.com/astral-sh/ruff/pull/22078))

### Other changes

- Add support for `dict(...)` calls in `TypedDict` contexts ([#22113](https://github.com/astral-sh/ruff/pull/22113))
- Speedup bidirectional type-checking involving large unions by avoiding narrowing on non-generic calls ([#22102](https://github.com/astral-sh/ruff/pull/22102))
- Simplify inferred types by avoiding storing multi-inference attempts ([#22062](https://github.com/astral-sh/ruff/pull/22062), [#22103](https://github.com/astral-sh/ruff/pull/22103))
- Improve union builder performance ([#22048](https://github.com/astral-sh/ruff/pull/22048))
- Only prefer declared types in non-covariant positions ([#22068](https://github.com/astral-sh/ruff/pull/22068))
- Respect intersections in iterations ([#21965](https://github.com/astral-sh/ruff/pull/21965))
- Sync vendored typeshed stubs ([#22091](https://github.com/astral-sh/ruff/pull/22091)). [Typeshed diff](https://github.com/python/typeshed/compare/ef2b90c67e5c668b91b3ae121baf00ee5165c30b...3c2dbb1fde8e8d1d59b10161c8bf5fd06c0011cd)
- Understand that the type of `X` on an enum class will be `int` if `X` is defined using `enum.nonmember` in the class definition ([#22025](https://github.com/astral-sh/ruff/pull/22025))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@Hugo-Polloli](https://github.com/Hugo-Polloli)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)
- [@MichaReiser](https://github.com/MichaReiser)

## 0.0.4

Released on 2025-12-18.

### LSP server

- Add support for attribute docstrings ([#22036](https://github.com/astral-sh/ruff/pull/22036))
- Correctly encode multiline tokens for clients not supporting multiline tokens ([#22033](https://github.com/astral-sh/ruff/pull/22033))
- Autocompletions: Don't suggest keyword statements when only expressions are valid ([#22002](https://github.com/astral-sh/ruff/pull/22002))
- Fix goto-declaration on the right-hand side of `from module import submodule` ([#22042](https://github.com/astral-sh/ruff/pull/22042))
- Fix some configuration panics in the LSP ([#22040](https://github.com/astral-sh/ruff/pull/22040))
- Gracefully handle client requests that can't be deserialized ([#22051](https://github.com/astral-sh/ruff/pull/22051))

### Other changes

- Improve performance for large match statements ([#22045](https://github.com/astral-sh/ruff/pull/22045))
- Disable possibly-missing-imports by default ([#22041](https://github.com/astral-sh/ruff/pull/22041))
- Implement disjointness for TypedDicts, significantly speeding up checking of code that uses pydantic ([#22044](https://github.com/astral-sh/ruff/pull/22044))

### Contributors

- [@oconnor663](https://github.com/oconnor663)
- [@MichaReiser](https://github.com/MichaReiser)
- [@Gankra](https://github.com/Gankra)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@charliermarsh](https://github.com/charliermarsh)

## 0.0.3

Released on 2025-12-17.

### LSP server

- Improve rendering of signatures in hovers ([#22007](https://github.com/astral-sh/ruff/pull/22007))

### Core type checking

- Apply narrowing to `len` calls based on argument size ([#22026](https://github.com/astral-sh/ruff/pull/22026))
- Don't add identical lower/upper bounds multiple times when inferring specializations ([#22030](https://github.com/astral-sh/ruff/pull/22030))
- Improve `unsupported-base` and `invalid-super-argument` diagnostics to avoid extremely long lines when encountering verbose types ([#22022](https://github.com/astral-sh/ruff/pull/22022))
- Improve disambiguation of types in many cases ([#22019](https://github.com/astral-sh/ruff/pull/22019))
- Respect deferred values in keyword arguments etc. for `.pyi` files ([#22029](https://github.com/astral-sh/ruff/pull/22029))
- Handle field specifier functions that accept `**kwargs` and recognize metaclass-based transformers as instances of `DataclassInstance` ([#22018](https://github.com/astral-sh/ruff/pull/22018))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@sharkdp](https://github.com/sharkdp)
- [@Gankra](https://github.com/Gankra)
- [@zanieb](https://github.com/zanieb)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@dcreager](https://github.com/dcreager)

## 0.0.2

Released on 2025-12-16.

This is the first Beta release of ty, which we're now ready to recommend to motivated users for
production use. See our [blog post](https://astral.sh/blog/ty) for more details.

### LSP server

- Improve display of completions to show actual insertion text ([#21988](https://github.com/astral-sh/ruff/pull/21988))
- Improve highlighting of special type syntax in hovers ([#22005](https://github.com/astral-sh/ruff/pull/22005))
- Improve syntax highlighting of constants ([#22006](https://github.com/astral-sh/ruff/pull/22006))

### Core type checking

- Infer precise types for `isinstance(…)` calls involving type variables ([#21999](https://github.com/astral-sh/ruff/pull/21999))
- Infer `TypeVar` specializations for `Callable` types ([#21551](https://github.com/astral-sh/ruff/pull/21551))
- Propagate `classmethod`-ness through decorators returning `Callable`s ([#21958](https://github.com/astral-sh/ruff/pull/21958))
- Improve rendering of default values for function args ([#22010](https://github.com/astral-sh/ruff/pull/22010))
- Don't use implicit superclass annotation when converting a class constructor into a `Callable` ([#22011](https://github.com/astral-sh/ruff/pull/22011))

### Other

- Type checking performance improvement ([#22000](https://github.com/astral-sh/ruff/pull/22000))

### Contributors

- [@sharkdp](https://github.com/sharkdp)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)
- [@BurntSushi](https://github.com/BurntSushi)
- [@dcreager](https://github.com/dcreager)
- [@MichaReiser](https://github.com/MichaReiser)

## 0.0.1-alpha.35

Released on 2025-12-16.

### Bug fixes

- Fix panic for stringified comprehensions and boolean expressions in type expression ([#21967](https://github.com/astral-sh/ruff/pull/21967))
- Avoid stack overflow when determining inferable typevars ([#21971](https://github.com/astral-sh/ruff/pull/21971))
- Fix false-positive `invalid-method-override` diagnostic on method that uses `Callable` with a `ParamSpec` ([#21934](https://github.com/astral-sh/ruff/pull/21934))
- Disallow explicit specialization of type variables themselves ([#21938](https://github.com/astral-sh/ruff/pull/21938))
- Fix hover type on named expression ("walrus expression") targets ([#21952](https://github.com/astral-sh/ruff/pull/21952))

### LSP server

- Add *"qualify ..."* code fix for undefined references ([#21968](https://github.com/astral-sh/ruff/pull/21968))
- Add new goto-definition targets on inlay hints ([#21950](https://github.com/astral-sh/ruff/pull/21950))
- Remove invalid statement-keyword completions in `for`-statements ([#21979](https://github.com/astral-sh/ruff/pull/21979))

### Core type checking

- Add support for `__qualname__` and other implicit class attributes ([#21966](https://github.com/astral-sh/ruff/pull/21966))
- Emit a diagnostic when a frozen dataclass inherits a non-frozen dataclass and vice versa ([#21962](https://github.com/astral-sh/ruff/pull/21962))
- Emit a diagnostic when a type variable with a default is followed by one without a default ([#21787](https://github.com/astral-sh/ruff/pull/21787))
- Improve diagnostics for unsupported binary operations and unsupported augmented assignments ([#21947](https://github.com/astral-sh/ruff/pull/21947))
- Improve check enforcing that an overloaded function must have an implementation ([#21978](https://github.com/astral-sh/ruff/pull/21978))
- Use unqualified names for displays of `TypeAliasType`s and unbound `ParamSpec`s/`TypeVar`s ([#21960](https://github.com/astral-sh/ruff/pull/21960))

### Performance

- Speed up ty on Linux by using jemalloc ([#21975](https://github.com/astral-sh/ruff/pull/21975))

### Contributors

- [@11happy](https://github.com/11happy)
- [@dhruvmanila](https://github.com/dhruvmanila)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@mtshiba](https://github.com/mtshiba)
- [@MichaReiser](https://github.com/MichaReiser)
- [@Gankra](https://github.com/Gankra)
- [@silamon](https://github.com/silamon)
- [@dcreager](https://github.com/dcreager)
- [@charliermarsh](https://github.com/charliermarsh)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@carljm](https://github.com/carljm)

## 0.0.1-alpha.34

Released on 2025-12-12.

### Bug fixes

- Improve solving of a type variable with an upper bound when that type variable appears as one element in a union type ([#21893](https://github.com/astral-sh/ruff/pull/21893))
- Accurately emulate runtime semantics for `kw_only=True` dataclasses such that only fields declared in the immediate class body are understood as being keyword-only ([#21820](https://github.com/astral-sh/ruff/pull/21820))
- Avoid inferring types for invalid binary expressions in string annotations ([#21911](https://github.com/astral-sh/ruff/pull/21911))
- Fix logic used to determine whether two `@final` instance types are disjoint ([#21769](https://github.com/astral-sh/ruff/pull/21769))
- Fix logic used to determine whether two `@final` `type[]` types are disjoint ([#21770](https://github.com/astral-sh/ruff/pull/21770))
- Fix false-positive diagnostics that could arise when analysing cyclic types ([#21910](https://github.com/astral-sh/ruff/pull/21910)), ([#21909](https://github.com/astral-sh/ruff/pull/21909))

### LSP server

- Fix outdated version in publish diagnostics after `didChange` ([#21943](https://github.com/astral-sh/ruff/pull/21943))
- Fix workspace symbols to return members too ([#21926](https://github.com/astral-sh/ruff/pull/21926))
- Adjust scope completions to use all reachable symbols ([#21872](https://github.com/astral-sh/ruff/pull/21872))
- Classify `cls` as class parameter for semantic highlighting ([#21944](https://github.com/astral-sh/ruff/pull/21944))
- Don't show on-hover tooltips for expressions with no inferred type ([#21924](https://github.com/astral-sh/ruff/pull/21924))
- Ignore `__all__` for document and workspace symbol requests ([#21928](https://github.com/astral-sh/ruff/pull/21928))
- Recognize `__all__ += submodule.__all__` in auto-import ([#21918](https://github.com/astral-sh/ruff/pull/21918))
- Stabilize rename ([#21940](https://github.com/astral-sh/ruff/pull/21940))

### Other changes

- Support checking files without extensions ([#21867](https://github.com/astral-sh/ruff/pull/21867))
- Improve performance and semantics by deferring inference of all parameter and return-type annotations ([#21906](https://github.com/astral-sh/ruff/pull/21906))
- Improve resolution of absolute imports in tests ([#21817](https://github.com/astral-sh/ruff/pull/21817))
- Infer the implicit type of the `cls` parameter in `@classmethod` method bodies ([#21685](https://github.com/astral-sh/ruff/pull/21685))
- Support the implicit type of the `cls` parameter in signatures of `@classmethod` methods ([#21771](https://github.com/astral-sh/ruff/pull/21771))
- Uniformly use "not supported" in diagnostics ([#21916](https://github.com/astral-sh/ruff/pull/21916))
- Implement the [equivalence relation](https://typing.python.org/en/latest/spec/glossary.html#term-equivalent) for `TypedDict`s ([#21784](https://github.com/astral-sh/ruff/pull/21784))
- Ensure that the type of the class object `C` is always considered assignable to `type[C[Unknown]]` if `C` is a generic class ([#21883](https://github.com/astral-sh/ruff/pull/21883))
- Improve bad specialization results and error messages ([#21840](https://github.com/astral-sh/ruff/pull/21840))
- Support `NewType`s of `float` and `complex` ([#21886](https://github.com/astral-sh/ruff/pull/21886))

### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@oconnor663](https://github.com/oconnor663)
- [@MichaReiser](https://github.com/MichaReiser)
- [@BurntSushi](https://github.com/BurntSushi)
- [@lucach](https://github.com/lucach)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@mtshiba](https://github.com/mtshiba)
- [@dcreager](https://github.com/dcreager)
- [@sharkdp](https://github.com/sharkdp)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)

## 0.0.1-alpha.33

Released on 2025-12-09.

### Bug fixes

- Fix assignability problem between `tuple[Any, ...]` and `tuple[int, *tuple[int, ...]]` ([#21803](https://github.com/astral-sh/ruff/pull/21803))
- Avoid diagnostic when `typing_extensions.ParamSpec` uses a `default` parameter ([#21839](https://github.com/astral-sh/ruff/pull/21839))
- Avoid crash for invalid `Annotated` subscript ([#21837](https://github.com/astral-sh/ruff/pull/21837))
- Avoid crash for invalid `Final` subscript ([#21828](https://github.com/astral-sh/ruff/pull/21828))
- Fix overload filtering to prefer more precise match when `*args: Any` is involved ([#21859](https://github.com/astral-sh/ruff/pull/21859))
- Handle various invalid explicit specializations for `ParamSpec` ([#21821](https://github.com/astral-sh/ruff/pull/21821))
- Fix stack overflow with recursive generic protocols (depth limit) ([#21858](https://github.com/astral-sh/ruff/pull/21858))

### LSP server

- Add autocomplete suggestions for parameters in function calls ([#21796](https://github.com/astral-sh/ruff/pull/21796))
- Don't create a related diagnostic for the primary annotation of sub-diagnostics ([#21845](https://github.com/astral-sh/ruff/pull/21845))
- Stabilize auto-import ([#21851](https://github.com/astral-sh/ruff/pull/21851))
- Suppress inlay hints when assigning a trivial initializer call ([#21848](https://github.com/astral-sh/ruff/pull/21848))
- Use concise message for LSP clients not supporting related diagnostic information ([#21850](https://github.com/astral-sh/ruff/pull/21850))
- Fix add-import action for `reveal_type` ([#21668](https://github.com/astral-sh/ruff/pull/21668))

### Core type checking

- Infer type variables within generic unions ([#21862](https://github.com/astral-sh/ruff/pull/21862))
- Type inference for `@asynccontextmanager` ([#21876](https://github.com/astral-sh/ruff/pull/21876))
- Make Python-version subdiagnostics less verbose ([#21849](https://github.com/astral-sh/ruff/pull/21849))

### Contributors

- [@BurntSushi](https://github.com/BurntSushi)
- [@dhruvmanila](https://github.com/dhruvmanila)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@carljm](https://github.com/carljm)
- [@Gankra](https://github.com/Gankra)
- [@charliermarsh](https://github.com/charliermarsh)
- [@RasmusNygren](https://github.com/RasmusNygren)
- [@sharkdp](https://github.com/sharkdp)
- [@MichaReiser](https://github.com/MichaReiser)

## 0.0.1-alpha.32

Released on 2025-12-05.

### LSP server

- Provide auto-import completion suggestions for modules in more situations ([#21799](https://github.com/astral-sh/ruff/pull/21799))
- Always register the ty server as a [rename provider](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename) if the LSP client doesn't support dynamic registration ([#21789](https://github.com/astral-sh/ruff/pull/21789))
- Support auto-import of re-exported symbols in completion suggestions ([#21779](https://github.com/astral-sh/ruff/pull/21779))
- Support renaming import aliases ([#21792](https://github.com/astral-sh/ruff/pull/21792))

### Core type checking

- Support `ParamSpec` ([#21445](https://github.com/astral-sh/ruff/pull/21445))
- Improve the accuracy of the inferred `Callable` supertype of generic classes ([#21798](https://github.com/astral-sh/ruff/pull/21798))
- Increase the limit on the number of elements in a non-recursively defined literal union ([#21683](https://github.com/astral-sh/ruff/pull/21683))
- Fix panics on mutually recursive generic protocols by normalizing the bounds/constraints of cyclic type variables ([#21800](https://github.com/astral-sh/ruff/pull/21800))

### Other changes

- Minor improvements to `assert_type` diagnostics ([#21811](https://github.com/astral-sh/ruff/pull/21811))
- Fix a panic in recursive + generic type aliases ([#21718](https://github.com/astral-sh/ruff/pull/21718))
- Fix a panic when instantiating a type variable with invalid constraints ([#21663](https://github.com/astral-sh/ruff/pull/21663))

### Contributors

- [@BurntSushi](https://github.com/BurntSushi)
- [@dhruvmanila](https://github.com/dhruvmanila)
- [@MichaReiser](https://github.com/MichaReiser)
- [@mtshiba](https://github.com/mtshiba)
- [@dcreager](https://github.com/dcreager)
- [@carljm](https://github.com/carljm)
- [@AlexWaygood](https://github.com/AlexWaygood)

## 0.0.1-alpha.31

Released on 2025-12-04.

### Bug fixes

- Fix incorrect `possibly-missing-attribute` diagnostics for `asyncio` imports on Python 3.14 ([#21776](https://github.com/astral-sh/ruff/pull/21776))
- Fix panic for recursive type aliases ([#21778](https://github.com/astral-sh/ruff/pull/21778))

### Core type checking

- Try ancestor `pyproject.toml` directories as search-paths if module resolution fails ([#21745](https://github.com/astral-sh/ruff/pull/21745))
- Sync vendored typeshed stubs ([#21715](https://github.com/astral-sh/ruff/pull/21715)) [Typeshed diff](https://github.com/python/typeshed/compare/f8cdc0bd526301e873cd952eb0d457bdf2554e57...ef2b90c67e5c668b91b3ae121baf00ee5165c30b)

### LSP server

- Don't send publish diagnostics for clients supporting pull diagnostics ([#21772](https://github.com/astral-sh/ruff/pull/21772))
- Fix crash when hovering over string annotations with unknown symbols ([#21782](https://github.com/astral-sh/ruff/pull/21782))

### Diagnostics

- Add subdiagnostic hint if the user wrote `X = Any` rather than `X: Any` ([#21777](https://github.com/astral-sh/ruff/pull/21777))
- Improve the display of various special-form types ([#21775](https://github.com/astral-sh/ruff/pull/21775))

### Contributors

- [@sharkdp](https://github.com/sharkdp)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@MichaReiser](https://github.com/MichaReiser)
- [@Gankra](https://github.com/Gankra)

## 0.0.1-alpha.30

Released on 2025-12-03.

### Bug fixes

- Fix exhaustiveness checking for `match` statements over unions of generic instance types ([#21726](https://github.com/astral-sh/ruff/pull/21726))
- Don't introduce invalid syntax when autofixing `override-of-final-method` ([#21699](https://github.com/astral-sh/ruff/pull/21699))
- Suppress false positives when `dataclasses.dataclass(...)(cls)` is called imperatively ([#21729](https://github.com/astral-sh/ruff/pull/21729))
- Fix false positives for `class F(Generic[*Ts]): ...` ([#21723](https://github.com/astral-sh/ruff/pull/21723))
- Don't confuse multiple occurrences of `typing.Self` when binding bound methods ([#21754](https://github.com/astral-sh/ruff/pull/21754))
- Fix subtyping between `type[T]` and a union type, where `T` is a type variable in scope ([#21740](https://github.com/astral-sh/ruff/pull/21740))
- Fix subtyping between `type[T]` and `U`, where `T` is a type variable in scope and `U` is a type variable not in scope ([#21766](https://github.com/astral-sh/ruff/pull/21766))
- Fix false positives for `type[tuple[...]]` ([#21652](https://github.com/astral-sh/ruff/pull/21652))

### Memory usage improvements

- Significantly reduce memory usage (especially when ty is used as an LSP server) by enabling least-recently-used ([LRU](https://en.wikipedia.org/wiki/Page_replacement_algorithm#Least_recently_used)) cache eviction for module ASTs ([#21749](https://github.com/astral-sh/ruff/pull/21749))

### LSP server

- Add code action to ignore diagnostic on the current line ([#21595](https://github.com/astral-sh/ruff/pull/21595))
- Exclude `typing_extensions` from autocomplete suggestions unless it's really available ([#21731](https://github.com/astral-sh/ruff/pull/21731))
- Fix auto-import code action to handle pre-existing imports ([#21733](https://github.com/astral-sh/ruff/pull/21733))
- Fix "find all references" for types defined in stub files ([#21732](https://github.com/astral-sh/ruff/pull/21732))
- Fix "find all references" for symbols defined via aliased imports ([#21736](https://github.com/astral-sh/ruff/pull/21736))

### Improvements to handling of type aliases

- Default-specialize generic type aliases when they appear unspecialized in type expressions ([#21765](https://github.com/astral-sh/ruff/pull/21765))
- Infer a type alias as being a generic type alias if it includes a type variable in its definition, even in cases where the value subscripted with the type variable is inferred as having a dynamic type such as `Any` or `Unknown` ([#21730](https://github.com/astral-sh/ruff/pull/21730))

### New `NamedTuple` diagnostics

- Detect `NamedTuple` classes that have field names starting with underscores, which is banned at runtime ([#21697](https://github.com/astral-sh/ruff/pull/21697))
- Add a diagnostic detecting overrides of prohibited `NamedTuple` attributes ([#21717](https://github.com/astral-sh/ruff/pull/21717))
- Detect illegal uses of `super()` in methods of `NamedTuple` classes ([#21700](https://github.com/astral-sh/ruff/pull/21700))

### Improvements to existing diagnostics

- Improve diagnostics for unsupported comparison operations ([#21737](https://github.com/astral-sh/ruff/pull/21737))
- For `invalid-type-arguments` diagnostics, show the user where the type variable was defined ([#21727](https://github.com/astral-sh/ruff/pull/21727))
- Extend `invalid-explicit-override` to also cover properties decorated with `@override` that do not override anything ([#21756](https://github.com/astral-sh/ruff/pull/21756))
- Improve `@override`, `@final` and Liskov checks in cases where there are multiple reachable definitions ([#21767](https://github.com/astral-sh/ruff/pull/21767))

### Contributors

- [@MichaReiser](https://github.com/MichaReiser)
- [@charliermarsh](https://github.com/charliermarsh)
- [@dcreager](https://github.com/dcreager)
- [@carljm](https://github.com/carljm)
- [@AlexWaygood](https://github.com/AlexWaygood)
- [@BurntSushi](https://github.com/BurntSushi)
- [@ibraheemdev](https://github.com/ibraheemdev)
- [@woodruffw](https://github.com/woodruffw)
- [@sharkdp](https://github.com/sharkdp)

## 0.0.1-alpha.29

Released on 2025-11-28.

### Bug Fix

- Fix multiple panics due to recursive type definitions ([#20566](https://github.com/astral-sh/ruff/pull/20566))

### Type inference

- Support `type[T]` where `T` is a type variable ([#21650](https://github.com/astral-sh/ruff/pull/21650))
- More precise inference for a failed specialization of a generic type ([#21651](https://github.com/astral-sh/ruff/pull/21651))
- Detect invalid overrides of methods that are marked as `typing.final` ([#21646](https://github.com/astral-sh/ruff/pull/21646))
- Fix subtyping of `type[Any]` / `type[T]` and protocols ([#21678](https://github.com/astral-sh/ruff/pull/21678))
- Added generics support for implicit and explicit (`typing.TypeAlias`) type aliases ([#21553](https://github.com/astral-sh/ruff/pull/21553))

### LSP server

- Add `import ...` code action for unresolved references ([#21629](https://github.com/astral-sh/ruff/pull/21629))
- Include all members on `type` in autocompletion suggestions for `type[]` types ([#21670](https://github.com/astral-sh/ruff/pull/21670))
- Mark comprehension targets as definitions in semantic highlighting ([#21636](https://github.com/astral-sh/ruff/pull/21636))
- Add IDE autofixes for two "Did you mean...?" suggestions ([#21667](https://github.com/astral-sh/ruff/pull/21667))
- Prettier rendering of `code:: lang` in docstrings ([#21665](https://github.com/astral-sh/ruff/pull/21665))
- Support go-to for patterns and typevars ([#21671](https://github.co
Download .txt
gitextract_pe4vyql8/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1_bug_report.yaml
│   │   ├── 2_question.yaml
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── actionlint.yaml
│   ├── renovate.json5
│   ├── workflows/
│   │   ├── build-binaries.yml
│   │   ├── build-docker.yml
│   │   ├── ci.yaml
│   │   ├── daily_property_tests.yml
│   │   ├── publish-docs.yml
│   │   ├── publish-mirror.yml
│   │   ├── publish-pypi.yml
│   │   └── release.yml
│   └── zizmor.yml
├── .gitignore
├── .gitmodules
├── .markdownlint.yaml
├── .pre-commit-config.yaml
├── .python-version
├── BENCHMARKS.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── SECURITY.md
├── _typos.toml
├── assets/
│   └── badge/
│       └── v0.json
├── dist-workspace.toml
├── docs/
│   ├── .overrides/
│   │   ├── main.html
│   │   └── partials/
│   │       └── integrations/
│   │           └── analytics/
│   │               └── fathom.html
│   ├── configuration.md
│   ├── editors.md
│   ├── exclusions.md
│   ├── features/
│   │   ├── diagnostics.md
│   │   ├── language-server.md
│   │   └── type-system.md
│   ├── index.md
│   ├── installation.md
│   ├── js/
│   │   └── extra.js
│   ├── modules.md
│   ├── python-version.md
│   ├── reference/
│   │   ├── cli.md
│   │   ├── configuration.md
│   │   ├── editor-settings.md
│   │   ├── environment.md
│   │   ├── exit-codes.md
│   │   ├── rules.md
│   │   └── typing-faq.md
│   ├── requirements.in
│   ├── requirements.txt
│   ├── rules.md
│   ├── stylesheets/
│   │   └── extra.css
│   ├── suppression.md
│   └── type-checking.md
├── mkdocs.yml
├── pyproject.toml
├── python/
│   └── ty/
│       ├── __init__.py
│       ├── __main__.py
│       ├── _find_ty.py
│       └── py.typed
└── scripts/
    ├── autogenerate_files.sh
    ├── release.sh
    ├── transform_readme.py
    └── update_schemastore.py
Download .txt
SYMBOL INDEX (17 symbols across 5 files)

FILE: docs/js/extra.js
  function cleanupClipboardText (line 1) | function cleanupClipboardText(targetSelector) {
  function setCopyText (line 20) | function setCopyText() {
  function get_path (line 64) | function get_path() {

FILE: python/ty/__main__.py
  function _run (line 9) | def _run() -> None:

FILE: python/ty/_find_ty.py
  class TyNotFound (line 8) | class TyNotFound(FileNotFoundError): ...
  function find_ty_bin (line 11) | def find_ty_bin() -> str:
  function _module_path (line 56) | def _module_path() -> str | None:
  function _matching_parents (line 61) | def _matching_parents(path: str | None, match: str) -> str | None:
  function _join (line 87) | def _join(path: str | None, *parts: str) -> str | None:
  function _user_scheme (line 93) | def _user_scheme() -> str:

FILE: scripts/transform_readme.py
  function main (line 21) | def main() -> None:

FILE: scripts/update_schemastore.py
  class SchemastoreRepos (line 34) | class SchemastoreRepos(NamedTuple):
  class GitProtocol (line 39) | class GitProtocol(enum.Enum):
    method schemastore_repos (line 43) | def schemastore_repos(self) -> SchemastoreRepos:
  function update_schemastore (line 59) | def update_schemastore(
  function determine_git_protocol (line 142) | def determine_git_protocol(argv: list[str] | None = None) -> GitProtocol:
  function main (line 158) | def main() -> None:
Condensed preview — 68 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (655K chars).
[
  {
    "path": ".editorconfig",
    "chars": 317,
    "preview": "# Check http://editorconfig.org for more information\n# This is the main config file for this project:\nroot = true\n\n[*]\nc"
  },
  {
    "path": ".gitattributes",
    "chars": 170,
    "preview": "* text=auto eol=lf\n\ndocs/reference/cli.md linguist-generated=true\ndocs/reference/configuration.md linguist-generated=tru"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1_bug_report.yaml",
    "chars": 1311,
    "preview": "name: Bug report\ndescription: Report an error or unexpected behavior\nbody:\n  - type: markdown\n    attributes:\n      valu"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2_question.yaml",
    "chars": 449,
    "preview": "name: Question\ndescription: Ask a question about ty\nlabels: [\"question\"]\nbody:\n  - type: textarea\n    attributes:\n      "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 335,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: Documentation\n    url: https://github.com/astral-sh/ty/blob/main/REA"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 424,
    "preview": "<!--\nThank you for contributing to ty! To help us out with reviewing, please consider the following:\n\n- Does this pull r"
  },
  {
    "path": ".github/actionlint.yaml",
    "chars": 404,
    "preview": "# Configuration for the actionlint tool, which we run via prek\n# to verify the correctness of the syntax in our GitHub A"
  },
  {
    "path": ".github/renovate.json5",
    "chars": 1894,
    "preview": "{\n  $schema: \"https://docs.renovatebot.com/renovate-schema.json\",\n  dependencyDashboard: true,\n  suppressNotifications: "
  },
  {
    "path": ".github/workflows/build-binaries.yml",
    "chars": 18058,
    "preview": "# Build ty on all platforms.\n#\n# Generates both wheels (for PyPI) and archived binaries (for GitHub releases).\n#\n# Assum"
  },
  {
    "path": ".github/workflows/build-docker.yml",
    "chars": 15113,
    "preview": "# Build and publish a Docker image.\n#\n# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, "
  },
  {
    "path": ".github/workflows/ci.yaml",
    "chars": 3760,
    "preview": "name: CI\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches: [main]\n  pull_request:\n  workflow_dispatch:\n\nconcurre"
  },
  {
    "path": ".github/workflows/daily_property_tests.yml",
    "chars": 2665,
    "preview": "name: Daily property test run\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: \"0 12 * * *\"\n  pull_request:\n    paths:\n"
  },
  {
    "path": ".github/workflows/publish-docs.yml",
    "chars": 4094,
    "preview": "# Publish the ty documentation.\n#\n# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a"
  },
  {
    "path": ".github/workflows/publish-mirror.yml",
    "chars": 1525,
    "preview": "# Publish ty releases to a mirror\n#\n# Assumed to run as a subworkflow of .github/workflows/release.yml as a custom publi"
  },
  {
    "path": ".github/workflows/publish-pypi.yml",
    "chars": 830,
    "preview": "# Publish a release to PyPI.\n#\n# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a pu"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 12048,
    "preview": "# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist\n#\n# Copyright 2022-2024, axodotdev\n# SPDX-"
  },
  {
    "path": ".github/zizmor.yml",
    "chars": 140,
    "preview": "rules:\n  secrets-outside-env:\n    ignore:\n      # TODO: move the ASTRAL_DOCS_PAT secret to the release environment\n     "
  },
  {
    "path": ".gitignore",
    "chars": 109,
    "preview": "# Python-generated files\n__pycache__/\n*.py[oc]\nbuild/\ndist/\nwheels/\n*.egg-info\n\n# Virtual environments\n.venv\n"
  },
  {
    "path": ".gitmodules",
    "chars": 73,
    "preview": "[submodule \"ruff\"]\n\tpath = ruff\n\turl = https://github.com/astral-sh/ruff\n"
  },
  {
    "path": ".markdownlint.yaml",
    "chars": 746,
    "preview": "# default to true for all rules\ndefault: true\n\n# MD007/unordered-list-indent\nMD007:\n  indent: 4\n\n# MD033/no-inline-html\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 3402,
    "preview": "fail_fast: false\n\nexclude: |\n  (?x)^(\n    .github/workflows/release.yml|\n    ruff/.*|\n    docs/reference/(cli|configurat"
  },
  {
    "path": ".python-version",
    "chars": 5,
    "preview": "3.13\n"
  },
  {
    "path": "BENCHMARKS.md",
    "chars": 33803,
    "preview": "# Benchmarks\n\nAll benchmarks were computed on macOS (Apple M4 Pro 14, 48 GB) with the following tool versions:\n\n- [Pyref"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 211799,
    "preview": "# Changelog\n\n## 0.0.24\n\nReleased on 2026-03-19.\n\n### Bug fixes\n\n- Ensure `TypedDict` subscripts for unknown keys return "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 9674,
    "preview": "# Contributing\n\n> [!IMPORTANT]\n> If you want to contribute changes to ty's core, please check out the\n> [dedicated `ty` "
  },
  {
    "path": "Dockerfile",
    "chars": 1490,
    "preview": "FROM --platform=$BUILDPLATFORM ubuntu AS build\nENV HOME=\"/root\"\nWORKDIR $HOME\n\nRUN apt update && apt install -y build-es"
  },
  {
    "path": "LICENSE",
    "chars": 1077,
    "preview": "MIT License\n\nCopyright (c) 2025 Astral Software Inc.\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "README.md",
    "chars": 4958,
    "preview": "# ty\n\n[![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.jso"
  },
  {
    "path": "SECURITY.md",
    "chars": 466,
    "preview": "# Security policy\n\n## Reporting a vulnerability\n\nIf you have found a possible vulnerability, please email `security at a"
  },
  {
    "path": "_typos.toml",
    "chars": 221,
    "preview": "[files]\nextend-exclude = []\n\n[default.extend-words]\n\n[default]\nextend-ignore-re = [\n    # Line ignore with trailing \"spe"
  },
  {
    "path": "assets/badge/v0.json",
    "chars": 335,
    "preview": "{\n  \"label\": \"\",\n  \"message\": \"ty\",\n  \"logoSvg\": \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"48\\\" height=\\\"48\\\"><"
  },
  {
    "path": "dist-workspace.toml",
    "chars": 3522,
    "preview": "[workspace]\nmembers = [\"cargo:./ruff\"]\npackages = [\"ty\"]\nversion = \"0.0.24\"\n\n# Config for 'dist'\n[dist]\n# The preferred "
  },
  {
    "path": "docs/.overrides/main.html",
    "chars": 1498,
    "preview": "{% extends \"base.html\" %}\n\n{% block htmltitle %}\n{% if page.meta and page.meta.title %}\n<title>{{ page.meta.title }} | {"
  },
  {
    "path": "docs/.overrides/partials/integrations/analytics/fathom.html",
    "chars": 87,
    "preview": "<script src=\"https://cdn.usefathom.com/script.js\" data-site=\"ASBGCSTT\" defer></script>\n"
  },
  {
    "path": "docs/configuration.md",
    "chars": 2178,
    "preview": "# Configuration\n\n## Configuration files\n\nty supports persistent configuration files at both the project- and user-level."
  },
  {
    "path": "docs/editors.md",
    "chars": 4578,
    "preview": "# Editor integration\n\nty can be integrated with various editors to provide a seamless development experience.\n\nLearn mor"
  },
  {
    "path": "docs/exclusions.md",
    "chars": 3422,
    "preview": "# Excluding files\n\nty automatically discovers all Python files in your project. You can customize where ty searches by u"
  },
  {
    "path": "docs/features/diagnostics.md",
    "chars": 1826,
    "preview": "# Diagnostics\n\nty provides diagnostics that include snippets of your source code, annotations and helpful\nexplanations. "
  },
  {
    "path": "docs/features/language-server.md",
    "chars": 14358,
    "preview": "<!-- Note for maintainers: the screenshots referenced in this document were taken using\n     the \"Atom One Light\" theme "
  },
  {
    "path": "docs/features/type-system.md",
    "chars": 8912,
    "preview": "# Type system\n\nYou can generally expect ty to support all typing features that are described and specified in the\n[Pytho"
  },
  {
    "path": "docs/index.md",
    "chars": 2621,
    "preview": "# ty\n\nAn extremely fast Python type checker and language server, written in Rust.\n\n<p align=\"center\">\n  <img alt=\"Shows "
  },
  {
    "path": "docs/installation.md",
    "chars": 4872,
    "preview": "# Installing ty\n\n## Running ty without installation\n\nUse [uvx](https://docs.astral.sh/uv/guides/tools/) to quickly get s"
  },
  {
    "path": "docs/js/extra.js",
    "chars": 2739,
    "preview": "function cleanupClipboardText(targetSelector) {\n  const targetElement = document.querySelector(targetSelector);\n\n  // ex"
  },
  {
    "path": "docs/modules.md",
    "chars": 2261,
    "preview": "# Module discovery\n\n## First-party modules\n\nFirst-party modules are Python files that are part of your project source co"
  },
  {
    "path": "docs/python-version.md",
    "chars": 1864,
    "preview": "# Python version\n\nThe Python version affects allowed syntax, type definitions of the standard library, and type\ndefiniti"
  },
  {
    "path": "docs/reference/cli.md",
    "chars": 13112,
    "preview": "<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the doc comments in 'crates/ty/src/args.rs' if "
  },
  {
    "path": "docs/reference/configuration.md",
    "chars": 21859,
    "preview": "<!-- WARNING: This file is auto-generated (cargo dev generate-all). Update the doc comments on the 'Options' struct in '"
  },
  {
    "path": "docs/reference/editor-settings.md",
    "chars": 13006,
    "preview": "# Editor settings\n\nThe editor settings supported by ty's language server, as well as the settings specific to [ty's VS\nC"
  },
  {
    "path": "docs/reference/environment.md",
    "chars": 2511,
    "preview": "# Environment variables\n\nty defines and respects the following environment variables:\n\n### `TY_CONFIG_FILE`\n\nPath to a `"
  },
  {
    "path": "docs/reference/exit-codes.md",
    "chars": 770,
    "preview": "# Exit codes\n\nThe ty command line interface uses the following exit codes:\n\n| Exit code | Description                   "
  },
  {
    "path": "docs/reference/rules.md",
    "chars": 136294,
    "preview": "<!-- WARNING: This file is auto-generated (cargo dev generate-all). Edit the lint-declarations in 'crates/ty_python_sema"
  },
  {
    "path": "docs/reference/typing-faq.md",
    "chars": 16122,
    "preview": "# Typing FAQ\n\nThis page answers some commonly asked questions about ty and Python's type system.\n\n## Why does ty report "
  },
  {
    "path": "docs/requirements.in",
    "chars": 233,
    "preview": "black>=23.10.0\nmkdocs>=1.5.0\nmkdocs-material>=9.7.0\nmkdocs-redirects>=1.2.1\nmdformat>=0.7.17\nmdformat-mkdocs>=2.0.4\nmdfo"
  },
  {
    "path": "docs/requirements.txt",
    "chars": 3321,
    "preview": "# This file was autogenerated by uv via the following command:\n#    uv pip compile docs/requirements.in -o docs/requirem"
  },
  {
    "path": "docs/rules.md",
    "chars": 2145,
    "preview": "# Rules\n\nRules are individual checks that ty performs to detect common issues in your code, such as\nincompatible assignm"
  },
  {
    "path": "docs/stylesheets/extra.css",
    "chars": 7078,
    "preview": ":root {\n  --black: #261230;\n  --white: #ffffff;\n  --radiate: #d7ff64;\n  --flare: #6340ac;\n  --rock: #78876e;\n  --galaxy:"
  },
  {
    "path": "docs/suppression.md",
    "chars": 2967,
    "preview": "# Suppression\n\nRules can also be ignored in specific locations in your code (instead of disabling the rule\nentirely) to "
  },
  {
    "path": "docs/type-checking.md",
    "chars": 2173,
    "preview": "# Type checking\n\nAfter [installing ty](./installation.md), it's time to type check some code!\n\n## Running the type check"
  },
  {
    "path": "mkdocs.yml",
    "chars": 4491,
    "preview": "site_name: ty\ntheme:\n  name: material\n  logo: assets/logo-letter.svg\n  favicon: assets/favicon.ico\n  features:\n    - nav"
  },
  {
    "path": "pyproject.toml",
    "chars": 3575,
    "preview": "[project]\nname = \"ty\"\nversion = \"0.0.24\"\nrequires-python = \">=3.8\"\ndependencies = []\ndescription = \"An extremely fast Py"
  },
  {
    "path": "python/ty/__init__.py",
    "chars": 97,
    "preview": "from __future__ import annotations\n\nfrom ._find_ty import find_ty_bin\n\n__all__ = [\"find_ty_bin\"]\n"
  },
  {
    "path": "python/ty/__main__.py",
    "chars": 520,
    "preview": "from __future__ import annotations\n\nimport os\nimport sys\n\nfrom ty import find_ty_bin\n\n\ndef _run() -> None:\n    ty = find"
  },
  {
    "path": "python/ty/_find_ty.py",
    "chars": 3192,
    "preview": "from __future__ import annotations\n\nimport os\nimport sys\nimport sysconfig\n\n\nclass TyNotFound(FileNotFoundError): ...\n\n\nd"
  },
  {
    "path": "python/ty/py.typed",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "scripts/autogenerate_files.sh",
    "chars": 602,
    "preview": "#!/usr/bin/env sh\n#\n# Generate files and copy documentation from Ruff.\n#\n# Usage\n#\n#   ./scripts/autogenerate-files.sh\n#"
  },
  {
    "path": "scripts/release.sh",
    "chars": 2418,
    "preview": "#!/usr/bin/env sh\n#\n# Prepare a release.\n#\n# Usage\n#\n#   ./scripts/release.sh [rooster-args ...]\n#\nset -eu\n\necho \"Checki"
  },
  {
    "path": "scripts/transform_readme.py",
    "chars": 2635,
    "preview": "\"\"\"Transform the README.md to support a specific deployment target.\n\nBy default, we assume that our README.md will be re"
  },
  {
    "path": "scripts/update_schemastore.py",
    "chars": 6135,
    "preview": "\"\"\"Update ty.json in schemastore.\n\nThis script will clone `astral-sh/schemastore`, update the schema and push the change"
  }
]

About this extraction

This page contains the full source code of the astral-sh/ty GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 68 files (616.9 KB), approximately 177.2k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!