Compare commits
52 Commits
zb/cache-u
...
micha/ty-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ad2e09430 | ||
|
|
dd3a985109 | ||
|
|
12f5ea51e3 | ||
|
|
f9afcc400c | ||
|
|
768c5a2285 | ||
|
|
139149f87b | ||
|
|
2de4464e92 | ||
|
|
ded4d4bbe9 | ||
|
|
eef403f6cf | ||
|
|
adef89eb7c | ||
|
|
e3498121b4 | ||
|
|
5e7fc9a4e1 | ||
|
|
3c5956e93d | ||
|
|
81f34fbc8e | ||
|
|
184f487c84 | ||
|
|
969c8a547e | ||
|
|
acdda78189 | ||
|
|
c28c1f534d | ||
|
|
b723917463 | ||
|
|
5decf94644 | ||
|
|
89a55dd09f | ||
|
|
8710a8c4ac | ||
|
|
e245c1d76e | ||
|
|
4c175fa0e1 | ||
|
|
ed64c4d943 | ||
|
|
f1e6c9c3a0 | ||
|
|
d9fe996e64 | ||
|
|
5ea30c4c53 | ||
|
|
ccc9132f73 | ||
|
|
65021fcee9 | ||
|
|
aa21b70a8b | ||
|
|
22ce0c8a51 | ||
|
|
d6a7c9b4ed | ||
|
|
4745d15fff | ||
|
|
06db474f20 | ||
|
|
664686bdbc | ||
|
|
4a937543b9 | ||
|
|
ec034fc359 | ||
|
|
29d7f22c1f | ||
|
|
8fc4349fd3 | ||
|
|
816b19c4a6 | ||
|
|
87406b43ea | ||
|
|
422e99ea70 | ||
|
|
ea6730f546 | ||
|
|
a46835c224 | ||
|
|
884e83591e | ||
|
|
6b3dd28e63 | ||
|
|
572f57aa3c | ||
|
|
ed423e0ae2 | ||
|
|
fee4e2d72a | ||
|
|
b6e84eca16 | ||
|
|
b4c2825afd |
67
.claude/settings.local.json
Normal file
67
.claude/settings.local.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cargo build:*)",
|
||||
"Read(//home/micha/astral/discord.py/discord/**)",
|
||||
"Bash(source:*)",
|
||||
"Bash(./target/profiling/ty check:*)",
|
||||
"Bash(tee:*)",
|
||||
"Read(//home/micha/astral/discord.py/.venv/**)",
|
||||
"Read(//home/micha/astral/discord.py/**)",
|
||||
"Bash(perf record:*)",
|
||||
"Bash(perf report:*)",
|
||||
"Bash(time:*)",
|
||||
"Bash(../ruff/target/profiling/ty check discord/audit_logs.py -vv)",
|
||||
"Bash(sed:*)",
|
||||
"Read(//home/micha/git/TypeScript/**)",
|
||||
"Bash(cargo test:*)",
|
||||
"Bash(MDTEST_TEST_FILTER='union_types.md - Union types - Unions of tuples' cargo test -p ty_python_semantic --test mdtest -- mdtest__union_types)",
|
||||
"Bash(timeout 10 cargo test --package ty_python_semantic --lib types::tests::divergent_type)",
|
||||
"Bash(timeout 30 cargo test:*)",
|
||||
"Bash(git stash:*)",
|
||||
"Bash(timeout 60 time:*)",
|
||||
"Bash(for i in 1 2 3 4 5)",
|
||||
"Bash(do echo \"Run $i:\")",
|
||||
"Bash(done)",
|
||||
"Bash(for i in 1 2 3)",
|
||||
"Bash(cargo fuzz run:*)",
|
||||
"Bash(timeout 60 cargo fuzz run -s none ty_check_invalid_syntax -- -timeout=1)",
|
||||
"Bash(for:*)",
|
||||
"Bash(do echo \"=== Checking $crash ===\")",
|
||||
"Bash(uvx ty@latest check \"$crash\")",
|
||||
"Bash(do echo \"=== $crash ===\")",
|
||||
"Bash(while read crash)",
|
||||
"Bash(cargo fuzz cmin:*)",
|
||||
"Bash(cargo +nightly fuzz cmin:*)",
|
||||
"Bash(timeout 120 cargo fuzz run -s none ty_check_invalid_syntax -- -timeout=1)",
|
||||
"Bash(awk:*)",
|
||||
"Bash(while read file)",
|
||||
"Bash(cat:*)",
|
||||
"Bash(uvx ty@latest:*)",
|
||||
"Bash(do cp \"$crash\" /tmp/isolated_crash.py)",
|
||||
"Bash(echo \"=== $crash ===\")",
|
||||
"Bash(do echo \"=== test$i.py ===\")",
|
||||
"Bash(do echo \"=== Testing $crash ===\")",
|
||||
"Bash(tree:*)",
|
||||
"Bash(cut:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(xargs basename:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash({} ;)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(do)",
|
||||
"Bash(if ! grep -q \"use crate::types\" \"$f\")",
|
||||
"Bash(! grep -q \"crate::types::\" \"$f\")",
|
||||
"Bash(then)",
|
||||
"Bash(else)",
|
||||
"Bash(fi)",
|
||||
"Bash(1)",
|
||||
"Bash(__NEW_LINE__ echo \"Done\")",
|
||||
"Bash(rm:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
2
.github/actionlint.yaml
vendored
2
.github/actionlint.yaml
vendored
@@ -4,10 +4,12 @@
|
||||
self-hosted-runner:
|
||||
# Various runners we use that aren't recognized out-of-the-box by actionlint:
|
||||
labels:
|
||||
- depot-ubuntu-24.04-4
|
||||
- depot-ubuntu-latest-8
|
||||
- depot-ubuntu-22.04-16
|
||||
- depot-ubuntu-22.04-32
|
||||
- depot-windows-2022-16
|
||||
- depot-ubuntu-22.04-arm-4
|
||||
- github-windows-2025-x86_64-8
|
||||
- github-windows-2025-x86_64-16
|
||||
- codspeed-macro
|
||||
|
||||
126
.github/workflows/ci.yaml
vendored
126
.github/workflows/ci.yaml
vendored
@@ -952,7 +952,7 @@ jobs:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench formatter --bench lexer --bench linter --bench parser
|
||||
run: cargo codspeed build --features "codspeed,ruff_instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench formatter --bench lexer --bench linter --bench parser
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1
|
||||
@@ -960,9 +960,9 @@ jobs:
|
||||
mode: simulation
|
||||
run: cargo codspeed run
|
||||
|
||||
benchmarks-instrumented-ty:
|
||||
name: "benchmarks instrumented (ty)"
|
||||
runs-on: ubuntu-24.04
|
||||
benchmarks-instrumented-ty-build:
|
||||
name: "benchmarks instrumented ty (build)"
|
||||
runs-on: depot-ubuntu-24.04-4
|
||||
needs: determine_changes
|
||||
if: |
|
||||
github.repository == 'astral-sh/ruff' &&
|
||||
@@ -971,9 +971,83 @@ jobs:
|
||||
needs.determine_changes.outputs.ty == 'true'
|
||||
)
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: "Checkout Branch"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install codspeed"
|
||||
uses: taiki-e/install-action@3575e532701a5fc614b0c842e4119af4cc5fd16d # v2.62.60
|
||||
with:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build -m instrumentation --features "codspeed,ty_instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench ty
|
||||
|
||||
- name: "Upload benchmark binary"
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: benchmarks-instrumented-ty-binary
|
||||
path: target/codspeed/simulation/ruff_benchmark
|
||||
retention-days: 1
|
||||
|
||||
benchmarks-instrumented-ty-run:
|
||||
name: "benchmarks instrumented ty (${{ matrix.benchmark }})"
|
||||
runs-on: ubuntu-24.04
|
||||
needs: benchmarks-instrumented-ty-build
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: read # required for actions/checkout
|
||||
id-token: write # required for OIDC authentication with CodSpeed
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
benchmark:
|
||||
- "check_file|micro|anyio"
|
||||
- "attrs|hydra|datetype"
|
||||
steps:
|
||||
- name: "Checkout Branch"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
|
||||
|
||||
- name: "Install codspeed"
|
||||
uses: taiki-e/install-action@3575e532701a5fc614b0c842e4119af4cc5fd16d # v2.62.60
|
||||
with:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Download benchmark binary"
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4.3.0
|
||||
with:
|
||||
name: benchmarks-instrumented-ty-binary
|
||||
path: target/codspeed/simulation/ruff_benchmark
|
||||
|
||||
- name: "Restore binary permissions"
|
||||
run: chmod +x target/codspeed/simulation/ruff_benchmark/ty
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1
|
||||
with:
|
||||
mode: simulation
|
||||
run: cargo codspeed run --bench ty "${{ matrix.benchmark }}"
|
||||
|
||||
benchmarks-walltime-build:
|
||||
name: "benchmarks walltime (build)"
|
||||
# We only run this job if `github.repository == 'astral-sh/ruff'`,
|
||||
# so hardcoding depot here is fine
|
||||
runs-on: depot-ubuntu-22.04-arm-4
|
||||
needs: determine_changes
|
||||
if: ${{ github.repository == 'astral-sh/ruff' && !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.ty == 'true' || github.ref == 'refs/heads/main') }}
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: "Checkout Branch"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
@@ -994,49 +1068,51 @@ jobs:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features "codspeed,instrumented" --profile profiling --no-default-features -p ruff_benchmark --bench ty
|
||||
run: cargo codspeed build -m walltime --features "codspeed,ty_walltime" --profile profiling --no-default-features -p ruff_benchmark
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1
|
||||
- name: "Upload benchmark binary"
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
mode: simulation
|
||||
run: cargo codspeed run
|
||||
name: benchmarks-walltime-binary
|
||||
path: target/codspeed/walltime/ruff_benchmark
|
||||
retention-days: 1
|
||||
|
||||
benchmarks-walltime:
|
||||
name: "benchmarks walltime (${{ matrix.benchmarks }})"
|
||||
benchmarks-walltime-run:
|
||||
name: "benchmarks walltime (${{ matrix.benchmark }})"
|
||||
runs-on: codspeed-macro
|
||||
needs: determine_changes
|
||||
if: ${{ github.repository == 'astral-sh/ruff' && !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.ty == 'true' || github.ref == 'refs/heads/main') }}
|
||||
needs: benchmarks-walltime-build
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: read # required for actions/checkout
|
||||
id-token: write # required for OIDC authentication with CodSpeed
|
||||
strategy:
|
||||
matrix:
|
||||
benchmarks:
|
||||
- "medium|multithreaded"
|
||||
- "small|large"
|
||||
benchmark:
|
||||
- colour_science
|
||||
- "pandas|tanjun|altair"
|
||||
- "static_frame|sympy"
|
||||
- "pydantic|multithreaded|freqtrade"
|
||||
steps:
|
||||
- name: "Checkout Branch"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
- uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
|
||||
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install codspeed"
|
||||
uses: taiki-e/install-action@3575e532701a5fc614b0c842e4119af4cc5fd16d # v2.62.60
|
||||
with:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features "codspeed,walltime" --profile profiling --no-default-features -p ruff_benchmark
|
||||
- name: "Download benchmark binary"
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
name: benchmarks-walltime-binary
|
||||
path: target/codspeed/walltime/ruff_benchmark
|
||||
|
||||
- name: "Restore binary permissions"
|
||||
run: chmod +x target/codspeed/walltime/ruff_benchmark/ty_walltime
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1
|
||||
@@ -1047,4 +1123,4 @@ jobs:
|
||||
CODSPEED_PERF_ENABLED: false
|
||||
with:
|
||||
mode: walltime
|
||||
run: cargo codspeed run --bench ty_walltime "${{ matrix.benchmarks }}"
|
||||
run: cargo codspeed run --bench ty_walltime -m walltime "${{ matrix.benchmark }}"
|
||||
|
||||
18
.github/workflows/ty-ecosystem-report.yaml
vendored
18
.github/workflows/ty-ecosystem-report.yaml
vendored
@@ -14,7 +14,6 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
RUST_BACKTRACE: 1
|
||||
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
|
||||
|
||||
jobs:
|
||||
ty-ecosystem-report:
|
||||
@@ -31,12 +30,12 @@ jobs:
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
|
||||
with:
|
||||
enable-cache: true # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
|
||||
enable-cache: true
|
||||
|
||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||
with:
|
||||
workspaces: "ruff"
|
||||
lookup-only: false # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
|
||||
lookup-only: false
|
||||
|
||||
- name: Install Rust toolchain
|
||||
run: rustup show
|
||||
@@ -70,11 +69,10 @@ jobs:
|
||||
ecosystem-diagnostics.json \
|
||||
--output dist/index.html
|
||||
|
||||
- name: "Deploy to Cloudflare Pages"
|
||||
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
||||
id: deploy
|
||||
uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1
|
||||
# NOTE: astral-sh-bot uses this artifact to publish the ecosystem report.
|
||||
# Make sure to update the bot if you rename the artifact.
|
||||
- name: "Upload ecosystem report"
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
command: pages deploy dist --project-name=ty-ecosystem --branch main --commit-hash ${GITHUB_SHA}
|
||||
name: full-report
|
||||
path: dist/
|
||||
|
||||
@@ -5,7 +5,7 @@ exclude: |
|
||||
.github/workflows/release.yml|
|
||||
crates/ty_vendored/vendor/.*|
|
||||
crates/ty_project/resources/.*|
|
||||
crates/ty_python_semantic/resources/corpus/.*|
|
||||
crates/ty_python_types/resources/corpus/.*|
|
||||
crates/ty/docs/(configuration|rules|cli|environment).md|
|
||||
crates/ruff_benchmark/resources/.*|
|
||||
crates/ruff_linter/resources/.*|
|
||||
|
||||
109
Cargo.lock
generated
109
Cargo.lock
generated
@@ -3083,6 +3083,7 @@ dependencies = [
|
||||
"ty",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"url",
|
||||
]
|
||||
@@ -3129,7 +3130,9 @@ dependencies = [
|
||||
"salsa",
|
||||
"schemars",
|
||||
"serde",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -3619,8 +3622,8 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "salsa"
|
||||
version = "0.24.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=55e5e7d32fa3fc189276f35bb04c9438f9aedbd1#55e5e7d32fa3fc189276f35bb04c9438f9aedbd1"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=ce80691fa0b87dc2fd2235a26544e63e5e43d8d3#ce80691fa0b87dc2fd2235a26544e63e5e43d8d3"
|
||||
dependencies = [
|
||||
"boxcar",
|
||||
"compact_str",
|
||||
@@ -3644,13 +3647,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "salsa-macro-rules"
|
||||
version = "0.24.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=55e5e7d32fa3fc189276f35bb04c9438f9aedbd1#55e5e7d32fa3fc189276f35bb04c9438f9aedbd1"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=ce80691fa0b87dc2fd2235a26544e63e5e43d8d3#ce80691fa0b87dc2fd2235a26544e63e5e43d8d3"
|
||||
|
||||
[[package]]
|
||||
name = "salsa-macros"
|
||||
version = "0.24.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=55e5e7d32fa3fc189276f35bb04c9438f9aedbd1#55e5e7d32fa3fc189276f35bb04c9438f9aedbd1"
|
||||
version = "0.25.2"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=ce80691fa0b87dc2fd2235a26544e63e5e43d8d3#ce80691fa0b87dc2fd2235a26544e63e5e43d8d3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4375,6 +4378,7 @@ dependencies = [
|
||||
"tracing-flame",
|
||||
"tracing-subscriber",
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"ty_server",
|
||||
@@ -4389,7 +4393,6 @@ dependencies = [
|
||||
"ordermap",
|
||||
"ruff_db",
|
||||
"ruff_python_ast",
|
||||
"ty_python_semantic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4407,8 +4410,8 @@ dependencies = [
|
||||
"tempfile",
|
||||
"toml",
|
||||
"ty_ide",
|
||||
"ty_module_resolver",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -4438,8 +4441,33 @@ dependencies = [
|
||||
"salsa",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"ty_module_resolver",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty_module_resolver"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
"compact_str",
|
||||
"get-size2",
|
||||
"insta",
|
||||
"ruff_db",
|
||||
"ruff_memory_usage",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_stdlib",
|
||||
"rustc-hash",
|
||||
"salsa",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
@@ -4477,7 +4505,9 @@ dependencies = [
|
||||
"toml",
|
||||
"tracing",
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
@@ -4491,19 +4521,12 @@ dependencies = [
|
||||
"bitvec",
|
||||
"camino",
|
||||
"colored 3.0.0",
|
||||
"compact_str",
|
||||
"datatest-stable",
|
||||
"drop_bomb",
|
||||
"get-size2",
|
||||
"glob",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"memchr",
|
||||
"ordermap",
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"ruff_annotate_snippets",
|
||||
@@ -4513,9 +4536,7 @@ dependencies = [
|
||||
"ruff_macros",
|
||||
"ruff_memory_usage",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
@@ -4529,10 +4550,57 @@ dependencies = [
|
||||
"strsim",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
"ty_combine",
|
||||
"ty_module_resolver",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ty_python_types"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.10.0",
|
||||
"camino",
|
||||
"compact_str",
|
||||
"datatest-stable",
|
||||
"drop_bomb",
|
||||
"get-size2",
|
||||
"glob",
|
||||
"indexmap",
|
||||
"indoc",
|
||||
"insta",
|
||||
"itertools 0.14.0",
|
||||
"memchr",
|
||||
"ordermap",
|
||||
"pretty_assertions",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"ruff_db",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_memory_usage",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"salsa",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"test-case",
|
||||
"tracing",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_static",
|
||||
"ty_test",
|
||||
@@ -4572,6 +4640,7 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
"ty_combine",
|
||||
"ty_ide",
|
||||
"ty_module_resolver",
|
||||
"ty_project",
|
||||
"ty_python_semantic",
|
||||
]
|
||||
@@ -4612,7 +4681,9 @@ dependencies = [
|
||||
"thiserror 2.0.17",
|
||||
"toml",
|
||||
"tracing",
|
||||
"ty_module_resolver",
|
||||
"ty_python_semantic",
|
||||
"ty_python_types",
|
||||
"ty_static",
|
||||
"ty_vendored",
|
||||
]
|
||||
|
||||
@@ -45,8 +45,10 @@ ty = { path = "crates/ty" }
|
||||
ty_combine = { path = "crates/ty_combine" }
|
||||
ty_completion_eval = { path = "crates/ty_completion_eval" }
|
||||
ty_ide = { path = "crates/ty_ide" }
|
||||
ty_module_resolver = { path = "crates/ty_module_resolver" }
|
||||
ty_project = { path = "crates/ty_project", default-features = false }
|
||||
ty_python_semantic = { path = "crates/ty_python_semantic" }
|
||||
ty_python_types = { path = "crates/ty_python_types" }
|
||||
ty_server = { path = "crates/ty_server" }
|
||||
ty_static = { path = "crates/ty_static" }
|
||||
ty_test = { path = "crates/ty_test" }
|
||||
@@ -146,7 +148,7 @@ regex-automata = { version = "0.4.9" }
|
||||
rustc-hash = { version = "2.0.0" }
|
||||
rustc-stable-hash = { version = "0.1.2" }
|
||||
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "55e5e7d32fa3fc189276f35bb04c9438f9aedbd1", default-features = false, features = [
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "ce80691fa0b87dc2fd2235a26544e63e5e43d8d3", default-features = false, features = [
|
||||
"compact_str",
|
||||
"macros",
|
||||
"salsa_unstable",
|
||||
|
||||
@@ -14,6 +14,6 @@ info:
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
::error title=Ruff (unformatted),file=[TMP]/input.py,line=1,col=1,endLine=2,endColumn=1::input.py:1:1: unformatted: File would be reformatted
|
||||
::error title=Ruff (unformatted),file=[TMP]/input.py,line=1,endLine=2::input.py:1:1: unformatted: File would be reformatted
|
||||
|
||||
----- stderr -----
|
||||
|
||||
@@ -19,32 +19,32 @@ doctest = false
|
||||
[[bench]]
|
||||
name = "linter"
|
||||
harness = false
|
||||
required-features = ["instrumented"]
|
||||
required-features = ["ruff_instrumented"]
|
||||
|
||||
[[bench]]
|
||||
name = "lexer"
|
||||
harness = false
|
||||
required-features = ["instrumented"]
|
||||
required-features = ["ruff_instrumented"]
|
||||
|
||||
[[bench]]
|
||||
name = "parser"
|
||||
harness = false
|
||||
required-features = ["instrumented"]
|
||||
required-features = ["ruff_instrumented"]
|
||||
|
||||
[[bench]]
|
||||
name = "formatter"
|
||||
harness = false
|
||||
required-features = ["instrumented"]
|
||||
required-features = ["ruff_instrumented"]
|
||||
|
||||
[[bench]]
|
||||
name = "ty"
|
||||
harness = false
|
||||
required-features = ["instrumented"]
|
||||
required-features = ["ty_instrumented"]
|
||||
|
||||
[[bench]]
|
||||
name = "ty_walltime"
|
||||
harness = false
|
||||
required-features = ["walltime"]
|
||||
required-features = ["ty_walltime"]
|
||||
|
||||
[dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing"] }
|
||||
@@ -67,25 +67,32 @@ tracing = { workspace = true }
|
||||
workspace = true
|
||||
|
||||
[features]
|
||||
default = ["instrumented", "walltime"]
|
||||
# Enables the benchmark that should only run with codspeed's instrumented runner
|
||||
instrumented = [
|
||||
default = ["ty_instrumented", "ty_walltime", "ruff_instrumented"]
|
||||
# Enables the ruff instrumented benchmarks
|
||||
ruff_instrumented = [
|
||||
"criterion",
|
||||
"ruff_linter",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"mimalloc",
|
||||
"tikv-jemallocator",
|
||||
]
|
||||
# Enables the ty instrumented benchmarks
|
||||
ty_instrumented = [
|
||||
"criterion",
|
||||
"ty_project",
|
||||
"ruff_python_trivia",
|
||||
]
|
||||
codspeed = ["codspeed-criterion-compat"]
|
||||
# Enables benchmark that should only run with codspeed's walltime runner.
|
||||
walltime = ["ruff_db/os", "ty_project", "divan"]
|
||||
# Enables the ty_walltime benchmarks
|
||||
ty_walltime = ["ruff_db/os", "ty_project", "divan"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dev-dependencies]
|
||||
mimalloc = { workspace = true }
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
mimalloc = { workspace = true, optional = true }
|
||||
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64", target_arch = "riscv64")))'.dev-dependencies]
|
||||
tikv-jemallocator = { workspace = true }
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64", target_arch = "riscv64")))'.dependencies]
|
||||
tikv-jemallocator = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-hash = { workspace = true }
|
||||
|
||||
@@ -194,7 +194,7 @@ static SYMPY: Benchmark = Benchmark::new(
|
||||
max_dep_date: "2025-06-17",
|
||||
python_version: PythonVersion::PY312,
|
||||
},
|
||||
13100,
|
||||
13106,
|
||||
);
|
||||
|
||||
static TANJUN: Benchmark = Benchmark::new(
|
||||
@@ -235,30 +235,55 @@ fn run_single_threaded(bencher: Bencher, benchmark: &Benchmark) {
|
||||
});
|
||||
}
|
||||
|
||||
#[bench(args=[&ALTAIR, &FREQTRADE, &TANJUN], sample_size=2, sample_count=3)]
|
||||
fn small(bencher: Bencher, benchmark: &Benchmark) {
|
||||
run_single_threaded(bencher, benchmark);
|
||||
#[bench(sample_size = 2, sample_count = 3)]
|
||||
fn altair(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &ALTAIR);
|
||||
}
|
||||
|
||||
#[bench(args=[&COLOUR_SCIENCE, &PANDAS, &STATIC_FRAME], sample_size=1, sample_count=3)]
|
||||
fn medium(bencher: Bencher, benchmark: &Benchmark) {
|
||||
run_single_threaded(bencher, benchmark);
|
||||
#[bench(sample_size = 2, sample_count = 3)]
|
||||
fn freqtrade(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &FREQTRADE);
|
||||
}
|
||||
|
||||
#[bench(args=[&SYMPY, &PYDANTIC], sample_size=1, sample_count=2)]
|
||||
fn large(bencher: Bencher, benchmark: &Benchmark) {
|
||||
run_single_threaded(bencher, benchmark);
|
||||
#[bench(sample_size = 2, sample_count = 3)]
|
||||
fn tanjun(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &TANJUN);
|
||||
}
|
||||
|
||||
#[bench(args=[&ALTAIR], sample_size=3, sample_count=8)]
|
||||
fn multithreaded(bencher: Bencher, benchmark: &Benchmark) {
|
||||
#[bench(sample_size = 2, sample_count = 3)]
|
||||
fn pydantic(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &PYDANTIC);
|
||||
}
|
||||
|
||||
#[bench(sample_size = 1, sample_count = 3)]
|
||||
fn static_frame(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &STATIC_FRAME);
|
||||
}
|
||||
|
||||
#[bench(sample_size = 1, sample_count = 2)]
|
||||
fn colour_science(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &COLOUR_SCIENCE);
|
||||
}
|
||||
|
||||
#[bench(sample_size = 1, sample_count = 2)]
|
||||
fn pandas(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &PANDAS);
|
||||
}
|
||||
|
||||
#[bench(sample_size = 1, sample_count = 2)]
|
||||
fn sympy(bencher: Bencher) {
|
||||
run_single_threaded(bencher, &SYMPY);
|
||||
}
|
||||
|
||||
#[bench(sample_size = 3, sample_count = 8)]
|
||||
fn multithreaded(bencher: Bencher) {
|
||||
let thread_pool = ThreadPoolBuilder::new().build().unwrap();
|
||||
|
||||
bencher
|
||||
.with_inputs(|| benchmark.setup_iteration())
|
||||
.with_inputs(|| ALTAIR.setup_iteration())
|
||||
.bench_local_values(|db| {
|
||||
thread_pool.install(|| {
|
||||
check_project(&db, benchmark.project.name, benchmark.max_diagnostics);
|
||||
check_project(&db, ALTAIR.project.name, ALTAIR.max_diagnostics);
|
||||
db
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "instrumented")]
|
||||
#[cfg(any(feature = "ty_instrumented", feature = "ruff_instrumented"))]
|
||||
pub mod criterion;
|
||||
pub mod real_world_projects;
|
||||
|
||||
|
||||
51
crates/ruff_db/src/cancellation.rs
Normal file
51
crates/ruff_db/src/cancellation.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// Signals a [`CancellationToken`] that it should be canceled.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CancellationTokenSource {
|
||||
cancelled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Default for CancellationTokenSource {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl CancellationTokenSource {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cancelled: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_cancellation_requested(&self) -> bool {
|
||||
self.cancelled.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Creates a new token that uses this source.
|
||||
pub fn token(&self) -> CancellationToken {
|
||||
CancellationToken {
|
||||
cancelled: self.cancelled.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Requests cancellation for operations using this token.
|
||||
pub fn cancel(&self) {
|
||||
self.cancelled
|
||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
/// Token signals whether an operation should be canceled.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CancellationToken {
|
||||
cancelled: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl CancellationToken {
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
self.cancelled.load(std::sync::atomic::Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::{fmt::Formatter, path::Path, sync::Arc};
|
||||
use std::{borrow::Cow, fmt::Formatter, path::Path, sync::Arc};
|
||||
|
||||
use ruff_diagnostics::{Applicability, Fix};
|
||||
use ruff_source_file::{LineColumn, SourceCode, SourceFile};
|
||||
@@ -11,6 +11,7 @@ pub use self::render::{
|
||||
ceil_char_boundary,
|
||||
github::{DisplayGithubDiagnostics, GithubRenderer},
|
||||
};
|
||||
use crate::cancellation::CancellationToken;
|
||||
use crate::{Db, files::File};
|
||||
|
||||
mod render;
|
||||
@@ -410,11 +411,6 @@ impl Diagnostic {
|
||||
self.id().is_invalid_syntax()
|
||||
}
|
||||
|
||||
/// Returns the message body to display to the user.
|
||||
pub fn body(&self) -> &str {
|
||||
self.primary_message()
|
||||
}
|
||||
|
||||
/// Returns the message of the first sub-diagnostic with a `Help` severity.
|
||||
///
|
||||
/// Note that this is used as the fix title/suggestion for some of Ruff's output formats, but in
|
||||
@@ -1312,6 +1308,8 @@ pub struct DisplayDiagnosticConfig {
|
||||
show_fix_diff: bool,
|
||||
/// The lowest applicability that should be shown when reporting diagnostics.
|
||||
fix_applicability: Applicability,
|
||||
|
||||
cancellation_token: Option<CancellationToken>,
|
||||
}
|
||||
|
||||
impl DisplayDiagnosticConfig {
|
||||
@@ -1385,6 +1383,20 @@ impl DisplayDiagnosticConfig {
|
||||
pub fn fix_applicability(&self) -> Applicability {
|
||||
self.fix_applicability
|
||||
}
|
||||
|
||||
pub fn with_cancellation_token(
|
||||
mut self,
|
||||
token: Option<CancellationToken>,
|
||||
) -> DisplayDiagnosticConfig {
|
||||
self.cancellation_token = token;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_canceled(&self) -> bool {
|
||||
self.cancellation_token
|
||||
.as_ref()
|
||||
.is_some_and(|token| token.is_cancelled())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DisplayDiagnosticConfig {
|
||||
@@ -1398,6 +1410,7 @@ impl Default for DisplayDiagnosticConfig {
|
||||
show_fix_status: false,
|
||||
show_fix_diff: false,
|
||||
fix_applicability: Applicability::Safe,
|
||||
cancellation_token: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1474,6 +1487,15 @@ pub enum ConciseMessage<'a> {
|
||||
Custom(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> ConciseMessage<'a> {
|
||||
pub fn to_str(&self) -> Cow<'a, str> {
|
||||
match self {
|
||||
ConciseMessage::MainDiagnostic(s) | ConciseMessage::Custom(s) => Cow::Borrowed(s),
|
||||
ConciseMessage::Both { .. } => Cow::Owned(self.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ConciseMessage<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match *self {
|
||||
@@ -1490,6 +1512,16 @@ impl std::fmt::Display for ConciseMessage<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl serde::Serialize for ConciseMessage<'_> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.collect_str(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A diagnostic message string.
|
||||
///
|
||||
/// This is, for all intents and purposes, equivalent to a `Box<str>`.
|
||||
|
||||
@@ -52,7 +52,7 @@ impl AzureRenderer<'_> {
|
||||
f,
|
||||
"code={code};]{body}",
|
||||
code = diag.secondary_code_or_id(),
|
||||
body = diag.body(),
|
||||
body = diag.concise_message(),
|
||||
)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ impl<'a> ConciseRenderer<'a> {
|
||||
|
||||
let sep = fmt_styled(":", stylesheet.separator);
|
||||
for diag in diagnostics {
|
||||
if self.config.is_canceled() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(span) = diag.primary_span() {
|
||||
write!(
|
||||
f,
|
||||
|
||||
@@ -53,6 +53,10 @@ impl<'a> FullRenderer<'a> {
|
||||
.hyperlink(stylesheet.hyperlink);
|
||||
|
||||
for diag in diagnostics {
|
||||
if self.config.is_canceled() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let resolved = Resolved::new(self.resolver, diag, self.config);
|
||||
let renderable = resolved.to_renderable(self.config.context);
|
||||
for diag in renderable.diagnostics.iter() {
|
||||
|
||||
@@ -49,14 +49,26 @@ impl<'a> GithubRenderer<'a> {
|
||||
}
|
||||
.unwrap_or_default();
|
||||
|
||||
write!(
|
||||
f,
|
||||
",line={row},col={column},endLine={end_row},endColumn={end_column}::",
|
||||
row = start_location.line,
|
||||
column = start_location.column,
|
||||
end_row = end_location.line,
|
||||
end_column = end_location.column,
|
||||
)?;
|
||||
// GitHub Actions workflow commands have constraints on error annotations:
|
||||
// - `col` and `endColumn` cannot be set if `line` and `endLine` are different
|
||||
// See: https://github.com/astral-sh/ruff/issues/22074
|
||||
if start_location.line == end_location.line {
|
||||
write!(
|
||||
f,
|
||||
",line={row},col={column},endLine={end_row},endColumn={end_column}::",
|
||||
row = start_location.line,
|
||||
column = start_location.column,
|
||||
end_row = end_location.line,
|
||||
end_column = end_location.column,
|
||||
)?;
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
",line={row},endLine={end_row}::",
|
||||
row = start_location.line,
|
||||
end_row = end_location.line,
|
||||
)?;
|
||||
}
|
||||
|
||||
write!(
|
||||
f,
|
||||
@@ -75,7 +87,7 @@ impl<'a> GithubRenderer<'a> {
|
||||
write!(f, "{id}:", id = diagnostic.id())?;
|
||||
}
|
||||
|
||||
writeln!(f, " {}", diagnostic.body())?;
|
||||
writeln!(f, " {}", diagnostic.concise_message())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -98,7 +98,7 @@ impl Serialize for SerializedMessages<'_> {
|
||||
}
|
||||
fingerprints.insert(message_fingerprint);
|
||||
|
||||
let description = diagnostic.body();
|
||||
let description = diagnostic.concise_message();
|
||||
let check_name = diagnostic.secondary_code_or_id();
|
||||
let severity = match diagnostic.severity() {
|
||||
Severity::Info => "info",
|
||||
|
||||
@@ -6,7 +6,7 @@ use ruff_notebook::NotebookIndex;
|
||||
use ruff_source_file::{LineColumn, OneIndexed};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticSource, DisplayDiagnosticConfig};
|
||||
use crate::diagnostic::{ConciseMessage, Diagnostic, DiagnosticSource, DisplayDiagnosticConfig};
|
||||
|
||||
use super::FileResolver;
|
||||
|
||||
@@ -101,7 +101,7 @@ pub(super) fn diagnostic_to_json<'a>(
|
||||
JsonDiagnostic {
|
||||
code: diagnostic.secondary_code_or_id(),
|
||||
url: diagnostic.documentation_url(),
|
||||
message: diagnostic.body(),
|
||||
message: diagnostic.concise_message(),
|
||||
fix,
|
||||
cell: notebook_cell_index,
|
||||
location: start_location.map(JsonLocation::from),
|
||||
@@ -113,7 +113,7 @@ pub(super) fn diagnostic_to_json<'a>(
|
||||
JsonDiagnostic {
|
||||
code: diagnostic.secondary_code_or_id(),
|
||||
url: diagnostic.documentation_url(),
|
||||
message: diagnostic.body(),
|
||||
message: diagnostic.concise_message(),
|
||||
fix,
|
||||
cell: notebook_cell_index,
|
||||
location: Some(start_location.unwrap_or_default().into()),
|
||||
@@ -226,7 +226,7 @@ pub(crate) struct JsonDiagnostic<'a> {
|
||||
filename: Option<&'a str>,
|
||||
fix: Option<JsonFix<'a>>,
|
||||
location: Option<JsonLocation>,
|
||||
message: &'a str,
|
||||
message: ConciseMessage<'a>,
|
||||
noqa_row: Option<OneIndexed>,
|
||||
url: Option<&'a str>,
|
||||
}
|
||||
|
||||
@@ -56,17 +56,17 @@ impl<'a> JunitRenderer<'a> {
|
||||
start_location: location,
|
||||
} = diagnostic;
|
||||
let mut status = TestCaseStatus::non_success(NonSuccessKind::Failure);
|
||||
status.set_message(diagnostic.body());
|
||||
status.set_message(diagnostic.concise_message().to_str());
|
||||
|
||||
if let Some(location) = location {
|
||||
status.set_description(format!(
|
||||
"line {row}, col {col}, {body}",
|
||||
row = location.line,
|
||||
col = location.column,
|
||||
body = diagnostic.body()
|
||||
body = diagnostic.concise_message()
|
||||
));
|
||||
} else {
|
||||
status.set_description(diagnostic.body());
|
||||
status.set_description(diagnostic.concise_message().to_str());
|
||||
}
|
||||
|
||||
let code = diagnostic
|
||||
|
||||
@@ -55,7 +55,7 @@ impl PylintRenderer<'_> {
|
||||
f,
|
||||
"{path}:{row}: [{code}] {body}",
|
||||
path = filename,
|
||||
body = diagnostic.body()
|
||||
body = diagnostic.concise_message()
|
||||
)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use ruff_diagnostics::{Edit, Fix};
|
||||
use ruff_source_file::{LineColumn, SourceCode};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::diagnostic::Diagnostic;
|
||||
use crate::diagnostic::{ConciseMessage, Diagnostic};
|
||||
|
||||
use super::FileResolver;
|
||||
|
||||
@@ -76,7 +76,7 @@ fn diagnostic_to_rdjson<'a>(
|
||||
let edits = diagnostic.fix().map(Fix::edits).unwrap_or_default();
|
||||
|
||||
RdjsonDiagnostic {
|
||||
message: diagnostic.body(),
|
||||
message: diagnostic.concise_message(),
|
||||
location,
|
||||
code: RdjsonCode {
|
||||
value: diagnostic
|
||||
@@ -155,7 +155,7 @@ struct RdjsonDiagnostic<'a> {
|
||||
code: RdjsonCode<'a>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
location: Option<RdjsonLocation<'a>>,
|
||||
message: &'a str,
|
||||
message: ConciseMessage<'a>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
suggestions: Vec<RdjsonSuggestion<'a>>,
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
source: crates/ruff_db/src/diagnostic/render/github.rs
|
||||
expression: env.render_diagnostics(&diagnostics)
|
||||
---
|
||||
::error title=ty (invalid-syntax),file=/syntax_errors.py,line=1,col=15,endLine=2,endColumn=1::syntax_errors.py:1:15: invalid-syntax: Expected one or more symbol names after import
|
||||
::error title=ty (invalid-syntax),file=/syntax_errors.py,line=3,col=12,endLine=4,endColumn=1::syntax_errors.py:3:12: invalid-syntax: Expected ')', found newline
|
||||
::error title=ty (invalid-syntax),file=/syntax_errors.py,line=1,endLine=2::syntax_errors.py:1:15: invalid-syntax: Expected one or more symbol names after import
|
||||
::error title=ty (invalid-syntax),file=/syntax_errors.py,line=3,endLine=4::syntax_errors.py:3:12: invalid-syntax: Expected ')', found newline
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::hash::BuildHasherDefault;
|
||||
use std::num::NonZeroUsize;
|
||||
use ty_static::EnvVars;
|
||||
|
||||
pub mod cancellation;
|
||||
pub mod diagnostic;
|
||||
pub mod display;
|
||||
pub mod file_revision;
|
||||
|
||||
@@ -275,16 +275,16 @@ impl OsSystem {
|
||||
/// instead of at least one system call for each component between `path` and `prefix`.
|
||||
///
|
||||
/// However, using `canonicalize` to resolve the path's casing doesn't work in two cases:
|
||||
/// * if `path` is a symlink because `canonicalize` then returns the symlink's target and not the symlink's source path.
|
||||
/// * on Windows: If `path` is a mapped network drive because `canonicalize` then returns the UNC path
|
||||
/// (e.g. `Z:\` is mapped to `\\server\share` and `canonicalize` then returns `\\?\UNC\server\share`).
|
||||
/// * if `path` is a symlink, `canonicalize` returns the symlink's target and not the symlink's source path.
|
||||
/// * on Windows: If `path` is a mapped network drive, `canonicalize` returns the UNC path
|
||||
/// (e.g. `Z:\` is mapped to `\\server\share` and `canonicalize` returns `\\?\UNC\server\share`).
|
||||
///
|
||||
/// Symlinks and mapped network drives should be rare enough that this fast path is worth trying first,
|
||||
/// even if it comes at a cost for those rare use cases.
|
||||
fn path_exists_case_sensitive_fast(&self, path: &SystemPath) -> Option<bool> {
|
||||
// This is a more forgiving version of `dunce::simplified` that removes all `\\?\` prefixes on Windows.
|
||||
// We use this more forgiving version because we don't intend on using either path for anything other than comparison
|
||||
// and the prefix is only relevant when passing the path to other programs and its longer than 200 something
|
||||
// and the prefix is only relevant when passing the path to other programs and it's longer than 200 something
|
||||
// characters.
|
||||
fn simplify_ignore_verbatim(path: &SystemPath) -> &SystemPath {
|
||||
if cfg!(windows) {
|
||||
@@ -298,9 +298,7 @@ impl OsSystem {
|
||||
}
|
||||
}
|
||||
|
||||
let simplified = simplify_ignore_verbatim(path);
|
||||
|
||||
let Ok(canonicalized) = simplified.as_std_path().canonicalize() else {
|
||||
let Ok(canonicalized) = path.as_std_path().canonicalize() else {
|
||||
// The path doesn't exist or can't be accessed. The path doesn't exist.
|
||||
return Some(false);
|
||||
};
|
||||
@@ -309,12 +307,13 @@ impl OsSystem {
|
||||
// The original path is valid UTF8 but the canonicalized path isn't. This definitely suggests
|
||||
// that a symlink is involved. Fall back to the slow path.
|
||||
tracing::debug!(
|
||||
"Falling back to the slow case-sensitive path existence check because the canonicalized path of `{simplified}` is not valid UTF-8"
|
||||
"Falling back to the slow case-sensitive path existence check because the canonicalized path of `{path}` is not valid UTF-8"
|
||||
);
|
||||
return None;
|
||||
};
|
||||
|
||||
let simplified_canonicalized = simplify_ignore_verbatim(&canonicalized);
|
||||
let simplified = simplify_ignore_verbatim(path);
|
||||
|
||||
// Test if the paths differ by anything other than casing. If so, that suggests that
|
||||
// `path` pointed to a symlink (or some other none reversible path normalization happened).
|
||||
|
||||
@@ -14,6 +14,7 @@ license = { workspace = true }
|
||||
ty = { workspace = true }
|
||||
ty_project = { workspace = true, features = ["schemars"] }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ruff = { workspace = true }
|
||||
ruff_formatter = { workspace = true }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
//! Generate a Markdown-compatible listing of configuration options for `pyproject.toml`.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::{fmt::Write, path::PathBuf};
|
||||
|
||||
use anyhow::bail;
|
||||
use itertools::Itertools;
|
||||
use pretty_assertions::StrComparison;
|
||||
use std::{fmt::Write, path::PathBuf};
|
||||
|
||||
use ruff_options_metadata::{OptionField, OptionSet, OptionsMetadata, Visit};
|
||||
use ruff_python_trivia::textwrap;
|
||||
use ty_project::metadata::Options;
|
||||
|
||||
use crate::{
|
||||
@@ -165,62 +167,69 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parents: &[S
|
||||
let _ = writeln!(output, "**Default value**: `{}`", field.default);
|
||||
output.push('\n');
|
||||
let _ = writeln!(output, "**Type**: `{}`", field.value_type);
|
||||
|
||||
output.push('\n');
|
||||
output.push_str("**Example usage**:\n\n");
|
||||
output.push_str(&format_example(
|
||||
"pyproject.toml",
|
||||
&format_header(
|
||||
field.scope,
|
||||
field.example,
|
||||
parents,
|
||||
ConfigurationFile::PyprojectToml,
|
||||
),
|
||||
field.example,
|
||||
));
|
||||
output.push('\n');
|
||||
}
|
||||
|
||||
fn format_example(title: &str, header: &str, content: &str) -> String {
|
||||
if header.is_empty() {
|
||||
format!("```toml title=\"{title}\"\n{content}\n```\n",)
|
||||
} else {
|
||||
format!("```toml title=\"{title}\"\n{header}\n{content}\n```\n",)
|
||||
for configuration_file in [ConfigurationFile::PyprojectToml, ConfigurationFile::TyToml] {
|
||||
let (header, example) =
|
||||
format_snippet(field.scope, field.example, parents, configuration_file);
|
||||
output.push_str(&format_tab(configuration_file.name(), &header, &example));
|
||||
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
|
||||
fn format_tab(tab_name: &str, header: &str, content: &str) -> String {
|
||||
let header = if header.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("\n {header}")
|
||||
};
|
||||
format!(
|
||||
"=== \"{}\"\n\n ```toml{}\n{}\n ```\n",
|
||||
tab_name,
|
||||
header,
|
||||
textwrap::indent(content, " ")
|
||||
)
|
||||
}
|
||||
/// Format the TOML header for the example usage for a given option.
|
||||
///
|
||||
/// For example: `[tool.ruff.format]` or `[tool.ruff.lint.isort]`.
|
||||
fn format_header(
|
||||
/// For example: `[tool.ty.rules]`.
|
||||
fn format_snippet<'a>(
|
||||
scope: Option<&str>,
|
||||
example: &str,
|
||||
example: &'a str,
|
||||
parents: &[Set],
|
||||
configuration: ConfigurationFile,
|
||||
) -> String {
|
||||
let tool_parent = match configuration {
|
||||
ConfigurationFile::PyprojectToml => Some("tool.ty"),
|
||||
ConfigurationFile::TyToml => None,
|
||||
};
|
||||
) -> (String, Cow<'a, str>) {
|
||||
let mut example = Cow::Borrowed(example);
|
||||
|
||||
let header = tool_parent
|
||||
let header = configuration
|
||||
.parent_table()
|
||||
.into_iter()
|
||||
.chain(parents.iter().filter_map(|parent| parent.name()))
|
||||
.chain(scope)
|
||||
.join(".");
|
||||
|
||||
// Rewrite examples starting with `[tool.ty]` or `[[tool.ty]]` to their `ty.toml` equivalent.
|
||||
if matches!(configuration, ConfigurationFile::TyToml) {
|
||||
example = example.replace("[tool.ty.", "[").into();
|
||||
}
|
||||
|
||||
// Ex) `[[tool.ty.xx]]`
|
||||
if example.starts_with(&format!("[[{header}")) {
|
||||
return String::new();
|
||||
return (String::new(), example);
|
||||
}
|
||||
|
||||
// Ex) `[tool.ty.rules]`
|
||||
if example.starts_with(&format!("[{header}")) {
|
||||
return String::new();
|
||||
return (String::new(), example);
|
||||
}
|
||||
|
||||
if header.is_empty() {
|
||||
String::new()
|
||||
(String::new(), example)
|
||||
} else {
|
||||
format!("[{header}]")
|
||||
(format!("[{header}]"), example)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,10 +252,25 @@ impl Visit for CollectOptionsVisitor {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum ConfigurationFile {
|
||||
PyprojectToml,
|
||||
#[expect(dead_code)]
|
||||
TyToml,
|
||||
}
|
||||
|
||||
impl ConfigurationFile {
|
||||
const fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::PyprojectToml => "pyproject.toml",
|
||||
Self::TyToml => "ty.toml",
|
||||
}
|
||||
}
|
||||
|
||||
const fn parent_table(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::PyprojectToml => Some("tool.ty"),
|
||||
Self::TyToml => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -52,7 +52,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
}
|
||||
|
||||
fn generate_markdown() -> String {
|
||||
let registry = ty_python_semantic::default_lint_registry();
|
||||
let registry = ty_python_types::default_lint_registry();
|
||||
|
||||
let mut output = String::new();
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ ruff_linter = { workspace = true }
|
||||
ruff_macros = { workspace = true }
|
||||
ruff_python_ast = { workspace = true }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true, optional = true }
|
||||
|
||||
@@ -3,7 +3,7 @@ use ruff_python_ast::visitor::source_order::{
|
||||
SourceOrderVisitor, walk_expr, walk_module, walk_stmt,
|
||||
};
|
||||
use ruff_python_ast::{self as ast, Expr, Mod, Stmt};
|
||||
use ty_python_semantic::ModuleName;
|
||||
use ty_module_resolver::ModuleName;
|
||||
|
||||
/// Collect all imports for a given Python file.
|
||||
#[derive(Default, Debug)]
|
||||
|
||||
@@ -7,11 +7,13 @@ use ruff_db::files::{File, Files};
|
||||
use ruff_db::system::{OsSystem, System, SystemPathBuf};
|
||||
use ruff_db::vendored::{VendoredFileSystem, VendoredFileSystemBuilder};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_module_resolver::{SearchPathSettings, SearchPaths};
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{
|
||||
Db, Program, ProgramSettings, PythonEnvironment, PythonPlatform, PythonVersionSource,
|
||||
PythonVersionWithSource, SearchPathSettings, SysPrefixPathOrigin, default_lint_registry,
|
||||
AnalysisSettings, Db, Program, ProgramSettings, PythonEnvironment, PythonPlatform,
|
||||
PythonVersionSource, PythonVersionWithSource, SysPrefixPathOrigin,
|
||||
};
|
||||
use ty_python_types::default_lint_registry;
|
||||
|
||||
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
|
||||
let mut builder = VendoredFileSystemBuilder::new(CompressionMethod::Stored);
|
||||
@@ -26,6 +28,7 @@ pub struct ModuleDb {
|
||||
files: Files,
|
||||
system: OsSystem,
|
||||
rule_selection: Arc<RuleSelection>,
|
||||
analysis_settings: Arc<AnalysisSettings>,
|
||||
}
|
||||
|
||||
impl ModuleDb {
|
||||
@@ -85,6 +88,13 @@ impl SourceDb for ModuleDb {
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl ty_module_resolver::Db for ModuleDb {
|
||||
fn search_paths(&self) -> &SearchPaths {
|
||||
Program::get(self).search_paths(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for ModuleDb {
|
||||
fn should_check_file(&self, file: File) -> bool {
|
||||
@@ -102,6 +112,10 @@ impl Db for ModuleDb {
|
||||
fn verbose(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
&self.analysis_settings
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ruff_db::files::{File, FilePath, system_path_to_file};
|
||||
use ruff_db::system::SystemPath;
|
||||
use ty_python_semantic::{
|
||||
use ty_module_resolver::{
|
||||
ModuleName, resolve_module, resolve_module_confident, resolve_real_module,
|
||||
resolve_real_module_confident,
|
||||
};
|
||||
|
||||
@@ -197,7 +197,7 @@ impl Display for RuleCodeAndBody<'_> {
|
||||
f,
|
||||
"{fix}{body}",
|
||||
fix = format_args!("[{}] ", "*".cyan()),
|
||||
body = self.message.body(),
|
||||
body = self.message.concise_message(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -208,14 +208,14 @@ impl Display for RuleCodeAndBody<'_> {
|
||||
f,
|
||||
"{code} {body}",
|
||||
code = code.red().bold(),
|
||||
body = self.message.body(),
|
||||
body = self.message.concise_message(),
|
||||
)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{code}: {body}",
|
||||
code = self.message.id().as_str().red().bold(),
|
||||
body = self.message.body(),
|
||||
body = self.message.concise_message(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ impl<'a> SarifResult<'a> {
|
||||
rule_id: RuleCode::from(diagnostic),
|
||||
level: "error".to_string(),
|
||||
message: SarifMessage {
|
||||
text: diagnostic.body().to_string(),
|
||||
text: diagnostic.concise_message().to_string(),
|
||||
},
|
||||
fixes: Self::fix(diagnostic, &uri).into_iter().collect(),
|
||||
locations: vec![SarifLocation {
|
||||
|
||||
@@ -243,7 +243,7 @@ fn to_lsp_diagnostic(
|
||||
) -> (usize, lsp_types::Diagnostic) {
|
||||
let diagnostic_range = diagnostic.range().unwrap_or_default();
|
||||
let name = diagnostic.name();
|
||||
let body = diagnostic.body().to_string();
|
||||
let body = diagnostic.concise_message().to_string();
|
||||
let fix = diagnostic.fix();
|
||||
let suggestion = diagnostic.first_help_text();
|
||||
let code = diagnostic.secondary_code();
|
||||
|
||||
@@ -241,7 +241,7 @@ impl Workspace {
|
||||
let range = msg.range().unwrap_or_default();
|
||||
ExpandedMessage {
|
||||
code: msg.secondary_code_or_id().to_string(),
|
||||
message: msg.body().to_string(),
|
||||
message: msg.concise_message().to_string(),
|
||||
start_location: source_code
|
||||
.source_location(range.start(), self.position_encoding)
|
||||
.into(),
|
||||
|
||||
@@ -42,6 +42,7 @@ wild = { workspace = true }
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing"] }
|
||||
ruff_python_trivia = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
|
||||
dunce = { workspace = true }
|
||||
insta = { workspace = true, features = ["filters"] }
|
||||
|
||||
377
crates/ty/docs/configuration.md
generated
377
crates/ty/docs/configuration.md
generated
@@ -20,11 +20,59 @@ Valid severities are:
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "warn"
|
||||
division-by-zero = "ignore"
|
||||
```
|
||||
=== "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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -47,10 +95,19 @@ configuration setting.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
extra-paths = ["./shared/my-search-path"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -78,10 +135,19 @@ This option can be used to point to virtual or system Python environments.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python = "./custom-venv-location/.venv"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -105,11 +171,21 @@ If no platform is specified, ty will use the current platform:
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
# Tailor type stubs and conditionalized type definitions to windows.
|
||||
python-platform = "win32"
|
||||
```
|
||||
=== "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"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -139,10 +215,19 @@ to reflect the differing contents of the standard library across Python versions
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -167,11 +252,21 @@ it will also be included in the first party search path.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
# Multiple directories (priority order)
|
||||
root = ["./src", "./lib", "./vendor"]
|
||||
```
|
||||
=== "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"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -187,10 +282,19 @@ bundled as a zip file in the binary
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
typeshed = "/path/to/custom/typeshed"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -240,15 +344,29 @@ If not specified, defaults to `[]` (excludes no files).
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[[tool.ty.overrides]]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
=== "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
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -268,13 +386,25 @@ If not specified, defaults to `["**"]` (matches all files).
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[[tool.ty.overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[[tool.ty.overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[[overrides]]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -292,13 +422,25 @@ severity levels or disable them entirely.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[[tool.ty.overrides]]
|
||||
include = ["src"]
|
||||
=== "pyproject.toml"
|
||||
|
||||
[tool.ty.overrides.rules]
|
||||
possibly-unresolved-reference = "ignore"
|
||||
```
|
||||
```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"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -358,15 +500,29 @@ to re-include `dist` use `exclude = ["!dist"]`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.src]
|
||||
exclude = [
|
||||
"generated",
|
||||
"*.proto",
|
||||
"tests/fixtures/**",
|
||||
"!tests/fixtures/important.py" # Include this one file
|
||||
]
|
||||
```
|
||||
=== "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
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -399,13 +555,25 @@ matches `<project_root>/src` and not `<project_root>/test/src`).
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
include = [
|
||||
"src",
|
||||
"tests",
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -421,10 +589,19 @@ Enabled by default.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
respect-ignore-files = false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -450,10 +627,19 @@ it will also be included in the first party search path.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.src]
|
||||
root = "./app"
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.src]
|
||||
root = "./app"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[src]
|
||||
root = "./app"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -471,11 +657,21 @@ Defaults to `false`.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.terminal]
|
||||
# Error if ty emits any warning-level diagnostics.
|
||||
error-on-warning = true
|
||||
```
|
||||
=== "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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -491,10 +687,19 @@ Defaults to `full`.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml title="pyproject.toml"
|
||||
[tool.ty.terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
=== "pyproject.toml"
|
||||
|
||||
```toml
|
||||
[tool.ty.terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
|
||||
=== "ty.toml"
|
||||
|
||||
```toml
|
||||
[terminal]
|
||||
output-format = "concise"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
254
crates/ty/docs/rules.md
generated
254
crates/ty/docs/rules.md
generated
@@ -8,7 +8,7 @@
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ambiguous-protocol-member" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L511" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L538" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class SubProto(BaseProto, Protocol):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20byte-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L36" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L36" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-non-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L135" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L137" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -98,13 +98,44 @@ Calling a non-callable object will raise a `TypeError` at runtime.
|
||||
4() # TypeError: 'int' object is not callable
|
||||
```
|
||||
|
||||
## `call-top-callable`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.7">0.0.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20call-top-callable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L155" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for calls to objects typed as `Top[Callable[..., T]]` (the infinite union of all
|
||||
callable types with return type `T`).
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
When an object is narrowed to `Top[Callable[..., object]]` (e.g., via `callable(x)` or
|
||||
`isinstance(x, Callable)`), we know the object is callable, but we don't know its
|
||||
precise signature. This type represents the set of all possible callable types
|
||||
(including, e.g., functions that take no arguments and functions that require arguments),
|
||||
so no specific set of arguments can be guaranteed to be valid.
|
||||
|
||||
**Examples**
|
||||
|
||||
```python
|
||||
def f(x: object):
|
||||
if callable(x):
|
||||
x() # error: We know `x` is callable, but not what arguments it accepts
|
||||
```
|
||||
|
||||
## `conflicting-argument-forms`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-argument-forms" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L179" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L206" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -136,7 +167,7 @@ f(int) # error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-declarations" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L205" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L232" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -167,7 +198,7 @@ a = 1
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20conflicting-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L230" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L257" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -199,7 +230,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-class-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L256" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L283" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -231,7 +262,7 @@ class B(A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20cyclic-type-alias-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L282" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L309" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -259,7 +290,7 @@ type B = A
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.16">0.0.1-alpha.16</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20deprecated" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L326" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L353" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -286,7 +317,7 @@ old_func() # emits [deprecated] diagnostic
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20division-by-zero" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L304" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L331" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -315,7 +346,7 @@ false positives it can produce.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L347" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L374" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -342,7 +373,7 @@ class B(A, A): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20duplicate-kw-only" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L368" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L395" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -380,11 +411,24 @@ class A: # Crash at runtime
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20escape-character-in-forward-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L120" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L154" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
TODO #14889
|
||||
**What it does**
|
||||
|
||||
Checks for forward annotations that contain escape characters.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
Static analysis tools like ty can't analyze type annotations that contain escape characters.
|
||||
|
||||
**Example**
|
||||
|
||||
|
||||
```python
|
||||
def foo() -> "intt\b": ...
|
||||
```
|
||||
|
||||
## `fstring-type-annotation`
|
||||
|
||||
@@ -392,7 +436,7 @@ TODO #14889
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20fstring-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L11" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L11" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -423,7 +467,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20ignore-comment-unknown-rule" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L47" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L49" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -454,7 +498,7 @@ a = 20 / 0 # ty: ignore[division-by-zero]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20implicit-concatenated-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L86" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L86" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -485,7 +529,7 @@ def test(): -> "Literal[5]":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20inconsistent-mro" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L594" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L621" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -515,7 +559,7 @@ class C(A, B): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20index-out-of-bounds" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L618" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L645" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -541,7 +585,7 @@ t[3] # IndexError: tuple index out of range
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.12">0.0.1-alpha.12</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20instance-layout-conflict" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L400" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L427" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -630,7 +674,7 @@ an atypical memory layout.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-argument-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L672" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L699" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -657,7 +701,7 @@ func("foo") # error: [invalid-argument-type]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-assignment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L712" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L739" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -685,7 +729,7 @@ a: int = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-attribute-access" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2015" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2042" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -719,7 +763,7 @@ C.instance_var = 3 # error: Cannot assign to instance variable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-await" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L734" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L761" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -755,7 +799,7 @@ asyncio.run(main())
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L764" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -779,7 +823,7 @@ class A(42): ... # error: [invalid-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-context-manager" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L815" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L842" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -806,7 +850,7 @@ with 1:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-declaration" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L836" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L863" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -835,7 +879,7 @@ a: str
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-exception-caught" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L859" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L886" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -879,7 +923,7 @@ except ZeroDivisionError:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.28">0.0.1-alpha.28</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-explicit-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1685" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1712" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -921,7 +965,7 @@ class D(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.35">0.0.1-alpha.35</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-frozen-dataclass-subclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2241" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2268" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -965,7 +1009,7 @@ class NonFrozenChild(FrozenBase): # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-generic-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L895" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L922" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1003,7 +1047,7 @@ class D(Generic[U, T]): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L72" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L74" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1033,7 +1077,7 @@ a = 20 / 0 # type: ignore
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.17">0.0.1-alpha.17</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L639" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L666" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1072,7 +1116,7 @@ carol = Person(name="Carol", age=25) # typo!
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-legacy-type-variable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L926" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L953" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1107,7 +1151,7 @@ def f(t: TypeVar("U")): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-metaclass" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1023" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1141,7 +1185,7 @@ class B(metaclass=f): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-method-override" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2143" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2170" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1248,7 +1292,7 @@ Correct use of `@override` is enforced by ty's `invalid-explicit-override` rule.
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.19">0.0.1-alpha.19</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-named-tuple" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L546" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L573" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1302,7 +1346,7 @@ AttributeError: Cannot overwrite NamedTuple attribute _asdict
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/1.0.0">1.0.0</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-newtype" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L999" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1026" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1332,7 +1376,7 @@ Baz = NewType("Baz", int | str) # error: invalid base for `typing.NewType`
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1050" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1077" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1382,7 +1426,7 @@ def foo(x: int) -> int: ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-parameter-default" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1149" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1176" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1408,7 +1452,7 @@ def f(a: int = ''): ...
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-paramspec" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L954" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L981" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1439,7 +1483,7 @@ P2 = ParamSpec("S2") # error: ParamSpec name must match the variable it's assig
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-protocol" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L482" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L509" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1473,7 +1517,7 @@ TypeError: Protocols can only inherit from other protocols, got <class 'int'>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-raise" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1169" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1196" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1522,7 +1566,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-return-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L693" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L720" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1547,7 +1591,7 @@ def func() -> int:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-super-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1212" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1239" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1593,11 +1637,49 @@ super(B, A) # error: `A` does not satisfy `issubclass(A, B)`
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-syntax-in-forward-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L111" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
TODO #14889
|
||||
**What it does**
|
||||
|
||||
Checks for string-literal annotations where the string cannot be
|
||||
parsed as a Python expression.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
Type annotations are expected to be Python expressions that
|
||||
describe the expected type of a variable, parameter, attribute or
|
||||
`return` statement.
|
||||
|
||||
Type annotations are permitted to be string-literal expressions, in
|
||||
order to enable forward references to names not yet defined.
|
||||
However, it must be possible to parse the contents of that string
|
||||
literal as a normal Python expression.
|
||||
|
||||
**Example**
|
||||
|
||||
|
||||
```python
|
||||
def foo() -> "intstance of C":
|
||||
return 42
|
||||
|
||||
class C: ...
|
||||
```
|
||||
|
||||
Use instead:
|
||||
|
||||
```python
|
||||
def foo() -> "C":
|
||||
return 42
|
||||
|
||||
class C: ...
|
||||
```
|
||||
|
||||
**References**
|
||||
|
||||
- [Typing spec: The meaning of annotations](https://typing.python.org/en/latest/spec/annotations.html#the-meaning-of-annotations)
|
||||
- [Typing spec: String annotations](https://typing.python.org/en/latest/spec/annotations.html#string-annotations)
|
||||
|
||||
## `invalid-type-alias-type`
|
||||
|
||||
@@ -1605,7 +1687,7 @@ TODO #14889
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.6">0.0.1-alpha.6</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-alias-type" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L978" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1005" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1632,7 +1714,7 @@ NewAlias = TypeAliasType(get_name(), int) # error: TypeAliasType name mus
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1444" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1471" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1679,7 +1761,7 @@ Bar[int] # error: too few arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-checking-constant" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1251" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1278" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1709,7 +1791,7 @@ TYPE_CHECKING = ''
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-form" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1275" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1302" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1739,7 +1821,7 @@ b: Annotated[int] # `Annotated` expects at least two arguments
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1327" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1354" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1773,7 +1855,7 @@ f(10) # Error
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.11">0.0.1-alpha.11</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-guard-definition" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1299" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1326" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1807,7 +1889,7 @@ class C:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20invalid-type-variable-constraints" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1355" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1382" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1842,7 +1924,7 @@ T = TypeVar('T', bound=str) # valid bound TypeVar
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1384" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1411" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1867,7 +1949,7 @@ func() # TypeError: func() missing 1 required positional argument: 'x'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.20">0.0.1-alpha.20</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20missing-typed-dict-key" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2116" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2143" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1900,7 +1982,7 @@ alice["age"] # KeyError
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20no-matching-overload" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1403" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1430" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1929,7 +2011,7 @@ func("string") # error: [no-matching-overload]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1426" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1953,7 +2035,7 @@ Subscripting an object that does not support it will raise a `TypeError` at runt
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-iterable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1485" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1512" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -1979,7 +2061,7 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.29">0.0.1-alpha.29</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20override-of-final-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1658" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1685" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2012,7 +2094,7 @@ class B(A):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20parameter-already-assigned" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1536" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1563" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2039,7 +2121,7 @@ f(1, x=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20positional-only-parameter-as-kwarg" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1869" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1896" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2066,7 +2148,7 @@ f(x=1) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1557" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1584" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2094,7 +2176,7 @@ A.c # AttributeError: type object 'A' has no attribute 'c'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-implicit-call" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L153" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L180" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2126,7 +2208,7 @@ A()[0] # TypeError: 'A' object is not subscriptable
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-missing-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1579" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1606" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2163,7 +2245,7 @@ from module import a # ImportError: cannot import name 'a' from 'module'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20possibly-unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1609" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1636" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2196,7 +2278,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20raw-string-type-annotation" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fstring_annotation.rs#L61" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fstring_annotation.rs#L61" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2227,7 +2309,7 @@ def test(): -> "int":
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20redundant-cast" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2043" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2070" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2254,7 +2336,7 @@ cast(int, f()) # Redundant
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20static-assert-error" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1991" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2018" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2284,7 +2366,7 @@ static_assert(int(2.0 * 3.0) == 6) # error: does not have a statically known tr
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20subclass-of-final-class" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1635" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1662" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2313,7 +2395,7 @@ class B(A): ... # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Preview (since <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.30">0.0.1-alpha.30</a>) ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20super-call-in-named-tuple-method" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1803" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1830" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2347,7 +2429,7 @@ class F(NamedTuple):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20too-many-positional-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1743" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1770" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2374,7 +2456,7 @@ f("foo") # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20type-assertion-failure" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1721" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1748" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2402,7 +2484,7 @@ def _(x: int):
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unavailable-implicit-super-arguments" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1764" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1791" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2448,7 +2530,7 @@ class A:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20undefined-reveal" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1830" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1857" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2472,7 +2554,7 @@ reveal_type(1) # NameError: name 'reveal_type' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unknown-argument" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1848" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1875" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2499,7 +2581,7 @@ f(x=1, y=2) # Error raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-attribute" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1890" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1917" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2527,7 +2609,7 @@ A().foo # AttributeError: 'A' object has no attribute 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.15">0.0.1-alpha.15</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-global" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2064" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L2091" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2585,7 +2667,7 @@ def g():
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-import" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1912" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1939" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2610,7 +2692,7 @@ import foo # ModuleNotFoundError: No module named 'foo'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unresolved-reference" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1931" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1958" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2635,7 +2717,7 @@ print(x) # NameError: name 'x' is not defined
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.7">0.0.1-alpha.7</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-base" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L782" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L809" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2674,7 +2756,7 @@ class D(C): ... # error: [unsupported-base]
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-bool-conversion" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1505" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1532" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2711,7 +2793,7 @@ b1 < b2 < b1 # exception raised here
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unsupported-operator" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1950" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1977" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2739,7 +2821,7 @@ A() + A() # TypeError: unsupported operand type(s) for +: 'A' and 'A'
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'ignore'."><code>ignore</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20unused-ignore-comment" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L22" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Fsuppression.rs#L24" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2770,7 +2852,7 @@ a = 20 / 2
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'warn'."><code>warn</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.22">0.0.1-alpha.22</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20useless-overload-body" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1093" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1120" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
@@ -2833,7 +2915,7 @@ def foo(x: int | str) -> int | str:
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20zero-stepsize-in-slice" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1972" target="_blank">View source</a>
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_types%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1999" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ use ty_static::EnvVars;
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::process::{ExitCode, Termination};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use anyhow::Result;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::args::{CheckCommand, Command, TerminalColor};
|
||||
use crate::logging::{VerbosityLevel, setup_tracing};
|
||||
@@ -22,6 +22,7 @@ use clap::{CommandFactory, Parser};
|
||||
use colored::Colorize;
|
||||
use crossbeam::channel as crossbeam_channel;
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use ruff_db::cancellation::{CancellationToken, CancellationTokenSource};
|
||||
use ruff_db::diagnostic::{
|
||||
Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics, Severity,
|
||||
};
|
||||
@@ -121,7 +122,9 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
|
||||
let force_exclude = args.force_exclude();
|
||||
|
||||
let mut project_metadata = match &config_file {
|
||||
Some(config_file) => ProjectMetadata::from_config_file(config_file.clone(), &system)?,
|
||||
Some(config_file) => {
|
||||
ProjectMetadata::from_config_file(config_file.clone(), &project_path, &system)?
|
||||
}
|
||||
None => ProjectMetadata::discover(&project_path, &system)?,
|
||||
};
|
||||
|
||||
@@ -225,6 +228,11 @@ struct MainLoop {
|
||||
printer: Printer,
|
||||
|
||||
project_options_overrides: ProjectOptionsOverrides,
|
||||
|
||||
/// Cancellation token that gets set by Ctrl+C.
|
||||
/// Used for long-running operations on the main thread. Operations on background threads
|
||||
/// use Salsa's cancellation mechanism.
|
||||
cancellation_token: CancellationToken,
|
||||
}
|
||||
|
||||
impl MainLoop {
|
||||
@@ -234,6 +242,9 @@ impl MainLoop {
|
||||
) -> (Self, MainLoopCancellationToken) {
|
||||
let (sender, receiver) = crossbeam_channel::bounded(10);
|
||||
|
||||
let cancellation_token_source = CancellationTokenSource::new();
|
||||
let cancellation_token = cancellation_token_source.token();
|
||||
|
||||
(
|
||||
Self {
|
||||
sender: sender.clone(),
|
||||
@@ -241,8 +252,12 @@ impl MainLoop {
|
||||
watcher: None,
|
||||
project_options_overrides,
|
||||
printer,
|
||||
cancellation_token,
|
||||
},
|
||||
MainLoopCancellationToken {
|
||||
sender,
|
||||
source: cancellation_token_source,
|
||||
},
|
||||
MainLoopCancellationToken { sender },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -314,6 +329,7 @@ impl MainLoop {
|
||||
let display_config = DisplayDiagnosticConfig::default()
|
||||
.format(terminal_settings.output_format.into())
|
||||
.color(colored::control::SHOULD_COLORIZE.should_colorize())
|
||||
.with_cancellation_token(Some(self.cancellation_token.clone()))
|
||||
.show_fix_diff(true);
|
||||
|
||||
if check_revision == revision {
|
||||
@@ -357,19 +373,21 @@ impl MainLoop {
|
||||
)?;
|
||||
}
|
||||
|
||||
if is_human_readable {
|
||||
writeln!(
|
||||
self.printer.stream_for_failure_summary(),
|
||||
"Found {} diagnostic{}",
|
||||
diagnostics_count,
|
||||
if diagnostics_count > 1 { "s" } else { "" }
|
||||
)?;
|
||||
}
|
||||
if !self.cancellation_token.is_cancelled() {
|
||||
if is_human_readable {
|
||||
writeln!(
|
||||
self.printer.stream_for_failure_summary(),
|
||||
"Found {} diagnostic{}",
|
||||
diagnostics_count,
|
||||
if diagnostics_count > 1 { "s" } else { "" }
|
||||
)?;
|
||||
}
|
||||
|
||||
if exit_status.is_internal_error() {
|
||||
tracing::warn!(
|
||||
"A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details."
|
||||
);
|
||||
if exit_status.is_internal_error() {
|
||||
tracing::warn!(
|
||||
"A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self.watcher.is_none() {
|
||||
@@ -496,10 +514,12 @@ impl ty_project::ProgressReporter for IndicatifReporter {
|
||||
#[derive(Debug)]
|
||||
struct MainLoopCancellationToken {
|
||||
sender: crossbeam_channel::Sender<MainLoopMessage>,
|
||||
source: CancellationTokenSource,
|
||||
}
|
||||
|
||||
impl MainLoopCancellationToken {
|
||||
fn stop(self) {
|
||||
self.source.cancel();
|
||||
self.sender.send(MainLoopMessage::Exit).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
43
crates/ty/tests/cli/analysis_options.rs
Normal file
43
crates/ty/tests/cli/analysis_options.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use insta_cmd::assert_cmd_snapshot;
|
||||
|
||||
use crate::CliTest;
|
||||
|
||||
/// ty ignores `type: ignore` comments when setting `respect-type-ignore-comments=false`
|
||||
#[test]
|
||||
fn respect_type_ignore_comments_is_turned_off() -> anyhow::Result<()> {
|
||||
let case = CliTest::with_file(
|
||||
"test.py",
|
||||
r#"
|
||||
y = a + 5 # type: ignore
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Assert that there's an `unresolved-reference` diagnostic (error).
|
||||
assert_cmd_snapshot!(case.command(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
All checks passed!
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
||||
assert_cmd_snapshot!(case.command().arg("--config").arg("analysis.respect-type-ignore-comments=false"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
error[unresolved-reference]: Name `a` used when not defined
|
||||
--> test.py:2:5
|
||||
|
|
||||
2 | y = a + 5 # type: ignore
|
||||
| ^
|
||||
|
|
||||
info: rule `unresolved-reference` is enabled by default
|
||||
|
||||
Found 1 diagnostic
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -133,7 +133,7 @@ fn cli_config_args_invalid_option() -> anyhow::Result<()> {
|
||||
|
|
||||
1 | bad-option=true
|
||||
| ^^^^^^^^^^
|
||||
unknown field `bad-option`, expected one of `environment`, `src`, `rules`, `terminal`, `overrides`
|
||||
unknown field `bad-option`, expected one of `environment`, `src`, `rules`, `terminal`, `analysis`, `overrides`
|
||||
|
||||
|
||||
Usage: ty <COMMAND>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod analysis_options;
|
||||
mod config_option;
|
||||
mod exit_code;
|
||||
mod file_selection;
|
||||
@@ -658,6 +659,8 @@ fn gitlab_diagnostics() -> anyhow::Result<()> {
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
from typing_extensions import reveal_type
|
||||
reveal_type('str'.lower()) # [revealed-type]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -708,6 +711,25 @@ fn gitlab_diagnostics() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"check_name": "revealed-type",
|
||||
"description": "revealed-type: Revealed type: `LiteralString`",
|
||||
"severity": "info",
|
||||
"fingerprint": "[FINGERPRINT]",
|
||||
"location": {
|
||||
"path": "test.py",
|
||||
"positions": {
|
||||
"begin": {
|
||||
"line": 5,
|
||||
"column": 13
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"column": 26
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
----- stderr -----
|
||||
@@ -723,6 +745,8 @@ fn github_diagnostics() -> anyhow::Result<()> {
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
from typing_extensions import reveal_type
|
||||
reveal_type('str'.lower()) # [revealed-type]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -732,6 +756,7 @@ fn github_diagnostics() -> anyhow::Result<()> {
|
||||
----- stdout -----
|
||||
::warning title=ty (unresolved-reference),file=<temp_dir>/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined
|
||||
::error title=ty (non-subscriptable),file=<temp_dir>/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
::notice title=ty (revealed-type),file=<temp_dir>/test.py,line=5,col=13,endLine=5,endColumn=26::test.py:5:13: revealed-type: Revealed type: `LiteralString`
|
||||
|
||||
----- stderr -----
|
||||
");
|
||||
|
||||
@@ -10,12 +10,13 @@ use ruff_db::system::{
|
||||
OsSystem, System, SystemPath, SystemPathBuf, UserConfigDirectoryOverrideGuard, file_time_now,
|
||||
};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_module_resolver::{Module, ModuleName, resolve_module_confident};
|
||||
use ty_project::metadata::options::{EnvironmentOptions, Options, ProjectOptionsOverrides};
|
||||
use ty_project::metadata::pyproject::{PyProject, Tool};
|
||||
use ty_project::metadata::value::{RangedValue, RelativePathBuf};
|
||||
use ty_project::watch::{ChangeEvent, ProjectWatcher, directory_watcher};
|
||||
use ty_project::{Db, ProjectDatabase, ProjectMetadata};
|
||||
use ty_python_semantic::{Module, ModuleName, PythonPlatform, resolve_module_confident};
|
||||
use ty_python_semantic::PythonPlatform;
|
||||
|
||||
struct TestCase {
|
||||
db: ProjectDatabase,
|
||||
@@ -1019,7 +1020,7 @@ fn search_path() -> anyhow::Result<()> {
|
||||
let site_packages = case.root_path().join("site_packages");
|
||||
|
||||
assert_eq!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("a").unwrap()),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("a").unwrap()),
|
||||
None
|
||||
);
|
||||
|
||||
@@ -1192,7 +1193,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
|
||||
|
||||
// Unset the custom typeshed directory.
|
||||
assert_eq!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("os").unwrap()),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("os").unwrap()),
|
||||
None
|
||||
);
|
||||
|
||||
@@ -1207,7 +1208,7 @@ fn changed_versions_file() -> anyhow::Result<()> {
|
||||
|
||||
case.apply_changes(changes, None);
|
||||
|
||||
assert!(resolve_module_confident(case.db(), &ModuleName::new("os").unwrap()).is_some());
|
||||
assert!(resolve_module_confident(case.db(), &ModuleName::new_static("os").unwrap()).is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1874,11 +1875,11 @@ fn rename_files_casing_only() -> anyhow::Result<()> {
|
||||
let mut case = setup([("lib.py", "class Foo: ...")])?;
|
||||
|
||||
assert!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("lib").unwrap()).is_some(),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("lib").unwrap()).is_some(),
|
||||
"Expected `lib` module to exist."
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("Lib").unwrap()),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("Lib").unwrap()),
|
||||
None,
|
||||
"Expected `Lib` module not to exist"
|
||||
);
|
||||
@@ -1911,13 +1912,13 @@ fn rename_files_casing_only() -> anyhow::Result<()> {
|
||||
|
||||
// Resolving `lib` should now fail but `Lib` should now succeed
|
||||
assert_eq!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("lib").unwrap()),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("lib").unwrap()),
|
||||
None,
|
||||
"Expected `lib` module to no longer exist."
|
||||
);
|
||||
|
||||
assert!(
|
||||
resolve_module_confident(case.db(), &ModuleName::new("Lib").unwrap()).is_some(),
|
||||
resolve_module_confident(case.db(), &ModuleName::new_static("Lib").unwrap()).is_some(),
|
||||
"Expected `Lib` module to exist"
|
||||
);
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ license.workspace = true
|
||||
[dependencies]
|
||||
ruff_db = { workspace = true }
|
||||
ruff_python_ast = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
|
||||
ordermap = { workspace = true }
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ use std::{collections::HashMap, hash::BuildHasher};
|
||||
use ordermap::OrderMap;
|
||||
use ruff_db::system::SystemPathBuf;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_python_semantic::PythonPlatform;
|
||||
|
||||
/// Combine two values, preferring the values in `self`.
|
||||
///
|
||||
@@ -145,7 +144,6 @@ macro_rules! impl_noop_combine {
|
||||
}
|
||||
|
||||
impl_noop_combine!(SystemPathBuf);
|
||||
impl_noop_combine!(PythonPlatform);
|
||||
impl_noop_combine!(PythonVersion);
|
||||
|
||||
// std types
|
||||
|
||||
@@ -15,8 +15,8 @@ ruff_db = { workspace = true, features = ["os"] }
|
||||
ruff_text_size = { workspace = true }
|
||||
|
||||
ty_ide = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_project = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bstr = { workspace = true }
|
||||
|
||||
@@ -15,11 +15,11 @@ use regex::bytes::Regex;
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
|
||||
use ty_ide::Completion;
|
||||
use ty_module_resolver::ModuleName;
|
||||
use ty_project::metadata::Options;
|
||||
use ty_project::metadata::options::EnvironmentOptions;
|
||||
use ty_project::metadata::value::RelativePathBuf;
|
||||
use ty_project::{ProjectDatabase, ProjectMetadata};
|
||||
use ty_python_semantic::ModuleName;
|
||||
|
||||
#[derive(Debug, clap::Parser)]
|
||||
#[command(
|
||||
|
||||
@@ -22,7 +22,9 @@ ruff_python_importer = { workspace = true }
|
||||
ruff_python_trivia = { workspace = true }
|
||||
ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_project = { workspace = true, features = ["testing"] }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ruff_db::files::File;
|
||||
use ty_module_resolver::{Module, ModuleName, all_modules, resolve_real_shadowable_module};
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::{Module, ModuleName, all_modules, resolve_real_shadowable_module};
|
||||
|
||||
use crate::{
|
||||
SymbolKind,
|
||||
@@ -21,7 +21,7 @@ pub fn all_symbols<'db>(
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let typing_extensions = ModuleName::new("typing_extensions").unwrap();
|
||||
let typing_extensions = ModuleName::new_static("typing_extensions").unwrap();
|
||||
let is_typing_extensions_available = importing_from.is_stub(db)
|
||||
|| resolve_real_shadowable_module(db, importing_from, &typing_extensions).is_some();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use ruff_text_size::TextRange;
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::create_suppression_fix;
|
||||
use ty_python_semantic::lint::LintId;
|
||||
use ty_python_semantic::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
use ty_python_types::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
|
||||
/// A `QuickFix` Code Action
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -87,10 +87,8 @@ mod tests {
|
||||
use ruff_python_trivia::textwrap::dedent;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ty_project::ProjectMetadata;
|
||||
use ty_python_semantic::{
|
||||
lint::LintMetadata,
|
||||
types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE},
|
||||
};
|
||||
use ty_python_semantic::lint::LintMetadata;
|
||||
use ty_python_types::types::{UNDEFINED_REVEAL, UNRESOLVED_REFERENCE};
|
||||
|
||||
#[test]
|
||||
fn add_ignore() {
|
||||
|
||||
@@ -11,11 +11,9 @@ use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use rustc_hash::FxHashSet;
|
||||
use ty_python_semantic::types::UnionType;
|
||||
use ty_python_semantic::{
|
||||
Completion as SemanticCompletion, KnownModule, ModuleName, NameKind, SemanticModel,
|
||||
types::{CycleDetector, KnownClass, Type},
|
||||
};
|
||||
use ty_module_resolver::{KnownModule, ModuleName};
|
||||
use ty_python_types::types::{CycleDetector, KnownClass, Type, UnionType};
|
||||
use ty_python_types::{Completion as SemanticCompletion, NameKind, SemanticModel};
|
||||
|
||||
use crate::docstring::Docstring;
|
||||
use crate::goto::Definitions;
|
||||
@@ -2106,7 +2104,7 @@ mod tests {
|
||||
use insta::assert_snapshot;
|
||||
use ruff_python_ast::token::{TokenKind, Tokens};
|
||||
use ruff_python_parser::{Mode, ParseOptions};
|
||||
use ty_python_semantic::ModuleName;
|
||||
use ty_module_resolver::ModuleName;
|
||||
|
||||
use crate::completion::{Completion, completion};
|
||||
use crate::tests::{CursorTest, CursorTestBuilder};
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Find all document highlights for a symbol at the given position.
|
||||
/// Document highlights are limited to the current file only.
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Find all references to a symbol at the given position.
|
||||
/// Search for references across all files in the project.
|
||||
|
||||
@@ -12,12 +12,12 @@ use ruff_python_ast::token::{TokenKind, Tokens};
|
||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use ty_python_semantic::ResolvedDefinition;
|
||||
use ty_python_semantic::types::Type;
|
||||
use ty_python_semantic::types::ide_support::{
|
||||
use ty_python_types::ResolvedDefinition;
|
||||
use ty_python_types::types::Type;
|
||||
use ty_python_types::types::ide_support::{
|
||||
call_signature_details, call_type_simplified_by_overloads, definitions_for_keyword_argument,
|
||||
};
|
||||
use ty_python_semantic::{
|
||||
use ty_python_types::{
|
||||
HasDefinition, HasType, ImportAliasResolution, SemanticModel, definitions_for_imported_symbol,
|
||||
definitions_for_name,
|
||||
};
|
||||
@@ -228,15 +228,15 @@ impl<'db> Definitions<'db> {
|
||||
pub(crate) fn from_ty(db: &'db dyn crate::Db, ty: Type<'db>) -> Option<Self> {
|
||||
let ty_def = ty.definition(db)?;
|
||||
let resolved = match ty_def {
|
||||
ty_python_semantic::types::TypeDefinition::Module(module) => {
|
||||
ty_python_types::types::TypeDefinition::Module(module) => {
|
||||
ResolvedDefinition::Module(module.file(db)?)
|
||||
}
|
||||
ty_python_semantic::types::TypeDefinition::Class(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::Function(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::TypeVar(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::TypeAlias(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::SpecialForm(definition)
|
||||
| ty_python_semantic::types::TypeDefinition::NewType(definition) => {
|
||||
ty_python_types::types::TypeDefinition::Class(definition)
|
||||
| ty_python_types::types::TypeDefinition::Function(definition)
|
||||
| ty_python_types::types::TypeDefinition::TypeVar(definition)
|
||||
| ty_python_types::types::TypeDefinition::TypeAlias(definition)
|
||||
| ty_python_types::types::TypeDefinition::SpecialForm(definition)
|
||||
| ty_python_types::types::TypeDefinition::NewType(definition) => {
|
||||
ResolvedDefinition::Definition(definition)
|
||||
}
|
||||
};
|
||||
@@ -338,11 +338,11 @@ impl GotoTarget<'_> {
|
||||
}
|
||||
}
|
||||
GotoTarget::BinOp { expression, .. } => {
|
||||
let (_, ty) = ty_python_semantic::definitions_for_bin_op(model, expression)?;
|
||||
let (_, ty) = ty_python_types::definitions_for_bin_op(model, expression)?;
|
||||
Some(ty)
|
||||
}
|
||||
GotoTarget::UnaryOp { expression, .. } => {
|
||||
let (_, ty) = ty_python_semantic::definitions_for_unary_op(model, expression)?;
|
||||
let (_, ty) = ty_python_types::definitions_for_unary_op(model, expression)?;
|
||||
Some(ty)
|
||||
}
|
||||
// TODO: Support identifier targets
|
||||
@@ -526,15 +526,14 @@ impl GotoTarget<'_> {
|
||||
}
|
||||
|
||||
GotoTarget::BinOp { expression, .. } => {
|
||||
let (definitions, _) =
|
||||
ty_python_semantic::definitions_for_bin_op(model, expression)?;
|
||||
let (definitions, _) = ty_python_types::definitions_for_bin_op(model, expression)?;
|
||||
|
||||
Some(definitions)
|
||||
}
|
||||
|
||||
GotoTarget::UnaryOp { expression, .. } => {
|
||||
let (definitions, _) =
|
||||
ty_python_semantic::definitions_for_unary_op(model, expression)?;
|
||||
ty_python_types::definitions_for_unary_op(model, expression)?;
|
||||
|
||||
Some(definitions)
|
||||
}
|
||||
@@ -939,12 +938,12 @@ impl Ranged for GotoTarget<'_> {
|
||||
/// Converts a collection of `ResolvedDefinition` items into `NavigationTarget` items.
|
||||
fn convert_resolved_definitions_to_targets<'db>(
|
||||
db: &'db dyn ty_python_semantic::Db,
|
||||
definitions: Vec<ty_python_semantic::ResolvedDefinition<'db>>,
|
||||
definitions: Vec<ty_python_types::ResolvedDefinition<'db>>,
|
||||
) -> Vec<crate::NavigationTarget> {
|
||||
definitions
|
||||
.into_iter()
|
||||
.map(|resolved_definition| match resolved_definition {
|
||||
ty_python_semantic::ResolvedDefinition::Definition(definition) => {
|
||||
ty_python_types::ResolvedDefinition::Definition(definition) => {
|
||||
// Get the parsed module for range calculation
|
||||
let definition_file = definition.file(db);
|
||||
let module = ruff_db::parsed::parsed_module(db, definition_file).load(db);
|
||||
@@ -959,11 +958,11 @@ fn convert_resolved_definitions_to_targets<'db>(
|
||||
full_range: full_range.range(),
|
||||
}
|
||||
}
|
||||
ty_python_semantic::ResolvedDefinition::Module(file) => {
|
||||
ty_python_types::ResolvedDefinition::Module(file) => {
|
||||
// For modules, navigate to the start of the file
|
||||
crate::NavigationTarget::new(file, TextRange::default())
|
||||
}
|
||||
ty_python_semantic::ResolvedDefinition::FileWithRange(file_range) => {
|
||||
ty_python_types::ResolvedDefinition::FileWithRange(file_range) => {
|
||||
// For file ranges, navigate to the specific range within the file
|
||||
crate::NavigationTarget::from(file_range)
|
||||
}
|
||||
@@ -984,9 +983,9 @@ fn definitions_for_expression<'db>(
|
||||
expression.into(),
|
||||
alias_resolution,
|
||||
)),
|
||||
ast::ExprRef::Attribute(attribute) => Some(ty_python_semantic::definitions_for_attribute(
|
||||
model, attribute,
|
||||
)),
|
||||
ast::ExprRef::Attribute(attribute) => {
|
||||
Some(ty_python_types::definitions_for_attribute(model, attribute))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -1007,7 +1006,7 @@ fn definitions_for_callable<'db>(
|
||||
fn definitions_to_navigation_targets<'db>(
|
||||
db: &dyn ty_python_semantic::Db,
|
||||
stub_mapper: Option<&StubMapper<'db>>,
|
||||
mut definitions: Vec<ty_python_semantic::ResolvedDefinition<'db>>,
|
||||
mut definitions: Vec<ty_python_types::ResolvedDefinition<'db>>,
|
||||
) -> Option<crate::NavigationTargets> {
|
||||
if let Some(mapper) = stub_mapper {
|
||||
definitions = mapper.map_definitions(definitions);
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Navigate to the declaration of a symbol.
|
||||
///
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Navigate to the definition of a symbol.
|
||||
///
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{Db, HasNavigationTargets, NavigationTargets, RangedValue};
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
pub fn goto_type_definition(
|
||||
db: &dyn Db,
|
||||
|
||||
@@ -6,8 +6,8 @@ use ruff_db::parsed::parsed_module;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use ty_python_semantic::types::{KnownInstanceType, Type, TypeVarVariance};
|
||||
use ty_python_semantic::{DisplaySettings, SemanticModel};
|
||||
use ty_python_types::types::{KnownInstanceType, Type, TypeVarVariance};
|
||||
use ty_python_types::{DisplaySettings, SemanticModel};
|
||||
|
||||
pub fn hover(db: &dyn Db, file: File, offset: TextSize) -> Option<RangedValue<Hover<'_>>> {
|
||||
let parsed = parsed_module(db, file).load(db);
|
||||
@@ -23,7 +23,7 @@ pub fn hover(db: &dyn Db, file: File, offset: TextSize) -> Option<RangedValue<Ho
|
||||
let docs = goto_target
|
||||
.get_definition_targets(
|
||||
&model,
|
||||
ty_python_semantic::ImportAliasResolution::ResolveAliases,
|
||||
ty_python_types::ImportAliasResolution::ResolveAliases,
|
||||
)
|
||||
.and_then(|definitions| definitions.docstring(db))
|
||||
.map(HoverContent::Docstring);
|
||||
|
||||
@@ -29,10 +29,11 @@ use ruff_python_ast::visitor::source_order::{SourceOrderVisitor, TraversalSignal
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_importer::Insertion;
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_module_resolver::ModuleName;
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::semantic_index::definition::DefinitionKind;
|
||||
use ty_python_semantic::types::Type;
|
||||
use ty_python_semantic::{MemberDefinition, ModuleName, SemanticModel};
|
||||
use ty_python_types::types::Type;
|
||||
use ty_python_types::{MemberDefinition, SemanticModel};
|
||||
|
||||
pub(crate) struct Importer<'a> {
|
||||
/// The ty Salsa database.
|
||||
@@ -880,11 +881,10 @@ mod tests {
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_trivia::textwrap::dedent;
|
||||
use ruff_text_size::TextSize;
|
||||
use ty_module_resolver::SearchPathSettings;
|
||||
use ty_project::ProjectMetadata;
|
||||
use ty_python_semantic::{
|
||||
Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SearchPathSettings,
|
||||
SemanticModel,
|
||||
};
|
||||
use ty_python_semantic::{Program, ProgramSettings, PythonPlatform, PythonVersionWithSource};
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ use ruff_db::parsed::parsed_module;
|
||||
use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor, TraversalSignal};
|
||||
use ruff_python_ast::{AnyNodeRef, ArgOrKeyword, Expr, ExprUnaryOp, Stmt, UnaryOp};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_python_semantic::types::ide_support::inlay_hint_call_argument_details;
|
||||
use ty_python_semantic::types::{Type, TypeDetail};
|
||||
use ty_python_semantic::{HasType, SemanticModel};
|
||||
use ty_python_types::types::ide_support::inlay_hint_call_argument_details;
|
||||
use ty_python_types::types::{Type, TypeDetail};
|
||||
use ty_python_types::{HasType, SemanticModel};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InlayHint {
|
||||
@@ -6614,13 +6614,6 @@ mod tests {
|
||||
3 | y[: type[T@f]] = x
|
||||
| ^^^
|
||||
|
|
||||
|
||||
---------------------------------------------
|
||||
info[inlay-hint-edit]: File after edits
|
||||
info: Source
|
||||
|
||||
def f[T](x: type[T]):
|
||||
y: type[T@f] = x
|
||||
"#);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ use ruff_text_size::{Ranged, TextRange};
|
||||
use rustc_hash::FxHashSet;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::types::{Type, TypeDefinition};
|
||||
use ty_python_types::types::{Type, TypeDefinition};
|
||||
|
||||
/// Information associated with a text range.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
|
||||
@@ -20,7 +20,7 @@ use ruff_python_ast::{
|
||||
visitor::source_order::{SourceOrderVisitor, TraversalSignal},
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
use ty_python_semantic::{ImportAliasResolution, SemanticModel};
|
||||
use ty_python_types::{ImportAliasResolution, SemanticModel};
|
||||
|
||||
/// Mode for references search behavior
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::references::{ReferencesMode, references};
|
||||
use crate::{Db, ReferenceTarget};
|
||||
use ruff_db::files::File;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_types::SemanticModel;
|
||||
|
||||
/// Returns the range of the symbol if it can be renamed, None if not.
|
||||
pub fn can_rename(db: &dyn Db, file: File, offset: TextSize) -> Option<ruff_text_size::TextRange> {
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
//! TODO: Need to properly handle Annotated expressions. All type arguments other
|
||||
//! than the first should be treated as value expressions, not as type expressions.
|
||||
//!
|
||||
//! TODO: An identifier that resolves to a parameter when used within a function
|
||||
//! should be classified as a parameter, selfParameter, or clsParameter token.
|
||||
//!
|
||||
//! TODO: Properties (or perhaps more generally, descriptor objects?) should be
|
||||
//! classified as property tokens rather than just variables.
|
||||
//!
|
||||
@@ -47,10 +44,10 @@ use ruff_python_ast::{
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
use std::ops::Deref;
|
||||
use ty_python_semantic::semantic_index::definition::Definition;
|
||||
use ty_python_semantic::types::TypeVarKind;
|
||||
use ty_python_semantic::{
|
||||
HasType, SemanticModel, semantic_index::definition::DefinitionKind, types::Type,
|
||||
types::ide_support::definition_for_name,
|
||||
use ty_python_semantic::semantic_index::definition::DefinitionKind;
|
||||
use ty_python_types::types::TypeVarKind;
|
||||
use ty_python_types::{
|
||||
HasType, SemanticModel, types::Type, types::ide_support::definition_for_name,
|
||||
};
|
||||
|
||||
/// Semantic token types supported by the language server.
|
||||
@@ -230,6 +227,11 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||
modifiers: SemanticTokenModifier,
|
||||
) {
|
||||
let range = ranged.range();
|
||||
|
||||
if range.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only emit tokens that intersect with the range filter, if one is specified
|
||||
if let Some(range_filter) = self.range_filter {
|
||||
// Only include ranges that have a non-empty overlap. Adjacent ranges
|
||||
@@ -270,7 +272,7 @@ impl<'db> SemanticTokenVisitor<'db> {
|
||||
let definition = definition_for_name(
|
||||
self.model,
|
||||
name,
|
||||
ty_python_semantic::ImportAliasResolution::ResolveAliases,
|
||||
ty_python_types::ImportAliasResolution::ResolveAliases,
|
||||
);
|
||||
|
||||
if let Some(definition) = definition {
|
||||
@@ -707,15 +709,15 @@ impl SourceOrderVisitor<'_> for SemanticTokenVisitor<'_> {
|
||||
}
|
||||
ast::Stmt::Import(import) => {
|
||||
for alias in &import.names {
|
||||
// Create separate tokens for each part of a dotted module name
|
||||
self.add_dotted_name_tokens(&alias.name, SemanticTokenType::Namespace);
|
||||
|
||||
if let Some(asname) = &alias.asname {
|
||||
self.add_token(
|
||||
asname.range(),
|
||||
SemanticTokenType::Namespace,
|
||||
SemanticTokenModifier::empty(),
|
||||
);
|
||||
} else {
|
||||
// Create separate tokens for each part of a dotted module name
|
||||
self.add_dotted_name_tokens(&alias.name, SemanticTokenType::Namespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1131,7 +1133,7 @@ mod tests {
|
||||
use ty_project::ProjectMetadata;
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_basic() {
|
||||
fn semantic_tokens_basic() {
|
||||
let test = SemanticTokenTest::new("def foo(): pass");
|
||||
|
||||
let tokens = test.highlight_file();
|
||||
@@ -1142,7 +1144,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_class() {
|
||||
fn semantic_tokens_class() {
|
||||
let test = SemanticTokenTest::new("class MyClass: pass");
|
||||
|
||||
let tokens = test.highlight_file();
|
||||
@@ -1153,7 +1155,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_class_args() {
|
||||
fn semantic_tokens_class_args() {
|
||||
// This used to cause a panic because of an incorrect
|
||||
// insertion-order when visiting arguments inside
|
||||
// class definitions.
|
||||
@@ -1169,7 +1171,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_variables() {
|
||||
fn semantic_tokens_variables() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
x = 42
|
||||
@@ -1188,7 +1190,7 @@ y = 'hello'
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_walrus() {
|
||||
fn semantic_tokens_walrus() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
if x := 42:
|
||||
@@ -1207,7 +1209,7 @@ if x := 42:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_self_parameter() {
|
||||
fn semantic_tokens_self_parameter() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1238,7 +1240,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_cls_parameter() {
|
||||
fn semantic_tokens_cls_parameter() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1261,7 +1263,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_staticmethod_parameter() {
|
||||
fn semantic_tokens_staticmethod_parameter() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1282,7 +1284,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_custom_self_cls_names() {
|
||||
fn semantic_tokens_custom_self_cls_names() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1317,7 +1319,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_modifiers() {
|
||||
fn semantic_tokens_modifiers() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1338,7 +1340,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_classification_vs_heuristic() {
|
||||
fn semantic_classification_vs_heuristic() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
import sys
|
||||
@@ -1372,7 +1374,7 @@ z = sys.version
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builtin_constants() {
|
||||
fn builtin_constants() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
x = True
|
||||
@@ -1394,7 +1396,7 @@ z = None
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builtin_constants_in_expressions() {
|
||||
fn builtin_constants_in_expressions() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
def check(value):
|
||||
@@ -1422,7 +1424,7 @@ result = check(None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_builtin_types() {
|
||||
fn builtin_types() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
type U = str | int
|
||||
@@ -1467,7 +1469,7 @@ result = check(None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_semantic_tokens_range() {
|
||||
fn semantic_tokens_range() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
def function1():
|
||||
@@ -1532,7 +1534,7 @@ def function2():
|
||||
/// When a token starts right at where the requested range ends,
|
||||
/// don't include it in the semantic tokens.
|
||||
#[test]
|
||||
fn test_semantic_tokens_range_excludes_boundary_tokens() {
|
||||
fn semantic_tokens_range_excludes_boundary_tokens() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
x = 1
|
||||
@@ -1555,7 +1557,7 @@ z = 3
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dotted_module_names() {
|
||||
fn dotted_module_names() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
import os.path
|
||||
@@ -1582,7 +1584,7 @@ from collections.abc import Mapping
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_module_type_classification() {
|
||||
fn module_type_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
import os
|
||||
@@ -1610,7 +1612,7 @@ y = sys
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_import_classification() {
|
||||
fn import_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
from os import path
|
||||
@@ -1641,7 +1643,7 @@ from mymodule import CONSTANT, my_function, MyClass
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_str_annotation() {
|
||||
fn str_annotation() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
x: int = 1
|
||||
@@ -1685,7 +1687,7 @@ w5: "float
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attribute_classification() {
|
||||
fn attribute_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
import os
|
||||
@@ -1759,7 +1761,7 @@ u = List.__name__ # __name__ should be variable
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attribute_fallback_classification() {
|
||||
fn attribute_fallback_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1790,7 +1792,7 @@ y = obj.unknown_attr # Should fall back to variable
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_constant_name_detection() {
|
||||
fn constant_name_detection() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -1837,7 +1839,7 @@ w = obj.A # Should not have readonly modifier (length == 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_annotations() {
|
||||
fn type_annotations() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
from typing import List, Optional
|
||||
@@ -2325,7 +2327,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_int_classification() {
|
||||
fn debug_int_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
x: int = 42
|
||||
@@ -2342,7 +2344,7 @@ x: int = 42
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_user_defined_type_classification() {
|
||||
fn debug_user_defined_type_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
class MyClass:
|
||||
@@ -2363,7 +2365,7 @@ x: MyClass = MyClass()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_annotation_vs_variable_classification() {
|
||||
fn type_annotation_vs_variable_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
from typing import List, Optional
|
||||
@@ -2413,7 +2415,7 @@ def test_function(param: int, other: MyClass) -> Optional[List[str]]:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_protocol_types_in_annotations() {
|
||||
fn protocol_types_in_annotations() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
from typing import Protocol
|
||||
@@ -2444,7 +2446,7 @@ def test_function(param: MyProtocol) -> None:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_protocol_type_annotation_vs_value_context() {
|
||||
fn protocol_type_annotation_vs_value_context() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
from typing import Protocol
|
||||
@@ -2530,7 +2532,7 @@ def test_function(param: my_type_alias): ...
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_parameters_pep695() {
|
||||
fn type_parameters_pep695() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
# Test Python 3.12 PEP 695 type parameter syntax
|
||||
@@ -2654,7 +2656,7 @@ class BoundedContainer[T: int, U = str]:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_parameters_usage_in_function_body() {
|
||||
fn type_parameters_usage_in_function_body() {
|
||||
let test = SemanticTokenTest::new(
|
||||
"
|
||||
def generic_function[T](value: T) -> T:
|
||||
@@ -2683,7 +2685,7 @@ def generic_function[T](value: T) -> T:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decorator_classification() {
|
||||
fn decorator_classification() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
@staticmethod
|
||||
@@ -2713,7 +2715,7 @@ class MyClass:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_constant_variations() {
|
||||
fn constant_variations() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
A = 1
|
||||
@@ -2756,7 +2758,7 @@ A_1 = 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_implicitly_concatenated_strings() {
|
||||
fn implicitly_concatenated_strings() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"x = "hello" "world"
|
||||
y = ("multi"
|
||||
@@ -2783,7 +2785,7 @@ z = 'single' "mixed" 'quotes'"#,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_literals() {
|
||||
fn bytes_literals() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"x = b"hello" b"world"
|
||||
y = (b"multi"
|
||||
@@ -2810,7 +2812,7 @@ z = b'single' b"mixed" b'quotes'"#,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_string_and_bytes_literals() {
|
||||
fn mixed_string_and_bytes_literals() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"# Test mixed string and bytes literals
|
||||
string_concat = "hello" "world"
|
||||
@@ -2846,7 +2848,7 @@ regular_bytes = b"just bytes""#,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fstring_with_mixed_literals() {
|
||||
fn fstring_with_mixed_literals() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
# Test f-strings with various literal types
|
||||
@@ -2898,7 +2900,7 @@ complex_fstring = f"User: {name.upper()}, Count: {len(data)}, Hex: {value:x}"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonlocal_and_global_statements() {
|
||||
fn nonlocal_and_global_statements() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
x = "global_value"
|
||||
@@ -2960,7 +2962,7 @@ def outer():
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonlocal_global_edge_cases() {
|
||||
fn nonlocal_global_edge_cases() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
# Single variable statements
|
||||
@@ -3000,7 +3002,7 @@ def test():
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pattern_matching() {
|
||||
fn pattern_matching() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
def process_data(data):
|
||||
@@ -3056,7 +3058,7 @@ def process_data(data):
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exception_handlers() {
|
||||
fn exception_handlers() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
try:
|
||||
@@ -3095,7 +3097,7 @@ finally:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_self_attribute_expression() {
|
||||
fn self_attribute_expression() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
from typing import Self
|
||||
@@ -3135,7 +3137,7 @@ class C:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_augmented_assignment() {
|
||||
fn augmented_assignment() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
x = 0
|
||||
@@ -3154,7 +3156,7 @@ x += 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_type_alias() {
|
||||
fn type_alias() {
|
||||
let test = SemanticTokenTest::new("type MyList[T] = list[T]");
|
||||
|
||||
let tokens = test.highlight_file();
|
||||
@@ -3168,7 +3170,7 @@ x += 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_for_stmt() {
|
||||
fn for_stmt() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
for item in []:
|
||||
@@ -3190,7 +3192,7 @@ else:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_stmt() {
|
||||
fn with_stmt() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
with open("file.txt") as f:
|
||||
@@ -3210,7 +3212,7 @@ with open("file.txt") as f:
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_comprehensions() {
|
||||
fn comprehensions() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
list_comp = [x for x in range(10) if x % 2 == 0]
|
||||
@@ -3255,7 +3257,7 @@ generator = (x for x in range(10))
|
||||
|
||||
/// Regression test for <https://github.com/astral-sh/ty/issues/1406>
|
||||
#[test]
|
||||
fn test_invalid_kwargs() {
|
||||
fn invalid_kwargs() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
def foo(self, **key, value=10):
|
||||
@@ -3274,6 +3276,24 @@ def foo(self, **key, value=10):
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_as() {
|
||||
let test = SemanticTokenTest::new(
|
||||
r#"
|
||||
import pathlib as path
|
||||
from pathlib import Path
|
||||
"#,
|
||||
);
|
||||
|
||||
let tokens = test.highlight_file();
|
||||
assert_snapshot!(test.to_snapshot(&tokens), @r#"
|
||||
"pathlib" @ 8..15: Namespace
|
||||
"path" @ 19..23: Namespace
|
||||
"pathlib" @ 29..36: Namespace
|
||||
"Path" @ 44..48: Class
|
||||
"#);
|
||||
}
|
||||
|
||||
pub(super) struct SemanticTokenTest {
|
||||
pub(super) db: ty_project::TestDb,
|
||||
file: File,
|
||||
|
||||
@@ -15,13 +15,13 @@ use ruff_python_ast::find_node::covering_node;
|
||||
use ruff_python_ast::token::TokenKind;
|
||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use ty_python_semantic::ResolvedDefinition;
|
||||
use ty_python_semantic::SemanticModel;
|
||||
use ty_python_semantic::semantic_index::definition::Definition;
|
||||
use ty_python_semantic::types::ide_support::{
|
||||
use ty_python_types::ResolvedDefinition;
|
||||
use ty_python_types::SemanticModel;
|
||||
use ty_python_types::types::ide_support::{
|
||||
CallSignatureDetails, call_signature_details, find_active_signature_from_details,
|
||||
};
|
||||
use ty_python_semantic::types::{ParameterKind, Type};
|
||||
use ty_python_types::types::{ParameterKind, Type};
|
||||
|
||||
// TODO: We may want to add special-case handling for calls to constructors
|
||||
// so the class docstring is used in place of (or inaddition to) any docstring
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use itertools::Either;
|
||||
use ruff_db::system::SystemPathBuf;
|
||||
use ty_python_semantic::{ResolvedDefinition, map_stub_definition};
|
||||
use ty_python_types::{ResolvedDefinition, map_stub_definition};
|
||||
|
||||
use crate::cached_vendored_root;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ use ruff_python_ast::name::{Name, UnqualifiedName};
|
||||
use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use ty_module_resolver::{ModuleName, resolve_module};
|
||||
use ty_project::Db;
|
||||
use ty_python_semantic::{ModuleName, resolve_module};
|
||||
|
||||
use crate::completion::CompletionKind;
|
||||
|
||||
|
||||
38
crates/ty_module_resolver/Cargo.toml
Normal file
38
crates/ty_module_resolver/Cargo.toml
Normal file
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "ty_module_resolver"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff_db = { workspace = true }
|
||||
ruff_memory_usage = { workspace = true }
|
||||
ruff_python_ast = { workspace = true, features = ["salsa"] }
|
||||
ruff_python_stdlib = { workspace = true }
|
||||
|
||||
camino = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
get-size2 = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
salsa = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
insta = { workspace = true, features = ["filters"] }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
124
crates/ty_module_resolver/src/db.rs
Normal file
124
crates/ty_module_resolver/src/db.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use ruff_db::Db as SourceDb;
|
||||
|
||||
use crate::resolve::SearchPaths;
|
||||
|
||||
#[salsa::db]
|
||||
pub trait Db: SourceDb {
|
||||
/// Returns the search paths for module resolution.
|
||||
fn search_paths(&self) -> &SearchPaths;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use ruff_db::Db as SourceDb;
|
||||
use ruff_db::files::Files;
|
||||
use ruff_db::system::{DbWithTestSystem, TestSystem};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use super::Db;
|
||||
use crate::resolve::SearchPaths;
|
||||
|
||||
type Events = Arc<Mutex<Vec<salsa::Event>>>;
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestDb {
|
||||
storage: salsa::Storage<Self>,
|
||||
files: Files,
|
||||
system: TestSystem,
|
||||
vendored: VendoredFileSystem,
|
||||
search_paths: Arc<SearchPaths>,
|
||||
python_version: PythonVersion,
|
||||
events: Events,
|
||||
}
|
||||
|
||||
impl TestDb {
|
||||
pub(crate) fn new() -> Self {
|
||||
let events = Events::default();
|
||||
Self {
|
||||
storage: salsa::Storage::new(Some(Box::new({
|
||||
let events = events.clone();
|
||||
move |event| {
|
||||
tracing::trace!("event: {event:?}");
|
||||
let mut events = events.lock().unwrap();
|
||||
events.push(event);
|
||||
}
|
||||
}))),
|
||||
system: TestSystem::default(),
|
||||
vendored: ty_vendored::file_system().clone(),
|
||||
files: Files::default(),
|
||||
search_paths: Arc::new(SearchPaths::empty(ty_vendored::file_system())),
|
||||
python_version: PythonVersion::default(),
|
||||
events,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_search_paths(mut self, search_paths: SearchPaths) -> Self {
|
||||
self.set_search_paths(search_paths);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_python_version(mut self, python_version: PythonVersion) -> Self {
|
||||
self.python_version = python_version;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_search_paths(&mut self, search_paths: SearchPaths) {
|
||||
search_paths.try_register_static_roots(self);
|
||||
self.search_paths = Arc::new(search_paths);
|
||||
}
|
||||
|
||||
/// Takes the salsa events.
|
||||
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||
let mut events = self.events.lock().unwrap();
|
||||
std::mem::take(&mut *events)
|
||||
}
|
||||
|
||||
/// Clears the salsa events.
|
||||
pub(crate) fn clear_salsa_events(&mut self) {
|
||||
self.take_salsa_events();
|
||||
}
|
||||
}
|
||||
|
||||
impl DbWithTestSystem for TestDb {
|
||||
fn test_system(&self) -> &TestSystem {
|
||||
&self.system
|
||||
}
|
||||
|
||||
fn test_system_mut(&mut self) -> &mut TestSystem {
|
||||
&mut self.system
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl SourceDb for TestDb {
|
||||
fn vendored(&self) -> &VendoredFileSystem {
|
||||
&self.vendored
|
||||
}
|
||||
|
||||
fn system(&self) -> &dyn ruff_db::system::System {
|
||||
&self.system
|
||||
}
|
||||
|
||||
fn files(&self) -> &Files {
|
||||
&self.files
|
||||
}
|
||||
|
||||
fn python_version(&self) -> PythonVersion {
|
||||
self.python_version
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for TestDb {
|
||||
fn search_paths(&self) -> &SearchPaths {
|
||||
&self.search_paths
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for TestDb {}
|
||||
}
|
||||
@@ -1,24 +1,31 @@
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
pub use list::{all_modules, list_modules};
|
||||
pub use module::KnownModule;
|
||||
pub use module::Module;
|
||||
pub use path::{SearchPath, SearchPathValidationError};
|
||||
pub use resolver::SearchPaths;
|
||||
pub(crate) use resolver::file_to_module;
|
||||
pub use resolver::{
|
||||
resolve_module, resolve_module_confident, resolve_real_module, resolve_real_module_confident,
|
||||
resolve_real_shadowable_module,
|
||||
};
|
||||
use ruff_db::system::SystemPath;
|
||||
|
||||
use crate::Db;
|
||||
pub(crate) use resolver::{ModuleResolveMode, SearchPathIterator, search_paths};
|
||||
pub use db::Db;
|
||||
pub use module::KnownModule;
|
||||
pub use module::Module;
|
||||
pub use module_name::{ModuleName, ModuleNameResolutionError};
|
||||
pub use path::{SearchPath, SearchPathError};
|
||||
pub use resolve::{
|
||||
SearchPaths, file_to_module, resolve_module, resolve_module_confident, resolve_real_module,
|
||||
resolve_real_module_confident, resolve_real_shadowable_module,
|
||||
};
|
||||
pub use settings::{MisconfigurationMode, SearchPathSettings, SearchPathSettingsError};
|
||||
pub use typeshed::{
|
||||
PyVersionRange, TypeshedVersions, TypeshedVersionsParseError, vendored_typeshed_versions,
|
||||
};
|
||||
|
||||
pub use list::{all_modules, list_modules};
|
||||
pub use resolve::{ModuleResolveMode, SearchPathIterator, search_paths};
|
||||
|
||||
mod db;
|
||||
mod list;
|
||||
mod module;
|
||||
mod module_name;
|
||||
mod path;
|
||||
mod resolver;
|
||||
mod resolve;
|
||||
mod settings;
|
||||
mod typeshed;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -3,12 +3,10 @@ use std::collections::btree_map::{BTreeMap, Entry};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use crate::db::Db;
|
||||
use crate::module::{Module, ModuleKind};
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::program::Program;
|
||||
|
||||
use super::module::{Module, ModuleKind};
|
||||
use super::path::{ModulePath, SearchPath, SystemOrVendoredPathRef};
|
||||
use super::resolver::{ModuleResolveMode, ResolverContext, resolve_file_module, search_paths};
|
||||
use crate::path::{ModulePath, SearchPath, SystemOrVendoredPathRef};
|
||||
use crate::resolve::{ModuleResolveMode, ResolverContext, resolve_file_module, search_paths};
|
||||
|
||||
/// List all available modules, including all sub-modules, sorted in lexicographic order.
|
||||
pub fn all_modules(db: &dyn Db) -> Vec<Module<'_>> {
|
||||
@@ -100,7 +98,6 @@ fn list_modules_in<'db>(
|
||||
/// in the same directory).
|
||||
struct Lister<'db> {
|
||||
db: &'db dyn Db,
|
||||
program: Program,
|
||||
search_path: &'db SearchPath,
|
||||
modules: BTreeMap<&'db ModuleName, Module<'db>>,
|
||||
}
|
||||
@@ -109,10 +106,8 @@ impl<'db> Lister<'db> {
|
||||
/// Create new state that can accumulate modules from a list
|
||||
/// of file paths.
|
||||
fn new(db: &'db dyn Db, search_path: &'db SearchPath) -> Lister<'db> {
|
||||
let program = Program::get(db);
|
||||
Lister {
|
||||
db,
|
||||
program,
|
||||
search_path,
|
||||
modules: BTreeMap::new(),
|
||||
}
|
||||
@@ -314,7 +309,7 @@ impl<'db> Lister<'db> {
|
||||
/// Returns the Python version we want to perform module resolution
|
||||
/// with.
|
||||
fn python_version(&self) -> PythonVersion {
|
||||
self.program.python_version(self.db)
|
||||
self.db.python_version()
|
||||
}
|
||||
|
||||
/// Constructs a resolver context for use with some APIs that require it.
|
||||
@@ -382,20 +377,17 @@ mod tests {
|
||||
use camino::{Utf8Component, Utf8Path};
|
||||
use ruff_db::Db as _;
|
||||
use ruff_db::files::{File, FilePath, FileRootKind};
|
||||
use ruff_db::system::{
|
||||
DbWithTestSystem, DbWithWritableSystem, OsSystem, SystemPath, SystemPathBuf,
|
||||
};
|
||||
use ruff_db::system::{DbWithTestSystem, DbWithWritableSystem, SystemPath, SystemPathBuf};
|
||||
use ruff_db::testing::assert_function_query_was_not_run;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use crate::db::{Db, tests::TestDb};
|
||||
use crate::module_resolver::module::Module;
|
||||
use crate::module_resolver::resolver::{
|
||||
use crate::module::Module;
|
||||
use crate::resolve::{
|
||||
ModuleResolveMode, ModuleResolveModeIngredient, dynamic_resolution_paths,
|
||||
};
|
||||
use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
use crate::program::{Program, ProgramSettings, SearchPathSettings};
|
||||
use crate::{PythonPlatform, PythonVersionSource, PythonVersionWithSource};
|
||||
use crate::settings::SearchPathSettings;
|
||||
use crate::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
|
||||
use super::list_modules;
|
||||
|
||||
@@ -940,7 +932,7 @@ mod tests {
|
||||
fn symlink() -> anyhow::Result<()> {
|
||||
use anyhow::Context;
|
||||
|
||||
let mut db = TestDb::new();
|
||||
let mut db = TestDb::new().with_python_version(PythonVersion::PY38);
|
||||
|
||||
let temp_dir = tempfile::TempDir::with_prefix("PREFIX-SENTINEL")?;
|
||||
let root = temp_dir
|
||||
@@ -948,7 +940,7 @@ mod tests {
|
||||
.canonicalize()
|
||||
.context("Failed to canonicalize temp dir")?;
|
||||
let root = SystemPath::from_std_path(&root).unwrap();
|
||||
db.use_system(OsSystem::new(root));
|
||||
db.use_system(ruff_db::system::OsSystem::new(root));
|
||||
|
||||
let src = root.join("src");
|
||||
let site_packages = root.join("site-packages");
|
||||
@@ -965,26 +957,21 @@ mod tests {
|
||||
std::fs::write(foo.as_std_path(), "")?;
|
||||
std::os::unix::fs::symlink(foo.as_std_path(), bar.as_std_path())?;
|
||||
|
||||
db.files().try_add_root(&db, &src, FileRootKind::Project);
|
||||
let settings = SearchPathSettings {
|
||||
src_roots: vec![src.clone()],
|
||||
custom_typeshed: Some(custom_typeshed),
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::empty()
|
||||
};
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource {
|
||||
version: PythonVersion::PY38,
|
||||
source: PythonVersionSource::default(),
|
||||
},
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
custom_typeshed: Some(custom_typeshed),
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::new(vec![src])
|
||||
}
|
||||
db.set_search_paths(
|
||||
settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
},
|
||||
);
|
||||
|
||||
db.files().try_add_root(&db, &src, FileRootKind::Project);
|
||||
|
||||
// From the original test in the "resolve this module"
|
||||
// implementation, this test seems to symlink a Python module
|
||||
// and assert that they are treated as two distinct modules.
|
||||
@@ -1479,18 +1466,15 @@ not_a_directory
|
||||
db.files()
|
||||
.try_add_root(&db, SystemPath::new("/src"), FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages],
|
||||
..SearchPathSettings::new(vec![src.to_path_buf()])
|
||||
}
|
||||
let settings = SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages],
|
||||
..SearchPathSettings::new(vec![src.to_path_buf()])
|
||||
};
|
||||
|
||||
db.set_search_paths(
|
||||
settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
},
|
||||
);
|
||||
|
||||
insta::assert_debug_snapshot!(
|
||||
@@ -1533,18 +1517,15 @@ not_a_directory
|
||||
db.files()
|
||||
.try_add_root(&db, SystemPath::new("/src"), FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages, system_site_packages],
|
||||
..SearchPathSettings::new(vec![SystemPathBuf::from("/src")])
|
||||
}
|
||||
let settings = SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages, system_site_packages],
|
||||
..SearchPathSettings::new(vec![SystemPathBuf::from("/src")])
|
||||
};
|
||||
|
||||
db.set_search_paths(
|
||||
settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
},
|
||||
);
|
||||
|
||||
// The editable installs discovered from the `.pth` file in the
|
||||
@@ -1585,7 +1566,7 @@ not_a_directory
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn case_sensitive_resolution_with_symlinked_directory() -> anyhow::Result<()> {
|
||||
use anyhow::Context;
|
||||
use anyhow::Context as _;
|
||||
|
||||
let temp_dir = tempfile::TempDir::with_prefix("PREFIX-SENTINEL")?;
|
||||
let root = SystemPathBuf::from_path_buf(
|
||||
@@ -1602,7 +1583,7 @@ not_a_directory
|
||||
let a_package_target = root.join("a-package");
|
||||
let a_src = src.join("a");
|
||||
|
||||
db.use_system(OsSystem::new(&root));
|
||||
db.use_system(ruff_db::system::OsSystem::new(&root));
|
||||
|
||||
db.write_file(
|
||||
a_package_target.join("__init__.py"),
|
||||
@@ -1621,16 +1602,11 @@ not_a_directory
|
||||
|
||||
db.files().try_add_root(&db, &root, FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings::new(vec![src])
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("valid search path settings"),
|
||||
},
|
||||
);
|
||||
let settings = SearchPathSettings::new(vec![src]);
|
||||
let search_paths = settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("valid search path settings");
|
||||
db.set_search_paths(search_paths);
|
||||
|
||||
insta::with_settings!({
|
||||
// Temporary directory often have random chars in them, so
|
||||
@@ -1662,18 +1638,14 @@ not_a_directory
|
||||
db.files()
|
||||
.try_add_root(&db, &project_directory, FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::new(vec![project_directory])
|
||||
}
|
||||
let settings = SearchPathSettings {
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::new(vec![project_directory])
|
||||
};
|
||||
db.set_search_paths(
|
||||
settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.unwrap(),
|
||||
},
|
||||
);
|
||||
|
||||
insta::assert_debug_snapshot!(
|
||||
@@ -1820,16 +1792,11 @@ not_a_directory
|
||||
db.files()
|
||||
.try_add_root(&db, SystemPath::new("/"), FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings::new(vec![project_directory])
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.unwrap(),
|
||||
},
|
||||
);
|
||||
let settings = SearchPathSettings::new(vec![project_directory]);
|
||||
let search_paths = settings
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings");
|
||||
db.set_search_paths(search_paths);
|
||||
|
||||
insta::assert_debug_snapshot!(
|
||||
list_snapshot_filter(&db, |m| m.name(&db).as_str() == "foo"),
|
||||
@@ -7,10 +7,9 @@ use ruff_db::vendored::VendoredPath;
|
||||
use salsa::Database;
|
||||
use salsa::plumbing::AsId;
|
||||
|
||||
use super::path::SearchPath;
|
||||
use crate::Db;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::path::SystemOrVendoredPathRef;
|
||||
use crate::path::{SearchPath, SystemOrVendoredPathRef};
|
||||
|
||||
/// Representation of a Python module.
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, salsa::Supertype, salsa::Update)]
|
||||
@@ -330,16 +329,14 @@ pub enum KnownModule {
|
||||
TyExtensions,
|
||||
#[strum(serialize = "importlib")]
|
||||
ImportLib,
|
||||
#[cfg(test)]
|
||||
#[strum(serialize = "unittest.mock")]
|
||||
UnittestMock,
|
||||
#[cfg(test)]
|
||||
Uuid,
|
||||
Warnings,
|
||||
}
|
||||
|
||||
impl KnownModule {
|
||||
pub(crate) const fn as_str(self) -> &'static str {
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Builtins => "builtins",
|
||||
Self::Enum => "enum",
|
||||
@@ -360,23 +357,18 @@ impl KnownModule {
|
||||
Self::TyExtensions => "ty_extensions",
|
||||
Self::ImportLib => "importlib",
|
||||
Self::Warnings => "warnings",
|
||||
#[cfg(test)]
|
||||
Self::UnittestMock => "unittest.mock",
|
||||
#[cfg(test)]
|
||||
Self::Uuid => "uuid",
|
||||
Self::Templatelib => "string.templatelib",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn name(self) -> ModuleName {
|
||||
pub fn name(self) -> ModuleName {
|
||||
ModuleName::new_static(self.as_str())
|
||||
.unwrap_or_else(|| panic!("{self} should be a valid module name!"))
|
||||
}
|
||||
|
||||
pub(crate) fn try_from_search_path_and_name(
|
||||
search_path: &SearchPath,
|
||||
name: &ModuleName,
|
||||
) -> Option<Self> {
|
||||
fn try_from_search_path_and_name(search_path: &SearchPath, name: &ModuleName) -> Option<Self> {
|
||||
if search_path.is_standard_library() {
|
||||
Self::from_str(name.as_str()).ok()
|
||||
} else {
|
||||
@@ -384,23 +376,23 @@ impl KnownModule {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn is_builtins(self) -> bool {
|
||||
pub const fn is_builtins(self) -> bool {
|
||||
matches!(self, Self::Builtins)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_typing(self) -> bool {
|
||||
pub const fn is_typing(self) -> bool {
|
||||
matches!(self, Self::Typing)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_ty_extensions(self) -> bool {
|
||||
pub const fn is_ty_extensions(self) -> bool {
|
||||
matches!(self, Self::TyExtensions)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_inspect(self) -> bool {
|
||||
pub const fn is_inspect(self) -> bool {
|
||||
matches!(self, Self::Inspect)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_importlib(self) -> bool {
|
||||
pub const fn is_importlib(self) -> bool {
|
||||
matches!(self, Self::ImportLib)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@ use ruff_db::files::File;
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_stdlib::identifiers::is_identifier;
|
||||
|
||||
use crate::{db::Db, module_resolver::file_to_module};
|
||||
use crate::db::Db;
|
||||
use crate::resolve::file_to_module;
|
||||
|
||||
/// A module name, e.g. `foo.bar`.
|
||||
///
|
||||
@@ -47,7 +48,7 @@ impl ModuleName {
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert_eq!(ModuleName::new_static("foo.bar").as_deref(), Some("foo.bar"));
|
||||
/// assert_eq!(ModuleName::new_static(""), None);
|
||||
@@ -73,7 +74,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert_eq!(ModuleName::new_static("foo.bar.baz").unwrap().components().collect::<Vec<_>>(), vec!["foo", "bar", "baz"]);
|
||||
/// ```
|
||||
@@ -87,7 +88,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert_eq!(ModuleName::new_static("foo.bar").unwrap().parent(), Some(ModuleName::new_static("foo").unwrap()));
|
||||
/// assert_eq!(ModuleName::new_static("foo.bar.baz").unwrap().parent(), Some(ModuleName::new_static("foo.bar").unwrap()));
|
||||
@@ -106,7 +107,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert!(ModuleName::new_static("foo.bar").unwrap().starts_with(&ModuleName::new_static("foo").unwrap()));
|
||||
///
|
||||
@@ -142,7 +143,7 @@ impl ModuleName {
|
||||
/// module name:
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// let this = ModuleName::new_static("importlib.resources").unwrap();
|
||||
/// let parent = ModuleName::new_static("importlib").unwrap();
|
||||
@@ -156,7 +157,7 @@ impl ModuleName {
|
||||
/// This shows some cases where it isn't a parent:
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// let this = ModuleName::new_static("importliblib.resources").unwrap();
|
||||
/// let parent = ModuleName::new_static("importlib").unwrap();
|
||||
@@ -199,7 +200,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert_eq!(&*ModuleName::from_components(["a"]).unwrap(), "a");
|
||||
/// assert_eq!(&*ModuleName::from_components(["a", "b"]).unwrap(), "a.b");
|
||||
@@ -240,7 +241,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// let mut module_name = ModuleName::new_static("foo").unwrap();
|
||||
/// module_name.extend(&ModuleName::new_static("bar").unwrap());
|
||||
@@ -258,7 +259,7 @@ impl ModuleName {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ty_python_semantic::ModuleName;
|
||||
/// use ty_module_resolver::ModuleName;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// ModuleName::new_static("foo.bar.baz").unwrap().ancestors().collect::<Vec<_>>(),
|
||||
@@ -314,7 +315,7 @@ impl ModuleName {
|
||||
/// Computes the absolute module name for the package this file belongs to.
|
||||
///
|
||||
/// i.e. this resolves `.`
|
||||
pub(crate) fn package_for_file(
|
||||
pub fn package_for_file(
|
||||
db: &dyn Db,
|
||||
importing_file: File,
|
||||
) -> Result<Self, ModuleNameResolutionError> {
|
||||
@@ -8,11 +8,10 @@ use ruff_db::files::{File, FileError, FilePath, system_path_to_file, vendored_pa
|
||||
use ruff_db::system::{System, SystemPath, SystemPathBuf};
|
||||
use ruff_db::vendored::{VendoredPath, VendoredPathBuf};
|
||||
|
||||
use super::typeshed::{TypeshedVersionsParseError, TypeshedVersionsQueryResult, typeshed_versions};
|
||||
use crate::Db;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::resolver::{PyTyped, ResolverContext};
|
||||
use crate::site_packages::SitePackagesDiscoveryError;
|
||||
use crate::resolve::{PyTyped, ResolverContext};
|
||||
use crate::typeshed::{TypeshedVersionsQueryResult, typeshed_versions};
|
||||
|
||||
/// A path that points to a Python module.
|
||||
///
|
||||
@@ -397,13 +396,8 @@ fn query_stdlib_version(
|
||||
typeshed_versions(*db).query_module(&module_name, *python_version)
|
||||
}
|
||||
|
||||
/// Enumeration describing the various ways in which validation of a search path might fail.
|
||||
///
|
||||
/// If validation fails for a search path derived from the user settings,
|
||||
/// a message must be displayed to the user,
|
||||
/// as type checking cannot be done reliably in these circumstances.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SearchPathValidationError {
|
||||
pub enum SearchPathError {
|
||||
/// The path provided by the user was not a directory
|
||||
#[error("{0} does not point to a directory")]
|
||||
NotADirectory(SystemPathBuf),
|
||||
@@ -413,41 +407,9 @@ pub enum SearchPathValidationError {
|
||||
/// (This is only relevant for stdlib search paths.)
|
||||
#[error("The directory at {0} has no `stdlib/` subdirectory")]
|
||||
NoStdlibSubdirectory(SystemPathBuf),
|
||||
|
||||
/// The typeshed path provided by the user is a directory,
|
||||
/// but `stdlib/VERSIONS` could not be read.
|
||||
/// (This is only relevant for stdlib search paths.)
|
||||
#[error("Failed to read the custom typeshed versions file '{path}'")]
|
||||
FailedToReadVersionsFile {
|
||||
path: SystemPathBuf,
|
||||
#[source]
|
||||
error: std::io::Error,
|
||||
},
|
||||
|
||||
/// The path provided by the user is a directory,
|
||||
/// and a `stdlib/VERSIONS` file exists, but it fails to parse.
|
||||
/// (This is only relevant for stdlib search paths.)
|
||||
#[error(transparent)]
|
||||
VersionsParseError(TypeshedVersionsParseError),
|
||||
|
||||
/// Failed to discover the site-packages for the configured virtual environment.
|
||||
#[error("Failed to discover the site-packages directory")]
|
||||
SitePackagesDiscovery(#[source] SitePackagesDiscoveryError),
|
||||
}
|
||||
|
||||
impl From<TypeshedVersionsParseError> for SearchPathValidationError {
|
||||
fn from(value: TypeshedVersionsParseError) -> Self {
|
||||
Self::VersionsParseError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SitePackagesDiscoveryError> for SearchPathValidationError {
|
||||
fn from(value: SitePackagesDiscoveryError) -> Self {
|
||||
Self::SitePackagesDiscovery(value)
|
||||
}
|
||||
}
|
||||
|
||||
type SearchPathResult<T> = Result<T, SearchPathValidationError>;
|
||||
type SearchPathResult<T> = Result<T, SearchPathError>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
|
||||
enum SearchPathInner {
|
||||
@@ -495,7 +457,7 @@ impl SearchPath {
|
||||
if system.is_directory(&root) {
|
||||
Ok(root)
|
||||
} else {
|
||||
Err(SearchPathValidationError::NotADirectory(root))
|
||||
Err(SearchPathError::NotADirectory(root))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,17 +481,15 @@ impl SearchPath {
|
||||
typeshed: &SystemPath,
|
||||
) -> SearchPathResult<Self> {
|
||||
if !system.is_directory(typeshed) {
|
||||
return Err(SearchPathValidationError::NotADirectory(
|
||||
typeshed.to_path_buf(),
|
||||
));
|
||||
return Err(SearchPathError::NotADirectory(typeshed.to_path_buf()));
|
||||
}
|
||||
|
||||
let stdlib =
|
||||
Self::directory_path(system, typeshed.join("stdlib")).map_err(|err| match err {
|
||||
SearchPathValidationError::NotADirectory(_) => {
|
||||
SearchPathValidationError::NoStdlibSubdirectory(typeshed.to_path_buf())
|
||||
SearchPathError::NotADirectory(_) => {
|
||||
SearchPathError::NoStdlibSubdirectory(typeshed.to_path_buf())
|
||||
}
|
||||
err => err,
|
||||
SearchPathError::NoStdlibSubdirectory(_) => err,
|
||||
})?;
|
||||
|
||||
Ok(Self(Arc::new(SearchPathInner::StandardLibraryCustom(
|
||||
@@ -585,7 +545,7 @@ impl SearchPath {
|
||||
|
||||
/// Does this search path point to the standard library?
|
||||
#[must_use]
|
||||
pub(crate) fn is_standard_library(&self) -> bool {
|
||||
pub fn is_standard_library(&self) -> bool {
|
||||
matches!(
|
||||
&*self.0,
|
||||
SearchPathInner::StandardLibraryCustom(_)
|
||||
@@ -680,7 +640,7 @@ impl SearchPath {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn as_system_path(&self) -> Option<&SystemPath> {
|
||||
pub fn as_system_path(&self) -> Option<&SystemPath> {
|
||||
self.as_path().as_system_path()
|
||||
}
|
||||
|
||||
@@ -709,7 +669,7 @@ impl SearchPath {
|
||||
/// Returns a string suitable for describing what kind of search path this is
|
||||
/// in user-facing diagnostics.
|
||||
#[must_use]
|
||||
pub(crate) fn describe_kind(&self) -> &'static str {
|
||||
pub fn describe_kind(&self) -> &'static str {
|
||||
match *self.0 {
|
||||
SearchPathInner::Extra(_) => {
|
||||
"extra search path specified on the CLI or in your config file"
|
||||
@@ -869,8 +829,8 @@ mod tests {
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
use crate::module_resolver::resolver::ModuleResolveMode;
|
||||
use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
use crate::resolve::ModuleResolveMode;
|
||||
use crate::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -48,13 +48,11 @@ use ruff_python_ast::{
|
||||
};
|
||||
|
||||
use crate::db::Db;
|
||||
use crate::module::{Module, ModuleKind};
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::typeshed::{TypeshedVersions, vendored_typeshed_versions};
|
||||
use crate::program::MisconfigurationMode;
|
||||
use crate::{Program, SearchPathSettings};
|
||||
|
||||
use super::module::{Module, ModuleKind};
|
||||
use super::path::{ModulePath, SearchPath, SearchPathValidationError, SystemOrVendoredPathRef};
|
||||
use crate::path::{ModulePath, SearchPath, SystemOrVendoredPathRef};
|
||||
use crate::typeshed::{TypeshedVersions, vendored_typeshed_versions};
|
||||
use crate::{MisconfigurationMode, SearchPathSettings, SearchPathSettingsError};
|
||||
|
||||
/// Resolves a module name to a module.
|
||||
pub fn resolve_module<'db>(
|
||||
@@ -137,7 +135,7 @@ pub fn resolve_real_shadowable_module<'db>(
|
||||
/// Which files should be visible when doing a module query
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, get_size2::GetSize)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub(crate) enum ModuleResolveMode {
|
||||
pub enum ModuleResolveMode {
|
||||
/// Stubs are allowed to appear.
|
||||
///
|
||||
/// This is the "normal" mode almost everything uses, as type checkers are in fact supposed
|
||||
@@ -326,7 +324,7 @@ pub(crate) fn path_to_module<'db>(db: &'db dyn Db, path: &FilePath) -> Option<Mo
|
||||
/// This intuition is particularly useful for understanding why it's correct that we pass
|
||||
/// the file itself as `importing_file` to various subroutines.
|
||||
#[salsa::tracked(heap_size=ruff_memory_usage::heap_size)]
|
||||
pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module<'_>> {
|
||||
pub fn file_to_module(db: &dyn Db, file: File) -> Option<Module<'_>> {
|
||||
let _span = tracing::trace_span!("file_to_module", ?file).entered();
|
||||
|
||||
let path = SystemOrVendoredPathRef::try_from_file(db, file)?;
|
||||
@@ -392,8 +390,8 @@ fn file_to_module_impl<'db, 'a>(
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn search_paths(db: &dyn Db, resolve_mode: ModuleResolveMode) -> SearchPathIterator<'_> {
|
||||
Program::get(db).search_paths(db).iter(db, resolve_mode)
|
||||
pub fn search_paths(db: &dyn Db, resolve_mode: ModuleResolveMode) -> SearchPathIterator<'_> {
|
||||
db.search_paths().iter(db, resolve_mode)
|
||||
}
|
||||
|
||||
/// Get the search-paths for desperate resolution of absolute imports in this file.
|
||||
@@ -554,11 +552,11 @@ impl SearchPaths {
|
||||
/// This method also implements the typing spec's [module resolution order].
|
||||
///
|
||||
/// [module resolution order]: https://typing.python.org/en/latest/spec/distributing.html#import-resolution-ordering
|
||||
pub(crate) fn from_settings(
|
||||
pub fn from_settings(
|
||||
settings: &SearchPathSettings,
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
) -> Result<Self, SearchPathValidationError> {
|
||||
) -> Result<Self, SearchPathSettingsError> {
|
||||
fn canonicalize(path: &SystemPath, system: &dyn System) -> SystemPathBuf {
|
||||
system
|
||||
.canonicalize_path(path)
|
||||
@@ -586,7 +584,7 @@ impl SearchPaths {
|
||||
if *misconfiguration_mode == MisconfigurationMode::UseDefault {
|
||||
tracing::debug!("Skipping invalid extra search-path: {err}");
|
||||
} else {
|
||||
return Err(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -600,7 +598,7 @@ impl SearchPaths {
|
||||
if *misconfiguration_mode == MisconfigurationMode::UseDefault {
|
||||
tracing::debug!("Skipping invalid first-party search-path: {err}");
|
||||
} else {
|
||||
return Err(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,12 +612,10 @@ impl SearchPaths {
|
||||
|
||||
let results = system
|
||||
.read_to_string(&versions_path)
|
||||
.map_err(
|
||||
|error| SearchPathValidationError::FailedToReadVersionsFile {
|
||||
path: versions_path,
|
||||
error,
|
||||
},
|
||||
)
|
||||
.map_err(|error| SearchPathSettingsError::FailedToReadVersionsFile {
|
||||
path: versions_path,
|
||||
error,
|
||||
})
|
||||
.and_then(|versions_content| Ok(versions_content.parse()?))
|
||||
.and_then(|parsed| Ok((parsed, SearchPath::custom_stdlib(system, &typeshed)?)));
|
||||
|
||||
@@ -653,7 +649,7 @@ impl SearchPaths {
|
||||
tracing::debug!("Skipping invalid real-stdlib search-path: {err}");
|
||||
None
|
||||
} else {
|
||||
return Err(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,9 +665,9 @@ impl SearchPaths {
|
||||
Ok(path) => site_packages.push(path),
|
||||
Err(err) => {
|
||||
if settings.misconfiguration_mode == MisconfigurationMode::UseDefault {
|
||||
tracing::debug!("Skipping invalid real-stdlib search-path: {err}");
|
||||
tracing::debug!("Skipping invalid site-packages search-path: {err}");
|
||||
} else {
|
||||
return Err(err);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -709,13 +705,11 @@ impl SearchPaths {
|
||||
// preserve this behaviour to avoid getting into the weeds of corner cases.)
|
||||
let stdlib_path_is_shadowed = stdlib_path
|
||||
.as_system_path()
|
||||
.map(|path| seen_paths.contains(path))
|
||||
.unwrap_or(false);
|
||||
.is_some_and(|path| seen_paths.contains(path));
|
||||
let real_stdlib_path_is_shadowed = real_stdlib_path
|
||||
.as_ref()
|
||||
.and_then(SearchPath::as_system_path)
|
||||
.map(|path| seen_paths.contains(path))
|
||||
.unwrap_or(false);
|
||||
.is_some_and(|path| seen_paths.contains(path));
|
||||
|
||||
let stdlib_path = if stdlib_path_is_shadowed {
|
||||
None
|
||||
@@ -737,8 +731,21 @@ impl SearchPaths {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a new `SearchPaths` with no search paths configured.
|
||||
///
|
||||
/// This is primarily useful for testing.
|
||||
pub fn empty(vendored: &VendoredFileSystem) -> Self {
|
||||
Self {
|
||||
static_paths: vec![],
|
||||
stdlib_path: Some(SearchPath::vendored_stdlib()),
|
||||
real_stdlib_path: None,
|
||||
site_packages: vec![],
|
||||
typeshed_versions: vendored_typeshed_versions(vendored),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers the file roots for all non-dynamically discovered search paths that aren't first-party.
|
||||
pub(crate) fn try_register_static_roots(&self, db: &dyn Db) {
|
||||
pub fn try_register_static_roots(&self, db: &dyn Db) {
|
||||
let files = db.files();
|
||||
for path in self
|
||||
.static_paths
|
||||
@@ -779,13 +786,13 @@ impl SearchPaths {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn custom_stdlib(&self) -> Option<&SystemPath> {
|
||||
pub fn custom_stdlib(&self) -> Option<&SystemPath> {
|
||||
self.stdlib_path
|
||||
.as_ref()
|
||||
.and_then(SearchPath::as_system_path)
|
||||
}
|
||||
|
||||
pub(crate) fn typeshed_versions(&self) -> &TypeshedVersions {
|
||||
pub fn typeshed_versions(&self) -> &TypeshedVersions {
|
||||
&self.typeshed_versions
|
||||
}
|
||||
}
|
||||
@@ -811,7 +818,7 @@ pub(crate) fn dynamic_resolution_paths<'db>(
|
||||
site_packages,
|
||||
typeshed_versions: _,
|
||||
real_stdlib_path,
|
||||
} = Program::get(db).search_paths(db);
|
||||
} = db.search_paths();
|
||||
|
||||
let mut dynamic_paths = Vec::new();
|
||||
|
||||
@@ -932,7 +939,7 @@ pub(crate) fn dynamic_resolution_paths<'db>(
|
||||
/// are only calculated lazily.
|
||||
///
|
||||
/// [`sys.path` at runtime]: https://docs.python.org/3/library/site.html#module-site
|
||||
pub(crate) struct SearchPathIterator<'db> {
|
||||
pub struct SearchPathIterator<'db> {
|
||||
db: &'db dyn Db,
|
||||
static_paths: std::slice::Iter<'db, SearchPath>,
|
||||
stdlib_path: Option<&'db SearchPath>,
|
||||
@@ -1101,8 +1108,7 @@ fn resolve_name_impl<'a>(
|
||||
mode: ModuleResolveMode,
|
||||
search_paths: impl Iterator<Item = &'a SearchPath>,
|
||||
) -> Option<ResolvedName> {
|
||||
let program = Program::get(db);
|
||||
let python_version = program.python_version(db);
|
||||
let python_version = db.python_version();
|
||||
let resolver_state = ResolverContext::new(db, python_version, mode);
|
||||
let is_non_shadowable = mode.is_non_shadowable(python_version.minor, name.as_str());
|
||||
|
||||
@@ -1740,10 +1746,9 @@ mod tests {
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
use crate::module::ModuleKind;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::module::ModuleKind;
|
||||
use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
use crate::{ProgramSettings, PythonPlatform, PythonVersionWithSource};
|
||||
use crate::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -2267,15 +2272,11 @@ mod tests {
|
||||
#[cfg(target_family = "unix")]
|
||||
fn symlink() -> anyhow::Result<()> {
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::{
|
||||
PythonPlatform, PythonVersionSource, PythonVersionWithSource, program::Program,
|
||||
};
|
||||
use ruff_db::system::{OsSystem, SystemPath};
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
|
||||
let mut db = TestDb::new();
|
||||
let mut db = TestDb::new().with_python_version(PythonVersion::PY38);
|
||||
|
||||
let temp_dir = tempfile::tempdir()?;
|
||||
let root = temp_dir
|
||||
@@ -2300,22 +2301,15 @@ mod tests {
|
||||
std::fs::write(foo.as_std_path(), "")?;
|
||||
std::os::unix::fs::symlink(foo.as_std_path(), bar.as_std_path())?;
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource {
|
||||
version: PythonVersion::PY38,
|
||||
source: PythonVersionSource::default(),
|
||||
},
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
custom_typeshed: Some(custom_typeshed),
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::new(vec![src.clone()])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
},
|
||||
db.set_search_paths(
|
||||
SearchPathSettings {
|
||||
src_roots: vec![src.clone()],
|
||||
custom_typeshed: Some(custom_typeshed),
|
||||
site_packages_paths: vec![site_packages],
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
);
|
||||
|
||||
let foo_module =
|
||||
@@ -2848,18 +2842,13 @@ not_a_directory
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages, system_site_packages],
|
||||
..SearchPathSettings::new(vec![SystemPathBuf::from("/src")])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
},
|
||||
db.set_search_paths(
|
||||
SearchPathSettings {
|
||||
site_packages_paths: vec![venv_site_packages, system_site_packages],
|
||||
..SearchPathSettings::new(vec![SystemPathBuf::from("/src")])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
);
|
||||
|
||||
// The editable installs discovered from the `.pth` file in the first `site-packages` directory
|
||||
@@ -2924,15 +2913,10 @@ not_a_directory
|
||||
std::os::unix::fs::symlink(a_package_target.as_std_path(), a_src.as_std_path())
|
||||
.context("Failed to symlink `src/a` to `a-package`")?;
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings::new(vec![src])
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("valid search path settings"),
|
||||
},
|
||||
db.set_search_paths(
|
||||
SearchPathSettings::new(vec![src])
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings"),
|
||||
);
|
||||
|
||||
// Now try to resolve the module `A` (note the capital `A` instead of `a`).
|
||||
@@ -2964,19 +2948,14 @@ not_a_directory
|
||||
let mut db = TestDb::new();
|
||||
db.write_file(&installed_foo_module, "").unwrap();
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::new(vec![project_directory])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.unwrap(),
|
||||
},
|
||||
);
|
||||
let search_paths = SearchPathSettings {
|
||||
src_roots: vec![project_directory],
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings");
|
||||
db.set_search_paths(search_paths);
|
||||
|
||||
let foo_module_file = File::new(&db, FilePath::System(installed_foo_module));
|
||||
let module = file_to_module(&db, foo_module_file).unwrap();
|
||||
105
crates/ty_module_resolver/src/settings.rs
Normal file
105
crates/ty_module_resolver/src/settings.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
//! Search path configuration settings.
|
||||
|
||||
use ruff_db::system::{System, SystemPathBuf};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
|
||||
use crate::path::SearchPathError;
|
||||
use crate::resolve::SearchPaths;
|
||||
use crate::typeshed::TypeshedVersionsParseError;
|
||||
|
||||
/// How to handle apparent misconfiguration
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, get_size2::GetSize)]
|
||||
pub enum MisconfigurationMode {
|
||||
/// Settings Failure Is Not An Error.
|
||||
///
|
||||
/// This is used by the default database, which we are incentivized to make infallible,
|
||||
/// while still trying to "do our best" to set things up properly where we can.
|
||||
UseDefault,
|
||||
/// Settings Failure Is An Error.
|
||||
#[default]
|
||||
Fail,
|
||||
}
|
||||
|
||||
/// Configures the search paths for module resolution.
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct SearchPathSettings {
|
||||
/// List of user-provided paths that should take first priority in the module resolution.
|
||||
/// Examples in other type checkers are mypy's MYPYPATH environment variable,
|
||||
/// or pyright's stubPath configuration setting.
|
||||
pub extra_paths: Vec<SystemPathBuf>,
|
||||
|
||||
/// The root of the project, used for finding first-party modules.
|
||||
pub src_roots: Vec<SystemPathBuf>,
|
||||
|
||||
/// Optional path to a "custom typeshed" directory on disk for us to use for standard-library types.
|
||||
/// If this is not provided, we will fallback to our vendored typeshed stubs for the stdlib,
|
||||
/// bundled as a zip file in the binary
|
||||
pub custom_typeshed: Option<SystemPathBuf>,
|
||||
|
||||
/// List of site packages paths to use.
|
||||
pub site_packages_paths: Vec<SystemPathBuf>,
|
||||
|
||||
/// Option path to the real stdlib on the system, and not some instance of typeshed.
|
||||
///
|
||||
/// We should ideally only ever use this for things like goto-definition,
|
||||
/// where typeshed isn't the right answer.
|
||||
pub real_stdlib_path: Option<SystemPathBuf>,
|
||||
|
||||
/// How to handle apparent misconfiguration
|
||||
pub misconfiguration_mode: MisconfigurationMode,
|
||||
}
|
||||
|
||||
impl SearchPathSettings {
|
||||
pub fn new(src_roots: Vec<SystemPathBuf>) -> Self {
|
||||
Self {
|
||||
src_roots,
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
SearchPathSettings {
|
||||
src_roots: vec![],
|
||||
extra_paths: vec![],
|
||||
custom_typeshed: None,
|
||||
site_packages_paths: vec![],
|
||||
real_stdlib_path: None,
|
||||
misconfiguration_mode: MisconfigurationMode::Fail,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_search_paths(
|
||||
&self,
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
) -> Result<SearchPaths, SearchPathSettingsError> {
|
||||
SearchPaths::from_settings(self, system, vendored)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumeration describing the various ways in which validation of the search paths options might fail.
|
||||
///
|
||||
/// If validation fails for a search path derived from the user settings,
|
||||
/// a message must be displayed to the user,
|
||||
/// as type checking cannot be done reliably in these circumstances.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SearchPathSettingsError {
|
||||
#[error(transparent)]
|
||||
InvalidSearchPath(#[from] SearchPathError),
|
||||
|
||||
/// The typeshed path provided by the user is a directory,
|
||||
/// but `stdlib/VERSIONS` could not be read.
|
||||
/// (This is only relevant for stdlib search paths.)
|
||||
#[error("Failed to read the custom typeshed versions file '{path}'")]
|
||||
FailedToReadVersionsFile {
|
||||
path: SystemPathBuf,
|
||||
#[source]
|
||||
error: std::io::Error,
|
||||
},
|
||||
|
||||
/// The path provided by the user is a directory,
|
||||
/// and a `stdlib/VERSIONS` file exists, but it fails to parse.
|
||||
/// (This is only relevant for stdlib search paths.)
|
||||
#[error(transparent)]
|
||||
VersionsParseError(#[from] TypeshedVersionsParseError),
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use ruff_db::Db;
|
||||
use ruff_db::Db as _;
|
||||
use ruff_db::files::FileRootKind;
|
||||
use ruff_db::system::{
|
||||
DbWithTestSystem as _, DbWithWritableSystem as _, SystemPath, SystemPathBuf,
|
||||
@@ -7,8 +7,7 @@ use ruff_db::vendored::VendoredPathBuf;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
use crate::program::{Program, SearchPathSettings};
|
||||
use crate::{ProgramSettings, PythonPlatform, PythonVersionSource, PythonVersionWithSource};
|
||||
use crate::settings::SearchPathSettings;
|
||||
|
||||
/// A test case for the module resolver.
|
||||
///
|
||||
@@ -20,7 +19,7 @@ pub(crate) struct TestCase<T> {
|
||||
pub(crate) stdlib: T,
|
||||
// Most test cases only ever need a single `site-packages` directory,
|
||||
// so this is a single directory instead of a `Vec` of directories,
|
||||
// like it is in `ruff_db::Program`.
|
||||
// like it is in `SearchPaths`.
|
||||
pub(crate) site_packages: SystemPathBuf,
|
||||
pub(crate) python_version: PythonVersion,
|
||||
}
|
||||
@@ -105,7 +104,6 @@ pub(crate) struct UnspecifiedTypeshed;
|
||||
pub(crate) struct TestCaseBuilder<T> {
|
||||
typeshed_option: T,
|
||||
python_version: PythonVersion,
|
||||
python_platform: PythonPlatform,
|
||||
first_party_files: Vec<FileSpec>,
|
||||
site_packages_files: Vec<FileSpec>,
|
||||
// Additional file roots (beyond site_packages, src and stdlib)
|
||||
@@ -166,7 +164,6 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
Self {
|
||||
typeshed_option: UnspecifiedTypeshed,
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
first_party_files: vec![],
|
||||
site_packages_files: vec![],
|
||||
roots: vec![],
|
||||
@@ -178,7 +175,6 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: _,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
@@ -186,7 +182,6 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
TestCaseBuilder {
|
||||
typeshed_option: VendoredTypeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
@@ -201,7 +196,6 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: _,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
@@ -210,7 +204,6 @@ impl TestCaseBuilder<UnspecifiedTypeshed> {
|
||||
TestCaseBuilder {
|
||||
typeshed_option: typeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
@@ -241,18 +234,29 @@ impl TestCaseBuilder<MockedTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
} = self;
|
||||
|
||||
let mut db = TestDb::new();
|
||||
let mut db = TestDb::new().with_python_version(python_version);
|
||||
|
||||
let site_packages =
|
||||
Self::write_mock_directory(&mut db, "/site-packages", site_packages_files);
|
||||
let src = Self::write_mock_directory(&mut db, "/src", first_party_files);
|
||||
let typeshed = Self::build_typeshed_mock(&mut db, &typeshed_option);
|
||||
let stdlib = typeshed.join("stdlib");
|
||||
|
||||
let search_paths = SearchPathSettings {
|
||||
src_roots: vec![src.clone()],
|
||||
custom_typeshed: Some(typeshed),
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings");
|
||||
|
||||
db = db.with_search_paths(search_paths);
|
||||
|
||||
// This root is needed for correct Salsa tracking.
|
||||
// Namely, a `SearchPath` is treated as an input, and
|
||||
@@ -262,36 +266,19 @@ impl TestCaseBuilder<MockedTypeshed> {
|
||||
// here, they won't get added.
|
||||
//
|
||||
// Roots for other search paths are added as part of
|
||||
// search path initialization in `Program::from_settings`,
|
||||
// search path initialization in `SearchPaths::from_settings`,
|
||||
// and any remaining are added below.
|
||||
db.files()
|
||||
.try_add_root(&db, SystemPath::new("/src"), FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource {
|
||||
version: python_version,
|
||||
source: PythonVersionSource::default(),
|
||||
},
|
||||
python_platform,
|
||||
search_paths: SearchPathSettings {
|
||||
custom_typeshed: Some(typeshed.clone()),
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::new(vec![src.clone()])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("valid search path settings"),
|
||||
},
|
||||
);
|
||||
|
||||
let stdlib = typeshed.join("stdlib");
|
||||
db.files()
|
||||
.try_add_root(&db, &stdlib, FileRootKind::LibrarySearchPath);
|
||||
|
||||
for root in &roots {
|
||||
db.files()
|
||||
.try_add_root(&db, root, FileRootKind::LibrarySearchPath);
|
||||
}
|
||||
|
||||
TestCase {
|
||||
db,
|
||||
src,
|
||||
@@ -324,42 +311,34 @@ impl TestCaseBuilder<VendoredTypeshed> {
|
||||
let TestCaseBuilder {
|
||||
typeshed_option: VendoredTypeshed,
|
||||
python_version,
|
||||
python_platform,
|
||||
first_party_files,
|
||||
site_packages_files,
|
||||
roots,
|
||||
} = self;
|
||||
|
||||
let mut db = TestDb::new();
|
||||
let mut db = TestDb::new().with_python_version(python_version);
|
||||
|
||||
let site_packages =
|
||||
Self::write_mock_directory(&mut db, "/site-packages", site_packages_files);
|
||||
let src = Self::write_mock_directory(&mut db, "/src", first_party_files);
|
||||
|
||||
let search_paths = SearchPathSettings {
|
||||
src_roots: vec![src.clone()],
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("Valid search path settings");
|
||||
|
||||
db = db.with_search_paths(search_paths);
|
||||
|
||||
db.files()
|
||||
.try_add_root(&db, SystemPath::new("/src"), FileRootKind::Project);
|
||||
|
||||
Program::from_settings(
|
||||
&db,
|
||||
ProgramSettings {
|
||||
python_version: PythonVersionWithSource {
|
||||
version: python_version,
|
||||
source: PythonVersionSource::default(),
|
||||
},
|
||||
python_platform,
|
||||
search_paths: SearchPathSettings {
|
||||
site_packages_paths: vec![site_packages.clone()],
|
||||
..SearchPathSettings::new(vec![src.clone()])
|
||||
}
|
||||
.to_search_paths(db.system(), db.vendored())
|
||||
.expect("valid search path settings"),
|
||||
},
|
||||
);
|
||||
|
||||
for root in &roots {
|
||||
db.files()
|
||||
.try_add_root(&db, root, FileRootKind::LibrarySearchPath);
|
||||
}
|
||||
|
||||
TestCase {
|
||||
db,
|
||||
src,
|
||||
@@ -8,13 +8,10 @@ use ruff_db::vendored::VendoredFileSystem;
|
||||
use ruff_python_ast::{PythonVersion, PythonVersionDeserializationError};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::Program;
|
||||
use crate::db::Db;
|
||||
use crate::module_name::ModuleName;
|
||||
|
||||
pub(in crate::module_resolver) fn vendored_typeshed_versions(
|
||||
vendored: &VendoredFileSystem,
|
||||
) -> TypeshedVersions {
|
||||
pub fn vendored_typeshed_versions(vendored: &VendoredFileSystem) -> TypeshedVersions {
|
||||
TypeshedVersions::from_str(
|
||||
&vendored
|
||||
.read_to_string("stdlib/VERSIONS")
|
||||
@@ -24,7 +21,7 @@ pub(in crate::module_resolver) fn vendored_typeshed_versions(
|
||||
}
|
||||
|
||||
pub(crate) fn typeshed_versions(db: &dyn Db) -> &TypeshedVersions {
|
||||
Program::get(db).search_paths(db).typeshed_versions()
|
||||
db.search_paths().typeshed_versions()
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
@@ -61,7 +58,7 @@ impl std::error::Error for TypeshedVersionsParseError {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)]
|
||||
pub(crate) enum TypeshedVersionsParseErrorKind {
|
||||
pub enum TypeshedVersionsParseErrorKind {
|
||||
#[error("File has too many lines ({0}); maximum allowed is {max_allowed}", max_allowed = NonZeroU16::MAX)]
|
||||
TooManyLines(NonZeroUsize),
|
||||
#[error("Expected every non-comment line to have exactly one colon")]
|
||||
@@ -75,16 +72,16 @@ pub(crate) enum TypeshedVersionsParseErrorKind {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
|
||||
pub(crate) struct TypeshedVersions(FxHashMap<ModuleName, PyVersionRange>);
|
||||
pub struct TypeshedVersions(FxHashMap<ModuleName, PyVersionRange>);
|
||||
|
||||
impl TypeshedVersions {
|
||||
#[must_use]
|
||||
pub(crate) fn exact(&self, module_name: &ModuleName) -> Option<&PyVersionRange> {
|
||||
pub fn exact(&self, module_name: &ModuleName) -> Option<&PyVersionRange> {
|
||||
self.0.get(module_name)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(in crate::module_resolver) fn query_module(
|
||||
pub(crate) fn query_module(
|
||||
&self,
|
||||
module: &ModuleName,
|
||||
python_version: PythonVersion,
|
||||
@@ -231,14 +228,14 @@ impl fmt::Display for TypeshedVersions {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum PyVersionRange {
|
||||
pub enum PyVersionRange {
|
||||
AvailableFrom(RangeFrom<PythonVersion>),
|
||||
AvailableWithin(RangeInclusive<PythonVersion>),
|
||||
}
|
||||
|
||||
impl PyVersionRange {
|
||||
#[must_use]
|
||||
pub(crate) fn contains(&self, version: PythonVersion) -> bool {
|
||||
pub fn contains(&self, version: PythonVersion) -> bool {
|
||||
match self {
|
||||
Self::AvailableFrom(inner) => inner.contains(&version),
|
||||
Self::AvailableWithin(inner) => inner.contains(&version),
|
||||
@@ -246,7 +243,7 @@ impl PyVersionRange {
|
||||
}
|
||||
|
||||
/// Display the version range in a way that is suitable for rendering in user-facing diagnostics.
|
||||
pub(crate) fn diagnostic_display(&self) -> impl std::fmt::Display {
|
||||
pub fn diagnostic_display(&self) -> impl std::fmt::Display {
|
||||
struct DiagnosticDisplay<'a>(&'a PyVersionRange);
|
||||
|
||||
impl fmt::Display for DiagnosticDisplay<'_> {
|
||||
@@ -21,7 +21,9 @@ ruff_python_ast = { workspace = true, features = ["serde"] }
|
||||
ruff_python_formatter = { workspace = true, optional = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ty_combine = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_python_semantic = { workspace = true, features = ["serde"] }
|
||||
ty_python_types = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ use ruff_db::files::{File, Files};
|
||||
use ruff_db::system::System;
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use salsa::{Database, Event, Setter};
|
||||
use ty_module_resolver::SearchPaths;
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{Db as SemanticDb, Program};
|
||||
use ty_python_semantic::{AnalysisSettings, Db as SemanticDb, Program};
|
||||
|
||||
mod changes;
|
||||
|
||||
@@ -446,6 +447,13 @@ impl SalsaMemoryDump {
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl ty_module_resolver::Db for ProjectDatabase {
|
||||
fn search_paths(&self) -> &SearchPaths {
|
||||
Program::get(self).search_paths(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl SemanticDb for ProjectDatabase {
|
||||
fn should_check_file(&self, file: File) -> bool {
|
||||
@@ -459,7 +467,11 @@ impl SemanticDb for ProjectDatabase {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
ty_python_semantic::default_lint_registry()
|
||||
ty_python_types::default_lint_registry()
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
self.project().settings(self).analysis()
|
||||
}
|
||||
|
||||
fn verbose(&self) -> bool {
|
||||
@@ -523,9 +535,10 @@ pub(crate) mod tests {
|
||||
use ruff_db::files::{FileRootKind, Files};
|
||||
use ruff_db::system::{DbWithTestSystem, System, TestSystem};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use ty_module_resolver::SearchPathSettings;
|
||||
use ty_python_semantic::lint::{LintRegistry, RuleSelection};
|
||||
use ty_python_semantic::{
|
||||
Program, ProgramSettings, PythonPlatform, PythonVersionWithSource, SearchPathSettings,
|
||||
AnalysisSettings, Program, ProgramSettings, PythonPlatform, PythonVersionWithSource,
|
||||
};
|
||||
|
||||
use crate::db::Db;
|
||||
@@ -627,6 +640,13 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl ty_module_resolver::Db for TestDb {
|
||||
fn search_paths(&self) -> &ty_module_resolver::SearchPaths {
|
||||
Program::get(self).search_paths(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl ty_python_semantic::Db for TestDb {
|
||||
fn should_check_file(&self, file: ruff_db::files::File) -> bool {
|
||||
@@ -638,7 +658,11 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
ty_python_semantic::default_lint_registry()
|
||||
ty_python_types::default_lint_registry()
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
self.project().settings(self).analysis()
|
||||
}
|
||||
|
||||
fn verbose(&self) -> bool {
|
||||
|
||||
@@ -245,7 +245,9 @@ impl ProjectDatabase {
|
||||
|
||||
if result.project_changed {
|
||||
let new_project_metadata = match config_file_override {
|
||||
Some(config_file) => ProjectMetadata::from_config_file(config_file, self.system()),
|
||||
Some(config_file) => {
|
||||
ProjectMetadata::from_config_file(config_file, &project_root, self.system())
|
||||
}
|
||||
None => ProjectMetadata::discover(&project_root, self.system()),
|
||||
};
|
||||
match new_project_metadata {
|
||||
|
||||
@@ -29,7 +29,7 @@ use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use ty_python_semantic::add_inferred_python_version_hint_to_diagnostic;
|
||||
use ty_python_semantic::lint::RuleSelection;
|
||||
use ty_python_semantic::types::check_types;
|
||||
use ty_python_types::types::check_types;
|
||||
|
||||
mod db;
|
||||
mod files;
|
||||
@@ -769,7 +769,7 @@ mod tests {
|
||||
use ruff_db::system::{DbWithTestSystem, DbWithWritableSystem as _, SystemPath, SystemPathBuf};
|
||||
use ruff_db::testing::assert_function_query_was_not_run;
|
||||
use ruff_python_ast::name::Name;
|
||||
use ty_python_semantic::types::check_types;
|
||||
use ty_python_types::types::check_types;
|
||||
|
||||
#[test]
|
||||
fn check_file_skips_type_checking_when_file_cant_be_read() -> ruff_db::system::Result<()> {
|
||||
|
||||
@@ -56,6 +56,7 @@ impl ProjectMetadata {
|
||||
|
||||
pub fn from_config_file(
|
||||
path: SystemPathBuf,
|
||||
root: &SystemPath,
|
||||
system: &dyn System,
|
||||
) -> Result<Self, ProjectMetadataError> {
|
||||
tracing::debug!("Using overridden configuration file at '{path}'");
|
||||
@@ -70,8 +71,8 @@ impl ProjectMetadata {
|
||||
let options = config_file.into_options();
|
||||
|
||||
Ok(Self {
|
||||
name: Name::new(system.current_directory().file_name().unwrap_or("root")),
|
||||
root: system.current_directory().to_path_buf(),
|
||||
name: Name::new(root.file_name().unwrap_or("root")),
|
||||
root: root.to_path_buf(),
|
||||
options,
|
||||
extra_configuration_paths: vec![path],
|
||||
misconfiguration_mode: MisconfigurationMode::Fail,
|
||||
|
||||
@@ -28,11 +28,12 @@ use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use ty_combine::Combine;
|
||||
use ty_module_resolver::{SearchPathSettings, SearchPathSettingsError, SearchPaths};
|
||||
use ty_python_semantic::lint::{Level, LintSource, RuleSelection};
|
||||
use ty_python_semantic::{
|
||||
MisconfigurationMode, ProgramSettings, PythonEnvironment, PythonPlatform,
|
||||
PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource, SearchPathSettings,
|
||||
SearchPathValidationError, SearchPaths, SitePackagesPaths, SysPrefixPathOrigin,
|
||||
AnalysisSettings, MisconfigurationMode, ProgramSettings, PythonEnvironment, PythonPlatform,
|
||||
PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource, SitePackagesPaths,
|
||||
SysPrefixPathOrigin,
|
||||
};
|
||||
use ty_static::EnvVars;
|
||||
|
||||
@@ -86,6 +87,10 @@ pub struct Options {
|
||||
#[option_group]
|
||||
pub terminal: Option<TerminalOptions>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[option_group]
|
||||
pub analysis: Option<AnalysisOptions>,
|
||||
|
||||
/// Override configurations for specific file patterns.
|
||||
///
|
||||
/// Each override specifies include/exclude patterns and rule configurations
|
||||
@@ -258,7 +263,7 @@ impl Options {
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
misconfiguration_mode: MisconfigurationMode,
|
||||
) -> Result<SearchPaths, SearchPathValidationError> {
|
||||
) -> Result<SearchPaths, SearchPathSettingsError> {
|
||||
let environment = self.environment.or_default();
|
||||
let src = self.src.or_default();
|
||||
|
||||
@@ -434,6 +439,8 @@ impl Options {
|
||||
color: colored::control::SHOULD_COLORIZE.should_colorize(),
|
||||
})?;
|
||||
|
||||
let analysis = self.analysis.or_default().to_settings();
|
||||
|
||||
let overrides = self
|
||||
.to_overrides_settings(db, project_root, &mut diagnostics)
|
||||
.map_err(|err| ToSettingsError {
|
||||
@@ -446,6 +453,7 @@ impl Options {
|
||||
rules: Arc::new(rules),
|
||||
terminal,
|
||||
src,
|
||||
analysis,
|
||||
overrides,
|
||||
};
|
||||
|
||||
@@ -875,10 +883,7 @@ impl Rules {
|
||||
let lint_source = match source {
|
||||
ValueSource::File(_) => LintSource::File,
|
||||
ValueSource::Cli => LintSource::Cli,
|
||||
|
||||
ValueSource::Editor => {
|
||||
unreachable!("Can't configure rules from the user's editor")
|
||||
}
|
||||
ValueSource::Editor => LintSource::Editor,
|
||||
};
|
||||
if let Ok(severity) = Severity::try_from(**level) {
|
||||
selection.enable(lint, severity, lint_source);
|
||||
@@ -1014,7 +1019,12 @@ fn build_include_filter(
|
||||
SubDiagnosticSeverity::Info,
|
||||
"The pattern was specified on the CLI",
|
||||
)),
|
||||
ValueSource::Editor => unreachable!("Can't configure includes from the user's editor"),
|
||||
ValueSource::Editor => {
|
||||
diagnostic.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
"The pattern was specified in the editor settings.",
|
||||
))
|
||||
}
|
||||
}
|
||||
})?;
|
||||
}
|
||||
@@ -1097,9 +1107,10 @@ fn build_exclude_filter(
|
||||
SubDiagnosticSeverity::Info,
|
||||
"The pattern was specified on the CLI",
|
||||
)),
|
||||
ValueSource::Editor => unreachable!(
|
||||
"Can't configure excludes from the user's editor"
|
||||
)
|
||||
ValueSource::Editor => diagnostic.sub(SubDiagnostic::new(
|
||||
SubDiagnosticSeverity::Info,
|
||||
"The pattern was specified in the editor settings",
|
||||
))
|
||||
}
|
||||
})?;
|
||||
}
|
||||
@@ -1250,6 +1261,55 @@ pub struct TerminalOptions {
|
||||
pub error_on_warning: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Combine,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
OptionsMetadata,
|
||||
get_size2::GetSize,
|
||||
)]
|
||||
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct AnalysisOptions {
|
||||
/// 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`.
|
||||
#[option(
|
||||
default = r#"true"#,
|
||||
value_type = "bool",
|
||||
example = r#"
|
||||
# Disable support for `type: ignore` comments
|
||||
respect-type-ignore-comments = false
|
||||
"#
|
||||
)]
|
||||
respect_type_ignore_comments: Option<bool>,
|
||||
}
|
||||
|
||||
impl AnalysisOptions {
|
||||
fn to_settings(&self) -> AnalysisSettings {
|
||||
let AnalysisSettings {
|
||||
respect_type_ignore_comments: respect_type_ignore_default,
|
||||
} = AnalysisSettings::default();
|
||||
|
||||
AnalysisSettings {
|
||||
respect_type_ignore_comments: self
|
||||
.respect_type_ignore_comments
|
||||
.unwrap_or(respect_type_ignore_default),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration override that applies to specific files based on glob patterns.
|
||||
///
|
||||
/// An override allows you to apply different rule configurations to specific
|
||||
@@ -1606,7 +1666,7 @@ mod schema {
|
||||
fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
let registry = ty_python_semantic::default_lint_registry();
|
||||
let registry = ty_python_types::default_lint_registry();
|
||||
let level_schema = generator.subschema_for::<super::Level>();
|
||||
|
||||
let properties: Map<String, Value> = registry
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use ruff_db::files::File;
|
||||
use ty_combine::Combine;
|
||||
use ty_python_semantic::AnalysisSettings;
|
||||
use ty_python_semantic::lint::RuleSelection;
|
||||
|
||||
use crate::metadata::options::{InnerOverrideOptions, OutputFormat};
|
||||
@@ -25,6 +26,7 @@ pub struct Settings {
|
||||
pub(super) rules: Arc<RuleSelection>,
|
||||
pub(super) terminal: TerminalSettings,
|
||||
pub(super) src: SrcSettings,
|
||||
pub(super) analysis: AnalysisSettings,
|
||||
|
||||
/// Settings for configuration overrides that apply to specific file patterns.
|
||||
///
|
||||
@@ -54,6 +56,10 @@ impl Settings {
|
||||
pub fn overrides(&self) -> &[Override] {
|
||||
&self.overrides
|
||||
}
|
||||
|
||||
pub fn analysis(&self) -> &AnalysisSettings {
|
||||
&self.analysis
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default, get_size2::GetSize)]
|
||||
|
||||
@@ -5,7 +5,7 @@ use tracing::info;
|
||||
|
||||
use ruff_cache::{CacheKey, CacheKeyHasher};
|
||||
use ruff_db::system::{SystemPath, SystemPathBuf};
|
||||
use ty_python_semantic::system_module_search_paths;
|
||||
use ty_module_resolver::system_module_search_paths;
|
||||
|
||||
use crate::db::{Db, ProjectDatabase};
|
||||
use crate::watch::Watcher;
|
||||
|
||||
@@ -19,11 +19,11 @@ ruff_macros = { workspace = true }
|
||||
ruff_memory_usage = { workspace = true }
|
||||
ruff_python_ast = { workspace = true, features = ["salsa"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ruff_python_stdlib = { workspace = true }
|
||||
ruff_source_file = { workspace = true }
|
||||
ruff_text_size = { workspace = true }
|
||||
ruff_python_literal = { workspace = true }
|
||||
ruff_python_trivia = { workspace = true }
|
||||
ty_module_resolver = { workspace = true }
|
||||
ty_combine = { workspace = true }
|
||||
ty_static = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
@@ -31,8 +31,6 @@ bitflags = { workspace = true }
|
||||
bitvec = { workspace = true }
|
||||
camino = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
drop_bomb = { workspace = true }
|
||||
get-size2 = { workspace = true, features = ["indexmap", "ordermap"] }
|
||||
indexmap = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
@@ -46,9 +44,8 @@ schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
smallvec = { workspace = true }
|
||||
ty_vendored = { workspace = true, optional = true }
|
||||
static_assertions = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
strsim = "0.11.1"
|
||||
@@ -56,29 +53,19 @@ strsim = "0.11.1"
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["testing", "os"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
ty_python_semantic = { workspace = true, features = ["testing"] }
|
||||
ty_static = { workspace = true }
|
||||
ty_test = { workspace = true }
|
||||
ty_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
datatest-stable = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
indoc = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
quickcheck = { version = "1.0.3", default-features = false }
|
||||
quickcheck_macros = { version = "1.0.0" }
|
||||
|
||||
[features]
|
||||
schemars = ["dep:schemars", "dep:serde_json"]
|
||||
serde = ["ruff_db/serde", "dep:serde", "ruff_python_ast/serde"]
|
||||
testing = []
|
||||
|
||||
[[test]]
|
||||
name = "mdtest"
|
||||
harness = false
|
||||
testing = ["dep:ty_vendored", "ruff_db/testing"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.cargo-shear]
|
||||
# Used via macro expansion.
|
||||
ignored = ["quickcheck"]
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use crate::AnalysisSettings;
|
||||
use crate::lint::{LintRegistry, RuleSelection};
|
||||
use ruff_db::Db as SourceDb;
|
||||
use ruff_db::files::File;
|
||||
use ty_module_resolver::Db as ModuleResolverDb;
|
||||
|
||||
/// Database giving access to semantic information about a Python program.
|
||||
#[salsa::db]
|
||||
pub trait Db: SourceDb {
|
||||
pub trait Db: ModuleResolverDb {
|
||||
/// Returns `true` if the file should be checked.
|
||||
fn should_check_file(&self, file: File) -> bool;
|
||||
|
||||
@@ -13,22 +14,25 @@ pub trait Db: SourceDb {
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry;
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings;
|
||||
|
||||
/// Whether ty is running with logging verbosity INFO or higher (`-v` or more).
|
||||
fn verbose(&self) -> bool;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
#[cfg(any(test, feature = "testing"))]
|
||||
pub mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::program::{Program, SearchPathSettings};
|
||||
use crate::program::Program;
|
||||
use crate::{
|
||||
ProgramSettings, PythonPlatform, PythonVersionSource, PythonVersionWithSource,
|
||||
default_lint_registry,
|
||||
AnalysisSettings, ProgramSettings, PythonPlatform, PythonVersionSource,
|
||||
PythonVersionWithSource,
|
||||
};
|
||||
use ty_module_resolver::SearchPathSettings;
|
||||
|
||||
use super::Db;
|
||||
use crate::lint::{LintRegistry, RuleSelection};
|
||||
use crate::lint::{LintRegistry, LintRegistryBuilder, RuleSelection};
|
||||
use anyhow::Context;
|
||||
use ruff_db::Db as SourceDb;
|
||||
use ruff_db::files::{File, Files};
|
||||
@@ -37,23 +41,49 @@ pub(crate) mod tests {
|
||||
};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ty_module_resolver::Db as ModuleResolverDb;
|
||||
use ty_module_resolver::SearchPaths;
|
||||
|
||||
type Events = Arc<Mutex<Vec<salsa::Event>>>;
|
||||
|
||||
/// A default lint registry containing only the suppression lints.
|
||||
/// Full lint registry should be obtained from `ty_python_types`.
|
||||
fn test_lint_registry() -> &'static LintRegistry {
|
||||
static REGISTRY: std::sync::LazyLock<LintRegistry> = std::sync::LazyLock::new(|| {
|
||||
let mut builder = LintRegistryBuilder::default();
|
||||
crate::register_suppression_lints(&mut builder);
|
||||
builder.build()
|
||||
});
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct TestDb {
|
||||
pub struct TestDb {
|
||||
storage: salsa::Storage<Self>,
|
||||
files: Files,
|
||||
system: TestSystem,
|
||||
vendored: VendoredFileSystem,
|
||||
events: Events,
|
||||
rule_selection: Arc<RuleSelection>,
|
||||
lint_registry: Arc<LintRegistry>,
|
||||
analysis_settings: Arc<AnalysisSettings>,
|
||||
}
|
||||
|
||||
impl Default for TestDb {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestDb {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self::with_vendored(ty_vendored::file_system().clone())
|
||||
}
|
||||
|
||||
pub fn with_vendored(vendored: VendoredFileSystem) -> Self {
|
||||
let events = Events::default();
|
||||
let lint_registry = test_lint_registry();
|
||||
Self {
|
||||
storage: salsa::Storage::new(Some(Box::new({
|
||||
let events = events.clone();
|
||||
@@ -64,15 +94,17 @@ pub(crate) mod tests {
|
||||
}
|
||||
}))),
|
||||
system: TestSystem::default(),
|
||||
vendored: ty_vendored::file_system().clone(),
|
||||
vendored,
|
||||
events,
|
||||
files: Files::default(),
|
||||
rule_selection: Arc::new(RuleSelection::from_registry(default_lint_registry())),
|
||||
rule_selection: Arc::new(RuleSelection::from_registry(lint_registry)),
|
||||
lint_registry: Arc::new(lint_registry.clone()),
|
||||
analysis_settings: AnalysisSettings::default().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes the salsa events.
|
||||
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||
pub fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||
let mut events = self.events.lock().unwrap();
|
||||
|
||||
std::mem::take(&mut *events)
|
||||
@@ -82,7 +114,7 @@ pub(crate) mod tests {
|
||||
///
|
||||
/// ## Panics
|
||||
/// If there are any pending salsa snapshots.
|
||||
pub(crate) fn clear_salsa_events(&mut self) {
|
||||
pub fn clear_salsa_events(&mut self) {
|
||||
self.take_salsa_events();
|
||||
}
|
||||
}
|
||||
@@ -127,7 +159,11 @@ pub(crate) mod tests {
|
||||
}
|
||||
|
||||
fn lint_registry(&self) -> &LintRegistry {
|
||||
default_lint_registry()
|
||||
&self.lint_registry
|
||||
}
|
||||
|
||||
fn analysis_settings(&self) -> &AnalysisSettings {
|
||||
&self.analysis_settings
|
||||
}
|
||||
|
||||
fn verbose(&self) -> bool {
|
||||
@@ -135,10 +171,17 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl ModuleResolverDb for TestDb {
|
||||
fn search_paths(&self) -> &SearchPaths {
|
||||
Program::get(self).search_paths(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for TestDb {}
|
||||
|
||||
pub(crate) struct TestDbBuilder<'a> {
|
||||
pub struct TestDbBuilder<'a> {
|
||||
/// Target Python version
|
||||
python_version: PythonVersion,
|
||||
/// Target Python platform
|
||||
@@ -147,8 +190,14 @@ pub(crate) mod tests {
|
||||
files: Vec<(&'a str, &'a str)>,
|
||||
}
|
||||
|
||||
impl Default for TestDbBuilder<'_> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TestDbBuilder<'a> {
|
||||
pub(crate) fn new() -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
python_version: PythonVersion::default(),
|
||||
python_platform: PythonPlatform::default(),
|
||||
@@ -156,12 +205,14 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_python_version(mut self, version: PythonVersion) -> Self {
|
||||
#[must_use]
|
||||
pub fn with_python_version(mut self, version: PythonVersion) -> Self {
|
||||
self.python_version = version;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn with_file(
|
||||
#[must_use]
|
||||
pub fn with_file(
|
||||
mut self,
|
||||
path: &'a (impl AsRef<SystemPath> + ?Sized),
|
||||
content: &'a str,
|
||||
@@ -170,7 +221,7 @@ pub(crate) mod tests {
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> anyhow::Result<TestDb> {
|
||||
pub fn build(self) -> anyhow::Result<TestDb> {
|
||||
let mut db = TestDb::new();
|
||||
|
||||
let src_root = SystemPathBuf::from("/src");
|
||||
@@ -197,7 +248,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn setup_db() -> TestDb {
|
||||
pub fn setup_db() -> TestDb {
|
||||
TestDbBuilder::new().build().expect("valid TestDb setup")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
Db, Program, PythonVersionWithSource, lint::lint_documentation_url, types::TypeCheckDiagnostics,
|
||||
Db, Program, PythonVersionWithSource, lint::lint_documentation_url,
|
||||
suppression::TypeCheckDiagnostics,
|
||||
};
|
||||
use ruff_db::{
|
||||
diagnostic::{Annotation, Diagnostic, DiagnosticId, SubDiagnostic, SubDiagnosticSeverity},
|
||||
@@ -9,7 +10,7 @@ use std::cell::RefCell;
|
||||
use std::fmt::Write;
|
||||
|
||||
/// Suggest a name from `existing_names` that is similar to `wrong_name`.
|
||||
pub(crate) fn did_you_mean<S: AsRef<str>, T: AsRef<str>>(
|
||||
pub fn did_you_mean<S: AsRef<str>, T: AsRef<str>>(
|
||||
existing_names: impl Iterator<Item = S>,
|
||||
wrong_name: T,
|
||||
) -> Option<String> {
|
||||
@@ -127,7 +128,7 @@ pub fn add_inferred_python_version_hint_to_diagnostic(
|
||||
/// Format a list of elements as a human-readable enumeration.
|
||||
///
|
||||
/// Encloses every element in backticks (`1`, `2` and `3`).
|
||||
pub(crate) fn format_enumeration<I, IT, D>(elements: I) -> String
|
||||
pub fn format_enumeration<I, IT, D>(elements: I) -> String
|
||||
where
|
||||
I: IntoIterator<IntoIter = IT>,
|
||||
IT: ExactSizeIterator<Item = D> + DoubleEndedIterator,
|
||||
@@ -160,7 +161,7 @@ where
|
||||
/// associated file is equivalent to the file being type checked. As a result,
|
||||
/// if either is violated, then the `Drop` impl on `DiagnosticGuard` will
|
||||
/// panic.
|
||||
pub(super) struct DiagnosticGuard<'sink> {
|
||||
pub struct DiagnosticGuard<'sink> {
|
||||
/// The file of the primary span (to which file does this diagnostic belong).
|
||||
file: File,
|
||||
|
||||
@@ -187,7 +188,7 @@ pub(super) struct DiagnosticGuard<'sink> {
|
||||
}
|
||||
|
||||
impl<'sink> DiagnosticGuard<'sink> {
|
||||
pub(crate) fn new(
|
||||
pub fn new(
|
||||
file: File,
|
||||
sink: &'sink std::cell::RefCell<TypeCheckDiagnostics>,
|
||||
diag: Diagnostic,
|
||||
|
||||
15
crates/ty_python_semantic/src/has_tracked_scope.rs
Normal file
15
crates/ty_python_semantic/src/has_tracked_scope.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use ruff_python_ast::{self as ast, HasNodeIndex};
|
||||
|
||||
/// Implemented by types for which the semantic index tracks their scope.
|
||||
pub trait HasTrackedScope: HasNodeIndex {}
|
||||
|
||||
impl HasTrackedScope for ast::Expr {}
|
||||
|
||||
impl HasTrackedScope for ast::ExprRef<'_> {}
|
||||
impl HasTrackedScope for &ast::ExprRef<'_> {}
|
||||
|
||||
// We never explicitly register the scope of an `Identifier`.
|
||||
// However, `ExpressionsScopeMap` stores the text ranges of each scope.
|
||||
// That allows us to look up the identifier's scope for as long as it's
|
||||
// inside an expression (because the ranges overlap).
|
||||
impl HasTrackedScope for ast::Identifier {}
|
||||
@@ -4,80 +4,70 @@
|
||||
)]
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use crate::lint::{LintRegistry, LintRegistryBuilder};
|
||||
use crate::lint::LintRegistryBuilder;
|
||||
use crate::suppression::{
|
||||
IGNORE_COMMENT_UNKNOWN_RULE, INVALID_IGNORE_COMMENT, UNUSED_IGNORE_COMMENT,
|
||||
};
|
||||
pub use db::Db;
|
||||
pub use diagnostic::add_inferred_python_version_hint_to_diagnostic;
|
||||
pub use module_name::{ModuleName, ModuleNameResolutionError};
|
||||
pub use module_resolver::{
|
||||
KnownModule, Module, SearchPath, SearchPathValidationError, SearchPaths, all_modules,
|
||||
list_modules, resolve_module, resolve_module_confident, resolve_real_module,
|
||||
resolve_real_module_confident, resolve_real_shadowable_module, system_module_search_paths,
|
||||
};
|
||||
pub use program::{
|
||||
MisconfigurationMode, Program, ProgramSettings, PythonVersionFileSource, PythonVersionSource,
|
||||
PythonVersionWithSource, SearchPathSettings,
|
||||
Program, ProgramSettings, PythonVersionFileSource, PythonVersionSource, PythonVersionWithSource,
|
||||
};
|
||||
pub use python_platform::PythonPlatform;
|
||||
use rustc_hash::FxHasher;
|
||||
pub use semantic_model::{
|
||||
Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel,
|
||||
};
|
||||
pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin};
|
||||
pub use suppression::create_suppression_fix;
|
||||
pub use types::DisplaySettings;
|
||||
pub use types::ide_support::{
|
||||
ImportAliasResolution, ResolvedDefinition, definitions_for_attribute, definitions_for_bin_op,
|
||||
definitions_for_imported_symbol, definitions_for_name, definitions_for_unary_op,
|
||||
map_stub_definition,
|
||||
};
|
||||
pub use suppression::{FileSuppressionId, TypeCheckDiagnostics, create_suppression_fix};
|
||||
pub use ty_module_resolver::MisconfigurationMode;
|
||||
|
||||
pub mod ast_node_ref;
|
||||
mod db;
|
||||
mod dunder_all;
|
||||
pub mod db;
|
||||
pub(crate) mod has_tracked_scope;
|
||||
pub mod lint;
|
||||
pub(crate) mod list;
|
||||
mod module_name;
|
||||
mod module_resolver;
|
||||
mod node_key;
|
||||
pub(crate) mod place;
|
||||
pub mod list;
|
||||
pub mod node_key;
|
||||
pub mod place_qualifiers;
|
||||
mod program;
|
||||
mod python_platform;
|
||||
mod rank;
|
||||
pub mod rank;
|
||||
pub mod semantic_index;
|
||||
mod semantic_model;
|
||||
pub(crate) mod site_packages;
|
||||
mod subscript;
|
||||
mod suppression;
|
||||
pub mod types;
|
||||
mod unpack;
|
||||
pub mod subscript;
|
||||
pub mod suppression;
|
||||
mod truthiness;
|
||||
pub mod unpack;
|
||||
|
||||
mod diagnostic;
|
||||
#[cfg(feature = "testing")]
|
||||
pub mod pull_types;
|
||||
pub use truthiness::Truthiness;
|
||||
|
||||
type FxOrderMap<K, V> = ordermap::map::OrderMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub mod diagnostic;
|
||||
|
||||
/// Returns the default registry with all known semantic lints.
|
||||
pub fn default_lint_registry() -> &'static LintRegistry {
|
||||
static REGISTRY: std::sync::LazyLock<LintRegistry> = std::sync::LazyLock::new(|| {
|
||||
let mut registry = LintRegistryBuilder::default();
|
||||
register_lints(&mut registry);
|
||||
registry.build()
|
||||
});
|
||||
pub type FxOrderMap<K, V> = ordermap::map::OrderMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
/// Register all known semantic lints.
|
||||
pub fn register_lints(registry: &mut LintRegistryBuilder) {
|
||||
types::register_lints(registry);
|
||||
/// Register suppression-related lints (used by `ty_python_types` to build the full registry).
|
||||
pub fn register_suppression_lints(registry: &mut LintRegistryBuilder) {
|
||||
registry.register_lint(&UNUSED_IGNORE_COMMENT);
|
||||
registry.register_lint(&IGNORE_COMMENT_UNKNOWN_RULE);
|
||||
registry.register_lint(&INVALID_IGNORE_COMMENT);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)]
|
||||
pub struct AnalysisSettings {
|
||||
/// Whether errors can be suppressed with `type: ignore` comments.
|
||||
///
|
||||
/// If set to false, ty won't:
|
||||
///
|
||||
/// * allow suppressing errors with `type: ignore` comments
|
||||
/// * report unused `type: ignore` comments
|
||||
/// * report invalid `type: ignore` comments
|
||||
pub respect_type_ignore_comments: bool,
|
||||
}
|
||||
|
||||
impl Default for AnalysisSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
respect_type_ignore_comments: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,4 +615,7 @@ pub enum LintSource {
|
||||
|
||||
/// The rule was enabled in a configuration file.
|
||||
File,
|
||||
|
||||
/// The rule was enabled from the configuration in the editor.
|
||||
Editor,
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ use ruff_index::{IndexVec, newtype_index};
|
||||
/// A handle to an association list. Use [`ListStorage`] to access its elements, and
|
||||
/// [`ListBuilder`] to construct other lists based on this one.
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
|
||||
pub(crate) struct List<K, V = ()> {
|
||||
pub struct List<K, V = ()> {
|
||||
last: Option<ListCellId>,
|
||||
_phantom: PhantomData<(K, V)>,
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@ use crate::ast_node_ref::AstNodeRef;
|
||||
|
||||
/// Compact key for a node for use in a hash map.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||
pub(super) struct NodeKey(NodeIndex);
|
||||
pub struct NodeKey(NodeIndex);
|
||||
|
||||
impl NodeKey {
|
||||
pub(super) fn from_node<N>(node: N) -> Self
|
||||
pub fn from_node<N>(node: N) -> Self
|
||||
where
|
||||
N: HasNodeIndex,
|
||||
{
|
||||
NodeKey(node.node_index().load())
|
||||
}
|
||||
|
||||
pub(super) fn from_node_ref<T>(node_ref: &AstNodeRef<T>) -> Self {
|
||||
pub fn from_node_ref<T>(node_ref: &AstNodeRef<T>) -> Self {
|
||||
NodeKey(node_ref.index())
|
||||
}
|
||||
}
|
||||
|
||||
70
crates/ty_python_semantic/src/place_qualifiers.rs
Normal file
70
crates/ty_python_semantic/src/place_qualifiers.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
//! Place qualifier enums that are used by both semantic and type analysis.
|
||||
//!
|
||||
//! These simple enums don't depend on type information and are used by
|
||||
//! `use_def.rs` and other semantic index components.
|
||||
|
||||
/// Specifies how the boundness of a place should be determined.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
|
||||
pub enum BoundnessAnalysis {
|
||||
/// The place is always considered bound.
|
||||
AssumeBound,
|
||||
/// The boundness of the place is determined based on the visibility of the implicit
|
||||
/// `unbound` binding. In the example below, when analyzing the visibility of the
|
||||
/// `x = <unbound>` binding from the position of the end of the scope, it would be
|
||||
/// `Truthiness::Ambiguous`, because it could either be visible or not, depending on the
|
||||
/// `flag()` return value. This would result in a `Definedness::PossiblyUndefined` for `x`.
|
||||
///
|
||||
/// ```py
|
||||
/// x = <unbound>
|
||||
///
|
||||
/// if flag():
|
||||
/// x = 1
|
||||
/// ```
|
||||
BasedOnUnboundVisibility,
|
||||
}
|
||||
|
||||
/// Specifies whether a place is always defined or might be undefined.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
|
||||
pub enum Definedness {
|
||||
/// The place is always defined at this point.
|
||||
AlwaysDefined,
|
||||
/// The place might or might not be defined at this point.
|
||||
PossiblyUndefined,
|
||||
}
|
||||
|
||||
/// Specifies how a type was determined.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum TypeOrigin {
|
||||
/// The type was explicitly declared.
|
||||
Declared,
|
||||
/// The type was inferred from bindings.
|
||||
#[default]
|
||||
Inferred,
|
||||
}
|
||||
|
||||
/// Specifies whether to widen the type with `Unknown`.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default, get_size2::GetSize)]
|
||||
pub enum Widening {
|
||||
/// Don't widen the type.
|
||||
#[default]
|
||||
None,
|
||||
/// Widen the type with `Unknown` to handle undefined bindings.
|
||||
WithUnknown,
|
||||
}
|
||||
|
||||
/// Specifies whether a re-export requires explicit `__all__` inclusion.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RequiresExplicitReExport {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
/// Specifies which definitions to consider when looking up a place.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Default)]
|
||||
pub enum ConsideredDefinitions {
|
||||
/// Consider all reachable definitions at a specific use.
|
||||
AllReachable,
|
||||
/// Consider definitions visible at the end of the scope.
|
||||
#[default]
|
||||
EndOfScope,
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::Db;
|
||||
use crate::module_resolver::{SearchPathValidationError, SearchPaths};
|
||||
use crate::python_platform::PythonPlatform;
|
||||
|
||||
use ruff_db::diagnostic::Span;
|
||||
use ruff_db::files::system_path_to_file;
|
||||
use ruff_db::system::{System, SystemPath, SystemPathBuf};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
use ruff_db::system::{SystemPath, SystemPathBuf};
|
||||
use ruff_python_ast::PythonVersion;
|
||||
use ruff_text_size::TextRange;
|
||||
use salsa::Durability;
|
||||
use salsa::Setter;
|
||||
use ty_module_resolver::SearchPaths;
|
||||
|
||||
#[salsa::input(singleton, heap_size=ruff_memory_usage::heap_size)]
|
||||
pub struct Program {
|
||||
@@ -22,7 +21,7 @@ pub struct Program {
|
||||
pub python_platform: PythonPlatform,
|
||||
|
||||
#[returns(ref)]
|
||||
pub(crate) search_paths: SearchPaths,
|
||||
pub search_paths: SearchPaths,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
@@ -162,71 +161,3 @@ impl Default for PythonVersionWithSource {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, get_size2::GetSize)]
|
||||
pub enum MisconfigurationMode {
|
||||
/// Settings Failure Is Not An Error.
|
||||
///
|
||||
/// This is used by the default database, which we are incentivized to make infallible,
|
||||
/// while still trying to "do our best" to set things up properly where we can.
|
||||
UseDefault,
|
||||
/// Settings Failure Is An Error.
|
||||
Fail,
|
||||
}
|
||||
|
||||
/// Configures the search paths for module resolution.
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct SearchPathSettings {
|
||||
/// List of user-provided paths that should take first priority in the module resolution.
|
||||
/// Examples in other type checkers are mypy's MYPYPATH environment variable,
|
||||
/// or pyright's stubPath configuration setting.
|
||||
pub extra_paths: Vec<SystemPathBuf>,
|
||||
|
||||
/// The root of the project, used for finding first-party modules.
|
||||
pub src_roots: Vec<SystemPathBuf>,
|
||||
|
||||
/// Optional path to a "custom typeshed" directory on disk for us to use for standard-library types.
|
||||
/// If this is not provided, we will fallback to our vendored typeshed stubs for the stdlib,
|
||||
/// bundled as a zip file in the binary
|
||||
pub custom_typeshed: Option<SystemPathBuf>,
|
||||
|
||||
/// List of site packages paths to use.
|
||||
pub site_packages_paths: Vec<SystemPathBuf>,
|
||||
|
||||
/// Option path to the real stdlib on the system, and not some instance of typeshed.
|
||||
///
|
||||
/// We should ideally only ever use this for things like goto-definition,
|
||||
/// where typeshed isn't the right answer.
|
||||
pub real_stdlib_path: Option<SystemPathBuf>,
|
||||
|
||||
/// How to handle apparent misconfiguration
|
||||
pub misconfiguration_mode: MisconfigurationMode,
|
||||
}
|
||||
|
||||
impl SearchPathSettings {
|
||||
pub fn new(src_roots: Vec<SystemPathBuf>) -> Self {
|
||||
Self {
|
||||
src_roots,
|
||||
..SearchPathSettings::empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
SearchPathSettings {
|
||||
src_roots: vec![],
|
||||
extra_paths: vec![],
|
||||
custom_typeshed: None,
|
||||
site_packages_paths: vec![],
|
||||
real_stdlib_path: None,
|
||||
misconfiguration_mode: MisconfigurationMode::Fail,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_search_paths(
|
||||
&self,
|
||||
system: &dyn System,
|
||||
vendored: &VendoredFileSystem,
|
||||
) -> Result<SearchPaths, SearchPathValidationError> {
|
||||
SearchPaths::from_settings(self, system, vendored)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use ty_combine::Combine;
|
||||
|
||||
/// The target platform to assume when resolving types.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)]
|
||||
@@ -54,6 +55,10 @@ impl Default for PythonPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
impl Combine for PythonPlatform {
|
||||
fn combine_with(&mut self, _other: Self) {}
|
||||
}
|
||||
|
||||
#[cfg(feature = "schemars")]
|
||||
mod schema {
|
||||
use crate::PythonPlatform;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user