Compare commits
102 Commits
charlie/zs
...
0.6.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
975be9c1c6 | ||
|
|
99e4566fce | ||
|
|
7ad07c2c5d | ||
|
|
4aefe52393 | ||
|
|
cc1f766622 | ||
|
|
fdd0a22c03 | ||
|
|
3728d5b3a2 | ||
|
|
7e3894f5b3 | ||
|
|
c3b40da0d2 | ||
|
|
ef45185dbc | ||
|
|
961fc98344 | ||
|
|
0a6dc8e1b8 | ||
|
|
8d54996ffb | ||
|
|
73e884b232 | ||
|
|
edba60106b | ||
|
|
043fba7a57 | ||
|
|
20d997784d | ||
|
|
82324678cf | ||
|
|
cfd5d63917 | ||
|
|
2a36b47f13 | ||
|
|
6322639aca | ||
|
|
360af1bc32 | ||
|
|
3af3f74c66 | ||
|
|
45f01e7872 | ||
|
|
6cdf996af6 | ||
|
|
9d8a4c0057 | ||
|
|
c9c748a79e | ||
|
|
32c746bd82 | ||
|
|
e76f77d711 | ||
|
|
d86b73eb3d | ||
|
|
5f4b282327 | ||
|
|
d9267132d6 | ||
|
|
5118166d21 | ||
|
|
6fb1d6037a | ||
|
|
9237813e0c | ||
|
|
3bebde3ccc | ||
|
|
6c5cbad533 | ||
|
|
7a2f8d4463 | ||
|
|
ad87ea948d | ||
|
|
acfc34d615 | ||
|
|
668730cc28 | ||
|
|
bee498d635 | ||
|
|
ec72e675d9 | ||
|
|
1639488082 | ||
|
|
f3e464ea4c | ||
|
|
253f5f269a | ||
|
|
c046101b79 | ||
|
|
7706f561a9 | ||
|
|
f5e3662446 | ||
|
|
a354d9ead6 | ||
|
|
58a8e9c511 | ||
|
|
e83388dcea | ||
|
|
ae39ce56c0 | ||
|
|
ff2d214e11 | ||
|
|
9442cd8fae | ||
|
|
8012707348 | ||
|
|
d7ffe46054 | ||
|
|
7c83af419c | ||
|
|
bbb044ebda | ||
|
|
481065238b | ||
|
|
11f06e0d55 | ||
|
|
f27a8b8c7a | ||
|
|
ca0ae0a484 | ||
|
|
be1d5e3368 | ||
|
|
03503f7f56 | ||
|
|
ff4b6d11fa | ||
|
|
96e7f3f96f | ||
|
|
90dc7438ee | ||
|
|
3e99ab141c | ||
|
|
115745a8ac | ||
|
|
8bb59d7216 | ||
|
|
47aac060de | ||
|
|
7c55330534 | ||
|
|
047d77c60b | ||
|
|
18fddd458a | ||
|
|
db76000521 | ||
|
|
a2ed1e1cd1 | ||
|
|
7457679582 | ||
|
|
1d352872ba | ||
|
|
c8b905bc96 | ||
|
|
5b593d0397 | ||
|
|
c5c5acda23 | ||
|
|
26747aae75 | ||
|
|
85b825a2a1 | ||
|
|
9e764ef6d0 | ||
|
|
0e325a53ef | ||
|
|
2a136cfb57 | ||
|
|
7749164d4a | ||
|
|
da50e14524 | ||
|
|
1886b731a5 | ||
|
|
364eddc95a | ||
|
|
48fb340e3b | ||
|
|
71bb4d3bdc | ||
|
|
5c20f570d0 | ||
|
|
7441da287f | ||
|
|
c2a5179d75 | ||
|
|
17c4690b5e | ||
|
|
f06d44e6e5 | ||
|
|
653c09001a | ||
|
|
8921fbb54c | ||
|
|
3018303c87 | ||
|
|
6c303b2445 |
14
.github/workflows/sync_typeshed.yaml
vendored
14
.github/workflows/sync_typeshed.yaml
vendored
@@ -37,13 +37,13 @@ jobs:
|
||||
- name: Sync typeshed
|
||||
id: sync
|
||||
run: |
|
||||
rm -rf ruff/crates/red_knot_python_semantic/vendor/typeshed
|
||||
mkdir ruff/crates/red_knot_python_semantic/vendor/typeshed
|
||||
cp typeshed/README.md ruff/crates/red_knot_python_semantic/vendor/typeshed
|
||||
cp typeshed/LICENSE ruff/crates/red_knot_python_semantic/vendor/typeshed
|
||||
cp -r typeshed/stdlib ruff/crates/red_knot_python_semantic/vendor/typeshed/stdlib
|
||||
rm -rf ruff/crates/red_knot_python_semantic/vendor/typeshed/stdlib/@tests
|
||||
git -C typeshed rev-parse HEAD > ruff/crates/red_knot_python_semantic/vendor/typeshed/source_commit.txt
|
||||
rm -rf ruff/crates/red_knot_vendored/vendor/typeshed
|
||||
mkdir ruff/crates/red_knot_vendored/vendor/typeshed
|
||||
cp typeshed/README.md ruff/crates/red_knot_vendored/vendor/typeshed
|
||||
cp typeshed/LICENSE ruff/crates/red_knot_vendored/vendor/typeshed
|
||||
cp -r typeshed/stdlib ruff/crates/red_knot_vendored/vendor/typeshed/stdlib
|
||||
rm -rf ruff/crates/red_knot_vendored/vendor/typeshed/stdlib/@tests
|
||||
git -C typeshed rev-parse HEAD > ruff/crates/red_knot_vendored/vendor/typeshed/source_commit.txt
|
||||
- name: Commit the changes
|
||||
id: commit
|
||||
if: ${{ steps.sync.outcome == 'success' }}
|
||||
|
||||
@@ -2,7 +2,7 @@ fail_fast: true
|
||||
|
||||
exclude: |
|
||||
(?x)^(
|
||||
crates/red_knot_python_semantic/vendor/.*|
|
||||
crates/red_knot_vendored/vendor/.*|
|
||||
crates/red_knot_workspace/resources/.*|
|
||||
crates/ruff_linter/resources/.*|
|
||||
crates/ruff_linter/src/rules/.*/snapshots/.*|
|
||||
@@ -17,7 +17,7 @@ exclude: |
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.19
|
||||
rev: v0.20.2
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
|
||||
@@ -35,7 +35,7 @@ repos:
|
||||
)$
|
||||
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.41.0
|
||||
rev: v0.42.0
|
||||
hooks:
|
||||
- id: markdownlint-fix
|
||||
exclude: |
|
||||
@@ -45,7 +45,7 @@ repos:
|
||||
)$
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.24.5
|
||||
rev: v1.24.6
|
||||
hooks:
|
||||
- id: typos
|
||||
|
||||
@@ -59,7 +59,7 @@ repos:
|
||||
pass_filenames: false # This makes it a lot faster
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.6.5
|
||||
rev: v0.6.8
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
- id: ruff
|
||||
@@ -68,8 +68,8 @@ repos:
|
||||
require_serial: true
|
||||
|
||||
# Prettier
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
rev: v3.1.0
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: v3.3.3
|
||||
hooks:
|
||||
- id: prettier
|
||||
types: [yaml]
|
||||
|
||||
74
CHANGELOG.md
74
CHANGELOG.md
@@ -1,5 +1,79 @@
|
||||
# Changelog
|
||||
|
||||
## 0.6.9
|
||||
|
||||
### Preview features
|
||||
|
||||
- Fix codeblock dynamic line length calculation for indented docstring examples ([#13523](https://github.com/astral-sh/ruff/pull/13523))
|
||||
- \[`refurb`\] Mark `FURB118` fix as unsafe ([#13613](https://github.com/astral-sh/ruff/pull/13613))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- \[`pydocstyle`\] Don't raise `D208` when last line is non-empty ([#13372](https://github.com/astral-sh/ruff/pull/13372))
|
||||
- \[`pylint`\] Preserve trivia (i.e. comments) in `PLR5501` autofix ([#13573](https://github.com/astral-sh/ruff/pull/13573))
|
||||
|
||||
### Configuration
|
||||
|
||||
- \[`pyflakes`\] Add `allow-unused-imports` setting for `unused-import` rule (`F401`) ([#13601](https://github.com/astral-sh/ruff/pull/13601))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Support ruff discovery in pip build environments ([#13591](https://github.com/astral-sh/ruff/pull/13591))
|
||||
- \[`flake8-bugbear`\] Avoid short circuiting `B017` for multiple context managers ([#13609](https://github.com/astral-sh/ruff/pull/13609))
|
||||
- \[`pylint`\] Do not offer an invalid fix for `PLR1716` when the comparisons contain parenthesis ([#13527](https://github.com/astral-sh/ruff/pull/13527))
|
||||
- \[`pyupgrade`\] Fix `UP043` to apply to `collections.abc.Generator` and `collections.abc.AsyncGenerator` ([#13611](https://github.com/astral-sh/ruff/pull/13611))
|
||||
- \[`refurb`\] Fix handling of slices in tuples for `FURB118`, e.g., `x[:, 1]` ([#13518](https://github.com/astral-sh/ruff/pull/13518))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Update GitHub Action link to `astral-sh/ruff-action` ([#13551](https://github.com/astral-sh/ruff/pull/13551))
|
||||
|
||||
## 0.6.8
|
||||
|
||||
### Preview features
|
||||
|
||||
- Remove unnecessary parentheses around `match case` clauses ([#13510](https://github.com/astral-sh/ruff/pull/13510))
|
||||
- Parenthesize overlong `if` guards in `match..case` clauses ([#13513](https://github.com/astral-sh/ruff/pull/13513))
|
||||
- Detect basic wildcard imports in `ruff analyze graph` ([#13486](https://github.com/astral-sh/ruff/pull/13486))
|
||||
- \[`pylint`\] Implement `boolean-chained-comparison` (`R1716`) ([#13435](https://github.com/astral-sh/ruff/pull/13435))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- \[`lake8-simplify`\] Detect `SIM910` when using variadic keyword arguments, i.e., `**kwargs` ([#13503](https://github.com/astral-sh/ruff/pull/13503))
|
||||
- \[`pyupgrade`\] Avoid false negatives with non-reference shadowed bindings of loop variables (`UP028`) ([#13504](https://github.com/astral-sh/ruff/pull/13504))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Detect tuples bound to variadic positional arguments i.e. `*args` ([#13512](https://github.com/astral-sh/ruff/pull/13512))
|
||||
- Exit gracefully on broken pipe errors ([#13485](https://github.com/astral-sh/ruff/pull/13485))
|
||||
- Avoid panic when analyze graph hits broken pipe ([#13484](https://github.com/astral-sh/ruff/pull/13484))
|
||||
|
||||
### Performance
|
||||
|
||||
- Reuse `BTreeSets` in module resolver ([#13440](https://github.com/astral-sh/ruff/pull/13440))
|
||||
- Skip traversal for non-compound statements ([#13441](https://github.com/astral-sh/ruff/pull/13441))
|
||||
|
||||
## 0.6.7
|
||||
|
||||
### Preview features
|
||||
|
||||
- Add Python version support to ruff analyze CLI ([#13426](https://github.com/astral-sh/ruff/pull/13426))
|
||||
- Add `exclude` support to `ruff analyze` ([#13425](https://github.com/astral-sh/ruff/pull/13425))
|
||||
- Fix parentheses around return type annotations ([#13381](https://github.com/astral-sh/ruff/pull/13381))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- \[`pycodestyle`\] Fix: Don't autofix if the first line ends in a question mark? (D400) ([#13399](https://github.com/astral-sh/ruff/pull/13399))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Respect `lint.exclude` in ruff check `--add-noqa` ([#13427](https://github.com/astral-sh/ruff/pull/13427))
|
||||
|
||||
### Performance
|
||||
|
||||
- Avoid tracking module resolver files in Salsa ([#13437](https://github.com/astral-sh/ruff/pull/13437))
|
||||
- Use `forget` for module resolver database ([#13438](https://github.com/astral-sh/ruff/pull/13438))
|
||||
|
||||
## 0.6.6
|
||||
|
||||
### Preview features
|
||||
|
||||
@@ -29,16 +29,14 @@ You'll also need [Insta](https://insta.rs/docs/) to update snapshot tests:
|
||||
cargo install cargo-insta
|
||||
```
|
||||
|
||||
And you'll need pre-commit to run some validation checks:
|
||||
|
||||
```shell
|
||||
pipx install pre-commit # or `pip install pre-commit` if you have a virtualenv
|
||||
```
|
||||
You'll need [uv](https://docs.astral.sh/uv/getting-started/installation/) (or `pipx` and `pip`) to
|
||||
run Python utility commands.
|
||||
|
||||
You can optionally install pre-commit hooks to automatically run the validation checks
|
||||
when making a commit:
|
||||
|
||||
```shell
|
||||
uv tool install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
@@ -66,7 +64,7 @@ and that it passes both the lint and test validation checks:
|
||||
```shell
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings # Rust linting
|
||||
RUFF_UPDATE_SCHEMA=1 cargo test # Rust testing and updating ruff.schema.json
|
||||
pre-commit run --all-files --show-diff-on-failure # Rust and Python formatting, Markdown and Python linting, etc.
|
||||
uvx pre-commit run --all-files --show-diff-on-failure # Rust and Python formatting, Markdown and Python linting, etc.
|
||||
```
|
||||
|
||||
These checks will run on GitHub Actions when you open your pull request, but running them locally
|
||||
@@ -267,26 +265,20 @@ To preview any changes to the documentation locally:
|
||||
|
||||
1. Install the [Rust toolchain](https://www.rust-lang.org/tools/install).
|
||||
|
||||
1. Install MkDocs and Material for MkDocs with:
|
||||
|
||||
```shell
|
||||
pip install -r docs/requirements.txt
|
||||
```
|
||||
|
||||
1. Generate the MkDocs site with:
|
||||
|
||||
```shell
|
||||
python scripts/generate_mkdocs.py
|
||||
uv run --no-project --isolated --with-requirements docs/requirements.txt scripts/generate_mkdocs.py
|
||||
```
|
||||
|
||||
1. Run the development server with:
|
||||
|
||||
```shell
|
||||
# For contributors.
|
||||
mkdocs serve -f mkdocs.public.yml
|
||||
uvx --with-requirements docs/requirements.txt -- mkdocs serve -f mkdocs.public.yml
|
||||
|
||||
# For members of the Astral org, which has access to MkDocs Insiders via sponsorship.
|
||||
mkdocs serve -f mkdocs.insiders.yml
|
||||
uvx --with-requirements docs/requirements-insiders.txt -- mkdocs serve -f mkdocs.insiders.yml
|
||||
```
|
||||
|
||||
The documentation should then be available locally at
|
||||
@@ -368,9 +360,8 @@ GitHub Actions will run your changes against a number of real-world projects fro
|
||||
report on any linter or formatter differences. You can also run those checks locally via:
|
||||
|
||||
```shell
|
||||
pip install -e ./python/ruff-ecosystem
|
||||
ruff-ecosystem check ruff "./target/debug/ruff"
|
||||
ruff-ecosystem format ruff "./target/debug/ruff"
|
||||
uvx --from ./python/ruff-ecosystem ruff-ecosystem check ruff "./target/debug/ruff"
|
||||
uvx --from ./python/ruff-ecosystem ruff-ecosystem format ruff "./target/debug/ruff"
|
||||
```
|
||||
|
||||
See the [ruff-ecosystem package](https://github.com/astral-sh/ruff/tree/main/python/ruff-ecosystem) for more details.
|
||||
|
||||
187
Cargo.lock
generated
187
Cargo.lock
generated
@@ -129,9 +129,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
|
||||
[[package]]
|
||||
name = "append-only-vec"
|
||||
@@ -225,7 +225,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-automata 0.4.8",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -353,9 +353,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.16"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
|
||||
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -363,9 +363,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.15"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
|
||||
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -406,9 +406,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -437,9 +437,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "codspeed"
|
||||
version = "2.6.0"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a104ac948e0188b921eb3fcbdd55dcf62e542df4c7ab7e660623f6288302089"
|
||||
checksum = "450a0e9df9df1c154156f4344f99d8f6f6e69d0fc4de96ef6e2e68b2ec3bce97"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"libc",
|
||||
@@ -448,9 +448,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "codspeed-criterion-compat"
|
||||
version = "2.6.0"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "722c36bdc62d9436d027256ce2627af81ac7a596dfc7d13d849d0d212448d7fe"
|
||||
checksum = "8eb1a6cb9c20e177fde58cdef97c1c7c9264eb1424fe45c4fccedc2fb078a569"
|
||||
dependencies = [
|
||||
"codspeed",
|
||||
"colored",
|
||||
@@ -722,9 +722,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.0.1"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "804c8821570c3f8b70230c2ba75ffa5c0f9a4189b9a432b6656c536712acae28"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
@@ -879,9 +879,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.2"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "fern"
|
||||
@@ -894,9 +894,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.24"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
|
||||
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -987,15 +987,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.14"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.3",
|
||||
"regex-automata 0.4.8",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1106,15 +1106,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-automata 0.4.8",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
@@ -1142,9 +1142,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1193,9 +1193,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.39.0"
|
||||
version = "1.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
|
||||
checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60"
|
||||
dependencies = [
|
||||
"console",
|
||||
"globset",
|
||||
@@ -1347,9 +1347,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
version = "0.2.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
@@ -1405,9 +1405,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1427,9 +1427,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "lsp-server"
|
||||
version = "0.7.6"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095"
|
||||
checksum = "550446e84739dcaf6d48a4a093973850669e13e8a34d8f8d64851041be267cd9"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"log",
|
||||
@@ -1644,9 +1644,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordermap"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61d7d835be600a7ac71b24e39c92fe6fad9e818b3c71bfc379e3ba65e327d77f"
|
||||
checksum = "31f2bd7b03bf2c767e1bb7b91505dbe022833776e60480275e6f2fb0db0c7503"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
@@ -1934,9 +1934,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
@@ -2083,9 +2083,8 @@ dependencies = [
|
||||
"countme",
|
||||
"hashbrown",
|
||||
"insta",
|
||||
"once_cell",
|
||||
"ordermap",
|
||||
"path-slash",
|
||||
"red_knot_vendored",
|
||||
"ruff_db",
|
||||
"ruff_index",
|
||||
"ruff_python_ast",
|
||||
@@ -2102,8 +2101,6 @@ dependencies = [
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2130,6 +2127,17 @@ dependencies = [
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "red_knot_vendored"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"path-slash",
|
||||
"ruff_db",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "red_knot_wasm"
|
||||
version = "0.0.0"
|
||||
@@ -2155,6 +2163,7 @@ dependencies = [
|
||||
"notify",
|
||||
"rayon",
|
||||
"red_knot_python_semantic",
|
||||
"red_knot_vendored",
|
||||
"ruff_cache",
|
||||
"ruff_db",
|
||||
"ruff_python_ast",
|
||||
@@ -2196,14 +2205,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.3",
|
||||
"regex-automata 0.4.8",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2217,13 +2226,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.6"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.3",
|
||||
"regex-syntax 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2234,9 +2243,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
@@ -2255,7 +2264,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.6.6"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
@@ -2327,6 +2336,7 @@ dependencies = [
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"rustc-hash 2.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tikv-jemallocator",
|
||||
@@ -2353,7 +2363,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"countme",
|
||||
"dashmap 6.0.1",
|
||||
"dashmap 6.1.0",
|
||||
"filetime",
|
||||
"ignore",
|
||||
"insta",
|
||||
@@ -2450,15 +2460,18 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"once_cell",
|
||||
"red_knot_python_semantic",
|
||||
"ruff_cache",
|
||||
"ruff_db",
|
||||
"ruff_linter",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_parser",
|
||||
"salsa",
|
||||
"schemars",
|
||||
"serde",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2471,7 +2484,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.6.6"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"annotate-snippets 0.9.2",
|
||||
@@ -2791,7 +2804,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_wasm"
|
||||
version = "0.6.6"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
@@ -2874,9 +2887,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
version = "0.38.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
@@ -2932,12 +2945,12 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
[[package]]
|
||||
name = "salsa"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=f608ff8b24f07706492027199f51132244034f29#f608ff8b24f07706492027199f51132244034f29"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
|
||||
dependencies = [
|
||||
"append-only-vec",
|
||||
"arc-swap",
|
||||
"crossbeam",
|
||||
"dashmap 6.0.1",
|
||||
"dashmap 6.1.0",
|
||||
"hashlink",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
@@ -2952,12 +2965,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "salsa-macro-rules"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=f608ff8b24f07706492027199f51132244034f29#f608ff8b24f07706492027199f51132244034f29"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
|
||||
|
||||
[[package]]
|
||||
name = "salsa-macros"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=f608ff8b24f07706492027199f51132244034f29#f608ff8b24f07706492027199f51132244034f29"
|
||||
source = "git+https://github.com/salsa-rs/salsa.git?rev=4a7c955255e707e64e43f3ce5eabb771ae067768#4a7c955255e707e64e43f3ce5eabb771ae067768"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -3019,9 +3032,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.209"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -3039,9 +3052,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.209"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3061,9 +3074,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.127"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -3233,9 +3246,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.76"
|
||||
version = "2.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3255,9 +3268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.12.0"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
|
||||
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
@@ -3330,18 +3343,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3602,15 +3615,15 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.23"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
@@ -3623,9 +3636,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "1.2.2"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addeebf294df7922a1164f729fb27ebbbcea99cc32b3bf08afab62757f707677"
|
||||
checksum = "d1673eca9782c84de5f81b82e4109dcfb3611c8ba0d52930ec4a9478f547b2dd"
|
||||
dependencies = [
|
||||
"phf",
|
||||
"unicode_names2_generator",
|
||||
@@ -3633,9 +3646,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2_generator"
|
||||
version = "1.2.2"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f444b8bba042fe3c1251ffaca35c603f2dc2ccc08d595c65a8c4f76f3e8426c0"
|
||||
checksum = "b91e5b84611016120197efd7dc93ef76774f4e084cd73c9fb3ea4a86c570c56e"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"log",
|
||||
@@ -4121,9 +4134,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yansi-term"
|
||||
|
||||
@@ -14,7 +14,7 @@ license = "MIT"
|
||||
[workspace.dependencies]
|
||||
ruff = { path = "crates/ruff" }
|
||||
ruff_cache = { path = "crates/ruff_cache" }
|
||||
ruff_db = { path = "crates/ruff_db" }
|
||||
ruff_db = { path = "crates/ruff_db", default-features = false }
|
||||
ruff_diagnostics = { path = "crates/ruff_diagnostics" }
|
||||
ruff_formatter = { path = "crates/ruff_formatter" }
|
||||
ruff_graph = { path = "crates/ruff_graph" }
|
||||
@@ -34,11 +34,12 @@ ruff_python_trivia = { path = "crates/ruff_python_trivia" }
|
||||
ruff_server = { path = "crates/ruff_server" }
|
||||
ruff_source_file = { path = "crates/ruff_source_file" }
|
||||
ruff_text_size = { path = "crates/ruff_text_size" }
|
||||
red_knot_vendored = { path = "crates/red_knot_vendored" }
|
||||
ruff_workspace = { path = "crates/ruff_workspace" }
|
||||
|
||||
red_knot_python_semantic = { path = "crates/red_knot_python_semantic" }
|
||||
red_knot_server = { path = "crates/red_knot_server" }
|
||||
red_knot_workspace = { path = "crates/red_knot_workspace" }
|
||||
red_knot_workspace = { path = "crates/red_knot_workspace", default-features = false }
|
||||
|
||||
aho-corasick = { version = "1.1.3" }
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
@@ -111,7 +112,7 @@ rand = { version = "0.8.5" }
|
||||
rayon = { version = "1.10.0" }
|
||||
regex = { version = "1.10.2" }
|
||||
rustc-hash = { version = "2.0.0" }
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "f608ff8b24f07706492027199f51132244034f29" }
|
||||
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "4a7c955255e707e64e43f3ce5eabb771ae067768" }
|
||||
schemars = { version = "0.8.16" }
|
||||
seahash = { version = "4.1.0" }
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
|
||||
10
README.md
10
README.md
@@ -136,8 +136,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
|
||||
|
||||
# For a specific version.
|
||||
curl -LsSf https://astral.sh/ruff/0.6.6/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.6.6/install.ps1 | iex"
|
||||
curl -LsSf https://astral.sh/ruff/0.6.9/install.sh | sh
|
||||
powershell -c "irm https://astral.sh/ruff/0.6.9/install.ps1 | iex"
|
||||
```
|
||||
|
||||
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
|
||||
@@ -170,7 +170,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.6.6
|
||||
rev: v0.6.9
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
@@ -182,7 +182,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
Ruff can also be used as a [VS Code extension](https://github.com/astral-sh/ruff-vscode) or with [various other editors](https://docs.astral.sh/ruff/editors/setup).
|
||||
|
||||
Ruff can also be used as a [GitHub Action](https://github.com/features/actions) via
|
||||
[`ruff-action`](https://github.com/chartboost/ruff-action):
|
||||
[`ruff-action`](https://github.com/astral-sh/ruff-action):
|
||||
|
||||
```yaml
|
||||
name: Ruff
|
||||
@@ -192,7 +192,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: chartboost/ruff-action@v1
|
||||
- uses: astral-sh/ruff-action@v1
|
||||
```
|
||||
|
||||
### Configuration<a id="configuration"></a>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[files]
|
||||
# https://github.com/crate-ci/typos/issues/868
|
||||
extend-exclude = ["crates/red_knot_python_semantic/vendor/**/*", "**/resources/**/*", "**/snapshots/**/*"]
|
||||
extend-exclude = ["crates/red_knot_vendored/vendor/**/*", "**/resources/**/*", "**/snapshots/**/*"]
|
||||
|
||||
[default.extend-words]
|
||||
"arange" = "arange" # e.g. `numpy.arange`
|
||||
@@ -8,7 +8,7 @@ hel = "hel"
|
||||
whos = "whos"
|
||||
spawnve = "spawnve"
|
||||
ned = "ned"
|
||||
pn = "pn" # `import panel as pd` is a thing
|
||||
pn = "pn" # `import panel as pn` is a thing
|
||||
poit = "poit"
|
||||
BA = "BA" # acronym for "Bad Allowed", used in testing.
|
||||
jod = "jod" # e.g., `jod-thread`
|
||||
|
||||
@@ -13,9 +13,8 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
red_knot_python_semantic = { workspace = true }
|
||||
red_knot_workspace = { workspace = true }
|
||||
red_knot_workspace = { workspace = true, features = ["zstd"] }
|
||||
red_knot_server = { workspace = true }
|
||||
|
||||
ruff_db = { workspace = true, features = ["os", "cache"] }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -160,7 +160,7 @@ fn run() -> anyhow::Result<ExitStatus> {
|
||||
SystemPathBuf::from_path_buf(cwd)
|
||||
.map_err(|path| {
|
||||
anyhow!(
|
||||
"The current working directory '{}' contains non-unicode characters. Red Knot only supports unicode paths.",
|
||||
"The current working directory `{}` contains non-Unicode characters. Red Knot only supports Unicode paths.",
|
||||
path.display()
|
||||
)
|
||||
})?
|
||||
@@ -174,7 +174,7 @@ fn run() -> anyhow::Result<ExitStatus> {
|
||||
Ok(SystemPath::absolute(cwd, &cli_base_path))
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"Provided current-directory path '{cwd}' is not a directory."
|
||||
"Provided current-directory path `{cwd}` is not a directory"
|
||||
))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -42,14 +42,14 @@ impl TestCase {
|
||||
|
||||
fn stop_watch(&mut self) -> Vec<watch::ChangeEvent> {
|
||||
self.try_stop_watch(Duration::from_secs(10))
|
||||
.expect("Expected watch changes but observed none.")
|
||||
.expect("Expected watch changes but observed none")
|
||||
}
|
||||
|
||||
fn try_stop_watch(&mut self, timeout: Duration) -> Option<Vec<watch::ChangeEvent>> {
|
||||
let watcher = self
|
||||
.watcher
|
||||
.take()
|
||||
.expect("Cannot call `stop_watch` more than once.");
|
||||
.expect("Cannot call `stop_watch` more than once");
|
||||
|
||||
let mut all_events = self
|
||||
.changes_receiver
|
||||
@@ -72,7 +72,7 @@ impl TestCase {
|
||||
#[cfg(unix)]
|
||||
fn take_watch_changes(&self) -> Vec<watch::ChangeEvent> {
|
||||
self.try_take_watch_changes(Duration::from_secs(10))
|
||||
.expect("Expected watch changes but observed none.")
|
||||
.expect("Expected watch changes but observed none")
|
||||
}
|
||||
|
||||
fn try_take_watch_changes(&self, timeout: Duration) -> Option<Vec<watch::ChangeEvent>> {
|
||||
@@ -150,14 +150,14 @@ where
|
||||
let absolute_path = workspace_path.join(relative_path);
|
||||
if let Some(parent) = absolute_path.parent() {
|
||||
std::fs::create_dir_all(parent).with_context(|| {
|
||||
format!("Failed to create parent directory for file '{relative_path}'.",)
|
||||
format!("Failed to create parent directory for file `{relative_path}`")
|
||||
})?;
|
||||
}
|
||||
|
||||
let mut file = std::fs::File::create(absolute_path.as_std_path())
|
||||
.with_context(|| format!("Failed to open file '{relative_path}'"))?;
|
||||
.with_context(|| format!("Failed to open file `{relative_path}`"))?;
|
||||
file.write_all(content.as_bytes())
|
||||
.with_context(|| format!("Failed to write to file '{relative_path}'"))?;
|
||||
.with_context(|| format!("Failed to write to file `{relative_path}`"))?;
|
||||
file.sync_data()?;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ where
|
||||
|
||||
let root_path = SystemPath::from_std_path(temp_dir.path()).ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Temp directory '{}' is not a valid UTF-8 path.",
|
||||
"Temporary directory `{}` is not a valid UTF-8 path.",
|
||||
temp_dir.path().display()
|
||||
)
|
||||
})?;
|
||||
@@ -209,7 +209,7 @@ where
|
||||
let workspace_path = root_path.join("workspace");
|
||||
|
||||
std::fs::create_dir_all(workspace_path.as_std_path())
|
||||
.with_context(|| format!("Failed to create workspace directory '{workspace_path}'",))?;
|
||||
.with_context(|| format!("Failed to create workspace directory `{workspace_path}`"))?;
|
||||
|
||||
setup_files
|
||||
.setup(&root_path, &workspace_path)
|
||||
@@ -233,7 +233,7 @@ where
|
||||
}))
|
||||
{
|
||||
std::fs::create_dir_all(path.as_std_path())
|
||||
.with_context(|| format!("Failed to create search path '{path}'"))?;
|
||||
.with_context(|| format!("Failed to create search path `{path}`"))?;
|
||||
}
|
||||
|
||||
let configuration = Configuration {
|
||||
@@ -665,7 +665,7 @@ fn directory_deleted() -> anyhow::Result<()> {
|
||||
|
||||
let bar = case.system_file(case.workspace_path("bar.py")).unwrap();
|
||||
|
||||
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some(),);
|
||||
assert!(resolve_module(case.db().upcast(), ModuleName::new_static("sub.a").unwrap()).is_some());
|
||||
|
||||
let sub_path = case.workspace_path("sub");
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ bitflags = { workspace = true }
|
||||
camino = { workspace = true }
|
||||
compact_str = { workspace = true }
|
||||
countme = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
ordermap = { workspace = true }
|
||||
salsa = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -35,25 +34,14 @@ smallvec = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
path-slash = { workspace = true }
|
||||
walkdir = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "powerpc64"))'.build-dependencies]
|
||||
zip = { workspace = true, features = ["deflate", "zstd"] }
|
||||
|
||||
[target.'cfg(target_arch = "powerpc64")'.build-dependencies]
|
||||
zip = { workspace = true, features = ["deflate"] }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_db = { workspace = true, features = ["os", "testing"] }
|
||||
ruff_python_parser = { workspace = true }
|
||||
red_knot_vendored = { workspace = true }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
insta = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
walkdir = { workspace = true }
|
||||
zip = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -11,7 +11,6 @@ pub trait Db: SourceDb + Upcast<dyn SourceDb> {
|
||||
pub(crate) mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::module_resolver::vendored_typeshed_stubs;
|
||||
use ruff_db::files::{File, Files};
|
||||
use ruff_db::system::{DbWithTestSystem, System, TestSystem};
|
||||
use ruff_db::vendored::VendoredFileSystem;
|
||||
@@ -33,7 +32,7 @@ pub(crate) mod tests {
|
||||
Self {
|
||||
storage: salsa::Storage::default(),
|
||||
system: TestSystem::default(),
|
||||
vendored: vendored_typeshed_stubs().clone(),
|
||||
vendored: red_knot_vendored::file_system().clone(),
|
||||
events: std::sync::Arc::default(),
|
||||
files: Files::default(),
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ use rustc_hash::FxHasher;
|
||||
|
||||
pub use db::Db;
|
||||
pub use module_name::ModuleName;
|
||||
pub use module_resolver::{
|
||||
resolve_module, system_module_search_paths, vendored_typeshed_stubs, Module,
|
||||
};
|
||||
pub use module_resolver::{resolve_module, system_module_search_paths, Module};
|
||||
pub use program::{Program, ProgramSettings, SearchPathSettings, SitePackages};
|
||||
pub use python_version::PythonVersion;
|
||||
pub use semantic_model::{HasTy, SemanticModel};
|
||||
|
||||
@@ -4,7 +4,6 @@ pub use module::Module;
|
||||
pub use resolver::resolve_module;
|
||||
pub(crate) use resolver::{file_to_module, SearchPaths};
|
||||
use ruff_db::system::SystemPath;
|
||||
pub use typeshed::vendored_typeshed_stubs;
|
||||
|
||||
use crate::module_resolver::resolver::search_paths;
|
||||
use crate::Db;
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||
use std::borrow::Cow;
|
||||
use std::iter::FusedIterator;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||
|
||||
use ruff_db::files::{File, FilePath, FileRootKind};
|
||||
use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf};
|
||||
use ruff_db::vendored::{VendoredFileSystem, VendoredPath};
|
||||
|
||||
use super::module::{Module, ModuleKind};
|
||||
use super::path::{ModulePath, SearchPath, SearchPathValidationError};
|
||||
use crate::db::Db;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::typeshed::{vendored_typeshed_versions, TypeshedVersions};
|
||||
use crate::site_packages::VirtualEnvironment;
|
||||
use crate::{Program, PythonVersion, SearchPathSettings, SitePackages};
|
||||
|
||||
use super::module::{Module, ModuleKind};
|
||||
use super::path::{ModulePath, SearchPath, SearchPathValidationError};
|
||||
|
||||
/// Resolves a module name to a module.
|
||||
pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option<Module> {
|
||||
let interned_name = ModuleNameIngredient::new(db, module_name);
|
||||
@@ -35,14 +36,14 @@ pub(crate) fn resolve_module_query<'db>(
|
||||
let _span = tracing::trace_span!("resolve_module", %name).entered();
|
||||
|
||||
let Some((search_path, module_file, kind)) = resolve_name(db, name) else {
|
||||
tracing::debug!("Module '{name}' not found in the search paths.");
|
||||
tracing::debug!("Module `{name}` not found in search paths");
|
||||
return None;
|
||||
};
|
||||
|
||||
let module = Module::new(name.clone(), kind, search_path, module_file);
|
||||
|
||||
tracing::trace!(
|
||||
"Resolved module '{name}' to '{path}'.",
|
||||
"Resolved module `{name}` to `{path}`",
|
||||
path = module_file.path(db)
|
||||
);
|
||||
|
||||
@@ -136,7 +137,7 @@ pub(crate) struct SearchPaths {
|
||||
/// for the first `site-packages` path
|
||||
site_packages: Vec<SearchPath>,
|
||||
|
||||
typeshed_versions: ResolvedTypeshedVersions,
|
||||
typeshed_versions: TypeshedVersions,
|
||||
}
|
||||
|
||||
impl SearchPaths {
|
||||
@@ -202,11 +203,11 @@ impl SearchPaths {
|
||||
|
||||
let search_path = SearchPath::custom_stdlib(db, &custom_typeshed)?;
|
||||
|
||||
(ResolvedTypeshedVersions::Custom(parsed), search_path)
|
||||
(parsed, search_path)
|
||||
} else {
|
||||
tracing::debug!("Using vendored stdlib");
|
||||
(
|
||||
ResolvedTypeshedVersions::Vendored(vendored_typeshed_versions()),
|
||||
vendored_typeshed_versions(db),
|
||||
SearchPath::vendored_stdlib(),
|
||||
)
|
||||
};
|
||||
@@ -279,23 +280,6 @@ impl SearchPaths {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum ResolvedTypeshedVersions {
|
||||
Vendored(&'static TypeshedVersions),
|
||||
Custom(TypeshedVersions),
|
||||
}
|
||||
|
||||
impl Deref for ResolvedTypeshedVersions {
|
||||
type Target = TypeshedVersions;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
ResolvedTypeshedVersions::Vendored(versions) => versions,
|
||||
ResolvedTypeshedVersions::Custom(versions) => versions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all dynamic search paths. For each `site-packages` path:
|
||||
/// - Collect that `site-packages` path
|
||||
/// - Collect any search paths listed in `.pth` files in that `site-packages` directory
|
||||
@@ -340,7 +324,7 @@ pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
|
||||
|
||||
let site_packages_root = files
|
||||
.root(db.upcast(), site_packages_dir)
|
||||
.expect("Site-package root to have been created.");
|
||||
.expect("Site-package root to have been created");
|
||||
|
||||
// This query needs to be re-executed each time a `.pth` file
|
||||
// is added, modified or removed from the `site-packages` directory.
|
||||
|
||||
@@ -4,25 +4,19 @@ use std::num::{NonZeroU16, NonZeroUsize};
|
||||
use std::ops::{RangeFrom, RangeInclusive};
|
||||
use std::str::FromStr;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use super::vendored::vendored_typeshed_stubs;
|
||||
use crate::db::Db;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::{Program, PythonVersion};
|
||||
|
||||
static VENDORED_VERSIONS: Lazy<TypeshedVersions> = Lazy::new(|| {
|
||||
pub(in crate::module_resolver) fn vendored_typeshed_versions(db: &dyn Db) -> TypeshedVersions {
|
||||
TypeshedVersions::from_str(
|
||||
&vendored_typeshed_stubs()
|
||||
&db.vendored()
|
||||
.read_to_string("stdlib/VERSIONS")
|
||||
.unwrap(),
|
||||
.expect("The vendored typeshed stubs should contain a VERSIONS file"),
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
pub(crate) fn vendored_typeshed_versions() -> &'static TypeshedVersions {
|
||||
&VENDORED_VERSIONS
|
||||
.expect("The VERSIONS file in the vendored typeshed stubs should be well-formed")
|
||||
}
|
||||
|
||||
pub(crate) fn typeshed_versions(db: &dyn Db) -> &TypeshedVersions {
|
||||
@@ -332,6 +326,8 @@ mod tests {
|
||||
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use crate::db::tests::TestDb;
|
||||
|
||||
use super::*;
|
||||
|
||||
const TYPESHED_STDLIB_DIR: &str = "stdlib";
|
||||
@@ -353,12 +349,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn can_parse_vendored_versions_file() {
|
||||
let versions_data = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/vendor/typeshed/stdlib/VERSIONS"
|
||||
));
|
||||
let db = TestDb::new();
|
||||
|
||||
let versions = TypeshedVersions::from_str(versions_data).unwrap();
|
||||
let versions = vendored_typeshed_versions(&db);
|
||||
assert!(versions.len() > 100);
|
||||
assert!(versions.len() < 1000);
|
||||
|
||||
@@ -395,9 +388,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn typeshed_versions_consistent_with_vendored_stubs() {
|
||||
const VERSIONS_DATA: &str = include_str!("../../../vendor/typeshed/stdlib/VERSIONS");
|
||||
let vendored_typeshed_dir = Path::new("vendor/typeshed").canonicalize().unwrap();
|
||||
let vendored_typeshed_versions = TypeshedVersions::from_str(VERSIONS_DATA).unwrap();
|
||||
let db = TestDb::new();
|
||||
let vendored_typeshed_versions = vendored_typeshed_versions(&db);
|
||||
let vendored_typeshed_dir =
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("../red_knot_vendored/vendor/typeshed");
|
||||
|
||||
let mut empty_iterator = true;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
pub use self::vendored::vendored_typeshed_stubs;
|
||||
pub(super) use self::versions::{
|
||||
typeshed_versions, vendored_typeshed_versions, TypeshedVersions, TypeshedVersionsParseError,
|
||||
TypeshedVersionsQueryResult,
|
||||
};
|
||||
|
||||
mod vendored;
|
||||
mod versions;
|
||||
@@ -3,6 +3,7 @@ use ruff_db::parsed::ParsedModule;
|
||||
use ruff_python_ast as ast;
|
||||
|
||||
use crate::ast_node_ref::AstNodeRef;
|
||||
use crate::module_resolver::file_to_module;
|
||||
use crate::node_key::NodeKey;
|
||||
use crate::semantic_index::symbol::{FileScopeId, ScopeId, ScopedSymbolId};
|
||||
use crate::Db;
|
||||
@@ -45,6 +46,14 @@ impl<'db> Definition<'db> {
|
||||
pub(crate) fn is_binding(self, db: &'db dyn Db) -> bool {
|
||||
self.kind(db).category().is_binding()
|
||||
}
|
||||
|
||||
/// Return true if this is a symbol was defined in the `typing` or `typing_extensions` modules
|
||||
pub(crate) fn is_typing_definition(self, db: &'db dyn Db) -> bool {
|
||||
file_to_module(db, self.file(db)).is_some_and(|module| {
|
||||
module.search_path().is_standard_library()
|
||||
&& matches!(&**module.name(), "typing" | "typing_extensions")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
||||
@@ -192,7 +192,7 @@ impl VirtualEnvironment {
|
||||
} else {
|
||||
tracing::warn!(
|
||||
"Failed to resolve `sys.prefix` of the system Python installation \
|
||||
from the `home` value in the `pyvenv.cfg` file at '{}'. \
|
||||
from the `home` value in the `pyvenv.cfg` file at `{}`. \
|
||||
System site-packages will not be used for module resolution.",
|
||||
venv_path.join("pyvenv.cfg")
|
||||
);
|
||||
@@ -426,7 +426,7 @@ impl Deref for SysPrefixPath {
|
||||
|
||||
impl fmt::Display for SysPrefixPath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "`sys.prefix` path '{}'", self.0)
|
||||
write!(f, "`sys.prefix` path `{}`", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ impl Deref for PythonHomePath {
|
||||
|
||||
impl fmt::Display for PythonHomePath {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "`home` location '{}'", self.0)
|
||||
write!(f, "`home` location `{}`", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ fn bindings_ty<'db>(
|
||||
|
||||
let first = all_types
|
||||
.next()
|
||||
.expect("bindings_ty should never be called with zero definitions and no unbound_ty.");
|
||||
.expect("bindings_ty should never be called with zero definitions and no unbound_ty");
|
||||
|
||||
if let Some(second) = all_types.next() {
|
||||
UnionType::from_elements(db, [first, second].into_iter().chain(all_types))
|
||||
@@ -204,7 +204,7 @@ fn declarations_ty<'db>(
|
||||
let mut all_types = undeclared_ty.into_iter().chain(decl_types);
|
||||
|
||||
let first = all_types.next().expect(
|
||||
"declarations_ty must not be called with zero declarations and no may-be-undeclared.",
|
||||
"declarations_ty must not be called with zero declarations and no may-be-undeclared",
|
||||
);
|
||||
|
||||
let mut conflicting: Vec<Type<'db>> = vec![];
|
||||
@@ -221,9 +221,9 @@ fn declarations_ty<'db>(
|
||||
first
|
||||
};
|
||||
if conflicting.is_empty() {
|
||||
DeclaredTypeResult::Ok(declared_ty)
|
||||
Ok(declared_ty)
|
||||
} else {
|
||||
DeclaredTypeResult::Err((
|
||||
Err((
|
||||
declared_ty,
|
||||
[first].into_iter().chain(conflicting).collect(),
|
||||
))
|
||||
@@ -233,31 +233,38 @@ fn declarations_ty<'db>(
|
||||
/// Unique ID for a type.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Type<'db> {
|
||||
/// the dynamic type: a statically-unknown set of values
|
||||
/// The dynamic type: a statically-unknown set of values
|
||||
Any,
|
||||
/// the empty set of values
|
||||
/// The empty set of values
|
||||
Never,
|
||||
/// unknown type (either no annotation, or some kind of type error)
|
||||
/// equivalent to Any, or possibly to object in strict mode
|
||||
/// Unknown type (either no annotation, or some kind of type error).
|
||||
/// Equivalent to Any, or possibly to object in strict mode
|
||||
Unknown,
|
||||
/// name does not exist or is not bound to any value (this represents an error, but with some
|
||||
/// Name does not exist or is not bound to any value (this represents an error, but with some
|
||||
/// leniency options it could be silently resolved to Unknown in some cases)
|
||||
Unbound,
|
||||
/// the None object -- TODO remove this in favor of Instance(types.NoneType)
|
||||
/// The None object -- TODO remove this in favor of Instance(types.NoneType)
|
||||
None,
|
||||
/// a specific function object
|
||||
/// Temporary type for symbols that can't be inferred yet because of missing implementations.
|
||||
/// Behaves equivalently to `Any`.
|
||||
///
|
||||
/// This variant should eventually be removed once red-knot is spec-compliant.
|
||||
///
|
||||
/// General rule: `Todo` should only propagate when the presence of the input `Todo` caused the
|
||||
/// output to be unknown. An output should only be `Todo` if fixing all `Todo` inputs to be not
|
||||
/// `Todo` would change the output type.
|
||||
Todo,
|
||||
/// A specific function object
|
||||
Function(FunctionType<'db>),
|
||||
/// The `typing.reveal_type` function, which has special `__call__` behavior.
|
||||
RevealTypeFunction(FunctionType<'db>),
|
||||
/// a specific module object
|
||||
/// A specific module object
|
||||
Module(File),
|
||||
/// a specific class object
|
||||
/// A specific class object
|
||||
Class(ClassType<'db>),
|
||||
/// the set of Python objects with the given class in their __class__'s method resolution order
|
||||
/// The set of Python objects with the given class in their __class__'s method resolution order
|
||||
Instance(ClassType<'db>),
|
||||
/// the set of objects in any of the types in the union
|
||||
/// The set of objects in any of the types in the union
|
||||
Union(UnionType<'db>),
|
||||
/// the set of objects in all of the types in the intersection
|
||||
/// The set of objects in all of the types in the intersection
|
||||
Intersection(IntersectionType<'db>),
|
||||
/// An integer literal
|
||||
IntLiteral(i64),
|
||||
@@ -335,16 +342,14 @@ impl<'db> Type<'db> {
|
||||
|
||||
pub const fn into_function_type(self) -> Option<FunctionType<'db>> {
|
||||
match self {
|
||||
Type::Function(function_type) | Type::RevealTypeFunction(function_type) => {
|
||||
Some(function_type)
|
||||
}
|
||||
Type::Function(function_type) => Some(function_type),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_function(self) -> FunctionType<'db> {
|
||||
self.into_function_type()
|
||||
.expect("Expected a variant wrapping a FunctionType")
|
||||
.expect("Expected a Type::Function variant")
|
||||
}
|
||||
|
||||
pub const fn into_int_literal_type(self) -> Option<i64> {
|
||||
@@ -380,12 +385,28 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn builtin_str_instance(db: &'db dyn Db) -> Self {
|
||||
builtins_symbol_ty(db, "str").to_instance(db)
|
||||
}
|
||||
|
||||
pub fn builtin_int_instance(db: &'db dyn Db) -> Self {
|
||||
builtins_symbol_ty(db, "int").to_instance(db)
|
||||
}
|
||||
|
||||
pub fn is_stdlib_symbol(&self, db: &'db dyn Db, module_name: &str, name: &str) -> bool {
|
||||
match self {
|
||||
Type::Class(class) => class.is_stdlib_symbol(db, module_name, name),
|
||||
Type::Function(function) | Type::RevealTypeFunction(function) => {
|
||||
function.is_stdlib_symbol(db, module_name, name)
|
||||
}
|
||||
Type::Function(function) => function.is_stdlib_symbol(db, module_name, name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the type is a class or a union of classes.
|
||||
pub fn is_class(&self, db: &'db dyn Db) -> bool {
|
||||
match self {
|
||||
Type::Union(union) => union.elements(db).iter().all(|ty| ty.is_class(db)),
|
||||
Type::Class(_) => true,
|
||||
// / TODO include type[X], once we add that type
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -398,8 +419,8 @@ impl<'db> Type<'db> {
|
||||
return true;
|
||||
}
|
||||
match (self, target) {
|
||||
(Type::Unknown | Type::Any, _) => false,
|
||||
(_, Type::Unknown | Type::Any) => false,
|
||||
(Type::Unknown | Type::Any | Type::Todo, _) => false,
|
||||
(_, Type::Unknown | Type::Any | Type::Todo) => false,
|
||||
(Type::Never, _) => true,
|
||||
(_, Type::Never) => false,
|
||||
(Type::IntLiteral(_), Type::Instance(class))
|
||||
@@ -434,8 +455,8 @@ impl<'db> Type<'db> {
|
||||
/// [assignable to]: https://typing.readthedocs.io/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
|
||||
pub(crate) fn is_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool {
|
||||
match (self, target) {
|
||||
(Type::Unknown | Type::Any, _) => true,
|
||||
(_, Type::Unknown | Type::Any) => true,
|
||||
(Type::Unknown | Type::Any | Type::Todo, _) => true,
|
||||
(_, Type::Unknown | Type::Any | Type::Todo) => true,
|
||||
(ty, Type::Union(union)) => union
|
||||
.elements(db)
|
||||
.iter()
|
||||
@@ -471,53 +492,104 @@ impl<'db> Type<'db> {
|
||||
Type::Any => Type::Any,
|
||||
Type::Never => {
|
||||
// TODO: attribute lookup on Never type
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Unknown => Type::Unknown,
|
||||
Type::Unbound => Type::Unbound,
|
||||
Type::None => {
|
||||
// TODO: attribute lookup on None type
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Function(_) | Type::RevealTypeFunction(_) => {
|
||||
Type::Function(_) => {
|
||||
// TODO: attribute lookup on function type
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Module(file) => global_symbol_ty(db, *file, name),
|
||||
Type::Class(class) => class.class_member(db, name),
|
||||
Type::Instance(_) => {
|
||||
// TODO MRO? get_own_instance_member, get_instance_member
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Union(union) => union.map(db, |element| element.member(db, name)),
|
||||
Type::Intersection(_) => {
|
||||
// TODO perform the get_member on each type in the intersection
|
||||
// TODO return the intersection of those results
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::IntLiteral(_) => {
|
||||
// TODO raise error
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::BooleanLiteral(_) => Type::Unknown,
|
||||
Type::BooleanLiteral(_) => Type::Todo,
|
||||
Type::StringLiteral(_) => {
|
||||
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
||||
// from typeshed's stubs
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::LiteralString => {
|
||||
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
||||
// from typeshed's stubs
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::BytesLiteral(_) => {
|
||||
// TODO defer to Type::Instance(<bytes from typeshed>).member
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Tuple(_) => {
|
||||
// TODO: implement tuple methods
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
}
|
||||
Type::Todo => Type::Todo,
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the boolean value of a type.
|
||||
///
|
||||
/// This is used to determine the value that would be returned
|
||||
/// when `bool(x)` is called on an object `x`.
|
||||
fn bool(&self, db: &'db dyn Db) -> Truthiness {
|
||||
match self {
|
||||
Type::Any | Type::Todo | Type::Never | Type::Unknown | Type::Unbound => {
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
Type::None => Truthiness::AlwaysFalse,
|
||||
Type::Function(_) => Truthiness::AlwaysTrue,
|
||||
Type::Module(_) => Truthiness::AlwaysTrue,
|
||||
Type::Class(_) => {
|
||||
// TODO: lookup `__bool__` and `__len__` methods on the class's metaclass
|
||||
// More info in https://docs.python.org/3/library/stdtypes.html#truth-value-testing
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
Type::Instance(_) => {
|
||||
// TODO: lookup `__bool__` and `__len__` methods on the instance's class
|
||||
// More info in https://docs.python.org/3/library/stdtypes.html#truth-value-testing
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
Type::Union(union) => {
|
||||
let union_elements = union.elements(db);
|
||||
let first_element_truthiness = union_elements[0].bool(db);
|
||||
if first_element_truthiness.is_ambiguous() {
|
||||
return Truthiness::Ambiguous;
|
||||
}
|
||||
if !union_elements
|
||||
.iter()
|
||||
.skip(1)
|
||||
.all(|element| element.bool(db) == first_element_truthiness)
|
||||
{
|
||||
return Truthiness::Ambiguous;
|
||||
}
|
||||
first_element_truthiness
|
||||
}
|
||||
Type::Intersection(_) => {
|
||||
// TODO
|
||||
Truthiness::Ambiguous
|
||||
}
|
||||
Type::IntLiteral(num) => Truthiness::from(*num != 0),
|
||||
Type::BooleanLiteral(bool) => Truthiness::from(*bool),
|
||||
Type::StringLiteral(str) => Truthiness::from(!str.value(db).is_empty()),
|
||||
Type::LiteralString => Truthiness::Ambiguous,
|
||||
Type::BytesLiteral(bytes) => Truthiness::from(!bytes.value(db).is_empty()),
|
||||
Type::Tuple(items) => Truthiness::from(!items.elements(db).is_empty()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,21 +600,48 @@ impl<'db> Type<'db> {
|
||||
fn call(self, db: &'db dyn Db, arg_types: &[Type<'db>]) -> CallOutcome<'db> {
|
||||
match self {
|
||||
// TODO validate typed call arguments vs callable signature
|
||||
Type::Function(function_type) => CallOutcome::callable(function_type.return_type(db)),
|
||||
Type::RevealTypeFunction(function_type) => CallOutcome::revealed(
|
||||
function_type.return_type(db),
|
||||
*arg_types.first().unwrap_or(&Type::Unknown),
|
||||
),
|
||||
Type::Function(function_type) => match function_type.kind(db) {
|
||||
FunctionKind::Ordinary => CallOutcome::callable(function_type.return_type(db)),
|
||||
FunctionKind::RevealType => CallOutcome::revealed(
|
||||
function_type.return_type(db),
|
||||
*arg_types.first().unwrap_or(&Type::Unknown),
|
||||
),
|
||||
},
|
||||
|
||||
// TODO annotated return type on `__new__` or metaclass `__call__`
|
||||
Type::Class(class) => CallOutcome::callable(Type::Instance(class)),
|
||||
Type::Class(class) => {
|
||||
// If the class is the builtin-bool class (for example `bool(1)`), we try to return
|
||||
// the specific truthiness value of the input arg, `Literal[True]` for the example above.
|
||||
let is_bool = class.is_stdlib_symbol(db, "builtins", "bool");
|
||||
CallOutcome::callable(if is_bool {
|
||||
arg_types
|
||||
.first()
|
||||
.map(|arg| arg.bool(db).into_type(db))
|
||||
.unwrap_or(Type::BooleanLiteral(false))
|
||||
} else {
|
||||
Type::Instance(class)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: handle classes which implement the `__call__` protocol
|
||||
Type::Instance(_instance_ty) => CallOutcome::callable(Type::Unknown),
|
||||
Type::Instance(class) => {
|
||||
// Since `__call__` is a dunder, we need to access it as an attribute on the class
|
||||
// rather than the instance (matching runtime semantics).
|
||||
let dunder_call_method = class.class_member(db, "__call__");
|
||||
if dunder_call_method.is_unbound() {
|
||||
CallOutcome::not_callable(self)
|
||||
} else {
|
||||
let args = std::iter::once(self)
|
||||
.chain(arg_types.iter().copied())
|
||||
.collect::<Vec<_>>();
|
||||
dunder_call_method.call(db, &args)
|
||||
}
|
||||
}
|
||||
|
||||
// `Any` is callable, and its return type is also `Any`.
|
||||
Type::Any => CallOutcome::callable(Type::Any),
|
||||
|
||||
Type::Todo => CallOutcome::callable(Type::Todo),
|
||||
|
||||
Type::Unknown => CallOutcome::callable(Type::Unknown),
|
||||
|
||||
Type::Union(union) => CallOutcome::union(
|
||||
@@ -550,12 +649,11 @@ impl<'db> Type<'db> {
|
||||
union
|
||||
.elements(db)
|
||||
.iter()
|
||||
.map(|elem| elem.call(db, arg_types))
|
||||
.collect::<Box<[CallOutcome<'db>]>>(),
|
||||
.map(|elem| elem.call(db, arg_types)),
|
||||
),
|
||||
|
||||
// TODO: intersection types
|
||||
Type::Intersection(_) => CallOutcome::callable(Type::Unknown),
|
||||
Type::Intersection(_) => CallOutcome::callable(Type::Todo),
|
||||
|
||||
_ => CallOutcome::not_callable(self),
|
||||
}
|
||||
@@ -576,6 +674,12 @@ impl<'db> Type<'db> {
|
||||
};
|
||||
}
|
||||
|
||||
if let Type::Unknown | Type::Any = self {
|
||||
// Explicit handling of `Unknown` and `Any` necessary until `type[Unknown]` and
|
||||
// `type[Any]` are not defined as `Todo` anymore.
|
||||
return IterationOutcome::Iterable { element_ty: self };
|
||||
}
|
||||
|
||||
// `self` represents the type of the iterable;
|
||||
// `__iter__` and `__next__` are both looked up on the class of the iterable:
|
||||
let iterable_meta_type = self.to_meta_type(db);
|
||||
@@ -584,7 +688,7 @@ impl<'db> Type<'db> {
|
||||
if !dunder_iter_method.is_unbound() {
|
||||
let CallOutcome::Callable {
|
||||
return_ty: iterator_ty,
|
||||
} = dunder_iter_method.call(db, &[])
|
||||
} = dunder_iter_method.call(db, &[self])
|
||||
else {
|
||||
return IterationOutcome::NotIterable {
|
||||
not_iterable_ty: self,
|
||||
@@ -593,7 +697,7 @@ impl<'db> Type<'db> {
|
||||
|
||||
let dunder_next_method = iterator_ty.to_meta_type(db).member(db, "__next__");
|
||||
return dunder_next_method
|
||||
.call(db, &[])
|
||||
.call(db, &[self])
|
||||
.return_ty(db)
|
||||
.map(|element_ty| IterationOutcome::Iterable { element_ty })
|
||||
.unwrap_or(IterationOutcome::NotIterable {
|
||||
@@ -610,7 +714,7 @@ impl<'db> Type<'db> {
|
||||
let dunder_get_item_method = iterable_meta_type.member(db, "__getitem__");
|
||||
|
||||
dunder_get_item_method
|
||||
.call(db, &[])
|
||||
.call(db, &[self, builtins_symbol_ty(db, "int").to_instance(db)])
|
||||
.return_ty(db)
|
||||
.map(|element_ty| IterationOutcome::Iterable { element_ty })
|
||||
.unwrap_or(IterationOutcome::NotIterable {
|
||||
@@ -622,19 +726,19 @@ impl<'db> Type<'db> {
|
||||
pub fn to_instance(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
Type::Any => Type::Any,
|
||||
Type::Todo => Type::Todo,
|
||||
Type::Unknown => Type::Unknown,
|
||||
Type::Unbound => Type::Unknown,
|
||||
Type::Never => Type::Never,
|
||||
Type::Class(class) => Type::Instance(*class),
|
||||
Type::Union(union) => union.map(db, |element| element.to_instance(db)),
|
||||
// TODO: we can probably do better here: --Alex
|
||||
Type::Intersection(_) => Type::Unknown,
|
||||
Type::Intersection(_) => Type::Todo,
|
||||
// TODO: calling `.to_instance()` on any of these should result in a diagnostic,
|
||||
// since they already indicate that the object is an instance of some kind:
|
||||
Type::BooleanLiteral(_)
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::Function(_)
|
||||
| Type::RevealTypeFunction(_)
|
||||
| Type::Instance(_)
|
||||
| Type::Module(_)
|
||||
| Type::IntLiteral(_)
|
||||
@@ -657,20 +761,59 @@ impl<'db> Type<'db> {
|
||||
Type::BooleanLiteral(_) => builtins_symbol_ty(db, "bool"),
|
||||
Type::BytesLiteral(_) => builtins_symbol_ty(db, "bytes"),
|
||||
Type::IntLiteral(_) => builtins_symbol_ty(db, "int"),
|
||||
Type::Function(_) | Type::RevealTypeFunction(_) => types_symbol_ty(db, "FunctionType"),
|
||||
Type::Function(_) => types_symbol_ty(db, "FunctionType"),
|
||||
Type::Module(_) => types_symbol_ty(db, "ModuleType"),
|
||||
Type::Tuple(_) => builtins_symbol_ty(db, "tuple"),
|
||||
Type::None => typeshed_symbol_ty(db, "NoneType"),
|
||||
// TODO not accurate if there's a custom metaclass...
|
||||
Type::Class(_) => builtins_symbol_ty(db, "type"),
|
||||
// TODO can we do better here? `type[LiteralString]`?
|
||||
Type::StringLiteral(_) | Type::LiteralString => builtins_symbol_ty(db, "str"),
|
||||
// TODO: `type[Any]`?
|
||||
Type::Any => Type::Any,
|
||||
Type::Any => Type::Todo,
|
||||
// TODO: `type[Unknown]`?
|
||||
Type::Unknown => Type::Unknown,
|
||||
Type::Unknown => Type::Todo,
|
||||
// TODO intersections
|
||||
Type::Intersection(_) => Type::Unknown,
|
||||
Type::Tuple(_) => builtins_symbol_ty(db, "tuple"),
|
||||
Type::Intersection(_) => Type::Todo,
|
||||
Type::Todo => Type::Todo,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the string representation of this type when converted to string as it would be
|
||||
/// provided by the `__str__` method.
|
||||
///
|
||||
/// When not available, this should fall back to the value of `[Type::repr]`.
|
||||
/// Note: this method is used in the builtins `format`, `print`, `str.format` and `f-strings`.
|
||||
#[must_use]
|
||||
pub fn str(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
Type::IntLiteral(_) | Type::BooleanLiteral(_) => self.repr(db),
|
||||
Type::StringLiteral(_) | Type::LiteralString => *self,
|
||||
// TODO: handle more complex types
|
||||
_ => Type::builtin_str_instance(db),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the string representation of this type as it would be provided by the `__repr__`
|
||||
/// method at runtime.
|
||||
#[must_use]
|
||||
pub fn repr(&self, db: &'db dyn Db) -> Type<'db> {
|
||||
match self {
|
||||
Type::IntLiteral(number) => Type::StringLiteral(StringLiteralType::new(db, {
|
||||
number.to_string().into_boxed_str()
|
||||
})),
|
||||
Type::BooleanLiteral(true) => {
|
||||
Type::StringLiteral(StringLiteralType::new(db, "True".into()))
|
||||
}
|
||||
Type::BooleanLiteral(false) => {
|
||||
Type::StringLiteral(StringLiteralType::new(db, "False".into()))
|
||||
}
|
||||
Type::StringLiteral(literal) => Type::StringLiteral(StringLiteralType::new(db, {
|
||||
format!("'{}'", literal.value(db).escape_default()).into()
|
||||
})),
|
||||
Type::LiteralString => Type::LiteralString,
|
||||
// TODO: handle more complex types
|
||||
_ => Type::builtin_str_instance(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,12 +844,12 @@ enum CallOutcome<'db> {
|
||||
|
||||
impl<'db> CallOutcome<'db> {
|
||||
/// Create a new `CallOutcome::Callable` with given return type.
|
||||
fn callable(return_ty: Type<'db>) -> CallOutcome {
|
||||
fn callable(return_ty: Type<'db>) -> CallOutcome<'db> {
|
||||
CallOutcome::Callable { return_ty }
|
||||
}
|
||||
|
||||
/// Create a new `CallOutcome::NotCallable` with given not-callable type.
|
||||
fn not_callable(not_callable_ty: Type<'db>) -> CallOutcome {
|
||||
fn not_callable(not_callable_ty: Type<'db>) -> CallOutcome<'db> {
|
||||
CallOutcome::NotCallable { not_callable_ty }
|
||||
}
|
||||
|
||||
@@ -719,10 +862,13 @@ impl<'db> CallOutcome<'db> {
|
||||
}
|
||||
|
||||
/// Create a new `CallOutcome::Union` with given wrapped outcomes.
|
||||
fn union(called_ty: Type<'db>, outcomes: impl Into<Box<[CallOutcome<'db>]>>) -> CallOutcome {
|
||||
fn union(
|
||||
called_ty: Type<'db>,
|
||||
outcomes: impl IntoIterator<Item = CallOutcome<'db>>,
|
||||
) -> CallOutcome<'db> {
|
||||
CallOutcome::Union {
|
||||
called_ty,
|
||||
outcomes: outcomes.into(),
|
||||
outcomes: outcomes.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,15 +900,73 @@ impl<'db> CallOutcome<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the return type of the call, emitting diagnostics if needed.
|
||||
/// Get the return type of the call, emitting default diagnostics if needed.
|
||||
fn unwrap_with_diagnostic<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
node: ast::AnyNodeRef,
|
||||
builder: &'a mut TypeInferenceBuilder<'db>,
|
||||
) -> Type<'db> {
|
||||
match self.return_ty_result(db, node, builder) {
|
||||
Ok(return_ty) => return_ty,
|
||||
Err(NotCallableError::Type {
|
||||
not_callable_ty,
|
||||
return_ty,
|
||||
}) => {
|
||||
builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type `{}` is not callable",
|
||||
not_callable_ty.display(db)
|
||||
),
|
||||
);
|
||||
return_ty
|
||||
}
|
||||
Err(NotCallableError::UnionElement {
|
||||
not_callable_ty,
|
||||
called_ty,
|
||||
return_ty,
|
||||
}) => {
|
||||
builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type `{}` is not callable (due to union element `{}`)",
|
||||
called_ty.display(db),
|
||||
not_callable_ty.display(db),
|
||||
),
|
||||
);
|
||||
return_ty
|
||||
}
|
||||
Err(NotCallableError::UnionElements {
|
||||
not_callable_tys,
|
||||
called_ty,
|
||||
return_ty,
|
||||
}) => {
|
||||
builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type `{}` is not callable (due to union elements {})",
|
||||
called_ty.display(db),
|
||||
not_callable_tys.display(db),
|
||||
),
|
||||
);
|
||||
return_ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the return type of the call as a result.
|
||||
fn return_ty_result<'a>(
|
||||
&self,
|
||||
db: &'db dyn Db,
|
||||
node: ast::AnyNodeRef,
|
||||
builder: &'a mut TypeInferenceBuilder<'db>,
|
||||
) -> Result<Type<'db>, NotCallableError<'db>> {
|
||||
match self {
|
||||
Self::Callable { return_ty } => *return_ty,
|
||||
Self::Callable { return_ty } => Ok(*return_ty),
|
||||
Self::RevealType {
|
||||
return_ty,
|
||||
revealed_ty,
|
||||
@@ -770,21 +974,14 @@ impl<'db> CallOutcome<'db> {
|
||||
builder.add_diagnostic(
|
||||
node,
|
||||
"revealed-type",
|
||||
format_args!("Revealed type is '{}'.", revealed_ty.display(db)),
|
||||
format_args!("Revealed type is `{}`", revealed_ty.display(db)),
|
||||
);
|
||||
*return_ty
|
||||
}
|
||||
Self::NotCallable { not_callable_ty } => {
|
||||
builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type '{}' is not callable.",
|
||||
not_callable_ty.display(db)
|
||||
),
|
||||
);
|
||||
Type::Unknown
|
||||
Ok(*return_ty)
|
||||
}
|
||||
Self::NotCallable { not_callable_ty } => Err(NotCallableError::Type {
|
||||
not_callable_ty: *not_callable_ty,
|
||||
return_ty: Type::Unknown,
|
||||
}),
|
||||
Self::Union {
|
||||
outcomes,
|
||||
called_ty,
|
||||
@@ -813,41 +1010,75 @@ impl<'db> CallOutcome<'db> {
|
||||
};
|
||||
union_builder = union_builder.add(return_ty);
|
||||
}
|
||||
let return_ty = union_builder.build();
|
||||
match not_callable[..] {
|
||||
[] => {}
|
||||
[elem] => builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type '{}' is not callable (due to union element '{}').",
|
||||
called_ty.display(db),
|
||||
elem.display(db),
|
||||
),
|
||||
),
|
||||
_ if not_callable.len() == outcomes.len() => builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type '{}' is not callable.",
|
||||
called_ty.display(db)
|
||||
),
|
||||
),
|
||||
_ => builder.add_diagnostic(
|
||||
node,
|
||||
"call-non-callable",
|
||||
format_args!(
|
||||
"Object of type '{}' is not callable (due to union elements {}).",
|
||||
called_ty.display(db),
|
||||
not_callable.display(db),
|
||||
),
|
||||
),
|
||||
[] => Ok(return_ty),
|
||||
[elem] => Err(NotCallableError::UnionElement {
|
||||
not_callable_ty: elem,
|
||||
called_ty: *called_ty,
|
||||
return_ty,
|
||||
}),
|
||||
_ if not_callable.len() == outcomes.len() => Err(NotCallableError::Type {
|
||||
not_callable_ty: *called_ty,
|
||||
return_ty,
|
||||
}),
|
||||
_ => Err(NotCallableError::UnionElements {
|
||||
not_callable_tys: not_callable.into_boxed_slice(),
|
||||
called_ty: *called_ty,
|
||||
return_ty,
|
||||
}),
|
||||
}
|
||||
union_builder.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum NotCallableError<'db> {
|
||||
/// The type is not callable.
|
||||
Type {
|
||||
not_callable_ty: Type<'db>,
|
||||
return_ty: Type<'db>,
|
||||
},
|
||||
/// A single union element is not callable.
|
||||
UnionElement {
|
||||
not_callable_ty: Type<'db>,
|
||||
called_ty: Type<'db>,
|
||||
return_ty: Type<'db>,
|
||||
},
|
||||
/// Multiple (but not all) union elements are not callable.
|
||||
UnionElements {
|
||||
not_callable_tys: Box<[Type<'db>]>,
|
||||
called_ty: Type<'db>,
|
||||
return_ty: Type<'db>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'db> NotCallableError<'db> {
|
||||
/// The return type that should be used when a call is not callable.
|
||||
fn return_ty(&self) -> Type<'db> {
|
||||
match self {
|
||||
Self::Type { return_ty, .. } => *return_ty,
|
||||
Self::UnionElement { return_ty, .. } => *return_ty,
|
||||
Self::UnionElements { return_ty, .. } => *return_ty,
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolved type that was not callable.
|
||||
///
|
||||
/// For unions, returns the union type itself, which may contain a mix of callable and
|
||||
/// non-callable types.
|
||||
fn called_ty(&self) -> Type<'db> {
|
||||
match self {
|
||||
Self::Type {
|
||||
not_callable_ty, ..
|
||||
} => *not_callable_ty,
|
||||
Self::UnionElement { called_ty, .. } => *called_ty,
|
||||
Self::UnionElements { called_ty, .. } => *called_ty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum IterationOutcome<'db> {
|
||||
Iterable { element_ty: Type<'db> },
|
||||
@@ -870,12 +1101,57 @@ impl<'db> IterationOutcome<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum Truthiness {
|
||||
/// For an object `x`, `bool(x)` will always return `True`
|
||||
AlwaysTrue,
|
||||
/// For an object `x`, `bool(x)` will always return `False`
|
||||
AlwaysFalse,
|
||||
/// For an object `x`, `bool(x)` could return either `True` or `False`
|
||||
Ambiguous,
|
||||
}
|
||||
|
||||
impl Truthiness {
|
||||
const fn is_ambiguous(self) -> bool {
|
||||
matches!(self, Truthiness::Ambiguous)
|
||||
}
|
||||
|
||||
const fn negate(self) -> Self {
|
||||
match self {
|
||||
Self::AlwaysTrue => Self::AlwaysFalse,
|
||||
Self::AlwaysFalse => Self::AlwaysTrue,
|
||||
Self::Ambiguous => Self::Ambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_type(self, db: &dyn Db) -> Type {
|
||||
match self {
|
||||
Self::AlwaysTrue => Type::BooleanLiteral(true),
|
||||
Self::AlwaysFalse => Type::BooleanLiteral(false),
|
||||
Self::Ambiguous => builtins_symbol_ty(db, "bool").to_instance(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Truthiness {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Truthiness::AlwaysTrue
|
||||
} else {
|
||||
Truthiness::AlwaysFalse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::interned]
|
||||
pub struct FunctionType<'db> {
|
||||
/// name of the function at definition
|
||||
#[return_ref]
|
||||
pub name: ast::name::Name,
|
||||
|
||||
/// Is this a function that we special-case somehow? If so, which one?
|
||||
kind: FunctionKind,
|
||||
|
||||
definition: Definition<'db>,
|
||||
|
||||
/// types of all decorators on this function
|
||||
@@ -891,15 +1167,6 @@ impl<'db> FunctionType<'db> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Return true if this is a symbol with given name from `typing` or `typing_extensions`.
|
||||
pub(crate) fn is_typing_symbol(self, db: &'db dyn Db, name: &str) -> bool {
|
||||
name == self.name(db)
|
||||
&& file_to_module(db, self.definition(db).file(db)).is_some_and(|module| {
|
||||
module.search_path().is_standard_library()
|
||||
&& matches!(&**module.name(), "typing" | "typing_extensions")
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_decorator(self, db: &dyn Db, decorator: Type<'_>) -> bool {
|
||||
self.decorators(db).contains(&decorator)
|
||||
}
|
||||
@@ -917,7 +1184,7 @@ impl<'db> FunctionType<'db> {
|
||||
// rather than from `bar`'s return annotation
|
||||
// in order to determine the type that `bar` returns
|
||||
if !function_stmt_node.decorator_list.is_empty() {
|
||||
return Type::Unknown;
|
||||
return Type::Todo;
|
||||
}
|
||||
|
||||
function_stmt_node
|
||||
@@ -926,7 +1193,7 @@ impl<'db> FunctionType<'db> {
|
||||
.map(|returns| {
|
||||
if function_stmt_node.is_async {
|
||||
// TODO: generic `types.CoroutineType`!
|
||||
Type::Unknown
|
||||
Type::Todo
|
||||
} else {
|
||||
definition_expression_ty(db, definition, returns.as_ref())
|
||||
}
|
||||
@@ -935,6 +1202,15 @@ impl<'db> FunctionType<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default, Hash)]
|
||||
pub enum FunctionKind {
|
||||
/// Just a normal function for which we have no particular special casing
|
||||
#[default]
|
||||
Ordinary,
|
||||
/// `builtins.reveal_type`, `typing.reveal_type` or `typing_extensions.reveal_type`
|
||||
RevealType,
|
||||
}
|
||||
|
||||
#[salsa::interned]
|
||||
pub struct ClassType<'db> {
|
||||
/// Name of the class at definition
|
||||
@@ -1072,7 +1348,10 @@ pub struct TupleType<'db> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{builtins_symbol_ty, BytesLiteralType, StringLiteralType, Type, UnionType};
|
||||
use super::{
|
||||
builtins_symbol_ty, BytesLiteralType, StringLiteralType, Truthiness, TupleType, Type,
|
||||
UnionType,
|
||||
};
|
||||
use crate::db::tests::TestDb;
|
||||
use crate::program::{Program, SearchPathSettings};
|
||||
use crate::python_version::PythonVersion;
|
||||
@@ -1102,17 +1381,19 @@ mod tests {
|
||||
|
||||
/// A test representation of a type that can be transformed unambiguously into a real Type,
|
||||
/// given a db.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
enum Ty {
|
||||
Never,
|
||||
Unknown,
|
||||
Any,
|
||||
IntLiteral(i64),
|
||||
BoolLiteral(bool),
|
||||
StringLiteral(&'static str),
|
||||
LiteralString,
|
||||
BytesLiteral(&'static str),
|
||||
BuiltinInstance(&'static str),
|
||||
Union(Vec<Ty>),
|
||||
Tuple(Vec<Ty>),
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
@@ -1125,6 +1406,7 @@ mod tests {
|
||||
Ty::StringLiteral(s) => {
|
||||
Type::StringLiteral(StringLiteralType::new(db, (*s).into()))
|
||||
}
|
||||
Ty::BoolLiteral(b) => Type::BooleanLiteral(b),
|
||||
Ty::LiteralString => Type::LiteralString,
|
||||
Ty::BytesLiteral(s) => {
|
||||
Type::BytesLiteral(BytesLiteralType::new(db, s.as_bytes().into()))
|
||||
@@ -1133,6 +1415,10 @@ mod tests {
|
||||
Ty::Union(tys) => {
|
||||
UnionType::from_elements(db, tys.into_iter().map(|ty| ty.into_type(db)))
|
||||
}
|
||||
Ty::Tuple(tys) => {
|
||||
let elements = tys.into_iter().map(|ty| ty.into_type(db)).collect();
|
||||
Type::Tuple(TupleType::new(db, elements))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1202,4 +1488,56 @@ mod tests {
|
||||
|
||||
assert!(from.into_type(&db).is_equivalent_to(&db, to.into_type(&db)));
|
||||
}
|
||||
|
||||
#[test_case(Ty::IntLiteral(1); "is_int_literal_truthy")]
|
||||
#[test_case(Ty::IntLiteral(-1))]
|
||||
#[test_case(Ty::StringLiteral("foo"))]
|
||||
#[test_case(Ty::Tuple(vec![Ty::IntLiteral(0)]))]
|
||||
#[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(2)]))]
|
||||
fn is_truthy(ty: Ty) {
|
||||
let db = setup_db();
|
||||
assert_eq!(ty.into_type(&db).bool(&db), Truthiness::AlwaysTrue);
|
||||
}
|
||||
|
||||
#[test_case(Ty::Tuple(vec![]))]
|
||||
#[test_case(Ty::IntLiteral(0))]
|
||||
#[test_case(Ty::StringLiteral(""))]
|
||||
#[test_case(Ty::Union(vec![Ty::IntLiteral(0), Ty::IntLiteral(0)]))]
|
||||
fn is_falsy(ty: Ty) {
|
||||
let db = setup_db();
|
||||
assert_eq!(ty.into_type(&db).bool(&db), Truthiness::AlwaysFalse);
|
||||
}
|
||||
|
||||
#[test_case(Ty::BuiltinInstance("str"))]
|
||||
#[test_case(Ty::Union(vec![Ty::IntLiteral(1), Ty::IntLiteral(0)]))]
|
||||
#[test_case(Ty::Union(vec![Ty::BuiltinInstance("str"), Ty::IntLiteral(0)]))]
|
||||
#[test_case(Ty::Union(vec![Ty::BuiltinInstance("str"), Ty::IntLiteral(1)]))]
|
||||
fn boolean_value_is_unknown(ty: Ty) {
|
||||
let db = setup_db();
|
||||
assert_eq!(ty.into_type(&db).bool(&db), Truthiness::Ambiguous);
|
||||
}
|
||||
|
||||
#[test_case(Ty::IntLiteral(1), Ty::StringLiteral("1"))]
|
||||
#[test_case(Ty::BoolLiteral(true), Ty::StringLiteral("True"))]
|
||||
#[test_case(Ty::BoolLiteral(false), Ty::StringLiteral("False"))]
|
||||
#[test_case(Ty::StringLiteral("ab'cd"), Ty::StringLiteral("ab'cd"))] // no quotes
|
||||
#[test_case(Ty::LiteralString, Ty::LiteralString)]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str"))]
|
||||
fn has_correct_str(ty: Ty, expected: Ty) {
|
||||
let db = setup_db();
|
||||
|
||||
assert_eq!(ty.into_type(&db).str(&db), expected.into_type(&db));
|
||||
}
|
||||
|
||||
#[test_case(Ty::IntLiteral(1), Ty::StringLiteral("1"))]
|
||||
#[test_case(Ty::BoolLiteral(true), Ty::StringLiteral("True"))]
|
||||
#[test_case(Ty::BoolLiteral(false), Ty::StringLiteral("False"))]
|
||||
#[test_case(Ty::StringLiteral("ab'cd"), Ty::StringLiteral("'ab\\'cd'"))] // single quotes
|
||||
#[test_case(Ty::LiteralString, Ty::LiteralString)]
|
||||
#[test_case(Ty::BuiltinInstance("int"), Ty::BuiltinInstance("str"))]
|
||||
fn has_correct_repr(ty: Ty, expected: Ty) {
|
||||
let db = setup_db();
|
||||
|
||||
assert_eq!(ty.into_type(&db).repr(&db), expected.into_type(&db));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +215,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
|
||||
|
||||
/// Adds a positive type to this intersection.
|
||||
fn add_positive(&mut self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
// TODO `Any`/`Unknown`/`Todo` actually should not self-cancel
|
||||
match ty {
|
||||
Type::Intersection(inter) => {
|
||||
let pos = inter.positive(db);
|
||||
@@ -234,7 +235,7 @@ impl<'db> InnerIntersectionBuilder<'db> {
|
||||
|
||||
/// Adds a negative type to this intersection.
|
||||
fn add_negative(&mut self, db: &'db dyn Db, ty: Type<'db>) {
|
||||
// TODO Any/Unknown actually should not self-cancel
|
||||
// TODO `Any`/`Unknown`/`Todo` actually should not self-cancel
|
||||
match ty {
|
||||
Type::Intersection(intersection) => {
|
||||
let pos = intersection.negative(db);
|
||||
@@ -388,7 +389,7 @@ mod tests {
|
||||
#[test]
|
||||
fn build_union_simplify_subtype() {
|
||||
let db = setup_db();
|
||||
let t0 = builtins_symbol_ty(&db, "str").to_instance(&db);
|
||||
let t0 = Type::builtin_str_instance(&db);
|
||||
let t1 = Type::LiteralString;
|
||||
let u0 = UnionType::from_elements(&db, [t0, t1]);
|
||||
let u1 = UnionType::from_elements(&db, [t1, t0]);
|
||||
@@ -400,7 +401,7 @@ mod tests {
|
||||
#[test]
|
||||
fn build_union_no_simplify_unknown() {
|
||||
let db = setup_db();
|
||||
let t0 = builtins_symbol_ty(&db, "str").to_instance(&db);
|
||||
let t0 = Type::builtin_str_instance(&db);
|
||||
let t1 = Type::Unknown;
|
||||
let u0 = UnionType::from_elements(&db, [t0, t1]);
|
||||
let u1 = UnionType::from_elements(&db, [t1, t0]);
|
||||
@@ -412,8 +413,8 @@ mod tests {
|
||||
#[test]
|
||||
fn build_union_subsume_multiple() {
|
||||
let db = setup_db();
|
||||
let str_ty = builtins_symbol_ty(&db, "str").to_instance(&db);
|
||||
let int_ty = builtins_symbol_ty(&db, "int").to_instance(&db);
|
||||
let str_ty = Type::builtin_str_instance(&db);
|
||||
let int_ty = Type::builtin_int_instance(&db);
|
||||
let object_ty = builtins_symbol_ty(&db, "object").to_instance(&db);
|
||||
let unknown_ty = Type::Unknown;
|
||||
|
||||
|
||||
@@ -36,9 +36,8 @@ impl Display for DisplayType<'_> {
|
||||
| Type::BytesLiteral(_)
|
||||
| Type::Class(_)
|
||||
| Type::Function(_)
|
||||
| Type::RevealTypeFunction(_)
|
||||
) {
|
||||
write!(f, "Literal[{representation}]",)
|
||||
write!(f, "Literal[{representation}]")
|
||||
} else {
|
||||
representation.fmt(f)
|
||||
}
|
||||
@@ -67,15 +66,16 @@ impl Display for DisplayRepresentation<'_> {
|
||||
Type::Unknown => f.write_str("Unknown"),
|
||||
Type::Unbound => f.write_str("Unbound"),
|
||||
Type::None => f.write_str("None"),
|
||||
// `[Type::Todo]`'s display should be explicit that is not a valid display of
|
||||
// any other type
|
||||
Type::Todo => f.write_str("@Todo"),
|
||||
Type::Module(file) => {
|
||||
write!(f, "<module '{:?}'>", file.path(self.db))
|
||||
}
|
||||
// TODO functions and classes should display using a fully qualified name
|
||||
Type::Class(class) => f.write_str(class.name(self.db)),
|
||||
Type::Instance(class) => f.write_str(class.name(self.db)),
|
||||
Type::Function(function) | Type::RevealTypeFunction(function) => {
|
||||
f.write_str(function.name(self.db))
|
||||
}
|
||||
Type::Function(function) => f.write_str(function.name(self.db)),
|
||||
Type::Union(union) => union.display(self.db).fmt(f),
|
||||
Type::Intersection(intersection) => intersection.display(self.db).fmt(f),
|
||||
Type::IntLiteral(n) => n.fmt(f),
|
||||
@@ -194,7 +194,7 @@ impl TryFrom<Type<'_>> for LiteralTypeKind {
|
||||
fn try_from(value: Type<'_>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Type::Class(_) => Ok(Self::Class),
|
||||
Type::Function(_) | Type::RevealTypeFunction(_) => Ok(Self::Function),
|
||||
Type::Function(_) => Ok(Self::Function),
|
||||
Type::IntLiteral(_) => Ok(Self::IntLiteral),
|
||||
Type::StringLiteral(_) => Ok(Self::StringLiteral),
|
||||
Type::BytesLiteral(_) => Ok(Self::BytesLiteral),
|
||||
@@ -335,7 +335,7 @@ mod tests {
|
||||
class B: ...
|
||||
",
|
||||
)?;
|
||||
let mod_file = system_path_to_file(&db, "src/main.py").expect("Expected file to exist.");
|
||||
let mod_file = system_path_to_file(&db, "src/main.py").expect("file to exist");
|
||||
|
||||
let union_elements = &[
|
||||
Type::Unknown,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
9e506eb5e8fc2823db8c60ad561b1145ff114947
|
||||
@@ -1,46 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Iterator
|
||||
from contextlib import AbstractContextManager
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Any, BinaryIO, TextIO
|
||||
from typing_extensions import TypeAlias
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from importlib.abc import Traversable
|
||||
|
||||
__all__ = ["Package", "Resource", "contents", "is_resource", "open_binary", "open_text", "path", "read_binary", "read_text"]
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
__all__ += ["as_file", "files"]
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
__all__ += ["ResourceReader"]
|
||||
|
||||
Package: TypeAlias = str | ModuleType
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
Resource: TypeAlias = str
|
||||
else:
|
||||
Resource: TypeAlias = str | os.PathLike[Any]
|
||||
|
||||
def open_binary(package: Package, resource: Resource) -> BinaryIO: ...
|
||||
def open_text(package: Package, resource: Resource, encoding: str = "utf-8", errors: str = "strict") -> TextIO: ...
|
||||
def read_binary(package: Package, resource: Resource) -> bytes: ...
|
||||
def read_text(package: Package, resource: Resource, encoding: str = "utf-8", errors: str = "strict") -> str: ...
|
||||
def path(package: Package, resource: Resource) -> AbstractContextManager[Path]: ...
|
||||
def is_resource(package: Package, name: str) -> bool: ...
|
||||
def contents(package: Package) -> Iterator[str]: ...
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
def as_file(path: Traversable) -> AbstractContextManager[Path]: ...
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
def files(anchor: Package | None = ...) -> Traversable: ...
|
||||
|
||||
elif sys.version_info >= (3, 9):
|
||||
def files(package: Package) -> Traversable: ...
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
from importlib.abc import ResourceReader as ResourceReader
|
||||
@@ -47,7 +47,7 @@ impl BackgroundDocumentRequestHandler for DocumentDiagnosticRequestHandler {
|
||||
fn compute_diagnostics(snapshot: &DocumentSnapshot, db: &RootDatabase) -> Vec<Diagnostic> {
|
||||
let Some(file) = snapshot.file(db) else {
|
||||
tracing::info!(
|
||||
"No file found for snapshot for '{}'",
|
||||
"No file found for snapshot for `{}`",
|
||||
snapshot.query().file_url()
|
||||
);
|
||||
return vec![];
|
||||
|
||||
32
crates/red_knot_vendored/Cargo.toml
Normal file
32
crates/red_knot_vendored/Cargo.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "red_knot_vendored"
|
||||
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 }
|
||||
once_cell = { workspace = true }
|
||||
zip = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
path-slash = { workspace = true }
|
||||
walkdir = { workspace = true }
|
||||
zip = { workspace = true, features = ["zstd", "deflate"] }
|
||||
|
||||
[dev-dependencies]
|
||||
walkdir = { workspace = true }
|
||||
|
||||
[features]
|
||||
zstd = ["zip/zstd"]
|
||||
deflate = ["zip/deflate"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
# Red Knot
|
||||
# Vendored types for the stdlib
|
||||
|
||||
Semantic analysis for the red-knot project.
|
||||
|
||||
## Vendored types for the stdlib
|
||||
|
||||
This crate vendors [typeshed](https://github.com/python/typeshed)'s stubs for the standard library. The vendored stubs can be found in `crates/red_knot_python_semantic/vendor/typeshed`. The file `crates/red_knot_python_semantic/vendor/typeshed/source_commit.txt` tells you the typeshed commit that our vendored stdlib stubs currently correspond to.
|
||||
This crate vendors [typeshed](https://github.com/python/typeshed)'s stubs for the standard library. The vendored stubs can be found in `crates/red_knot_vendored/vendor/typeshed`. The file `crates/red_knot_vendored/vendor/typeshed/source_commit.txt` tells you the typeshed commit that our vendored stdlib stubs currently correspond to.
|
||||
|
||||
The typeshed stubs are updated every two weeks via an automated PR using the `sync_typeshed.yaml` workflow in the `.github/workflows` directory. This workflow can also be triggered at any time via [workflow dispatch](https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow#running-a-workflow).
|
||||
@@ -3,7 +3,7 @@
|
||||
//!
|
||||
//! This script should be automatically run at build time
|
||||
//! whenever the script itself changes, or whenever any files
|
||||
//! in `crates/red_knot_python_semantic/vendor/typeshed` change.
|
||||
//! in `crates/red_knot_vendored/vendor/typeshed` change.
|
||||
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
@@ -30,17 +30,12 @@ fn zip_dir(directory_path: &str, writer: File) -> ZipResult<File> {
|
||||
// We can't use `#[cfg(...)]` here because the target-arch in a build script is the
|
||||
// architecture of the system running the build script and not the architecture of the build-target.
|
||||
// That's why we use the `TARGET` environment variable here.
|
||||
#[cfg(target_arch = "powerpc64")]
|
||||
let method = CompressionMethod::Deflated;
|
||||
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
let method = {
|
||||
let target = std::env::var("TARGET").unwrap();
|
||||
if target.contains("wasm32") || target.contains("powerpc64") {
|
||||
CompressionMethod::Deflated
|
||||
} else {
|
||||
CompressionMethod::Zstd
|
||||
}
|
||||
let method = if cfg!(feature = "zstd") {
|
||||
CompressionMethod::Zstd
|
||||
} else if cfg!(feature = "deflate") {
|
||||
CompressionMethod::Deflated
|
||||
} else {
|
||||
CompressionMethod::Stored
|
||||
};
|
||||
|
||||
let options = FileOptions::default()
|
||||
@@ -6,7 +6,7 @@ use ruff_db::vendored::VendoredFileSystem;
|
||||
// Luckily this crate will fail to build if this file isn't available at build time.
|
||||
static TYPESHED_ZIP_BYTES: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/zipped_typeshed.zip"));
|
||||
|
||||
pub fn vendored_typeshed_stubs() -> &'static VendoredFileSystem {
|
||||
pub fn file_system() -> &'static VendoredFileSystem {
|
||||
static VENDORED_TYPESHED_STUBS: Lazy<VendoredFileSystem> =
|
||||
Lazy::new(|| VendoredFileSystem::new_static(TYPESHED_ZIP_BYTES).unwrap());
|
||||
&VENDORED_TYPESHED_STUBS
|
||||
@@ -42,7 +42,7 @@ mod tests {
|
||||
#[test]
|
||||
fn typeshed_vfs_consistent_with_vendored_stubs() {
|
||||
let vendored_typeshed_dir = Path::new("vendor/typeshed").canonicalize().unwrap();
|
||||
let vendored_typeshed_stubs = vendored_typeshed_stubs();
|
||||
let vendored_typeshed_stubs = file_system();
|
||||
|
||||
let mut empty_iterator = true;
|
||||
for entry in walkdir::WalkDir::new(&vendored_typeshed_dir).min_depth(1) {
|
||||
1
crates/red_knot_vendored/vendor/typeshed/source_commit.txt
vendored
Normal file
1
crates/red_knot_vendored/vendor/typeshed/source_commit.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
91a58b07cdd807b1d965e04ba85af2adab8bf924
|
||||
@@ -161,6 +161,8 @@ importlib.metadata._meta: 3.10-
|
||||
importlib.metadata.diagnose: 3.13-
|
||||
importlib.readers: 3.10-
|
||||
importlib.resources: 3.7-
|
||||
importlib.resources._common: 3.11-
|
||||
importlib.resources._functional: 3.13-
|
||||
importlib.resources.abc: 3.11-
|
||||
importlib.resources.readers: 3.11-
|
||||
importlib.resources.simple: 3.11-
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user