Compare commits
22 Commits
main
...
david/type
| Author | SHA1 | Date |
|---|---|---|
|
|
a0b2d91932 | |
|
|
6d86e85ab5 | |
|
|
4769721baa | |
|
|
1026a03306 | |
|
|
54b62c5ec7 | |
|
|
80e1ff294d | |
|
|
9e89c7a9ef | |
|
|
ab4ac358e7 | |
|
|
311b0880bf | |
|
|
a2692af074 | |
|
|
91e0f54dc0 | |
|
|
beb5a1fee9 | |
|
|
606a45d26c | |
|
|
bb96d86249 | |
|
|
208984e181 | |
|
|
7e96b365e7 | |
|
|
cd1b251bc3 | |
|
|
f5d67c3682 | |
|
|
9a41e102c0 | |
|
|
bcc9e1d05c | |
|
|
41fc2b79c0 | |
|
|
6dc83fb2b2 |
|
|
@ -57,9 +57,9 @@ jobs:
|
|||
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')
|
||||
version=$(grep -m 1 "^version = " dist-workspace.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 "The input tag does not match the version from dist-workspace.toml:" >&2
|
||||
echo "${TAG}" >&2
|
||||
echo "${version}" >&2
|
||||
exit 1
|
||||
|
|
@ -135,6 +135,7 @@ jobs:
|
|||
# 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=raw,value=${{ fromJson(inputs.plan).announcement_tag }}
|
||||
type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}
|
||||
|
||||
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
|
|
@ -169,9 +170,9 @@ jobs:
|
|||
# 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
|
||||
- alpine:3.21,alpine3.21,alpine
|
||||
- debian:bookworm-slim,bookworm-slim,debian-slim
|
||||
- buildpack-deps:bookworm,bookworm,debian
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
|
|
@ -194,7 +195,7 @@ jobs:
|
|||
# Generate Dockerfile content
|
||||
cat <<EOF > Dockerfile
|
||||
FROM ${BASE_IMAGE}
|
||||
COPY --from=${TY_BASE_IMG}:latest /ty /usr/local/bin/ty
|
||||
COPY --from=${TY_BASE_IMG}:${TAG_VALUE} /ty /usr/local/bin/ty
|
||||
ENTRYPOINT []
|
||||
CMD ["/usr/local/bin/ty"]
|
||||
EOF
|
||||
|
|
@ -280,6 +281,7 @@ jobs:
|
|||
# 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=raw,value=${{ fromJson(inputs.plan).announcement_tag }}
|
||||
type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}
|
||||
|
||||
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
|
|
|
|||
|
|
@ -88,4 +88,4 @@ repos:
|
|||
# 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"
|
||||
- "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.10.0"
|
||||
|
|
|
|||
464
BENCHMARKS.md
|
|
@ -1,464 +0,0 @@
|
|||
# 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
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
```
|
||||
284
CHANGELOG.md
|
|
@ -1,289 +1,5 @@
|
|||
# Changelog
|
||||
|
||||
## 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.
|
||||
|
|
|
|||
91
README.md
|
|
@ -6,60 +6,51 @@
|
|||
|
||||
An extremely fast Python type checker and language server, written in Rust.
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<img alt="Shows a bar chart with benchmark results." width="500px" src="./docs/assets/ty-benchmark-cli.svg">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<i>Type checking the <a href="https://github.com/home-assistant/core">home-assistant</a> project without caching.</i>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
ty is backed by [Astral](https://astral.sh), the creators of
|
||||
[uv](https://github.com/astral-sh/uv) and [Ruff](https://github.com/astral-sh/ruff).
|
||||
|
||||
## Highlights
|
||||
|
||||
- 10x - 100x faster than mypy and Pyright
|
||||
- Comprehensive [diagnostics](https://docs.astral.sh/ty/features/diagnostics/) with rich contextual information
|
||||
- Configurable [rule levels](https://docs.astral.sh/ty/rules/), [per-file overrides](https://docs.astral.sh/ty/reference/configuration/#overrides), [suppression comments](https://docs.astral.sh/ty/suppression/), and first-class project support
|
||||
- Designed for adoption, with support for [redeclarations](https://docs.astral.sh/ty/features/type-system/#redeclarations) and [partially typed code](https://docs.astral.sh/ty/features/type-system/#gradual-guarantee)
|
||||
- [Language server](https://docs.astral.sh/ty/features/language-server/) with code navigation, completions, code actions, auto-import, inlay hints, on-hover help, etc.
|
||||
- Fine-grained [incremental analysis](https://docs.astral.sh/ty/features/language-server/#fine-grained-incrementality) designed for fast updates when editing files in an IDE
|
||||
- Editor integrations for [VS Code](https://docs.astral.sh/ty/editors/#vs-code), [PyCharm](https://docs.astral.sh/ty/editors/#pycharm), [Neovim](https://docs.astral.sh/ty/editors/#neovim) and more
|
||||
- Advanced typing features like first-class [intersection types](https://docs.astral.sh/ty/features/type-system/#intersection-types), advanced [type narrowing](https://docs.astral.sh/ty/features/type-system/#top-and-bottom-materializations), and
|
||||
[sophisticated reachability analysis](https://docs.astral.sh/ty/features/type-system/#reachability-based-on-types)
|
||||
|
||||
## Getting started
|
||||
|
||||
Run ty with [uvx](https://docs.astral.sh/uv/guides/tools/#running-tools) to get started quickly:
|
||||
Try out the [online playground](https://play.ty.dev), or run ty with
|
||||
[uvx](https://docs.astral.sh/uv/guides/tools/#running-tools) to get started quickly:
|
||||
|
||||
```shell
|
||||
uvx ty
|
||||
```
|
||||
|
||||
For other ways to install ty, see the [installation](https://docs.astral.sh/ty/installation/) documentation.
|
||||
|
||||
If you do not provide a subcommand, ty will list available commands — for detailed information about
|
||||
command-line options, see the [CLI reference](https://docs.astral.sh/ty/reference/cli/).
|
||||
|
||||
Use the `check` command to run the type checker:
|
||||
|
||||
```shell
|
||||
uvx ty check
|
||||
```
|
||||
|
||||
Or, check out the [ty playground](https://play.ty.dev) to try it out in your browser.
|
||||
ty will run on all Python files in the working directory and or subdirectories. If used from a
|
||||
project, ty will run on all Python files in the project (starting in the directory with the
|
||||
`pyproject.toml`)
|
||||
|
||||
You can also provide specific paths to check:
|
||||
|
||||
```shell
|
||||
uvx ty check example.py
|
||||
```
|
||||
|
||||
When type checking, ty will find installed packages in the active virtual environment (via
|
||||
`VIRTUAL_ENV`) or discover a virtual environment named `.venv` in the project root or working
|
||||
directory. It will not find packages in non-virtual environments without specifying the target path
|
||||
with `--python`. See the [module discovery](https://docs.astral.sh/ty/modules/) documentation for
|
||||
details.
|
||||
|
||||
## Learning more
|
||||
|
||||
To learn more about using ty, see the [documentation](https://docs.astral.sh/ty/).
|
||||
|
||||
## Installation
|
||||
|
||||
To install ty, see the [installation](https://docs.astral.sh/ty/installation/) documentation.
|
||||
|
||||
To add the ty language server to your editor, see the [editor integration](https://docs.astral.sh/ty/editors/) guide.
|
||||
|
||||
## Getting help
|
||||
## Getting involved
|
||||
|
||||
If you have questions or want to report a bug, please open an
|
||||
[issue](https://github.com/astral-sh/ty/issues) in this repository.
|
||||
|
||||
You may also join our [Discord server](https://discord.com/invite/astral-sh).
|
||||
|
||||
## Contributing
|
||||
|
||||
Development of this project takes place in the [Ruff](https://github.com/astral-sh/ruff) repository
|
||||
at this time. Please [open pull requests](https://github.com/astral-sh/ruff/pulls) there for changes
|
||||
to anything in the `ruff` submodule (which includes all of the Rust source code).
|
||||
|
|
@ -67,26 +58,6 @@ to anything in the `ruff` submodule (which includes all of the Rust source code)
|
|||
See the
|
||||
[contributing guide](./CONTRIBUTING.md) for more details.
|
||||
|
||||
## FAQ
|
||||
|
||||
<!-- We intentionally use smaller headings for the FAQ items -->
|
||||
|
||||
<!-- markdownlint-disable MD001 -->
|
||||
|
||||
#### Why is ty doing \_\_\_\_\_?
|
||||
|
||||
See our [typing FAQ](https://docs.astral.sh/ty/reference/typing-faq).
|
||||
|
||||
#### How do you pronounce ty?
|
||||
|
||||
It's pronounced as "tee - why" ([`/tiː waɪ/`](https://en.wikipedia.org/wiki/Help:IPA/English#Key))
|
||||
|
||||
#### How should I stylize ty?
|
||||
|
||||
Just "ty", please.
|
||||
|
||||
<!-- markdownlint-enable MD001 -->
|
||||
|
||||
## License
|
||||
|
||||
ty is licensed under the MIT license ([LICENSE](LICENSE) or
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[workspace]
|
||||
members = ["cargo:./ruff"]
|
||||
packages = ["ty"]
|
||||
version = "0.0.8"
|
||||
version = "0.0.1-alpha.34"
|
||||
|
||||
# Config for 'dist'
|
||||
[dist]
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
|
@ -8,24 +8,25 @@ Specifically, ty will search for a `pyproject.toml` or `ty.toml` file in the cur
|
|||
|
||||
If a `pyproject.toml` file is found, ty will read configuration from the `[tool.ty]` table. For example, to ignore the `index-out-of-bounds` rule, add the following to a `pyproject.toml`:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
**`pyproject.toml`**:
|
||||
|
||||
```toml
|
||||
[tool.ty.rules]
|
||||
index-out-of-bounds = "ignore"
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
If there is no `tool.ty` table, the `pyproject.toml` file will be ignored, and ty will continue
|
||||
searching in the directory hierarchy.
|
||||
(If there is no `tool.ty` table, the `pyproject.toml` file will be ignored, and ty will continue searching in the directory hierarchy.)
|
||||
|
||||
ty will also search for `ty.toml` files, which follow an identical structure, but omit the `[tool.ty]` prefix. For example:
|
||||
|
||||
```toml title="ty.toml"
|
||||
**`ty.toml`**:
|
||||
|
||||
```toml
|
||||
[rules]
|
||||
index-out-of-bounds = "ignore"
|
||||
```
|
||||
|
||||
!!! important
|
||||
!!! note
|
||||
|
||||
`ty.toml` files take precedence over `pyproject.toml` files, so if both `ty.toml` and `pyproject.toml` files are present in a directory, configuration will be read from `ty.toml`, and the `[tool.ty]` section in the accompanying `pyproject.toml` will be ignored.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
ty can be integrated with various editors to provide a seamless development experience.
|
||||
|
||||
Learn more about ty's editor features in the [language server](./features/language-server.md)
|
||||
documentation.
|
||||
|
||||
## VS Code
|
||||
|
||||
The Astral team maintains an official VS Code extension.
|
||||
|
|
@ -105,7 +102,7 @@ Starting with version 2025.3, PyCharm users can enable native ty support in the
|
|||
|
||||
1. Select which options should be enabled.
|
||||
|
||||
For more information, refer to [PyCharm documentation](https://www.jetbrains.com/help/pycharm/lsp-tools.html#ty).
|
||||
For more information, refer to [PyCharm documentation](https://www.jetbrains.com/help/pycharm/2025.3/lsp-tools.html#ty).
|
||||
|
||||
## Other editors
|
||||
|
||||
|
|
@ -120,7 +117,7 @@ ty server
|
|||
|
||||
Refer to your editor's documentation to learn how to connect to an LSP server.
|
||||
|
||||
## Settings
|
||||
## Customize your experience
|
||||
|
||||
See the [editor settings reference](./reference/editor-settings.md) for more details on configuring the language
|
||||
See the [editor settings](./reference/editor-settings.md) for more details on configuring the language
|
||||
server.
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@ ty automatically discovers all Python files in your project. You can customize w
|
|||
|
||||
For example, with the following configuration, ty checks all Python files in the `src` and `tests` directories except those in the `src/generated` directory:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
include = ["src", "tests"]
|
||||
exclude = ["src/generated"]
|
||||
```
|
||||
|
||||
## Default exclusions
|
||||
By default, ty excludes a [variety of commonly ignored directories](./reference/configuration.md#exclude). If you want to include one of these directories, you can do so by adding a negative `exclude`:
|
||||
|
||||
By default, ty excludes a [variety of commonly ignored directories](./reference/configuration.md#exclude_1). If you want to include one of these directories, you can do so by adding a negative `exclude` using a leading `!`:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
# Remove `build` from the excluded directories.
|
||||
exclude = ["!**/build/"]
|
||||
|
|
@ -22,9 +20,7 @@ exclude = ["!**/build/"]
|
|||
|
||||
By default, ty ignores files listed in an `.ignore` or `.gitignore` file. To disable this functionality, set [`respect-ignore-files`](./reference/configuration.md#respect-ignore-files) to `false`.
|
||||
|
||||
## Explicit targets
|
||||
|
||||
You may explicitly pass the paths that ty should check, e.g.:
|
||||
You may also explicitly pass the paths that ty should check, e.g.:
|
||||
|
||||
```shell
|
||||
ty check src scripts/benchmark.py
|
||||
|
|
@ -48,23 +44,8 @@ Both `include` and `exclude` support gitignore like glob patterns:
|
|||
|
||||
All patterns are anchored: The pattern `src` only includes `<project_root>/src` but not something like `<project_root>/test/src`. To include any directory named `src`, use the prefix match `**/src`. The same applies for exclude patterns where `src` only excludes `<project_root>/src` but not something like `<project_root>/test/src`.
|
||||
|
||||
!!! warning
|
||||
!!! note
|
||||
|
||||
A prefix include pattern like `**/src` can notably slow down the Python file discovery.
|
||||
|
||||
All fields accepting patterns use the reduced portable glob syntax from [PEP 639](https://peps.python.org/pep-0639/#add-license-FILES-key), with the addition that characters can be escaped with a backslash.
|
||||
|
||||
## Excluding files from virtual environments
|
||||
|
||||
In Python 3.13+, the `venv` module will add a `.gitignore` file to the virtual environment root and
|
||||
ty will not emit diagnostics for the contained files. However, when using an older version of
|
||||
Python, ty may include diagnostics for files in the virtual environment.
|
||||
|
||||
You can resolve this by adding a `.gitignore` to the environment, e.g., for a virtual environment
|
||||
named `.venv`:
|
||||
|
||||
```shell
|
||||
echo "*" > .venv/.gitignore
|
||||
```
|
||||
|
||||
Or by adding your virtual environment to your `.gitignore` or `.ignore` file.
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
# Diagnostics
|
||||
|
||||
ty provides diagnostics that include snippets of your source code, annotations and helpful
|
||||
explanations. It will sometimes also provide suggestions on how to fix the reported issues.
|
||||
|
||||
## Example: Typed dictionaries
|
||||
|
||||
In this first example, ty detected an invalid assignment to a `TypedDict` key. Notice how the
|
||||
diagnostic includes both the context around the line with the error, as well as the reference to the
|
||||
`age` item in the `TypedDict` definition:
|
||||
|
||||

|
||||

|
||||
|
||||
When a `TypedDict` key is misspelled, ty will suggest the correct spelling. If you are using an
|
||||
editor with language server support, you can also apply this suggestion as a quick fix:
|
||||
|
||||

|
||||

|
||||
|
||||
## Example: Invalid arguments
|
||||
|
||||
Here, a file has been opened for writing in text mode, but we are trying to write bytes to it.
|
||||
The diagnostic points out the type mismatch and also includes the corresponding parameter in the
|
||||
function definition for `write`:
|
||||
|
||||

|
||||

|
||||
|
||||
## Example: Backwards compatibility
|
||||
|
||||
Instead of just telling you that `tomllib` can not be found, ty will tell you *why* it is not
|
||||
available for your project. In this case, your project is targeting Python 3.10, but `tomllib` was
|
||||
only added in Python 3.11:
|
||||
|
||||

|
||||

|
||||
|
|
@ -1,181 +0,0 @@
|
|||
<!-- Note for maintainers: the screenshots referenced in this document were taken using
|
||||
the "Atom One Light" theme in VS Code. -->
|
||||
|
||||
# Language server
|
||||
|
||||
You can generally expect ty to be a fully-featured [language server] for Python.
|
||||
This page describes some of the key features provided by ty's IDE integration and includes
|
||||
a reference table of supported LSP features at the end.
|
||||
See the [editor integration](../editors.md) guide for instructions on how to set up ty
|
||||
with your editor.
|
||||
|
||||
## Diagnostics
|
||||
|
||||
<figure markdown="span">
|
||||

|
||||
<figcaption>Example of an inline diagnostic with code-span annotations</figcaption>
|
||||
</figure>
|
||||
|
||||
ty reports type errors and other [diagnostics](./diagnostics.md) directly in your editor. Diagnostics
|
||||
are updated as you type. You can use the
|
||||
[`diagnosticMode`](../reference/editor-settings.md#diagnosticmode) setting to control if you want to
|
||||
see diagnostics for open files only, or for your entire workspace.
|
||||
|
||||
!!! info
|
||||
|
||||
ty supports both the "pull" and "push" diagnostic models. Most modern editors will use the "pull" model
|
||||
for better performance, where diagnostics are fetched on demand rather than pushed after every
|
||||
change.
|
||||
|
||||
## Code navigation
|
||||
|
||||
<figure markdown="span">
|
||||

|
||||
<figcaption>"Find references" shows usages across the entire workspace</figcaption>
|
||||
</figure>
|
||||
|
||||
ty powers several language server features that allow you to navigate a Python codebase:
|
||||
|
||||
- **Go to Definition**: Jump to where a symbol is defined. ty resolves imports, function calls,
|
||||
class references, and more.
|
||||
- **Go to Declaration**: Navigate to the declaration site of a symbol, which can differ from its
|
||||
definition (could be in a stub file).
|
||||
- **Go to Type Definition**: Navigate to the type of a symbol. For example, this takes you to the class `Person`
|
||||
when invoked on a variable `user: Person`.
|
||||
- **Find all references**: Find every usage of a function, class, or variable across your entire workspace.
|
||||
- **Document and workspace symbols**: See an outline of symbols in the current file, or search through symbols across your entire workspace.
|
||||
|
||||
## Code completions
|
||||
|
||||
<figure markdown="span">
|
||||
{ width="500" }
|
||||
<figcaption>Accepting this completion will automatically add a <code>subprocess</code> import at the top of the file.</figcaption>
|
||||
</figure>
|
||||
|
||||
ty provides intelligent code completions as you type, offering suggestions for variables, functions, classes, and modules that are in scope.
|
||||
For symbols that are not yet imported, ty suggests auto-import actions to add the necessary `import` statements.
|
||||
|
||||
## Code actions and refactorings
|
||||
|
||||
<figure markdown="span">
|
||||
{ width="700" }
|
||||
<figcaption>ty offers to remove the unused suppression comment</figcaption>
|
||||
</figure>
|
||||
|
||||
ty offers quick fixes and other code actions to help you resolve issues:
|
||||
|
||||
- **Add import**: Automatically add missing import statements
|
||||
- **Quick fixes**: Some diagnostics come with quick fix suggestions to resolve the issue
|
||||
- **Rename symbol**: Safely rename symbols across your entire codebase
|
||||
- **Selection range**: Expand or shrink the text selection in your editor based on ty's understanding of Python syntax
|
||||
|
||||
## Contextual information
|
||||
|
||||
<figure markdown="span">
|
||||

|
||||
<figcaption>Gray inlay hints and on-hover information (signature, docstring)</figcaption>
|
||||
</figure>
|
||||
|
||||
ty surfaces useful contextual information as you code:
|
||||
|
||||
- **Hover**: Hover over any symbol to see its type, documentation, function signatures, and other
|
||||
useful information like the variance of type parameters.
|
||||
- **Inlay hints**: Display inline type hints for variables and parameters without explicit
|
||||
annotations, as well as parameter names at call sites. These hints can also be double-clicked
|
||||
to insert the type annotations into your source code. You can also click on parts of the inlay
|
||||
hints for go-to-definition navigation.
|
||||
- **Signature help**: When calling a function, ty displays the function's parameters and their
|
||||
types. This appears automatically when you type `(` and updates as you navigate between arguments.
|
||||
- **Document highlight**: When the cursor is on a symbol, ty highlights all occurrences of that
|
||||
symbol in the current file.
|
||||
- **Semantic highlighting**: Syntax highlighting based on the underlying semantics and types.
|
||||
|
||||
## Notebook support
|
||||
|
||||
ty supports Jupyter notebooks (`.ipynb` files) with language server features. Each cell is
|
||||
analyzed in context, with diagnostics, completions, and other features working across cells.
|
||||
|
||||
## Fine-grained incrementality
|
||||
|
||||
ty's architecture is designed for low-latency updates of diagnostics and other language server features.
|
||||
When you make a change in your editor, ty incrementally updates only the affected parts of the
|
||||
codebase, rather than re-analyzing everything from scratch. This happens at a fine-grained level,
|
||||
down to individual definitions. This incrementality means that you get instant feedback as you type, i.e.,
|
||||
within a few milliseconds, even on large projects.
|
||||
|
||||
!!! info
|
||||
|
||||
Fine-grained dependencies also allow ty to skip large parts of 3rd-party dependencies when they are not relevant
|
||||
to your codebase.
|
||||
|
||||
## Feature reference
|
||||
|
||||
<!-- markdownlint-disable MD060 -->
|
||||
|
||||
| Feature | Status | Notes |
|
||||
| ----------------------------------------------------- | ---------------- | ------------------------------------------------------------- |
|
||||
| [`callHierarchy/*`][callhierarchy] | ❌ Not supported | |
|
||||
| [`notebookDocument/*`][notebookdocument] | ✅ Supported | |
|
||||
| [`textDocument/codeAction`][codeaction] | ✅ Supported | Quick fixes |
|
||||
| [`textDocument/codeLens`][codelens] | ❌ Not supported | |
|
||||
| [`textDocument/completion`][completion] | ✅ Supported | |
|
||||
| [`textDocument/declaration`][declaration] | ✅ Supported | |
|
||||
| [`textDocument/definition`][definition] | ✅ Supported | |
|
||||
| [`textDocument/diagnostic`][diagnostic] | ✅ Supported | |
|
||||
| [`textDocument/documentColor`][documentcolor] | ❌ Not supported | |
|
||||
| [`textDocument/documentHighlight`][documenthighlight] | ✅ Supported | |
|
||||
| [`textDocument/documentLink`][documentlink] | ❌ Not supported | |
|
||||
| [`textDocument/documentSymbol`][documentsymbol] | ✅ Supported | |
|
||||
| [`textDocument/foldingRange`][foldingrange] | ❌ Not supported | |
|
||||
| [`textDocument/formatting`][formatting] | — | Use [Ruff] for formatting |
|
||||
| [`textDocument/hover`][hover] | ✅ Supported | |
|
||||
| [`textDocument/implementation`][implementation] | ❌ Not supported | |
|
||||
| [`textDocument/inlayHint`][inlayhint] | ✅ Supported | |
|
||||
| [`textDocument/onTypeFormatting`][ontypeformatting] | — | [Ruff #16829](https://github.com/astral-sh/ruff/issues/16829) |
|
||||
| [`textDocument/prepareRename`][preparerename] | ✅ Supported | |
|
||||
| [`textDocument/rangeFormatting`][rangeformatting] | — | Use [Ruff] for formatting |
|
||||
| [`textDocument/references`][references] | ✅ Supported | |
|
||||
| [`textDocument/rename`][rename] | ✅ Supported | |
|
||||
| [`textDocument/selectionRange`][selectionrange] | ✅ Supported | |
|
||||
| [`textDocument/semanticTokens`][semantictokens] | ✅ Supported | |
|
||||
| [`textDocument/signatureHelp`][signaturehelp] | ✅ Supported | |
|
||||
| [`textDocument/typeDefinition`][typedefinition] | ✅ Supported | |
|
||||
| [`typeHierarchy/*`][typehierarchy] | ❌ Not supported | [#534] |
|
||||
| [`workspace/diagnostic`][workspacediagnostic] | ✅ Supported | |
|
||||
| [`workspace/symbol`][workspacesymbol] | ✅ Supported | |
|
||||
| [`workspace/willRenameFiles`][willrenamefiles] | ❌ Not supported | [#1560] |
|
||||
|
||||
[#1560]: https://github.com/astral-sh/ty/issues/1560
|
||||
[#534]: https://github.com/astral-sh/ty/issues/534
|
||||
[callhierarchy]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#callHierarchy_incomingCalls
|
||||
[codeaction]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction
|
||||
[codelens]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeLens
|
||||
[completion]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
|
||||
[declaration]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_declaration
|
||||
[definition]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition
|
||||
[diagnostic]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_diagnostic
|
||||
[documentcolor]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentColor
|
||||
[documenthighlight]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentHighlight
|
||||
[documentlink]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentLink
|
||||
[documentsymbol]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol
|
||||
[foldingrange]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_foldingRange
|
||||
[formatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting
|
||||
[hover]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover
|
||||
[implementation]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation
|
||||
[inlayhint]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlayHint
|
||||
[language server]: https://microsoft.github.io/language-server-protocol/
|
||||
[notebookdocument]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_synchronization
|
||||
[ontypeformatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_onTypeFormatting
|
||||
[preparerename]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_prepareRename
|
||||
[rangeformatting]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rangeFormatting
|
||||
[references]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references
|
||||
[rename]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename
|
||||
[ruff]: https://docs.astral.sh/ruff/
|
||||
[selectionrange]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_selectionRange
|
||||
[semantictokens]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens
|
||||
[signaturehelp]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_signatureHelp
|
||||
[typedefinition]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_typeDefinition
|
||||
[typehierarchy]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#typeHierarchy_supertypes
|
||||
[willrenamefiles]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_willRenameFiles
|
||||
[workspacediagnostic]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_diagnostic
|
||||
[workspacesymbol]: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol
|
||||
|
Before Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 309 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 285 KiB |
|
Before Width: | Height: | Size: 283 KiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
|
@ -1,223 +0,0 @@
|
|||
# Type system
|
||||
|
||||
You can generally expect ty to support all typing features that are described and specified in the
|
||||
[Python typing documentation] (for a detailed overview, please refer to the
|
||||
[type system features tracking issue](https://github.com/astral-sh/ty/issues/1889)). This page
|
||||
highlights some of the unique features that ty's type system provides.
|
||||
|
||||
## Redeclarations
|
||||
|
||||
ty allows you to reuse the same symbol with a different type. The following example shows how the
|
||||
`paths` parameter is redeclared as a list of strings:
|
||||
|
||||
```py
|
||||
def split_paths(paths: str) -> list[Path]:
|
||||
paths: list[str] = paths.split(":")
|
||||
return [Path(p) for p in paths]
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/80a74c95-a43e-4a3d-8c26-f88e879d7dcb))
|
||||
|
||||
## Intersection types
|
||||
|
||||
ty has first-class support for intersection types. In contrast to a union type `A | B`, which means
|
||||
"*either* A *or* B", an intersection type `A & B` means "*both* A *and* B". Type narrowing in ty is
|
||||
based on intersections. For example, notice how we can call `obj.serialize_json()` *and* access the
|
||||
`.version` property in the following function:
|
||||
|
||||
```py
|
||||
def output_as_json(obj: Serializable) -> str:
|
||||
if isinstance(obj, Versioned):
|
||||
reveal_type(obj) # reveals: Serializable & Versioned
|
||||
|
||||
return str({
|
||||
"data": obj.serialize_json(),
|
||||
"version": obj.version
|
||||
})
|
||||
else:
|
||||
return obj.serialize_json()
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/39241435-5e78-4ce9-817f-ce65be73a6ed))
|
||||
|
||||
Intersections can also be built using gradual types like `Any` or its implicit counterpart
|
||||
`Unknown`. For example, imagine you call into untyped (third party) code that returns an object of
|
||||
type `Unknown`. Narrowing the type of that object using `isinstance` will result in an intersection
|
||||
type `Unknown & Iterable`. This type allows you to use `obj` as an iterable. But more importantly,
|
||||
it still gives you access to attributes defined on the original unknown type (`.description`, in this
|
||||
example):
|
||||
|
||||
```py
|
||||
def print_content(data: bytes):
|
||||
obj = untyped_library.deserialize(data)
|
||||
|
||||
if isinstance(obj, Iterable):
|
||||
print(obj.description)
|
||||
for part in obj:
|
||||
print("*", part.description)
|
||||
else:
|
||||
print(obj.description)
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/8f98820e-7306-4d69-b572-56d69a92b90f))
|
||||
|
||||
Intersection types are also used in `hasattr` narrowing. Take a look at the following example where
|
||||
we narrow a type of `Person | Animal | None` using `hasattr(…, "name")`. `Person` is preserved in
|
||||
the narrowed union type because it has a `name` attribute. `Animal` is intersected with a synthetic
|
||||
protocol, accounting for the possibility of subclasses of `Animal` that add a `name` member.
|
||||
`None` is excluded completely since it is a final type that has no `name` attribute:
|
||||
|
||||
```py
|
||||
class Person:
|
||||
name: str
|
||||
|
||||
class Animal:
|
||||
species: str
|
||||
|
||||
def greet(being: Person | Animal | None):
|
||||
if hasattr(being, "name"):
|
||||
# `being` is now of type `Person | (Animal & <Protocol with members 'name'>)`
|
||||
|
||||
print(f"Hello, {being.name}!")
|
||||
else:
|
||||
print("Hello there!")
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/31f2c718-516a-4a85-80e0-2a4682b818f1))
|
||||
|
||||
!!! info
|
||||
|
||||
If you run into a situation like this and would like `Animal` to be excluded from the narrowed
|
||||
type as well, you can make `Animal` a `@final` class. This also allows ty to infer a more precise
|
||||
type for `being.name` (`str` instead of `object`).
|
||||
|
||||
If ty is the only type checker you use, you can also make direct use of intersection types in
|
||||
annotations by importing `Intersection` from the special `ty_extensions` module that is (currently)
|
||||
only available at type-checking time:
|
||||
|
||||
```py
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ty_extensions import Intersection
|
||||
|
||||
type SerializableVersioned = Intersection[Serializable, Versioned]
|
||||
|
||||
def output_as_json(obj: SerializableVersioned) -> str:
|
||||
...
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/f003e901-0e45-4f45-9759-d6db9d5e5f66))
|
||||
|
||||
## Top and bottom materializations
|
||||
|
||||
Gradual types generally have two special [materializations]. The top materialization represents the
|
||||
"largest" type that a gradual type can materialize to: the union of all possible materializations.
|
||||
For example, the top materialization of `Any` is `object`, and the top materialization of
|
||||
`Any & int` is `int`. For invariant generic classes, the top materialization cannot be expressed in
|
||||
Python's type system, but it is a useful type that ty intersects with when `isinstance` checks
|
||||
involve generic classes. For example, when checking `isinstance(…, list)`, ty intersects with the
|
||||
top materialization of `list[Unknown]`:
|
||||
|
||||
```py
|
||||
@final
|
||||
class Item: ...
|
||||
|
||||
def process(items: Item | list[Item]):
|
||||
if isinstance(items, list):
|
||||
# reveals: list[Item]
|
||||
reveal_type(items)
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/f1306120-0b8d-4ed5-b832-1f2d379eae2b))
|
||||
|
||||
!!! info
|
||||
|
||||
You might wonder why `Item` is declared `@final` here. If we remove the `@final` decorator, the
|
||||
inferred type in the `if` branch becomes `(Item & Top[list[Unknown]]) | list[Item]` instead.
|
||||
This accounts for the possibility of classes that inherit from both `Item` *and* `list`! If
|
||||
you run into this situation and want to rule out this case, you can also perform the `isinstance`
|
||||
check against `Item` instead. The `else` branch will then have a narrowed type of
|
||||
`list[Item] & ~Item`, which effectively acts like `list[Item]`.
|
||||
|
||||
## Reachability based on types
|
||||
|
||||
Reachability analysis in ty is based on type inference. This allows ty to detect unreachable
|
||||
branches in many more situations compared to approaches which match on a few known patterns (e.g.
|
||||
`sys.version_info >= (3, 10)` checks). This has useful practical applications. Consider a case
|
||||
where you are writing code that needs to be compatible with two major versions of a dependency.
|
||||
The following code can be successfully type-checked with either pydantic 1.x installed, or pydantic
|
||||
2.x installed. In both cases, ty will only consider the corresponding branch to be reachable, and
|
||||
will not emit any type errors for the other branch. This works because
|
||||
`pydantic.__version__.startswith("2.")` can be evaluated to `True` or `False` at type-checking time:
|
||||
|
||||
```py
|
||||
import pydantic
|
||||
from pydantic import BaseModel
|
||||
|
||||
PYDANTIC_V2 = pydantic.__version__.startswith("2.")
|
||||
|
||||
class Person(BaseModel):
|
||||
name: str
|
||||
|
||||
def to_json(person: Person):
|
||||
if PYDANTIC_V2:
|
||||
return person.model_dump_json() # no error here when checking with 1.x
|
||||
else:
|
||||
return person.json()
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/34a227bb-93d5-405e-86c3-72f57ec5642e))
|
||||
|
||||
## Gradual guarantee
|
||||
|
||||
ty generally tries to avoid emitting false positive type errors in untyped code. The following
|
||||
snippet does not produce any type errors when checked with ty (whereas other type checkers make the
|
||||
assumption that `max_retries` is of type `None`, leading to an error in the attribute assignment):
|
||||
|
||||
```py
|
||||
class RetryPolicy:
|
||||
max_retries = None
|
||||
|
||||
policy = RetryPolicy()
|
||||
policy.max_retries = 1
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/a5286db1-cdfd-45e7-af54-29649ba5c423))
|
||||
|
||||
This is achieved by treating `max_retries` as being of type `Unknown | None`, which means that the
|
||||
type of the attribute is not fully known, but `None` is definitely a possible value.
|
||||
|
||||
Users can always opt into stricter checking by adding type annotations (`int | None`, in this case).
|
||||
|
||||
!!! info
|
||||
|
||||
We are also planning to add a mode for users that prefer to have stricter types inferred by default
|
||||
in these situations. You can follow [this issue](https://github.com/astral-sh/ty/issues/1240) for
|
||||
updates.
|
||||
|
||||
## Fixpoint iteration
|
||||
|
||||
In a situation where a symbol's type cyclically depends on itself, ty uses a mechanism called fixpoint iteration to
|
||||
be able to infer a type for that symbol. In the `tick` method below, note how the type of `self.value` depends on
|
||||
`self.value` itself. ty starts by assuming that `self.value` is just `Unknown | Literal[0]` (the type inferred
|
||||
from the `__init__` method), and then iterates until the type converges to `Unknown | Literal[0, 1, 2, 3, 4]`.
|
||||
Without the modulo operation, the union would grow indefinitely. In that case, we fall back to `int` after a certain
|
||||
number of iterations.
|
||||
|
||||
```py
|
||||
class LoopingCounter:
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
|
||||
def tick(self):
|
||||
self.value = (self.value + 1) % 5
|
||||
|
||||
# reveals: Unknown | Literal[0, 1, 2, 3, 4]
|
||||
reveal_type(LoopingCounter().value)
|
||||
```
|
||||
|
||||
(Full example in the [playground](https://play.ty.dev/64400d96-ee1b-48f3-8361-b583dddddf82))
|
||||
|
||||
[materializations]: https://typing.python.org/en/latest/spec/concepts.html#materialization
|
||||
[python typing documentation]: https://typing.python.org/en/latest/spec/index.html
|
||||
|
|
@ -1,58 +1,54 @@
|
|||
# ty
|
||||
|
||||
An extremely fast Python type checker and language server, written in Rust.
|
||||
|
||||
<p align="center">
|
||||
<img alt="Shows a bar chart with benchmark results." width="500px" src="./assets/ty-benchmark-cli.svg#only-light">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="Shows a bar chart with benchmark results." width="500px" src="./assets/ty-benchmark-cli-dark.svg#only-dark">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<i>Type checking the <a href="https://github.com/home-assistant/core">home-assistant</a> project without caching.</i>
|
||||
</p>
|
||||
|
||||
ty is backed by [Astral](https://astral.sh), the creators of
|
||||
[uv](https://github.com/astral-sh/uv) and [Ruff](https://github.com/astral-sh/ruff).
|
||||
An extremely fast Python type checker, written in Rust.
|
||||
|
||||
<!-- TODO
|
||||
## Highlights
|
||||
|
||||
- 10x - 100x faster than mypy and Pyright
|
||||
- Comprehensive [diagnostics](./features/diagnostics.md) with rich contextual information
|
||||
- Configurable [rule levels](./rules.md), [per-file overrides](./reference/configuration.md#overrides), [suppression comments](./suppression.md), and first-class project support
|
||||
- Designed for adoption, with support for [redeclarations](./features/type-system.md#redeclarations) and [partially typed code](./features/type-system.md#gradual-guarantee)
|
||||
- [Language server](./features/language-server.md) with code navigation, completions, code actions, auto-import, inlay hints, on-hover help, etc.
|
||||
- Fine-grained [incremental analysis](./features/language-server.md#fine-grained-incrementality) designed for fast updates when editing files in an IDE
|
||||
- Editor integrations for [VS Code](./editors.md#vs-code), [PyCharm](./editors.md#pycharm), [Neovim](./editors.md#neovim) and more
|
||||
- Advanced typing features like first-class [intersection types](./features/type-system.md#intersection-types), advanced [type narrowing](./features/type-system.md#top-and-bottom-materializations), and
|
||||
[sophisticated reachability analysis](./features/type-system.md#reachability-based-on-types)
|
||||
- ...
|
||||
-->
|
||||
|
||||
## Getting started
|
||||
|
||||
Run ty with [uvx](https://docs.astral.sh/uv/guides/tools/#running-tools) to get started quickly:
|
||||
Try out the [online playground](https://play.ty.dev), or run ty with
|
||||
[uvx](https://docs.astral.sh/uv/guides/tools/#running-tools) to get started quickly:
|
||||
|
||||
```shell
|
||||
uvx ty
|
||||
```
|
||||
|
||||
For other ways to install ty, see the [installation](./installation.md) documentation.
|
||||
|
||||
If you do not provide a subcommand, ty will list available commands — for detailed information about
|
||||
command-line options, see the [CLI reference](./reference/cli.md).
|
||||
|
||||
Use the `check` command to run the type checker:
|
||||
|
||||
```shell
|
||||
uvx ty check
|
||||
```
|
||||
|
||||
ty will check all Python files in the working directory or project by default.
|
||||
ty will run on all Python files in the working directory and or subdirectories. If used from a
|
||||
project, ty will run on all Python files in the project (starting in the directory with the
|
||||
`pyproject.toml`)
|
||||
|
||||
See the [type checking](./type-checking.md) documentation for more details.
|
||||
You can also provide specific paths to check:
|
||||
|
||||
## Installation
|
||||
```shell
|
||||
uvx ty check example.py
|
||||
```
|
||||
|
||||
To install ty, see the [installation](./installation.md) documentation.
|
||||
When type checking, ty will find installed packages in the active virtual environment (via
|
||||
`VIRTUAL_ENV`) or discover a virtual environment named `.venv` in the project root or working
|
||||
directory. It will not find packages in non-virtual environments without specifying the target path
|
||||
with `--python`. See the [module discovery](./modules.md) documentation for
|
||||
details.
|
||||
|
||||
To add the ty language server to your editor, see the [editor integration](./editors.md) guide.
|
||||
### Usage
|
||||
|
||||
## Playground
|
||||
Run [`ty check`](./reference/cli.md#ty-check), in your project's top-level directory,
|
||||
to check the project for type errors using ty's default configuration.
|
||||
|
||||
ty has an [online playground](https://play.ty.dev) you can use to try it out on snippets or small
|
||||
projects.
|
||||
|
||||
!!! tip
|
||||
|
||||
The playground is a great way to share snippets with other people, e.g., when sharing a bug
|
||||
report.
|
||||
If this provokes a cascade of errors, and you are using the standard library `venv` module
|
||||
to provide your virtual environment, add the venv directory to your `.gitignore`
|
||||
or `.ignore` file and then retry.
|
||||
|
|
|
|||
|
|
@ -1,21 +1,6 @@
|
|||
# Installing ty
|
||||
|
||||
## Running ty without installation
|
||||
|
||||
Use [uvx](https://docs.astral.sh/uv/guides/tools/) to quickly get started with ty:
|
||||
|
||||
```shell
|
||||
uvx ty
|
||||
```
|
||||
|
||||
## Installation methods
|
||||
|
||||
### Adding ty to your project
|
||||
|
||||
!!! tip
|
||||
|
||||
Adding ty as a dependency ensures that all developers on the project are using the same version
|
||||
of ty.
|
||||
## Adding ty to your project
|
||||
|
||||
Use [uv](https://github.com/astral-sh/uv) (or your project manager of choice) to add ty as a
|
||||
development dependency:
|
||||
|
|
@ -24,19 +9,16 @@ development dependency:
|
|||
uv add --dev ty
|
||||
```
|
||||
|
||||
Adding ty as a dependency ensures that all developers on the project are using the same version of
|
||||
ty.
|
||||
|
||||
Then, use `uv run` to invoke ty:
|
||||
|
||||
```shell
|
||||
uv run ty
|
||||
```
|
||||
|
||||
To update ty, use `--upgrade-package`:
|
||||
|
||||
```shell
|
||||
uv lock --upgrade-package ty
|
||||
```
|
||||
|
||||
### Installing globally with uv
|
||||
## Installing globally
|
||||
|
||||
Install ty globally with uv:
|
||||
|
||||
|
|
@ -44,158 +26,16 @@ Install ty globally with uv:
|
|||
uv tool install ty@latest
|
||||
```
|
||||
|
||||
To update ty, use `uv tool upgrade`:
|
||||
|
||||
```shell
|
||||
uv tool upgrade ty
|
||||
```
|
||||
|
||||
### Installing with the standalone installer
|
||||
|
||||
ty includes a standalone installer.
|
||||
|
||||
=== "macOS and Linux"
|
||||
|
||||
Use `curl` to download the script and execute it with `sh`:
|
||||
|
||||
```console
|
||||
$ curl -LsSf https://astral.sh/ty/install.sh | sh
|
||||
```
|
||||
|
||||
If your system doesn't have `curl`, you can use `wget`:
|
||||
|
||||
```console
|
||||
$ wget -qO- https://astral.sh/ty/install.sh | sh
|
||||
```
|
||||
|
||||
Request a specific version by including it in the URL:
|
||||
|
||||
```console
|
||||
$ curl -LsSf https://astral.sh/ty/0.0.8/install.sh | sh
|
||||
```
|
||||
|
||||
=== "Windows"
|
||||
|
||||
Use `irm` to download the script and execute it with `iex`:
|
||||
|
||||
```pwsh-session
|
||||
PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/ty/install.ps1 | iex"
|
||||
```
|
||||
|
||||
Changing the [execution policy](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4#powershell-execution-policies) allows running a script from the internet.
|
||||
|
||||
Request a specific version by including it in the URL:
|
||||
|
||||
```pwsh-session
|
||||
PS> powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/ty/0.0.8/install.ps1 | iex"
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
The installation script may be inspected before use:
|
||||
|
||||
=== "macOS and Linux"
|
||||
|
||||
```console
|
||||
$ curl -LsSf https://astral.sh/ty/install.sh | less
|
||||
```
|
||||
|
||||
=== "Windows"
|
||||
|
||||
```pwsh-session
|
||||
PS> powershell -c "irm https://astral.sh/ty/install.ps1 | more"
|
||||
```
|
||||
|
||||
Alternatively, the installer or binaries can be downloaded directly from [GitHub](#installing-from-github-releases).
|
||||
|
||||
### Installing from GitHub Releases
|
||||
|
||||
ty release artifacts can be downloaded directly from
|
||||
[GitHub Releases](https://github.com/astral-sh/ty/releases).
|
||||
|
||||
Each release page includes binaries for all supported platforms as well as instructions for using
|
||||
the standalone installer via `github.com` instead of `astral.sh`.
|
||||
|
||||
### Installing globally with pipx
|
||||
|
||||
Install ty globally with pipx:
|
||||
Or, pipx:
|
||||
|
||||
```shell
|
||||
pipx install ty
|
||||
```
|
||||
|
||||
To update ty, use `pipx upgrade`:
|
||||
|
||||
```shell
|
||||
pipx upgrade ty
|
||||
```
|
||||
|
||||
### Installing with pip
|
||||
## Installing with pip
|
||||
|
||||
Install ty into your current Python environment with pip:
|
||||
|
||||
```shell
|
||||
pip install ty
|
||||
```
|
||||
|
||||
### Installing in Docker
|
||||
|
||||
Install ty in Docker by copying the binary from the official image:
|
||||
|
||||
```dockerfile title="Dockerfile"
|
||||
COPY --from=ghcr.io/astral-sh/ty:latest /ty /bin/
|
||||
```
|
||||
|
||||
The following tags are available:
|
||||
|
||||
- `ghcr.io/astral-sh/ty:latest`
|
||||
- `ghcr.io/astral-sh/ty:{major}.{minor}.{patch}`, e.g., `ghcr.io/astral-sh/ty:0.0.8`
|
||||
- `ghcr.io/astral-sh/ty:{major}.{minor}`, e.g., `ghcr.io/astral-sh/ty:0.0` (the latest patch
|
||||
version)
|
||||
|
||||
## Adding ty to your editor
|
||||
|
||||
See the [editor integration](./editors.md) guide to add ty to your editor.
|
||||
|
||||
## Shell autocompletion
|
||||
|
||||
!!! tip
|
||||
|
||||
You can run `echo $SHELL` to help you determine your shell.
|
||||
|
||||
To enable shell autocompletion for ty commands, run one of the following:
|
||||
|
||||
=== "Bash"
|
||||
|
||||
```bash
|
||||
echo 'eval "$(ty generate-shell-completion bash)"' >> ~/.bashrc
|
||||
```
|
||||
|
||||
=== "Zsh"
|
||||
|
||||
```bash
|
||||
echo 'eval "$(ty generate-shell-completion zsh)"' >> ~/.zshrc
|
||||
```
|
||||
|
||||
=== "fish"
|
||||
|
||||
```bash
|
||||
echo 'ty generate-shell-completion fish | source' > ~/.config/fish/completions/ty.fish
|
||||
```
|
||||
|
||||
=== "Elvish"
|
||||
|
||||
```bash
|
||||
echo 'eval (ty generate-shell-completion elvish | slurp)' >> ~/.elvish/rc.elv
|
||||
```
|
||||
|
||||
=== "PowerShell / pwsh"
|
||||
|
||||
```powershell
|
||||
if (!(Test-Path -Path $PROFILE)) {
|
||||
New-Item -ItemType File -Path $PROFILE -Force
|
||||
}
|
||||
Add-Content -Path $PROFILE -Value '(& ty generate-shell-completion powershell) | Out-String | Invoke-Expression'
|
||||
```
|
||||
|
||||
Then restart the shell or source the shell config file.
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ example-pkg
|
|||
|
||||
then set [`environment.root`](./reference/configuration.md#root) in your `pyproject.toml` to `["./app"]`:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
root = ["./app"]
|
||||
```
|
||||
|
||||
Note that a `./python` folder is automatically added to the project `root` if it exists,
|
||||
and is not itself a package (i.e. does not contain an `__init__.py` file or an
|
||||
Note that `python` and `tests` folders are automatically added to the project `root` if they exist,
|
||||
and if they are not packages themselves (i.e. they do not contain an `__init__.py` file or an
|
||||
`__init__.pyi` file).
|
||||
|
||||
## Third-party modules
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ configured or detected, ty will try to infer the Python version being used from
|
|||
environment's metadata.
|
||||
|
||||
If no virtual environment is present or inferring the Python version from the metadata fails,
|
||||
ty will fall back to the latest stable Python version supported by ty (currently 3.14).
|
||||
ty will fall back to the latest stable Python version supported by ty (currently 3.13).
|
||||
|
||||
The Python version may also be explicitly specified using the
|
||||
[`python-version`](./reference/configuration.md#python-version) setting or the
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ over all configuration files.</p>
|
|||
</dd><dt id="ty-check--exit-zero"><a href="#ty-check--exit-zero"><code>--exit-zero</code></a></dt><dd><p>Always use exit code 0, even when there are error-level diagnostics</p>
|
||||
</dd><dt id="ty-check--extra-search-path"><a href="#ty-check--extra-search-path"><code>--extra-search-path</code></a> <i>path</i></dt><dd><p>Additional path to use as a module-resolution source (can be passed multiple times).</p>
|
||||
<p>This is an advanced option that should usually only be used for first-party or third-party modules that are not installed into your Python environment in a conventional way. Use <code>--python</code> to point ty to your Python environment if it is in an unusual location.</p>
|
||||
</dd><dt id="ty-check--force-exclude"><a href="#ty-check--force-exclude"><code>--force-exclude</code></a></dt><dd><p>Enforce exclusions, even for paths passed to ty directly on the command-line. Use <code>--no-force-exclude</code> to disable</p>
|
||||
</dd><dt id="ty-check--help"><a href="#ty-check--help"><code>--help</code></a>, <code>-h</code></dt><dd><p>Print help (see a summary with '-h')</p>
|
||||
</dd><dt id="ty-check--ignore"><a href="#ty-check--ignore"><code>--ignore</code></a> <i>rule</i></dt><dd><p>Disables the rule. Can be specified multiple times.</p>
|
||||
</dd><dt id="ty-check--no-progress"><a href="#ty-check--no-progress"><code>--no-progress</code></a></dt><dd><p>Hide all progress outputs.</p>
|
||||
|
|
|
|||
|
|
@ -18,61 +18,13 @@ Valid severities are:
|
|||
|
||||
**Type**: `dict[RuleName, "ignore" | "warn" | "error"]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `analysis`
|
||||
|
||||
### `respect-type-ignore-comments`
|
||||
|
||||
Whether ty should respect `type: ignore` comments.
|
||||
|
||||
When set to `false`, `type: ignore` comments are treated like any other normal
|
||||
comment and can't be used to suppress ty errors (you have to use `ty: ignore` instead).
|
||||
|
||||
Setting this option can be useful when using ty alongside other type checkers or when
|
||||
you prefer using `ty: ignore` over `type: ignore`.
|
||||
|
||||
Defaults to `true`.
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.analysis]
|
||||
# Disable support for `type: ignore` comments
|
||||
respect-type-ignore-comments = false
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[analysis]
|
||||
# Disable support for `type: ignore` comments
|
||||
respect-type-ignore-comments = false
|
||||
```
|
||||
```toml
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -93,21 +45,12 @@ configuration setting.
|
|||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -133,21 +76,12 @@ This option can be used to point to virtual or system Python environments.
|
|||
|
||||
**Type**: `str`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -169,23 +103,13 @@ If no platform is specified, ty will use the current platform:
|
|||
|
||||
**Type**: `"win32" | "darwin" | "android" | "ios" | "linux" | "all" | str`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
# Tailor type stubs and conditionalized type definitions to windows.
|
||||
python-platform = "win32"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
# Tailor type stubs and conditionalized type definitions to windows.
|
||||
python-platform = "win32"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
# Tailor type stubs and conditionalized type definitions to windows.
|
||||
python-platform = "win32"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -213,21 +137,12 @@ to reflect the differing contents of the standard library across Python versions
|
|||
|
||||
**Type**: `"3.7" | "3.8" | "3.9" | "3.10" | "3.11" | "3.12" | "3.13" | "3.14" | <major>.<minor>`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -243,30 +158,20 @@ If left unspecified, ty will try to detect common project layouts and initialize
|
|||
* if a `./<project-name>/<project-name>` directory exists, include `.` and `./<project-name>` in the first party search path
|
||||
* otherwise, default to `.` (flat layout)
|
||||
|
||||
Additionally, if a `./python` directory exists and is not a package (i.e. it does not contain an `__init__.py` or `__init__.pyi` file),
|
||||
Besides, if a `./python` or `./tests` directory exists and is not a package (i.e. it does not contain an `__init__.py` or `__init__.pyi` file),
|
||||
it will also be included in the first party search path.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
# Multiple directories (priority order)
|
||||
root = ["./src", "./lib", "./vendor"]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
# Multiple directories (priority order)
|
||||
root = ["./src", "./lib", "./vendor"]
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
# Multiple directories (priority order)
|
||||
root = ["./src", "./lib", "./vendor"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -280,21 +185,12 @@ bundled as a zip file in the binary
|
|||
|
||||
**Type**: `str`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -304,22 +200,24 @@ Configuration override that applies to specific files based on glob patterns.
|
|||
|
||||
An override allows you to apply different rule configurations to specific
|
||||
files or directories. Multiple overrides can match the same file, with
|
||||
later overrides take precedence. Override rules take precedence over global
|
||||
rules for matching files.
|
||||
later overrides take precedence.
|
||||
|
||||
For example, to relax enforcement of rules in test files:
|
||||
### Precedence
|
||||
|
||||
- Later overrides in the array take precedence over earlier ones
|
||||
- Override rules take precedence over global rules for matching files
|
||||
|
||||
### Examples
|
||||
|
||||
```toml
|
||||
# Relax rules for test files
|
||||
[[tool.ty.overrides]]
|
||||
include = ["tests/**", "**/test_*.py"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
```
|
||||
|
||||
Or, to ignore a rule in generated files but retain enforcement in an important file:
|
||||
|
||||
```toml
|
||||
# Ignore generated files but still check important ones
|
||||
[[tool.ty.overrides]]
|
||||
include = ["generated/**"]
|
||||
exclude = ["generated/important.py"]
|
||||
|
|
@ -342,31 +240,17 @@ If not specified, defaults to `[]` (excludes no files).
|
|||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[[overrides]]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -384,27 +268,15 @@ If not specified, defaults to `["**"]` (matches all files).
|
|||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[[overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -420,27 +292,15 @@ severity levels or disable them entirely.
|
|||
|
||||
**Type**: `dict[RuleName, "ignore" | "warn" | "error"]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
include = ["src"]
|
||||
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
include = ["src"]
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
possibly-unresolved-reference = "ignore"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[[overrides]]
|
||||
include = ["src"]
|
||||
|
||||
[overrides.rules]
|
||||
possibly-unresolved-reference = "ignore"
|
||||
```
|
||||
[tool.ty.overrides.rules]
|
||||
possibly-unresolved-reference = "ignore"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -498,31 +358,17 @@ to re-include `dist` use `exclude = ["!dist"]`
|
|||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -553,27 +399,15 @@ matches `<project_root>/src` and not `<project_root>/test/src`).
|
|||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -587,28 +421,19 @@ Enabled by default.
|
|||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `root`
|
||||
|
||||
!!! warning "Deprecated"
|
||||
This option has been deprecated. Use `environment.root` instead.
|
||||
> [!WARN] "Deprecated"
|
||||
> This option has been deprecated. Use `environment.root` instead.
|
||||
|
||||
The root of the project, used for finding first-party modules.
|
||||
|
||||
|
|
@ -618,28 +443,19 @@ If left unspecified, ty will try to detect common project layouts and initialize
|
|||
* if a `./<project-name>/<project-name>` directory exists, include `.` and `./<project-name>` in the first party search path
|
||||
* otherwise, default to `.` (flat layout)
|
||||
|
||||
Additionally, if a `./python` directory exists and is not a package (i.e. it does not contain an `__init__.py` file),
|
||||
Besides, if a `./tests` directory exists and is not a package (i.e. it does not contain an `__init__.py` file),
|
||||
it will also be included in the first party search path.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
**Type**: `str`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
root = "./app"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
root = "./app"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
root = "./app"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -655,23 +471,13 @@ Defaults to `false`.
|
|||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.terminal]
|
||||
# Error if ty emits any warning-level diagnostics.
|
||||
error-on-warning = true
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[terminal]
|
||||
# Error if ty emits any warning-level diagnostics.
|
||||
error-on-warning = true
|
||||
```
|
||||
```toml
|
||||
[tool.ty.terminal]
|
||||
# Error if ty emits any warning-level diagnostics.
|
||||
error-on-warning = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -685,21 +491,12 @@ Defaults to `full`.
|
|||
|
||||
**Type**: `full | concise`
|
||||
|
||||
**Example usage**:
|
||||
**Example usage** (`pyproject.toml`):
|
||||
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
```toml
|
||||
[tool.ty.terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -3,138 +3,6 @@
|
|||
The editor settings supported by ty's language server, as well as the settings specific to [ty's VS
|
||||
Code extension][ty-vscode].
|
||||
|
||||
## `configuration`
|
||||
|
||||
In-editor configuration of ty's settings. The inline settings always take precedence over the settings from configuration files,
|
||||
including the configuration specified with [`configurationFile`](#configurationfile).
|
||||
|
||||
Consult [the configuration reference](../configuration.md) for a list of all supported configuration options.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
**Type**: `object`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
=== "VS Code"
|
||||
|
||||
```json
|
||||
{
|
||||
"ty.configuration": {
|
||||
"rules": {
|
||||
"unresolved-reference": "warn"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
=== "Neovim"
|
||||
|
||||
```lua
|
||||
require('lspconfig').ty.setup({
|
||||
settings = {
|
||||
ty = {
|
||||
configuration = {
|
||||
rules = {
|
||||
["unresolved-reference"] = "warn"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- For Neovim 0.11.0 and later:
|
||||
vim.lsp.config('ty', {
|
||||
settings = {
|
||||
ty = {
|
||||
configuration = {
|
||||
rules = {
|
||||
["unresolved-reference"] = "warn"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
=== "Zed"
|
||||
|
||||
```json
|
||||
{
|
||||
"lsp": {
|
||||
"ty": {
|
||||
"settings": {
|
||||
"configuration": {
|
||||
"rules": {
|
||||
"unresolved-reference": "warn"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `configurationFile`
|
||||
|
||||
The path to a `ty.toml` configuration file. ty will use the specified configuration over any automatically discovered configuration.
|
||||
ty will expand a tilde `~` at the start of a string to the user's home directory, as well as variables like `$A` or `${A}`.
|
||||
|
||||
!!! info
|
||||
|
||||
While ty configuration can be included in a `pyproject.toml` file, it is not allowed in this context.
|
||||
|
||||
**Default value**: `null`
|
||||
|
||||
**Type**: `string`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
=== "VS Code"
|
||||
|
||||
```json
|
||||
{
|
||||
"ty.configurationFile": "./.config/ty.toml"
|
||||
}
|
||||
```
|
||||
|
||||
=== "Neovim"
|
||||
|
||||
```lua
|
||||
require('lspconfig').ty.setup({
|
||||
settings = {
|
||||
ty = {
|
||||
configurationFile = "./.config/ty.toml"
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- For Neovim 0.11.0 and later:
|
||||
vim.lsp.config('ty', {
|
||||
settings = {
|
||||
ty = {
|
||||
configurationFile = "./.config/ty.toml"
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
=== "Zed"
|
||||
|
||||
```json
|
||||
{
|
||||
"lsp": {
|
||||
"ty": {
|
||||
"settings": {
|
||||
"configurationFile": "./.config/ty.toml"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## `disableLanguageServices`
|
||||
|
||||
Whether to disable the language services for the ty language server like code completion, hover,
|
||||
|
|
@ -194,20 +62,42 @@ server for features like code completion, hover, go to definition, etc.
|
|||
|
||||
______________________________________________________________________
|
||||
|
||||
## `python.ty.disableLanguageServices`
|
||||
|
||||
!!! warning "Deprecated"
|
||||
|
||||
This option has been deprecated. Use [`ty.disableLanguageServices`](#disablelanguageservices) instead.
|
||||
|
||||
Whether to disable the language services that ty provides like code completion, hover, go to
|
||||
definition, etc.
|
||||
|
||||
This is useful if you want to use ty exclusively for type checking in combination with another
|
||||
language server for features like code completion, hover, go to definition, etc.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `boolean`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```json
|
||||
{
|
||||
"python.ty.disableLanguageServices": true
|
||||
}
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## `diagnosticMode`
|
||||
|
||||
Determines the scope of the diagnostics reported by the language server.
|
||||
|
||||
Setting this to `off` is useful if you want to use ty exclusively for the language server features
|
||||
like code completion, hover, go to definition, etc.
|
||||
|
||||
- `off`: Diagnostics are disabled.
|
||||
- `openFilesOnly`: Diagnostics are reported only for files that are currently open in the editor.
|
||||
- `workspace`: Diagnostics are reported for all files in the workspace.
|
||||
|
||||
**Default value**: `"openFilesOnly"`
|
||||
|
||||
**Type**: `"off" | "workspace" | "openFilesOnly"`
|
||||
**Type**: `"workspace" | "openFilesOnly"`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
|
|
@ -256,64 +146,6 @@ like code completion, hover, go to definition, etc.
|
|||
|
||||
______________________________________________________________________
|
||||
|
||||
## `showSyntaxErrors`
|
||||
|
||||
Whether to show syntax error diagnostics.
|
||||
|
||||
This is useful when using ty with other language servers, allowing the user to refer to syntax errors
|
||||
from only one source.
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
=== "VS Code"
|
||||
|
||||
```json
|
||||
{
|
||||
"ty.showSyntaxErrors": false
|
||||
}
|
||||
```
|
||||
|
||||
=== "Neovim"
|
||||
|
||||
```lua
|
||||
require('lspconfig').ty.setup({
|
||||
settings = {
|
||||
ty = {
|
||||
showSyntaxErrors = false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- For Neovim 0.11.0 and later:
|
||||
vim.lsp.config('ty', {
|
||||
settings = {
|
||||
ty = {
|
||||
showSyntaxErrors = false,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
=== "Zed"
|
||||
|
||||
```json
|
||||
{
|
||||
"lsp": {
|
||||
"ty": {
|
||||
"settings": {
|
||||
"showSyntaxErrors": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
______________________________________________________________________
|
||||
|
||||
## `inlayHints`
|
||||
|
||||
These settings control the inline hints that ty provides in an editor.
|
||||
|
|
|
|||
|
|
@ -2,15 +2,6 @@
|
|||
|
||||
ty defines and respects the following environment variables:
|
||||
|
||||
### `TY_CONFIG_FILE`
|
||||
|
||||
Path to a `ty.toml` configuration file to use.
|
||||
|
||||
When set, ty will use this file for configuration instead of
|
||||
discovering configuration files automatically.
|
||||
|
||||
Equivalent to the `--config-file` command-line argument.
|
||||
|
||||
### `TY_LOG`
|
||||
|
||||
If set, ty will use this value as the log level for its `--verbose` output.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,465 @@
|
|||
# Type system features
|
||||
|
||||
This issue summarizes the support for various type system features in ty. Sections are organized to follow the structure of the [Python typing specification](https://typing.python.org/en/latest/spec/), with some additional sections at the end. If a top-level item is marked completed without any sub-items, you can generally expect that feature to be fully implemented (and we value any bug reports in case you find issues). If a top-level item is marked completed with open sub-items, the feature is generally working, but there might be some open issues — including but not limited to the ones listed (in this case, we also value any bug reports, but please search the issue tracker before doing so). If a top-level item is not checked, the feature is not implemented yet (it's probably not helpful to report bugs, but feel free to upvote the tracking issue or comment if you have useful information).
|
||||
|
||||
## Special types and type qualifiers
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/special-types.html)
|
||||
|
||||
**tests:** [`any.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/any.md), [`never.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/never.md), [`int_float_complex.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/int_float_complex.md), [`final.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/type_qualifiers/final.md), [`classvar.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/type_qualifiers/classvar.md), [`annotated.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/annotated.md), [`union.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/union.md), [`instance_layout_conflict.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/instance_layout_conflict.md)
|
||||
|
||||
- [x] `Any`
|
||||
- [x] `None`
|
||||
- [x] `NoReturn`, `Never`
|
||||
- [x] `object`
|
||||
- [x] `Literal[...]` (strings, ints, bools, enum, None)
|
||||
- [x] `LiteralString`
|
||||
- [x] `type[C]`
|
||||
- [x] `float`/`complex` special cases (`float` means `int | float`)
|
||||
- [x] `Final`, `Final[T]`
|
||||
- [ ] Diagnostic: subclass overrides `Final` attribute #871
|
||||
- [ ] Diagnostic: `Final` without binding #872
|
||||
- [x] `@final` decorator
|
||||
- [x] `@disjoint_base` decorator
|
||||
- [x] `ClassVar`, `ClassVar[T]`
|
||||
- [ ] Diagnostic: `ClassVar` with type variable #518
|
||||
- [x] `InitVar[T]` (see Dataclasses)
|
||||
- [x] `Annotated[T, ...]`
|
||||
- [x] `Required[T]`, `NotRequired[T]` (see TypedDict)
|
||||
- [x] `ReadOnly[T]` (see TypedDict)
|
||||
- [x] `Union[X, Y]`, `X | Y`
|
||||
- [x] `Optional[X]`
|
||||
- [ ] `type()` functional syntax #740
|
||||
|
||||
## Generics
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/generics.html)
|
||||
|
||||
**tests:** [`pep695/`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/generics/pep695/), [`legacy/`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/generics/legacy/), [`self.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/self.md), [`scoping.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/generics/scoping.md)
|
||||
|
||||
- [x] `TypeVar` (legacy syntax)
|
||||
- [x] `TypeVar` (PEP 695 syntax: `def f[T]()`)
|
||||
- [x] `TypeVar` upper bound (`bound=`)
|
||||
- [x] `TypeVar` constraints
|
||||
- [x] `TypeVar` defaults (PEP 696)
|
||||
- [x] `TypeVar` variance (`covariant`, `contravariant`)
|
||||
- [x] `TypeVar` variance inference (`infer_variance`)
|
||||
- [x] Generic classes (legacy and PEP 695 syntax)
|
||||
- [x] Generic functions (legacy and PEP 695 syntax)
|
||||
- [x] Generic type aliases (PEP 695)
|
||||
- [ ] Some limitations #1851
|
||||
- [x] `ParamSpec` (legacy and PEP 695 syntax)
|
||||
- [ ] `ParamSpec` usage validation #1861
|
||||
- [x] `ParamSpec.args`, `ParamSpec.kwargs`
|
||||
- [x] `ParamSpec` defaults
|
||||
- [x] `Self`
|
||||
- [ ] `Self` in attribute annotations #1124
|
||||
- [ ] Solve type variables in all cases #623
|
||||
- [x] Generic classes
|
||||
- [x] Unions
|
||||
- [ ] `Callable`s
|
||||
- [ ] Generic protocols #1714
|
||||
- [ ] Generic bounds/constraints on type variables #1839
|
||||
- [ ] Support `TypeVarTuple` #156
|
||||
|
||||
## Protocols
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/protocol.html)
|
||||
|
||||
**tests:** [`protocols.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/protocols.md)
|
||||
|
||||
- [x] `Protocol` class definition
|
||||
- [x] Generic protocols (legacy and PEP 695 syntax)
|
||||
- [x] Structural subtyping / assignability
|
||||
- [x] Protocol inheritance
|
||||
- [x] `is_protocol()`, `get_protocol_members()`
|
||||
- [x] `@runtime_checkable` decorator
|
||||
- [x] Protocol instantiation restriction
|
||||
- [x] Non-protocol class inheritance restriction
|
||||
- [x] `@property` members
|
||||
- [ ] Partial support #1379
|
||||
- [ ] Modules as protocol implementations #931
|
||||
- [ ] `@classmethod` and `@staticmethod` members #1381
|
||||
- [ ] `ClassVar` members #1380
|
||||
- [ ] `type[SomeProtocol]` #903
|
||||
- [ ] `issubclass()` on protocols with non-methods #1878
|
||||
|
||||
## Type narrowing
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/narrowing.html)
|
||||
|
||||
**tests:** [`narrow/`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/narrow/), [`type_guards.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/narrow/type_guards.md)
|
||||
|
||||
- [x] `isinstance()` / `issubclass()` narrowing
|
||||
- [x] `is None` / `is not None` narrowing
|
||||
- [x] `is` / `is not` identity narrowing
|
||||
- [x] Truthiness narrowing
|
||||
- [x] `assert` narrowing
|
||||
- [x] `match` statement narrowing
|
||||
- [x] `hasattr()` narrowing
|
||||
- [x] `callable()` narrowing
|
||||
- [x] Assignment narrowing
|
||||
- [x] `TypeIs[…]` user-defined type guards
|
||||
- [ ] `TypeGuard[…]` user-defined type guards #117
|
||||
- [ ] `TypeIs`/`TypeGuard` as method #1569
|
||||
- [ ] Tuple length checks #560
|
||||
- [ ] Tuple match case narrowing #561
|
||||
|
||||
## Tuples
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/tuples.html)
|
||||
|
||||
**tests:** [`subscript/tuple.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/subscript/tuple.md), [`comparison/tuples.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/comparison/tuples.md), [`binary/tuples.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/binary/tuples.md)
|
||||
|
||||
- [x] `tuple[X, Y, Z]` heterogeneous tuples
|
||||
- [x] `tuple[X, ...]` homogeneous tuples
|
||||
- [x] `tuple[()]` empty tuple
|
||||
- [x] Mixed tuples (`tuple[X, *tuple[Y, ...]]`)
|
||||
- [x] Indexing with literal integers
|
||||
- [x] Diagnostic: index out of bounds
|
||||
- [x] Slicing tuples
|
||||
- [x] Tuple subclasses
|
||||
- [x] `typing.Tuple` (deprecated alias)
|
||||
- [x] Covariant element types
|
||||
- [x] Tuple inheritance
|
||||
- [x] Unpacking in assignments
|
||||
- [x] `*args` unpacking in calls
|
||||
- [ ] Diagnostic: invalid comparisons for non-fixed-length tuples #1741
|
||||
- [ ] `TypeVarTuple` / `Unpack` #156
|
||||
|
||||
## `NamedTuple`
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/namedtuples.html)
|
||||
|
||||
**tests:** [`named_tuple.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/named_tuple.md)
|
||||
|
||||
- [x] Class syntax (`class Foo(NamedTuple): ...`)
|
||||
- [x] Field access by name and index, slicing, unpacking
|
||||
- [x] Default values, diagnostic for non-default after default
|
||||
- [x] Read-only fields (assignment rejected)
|
||||
- [x] Inheritance, generic `NamedTuple`s
|
||||
- [x] Multiple inheritance restriction
|
||||
- [x] Underscore field name restriction
|
||||
- [x] Prohibited attribute override check (`_asdict`, `_make`, …)
|
||||
- [x] `_fields`, `_field_defaults`, `_make`, `_asdict`, `_replace`
|
||||
- [x] Subtype of `tuple[...]`
|
||||
- [x] `super()` restriction in `NamedTuple` methods
|
||||
- [x] `NamedTuple` in type expressions
|
||||
- [x] `type[NamedTuple]` in type expressions
|
||||
- [ ] Not fully supported
|
||||
- [ ] Functional syntax (`NamedTuple("Foo", [...])`) #1049
|
||||
- [ ] `collections.namedtuple`: not tested
|
||||
- [ ] Subclass field conflicting with base class field: not tested
|
||||
|
||||
## `TypedDict`
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/typeddict.html)
|
||||
|
||||
**tests:** [`typed_dict.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/typed_dict.md)
|
||||
|
||||
- [x] Class syntax (`class Foo(TypedDict): ...`)
|
||||
- [x] Key access by literal string, `Final` constants
|
||||
- [x] Constructor validation (missing keys, invalid types)
|
||||
- [x] `total` parameter
|
||||
- [x] `Required[…]`, `NotRequired[…]`
|
||||
- [x] `ReadOnly[…]`
|
||||
- [x] Inheritance, generic `TypedDict`s
|
||||
- [x] Recursive `TypedDict`
|
||||
- [x] Structural assignability and equivalence
|
||||
- [x] Methods (`get`, `pop`, `setdefault`, `keys`, `values`, `copy`)
|
||||
- [x] `__total__`, `__required_keys__`, `__optional_keys__`
|
||||
- [ ] Functional syntax (`TypedDict("Foo", {...})`) #154
|
||||
- [ ] `closed`, `extra_items` (PEP 728) #154
|
||||
- [ ] `Unpack` for `**kwargs` typing #1746
|
||||
- [ ] Tagged union narrowing #1479
|
||||
- [ ] Diagnostic: Invalid `isinstance()` check on `TypedDict`: not tested
|
||||
|
||||
## Enums
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/enums.html)
|
||||
|
||||
**tests:** [`enums.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/enums.md), [`comparison/enums.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/comparison/enums.md)
|
||||
|
||||
- [x] `Enum`, `IntEnum`, `StrEnum`
|
||||
- [x] `Literal[EnumMember]` types
|
||||
- [x] `.name`, `.value` inference
|
||||
- [x] `auto()` value inference
|
||||
- [x] `member()`, `nonmember()`
|
||||
- [x] Enum aliases
|
||||
- [x] `_ignore_` attribute
|
||||
- [ ] List form not fully supported
|
||||
- [x] Implicitly final (subclassing restriction)
|
||||
- [x] Exhaustiveness checking (`if`/`match`)
|
||||
- [x] Custom `__eq__`/`__ne__` methods
|
||||
- [x] Iteration over enum members
|
||||
- [ ] `list(Enum)` returns `list[Unknown]`
|
||||
- [ ] Functional syntax (`Enum("Name", [...])`) #876
|
||||
- [ ] `enum.Flag` expansion handling #876
|
||||
- [ ] Custom `__new__` or `__init__` methods #876
|
||||
- [ ] `_generate_next_value_` support #876
|
||||
- [ ] Value-based member retrieval (`Color("red")`) #876
|
||||
- [ ] Narrowing with custom `__eq__` in `match` #1454
|
||||
|
||||
## Literals
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/literal.html)
|
||||
|
||||
**tests:** [`literal.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/literal.md), [`literal_string.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/literal_string.md)
|
||||
|
||||
- [x] `Literal[0]` (integer literals)
|
||||
- [x] `Literal["a"]` (string literals)
|
||||
- [x] `Literal[b"a"]` (bytes literals)
|
||||
- [x] `Literal[True]` (boolean literals)
|
||||
- [x] `Literal[Color.RED]` (enum literals)
|
||||
- [x] `Literal[None]`
|
||||
- [x] Nested `Literal` flattening
|
||||
- [x] Union of literals simplification
|
||||
- [x] `Literal` with type aliases
|
||||
- [x] Invalid form diagnostics
|
||||
- [x] `LiteralString`
|
||||
- [x] `LiteralString` assignability
|
||||
- [x] `LiteralString` narrowing
|
||||
- [x] `LiteralString` cannot be parameterized
|
||||
- [x] `LiteralString` cannot be subclassed
|
||||
|
||||
## Callables
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/callables.html)
|
||||
|
||||
**tests:** [`callable.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/annotations/callable.md), [`callable_instance.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/call/callable_instance.md)
|
||||
|
||||
- [x] `Callable[[X, Y], R]` syntax
|
||||
- [x] `Callable[..., R]` gradual form
|
||||
- [x] `Callable` with `ParamSpec`
|
||||
- [x] Callback protocols (`__call__` method)
|
||||
- [x] Callable assignability (contra/covariance)
|
||||
- [x] Nested `Callable` types
|
||||
- [x] `Callable` in unions/intersections
|
||||
- [x] Invalid form diagnostics
|
||||
- [ ] `Concatenate` #1535
|
||||
- [ ] `Unpack` for `**kwargs` typing #1746
|
||||
|
||||
## Overloads
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/overload.html)
|
||||
|
||||
**tests:** [`overloads.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/overloads.md), [`call/overloads.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/call/overloads.md)
|
||||
|
||||
- [x] `@overload` decorator
|
||||
- [x] Overload resolution
|
||||
- [x] Generic overloads
|
||||
- [x] Methods, constructors, `@staticmethod`, `@classmethod`
|
||||
- [x] Version-specific overloads
|
||||
- [x] Diagnostic: at least two overloads required
|
||||
- [x] Diagnostic: missing implementation (non-stub)
|
||||
- [x] Diagnostic: inconsistent decorators
|
||||
- [x] Diagnostic: `@final`/`@override` placement
|
||||
- [ ] Variadic parameters with generics #1825
|
||||
- [ ] Unannotated implementation validation: not tested #1232
|
||||
- [ ] Diagnostic: overlapping overloads #103
|
||||
- [ ] Implementation consistency check #109
|
||||
- [ ] `@overload` with other decorators #1675
|
||||
|
||||
## Dataclasses
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/dataclasses.html)
|
||||
|
||||
**tests:** [`dataclasses.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclasses.md), [`fields.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/dataclasses/fields.md)
|
||||
|
||||
- [x] `@dataclass` decorator (`init`, `repr`, `eq`, `order`, `frozen`, `match_args`, `kw_only`, `slots`, `weakref_slot`, `unsafe_hash`)
|
||||
- [x] `field()` (`default`, `default_factory`, `init`, `kw_only`, `doc`, `repr`, `hash`, `compare`)
|
||||
- [x] `InitVar[…]`, `ClassVar[…]` exclusion, `KW_ONLY` sentinel
|
||||
- [x] `fields()`, `__dataclass_fields__`
|
||||
- [x] `Final` fields
|
||||
- [x] Inheritance, generic dataclasses, descriptor-typed fields
|
||||
- [x] `replace()`, `__replace__`
|
||||
- [ ] `replace()` returns `Unknown`
|
||||
- [x] `asdict()`
|
||||
- [ ] Incorrectly accepts class objects
|
||||
- [x] Diagnostic: frozen/non-frozen dataclass inheritance
|
||||
- [ ] Diagnostic: non-default field after default field #111
|
||||
- [ ] Diagnostic: `order=True` with custom comparison methods #111
|
||||
- [ ] Diagnostic: `frozen=True` with `__setattr__`/`__delattr__` #111
|
||||
- [ ] `__post_init__` signature validation #111
|
||||
- [ ] Diagnostic: unsound subclassing of `order=True` dataclasses #1681
|
||||
- [ ] `astuple()`: not tested
|
||||
- [ ] `make_dataclass()`, `is_dataclass()`: not tested
|
||||
|
||||
## `dataclass_transform`
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/dataclasses.html#dataclass-transform)
|
||||
|
||||
**tests:** [`dataclass_transform.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/dataclasses/dataclass_transform.md)
|
||||
|
||||
- [x] Function-based transformers (decorator functions)
|
||||
- [x] Metaclass-based transformers
|
||||
- [x] Base-class-based transformers (`__init_subclass__`)
|
||||
- [x] `eq_default` parameter
|
||||
- [x] `order_default` parameter
|
||||
- [x] `kw_only_default` parameter
|
||||
- [x] `frozen_default` parameter
|
||||
- [ ] Metaclass override not working
|
||||
- [x] `field_specifiers` (`init`, `default`, `default_factory`, `factory`, `kw_only`, `alias`)
|
||||
- [ ] `converter` parameter #1327
|
||||
- [x] Other dataclass parameters (`slots`, etc.)
|
||||
- [x] Overloaded dataclass-like decorators
|
||||
- [x] Nested dataclass-transformers
|
||||
- [x] Combining with `@dataclass` (Home Assistant pattern)
|
||||
|
||||
## Constructors
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/constructors.html)
|
||||
|
||||
**tests:** [`constructor.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/call/constructor.md)
|
||||
|
||||
- [x] `__init__` signature inference
|
||||
- [x] `__new__` signature inference
|
||||
- [x] Constructor inheritance from superclass
|
||||
- [x] Both `__new__` and `__init__` present
|
||||
- [x] Descriptor-based `__new__`/`__init__`
|
||||
- [x] Generic class constructor inference
|
||||
- [x] Type variable solving from constructor params
|
||||
- [ ] Custom `__new__` return type #281
|
||||
- [ ] Custom metaclass `__call__`
|
||||
- [ ] `__new__`/`__init__` consistency validation
|
||||
- [ ] Diagnostic: explicit `__init__` on instance #1016
|
||||
|
||||
## Type aliases
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/aliases.html)
|
||||
|
||||
**tests:** [`pep695_type_aliases.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/pep695_type_aliases.md), [`pep613_type_aliases.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/pep613_type_aliases.md), [`implicit_type_aliases.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/implicit_type_aliases.md)
|
||||
|
||||
- [x] Implicit type aliases (`Alias = int`)
|
||||
- [x] PEP 613 `TypeAlias` annotation
|
||||
- [ ] Fully stringified RHS not supported
|
||||
- [x] PEP 695 `type` statement
|
||||
- [x] Generic type aliases (PEP 695)
|
||||
- [ ] Limitations #1851
|
||||
- [x] Generic implicit/PEP 613 aliases
|
||||
- [ ] Partial support #1739
|
||||
- [x] `TypeAliasType` introspection (`__name__`, `__value__`)
|
||||
- [ ] Self-referential generic aliases #1738
|
||||
|
||||
## Type checker directives
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/directives.html)
|
||||
|
||||
**tests:** [`directives/`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/directives/)
|
||||
|
||||
- [x] `cast(T, value)`
|
||||
- [x] Redundant `cast` diagnostic
|
||||
- [x] `assert_type(value, T)`
|
||||
- [x] `assert_never(value)`
|
||||
- [x] `reveal_type(value)`
|
||||
- [x] `TYPE_CHECKING` constant
|
||||
- [x] `@no_type_check` decorator
|
||||
- [x] `type: ignore` comments
|
||||
- [x] `ty: ignore` comments
|
||||
- [x] `@deprecated` decorator
|
||||
- [x] `@override` decorator
|
||||
- [ ] Diagnostic: override without `@override` decorator #155
|
||||
|
||||
## Module resolution, imports, packages
|
||||
|
||||
[Official documentation](https://typing.python.org/en/latest/spec/distributing.html)
|
||||
|
||||
**tests:** [`import/`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/import/)
|
||||
|
||||
- [x] Stub files (`.pyi`)
|
||||
- [x] Stub packages (`<package>-stubs`)
|
||||
- [x] Partial stub packages (`py.typed` with `partial`)
|
||||
- [x] Namespace packages (PEP 420)
|
||||
- [x] Relative imports
|
||||
- [x] `__all__` declarations
|
||||
- [x] `__all__` mutations (`.append`, `.extend`, `+=`)
|
||||
- [x] `__all__` with submodule `__all__`
|
||||
- [x] Wildcard (`*`) imports
|
||||
- [x] Wildcard imports in stubs re-export
|
||||
- [x] Re-export conventions (`import X as X`)
|
||||
- [x] Conditional re-exports in stub files
|
||||
- [x] Reachability constraints in imports
|
||||
- [x] Cyclic imports
|
||||
- [x] `py.typed` marker files
|
||||
- [x] `conftest.py` resolution (pytest)
|
||||
- [x] conda/pixi environment support
|
||||
- [ ] PEP 723 inline script metadata #691
|
||||
- [ ] Custom builtins (`__builtins__.pyi`) #374
|
||||
- [ ] Mono-repository support #819
|
||||
- [ ] Compiled extensions (`.so` files) #487
|
||||
- [ ] Per-library import suppression #1354
|
||||
|
||||
## Control flow analysis
|
||||
|
||||
**tests:** [`terminal_statements.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/terminal_statements.md), [`exhaustiveness_checking.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/exhaustiveness_checking.md), [`unreachable.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/unreachable.md), [`exception/control_flow.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/exception/control_flow.md)
|
||||
|
||||
- [x] Terminal statements (`return`, `raise`)
|
||||
- [x] Loop control flow (`break`, `continue`)
|
||||
- [x] `for`/`while` loop analysis
|
||||
- [x] `try`/`except`/`else`/`finally` control flow
|
||||
- [ ] `finally` limitations #233
|
||||
- [x] `Never`/`NoReturn` function propagation
|
||||
- [x] Exhaustiveness checking (`if`/`elif`/`else`)
|
||||
- [x] Exhaustiveness checking (`match`)
|
||||
- [ ] Advanced `match` pattern inference #887
|
||||
- [x] `assert_never()`
|
||||
- [x] `sys.version_info` comparisons
|
||||
- [x] `sys.platform` checks
|
||||
- [x] Statically known branches
|
||||
- [ ] Return type inference #128
|
||||
- [ ] Walrus operator in boolean expressions #626
|
||||
- [ ] Cyclic control flow (loop back edges) #232
|
||||
- [ ] Gray out unreachable code #784
|
||||
|
||||
## Invalid overrides
|
||||
|
||||
(Liskov Substitution Principle checks)
|
||||
|
||||
**tests:** [`liskov.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/liskov.md), [`override.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/override.md)
|
||||
|
||||
- [x] Covariant return types
|
||||
- [x] Contravariant parameter types
|
||||
- [x] Invariant mutable attributes
|
||||
- [x] Full class hierarchy checked
|
||||
- [x] Positional/keyword parameter kind changes
|
||||
- [x] Additional optional parameters
|
||||
- [x] `*args`/`**kwargs` compatibility
|
||||
- [x] `@staticmethod` and `@classmethod` overrides
|
||||
- [x] Synthesized method overrides (dataclasses)
|
||||
- [ ] Method overridden by non-method
|
||||
- [ ] Non-method overridden by non-method
|
||||
|
||||
## Abstract base classes
|
||||
|
||||
**tests:** [`return_type.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/function/return_type.md), [`overloads.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/overloads.md)
|
||||
|
||||
- [x] `@abstractmethod` decorator
|
||||
- [x] Empty body allowed for abstract methods
|
||||
- [x] `@abstractmethod` with `@overload` validation
|
||||
- [ ] Diagnostic: instantiating abstract class #1877
|
||||
|
||||
## `__slots__`
|
||||
|
||||
**tests:** [`instance_layout_conflict.md`](https://github.com/astral-sh/ruff/blob/main/crates/ty_python_semantic/resources/mdtest/instance_layout_conflict.md)
|
||||
|
||||
- [x] `__slots__` (string or tuple of strings)
|
||||
- [ ] `__slots__` (list, dict, set literals)
|
||||
- [ ] Attribute resolution from `__slots__` #1268
|
||||
- [ ] Diagnostic: access outside `__slots__` #1268
|
||||
- [ ] Diagnostic: class variable shadowing `__slots__` name #1268
|
||||
- [ ] `__dict__`/`__weakref__` presence validation #1268
|
||||
- [ ] Diagnostic: non-empty `__slots__` on builtin subclasses #1268
|
||||
|
||||
## Special library features
|
||||
|
||||
Standard library:
|
||||
|
||||
- [ ] `@cached_property` #1446
|
||||
- [ ] `functools.partial` #1536
|
||||
- [ ] `functools.total_ordering` #1202
|
||||
|
||||
Third-party library support (currently not decided how far we want to go here):
|
||||
|
||||
- [ ] Pydantic #291
|
||||
- [ ] Django #291
|
||||
- [ ] `attrs` #291
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
# Typing FAQ
|
||||
|
||||
This page answers some commonly asked questions about ty and Python's type system.
|
||||
|
||||
## Why does ty report an error on my code?
|
||||
|
||||
Check the [documentation](https://docs.astral.sh/ty/reference/rules/) for the specific error code
|
||||
you are seeing; it may explain the problem.
|
||||
|
||||
## What is the `Unknown` type and when does it appear?
|
||||
|
||||
`Unknown` is ty's way of representing a type that could not be fully inferred. It behaves the same
|
||||
way as `Any`, but appears implicitly, rather than through an explicit `Any` annotation:
|
||||
|
||||
```py
|
||||
from missing_module import MissingClass # error: unresolved-import
|
||||
|
||||
reveal_type(MissingClass) # Unknown
|
||||
```
|
||||
|
||||
ty also uses unions with `Unknown` to maintain the
|
||||
[gradual guarantee](../features/type-system.md#gradual-guarantee), which helps avoid false positive
|
||||
errors in untyped code while still providing useful type information where possible.
|
||||
|
||||
For example, consider the following untyped `Message` class (which could come from a third-party
|
||||
dependency that you have no control over). ty treats the `data` attribute as having type
|
||||
`Unknown | None`, since there is no type annotation that restricts it further. The `Unknown` in the
|
||||
union allows ty to avoid raising errors on the `msg.data = …` assignment. On the other hand, the
|
||||
`None` in the union reflects the fact that `data` *could* possibly be `None`, and requires code that
|
||||
uses `msg.data` to handle that case explicitly.
|
||||
|
||||
```py
|
||||
class Message:
|
||||
data = None
|
||||
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
|
||||
|
||||
def receive(msg: Message):
|
||||
reveal_type(msg.data) # Unknown | None
|
||||
|
||||
|
||||
msg = Message("Favorite color")
|
||||
msg.data = {"color": "blue"}
|
||||
```
|
||||
|
||||
([Full example in the playground](https://play.ty.dev/862941a8-a3f6-4818-9ea1-d9d59b0bd2fa))
|
||||
|
||||
## Why does ty show `int | float` when I annotate something as `float`?
|
||||
|
||||
The [Python typing specification](https://typing.python.org/en/latest/spec/special-types.html)
|
||||
includes a special rule for numeric types where an `int` can be used wherever a `float` is expected:
|
||||
|
||||
```py
|
||||
def circle_area(radius: float) -> float:
|
||||
return 3.14 * radius * radius
|
||||
|
||||
circle_area(2) # OK: int is allowed where float is expected
|
||||
```
|
||||
|
||||
This rule is a special case, since `int` is not actually a subclass of `float`. To support this, ty
|
||||
treats `float` annotations as meaning `int | float`. Unlike some other type checkers, ty makes this
|
||||
behavior explicit in type hints and error messages. For example, if you
|
||||
[hover over the `radius` parameter](https://play.ty.dev/fdc144c6-031c-4af9-b520-a4c6ccde9261), ty
|
||||
will show `int | float`.
|
||||
|
||||
A similar rule applies to `complex`, which is treated as `int | float | complex`.
|
||||
|
||||
!!! info
|
||||
|
||||
These special rules for `float` and `complex` exist for a reason. In almost all cases, you
|
||||
probably want to accept both `int` and `float` when you annotate something as `float`.
|
||||
If you really need to accept *only* `float` and not `int`, you can use ty's `JustFloat`
|
||||
type. At the time of writing, this import needs to be guarded by a `TYPE_CHECKING` block:
|
||||
|
||||
```py
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ty_extensions import JustFloat
|
||||
else:
|
||||
JustFloat = float
|
||||
|
||||
def only_actual_floats_allowed(f: JustFloat) -> None: ...
|
||||
|
||||
only_actual_floats_allowed(1.0) # OK
|
||||
only_actual_floats_allowed(1) # error: invalid-argument-type
|
||||
```
|
||||
|
||||
([Full example in the playground](https://play.ty.dev/fb034780-3ba7-4c6a-9449-5b0f44128bab))
|
||||
|
||||
If you need this for `complex`, you can use `ty_extensions.JustComplex` in a similar way.
|
||||
|
||||
## Why does ty say `Callable` has no attribute `__name__`?
|
||||
|
||||
When you access `__name__`, `__qualname__`, `__module__`, or `__doc__` on a value typed as `Callable`,
|
||||
ty reports an `unresolved-attribute` error. This is because not all callables have these attributes.
|
||||
Functions do (including lambdas), but other callable objects do not. The `FileUpload` class below, for
|
||||
example, is callable, but instances of `FileUpload` do not have a `__name__` attribute. Passing a
|
||||
`FileUpload` instance to `retry` would lead to an `AttributeError` at runtime.
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
def retry(times: int, operation: Callable[[], bool]) -> bool:
|
||||
for i in range(times):
|
||||
# WRONG: `operation` does not necessarily have a `__name__` attribute
|
||||
print(f"Calling {operation.__name__}, attempt {i + 1} of {times}")
|
||||
if operation():
|
||||
return True
|
||||
return False
|
||||
|
||||
class FileUpload:
|
||||
def __init__(self, name: str) -> None:
|
||||
# …
|
||||
|
||||
def __call__(self) -> bool:
|
||||
# …
|
||||
|
||||
retry(3, FileUpload("image.png"))
|
||||
```
|
||||
|
||||
To fix this, you could use `getattr` with a fall back to a default name when the
|
||||
attribute is not present (or use a `hasattr(…, "__name__")` check if you access
|
||||
it multiple times):
|
||||
|
||||
```py
|
||||
name = getattr(operation, "__name__", "operation")
|
||||
```
|
||||
|
||||
Alternatively, you could use an `isinstance(…, types.FunctionType)` check to narrow the type of
|
||||
`operation` to something that definitely has a `__name__` attribute:
|
||||
|
||||
```py
|
||||
if isinstance(operation, FunctionType):
|
||||
print(f"Calling {operation.__name__}, attempt {i + 1} of {times}")
|
||||
else:
|
||||
print(f"Calling operation, attempt {i + 1} of {times}")
|
||||
```
|
||||
|
||||
You can try various approaches in [this playground example](https://play.ty.dev/f6f7f35a-47c3-423d-be8d-33d03c61d40c).
|
||||
See also [this discussion](https://github.com/astral-sh/ty/issues/1495) for some plans to improve
|
||||
the developer experience around this in the future.
|
||||
|
||||
!!! info
|
||||
|
||||
ty has first-class support for intersection types. If you only want to accept function-like
|
||||
callables, you could define `FunctionLikeCallable` as an intersection of `Callable` and
|
||||
`types.FunctionType`:
|
||||
|
||||
```py
|
||||
from typing import Callable, TYPE_CHECKING
|
||||
from types import FunctionType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ty_extensions import Intersection
|
||||
|
||||
type FunctionLikeCallable[**P, R] = Intersection[Callable[P, R], FunctionType]
|
||||
else:
|
||||
FunctionLikeCallable = Callable
|
||||
|
||||
|
||||
def retry(times: int, operation: FunctionLikeCallable[[], bool]) -> bool:
|
||||
...
|
||||
```
|
||||
|
||||
You can check out the full example [here](https://play.ty.dev/7a1ea4ab-04e1-4271-adf5-ddc3a5d2fcfd),
|
||||
which demonstrates that `FileUpload` instances are no longer accepted by `retry`.
|
||||
|
||||
## Does ty have a strict mode?
|
||||
|
||||
Not yet. A stricter inference mode is tracked in
|
||||
[this issue](https://github.com/astral-sh/ty/issues/1240). In the meantime, you can consider using Ruff's
|
||||
[`flake8-annotations` rules](https://docs.astral.sh/ruff/rules/#flake8-annotations-ann) to enforce
|
||||
more explicit type annotations in your code.
|
||||
|
||||
## Why can't ty resolve my imports?
|
||||
|
||||
Import resolution issues are often caused by a missing or incorrect environment configuration. When
|
||||
ty reports *"Cannot resolve imported module …"*, check the following:
|
||||
|
||||
1. **Virtual environment**: Make sure your virtual environment is discoverable. ty looks for an
|
||||
active virtual environment via `VIRTUAL_ENV` or a `.venv` directory in your project root. See the
|
||||
[module discovery](../modules.md#python-environment) documentation for more details.
|
||||
|
||||
1. **Project structure**: If your source code is not in the project root or `src/` directory,
|
||||
configure [`environment.root`](./configuration.md#root) in your `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
root = ["./app"]
|
||||
```
|
||||
|
||||
1. **Third-party packages**: Ensure dependencies are installed in your virtual environment. Run ty
|
||||
with `-v` to see the search paths being used.
|
||||
|
||||
1. **Compiled extensions**: ty requires `.py` or `.pyi` files for type information. If a package
|
||||
contains only compiled extensions (`.so` or `.pyd` files), you'll need stub files (`.pyi`) for ty
|
||||
to understand the types. See also [this issue](https://github.com/astral-sh/ty/issues/487) which
|
||||
tracks improvements in this area.
|
||||
|
||||
## Does ty support monorepos?
|
||||
|
||||
ty can work with monorepos, but automatic discovery of nested projects is limited. By default, ty
|
||||
uses the current working directory or the `--project` option to determine the project root.
|
||||
|
||||
For monorepos with multiple Python packages, you have a few options:
|
||||
|
||||
1. **Run ty per-package**: Run `ty check` from each package directory, or use `--project` to specify
|
||||
the package:
|
||||
|
||||
```bash
|
||||
ty check --project packages/package-a
|
||||
ty check --project packages/package-b
|
||||
```
|
||||
|
||||
1. **Configure multiple source roots**: Use [`environment.root`](./configuration.md#root) to specify
|
||||
multiple source directories:
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
root = ["packages/package-a", "packages/package-b"]
|
||||
```
|
||||
|
||||
This has the disadvantage of treating all packages as a single project, which may lead to cases
|
||||
in which ty thinks something is importable when it wouldn't be at runtime.
|
||||
|
||||
You can follow [this issue](https://github.com/astral-sh/ty/issues/819) to get updates on this
|
||||
topic.
|
||||
|
||||
## Does ty support PEP 723 inline-metadata scripts?
|
||||
|
||||
It depends on what you want to do. If you have a single inline-metadata script, you can type check
|
||||
it with ty by using uv's `--with-requirements` flag to install the dependencies specified in the
|
||||
script header:
|
||||
|
||||
```bash
|
||||
uvx --with-requirements script.py ty check script.py
|
||||
```
|
||||
|
||||
If you have multiple scripts in your workspace, ty does not yet recognize that they have different
|
||||
dependencies based on their inline metadata.
|
||||
|
||||
You can follow [this issue](https://github.com/astral-sh/ty/issues/691) for updates.
|
||||
|
||||
## Is there a pre-commit hook for ty?
|
||||
|
||||
Not yet. You can track progress in [this issue](https://github.com/astral-sh/ty/issues/269), which
|
||||
also includes some suggested manual hooks you can use in the meantime.
|
||||
|
||||
## Does ty support (mypy) plugins?
|
||||
|
||||
No. ty does not have a plugin system and there is currently no plan to add one.
|
||||
|
||||
We prefer extending the type system with well-specified features rather than relying on
|
||||
type-checker-specific plugins. That said, we are considering adding support for popular third-party
|
||||
libraries like pydantic, SQLAlchemy, attrs, or django directly into ty.
|
||||
|
||||
## What is `Top[list[Unknown]]`, and why does it appear?
|
||||
|
||||
This type represents "all possible lists of any element type" (as opposed to `list[Unknown]`, which
|
||||
represents "a list of some unknown element type"). It usually arises from a check such as
|
||||
`if isinstance(x, list):`. If `x` was previously of type `Item | list[Item]`, you might expect this
|
||||
check to narrow the type to `list[Item]`, but ty respects the possibility that there could be a
|
||||
common subclass of both `Item` and `list` (which may not be a list of `Item`!), and so the narrowed
|
||||
type is instead `(Item & Top[list[Unknown]]) | list[Item]`. This code can be made more robust by
|
||||
instead checking `if instance(x, Item)`, or by declaring the `Item` type as `@typing.final`.
|
||||
|
||||
See also the [discussion
|
||||
here](https://docs.astral.sh/ty/features/type-system/#top-and-bottom-materializations) and [in this
|
||||
issue](https://github.com/astral-sh/ty/issues/1578).
|
||||
|
|
@ -6,7 +6,7 @@ specific pattern and can be turned on or off depending on your project’s needs
|
|||
|
||||
!!! tip
|
||||
|
||||
See the [rules reference](./reference/rules.md) for an enumeration of all supported rules.
|
||||
See [rules](./reference/rules.md) for an enumeration of all supported rules.
|
||||
|
||||
## Rule levels
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ Rule levels can also be changed in the [`rules`](./reference/configuration.md#ru
|
|||
|
||||
For example, the following is equivalent to the command above:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
```toml
|
||||
[tool.ty.rules]
|
||||
unused-ignore-comment = "warn"
|
||||
redundant-cast = "ignore"
|
||||
|
|
|
|||
|
|
@ -19,18 +19,18 @@ Rule violations spanning multiple lines can be suppressed by adding the comment
|
|||
violation's first or last line:
|
||||
|
||||
```py
|
||||
def sum_three_numbers(a: int, b: int, c: int) -> int: ...
|
||||
def add_three(a: int, b: int, c: int): ...
|
||||
|
||||
# on the first line
|
||||
|
||||
sum_three_numbers( # ty: ignore[missing-argument]
|
||||
add_three( # ty: ignore[missing-argument]
|
||||
3,
|
||||
2
|
||||
)
|
||||
|
||||
# or, on the last line
|
||||
|
||||
sum_three_numbers(
|
||||
add_three(
|
||||
3,
|
||||
2
|
||||
) # ty: ignore[missing-argument]
|
||||
|
|
@ -39,7 +39,7 @@ sum_three_numbers(
|
|||
To suppress multiple violations on a single line, enumerate each rule separated by a comma:
|
||||
|
||||
```python
|
||||
sum_three_numbers("one", 5) # ty: ignore[missing-argument, invalid-argument-type]
|
||||
add_three("one", 5) # ty: ignore[missing-argument, invalid-argument-type]
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
|
@ -49,7 +49,7 @@ sum_three_numbers("one", 5) # ty: ignore[missing-argument, invalid-argument-typ
|
|||
|
||||
## Standard suppression comments
|
||||
|
||||
ty supports the standard [`type: ignore`](https://typing.python.org/en/latest/spec/directives.html#type-ignore-comments) comment
|
||||
ty supports the standard [`type:ignore`](https://typing.python.org/en/latest/spec/directives.html#type-ignore-comments) comment
|
||||
format introduced by PEP 484.
|
||||
|
||||
ty handles these similarly to `ty: ignore` comments, but suppresses all violations on that line,
|
||||
|
|
@ -57,7 +57,7 @@ even when `type: ignore[code]` is used.
|
|||
|
||||
```python
|
||||
# Ignore all typing errors on the next line
|
||||
sum_three_numbers("one", 5) # type: ignore
|
||||
add_three("one", 5) # type: ignore
|
||||
```
|
||||
|
||||
## Multiple suppressions comments
|
||||
|
|
@ -91,12 +91,12 @@ to suppress all violations inside a function.
|
|||
```python
|
||||
from typing import no_type_check
|
||||
|
||||
def sum_three_numbers(a: int, b: int, c: int) -> int:
|
||||
return a + b + c
|
||||
def add_three(a: int, b: int, c: int):
|
||||
a + b + c
|
||||
|
||||
@no_type_check
|
||||
def main():
|
||||
sum_three_numbers(1, 2) # no error for the missing argument
|
||||
add_three(3, 4)
|
||||
```
|
||||
|
||||
Decorating a class with `@no_type_check` isn't supported.
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
# Type checking
|
||||
|
||||
After [installing ty](./installation.md), it's time to type check some code!
|
||||
|
||||
## Running the type checker
|
||||
|
||||
To run the type checker, use the `check` command:
|
||||
|
||||
```shell
|
||||
ty check
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
If you're in a project, you may need to use `uv run` or activate your virtual environment first
|
||||
for ty to find your dependencies.
|
||||
|
||||
## Environment discovery
|
||||
|
||||
The type checker needs to discover your installed packages in order to check your use of imported
|
||||
dependencies.
|
||||
|
||||
ty will find installed packages in the active virtual environment (via `VIRTUAL_ENV`) or discover a
|
||||
virtual environment named `.venv` in the project root or working directory. It will not find
|
||||
packages in non-virtual environments without specifying the target path with `--python`.
|
||||
|
||||
See the [module discovery](./modules.md) documentation for details.
|
||||
|
||||
## File selection
|
||||
|
||||
ty will run on all Python files in the working directory (including subdirectories, recursively).
|
||||
If used from a project, ty will run on all Python files in the project (starting in the directory
|
||||
with the `pyproject.toml`).
|
||||
|
||||
You can also provide specific paths to check:
|
||||
|
||||
```shell
|
||||
ty check example.py
|
||||
```
|
||||
|
||||
You can also persistently configure [included and excluded files](./exclusions.md).
|
||||
|
||||
## Rule selection and severity
|
||||
|
||||
ty's type checking diagnostics are often associated with a rule.
|
||||
|
||||
ty's type checking rules can be configured to your project's needs. See the [rules](./rules.md)
|
||||
documentation for details.
|
||||
|
||||
You can also suppress specific violations of rules using [suppression comments](./suppression.md).
|
||||
|
||||
## Watch mode
|
||||
|
||||
ty can be run in an incremental watch mode:
|
||||
|
||||
```shell
|
||||
ty check --watch
|
||||
```
|
||||
|
||||
ty will watch files for changes and recheck any affected files — including files that depend on the
|
||||
changed file. ty uses [fine-grained incrementality](./features/language-server.md#fine-grained-incrementality)
|
||||
to perform subsequent checks much faster than running `ty check` repeatedly.
|
||||
|
||||
## The type system
|
||||
|
||||
To learn more about what makes type checking in ty unique, read about the
|
||||
[type system](./features/type-system.md).
|
||||
14
mkdocs.yml
|
|
@ -81,30 +81,24 @@ extra:
|
|||
- icon: fontawesome/brands/x-twitter
|
||||
link: https://x.com/astral_sh
|
||||
nav:
|
||||
- Introduction: index.md
|
||||
- Guides:
|
||||
- Installation: installation.md
|
||||
- Type checking: type-checking.md
|
||||
- Editor integration: editors.md
|
||||
- Getting started: index.md
|
||||
- Concepts:
|
||||
- Installation: installation.md
|
||||
- Configuration: configuration.md
|
||||
- Module discovery: modules.md
|
||||
- Python version: python-version.md
|
||||
- File exclusions: exclusions.md
|
||||
- Rules: rules.md
|
||||
- Suppression: suppression.md
|
||||
- Features:
|
||||
- Type system: features/type-system.md
|
||||
- Diagnostics: features/diagnostics.md
|
||||
- Language server: features/language-server.md
|
||||
- Editors: editors.md
|
||||
- Reference:
|
||||
- Configuration: reference/configuration.md
|
||||
- Typing FAQ: reference/typing-faq.md
|
||||
- Rules: reference/rules.md
|
||||
- CLI: reference/cli.md
|
||||
- Exit codes: reference/exit-codes.md
|
||||
- Environment variables: reference/environment.md
|
||||
- Editor settings: reference/editor-settings.md
|
||||
- Type system features: reference/type-system-features.md
|
||||
validation:
|
||||
omitted_files: warn
|
||||
absolute_links: warn
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "ty"
|
||||
version = "0.0.8"
|
||||
version = "0.0.1a34"
|
||||
requires-python = ">=3.8"
|
||||
dependencies = []
|
||||
description = "An extremely fast Python type checker, written in Rust."
|
||||
|
|
@ -8,7 +8,7 @@ readme = "README.md"
|
|||
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
|
||||
keywords = ["ty", "typing", "analysis", "check"]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"Operating System :: OS Independent",
|
||||
|
|
@ -102,7 +102,6 @@ include = [
|
|||
version-files = [
|
||||
"pyproject.toml",
|
||||
{ path = "dist-workspace.toml", field = "workspace.version", format = "cargo" },
|
||||
"docs/installation.md",
|
||||
]
|
||||
submodules = ["ruff"]
|
||||
require-labels = [{ submodule = "ruff", labels = ["ty"] }]
|
||||
|
|
@ -118,6 +117,7 @@ changelog-ignore-authors = ["github-actions"]
|
|||
major-labels = [] # We do not use the major version number yet
|
||||
minor-labels = [] # We do not use the minor version number yet
|
||||
version-format = "cargo"
|
||||
default-bump-type = "pre"
|
||||
trim-title-prefixes = ["[ty]"]
|
||||
|
||||
[tool.rooster.section-labels]
|
||||
|
|
|
|||
2
ruff
|
|
@ -1 +1 @@
|
|||
Subproject commit e71fd9c0408dbedff0c80b6855c5612c82091f59
|
||||
Subproject commit 90b29c9e87bc5bbe12df43bad74f368b84b90427
|
||||
|
|
@ -25,13 +25,6 @@ def main() -> None:
|
|||
|
||||
content = Path("README.md").read_text(encoding="utf8")
|
||||
|
||||
# Replace relative src="./..." attributes with absolute GitHub raw URLs.
|
||||
def replace_src(match: re.Match) -> str:
|
||||
path = match.group(1).lstrip("./")
|
||||
return f'src="https://raw.githubusercontent.com/astral-sh/ty/{version}/{path}"'
|
||||
|
||||
content = re.sub(r'src="(\./[^"]+)"', replace_src, content)
|
||||
|
||||
# Replace any relative URLs (e.g., `[CONTRIBUTING.md`) with absolute URLs.
|
||||
def replace(match: re.Match) -> str:
|
||||
url = match.group(1)
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ def main() -> None:
|
|||
|
||||
if expected_ruff_revision != actual_ruff_revision:
|
||||
print(
|
||||
f"The ruff submodule is at {actual_ruff_revision} but main expects {expected_ruff_revision}"
|
||||
f"The ruff submodule is at {expected_ruff_revision} but main expects {actual_ruff_revision}"
|
||||
)
|
||||
match input(
|
||||
"How do you want to proceed (u=reset submodule, n=abort, y=continue)? "
|
||||
|
|
|
|||