Compare commits

..

1 Commits

Author SHA1 Message Date
Alex Waygood
09e8599e91 [red-knot] Explicitly test that no duplicate editable search paths are ever added 2024-07-19 14:30:08 +01:00
707 changed files with 5071 additions and 16784 deletions

View File

@@ -616,10 +616,10 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: "Build benchmarks"
run: cargo codspeed build -p ruff_benchmark
run: cargo codspeed build --features codspeed -p ruff_benchmark
- name: "Run benchmarks"
uses: CodSpeedHQ/action@v3
uses: CodSpeedHQ/action@v2
with:
run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }}

View File

@@ -23,7 +23,6 @@ jobs:
name: pr-number
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
if_no_artifact_found: ignore
allow_forks: true
- name: Parse pull request number
id: pr-number
@@ -44,7 +43,6 @@ jobs:
path: pr/ecosystem
workflow_conclusion: completed
if_no_artifact_found: ignore
allow_forks: true
- name: Generate comment content
id: generate-comment

View File

@@ -104,8 +104,8 @@ jobs:
run: |
branch_name="${{ env.branch_name }}"
git config user.name "astral-docs-bot"
git config user.email "176161322+astral-docs-bot@users.noreply.github.com"
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git checkout -b $branch_name
git add site/ruff

View File

@@ -9,8 +9,7 @@ exclude: |
crates/ruff_python_formatter/resources/.*|
crates/ruff_python_formatter/tests/snapshots/.*|
crates/ruff_python_resolver/resources/.*|
crates/ruff_python_resolver/tests/snapshots/.*|
crates/red_knot_workspace/resources/.*
crates/ruff_python_resolver/tests/snapshots/.*
)$
repos:
@@ -43,7 +42,7 @@ repos:
)$
- repo: https://github.com/crate-ci/typos
rev: v1.23.5
rev: v1.23.2
hooks:
- id: typos
@@ -57,13 +56,18 @@ repos:
pass_filenames: false # This makes it a lot faster
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.5
rev: v0.5.2
hooks:
- id: ruff-format
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
types_or: [python, pyi]
require_serial: true
exclude: |
(?x)^(
crates/ruff_linter/resources/.*|
crates/ruff_python_formatter/resources/.*
)$
# Prettier
- repo: https://github.com/pre-commit/mirrors-prettier

View File

@@ -1,107 +1,5 @@
# Changelog
## 0.5.6
Ruff 0.5.6 automatically enables linting and formatting of notebooks in *preview mode*.
You can opt-out of this behavior by adding `*.ipynb` to the `extend-exclude` setting.
```toml
[tool.ruff]
extend-exclude = ["*.ipynb"]
```
### Preview features
- Enable notebooks by default in preview mode ([#12621](https://github.com/astral-sh/ruff/pull/12621))
- \[`flake8-builtins`\] Implement import, lambda, and module shadowing ([#12546](https://github.com/astral-sh/ruff/pull/12546))
- \[`pydoclint`\] Add `docstring-missing-returns` (`DOC201`) and `docstring-extraneous-returns` (`DOC202`) ([#12485](https://github.com/astral-sh/ruff/pull/12485))
### Rule changes
- \[`flake8-return`\] Exempt cached properties and other property-like decorators from explicit return rule (`RET501`) ([#12563](https://github.com/astral-sh/ruff/pull/12563))
### Server
- Make server panic hook more error resilient ([#12610](https://github.com/astral-sh/ruff/pull/12610))
- Use `$/logTrace` for server trace logs in Zed and VS Code ([#12564](https://github.com/astral-sh/ruff/pull/12564))
- Keep track of deleted cells for reorder change request ([#12575](https://github.com/astral-sh/ruff/pull/12575))
### Configuration
- \[`flake8-implicit-str-concat`\] Always allow explicit multi-line concatenations when implicit concatenations are banned ([#12532](https://github.com/astral-sh/ruff/pull/12532))
### Bug fixes
- \[`flake8-async`\] Avoid flagging `asyncio.timeout`s as unused when the context manager includes `asyncio.TaskGroup` ([#12605](https://github.com/astral-sh/ruff/pull/12605))
- \[`flake8-slots`\] Avoid recommending `__slots__` for classes that inherit from more than `namedtuple` ([#12531](https://github.com/astral-sh/ruff/pull/12531))
- \[`isort`\] Avoid marking required imports as unused ([#12537](https://github.com/astral-sh/ruff/pull/12537))
- \[`isort`\] Preserve trailing inline comments on import-from statements ([#12498](https://github.com/astral-sh/ruff/pull/12498))
- \[`pycodestyle`\] Add newlines before comments (`E305`) ([#12606](https://github.com/astral-sh/ruff/pull/12606))
- \[`pycodestyle`\] Don't attach comments with mismatched indents ([#12604](https://github.com/astral-sh/ruff/pull/12604))
- \[`pyflakes`\] Fix preview-mode bugs in `F401` when attempting to autofix unused first-party submodule imports in an `__init__.py` file ([#12569](https://github.com/astral-sh/ruff/pull/12569))
- \[`pylint`\] Respect start index in `unnecessary-list-index-lookup` ([#12603](https://github.com/astral-sh/ruff/pull/12603))
- \[`pyupgrade`\] Avoid recommending no-argument super in `slots=True` dataclasses ([#12530](https://github.com/astral-sh/ruff/pull/12530))
- \[`pyupgrade`\] Use colon rather than dot formatting for integer-only types ([#12534](https://github.com/astral-sh/ruff/pull/12534))
- Fix NFKC normalization bug when removing unused imports ([#12571](https://github.com/astral-sh/ruff/pull/12571))
### Other changes
- Consider more stdlib decorators to be property-like ([#12583](https://github.com/astral-sh/ruff/pull/12583))
- Improve handling of metaclasses in various linter rules ([#12579](https://github.com/astral-sh/ruff/pull/12579))
- Improve consistency between linter rules in determining whether a function is property ([#12581](https://github.com/astral-sh/ruff/pull/12581))
## 0.5.5
### Preview features
- \[`fastapi`\] Implement `fastapi-redundant-response-model` (`FAST001`) and `fastapi-non-annotated-dependency`(`FAST002`) ([#11579](https://github.com/astral-sh/ruff/pull/11579))
- \[`pydoclint`\] Implement `docstring-missing-exception` (`DOC501`) and `docstring-extraneous-exception` (`DOC502`) ([#11471](https://github.com/astral-sh/ruff/pull/11471))
### Rule changes
- \[`numpy`\] Fix NumPy 2.0 rule for `np.alltrue` and `np.sometrue` ([#12473](https://github.com/astral-sh/ruff/pull/12473))
- \[`numpy`\] Ignore `NPY201` inside `except` blocks for compatibility with older numpy versions ([#12490](https://github.com/astral-sh/ruff/pull/12490))
- \[`pep8-naming`\] Avoid applying `ignore-names` to `self` and `cls` function names (`N804`, `N805`) ([#12497](https://github.com/astral-sh/ruff/pull/12497))
### Formatter
- Fix incorrect placement of leading function comment with type params ([#12447](https://github.com/astral-sh/ruff/pull/12447))
### Server
- Do not bail code action resolution when a quick fix is requested ([#12462](https://github.com/astral-sh/ruff/pull/12462))
### Bug fixes
- Fix `Ord` implementation of `cmp_fix` ([#12471](https://github.com/astral-sh/ruff/pull/12471))
- Raise syntax error for unparenthesized generator expression in multi-argument call ([#12445](https://github.com/astral-sh/ruff/pull/12445))
- \[`pydoclint`\] Fix panic in `DOC501` reported in [#12428](https://github.com/astral-sh/ruff/pull/12428) ([#12435](https://github.com/astral-sh/ruff/pull/12435))
- \[`flake8-bugbear`\] Allow singleton tuples with starred expressions in `B013` ([#12484](https://github.com/astral-sh/ruff/pull/12484))
### Documentation
- Add Eglot setup guide for Emacs editor ([#12426](https://github.com/astral-sh/ruff/pull/12426))
- Add note about the breaking change in `nvim-lspconfig` ([#12507](https://github.com/astral-sh/ruff/pull/12507))
- Add note to include notebook files for native server ([#12449](https://github.com/astral-sh/ruff/pull/12449))
- Add setup docs for Zed editor ([#12501](https://github.com/astral-sh/ruff/pull/12501))
## 0.5.4
### Rule changes
- \[`ruff`\] Rename `RUF007` to `zip-instead-of-pairwise` ([#12399](https://github.com/astral-sh/ruff/pull/12399))
### Bug fixes
- \[`flake8-builtins`\] Avoid shadowing diagnostics for `@override` methods ([#12415](https://github.com/astral-sh/ruff/pull/12415))
- \[`flake8-comprehensions`\] Insert parentheses for multi-argument generators ([#12422](https://github.com/astral-sh/ruff/pull/12422))
- \[`pydocstyle`\] Handle escaped docstrings within docstring (`D301`) ([#12192](https://github.com/astral-sh/ruff/pull/12192))
### Documentation
- Fix GitHub link to Neovim setup ([#12410](https://github.com/astral-sh/ruff/pull/12410))
- Fix `output-format` default in settings reference ([#12409](https://github.com/astral-sh/ruff/pull/12409))
## 0.5.3
**Ruff 0.5.3 marks the stable release of the Ruff language server and introduces revamped

View File

@@ -905,7 +905,7 @@ There are three ways in which an import can be categorized as "first-party":
package (e.g., `from foo import bar` or `import foo.bar`), they'll be classified as first-party
automatically. This check is as simple as comparing the first segment of the current file's
module path to the first segment of the import.
1. **Source roots**: Ruff supports a [`src`](https://docs.astral.sh/ruff/settings/#src) setting, which
1. **Source roots**: Ruff supports a `[src](https://docs.astral.sh/ruff/settings/#src)` setting, which
sets the directories to scan when identifying first-party imports. The algorithm is
straightforward: given an import, like `import foo`, iterate over the directories enumerated in
the `src` setting and, for each directory, check for the existence of a subdirectory `foo` or a

242
Cargo.lock generated
View File

@@ -141,9 +141,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
[[package]]
name = "argfile"
version = "0.2.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1cc0ba69de57db40674c66f7cf2caee3981ddef084388482c95c0e2133e5e8"
checksum = "b7c5c8e418080ef8aa932039d12eda7b6f5043baf48f1523c166fbc32d004534"
dependencies = [
"fs-err",
"os_str_bytes",
@@ -188,23 +188,11 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "boomphf"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617e2d952880a00583ddb9237ac3965732e8df6a92a8e7bcc054100ec467ec3b"
dependencies = [
"crossbeam-utils",
"log",
"rayon",
"wyhash",
]
[[package]]
name = "bstr"
version = "1.10.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
dependencies = [
"memchr",
"regex-automata 0.4.6",
@@ -326,9 +314,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.11"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3"
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
dependencies = [
"clap_builder",
"clap_derive",
@@ -336,9 +324,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.11"
version = "4.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa"
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
dependencies = [
"anstream",
"anstyle",
@@ -379,9 +367,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.11"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e"
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck",
"proc-macro2",
@@ -771,9 +759,9 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.11.5"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
dependencies = [
"anstream",
"anstyle",
@@ -942,9 +930,9 @@ dependencies = [
[[package]]
name = "hashlink"
version = "0.9.1"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
dependencies = [
"hashbrown",
]
@@ -1033,9 +1021,9 @@ dependencies = [
[[package]]
name = "imara-diff"
version = "0.1.7"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc9da1a252bd44cd341657203722352efc9bc0c847d06ea6d2dc1cd1135e0a01"
checksum = "af13c8ceb376860ff0c6a66d83a8cdd4ecd9e464da24621bbffcd02b49619434"
dependencies = [
"ahash",
"hashbrown",
@@ -1043,9 +1031,9 @@ dependencies = [
[[package]]
name = "imperative"
version = "1.0.6"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29a1f6526af721f9aec9ceed7ab8ebfca47f3399d08b80056c2acca3fcb694a9"
checksum = "8b70798296d538cdaa6d652941fcc795963f8b9878b9e300c9fab7a522bd2fc0"
dependencies = [
"phf",
"rust-stemmers",
@@ -1537,85 +1525,11 @@ dependencies = [
"indexmap",
]
[[package]]
name = "orx-concurrent-ordered-bag"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aa866e2be4aa03927eddb481e7c479d5109fe3121324fb7db6d97f91adf9876"
dependencies = [
"orx-fixed-vec",
"orx-pinned-concurrent-col",
"orx-pinned-vec",
"orx-pseudo-default",
"orx-split-vec",
]
[[package]]
name = "orx-concurrent-vec"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5912426ffb660f8b61e8f0812a1d07400803cd5513969d2c7af4d69602ba8a1"
dependencies = [
"orx-concurrent-ordered-bag",
"orx-fixed-vec",
"orx-pinned-concurrent-col",
"orx-pinned-vec",
"orx-pseudo-default",
"orx-split-vec",
]
[[package]]
name = "orx-fixed-vec"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f69466c7c1fc2e1f00b58e39059b78c438b9fad144d1937ef177ecfc413e997"
dependencies = [
"orx-pinned-vec",
"orx-pseudo-default",
]
[[package]]
name = "orx-pinned-concurrent-col"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdbcb1fa05dc1676f1c9cf19f443b3d2d2ca5835911477d22fa77cad8b79208d"
dependencies = [
"orx-fixed-vec",
"orx-pinned-vec",
"orx-pseudo-default",
"orx-split-vec",
]
[[package]]
name = "orx-pinned-vec"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1071baf586de45722668234bddf56c52c1ece6a6153d16541bbb0505f0ac055"
dependencies = [
"orx-pseudo-default",
]
[[package]]
name = "orx-pseudo-default"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2f627c439e723fa78e410a0faba89047a8a47d0dc013da5c0e05806e8a6cddb"
[[package]]
name = "orx-split-vec"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52b9dbfa8c7069ae73a890870d3aa9097a897d616751d3d0278f2b42d5214730"
dependencies = [
"orx-pinned-vec",
"orx-pseudo-default",
]
[[package]]
name = "os_str_bytes"
version = "7.0.0"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ac44c994af577c799b1b4bd80dc214701e349873ad894d6cdf96f4f7526e0b9"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
dependencies = [
"memchr",
]
@@ -1944,13 +1858,14 @@ dependencies = [
"countme",
"crossbeam",
"ctrlc",
"filetime",
"notify",
"rayon",
"red_knot_module_resolver",
"red_knot_workspace",
"red_knot_python_semantic",
"ruff_db",
"ruff_python_ast",
"rustc-hash 2.0.0",
"salsa",
"tempfile",
"tracing",
"tracing-subscriber",
"tracing-tree",
@@ -1982,7 +1897,6 @@ version = "0.0.0"
dependencies = [
"anyhow",
"bitflags 2.6.0",
"countme",
"hashbrown",
"ordermap",
"red_knot_module_resolver",
@@ -1990,28 +1904,13 @@ dependencies = [
"ruff_index",
"ruff_python_ast",
"ruff_python_parser",
"ruff_python_trivia",
"ruff_text_size",
"rustc-hash 2.0.0",
"salsa",
"tracing",
]
[[package]]
name = "red_knot_workspace"
version = "0.0.0"
dependencies = [
"anyhow",
"crossbeam",
"notify",
"red_knot_module_resolver",
"red_knot_python_semantic",
"ruff_db",
"ruff_python_ast",
"rustc-hash 2.0.0",
"salsa",
"tracing",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
@@ -2093,7 +1992,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.5.6"
version = "0.5.3"
dependencies = [
"anyhow",
"argfile",
@@ -2148,9 +2047,10 @@ name = "ruff_benchmark"
version = "0.0.0"
dependencies = [
"codspeed-criterion-compat",
"criterion",
"mimalloc",
"once_cell",
"red_knot_workspace",
"red_knot",
"ruff_db",
"ruff_linter",
"ruff_python_ast",
@@ -2187,13 +2087,10 @@ dependencies = [
"filetime",
"ignore",
"insta",
"matchit",
"path-slash",
"ruff_cache",
"ruff_notebook",
"ruff_python_ast",
"ruff_python_parser",
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
@@ -2279,7 +2176,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.5.6"
version = "0.5.3"
dependencies = [
"aho-corasick",
"annotate-snippets 0.9.2",
@@ -2333,7 +2230,6 @@ dependencies = [
"thiserror",
"toml",
"typed-arena",
"unicode-normalization",
"unicode-width",
"unicode_names2",
"url",
@@ -2503,17 +2399,13 @@ version = "0.0.0"
dependencies = [
"bitflags 2.6.0",
"is-macro",
"ruff_cache",
"ruff_index",
"ruff_macros",
"ruff_python_ast",
"ruff_python_parser",
"ruff_python_stdlib",
"ruff_source_file",
"ruff_text_size",
"rustc-hash 2.0.0",
"schemars",
"serde",
]
[[package]]
@@ -2599,7 +2491,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.5.6"
version = "0.5.3"
dependencies = [
"console_error_panic_hook",
"console_log",
@@ -2646,7 +2538,6 @@ dependencies = [
"ruff_macros",
"ruff_python_ast",
"ruff_python_formatter",
"ruff_python_semantic",
"ruff_source_file",
"rustc-hash 2.0.0",
"schemars",
@@ -2739,34 +2630,25 @@ checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "salsa"
version = "0.18.0"
source = "git+https://github.com/MichaReiser/salsa.git?rev=0cae5c52a3240172ef0be5c9d19e63448c53397c#0cae5c52a3240172ef0be5c9d19e63448c53397c"
source = "git+https://github.com/salsa-rs/salsa.git?rev=a1bf3a613f451af7fc0a59411c56abc47fe8e8e1#a1bf3a613f451af7fc0a59411c56abc47fe8e8e1"
dependencies = [
"arc-swap",
"boomphf",
"crossbeam",
"dashmap 6.0.1",
"dashmap 5.5.3",
"hashlink",
"indexmap",
"orx-concurrent-vec",
"log",
"parking_lot",
"rustc-hash 2.0.0",
"salsa-macro-rules",
"rustc-hash 1.1.0",
"salsa-macros",
"smallvec",
"tracing",
]
[[package]]
name = "salsa-macro-rules"
version = "0.1.0"
source = "git+https://github.com/MichaReiser/salsa.git?rev=0cae5c52a3240172ef0be5c9d19e63448c53397c#0cae5c52a3240172ef0be5c9d19e63448c53397c"
[[package]]
name = "salsa-macros"
version = "0.18.0"
source = "git+https://github.com/MichaReiser/salsa.git?rev=0cae5c52a3240172ef0be5c9d19e63448c53397c#0cae5c52a3240172ef0be5c9d19e63448c53397c"
source = "git+https://github.com/salsa-rs/salsa.git?rev=a1bf3a613f451af7fc0a59411c56abc47fe8e8e1#a1bf3a613f451af7fc0a59411c56abc47fe8e8e1"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
@@ -2868,12 +2750,11 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.121"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
@@ -2891,9 +2772,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "0.6.7"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [
"serde",
]
@@ -3029,9 +2910,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.72"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
@@ -3119,18 +3000,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.63"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
dependencies = [
"proc-macro2",
"quote",
@@ -3194,9 +3075,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "0.8.16"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c"
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
dependencies = [
"serde",
"serde_spanned",
@@ -3206,18 +3087,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.7"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.17"
version = "0.22.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16"
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
dependencies = [
"indexmap",
"serde",
@@ -3302,9 +3183,9 @@ dependencies = [
[[package]]
name = "tracing-tree"
version = "0.4.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c"
checksum = "b56c62d2c80033cb36fae448730a2f2ef99410fe3ecbffc916681a32f6807dbe"
dependencies = [
"nu-ansi-term 0.50.0",
"tracing-core",
@@ -3457,9 +3338,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uuid"
version = "1.10.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
dependencies = [
"getrandom",
"rand",
@@ -3469,9 +3350,9 @@ dependencies = [
[[package]]
name = "uuid-macro-internal"
version = "1.10.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a"
checksum = "a3ff64d5cde1e2cb5268bdb497235b6bd255ba8244f910dbc3574e59593de68c"
dependencies = [
"proc-macro2",
"quote",
@@ -3864,15 +3745,6 @@ version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wyhash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf6e163c25e3fac820b4b453185ea2dea3b6a3e0a721d4d23d75bd33734c295"
dependencies = [
"rand_core",
]
[[package]]
name = "yansi"
version = "0.5.1"

View File

@@ -4,7 +4,7 @@ resolver = "2"
[workspace.package]
edition = "2021"
rust-version = "1.76"
rust-version = "1.75"
homepage = "https://docs.astral.sh/ruff"
documentation = "https://docs.astral.sh/ruff"
repository = "https://github.com/astral-sh/ruff"
@@ -35,9 +35,9 @@ ruff_source_file = { path = "crates/ruff_source_file" }
ruff_text_size = { path = "crates/ruff_text_size" }
ruff_workspace = { path = "crates/ruff_workspace" }
red_knot = { path = "crates/red_knot" }
red_knot_module_resolver = { path = "crates/red_knot_module_resolver" }
red_knot_python_semantic = { path = "crates/red_knot_python_semantic" }
red_knot_workspace = { path = "crates/red_knot_workspace" }
aho-corasick = { version = "1.1.3" }
annotate-snippets = { version = "0.9.2", features = ["color"] }
@@ -58,6 +58,7 @@ console_error_panic_hook = { version = "0.1.7" }
console_log = { version = "1.0.0" }
countme = { version = "3.0.1" }
compact_str = "0.8.0"
criterion = { version = "0.5.1", default-features = false }
crossbeam = { version = "0.8.4" }
dashmap = { version = "6.0.1" }
drop_bomb = { version = "0.1.5" }
@@ -107,7 +108,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/MichaReiser/salsa.git", rev = "0cae5c52a3240172ef0be5c9d19e63448c53397c" }
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "a1bf3a613f451af7fc0a59411c56abc47fe8e8e1" }
schemars = { version = "0.8.16" }
seahash = { version = "4.1.0" }
serde = { version = "1.0.197", features = ["derive"] }
@@ -132,7 +133,7 @@ toml = { version = "0.8.11" }
tracing = { version = "0.1.40" }
tracing-indicatif = { version = "0.3.6" }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing-tree = { version = "0.4.0" }
tracing-tree = { version = "0.3.0" }
typed-arena = { version = "2.0.2" }
unic-ucd-category = { version = "0.9" }
unicode-ident = { version = "1.0.12" }
@@ -156,7 +157,6 @@ zip = { version = "0.6.6", default-features = false, features = ["zstd"] }
[workspace.lints.rust]
unsafe_code = "warn"
unreachable_pub = "warn"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
[workspace.lints.clippy]
pedantic = { level = "warn", priority = -2 }

25
LICENSE
View File

@@ -1371,28 +1371,3 @@ are:
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- pydoclint, licensed as follows:
"""
MIT License
Copyright (c) 2023 jsh9
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

View File

@@ -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.5.6/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.5.6/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.5.3/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.5.3/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.5.6
rev: v0.5.3
hooks:
# Run the linter.
- id: ruff
@@ -424,7 +424,6 @@ Ruff is used by a number of major open-source projects and companies, including:
- [Dagger](https://github.com/dagger/dagger)
- [Dagster](https://github.com/dagster-io/dagster)
- Databricks ([MLflow](https://github.com/mlflow/mlflow))
- [Dify](https://github.com/langgenius/dify)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Godot](https://github.com/godotengine/godot)
- [Gradio](https://github.com/gradio-app/gradio)
@@ -435,7 +434,6 @@ Ruff is used by a number of major open-source projects and companies, including:
- Hugging Face ([Transformers](https://github.com/huggingface/transformers),
[Datasets](https://github.com/huggingface/datasets),
[Diffusers](https://github.com/huggingface/diffusers))
- IBM ([Qiskit](https://github.com/Qiskit/qiskit))
- ING Bank ([popmon](https://github.com/ing-bank/popmon), [probatus](https://github.com/ing-bank/probatus))
- [Ibis](https://github.com/ibis-project/ibis)
- [ivy](https://github.com/unifyai/ivy)

View File

@@ -10,12 +10,4 @@ doc-valid-idents = [
"SCREAMING_SNAKE_CASE",
"SQLAlchemy",
"StackOverflow",
"PyCharm",
]
ignore-interior-mutability = [
# Interned is read-only. The wrapped `Rc` never gets updated.
"ruff_formatter::format_element::Interned",
# The expression is read-only.
"ruff_python_ast::hashable::HashableExpr",
]

View File

@@ -13,25 +13,24 @@ license.workspace = true
[dependencies]
red_knot_module_resolver = { workspace = true }
red_knot_workspace = { workspace = true }
red_knot_python_semantic = { workspace = true }
ruff_db = { workspace = true, features = ["os", "cache"] }
ruff_python_ast = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true, features = ["wrap_help"] }
countme = { workspace = true, features = ["enable"] }
crossbeam = { workspace = true }
ctrlc = { version = "3.4.4" }
notify = { workspace = true }
rayon = { workspace = true }
rustc-hash = { workspace = true }
salsa = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
tracing-tree = { workspace = true }
[dev-dependencies]
filetime = { workspace = true }
tempfile = { workspace = true }
[lints]
workspace = true

View File

@@ -1,28 +1,37 @@
use std::panic::{AssertUnwindSafe, RefUnwindSafe};
use std::sync::Arc;
use red_knot_module_resolver::{vendored_typeshed_stubs, Db as ResolverDb};
use red_knot_python_semantic::Db as SemanticDb;
use ruff_db::files::{File, Files};
use salsa::{Cancelled, Database, DbWithJar};
use red_knot_module_resolver::{vendored_typeshed_stubs, Db as ResolverDb, Jar as ResolverJar};
use red_knot_python_semantic::{Db as SemanticDb, Jar as SemanticJar};
use ruff_db::files::{system_path_to_file, File, Files};
use ruff_db::program::{Program, ProgramSettings};
use ruff_db::system::System;
use ruff_db::vendored::VendoredFileSystem;
use ruff_db::{Db as SourceDb, Upcast};
use salsa::Cancelled;
use ruff_db::{Db as SourceDb, Jar as SourceJar, Upcast};
use crate::lint::Diagnostics;
use crate::workspace::{check_file, Workspace, WorkspaceMetadata};
use crate::lint::{lint_semantic, lint_syntax, unwind_if_cancelled, Diagnostics};
use crate::watch::{FileChangeKind, FileWatcherChange};
use crate::workspace::{check_file, Package, Workspace, WorkspaceMetadata};
mod changes;
pub trait Db: DbWithJar<Jar> + SemanticDb + Upcast<dyn SemanticDb> {}
#[salsa::db]
pub trait Db: SemanticDb + Upcast<dyn SemanticDb> {}
#[salsa::jar(db=Db)]
pub struct Jar(
Workspace,
Package,
lint_syntax,
lint_semantic,
unwind_if_cancelled,
);
#[salsa::db]
#[salsa::db(SourceJar, ResolverJar, SemanticJar, Jar)]
pub struct RootDatabase {
workspace: Option<Workspace>,
storage: salsa::Storage<RootDatabase>,
files: Files,
system: Box<dyn System + Send + Sync + RefUnwindSafe>,
system: Arc<dyn System + Send + Sync + RefUnwindSafe>,
}
impl RootDatabase {
@@ -34,7 +43,7 @@ impl RootDatabase {
workspace: None,
storage: salsa::Storage::default(),
files: Files::default(),
system: Box::new(system),
system: Arc::new(system),
};
let workspace = Workspace::from_metadata(&db, workspace);
@@ -50,6 +59,58 @@ impl RootDatabase {
self.workspace.unwrap()
}
#[tracing::instrument(level = "debug", skip(self, changes))]
pub fn apply_changes(&mut self, changes: Vec<FileWatcherChange>) {
let workspace = self.workspace();
let workspace_path = workspace.root(self).to_path_buf();
// TODO: Optimize change tracking by only reloading a package if a file that is part of the package was changed.
let mut structural_change = false;
for change in changes {
if matches!(
change.path.file_name(),
Some(".gitignore" | ".ignore" | "ruff.toml" | ".ruff.toml" | "pyproject.toml")
) {
// Changes to ignore files or settings can change the workspace structure or add/remove files
// from packages.
structural_change = true;
} else {
match change.kind {
FileChangeKind::Created => {
// Reload the package when a new file was added. This is necessary because the file might be excluded
// by a gitignore.
if workspace.package(self, &change.path).is_some() {
structural_change = true;
}
}
FileChangeKind::Modified => {}
FileChangeKind::Deleted => {
if let Some(package) = workspace.package(self, &change.path) {
if let Some(file) = system_path_to_file(self, &change.path) {
package.remove_file(self, file);
}
}
}
}
}
File::touch_path(self, &change.path);
}
if structural_change {
match WorkspaceMetadata::from_path(&workspace_path, self.system()) {
Ok(metadata) => {
tracing::debug!("Reload workspace after structural change.");
// TODO: Handle changes in the program settings.
workspace.reload(self, metadata);
}
Err(error) => {
tracing::error!("Failed to load workspace, keep old workspace: {error}");
}
}
}
}
/// Checks all open files in the workspace and its dependencies.
pub fn check(&self) -> Result<Vec<String>, Cancelled> {
self.with_db(|db| db.workspace().check(db))
@@ -91,38 +152,24 @@ impl Upcast<dyn SemanticDb> for RootDatabase {
fn upcast(&self) -> &(dyn SemanticDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn SemanticDb + 'static) {
self
}
}
impl Upcast<dyn SourceDb> for RootDatabase {
fn upcast(&self) -> &(dyn SourceDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn SourceDb + 'static) {
self
}
}
impl Upcast<dyn ResolverDb> for RootDatabase {
fn upcast(&self) -> &(dyn ResolverDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn ResolverDb + 'static) {
self
}
}
#[salsa::db]
impl ResolverDb for RootDatabase {}
#[salsa::db]
impl SemanticDb for RootDatabase {}
#[salsa::db]
impl SourceDb for RootDatabase {
fn vendored(&self) -> &VendoredFileSystem {
vendored_typeshed_stubs()
@@ -137,100 +184,17 @@ impl SourceDb for RootDatabase {
}
}
#[salsa::db]
impl salsa::Database for RootDatabase {}
impl Database for RootDatabase {}
#[salsa::db]
impl Db for RootDatabase {}
#[cfg(test)]
pub(crate) mod tests {
use crate::db::Db;
use red_knot_module_resolver::{vendored_typeshed_stubs, Db as ResolverDb};
use red_knot_python_semantic::Db as SemanticDb;
use ruff_db::files::Files;
use ruff_db::system::{DbWithTestSystem, System, TestSystem};
use ruff_db::vendored::VendoredFileSystem;
use ruff_db::{Db as SourceDb, Upcast};
#[salsa::db]
pub(crate) struct TestDb {
storage: salsa::Storage<Self>,
files: Files,
system: TestSystem,
vendored: VendoredFileSystem,
impl salsa::ParallelDatabase for RootDatabase {
fn snapshot(&self) -> salsa::Snapshot<Self> {
salsa::Snapshot::new(Self {
workspace: self.workspace,
storage: self.storage.snapshot(),
files: self.files.snapshot(),
system: self.system.clone(),
})
}
impl TestDb {
pub(crate) fn new() -> Self {
Self {
storage: salsa::Storage::default(),
system: TestSystem::default(),
vendored: vendored_typeshed_stubs().clone(),
files: Files::default(),
}
}
}
impl DbWithTestSystem for TestDb {
fn test_system(&self) -> &TestSystem {
&self.system
}
fn test_system_mut(&mut self) -> &mut TestSystem {
&mut self.system
}
}
#[salsa::db]
impl SourceDb for TestDb {
fn vendored(&self) -> &VendoredFileSystem {
&self.vendored
}
fn system(&self) -> &dyn System {
&self.system
}
fn files(&self) -> &Files {
&self.files
}
}
impl Upcast<dyn SemanticDb> for TestDb {
fn upcast(&self) -> &(dyn SemanticDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn SemanticDb + 'static) {
self
}
}
impl Upcast<dyn SourceDb> for TestDb {
fn upcast(&self) -> &(dyn SourceDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn SourceDb + 'static) {
self
}
}
impl Upcast<dyn ResolverDb> for TestDb {
fn upcast(&self) -> &(dyn ResolverDb + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn ResolverDb + 'static) {
self
}
}
#[salsa::db]
impl red_knot_module_resolver::Db for TestDb {}
#[salsa::db]
impl red_knot_python_semantic::Db for TestDb {}
#[salsa::db]
impl Db for TestDb {}
#[salsa::db]
impl salsa::Database for TestDb {}
}

View File

@@ -1,3 +1,5 @@
use crate::db::Jar;
pub mod db;
pub mod lint;
pub mod watch;

View File

@@ -11,7 +11,7 @@ use ruff_db::files::File;
use ruff_db::parsed::{parsed_module, ParsedModule};
use ruff_db::source::{source_text, SourceText};
use ruff_python_ast as ast;
use ruff_python_ast::visitor::{walk_expr, walk_stmt, Visitor};
use ruff_python_ast::visitor::{walk_stmt, Visitor};
use crate::db::Db;
@@ -73,10 +73,9 @@ fn lint_lines(source: &str, diagnostics: &mut Vec<String>) {
}
}
#[allow(unreachable_pub)]
#[salsa::tracked(return_ref)]
pub fn lint_semantic(db: &dyn Db, file_id: File) -> Diagnostics {
let _span = trace_span!("lint_semantic", file=?file_id.path(db)).entered();
pub(crate) fn lint_semantic(db: &dyn Db, file_id: File) -> Diagnostics {
let _span = trace_span!("lint_semantic", ?file_id).entered();
let source = source_text(db.upcast(), file_id);
let parsed = parsed_module(db.upcast(), file_id);
@@ -121,25 +120,6 @@ fn lint_unresolved_imports(context: &SemanticLintContext, import: AnyImportRef)
}
}
fn lint_maybe_undefined(context: &SemanticLintContext, name: &ast::ExprName) {
if !matches!(name.ctx, ast::ExprContext::Load) {
return;
}
let semantic = &context.semantic;
match name.ty(semantic) {
Type::Unbound => {
context.push_diagnostic(format!("Name '{}' used when not defined.", &name.id));
}
Type::Union(union) if union.contains(semantic.db(), Type::Unbound) => {
context.push_diagnostic(format!(
"Name '{}' used when possibly not defined.",
&name.id
));
}
_ => {}
}
}
fn lint_bad_override(context: &SemanticLintContext, class: &ast::StmtClassDef) {
let semantic = &context.semantic;
@@ -253,17 +233,6 @@ impl Visitor<'_> for SemanticVisitor<'_> {
walk_stmt(self, stmt);
}
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr {
ast::Expr::Name(name) if matches!(name.ctx, ast::ExprContext::Load) => {
lint_maybe_undefined(self.context, name);
}
_ => {}
}
walk_expr(self, expr);
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -303,63 +272,3 @@ enum AnyImportRef<'a> {
Import(&'a ast::StmtImport),
ImportFrom(&'a ast::StmtImportFrom),
}
#[cfg(test)]
mod tests {
use ruff_db::files::system_path_to_file;
use ruff_db::program::{Program, SearchPathSettings, TargetVersion};
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
use super::{lint_semantic, Diagnostics};
use crate::db::tests::TestDb;
fn setup_db() -> TestDb {
setup_db_with_root(SystemPathBuf::from("/src"))
}
fn setup_db_with_root(workspace_root: SystemPathBuf) -> TestDb {
let db = TestDb::new();
Program::new(
&db,
TargetVersion::Py38,
SearchPathSettings {
extra_paths: Vec::new(),
workspace_root,
site_packages: vec![],
custom_typeshed: None,
},
);
db
}
#[test]
fn undefined_variable() {
let mut db = setup_db();
db.write_dedented(
"/src/a.py",
"
x = int
if flag:
y = x
y
",
)
.unwrap();
let file = system_path_to_file(&db, "/src/a.py").expect("file to exist");
let Diagnostics::List(messages) = lint_semantic(&db, file) else {
panic!("expected some diagnostics");
};
assert_eq!(
*messages,
vec![
"Name 'flag' used when not defined.",
"Name 'y' used when possibly not defined."
]
);
}
}

View File

@@ -2,6 +2,7 @@ use std::sync::Mutex;
use clap::Parser;
use crossbeam::channel as crossbeam_channel;
use salsa::ParallelDatabase;
use tracing::subscriber::Interest;
use tracing::{Level, Metadata};
use tracing_subscriber::filter::LevelFilter;
@@ -9,10 +10,10 @@ use tracing_subscriber::layer::{Context, Filter, SubscriberExt};
use tracing_subscriber::{Layer, Registry};
use tracing_tree::time::Uptime;
use red_knot_workspace::db::RootDatabase;
use red_knot_workspace::watch;
use red_knot_workspace::watch::WorkspaceWatcher;
use red_knot_workspace::workspace::WorkspaceMetadata;
use red_knot::db::RootDatabase;
use red_knot::watch::FileWatcher;
use red_knot::watch::FileWatcherChange;
use red_knot::workspace::WorkspaceMetadata;
use ruff_db::program::{ProgramSettings, SearchPathSettings};
use ruff_db::system::{OsSystem, System, SystemPathBuf};
@@ -56,13 +57,6 @@ struct Args {
#[clap(flatten)]
verbosity: Verbosity,
#[arg(
long,
help = "Run in watch mode by re-running whenever files change",
short = 'W'
)]
watch: bool,
}
#[allow(
@@ -78,7 +72,6 @@ pub fn main() -> anyhow::Result<()> {
extra_search_path: extra_paths,
target_version,
verbosity,
watch,
} = Args::parse_from(std::env::args().collect::<Vec<_>>());
let verbosity = verbosity.level();
@@ -104,13 +97,13 @@ pub fn main() -> anyhow::Result<()> {
extra_paths,
workspace_root: workspace_metadata.root().to_path_buf(),
custom_typeshed: custom_typeshed_dir,
site_packages: vec![],
site_packages: None,
},
};
// TODO: Use the `program_settings` to compute the key for the database's persistent
// cache and load the cache if it exists.
let db = RootDatabase::new(workspace_metadata, program_settings, system);
let mut db = RootDatabase::new(workspace_metadata, program_settings, system);
let (main_loop, main_loop_cancellation_token) = MainLoop::new(verbosity);
@@ -124,124 +117,125 @@ pub fn main() -> anyhow::Result<()> {
}
})?;
let mut db = salsa::Handle::new(db);
if watch {
main_loop.watch(&mut db)?;
} else {
main_loop.run(&mut db);
};
let file_changes_notifier = main_loop.file_changes_notifier();
std::mem::forget(db);
// Watch for file changes and re-trigger the analysis.
let mut file_watcher = FileWatcher::new(move |changes| {
file_changes_notifier.notify(changes);
})?;
file_watcher.watch_folder(db.workspace().root(&db).as_std_path())?;
main_loop.run(&mut db);
println!("{}", countme::get_all());
Ok(())
}
struct MainLoop {
/// Sender that can be used to send messages to the main loop.
sender: crossbeam_channel::Sender<MainLoopMessage>,
/// Receiver for the messages sent **to** the main loop.
receiver: crossbeam_channel::Receiver<MainLoopMessage>,
/// The file system watcher, if running in watch mode.
watcher: Option<WorkspaceWatcher>,
verbosity: Option<VerbosityLevel>,
orchestrator: crossbeam_channel::Sender<OrchestratorMessage>,
receiver: crossbeam_channel::Receiver<MainLoopMessage>,
}
impl MainLoop {
fn new(verbosity: Option<VerbosityLevel>) -> (Self, MainLoopCancellationToken) {
let (sender, receiver) = crossbeam_channel::bounded(10);
let (orchestrator_sender, orchestrator_receiver) = crossbeam_channel::bounded(1);
let (main_loop_sender, main_loop_receiver) = crossbeam_channel::bounded(1);
let mut orchestrator = Orchestrator {
receiver: orchestrator_receiver,
main_loop: main_loop_sender.clone(),
revision: 0,
};
std::thread::spawn(move || {
orchestrator.run();
});
(
Self {
sender: sender.clone(),
receiver,
watcher: None,
verbosity,
orchestrator: orchestrator_sender,
receiver: main_loop_receiver,
},
MainLoopCancellationToken {
sender: main_loop_sender,
},
MainLoopCancellationToken { sender },
)
}
fn watch(mut self, db: &mut salsa::Handle<RootDatabase>) -> anyhow::Result<()> {
let sender = self.sender.clone();
let watcher = watch::directory_watcher(move |event| {
sender.send(MainLoopMessage::ApplyChanges(event)).unwrap();
})?;
self.watcher = Some(WorkspaceWatcher::new(watcher, db));
self.run(db);
Ok(())
fn file_changes_notifier(&self) -> FileChangesNotifier {
FileChangesNotifier {
sender: self.orchestrator.clone(),
}
}
#[allow(clippy::print_stderr)]
fn run(mut self, db: &mut salsa::Handle<RootDatabase>) {
// Schedule the first check.
self.sender.send(MainLoopMessage::CheckWorkspace).unwrap();
let mut revision = 0usize;
fn run(self, db: &mut RootDatabase) {
self.orchestrator.send(OrchestratorMessage::Run).unwrap();
while let Ok(message) = self.receiver.recv() {
for message in &self.receiver {
tracing::trace!("Main Loop: Tick");
match message {
MainLoopMessage::CheckWorkspace => {
let db = db.clone();
let sender = self.sender.clone();
MainLoopMessage::CheckWorkspace { revision } => {
let db = db.snapshot();
let orchestrator = self.orchestrator.clone();
// Spawn a new task that checks the workspace. This needs to be done in a separate thread
// to prevent blocking the main loop here.
rayon::spawn(move || {
if let Ok(result) = db.check() {
// Send the result back to the main loop for printing.
sender
.send(MainLoopMessage::CheckCompleted { result, revision })
.ok();
orchestrator
.send(OrchestratorMessage::CheckCompleted {
diagnostics: result,
revision,
})
.unwrap();
}
});
}
MainLoopMessage::CheckCompleted {
result,
revision: check_revision,
} => {
if check_revision == revision {
eprintln!("{}", result.join("\n"));
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("{}", countme::get_all());
}
}
if self.watcher.is_none() {
return self.exit();
}
}
MainLoopMessage::ApplyChanges(changes) => {
revision += 1;
// Automatically cancels any pending queries and waits for them to complete.
db.get_mut().apply_changes(changes);
if let Some(watcher) = self.watcher.as_mut() {
watcher.update(db);
db.apply_changes(changes);
}
MainLoopMessage::CheckCompleted(diagnostics) => {
eprintln!("{}", diagnostics.join("\n"));
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("{}", countme::get_all());
}
self.sender.send(MainLoopMessage::CheckWorkspace).unwrap();
}
MainLoopMessage::Exit => {
return self.exit();
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("{}", countme::get_all());
}
return;
}
}
}
self.exit();
}
}
#[allow(clippy::print_stderr, clippy::unused_self)]
fn exit(self) {
if self.verbosity == Some(VerbosityLevel::Trace) {
eprintln!("Exit");
eprintln!("{}", countme::get_all());
}
impl Drop for MainLoop {
fn drop(&mut self) {
self.orchestrator
.send(OrchestratorMessage::Shutdown)
.unwrap();
}
}
#[derive(Debug, Clone)]
struct FileChangesNotifier {
sender: crossbeam_channel::Sender<OrchestratorMessage>,
}
impl FileChangesNotifier {
fn notify(&self, changes: Vec<FileWatcherChange>) {
self.sender
.send(OrchestratorMessage::FileChanges(changes))
.unwrap();
}
}
@@ -256,16 +250,115 @@ impl MainLoopCancellationToken {
}
}
struct Orchestrator {
/// Sends messages to the main loop.
main_loop: crossbeam_channel::Sender<MainLoopMessage>,
/// Receives messages from the main loop.
receiver: crossbeam_channel::Receiver<OrchestratorMessage>,
revision: usize,
}
impl Orchestrator {
#[allow(clippy::print_stderr)]
fn run(&mut self) {
while let Ok(message) = self.receiver.recv() {
match message {
OrchestratorMessage::Run => {
self.main_loop
.send(MainLoopMessage::CheckWorkspace {
revision: self.revision,
})
.unwrap();
}
OrchestratorMessage::CheckCompleted {
diagnostics,
revision,
} => {
// Only take the diagnostics if they are for the latest revision.
if self.revision == revision {
self.main_loop
.send(MainLoopMessage::CheckCompleted(diagnostics))
.unwrap();
} else {
tracing::debug!("Discarding diagnostics for outdated revision {revision} (current: {}).", self.revision);
}
}
OrchestratorMessage::FileChanges(changes) => {
// Request cancellation, but wait until all analysis tasks have completed to
// avoid stale messages in the next main loop.
self.revision += 1;
self.debounce_changes(changes);
}
OrchestratorMessage::Shutdown => {
return self.shutdown();
}
}
}
}
fn debounce_changes(&self, mut changes: Vec<FileWatcherChange>) {
loop {
// Consume possibly incoming file change messages before running a new analysis, but don't wait for more than 100ms.
crossbeam_channel::select! {
recv(self.receiver) -> message => {
match message {
Ok(OrchestratorMessage::Shutdown) => {
return self.shutdown();
}
Ok(OrchestratorMessage::FileChanges(file_changes)) => {
changes.extend(file_changes);
}
Ok(OrchestratorMessage::CheckCompleted { .. })=> {
// disregard any outdated completion message.
}
Ok(OrchestratorMessage::Run) => unreachable!("The orchestrator is already running."),
Err(_) => {
// There are no more senders, no point in waiting for more messages
return;
}
}
},
default(std::time::Duration::from_millis(10)) => {
// No more file changes after 10 ms, send the changes and schedule a new analysis
self.main_loop.send(MainLoopMessage::ApplyChanges(changes)).unwrap();
self.main_loop.send(MainLoopMessage::CheckWorkspace { revision: self.revision}).unwrap();
return;
}
}
}
}
#[allow(clippy::unused_self)]
fn shutdown(&self) {
tracing::trace!("Shutting down orchestrator.");
}
}
/// Message sent from the orchestrator to the main loop.
#[derive(Debug)]
enum MainLoopMessage {
CheckWorkspace,
CheckWorkspace { revision: usize },
CheckCompleted(Vec<String>),
ApplyChanges(Vec<FileWatcherChange>),
Exit,
}
#[derive(Debug)]
enum OrchestratorMessage {
Run,
Shutdown,
CheckCompleted {
result: Vec<String>,
diagnostics: Vec<String>,
revision: usize,
},
ApplyChanges(Vec<watch::ChangeEvent>),
Exit,
FileChanges(Vec<FileWatcherChange>),
}
fn setup_tracing(verbosity: Option<VerbosityLevel>) {
@@ -299,9 +392,6 @@ impl LoggingFilter {
fn is_enabled(&self, meta: &Metadata<'_>) -> bool {
let filter = if meta.target().starts_with("red_knot") || meta.target().starts_with("ruff") {
self.trace_level
} else if meta.target().starts_with("salsa") && self.trace_level <= Level::INFO {
// Salsa emits very verbose query traces with level info. Let's not show these to the user.
Level::WARN
} else {
Level::INFO
};

View File

@@ -0,0 +1,111 @@
use std::path::Path;
use anyhow::Context;
use notify::event::{CreateKind, ModifyKind, RemoveKind};
use notify::{recommended_watcher, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use ruff_db::system::{SystemPath, SystemPathBuf};
pub struct FileWatcher {
watcher: RecommendedWatcher,
}
pub trait EventHandler: Send + 'static {
fn handle(&self, changes: Vec<FileWatcherChange>);
}
impl<F> EventHandler for F
where
F: Fn(Vec<FileWatcherChange>) + Send + 'static,
{
fn handle(&self, changes: Vec<FileWatcherChange>) {
let f = self;
f(changes);
}
}
impl FileWatcher {
pub fn new<E>(handler: E) -> anyhow::Result<Self>
where
E: EventHandler,
{
Self::from_handler(Box::new(handler))
}
fn from_handler(handler: Box<dyn EventHandler>) -> anyhow::Result<Self> {
let watcher = recommended_watcher(move |event: notify::Result<Event>| {
match event {
Ok(event) => {
// TODO verify that this handles all events correctly
let change_kind = match event.kind {
EventKind::Create(CreateKind::File) => FileChangeKind::Created,
EventKind::Modify(ModifyKind::Name(notify::event::RenameMode::From)) => {
FileChangeKind::Deleted
}
EventKind::Modify(ModifyKind::Name(notify::event::RenameMode::To)) => {
FileChangeKind::Created
}
EventKind::Modify(ModifyKind::Name(notify::event::RenameMode::Any)) => {
// TODO Introduce a better catch all event for cases that we don't understand.
FileChangeKind::Created
}
EventKind::Modify(ModifyKind::Name(notify::event::RenameMode::Both)) => {
todo!("Handle both create and delete event.");
}
EventKind::Modify(_) => FileChangeKind::Modified,
EventKind::Remove(RemoveKind::File) => FileChangeKind::Deleted,
_ => {
return;
}
};
let mut changes = Vec::new();
for path in event.paths {
if let Some(fs_path) = SystemPath::from_std_path(&path) {
changes
.push(FileWatcherChange::new(fs_path.to_path_buf(), change_kind));
}
}
if !changes.is_empty() {
handler.handle(changes);
}
}
// TODO proper error handling
Err(err) => {
panic!("Error: {err}");
}
}
})
.context("Failed to create file watcher.")?;
Ok(Self { watcher })
}
pub fn watch_folder(&mut self, path: &Path) -> anyhow::Result<()> {
self.watcher.watch(path, RecursiveMode::Recursive)?;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct FileWatcherChange {
pub path: SystemPathBuf,
#[allow(unused)]
pub kind: FileChangeKind,
}
impl FileWatcherChange {
pub fn new(path: SystemPathBuf, kind: FileChangeKind) -> Self {
Self { path, kind }
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FileChangeKind {
Created,
Modified,
Deleted,
}

View File

@@ -1,23 +1,22 @@
use salsa::{Durability, Setter as _};
// TODO: Fix clippy warnings created by salsa macros
#![allow(clippy::used_underscore_binding)]
use std::{collections::BTreeMap, sync::Arc};
use rustc_hash::{FxBuildHasher, FxHashSet};
pub use metadata::{PackageMetadata, WorkspaceMetadata};
use red_knot_module_resolver::system_module_search_paths;
use ruff_db::{
files::{system_path_to_file, File},
system::{walk_directory::WalkState, SystemPath, SystemPathBuf},
};
use ruff_python_ast::{name::Name, PySourceType};
use crate::workspace::files::{Index, IndexedFiles, PackageFiles};
use crate::{
db::Db,
lint::{lint_semantic, lint_syntax, Diagnostics},
};
mod files;
mod metadata;
/// The project workspace as a Salsa ingredient.
@@ -65,6 +64,7 @@ mod metadata;
/// holding on to the most fundamental settings required for checking.
#[salsa::input]
pub struct Workspace {
#[id]
#[return_ref]
root_buf: SystemPathBuf,
@@ -87,12 +87,13 @@ pub struct Package {
pub name: Name,
/// The path to the root directory of the package.
#[id]
#[return_ref]
root_buf: SystemPathBuf,
/// The files that are part of this package.
#[return_ref]
file_set: PackageFiles,
file_set: Arc<FxHashSet<File>>,
// TODO: Add the loaded settings.
}
@@ -105,9 +106,7 @@ impl Workspace {
packages.insert(package.root.clone(), Package::from_metadata(db, package));
}
Workspace::builder(metadata.root, None, packages)
.durability(Durability::MEDIUM)
.new(db)
Workspace::new(db, metadata.root, None, packages)
}
pub fn root(self, db: &dyn Db) -> &SystemPath {
@@ -118,7 +117,6 @@ impl Workspace {
self.package_tree(db).values().copied()
}
#[tracing::instrument(skip_all)]
pub fn reload(self, db: &mut dyn Db, metadata: WorkspaceMetadata) {
assert_eq!(self.root(db), metadata.root());
@@ -138,12 +136,9 @@ impl Workspace {
new_packages.insert(path, package);
}
self.set_package_tree(db)
.with_durability(Durability::MEDIUM)
.to(new_packages);
self.set_package_tree(db).to(new_packages);
}
#[tracing::instrument(level = "debug", skip_all)]
pub fn update_package(self, db: &mut dyn Db, metadata: PackageMetadata) -> anyhow::Result<()> {
let path = metadata.root().to_path_buf();
@@ -162,7 +157,7 @@ impl Workspace {
pub fn package(self, db: &dyn Db, path: &SystemPath) -> Option<Package> {
let packages = self.package_tree(db);
let (package_path, package) = packages.range(..=path.to_path_buf()).next_back()?;
let (package_path, package) = packages.range(..path.to_path_buf()).next_back()?;
if path.starts_with(package_path) {
Some(*package)
@@ -229,30 +224,20 @@ impl Workspace {
///
/// This changes the behavior of `check` to check all files in the workspace instead of just the open files.
pub fn take_open_files(self, db: &mut dyn Db) -> FxHashSet<File> {
// Salsa will cancel any pending queries and remove its own reference to `open_files`
// so that the reference counter to `open_files` now drops to 1.
let open_files = self.set_open_file_set(db).to(None);
let open_files = self.open_file_set(db).clone();
if let Some(open_files) = open_files {
// Salsa will cancel any pending queries and remove its own reference to `open_files`
// so that the reference counter to `open_files` now drops to 1.
self.set_open_file_set(db).to(None);
Arc::try_unwrap(open_files).unwrap()
} else {
FxHashSet::default()
}
}
/// Returns the paths that should be watched.
///
/// The paths that require watching might change with every revision.
pub fn paths_to_watch(self, db: &dyn Db) -> FxHashSet<SystemPathBuf> {
ruff_db::system::deduplicate_nested_paths(
std::iter::once(self.root(db)).chain(system_module_search_paths(db.upcast())),
)
.map(SystemPath::to_path_buf)
.collect()
}
}
#[salsa::tracked]
impl Package {
pub fn root(self, db: &dyn Db) -> &SystemPath {
self.root_buf(db)
@@ -260,77 +245,51 @@ impl Package {
/// Returns `true` if `file` is a first-party file part of this package.
pub fn contains_file(self, db: &dyn Db, file: File) -> bool {
self.files(db).read().contains(&file)
self.files(db).contains(&file)
}
#[tracing::instrument(level = "debug", skip(db))]
pub fn remove_file(self, db: &mut dyn Db, file: File) {
let Some(mut index) = PackageFiles::indexed_mut(db, self) else {
return;
};
index.remove(file);
pub fn files(self, db: &dyn Db) -> &FxHashSet<File> {
self.file_set(db)
}
#[tracing::instrument(level = "debug", skip(db))]
pub fn add_file(self, db: &mut dyn Db, file: File) {
let Some(mut index) = PackageFiles::indexed_mut(db, self) else {
return;
};
pub fn remove_file(self, db: &mut dyn Db, file: File) -> bool {
let mut files_arc = self.file_set(db).clone();
index.insert(file);
// Set a dummy value. Salsa will cancel any pending queries and remove its own reference to `files`
// so that the reference counter to `files` now drops to 1.
self.set_file_set(db).to(Arc::new(FxHashSet::default()));
let files = Arc::get_mut(&mut files_arc).unwrap();
let removed = files.remove(&file);
self.set_file_set(db).to(files_arc);
removed
}
#[tracing::instrument(level = "debug", skip(db))]
pub(crate) fn check(self, db: &dyn Db) -> Vec<String> {
let mut result = Vec::new();
for file in &self.files(db).read() {
let diagnostics = check_file(db, file);
for file in self.files(db) {
let diagnostics = check_file(db, *file);
result.extend_from_slice(&diagnostics);
}
result
}
/// Returns the files belonging to this package.
#[salsa::tracked]
pub fn files(self, db: &dyn Db) -> IndexedFiles {
let files = self.file_set(db);
let indexed = match files.get() {
Index::Lazy(vacant) => {
let files = discover_package_files(db, self.root(db));
vacant.set(files)
}
Index::Indexed(indexed) => indexed,
};
indexed
}
fn from_metadata(db: &dyn Db, metadata: PackageMetadata) -> Self {
Self::builder(metadata.name, metadata.root, PackageFiles::default())
.durability(Durability::MEDIUM)
.new(db)
let files = discover_package_files(db, metadata.root());
Self::new(db, metadata.name, metadata.root, Arc::new(files))
}
fn update(self, db: &mut dyn Db, metadata: PackageMetadata) {
let root = self.root(db);
assert_eq!(root, metadata.root());
if self.name(db) != metadata.name() {
self.set_name(db)
.with_durability(Durability::MEDIUM)
.to(metadata.name);
}
}
let files = discover_package_files(db, root);
#[tracing::instrument(level = "debug", skip(db))]
pub fn reload_files(self, db: &mut dyn Db) {
if !self.file_set(db).is_lazy() {
// Force a re-index of the files in the next revision.
self.set_file_set(db).to(PackageFiles::lazy());
}
self.set_name(db).to(metadata.name);
self.set_file_set(db).to(Arc::new(files));
}
}
@@ -376,7 +335,7 @@ fn discover_package_files(db: &dyn Db, path: &SystemPath) -> FxHashSet<File> {
for path in paths {
// If this returns `None`, then the file was deleted between the `walk_directory` call and now.
// We can ignore this.
if let Ok(file) = system_path_to_file(db.upcast(), &path) {
if let Some(file) = system_path_to_file(db.upcast(), &path) {
files.insert(file);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,29 @@
use ruff_db::Upcast;
#[salsa::db]
pub trait Db: ruff_db::Db + Upcast<dyn ruff_db::Db> {}
use crate::resolver::{
editable_install_resolution_paths, file_to_module, internal::ModuleNameIngredient,
module_resolution_settings, resolve_module_query,
};
use crate::typeshed::parse_typeshed_versions;
#[salsa::jar(db=Db)]
pub struct Jar(
ModuleNameIngredient<'_>,
module_resolution_settings,
editable_install_resolution_paths,
resolve_module_query,
file_to_module,
parse_typeshed_versions,
);
pub trait Db: salsa::DbWithJar<Jar> + ruff_db::Db + Upcast<dyn ruff_db::Db> {}
#[cfg(test)]
pub(crate) mod tests {
use std::sync;
use salsa::DebugWithDb;
use ruff_db::files::Files;
use ruff_db::system::{DbWithTestSystem, TestSystem};
use ruff_db::vendored::VendoredFileSystem;
@@ -15,7 +32,7 @@ pub(crate) mod tests {
use super::*;
#[salsa::db]
#[salsa::db(Jar, ruff_db::Jar)]
pub(crate) struct TestDb {
storage: salsa::Storage<Self>,
system: TestSystem,
@@ -29,7 +46,7 @@ pub(crate) mod tests {
Self {
storage: salsa::Storage::default(),
system: TestSystem::default(),
vendored: vendored_typeshed_stubs().clone(),
vendored: vendored_typeshed_stubs().snapshot(),
events: sync::Arc::default(),
files: Files::default(),
}
@@ -59,12 +76,8 @@ pub(crate) mod tests {
fn upcast(&self) -> &(dyn ruff_db::Db + 'static) {
self
}
fn upcast_mut(&mut self) -> &mut (dyn ruff_db::Db + 'static) {
self
}
}
#[salsa::db]
impl ruff_db::Db for TestDb {
fn vendored(&self) -> &VendoredFileSystem {
&self.vendored
@@ -79,7 +92,6 @@ pub(crate) mod tests {
}
}
#[salsa::db]
impl Db for TestDb {}
impl DbWithTestSystem for TestDb {
@@ -92,14 +104,23 @@ pub(crate) mod tests {
}
}
#[salsa::db]
impl salsa::Database for TestDb {
fn salsa_event(&self, event: salsa::Event) {
self.attach(|_| {
tracing::trace!("event: {event:?}");
let mut events = self.events.lock().unwrap();
events.push(event);
});
tracing::trace!("event: {:?}", event.debug(self));
let mut events = self.events.lock().unwrap();
events.push(event);
}
}
impl salsa::ParallelDatabase for TestDb {
fn snapshot(&self) -> salsa::Snapshot<Self> {
salsa::Snapshot::new(Self {
storage: self.storage.snapshot(),
system: self.system.snapshot(),
vendored: self.vendored.snapshot(),
files: self.files.snapshot(),
events: self.events.clone(),
})
}
}
}

View File

@@ -1,16 +1,3 @@
use std::iter::FusedIterator;
pub use db::Db;
pub use module::{Module, ModuleKind};
pub use module_name::ModuleName;
pub use resolver::resolve_module;
use ruff_db::system::SystemPath;
pub use typeshed::{
vendored_typeshed_stubs, TypeshedVersionsParseError, TypeshedVersionsParseErrorKind,
};
use crate::resolver::{module_resolution_settings, SearchPathIterator};
mod db;
mod module;
mod module_name;
@@ -22,29 +9,10 @@ mod typeshed;
#[cfg(test)]
mod testing;
/// Returns an iterator over all search paths pointing to a system path
pub fn system_module_search_paths(db: &dyn Db) -> SystemModuleSearchPathsIter {
SystemModuleSearchPathsIter {
inner: module_resolution_settings(db).search_paths(db),
}
}
pub struct SystemModuleSearchPathsIter<'db> {
inner: SearchPathIterator<'db>,
}
impl<'db> Iterator for SystemModuleSearchPathsIter<'db> {
type Item = &'db SystemPath;
fn next(&mut self) -> Option<Self::Item> {
loop {
let next = self.inner.next()?;
if let Some(system_path) = next.as_system_path() {
return Some(system_path);
}
}
}
}
impl FusedIterator for SystemModuleSearchPathsIter<'_> {}
pub use db::{Db, Jar};
pub use module::{Module, ModuleKind};
pub use module_name::ModuleName;
pub use resolver::resolve_module;
pub use typeshed::{
vendored_typeshed_stubs, TypeshedVersionsParseError, TypeshedVersionsParseErrorKind,
};

View File

@@ -3,8 +3,9 @@ use std::sync::Arc;
use ruff_db::files::File;
use crate::db::Db;
use crate::module_name::ModuleName;
use crate::path::SearchPath;
use crate::path::{ModuleResolutionPathBuf, ModuleResolutionPathRef};
/// Representation of a Python module.
#[derive(Clone, PartialEq, Eq)]
@@ -16,7 +17,7 @@ impl Module {
pub(crate) fn new(
name: ModuleName,
kind: ModuleKind,
search_path: SearchPath,
search_path: Arc<ModuleResolutionPathBuf>,
file: File,
) -> Self {
Self {
@@ -40,8 +41,8 @@ impl Module {
}
/// The search path from which the module was resolved.
pub(crate) fn search_path(&self) -> &SearchPath {
&self.inner.search_path
pub(crate) fn search_path(&self) -> ModuleResolutionPathRef {
ModuleResolutionPathRef::from(&*self.inner.search_path)
}
/// Determine whether this module is a single-file module or a package
@@ -61,11 +62,22 @@ impl std::fmt::Debug for Module {
}
}
impl salsa::DebugWithDb<dyn Db> for Module {
fn fmt(&self, f: &mut Formatter<'_>, db: &dyn Db) -> std::fmt::Result {
f.debug_struct("Module")
.field("name", &self.name())
.field("kind", &self.kind())
.field("file", &self.file().debug(db.upcast()))
.field("search_path", &self.search_path())
.finish()
}
}
#[derive(PartialEq, Eq)]
struct ModuleInner {
name: ModuleName,
kind: ModuleKind,
search_path: SearchPath,
search_path: Arc<ModuleResolutionPathBuf>,
file: File,
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,24 @@
use std::borrow::Cow;
use std::iter::FusedIterator;
use std::sync::Arc;
use once_cell::sync::Lazy;
use ruff_db::files::{File, FilePath, FileRootKind};
use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_db::files::{File, FilePath};
use ruff_db::program::{Program, SearchPathSettings, TargetVersion};
use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf};
use ruff_db::vendored::VendoredPath;
use rustc_hash::{FxBuildHasher, FxHashSet};
use crate::db::Db;
use crate::module::{Module, ModuleKind};
use crate::module_name::ModuleName;
use crate::path::{ModulePath, SearchPath, SearchPathValidationError};
use crate::path::ModuleResolutionPathBuf;
use crate::state::ResolverState;
type SearchPathRoot = Arc<ModuleResolutionPathBuf>;
/// 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);
let interned_name = internal::ModuleNameIngredient::new(db, module_name);
resolve_module_query(db, interned_name)
}
@@ -28,10 +30,11 @@ pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option<Module> {
#[salsa::tracked]
pub(crate) fn resolve_module_query<'db>(
db: &'db dyn Db,
module_name: ModuleNameIngredient<'db>,
module_name: internal::ModuleNameIngredient<'db>,
) -> Option<Module> {
let _span = tracing::trace_span!("resolve_module", ?module_name).entered();
let name = module_name.name(db);
let _span = tracing::trace_span!("resolve_module", %name).entered();
let (search_path, module_file, kind) = resolve_name(db, name)?;
@@ -57,12 +60,6 @@ pub(crate) fn path_to_module(db: &dyn Db, path: &FilePath) -> Option<Module> {
file_to_module(db, file)
}
#[derive(Debug, Clone, Copy)]
enum SystemOrVendoredPathRef<'a> {
System(&'a SystemPath),
Vendored(&'a VendoredPath),
}
/// Resolves the module for the file with the given id.
///
/// Returns `None` if the file is not a module locatable via any of the known search paths.
@@ -70,11 +67,7 @@ enum SystemOrVendoredPathRef<'a> {
pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
let _span = tracing::trace_span!("file_to_module", ?file).entered();
let path = match file.path(db.upcast()) {
FilePath::System(system) => SystemOrVendoredPathRef::System(system),
FilePath::Vendored(vendored) => SystemOrVendoredPathRef::Vendored(vendored),
FilePath::SystemVirtual(_) => return None,
};
let path = file.path(db.upcast());
let settings = module_resolution_settings(db);
@@ -82,11 +75,7 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
let module_name = loop {
let candidate = search_paths.next()?;
let relative_path = match path {
SystemOrVendoredPathRef::System(path) => candidate.relativize_system_path(path),
SystemOrVendoredPathRef::Vendored(path) => candidate.relativize_vendored_path(path),
};
if let Some(relative_path) = relative_path {
if let Some(relative_path) = candidate.relativize_path(path) {
break relative_path.to_module_name()?;
}
};
@@ -116,10 +105,16 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
///
/// This method also implements the typing spec's [module resolution order].
///
/// TODO(Alex): this method does multiple `.unwrap()` calls when it should really return an error.
/// Each `.unwrap()` call is a point where we're validating a setting that the user would pass
/// and transforming it into an internal representation for a validated path.
/// Rather than panicking if a path fails to validate, we should display an error message to the user
/// and exit the process with a nonzero exit code.
/// This validation should probably be done outside of Salsa?
///
/// [module resolution order]: https://typing.readthedocs.io/en/latest/spec/distributing.html#import-resolution-ordering
fn try_resolve_module_resolution_settings(
db: &dyn Db,
) -> Result<ModuleResolutionSettings, SearchPathValidationError> {
#[salsa::tracked(return_ref)]
pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSettings {
let program = Program::get(db.upcast());
let SearchPathSettings {
@@ -137,28 +132,44 @@ fn try_resolve_module_resolution_settings(
tracing::info!("extra search paths: {extra_paths:?}");
}
let system = db.system();
let files = db.files();
let current_directory = db.system().current_directory();
let mut static_search_paths = vec![];
let mut static_search_paths: Vec<_> = extra_paths
.iter()
.map(|fs_path| {
Arc::new(
ModuleResolutionPathBuf::extra(SystemPath::absolute(fs_path, current_directory))
.unwrap(),
)
})
.collect();
for path in extra_paths {
files.try_add_root(db.upcast(), path, FileRootKind::LibrarySearchPath);
static_search_paths.push(SearchPath::extra(system, path.clone())?);
}
static_search_paths.push(Arc::new(
ModuleResolutionPathBuf::first_party(SystemPath::absolute(
workspace_root,
current_directory,
))
.unwrap(),
));
static_search_paths.push(SearchPath::first_party(system, workspace_root.clone())?);
static_search_paths.push(Arc::new(custom_typeshed.as_ref().map_or_else(
ModuleResolutionPathBuf::vendored_stdlib,
|custom| {
ModuleResolutionPathBuf::stdlib_from_custom_typeshed_root(&SystemPath::absolute(
custom,
current_directory,
))
.unwrap()
},
)));
static_search_paths.push(if let Some(custom_typeshed) = custom_typeshed.as_ref() {
files.try_add_root(
db.upcast(),
custom_typeshed,
FileRootKind::LibrarySearchPath,
if let Some(path) = site_packages {
let site_packages_root = Arc::new(
ModuleResolutionPathBuf::site_packages(SystemPath::absolute(path, current_directory))
.unwrap(),
);
SearchPath::custom_stdlib(db, custom_typeshed.clone())?
} else {
SearchPath::vendored_stdlib()
});
static_search_paths.push(site_packages_root);
}
// TODO vendor typeshed's third-party stubs as well as the stdlib and fallback to them as a final step
@@ -182,68 +193,41 @@ fn try_resolve_module_resolution_settings(
}
});
Ok(ModuleResolutionSettings {
ModuleResolutionSettings {
target_version,
static_search_paths,
site_packages_paths: site_packages.to_owned(),
})
}
#[salsa::tracked(return_ref)]
pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSettings {
// TODO proper error handling if this returns an error:
try_resolve_module_resolution_settings(db).unwrap()
}
/// 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
/// due to editable installations of third-party packages.
///
/// The editable-install search paths for the first `site-packages` directory
/// should come between the two `site-packages` directories when it comes to
/// module-resolution priority.
#[salsa::tracked(return_ref)]
pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
let ModuleResolutionSettings {
target_version: _,
static_search_paths,
site_packages_paths,
} = module_resolution_settings(db);
let mut dynamic_paths = Vec::new();
if site_packages_paths.is_empty() {
return dynamic_paths;
}
}
let mut existing_paths: FxHashSet<_> = static_search_paths
/// Collect all dynamic search paths:
/// search paths listed in `.pth` files in the `site-packages` directory
/// due to editable installations of third-party packages.
#[salsa::tracked(return_ref)]
pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec<Arc<ModuleResolutionPathBuf>> {
// This query needs to be re-executed each time a `.pth` file
// is added, modified or removed from the `site-packages` directory.
// However, we don't use Salsa queries to read the source text of `.pth` files;
// we use the APIs on the `System` trait directly. As such, for now we simply ask
// Salsa to recompute this query on each new revision.
//
// TODO: add some kind of watcher for the `site-packages` directory that looks
// for `site-packages/*.pth` files being added/modified/removed; get rid of this.
// When doing so, also make the test
// `deleting_pth_file_on_which_module_resolution_depends_invalidates_cache()`
// more principled!
db.report_untracked_read();
let static_search_paths = &module_resolution_settings(db).static_search_paths;
let site_packages = static_search_paths
.iter()
.filter_map(|path| path.as_system_path())
.map(Cow::Borrowed)
.collect();
.find(|path| path.is_site_packages());
let files = db.files();
let system = db.system();
let mut dynamic_paths = Vec::default();
for site_packages_dir in site_packages_paths {
if !existing_paths.insert(Cow::Borrowed(site_packages_dir)) {
continue;
}
let site_packages_root = files.try_add_root(
db.upcast(),
site_packages_dir,
FileRootKind::LibrarySearchPath,
);
// This query needs to be re-executed each time a `.pth` file
// is added, modified or removed from the `site-packages` directory.
// However, we don't use Salsa queries to read the source text of `.pth` files;
// we use the APIs on the `System` trait directly. As such, add a dependency on the
// site-package directory's revision.
site_packages_root.revision(db.upcast());
dynamic_paths
.push(SearchPath::site_packages(system, site_packages_dir.to_owned()).unwrap());
if let Some(site_packages) = site_packages {
let site_packages = site_packages
.as_system_path()
.expect("Expected site-packages never to be a VendoredPath!");
// As well as modules installed directly into `site-packages`,
// the directory may also contain `.pth` files.
@@ -251,8 +235,8 @@ pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
// containing a (relative or absolute) path.
// Each of these paths may point to an editable install of a package,
// so should be considered an additional search path.
let Ok(pth_file_iterator) = PthFileIterator::new(db, site_packages_dir) else {
continue;
let Ok(pth_file_iterator) = PthFileIterator::new(db, site_packages) else {
return dynamic_paths;
};
// The Python documentation specifies that `.pth` files in `site-packages`
@@ -261,12 +245,20 @@ pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
let mut all_pth_files: Vec<PthFile> = pth_file_iterator.collect();
all_pth_files.sort_by(|a, b| a.path.cmp(&b.path));
let mut existing_paths: FxHashSet<_> = static_search_paths
.iter()
.filter_map(|path| path.as_system_path())
.map(Cow::Borrowed)
.collect();
dynamic_paths.reserve(all_pth_files.len());
for pth_file in &all_pth_files {
for installation in pth_file.editable_installations() {
if existing_paths.insert(Cow::Owned(
installation.as_system_path().unwrap().to_path_buf(),
)) {
dynamic_paths.push(installation);
dynamic_paths.push(Arc::new(installation));
}
}
}
@@ -282,14 +274,14 @@ pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
/// are only calculated lazily.
///
/// [`sys.path` at runtime]: https://docs.python.org/3/library/site.html#module-site
pub(crate) struct SearchPathIterator<'db> {
struct SearchPathIterator<'db> {
db: &'db dyn Db,
static_paths: std::slice::Iter<'db, SearchPath>,
dynamic_paths: Option<std::slice::Iter<'db, SearchPath>>,
static_paths: std::slice::Iter<'db, SearchPathRoot>,
dynamic_paths: Option<std::slice::Iter<'db, SearchPathRoot>>,
}
impl<'db> Iterator for SearchPathIterator<'db> {
type Item = &'db SearchPath;
type Item = &'db SearchPathRoot;
fn next(&mut self) -> Option<Self::Item> {
let SearchPathIterator {
@@ -300,7 +292,7 @@ impl<'db> Iterator for SearchPathIterator<'db> {
static_paths.next().or_else(|| {
dynamic_paths
.get_or_insert_with(|| dynamic_resolution_paths(*db).iter())
.get_or_insert_with(|| editable_install_resolution_paths(*db).iter())
.next()
})
}
@@ -321,7 +313,7 @@ struct PthFile<'db> {
impl<'db> PthFile<'db> {
/// Yield paths in this `.pth` file that appear to represent editable installations,
/// and should therefore be added as module-resolution search paths.
fn editable_installations(&'db self) -> impl Iterator<Item = SearchPath> + 'db {
fn editable_installations(&'db self) -> impl Iterator<Item = ModuleResolutionPathBuf> + 'db {
let PthFile {
system,
path: _,
@@ -343,7 +335,7 @@ impl<'db> PthFile<'db> {
return None;
}
let possible_editable_install = SystemPath::absolute(line, site_packages);
SearchPath::editable(*system, possible_editable_install).ok()
ModuleResolutionPathBuf::editable_installation_root(*system, possible_editable_install)
})
}
}
@@ -410,18 +402,12 @@ impl<'db> Iterator for PthFileIterator<'db> {
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct ModuleResolutionSettings {
target_version: TargetVersion,
/// Search paths that have been statically determined purely from reading Ruff's configuration settings.
/// These shouldn't ever change unless the config settings themselves change.
static_search_paths: Vec<SearchPath>,
/// site-packages paths are not included in the above field:
/// if there are multiple site-packages paths, editable installations can appear
/// *between* the site-packages paths on `sys.path` at runtime.
/// That means we can't know where a second or third `site-packages` path should sit
/// in terms of module-resolution priority until we've discovered the editable installs
/// for the first `site-packages` path
site_packages_paths: Vec<SystemPathBuf>,
///
/// Note that `site-packages` *is included* as a search path in this sequence,
/// but it is also stored separately so that we're able to find editable installs later.
static_search_paths: Vec<SearchPathRoot>,
}
impl ModuleResolutionSettings {
@@ -429,7 +415,7 @@ impl ModuleResolutionSettings {
self.target_version
}
pub(crate) fn search_paths<'db>(&'db self, db: &'db dyn Db) -> SearchPathIterator<'db> {
fn search_paths<'db>(&'db self, db: &'db dyn Db) -> SearchPathIterator<'db> {
SearchPathIterator {
db,
static_paths: self.static_search_paths.iter(),
@@ -438,73 +424,34 @@ impl ModuleResolutionSettings {
}
}
/// A thin wrapper around `ModuleName` to make it a Salsa ingredient.
///
/// This is needed because Salsa requires that all query arguments are salsa ingredients.
#[salsa::interned]
struct ModuleNameIngredient<'db> {
#[return_ref]
pub(super) name: ModuleName,
}
// The singleton methods generated by salsa are all `pub` instead of `pub(crate)` which triggers
// `unreachable_pub`. Work around this by creating a module and allow `unreachable_pub` for it.
// Salsa also generates uses to `_db` variables for `interned` which triggers `clippy::used_underscore_binding`. Suppress that too
// TODO(micha): Contribute a fix for this upstream where the singleton methods have the same visibility as the struct.
#[allow(unreachable_pub, clippy::used_underscore_binding)]
pub(crate) mod internal {
use crate::module_name::ModuleName;
/// Modules that are builtin to the Python interpreter itself.
///
/// When these module names are imported, standard module resolution is bypassed:
/// the module name always resolves to the stdlib module,
/// even if there's a module of the same name in the workspace root
/// (which would normally result in the stdlib module being overridden).
///
/// TODO(Alex): write a script to generate this list,
/// similar to what we do in `crates/ruff_python_stdlib/src/sys.rs`
static BUILTIN_MODULES: Lazy<FxHashSet<&str>> = Lazy::new(|| {
const BUILTIN_MODULE_NAMES: &[&str] = &[
"_abc",
"_ast",
"_codecs",
"_collections",
"_functools",
"_imp",
"_io",
"_locale",
"_operator",
"_signal",
"_sre",
"_stat",
"_string",
"_symtable",
"_thread",
"_tokenize",
"_tracemalloc",
"_typing",
"_warnings",
"_weakref",
"atexit",
"builtins",
"errno",
"faulthandler",
"gc",
"itertools",
"marshal",
"posix",
"pwd",
"sys",
"time",
];
BUILTIN_MODULE_NAMES.iter().copied().collect()
});
/// A thin wrapper around `ModuleName` to make it a Salsa ingredient.
///
/// This is needed because Salsa requires that all query arguments are salsa ingredients.
#[salsa::interned]
pub(crate) struct ModuleNameIngredient<'db> {
#[return_ref]
pub(super) name: ModuleName,
}
}
/// Given a module name and a list of search paths in which to lookup modules,
/// attempt to resolve the module name
fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, File, ModuleKind)> {
fn resolve_name(
db: &dyn Db,
name: &ModuleName,
) -> Option<(Arc<ModuleResolutionPathBuf>, File, ModuleKind)> {
let resolver_settings = module_resolution_settings(db);
let resolver_state = ResolverState::new(db, resolver_settings.target_version());
let is_builtin_module = BUILTIN_MODULES.contains(&name.as_str());
for search_path in resolver_settings.search_paths(db) {
if is_builtin_module && !search_path.is_standard_library() {
continue;
}
let mut components = name.components();
let module_name = components.next_back()?;
@@ -515,7 +462,7 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, File, Mod
package_path.push(module_name);
// Must be a `__init__.pyi` or `__init__.py` or it isn't a package.
let kind = if package_path.is_directory(&resolver_state) {
let kind = if package_path.is_directory(search_path, &resolver_state) {
package_path.push("__init__");
ModuleKind::Package
} else {
@@ -523,13 +470,16 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, File, Mod
};
// TODO Implement full https://peps.python.org/pep-0561/#type-checker-module-resolution-order resolution
if let Some(stub) = package_path.with_pyi_extension().to_file(&resolver_state) {
if let Some(stub) = package_path
.with_pyi_extension()
.to_file(search_path, &resolver_state)
{
return Some((search_path.clone(), stub, kind));
}
if let Some(module) = package_path
.with_py_extension()
.and_then(|path| path.to_file(&resolver_state))
.and_then(|path| path.to_file(search_path, &resolver_state))
{
return Some((search_path.clone(), module, kind));
}
@@ -553,14 +503,14 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, File, Mod
}
fn resolve_package<'a, 'db, I>(
module_search_path: &SearchPath,
module_search_path: &ModuleResolutionPathBuf,
components: I,
resolver_state: &ResolverState<'db>,
) -> Result<ResolvedPackage, PackageKind>
where
I: Iterator<Item = &'a str>,
{
let mut package_path = module_search_path.to_module_path();
let mut package_path = module_search_path.clone();
// `true` if inside a folder that is a namespace package (has no `__init__.py`).
// Namespace packages are special because they can be spread across multiple search paths.
@@ -574,11 +524,12 @@ where
for folder in components {
package_path.push(folder);
let is_regular_package = package_path.is_regular_package(resolver_state);
let is_regular_package =
package_path.is_regular_package(module_search_path, resolver_state);
if is_regular_package {
in_namespace_package = false;
} else if package_path.is_directory(resolver_state) {
} else if package_path.is_directory(module_search_path, resolver_state) {
// A directory without an `__init__.py` is a namespace package, continue with the next folder.
in_namespace_package = true;
} else if in_namespace_package {
@@ -611,7 +562,7 @@ where
#[derive(Debug)]
struct ResolvedPackage {
path: ModulePath,
path: ModuleResolutionPathBuf,
kind: PackageKind,
}
@@ -639,11 +590,10 @@ impl PackageKind {
#[cfg(test)]
mod tests {
use internal::ModuleNameIngredient;
use ruff_db::files::{system_path_to_file, File, FilePath};
use ruff_db::system::DbWithTestSystem;
use ruff_db::testing::{
assert_const_function_query_was_not_run, assert_function_query_was_not_run,
};
use ruff_db::system::{DbWithTestSystem, OsSystem, SystemPath};
use ruff_db::testing::assert_function_query_was_not_run;
use ruff_db::Db;
use crate::db::tests::TestDb;
@@ -668,7 +618,7 @@ mod tests {
);
assert_eq!("foo", foo_module.name());
assert_eq!(&src, foo_module.search_path());
assert_eq!(&src, &foo_module.search_path());
assert_eq!(ModuleKind::Module, foo_module.kind());
let expected_foo_path = src.join("foo.py");
@@ -679,40 +629,6 @@ mod tests {
);
}
#[test]
fn builtins_vendored() {
let TestCase { db, stdlib, .. } = TestCaseBuilder::new()
.with_vendored_typeshed()
.with_src_files(&[("builtins.py", "FOOOO = 42")])
.build();
let builtins_module_name = ModuleName::new_static("builtins").unwrap();
let builtins = resolve_module(&db, builtins_module_name).expect("builtins to resolve");
assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
}
#[test]
fn builtins_custom() {
const TYPESHED: MockedTypeshed = MockedTypeshed {
stdlib_files: &[("builtins.pyi", "def min(a, b): ...")],
versions: "builtins: 3.8-",
};
const SRC: &[FileSpec] = &[("builtins.py", "FOOOO = 42")];
let TestCase { db, stdlib, .. } = TestCaseBuilder::new()
.with_src_files(SRC)
.with_custom_typeshed(TYPESHED)
.with_target_version(TargetVersion::Py38)
.build();
let builtins_module_name = ModuleName::new_static("builtins").unwrap();
let builtins = resolve_module(&db, builtins_module_name).expect("builtins to resolve");
assert_eq!(builtins.file().path(&db), &stdlib.join("builtins.pyi"));
}
#[test]
fn stdlib() {
const TYPESHED: MockedTypeshed = MockedTypeshed {
@@ -733,7 +649,7 @@ mod tests {
resolve_module(&db, functools_module_name).as_ref()
);
assert_eq!(&stdlib, functools_module.search_path());
assert_eq!(&stdlib, &functools_module.search_path().to_path_buf());
assert_eq!(ModuleKind::Module, functools_module.kind());
let expected_functools_path = stdlib.join("functools.pyi");
@@ -785,7 +701,7 @@ mod tests {
});
let search_path = resolved_module.search_path();
assert_eq!(
&stdlib, search_path,
&stdlib, &search_path,
"Search path for {module_name} was unexpectedly {search_path:?}"
);
assert!(
@@ -881,7 +797,7 @@ mod tests {
});
let search_path = resolved_module.search_path();
assert_eq!(
&stdlib, search_path,
&stdlib, &search_path,
"Search path for {module_name} was unexpectedly {search_path:?}"
);
assert!(
@@ -940,7 +856,7 @@ mod tests {
Some(&functools_module),
resolve_module(&db, functools_module_name).as_ref()
);
assert_eq!(&src, functools_module.search_path());
assert_eq!(&src, &functools_module.search_path());
assert_eq!(ModuleKind::Module, functools_module.kind());
assert_eq!(&src.join("functools.py"), functools_module.file().path(&db));
@@ -961,7 +877,7 @@ mod tests {
let pydoc_data_topics = resolve_module(&db, pydoc_data_topics_name).unwrap();
assert_eq!("pydoc_data.topics", pydoc_data_topics.name());
assert_eq!(pydoc_data_topics.search_path(), &stdlib);
assert_eq!(pydoc_data_topics.search_path(), stdlib);
assert_eq!(
pydoc_data_topics.file().path(&db),
&stdlib.join("pydoc_data/topics.pyi")
@@ -978,7 +894,7 @@ mod tests {
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
assert_eq!("foo", foo_module.name());
assert_eq!(&src, foo_module.search_path());
assert_eq!(&src, &foo_module.search_path());
assert_eq!(&foo_path, foo_module.file().path(&db));
assert_eq!(
@@ -1005,7 +921,7 @@ mod tests {
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_init_path = src.join("foo/__init__.py");
assert_eq!(&src, foo_module.search_path());
assert_eq!(&src, &foo_module.search_path());
assert_eq!(&foo_init_path, foo_module.file().path(&db));
assert_eq!(ModuleKind::Package, foo_module.kind());
@@ -1028,7 +944,7 @@ mod tests {
let foo = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_stub = src.join("foo.pyi");
assert_eq!(&src, foo.search_path());
assert_eq!(&src, &foo.search_path());
assert_eq!(&foo_stub, foo.file().path(&db));
assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
@@ -1052,7 +968,7 @@ mod tests {
resolve_module(&db, ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
let baz_path = src.join("foo/bar/baz.py");
assert_eq!(&src, baz_module.search_path());
assert_eq!(&src, &baz_module.search_path());
assert_eq!(&baz_path, baz_module.file().path(&db));
assert_eq!(
@@ -1152,7 +1068,7 @@ mod tests {
let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap();
let foo_src_path = src.join("foo.py");
assert_eq!(&src, foo_module.search_path());
assert_eq!(&src, &foo_module.search_path());
assert_eq!(&foo_src_path, foo_module.file().path(&db));
assert_eq!(
Some(foo_module),
@@ -1168,9 +1084,7 @@ mod tests {
#[test]
#[cfg(target_family = "unix")]
fn symlink() -> anyhow::Result<()> {
use crate::db::tests::TestDb;
use ruff_db::program::Program;
use ruff_db::system::{OsSystem, SystemPath};
let mut db = TestDb::new();
@@ -1187,8 +1101,7 @@ mod tests {
std::fs::create_dir_all(src.as_std_path())?;
std::fs::create_dir_all(site_packages.as_std_path())?;
std::fs::create_dir_all(custom_typeshed.join("stdlib").as_std_path())?;
std::fs::File::create(custom_typeshed.join("stdlib/VERSIONS").as_std_path())?;
std::fs::create_dir_all(custom_typeshed.as_std_path())?;
std::fs::write(foo.as_std_path(), "")?;
std::os::unix::fs::symlink(foo.as_std_path(), bar.as_std_path())?;
@@ -1197,7 +1110,7 @@ mod tests {
extra_paths: vec![],
workspace_root: src.clone(),
custom_typeshed: Some(custom_typeshed.clone()),
site_packages: vec![site_packages],
site_packages: Some(site_packages.clone()),
};
Program::new(&db, TargetVersion::Py38, search_paths);
@@ -1207,12 +1120,12 @@ mod tests {
assert_ne!(foo_module, bar_module);
assert_eq!(&src, foo_module.search_path());
assert_eq!(&src, &foo_module.search_path());
assert_eq!(&foo, foo_module.file().path(&db));
// `foo` and `bar` shouldn't resolve to the same file
assert_eq!(&src, bar_module.search_path());
assert_eq!(&src, &bar_module.search_path());
assert_eq!(&bar, bar_module.file().path(&db));
assert_eq!(&foo, foo_module.file().path(&db));
@@ -1247,7 +1160,7 @@ mod tests {
// Delete `bar.py`
db.memory_file_system().remove_file(&bar_path).unwrap();
bar.sync(&mut db);
bar.touch(&mut db);
// Re-query the foo module. The foo module should still be cached because `bar.py` isn't relevant
// for resolving `foo`.
@@ -1299,8 +1212,7 @@ mod tests {
db.memory_file_system().remove_file(&foo_init_path)?;
db.memory_file_system()
.remove_directory(foo_init_path.parent().unwrap())?;
File::sync_path(&mut db, &foo_init_path);
File::sync_path(&mut db, foo_init_path.parent().unwrap());
File::touch_path(&mut db, &foo_init_path);
let foo_module = resolve_module(&db, foo_module_name).expect("Foo module to resolve");
assert_eq!(&src.join("foo.py"), foo_module.file().path(&db));
@@ -1329,9 +1241,9 @@ mod tests {
let stdlib_functools_path = stdlib.join("functools.pyi");
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(functools_module.search_path(), stdlib);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, &stdlib_functools_path)
);
@@ -1343,15 +1255,15 @@ mod tests {
.unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
let events = db.take_salsa_events();
assert_function_query_was_not_run(
assert_function_query_was_not_run::<resolve_module_query, _, _>(
&db,
resolve_module_query,
ModuleNameIngredient::new(&db, functools_module_name.clone()),
|res| &res.function,
&ModuleNameIngredient::new(&db, functools_module_name.clone()),
&events,
);
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(functools_module.search_path(), stdlib);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, &stdlib_functools_path)
);
}
@@ -1375,9 +1287,9 @@ mod tests {
let functools_module_name = ModuleName::new_static("functools").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(functools_module.search_path(), stdlib);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, stdlib.join("functools.pyi"))
);
@@ -1386,9 +1298,9 @@ mod tests {
let src_functools_path = src.join("functools.py");
db.write_file(&src_functools_path, "FOO: int").unwrap();
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
assert_eq!(functools_module.search_path(), &src);
assert_eq!(functools_module.search_path(), src);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, &src_functools_path)
);
}
@@ -1417,9 +1329,9 @@ mod tests {
let src_functools_path = src.join("functools.py");
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
assert_eq!(functools_module.search_path(), &src);
assert_eq!(functools_module.search_path(), src);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, &src_functools_path)
);
@@ -1428,11 +1340,11 @@ mod tests {
db.memory_file_system()
.remove_file(&src_functools_path)
.unwrap();
File::sync_path(&mut db, &src_functools_path);
File::touch_path(&mut db, &src_functools_path);
let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap();
assert_eq!(functools_module.search_path(), &stdlib);
assert_eq!(functools_module.search_path(), stdlib);
assert_eq!(
Ok(functools_module.file()),
Some(functools_module.file()),
system_path_to_file(&db, stdlib.join("functools.pyi"))
);
}
@@ -1595,7 +1507,12 @@ not_a_directory
&FilePath::system("/y/src/bar.py")
);
let events = db.take_salsa_events();
assert_const_function_query_was_not_run(&db, dynamic_resolution_paths, &events);
assert_function_query_was_not_run::<editable_install_resolution_paths, _, _>(
&db,
|res| &res.function,
&(),
&events,
);
}
#[test]
@@ -1624,7 +1541,18 @@ not_a_directory
.remove_file(site_packages.join("_foo.pth"))
.unwrap();
File::sync_path(&mut db, &site_packages.join("_foo.pth"));
// Why are we touching a random file in the path that's been editably installed,
// rather than the `.pth` file, when the `.pth` file is the one that has been deleted?
// It's because the `.pth` file isn't directly tracked as a dependency by Salsa
// currently (we don't use `system_path_to_file()` to get the file, and we don't use
// `source_text()` to read the source of the file). Instead of using these APIs which
// would automatically add the existence and contents of the file as a Salsa-tracked
// dependency, we use `.report_untracked_read()` to force Salsa to re-parse all
// `.pth` files on each new "revision". Making a random modification to a tracked
// Salsa file forces a new revision.
//
// TODO: get rid of the `.report_untracked_read()` call...
File::touch_path(&mut db, SystemPath::new("/x/src/foo.py"));
assert_eq!(resolve_module(&db, foo_module_name.clone()), None);
}
@@ -1652,8 +1580,8 @@ not_a_directory
.remove_file(src_path.join("foo.py"))
.unwrap();
db.memory_file_system().remove_directory(&src_path).unwrap();
File::sync_path(&mut db, &src_path.join("foo.py"));
File::sync_path(&mut db, &src_path);
File::touch_path(&mut db, &src_path.join("foo.py"));
File::touch_path(&mut db, &src_path);
assert_eq!(resolve_module(&db, foo_module_name.clone()), None);
}
@@ -1664,62 +1592,39 @@ not_a_directory
.with_site_packages_files(&[("_foo.pth", "/src")])
.build();
let search_paths: Vec<&SearchPath> =
let search_paths: Vec<&SearchPathRoot> =
module_resolution_settings(&db).search_paths(&db).collect();
assert!(search_paths.contains(
&&SearchPath::first_party(db.system(), SystemPathBuf::from("/src")).unwrap()
));
assert!(!search_paths
.contains(&&SearchPath::editable(db.system(), SystemPathBuf::from("/src")).unwrap()));
assert!(search_paths.contains(&&Arc::new(
ModuleResolutionPathBuf::first_party("/src").unwrap()
)));
assert!(!search_paths.contains(&&Arc::new(
ModuleResolutionPathBuf::editable_installation_root(db.system(), "/src").unwrap()
)));
}
#[test]
fn multiple_site_packages_with_editables() {
let mut db = TestDb::new();
fn no_duplicate_editable_search_paths_added() {
let TestCase { mut db, .. } = TestCaseBuilder::new()
.with_site_packages_files(&[("_foo.pth", "/x"), ("_bar.pth", "/x")])
.build();
let venv_site_packages = SystemPathBuf::from("/venv-site-packages");
let site_packages_pth = venv_site_packages.join("foo.pth");
let system_site_packages = SystemPathBuf::from("/system-site-packages");
let editable_install_location = SystemPathBuf::from("/x/y/a.py");
let system_site_packages_location = system_site_packages.join("a.py");
db.write_file("/x/foo.py", "").unwrap();
db.memory_file_system()
.create_directory_all("/src")
.unwrap();
db.write_files([
(&site_packages_pth, "/x/y"),
(&editable_install_location, ""),
(&system_site_packages_location, ""),
])
.unwrap();
let search_paths: Vec<&SearchPathRoot> =
module_resolution_settings(&db).search_paths(&db).collect();
Program::new(
&db,
TargetVersion::default(),
SearchPathSettings {
extra_paths: vec![],
workspace_root: SystemPathBuf::from("/src"),
custom_typeshed: None,
site_packages: vec![venv_site_packages, system_site_packages],
},
let editable_install =
ModuleResolutionPathBuf::editable_installation_root(db.system(), "/x").unwrap();
assert_eq!(
search_paths
.iter()
.filter(|path| ****path == editable_install)
.count(),
1,
"Unexpected search paths: {search_paths:?}"
);
// The editable installs discovered from the `.pth` file in the first `site-packages` directory
// take precedence over the second `site-packages` directory...
let a_module_name = ModuleName::new_static("a").unwrap();
let a_module = resolve_module(&db, a_module_name.clone()).unwrap();
assert_eq!(a_module.file().path(&db), &editable_install_location);
db.memory_file_system()
.remove_file(&site_packages_pth)
.unwrap();
File::sync_path(&mut db, &site_packages_pth);
// ...But now that the `.pth` file in the first `site-packages` directory has been deleted,
// the editable install no longer exists, so the module now resolves to the file in the
// second `site-packages` directory
let a_module = resolve_module(&db, a_module_name).unwrap();
assert_eq!(a_module.file().path(&db), &system_site_packages_location);
}
}

View File

@@ -1,4 +1,5 @@
use ruff_db::program::TargetVersion;
use ruff_db::system::System;
use ruff_db::vendored::VendoredFileSystem;
use crate::db::Db;
@@ -19,6 +20,10 @@ impl<'db> ResolverState<'db> {
}
}
pub(crate) fn system(&self) -> &dyn System {
self.db.system()
}
pub(crate) fn vendored(&self) -> &VendoredFileSystem {
self.db.vendored()
}

View File

@@ -12,9 +12,6 @@ pub(crate) struct TestCase<T> {
pub(crate) db: TestDb,
pub(crate) src: SystemPathBuf,
pub(crate) stdlib: T,
// Most test cases only ever need a single `site-packages` directory,
// so this is a single directory instead of a `Vec` of directories,
// like it is in `ruff_db::Program`.
pub(crate) site_packages: SystemPathBuf,
pub(crate) target_version: TargetVersion,
}
@@ -128,8 +125,6 @@ impl<T> TestCaseBuilder<T> {
files: impl IntoIterator<Item = FileSpec>,
) -> SystemPathBuf {
let root = location.as_ref().to_path_buf();
// Make sure to create the directory even if the list of files is empty:
db.memory_file_system().create_directory_all(&root).unwrap();
db.write_files(
files
.into_iter()
@@ -226,7 +221,7 @@ impl TestCaseBuilder<MockedTypeshed> {
extra_paths: vec![],
workspace_root: src.clone(),
custom_typeshed: Some(typeshed.clone()),
site_packages: vec![site_packages.clone()],
site_packages: Some(site_packages.clone()),
},
);
@@ -279,7 +274,7 @@ impl TestCaseBuilder<VendoredTypeshed> {
extra_paths: vec![],
workspace_root: src.clone(),
custom_typeshed: None,
site_packages: vec![site_packages.clone()],
site_packages: Some(site_packages.clone()),
},
);

View File

@@ -52,7 +52,7 @@ impl<'db> LazyTypeshedVersions<'db> {
} else {
return &VENDORED_VERSIONS;
};
let Ok(versions_file) = system_path_to_file(db.upcast(), &versions_path) else {
let Some(versions_file) = system_path_to_file(db.upcast(), &versions_path) else {
todo!(
"Still need to figure out how to handle VERSIONS files being deleted \
from custom typeshed directories! Expected a file to exist at {versions_path}"

View File

@@ -1 +1 @@
4ef2d66663fc080fefa379e6ae5fc45d4f8b54eb
f863db6bc5242348ceaa6a3bca4e59aa9e62faaa

View File

@@ -1,18 +1,18 @@
import sys
from _typeshed import SupportsWrite
from collections.abc import Iterable, Iterator
from typing import Any, Final
from typing import Any, Final, Literal
from typing_extensions import TypeAlias
__version__: Final[str]
QUOTE_ALL: Final = 1
QUOTE_MINIMAL: Final = 0
QUOTE_NONE: Final = 3
QUOTE_NONNUMERIC: Final = 2
QUOTE_ALL: Literal[1]
QUOTE_MINIMAL: Literal[0]
QUOTE_NONE: Literal[3]
QUOTE_NONNUMERIC: Literal[2]
if sys.version_info >= (3, 12):
QUOTE_STRINGS: Final = 4
QUOTE_NOTNULL: Final = 5
QUOTE_STRINGS: Literal[4]
QUOTE_NOTNULL: Literal[5]
# Ideally this would be `QUOTE_ALL | QUOTE_MINIMAL | QUOTE_NONE | QUOTE_NONNUMERIC`
# However, using literals in situations like these can cause false-positives (see #7258)

View File

@@ -71,7 +71,7 @@ class _CData(metaclass=_CDataMeta):
@classmethod
def from_address(cls, address: int) -> Self: ...
@classmethod
def from_param(cls, value: Any, /) -> Self | _CArgObject: ...
def from_param(cls, obj: Any) -> Self | _CArgObject: ...
@classmethod
def in_dll(cls, library: CDLL, name: str) -> Self: ...
def __buffer__(self, flags: int, /) -> memoryview: ...

View File

@@ -368,7 +368,11 @@ def tparm(
) -> bytes: ...
def typeahead(fd: int, /) -> None: ...
def unctrl(ch: _ChType, /) -> bytes: ...
def unget_wch(ch: int | str, /) -> None: ...
if sys.version_info < (3, 12) or sys.platform != "darwin":
# The support for macos was dropped in 3.12
def unget_wch(ch: int | str, /) -> None: ...
def ungetch(ch: _ChType, /) -> None: ...
def ungetmouse(id: int, x: int, y: int, z: int, bstate: int, /) -> None: ...
def update_lines_cols() -> None: ...
@@ -443,10 +447,13 @@ class _CursesWindow:
def getch(self) -> int: ...
@overload
def getch(self, y: int, x: int) -> int: ...
@overload
def get_wch(self) -> int | str: ...
@overload
def get_wch(self, y: int, x: int) -> int | str: ...
if sys.version_info < (3, 12) or sys.platform != "darwin":
# The support for macos was dropped in 3.12
@overload
def get_wch(self) -> int | str: ...
@overload
def get_wch(self, y: int, x: int) -> int | str: ...
@overload
def getkey(self) -> str: ...
@overload

View File

@@ -17,20 +17,20 @@ class DecimalTuple(NamedTuple):
digits: tuple[int, ...]
exponent: int | Literal["n", "N", "F"]
ROUND_DOWN: Final[str]
ROUND_HALF_UP: Final[str]
ROUND_HALF_EVEN: Final[str]
ROUND_CEILING: Final[str]
ROUND_FLOOR: Final[str]
ROUND_UP: Final[str]
ROUND_HALF_DOWN: Final[str]
ROUND_05UP: Final[str]
HAVE_CONTEXTVAR: Final[bool]
HAVE_THREADS: Final[bool]
MAX_EMAX: Final[int]
MAX_PREC: Final[int]
MIN_EMIN: Final[int]
MIN_ETINY: Final[int]
ROUND_DOWN: str
ROUND_HALF_UP: str
ROUND_HALF_EVEN: str
ROUND_CEILING: str
ROUND_FLOOR: str
ROUND_UP: str
ROUND_HALF_DOWN: str
ROUND_05UP: str
HAVE_CONTEXTVAR: bool
HAVE_THREADS: bool
MAX_EMAX: int
MAX_PREC: int
MIN_EMIN: int
MIN_ETINY: int
class DecimalException(ArithmeticError): ...
class Clamped(DecimalException): ...

View File

@@ -1,5 +1,5 @@
from _typeshed import structseq
from typing import Any, Final, Literal, SupportsIndex, final
from typing import Final, Literal, SupportsIndex, final
from typing_extensions import Buffer, Self
class ChannelError(RuntimeError): ...
@@ -72,15 +72,13 @@ class ChannelInfo(structseq[int], tuple[bool, bool, bool, int, int, int, int, in
@property
def send_released(self) -> bool: ...
def create(unboundop: Literal[1, 2, 3]) -> ChannelID: ...
def create() -> ChannelID: ...
def destroy(cid: SupportsIndex) -> None: ...
def list_all() -> list[ChannelID]: ...
def list_interpreters(cid: SupportsIndex, *, send: bool) -> list[int]: ...
def send(cid: SupportsIndex, obj: object, *, blocking: bool = True, timeout: float | None = None) -> None: ...
def send_buffer(cid: SupportsIndex, obj: Buffer, *, blocking: bool = True, timeout: float | None = None) -> None: ...
def recv(cid: SupportsIndex, default: object = ...) -> tuple[Any, Literal[1, 2, 3]]: ...
def recv(cid: SupportsIndex, default: object = ...) -> object: ...
def close(cid: SupportsIndex, *, send: bool = False, recv: bool = False) -> None: ...
def get_count(cid: SupportsIndex) -> int: ...
def get_info(cid: SupportsIndex) -> ChannelInfo: ...
def get_channel_defaults(cid: SupportsIndex) -> Literal[1, 2, 3]: ...
def release(cid: SupportsIndex, *, send: bool = False, recv: bool = False, force: bool = False) -> None: ...

View File

@@ -1,5 +1,5 @@
from collections.abc import Iterable, Sequence
from typing import Final, TypeVar
from typing import TypeVar
_T = TypeVar("_T")
_K = TypeVar("_K")
@@ -7,15 +7,15 @@ _V = TypeVar("_V")
__all__ = ["compiler_fixup", "customize_config_vars", "customize_compiler", "get_platform_osx"]
_UNIVERSAL_CONFIG_VARS: Final[tuple[str, ...]] # undocumented
_COMPILER_CONFIG_VARS: Final[tuple[str, ...]] # undocumented
_INITPRE: Final[str] # undocumented
_UNIVERSAL_CONFIG_VARS: tuple[str, ...] # undocumented
_COMPILER_CONFIG_VARS: tuple[str, ...] # undocumented
_INITPRE: str # undocumented
def _find_executable(executable: str, path: str | None = None) -> str | None: ... # undocumented
def _read_output(commandstring: str, capture_stderr: bool = False) -> str | None: ... # undocumented
def _find_build_tool(toolname: str) -> str: ... # undocumented
_SYSTEM_VERSION: Final[str | None] # undocumented
_SYSTEM_VERSION: str | None # undocumented
def _get_system_version() -> str: ... # undocumented
def _remove_original_values(_config_vars: dict[str, str]) -> None: ... # undocumented

View File

@@ -1,30 +1,30 @@
import sys
from typing import Final
from typing import Literal
SF_APPEND: Final = 0x00040000
SF_ARCHIVED: Final = 0x00010000
SF_IMMUTABLE: Final = 0x00020000
SF_NOUNLINK: Final = 0x00100000
SF_SNAPSHOT: Final = 0x00200000
SF_APPEND: Literal[0x00040000]
SF_ARCHIVED: Literal[0x00010000]
SF_IMMUTABLE: Literal[0x00020000]
SF_NOUNLINK: Literal[0x00100000]
SF_SNAPSHOT: Literal[0x00200000]
ST_MODE: Final = 0
ST_INO: Final = 1
ST_DEV: Final = 2
ST_NLINK: Final = 3
ST_UID: Final = 4
ST_GID: Final = 5
ST_SIZE: Final = 6
ST_ATIME: Final = 7
ST_MTIME: Final = 8
ST_CTIME: Final = 9
ST_MODE: Literal[0]
ST_INO: Literal[1]
ST_DEV: Literal[2]
ST_NLINK: Literal[3]
ST_UID: Literal[4]
ST_GID: Literal[5]
ST_SIZE: Literal[6]
ST_ATIME: Literal[7]
ST_MTIME: Literal[8]
ST_CTIME: Literal[9]
S_IFIFO: Final = 0o010000
S_IFLNK: Final = 0o120000
S_IFREG: Final = 0o100000
S_IFSOCK: Final = 0o140000
S_IFBLK: Final = 0o060000
S_IFCHR: Final = 0o020000
S_IFDIR: Final = 0o040000
S_IFIFO: Literal[0o010000]
S_IFLNK: Literal[0o120000]
S_IFREG: Literal[0o100000]
S_IFSOCK: Literal[0o140000]
S_IFBLK: Literal[0o060000]
S_IFCHR: Literal[0o020000]
S_IFDIR: Literal[0o040000]
# These are 0 on systems that don't support the specific kind of file.
# Example: Linux doesn't support door files, so S_IFDOOR is 0 on linux.
@@ -32,37 +32,37 @@ S_IFDOOR: int
S_IFPORT: int
S_IFWHT: int
S_ISUID: Final = 0o4000
S_ISGID: Final = 0o2000
S_ISVTX: Final = 0o1000
S_ISUID: Literal[0o4000]
S_ISGID: Literal[0o2000]
S_ISVTX: Literal[0o1000]
S_IRWXU: Final = 0o0700
S_IRUSR: Final = 0o0400
S_IWUSR: Final = 0o0200
S_IXUSR: Final = 0o0100
S_IRWXU: Literal[0o0700]
S_IRUSR: Literal[0o0400]
S_IWUSR: Literal[0o0200]
S_IXUSR: Literal[0o0100]
S_IRWXG: Final = 0o0070
S_IRGRP: Final = 0o0040
S_IWGRP: Final = 0o0020
S_IXGRP: Final = 0o0010
S_IRWXG: Literal[0o0070]
S_IRGRP: Literal[0o0040]
S_IWGRP: Literal[0o0020]
S_IXGRP: Literal[0o0010]
S_IRWXO: Final = 0o0007
S_IROTH: Final = 0o0004
S_IWOTH: Final = 0o0002
S_IXOTH: Final = 0o0001
S_IRWXO: Literal[0o0007]
S_IROTH: Literal[0o0004]
S_IWOTH: Literal[0o0002]
S_IXOTH: Literal[0o0001]
S_ENFMT: Final = 0o2000
S_IREAD: Final = 0o0400
S_IWRITE: Final = 0o0200
S_IEXEC: Final = 0o0100
S_ENFMT: Literal[0o2000]
S_IREAD: Literal[0o0400]
S_IWRITE: Literal[0o0200]
S_IEXEC: Literal[0o0100]
UF_APPEND: Final = 0x00000004
UF_COMPRESSED: Final = 0x00000020 # OS X 10.6+ only
UF_HIDDEN: Final = 0x00008000 # OX X 10.5+ only
UF_IMMUTABLE: Final = 0x00000002
UF_NODUMP: Final = 0x00000001
UF_NOUNLINK: Final = 0x00000010
UF_OPAQUE: Final = 0x00000008
UF_APPEND: Literal[0x00000004]
UF_COMPRESSED: Literal[0x00000020] # OS X 10.6+ only
UF_HIDDEN: Literal[0x00008000] # OX X 10.5+ only
UF_IMMUTABLE: Literal[0x00000002]
UF_NODUMP: Literal[0x00000001]
UF_NOUNLINK: Literal[0x00000010]
UF_OPAQUE: Literal[0x00000008]
def S_IMODE(mode: int, /) -> int: ...
def S_IFMT(mode: int, /) -> int: ...
@@ -84,36 +84,34 @@ if sys.platform == "win32":
IO_REPARSE_TAG_APPEXECLINK: int
if sys.platform == "win32":
FILE_ATTRIBUTE_ARCHIVE: Final = 32
FILE_ATTRIBUTE_COMPRESSED: Final = 2048
FILE_ATTRIBUTE_DEVICE: Final = 64
FILE_ATTRIBUTE_DIRECTORY: Final = 16
FILE_ATTRIBUTE_ENCRYPTED: Final = 16384
FILE_ATTRIBUTE_HIDDEN: Final = 2
FILE_ATTRIBUTE_INTEGRITY_STREAM: Final = 32768
FILE_ATTRIBUTE_NORMAL: Final = 128
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: Final = 8192
FILE_ATTRIBUTE_NO_SCRUB_DATA: Final = 131072
FILE_ATTRIBUTE_OFFLINE: Final = 4096
FILE_ATTRIBUTE_READONLY: Final = 1
FILE_ATTRIBUTE_REPARSE_POINT: Final = 1024
FILE_ATTRIBUTE_SPARSE_FILE: Final = 512
FILE_ATTRIBUTE_SYSTEM: Final = 4
FILE_ATTRIBUTE_TEMPORARY: Final = 256
FILE_ATTRIBUTE_VIRTUAL: Final = 65536
FILE_ATTRIBUTE_ARCHIVE: Literal[32]
FILE_ATTRIBUTE_COMPRESSED: Literal[2048]
FILE_ATTRIBUTE_DEVICE: Literal[64]
FILE_ATTRIBUTE_DIRECTORY: Literal[16]
FILE_ATTRIBUTE_ENCRYPTED: Literal[16384]
FILE_ATTRIBUTE_HIDDEN: Literal[2]
FILE_ATTRIBUTE_INTEGRITY_STREAM: Literal[32768]
FILE_ATTRIBUTE_NORMAL: Literal[128]
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: Literal[8192]
FILE_ATTRIBUTE_NO_SCRUB_DATA: Literal[131072]
FILE_ATTRIBUTE_OFFLINE: Literal[4096]
FILE_ATTRIBUTE_READONLY: Literal[1]
FILE_ATTRIBUTE_REPARSE_POINT: Literal[1024]
FILE_ATTRIBUTE_SPARSE_FILE: Literal[512]
FILE_ATTRIBUTE_SYSTEM: Literal[4]
FILE_ATTRIBUTE_TEMPORARY: Literal[256]
FILE_ATTRIBUTE_VIRTUAL: Literal[65536]
if sys.version_info >= (3, 13):
# Varies by platform.
SF_SETTABLE: Final[int]
SF_SETTABLE: Literal[0x3FFF0000]
# https://github.com/python/cpython/issues/114081#issuecomment-2119017790
# SF_RESTRICTED: Literal[0x00080000]
SF_FIRMLINK: Final = 0x00800000
SF_DATALESS: Final = 0x40000000
SF_FIRMLINK: Literal[0x00800000]
SF_DATALESS: Literal[0x40000000]
if sys.platform == "darwin":
SF_SUPPORTED: Final = 0x9F0000
SF_SYNTHETIC: Final = 0xC0000000
SF_SUPPORTED: Literal[0x9F0000]
SF_SYNTHETIC: Literal[0xC0000000]
UF_TRACKED: Final = 0x00000040
UF_DATAVAULT: Final = 0x00000080
UF_SETTABLE: Final = 0x0000FFFF
UF_TRACKED: Literal[0x00000040]
UF_DATAVAULT: Literal[0x00000080]
UF_SETTABLE: Literal[0x0000FFFF]

View File

@@ -1,6 +1,6 @@
import sys
from collections.abc import Callable
from typing import Any, ClassVar, Final, final
from typing import Any, ClassVar, Literal, final
from typing_extensions import TypeAlias
# _tkinter is meant to be only used internally by tkinter, but some tkinter
@@ -95,16 +95,16 @@ class TkappType:
def settrace(self, func: _TkinterTraceFunc | None, /) -> None: ...
# These should be kept in sync with tkinter.tix constants, except ALL_EVENTS which doesn't match TCL_ALL_EVENTS
ALL_EVENTS: Final = -3
FILE_EVENTS: Final = 8
IDLE_EVENTS: Final = 32
TIMER_EVENTS: Final = 16
WINDOW_EVENTS: Final = 4
ALL_EVENTS: Literal[-3]
FILE_EVENTS: Literal[8]
IDLE_EVENTS: Literal[32]
TIMER_EVENTS: Literal[16]
WINDOW_EVENTS: Literal[4]
DONT_WAIT: Final = 2
EXCEPTION: Final = 8
READABLE: Final = 2
WRITABLE: Final = 4
DONT_WAIT: Literal[2]
EXCEPTION: Literal[8]
READABLE: Literal[2]
WRITABLE: Literal[4]
TCL_VERSION: str
TK_VERSION: str

View File

@@ -1,117 +1,117 @@
import sys
from _typeshed import ReadableBuffer
from collections.abc import Sequence
from typing import Any, Final, Literal, NoReturn, final, overload
from typing import Any, Literal, NoReturn, final, overload
if sys.platform == "win32":
ABOVE_NORMAL_PRIORITY_CLASS: Final = 0x8000
BELOW_NORMAL_PRIORITY_CLASS: Final = 0x4000
ABOVE_NORMAL_PRIORITY_CLASS: Literal[0x8000]
BELOW_NORMAL_PRIORITY_CLASS: Literal[0x4000]
CREATE_BREAKAWAY_FROM_JOB: Final = 0x1000000
CREATE_DEFAULT_ERROR_MODE: Final = 0x4000000
CREATE_NO_WINDOW: Final = 0x8000000
CREATE_NEW_CONSOLE: Final = 0x10
CREATE_NEW_PROCESS_GROUP: Final = 0x200
CREATE_BREAKAWAY_FROM_JOB: Literal[0x1000000]
CREATE_DEFAULT_ERROR_MODE: Literal[0x4000000]
CREATE_NO_WINDOW: Literal[0x8000000]
CREATE_NEW_CONSOLE: Literal[0x10]
CREATE_NEW_PROCESS_GROUP: Literal[0x200]
DETACHED_PROCESS: Final = 8
DUPLICATE_CLOSE_SOURCE: Final = 1
DUPLICATE_SAME_ACCESS: Final = 2
DETACHED_PROCESS: Literal[8]
DUPLICATE_CLOSE_SOURCE: Literal[1]
DUPLICATE_SAME_ACCESS: Literal[2]
ERROR_ALREADY_EXISTS: Final = 183
ERROR_BROKEN_PIPE: Final = 109
ERROR_IO_PENDING: Final = 997
ERROR_MORE_DATA: Final = 234
ERROR_NETNAME_DELETED: Final = 64
ERROR_NO_DATA: Final = 232
ERROR_NO_SYSTEM_RESOURCES: Final = 1450
ERROR_OPERATION_ABORTED: Final = 995
ERROR_PIPE_BUSY: Final = 231
ERROR_PIPE_CONNECTED: Final = 535
ERROR_SEM_TIMEOUT: Final = 121
ERROR_ALREADY_EXISTS: Literal[183]
ERROR_BROKEN_PIPE: Literal[109]
ERROR_IO_PENDING: Literal[997]
ERROR_MORE_DATA: Literal[234]
ERROR_NETNAME_DELETED: Literal[64]
ERROR_NO_DATA: Literal[232]
ERROR_NO_SYSTEM_RESOURCES: Literal[1450]
ERROR_OPERATION_ABORTED: Literal[995]
ERROR_PIPE_BUSY: Literal[231]
ERROR_PIPE_CONNECTED: Literal[535]
ERROR_SEM_TIMEOUT: Literal[121]
FILE_FLAG_FIRST_PIPE_INSTANCE: Final = 0x80000
FILE_FLAG_OVERLAPPED: Final = 0x40000000
FILE_FLAG_FIRST_PIPE_INSTANCE: Literal[0x80000]
FILE_FLAG_OVERLAPPED: Literal[0x40000000]
FILE_GENERIC_READ: Final = 1179785
FILE_GENERIC_WRITE: Final = 1179926
FILE_GENERIC_READ: Literal[1179785]
FILE_GENERIC_WRITE: Literal[1179926]
FILE_MAP_ALL_ACCESS: Final = 983071
FILE_MAP_COPY: Final = 1
FILE_MAP_EXECUTE: Final = 32
FILE_MAP_READ: Final = 4
FILE_MAP_WRITE: Final = 2
FILE_MAP_ALL_ACCESS: Literal[983071]
FILE_MAP_COPY: Literal[1]
FILE_MAP_EXECUTE: Literal[32]
FILE_MAP_READ: Literal[4]
FILE_MAP_WRITE: Literal[2]
FILE_TYPE_CHAR: Final = 2
FILE_TYPE_DISK: Final = 1
FILE_TYPE_PIPE: Final = 3
FILE_TYPE_REMOTE: Final = 32768
FILE_TYPE_UNKNOWN: Final = 0
FILE_TYPE_CHAR: Literal[2]
FILE_TYPE_DISK: Literal[1]
FILE_TYPE_PIPE: Literal[3]
FILE_TYPE_REMOTE: Literal[32768]
FILE_TYPE_UNKNOWN: Literal[0]
GENERIC_READ: Final = 0x80000000
GENERIC_WRITE: Final = 0x40000000
HIGH_PRIORITY_CLASS: Final = 0x80
INFINITE: Final = 0xFFFFFFFF
GENERIC_READ: Literal[0x80000000]
GENERIC_WRITE: Literal[0x40000000]
HIGH_PRIORITY_CLASS: Literal[0x80]
INFINITE: Literal[0xFFFFFFFF]
# Ignore the Flake8 error -- flake8-pyi assumes
# most numbers this long will be implementation details,
# but here we can see that it's a power of 2
INVALID_HANDLE_VALUE: Final = 0xFFFFFFFFFFFFFFFF # noqa: Y054
IDLE_PRIORITY_CLASS: Final = 0x40
NORMAL_PRIORITY_CLASS: Final = 0x20
REALTIME_PRIORITY_CLASS: Final = 0x100
NMPWAIT_WAIT_FOREVER: Final = 0xFFFFFFFF
INVALID_HANDLE_VALUE: Literal[0xFFFFFFFFFFFFFFFF] # noqa: Y054
IDLE_PRIORITY_CLASS: Literal[0x40]
NORMAL_PRIORITY_CLASS: Literal[0x20]
REALTIME_PRIORITY_CLASS: Literal[0x100]
NMPWAIT_WAIT_FOREVER: Literal[0xFFFFFFFF]
MEM_COMMIT: Final = 0x1000
MEM_FREE: Final = 0x10000
MEM_IMAGE: Final = 0x1000000
MEM_MAPPED: Final = 0x40000
MEM_PRIVATE: Final = 0x20000
MEM_RESERVE: Final = 0x2000
MEM_COMMIT: Literal[0x1000]
MEM_FREE: Literal[0x10000]
MEM_IMAGE: Literal[0x1000000]
MEM_MAPPED: Literal[0x40000]
MEM_PRIVATE: Literal[0x20000]
MEM_RESERVE: Literal[0x2000]
NULL: Final = 0
OPEN_EXISTING: Final = 3
NULL: Literal[0]
OPEN_EXISTING: Literal[3]
PIPE_ACCESS_DUPLEX: Final = 3
PIPE_ACCESS_INBOUND: Final = 1
PIPE_READMODE_MESSAGE: Final = 2
PIPE_TYPE_MESSAGE: Final = 4
PIPE_UNLIMITED_INSTANCES: Final = 255
PIPE_WAIT: Final = 0
PIPE_ACCESS_DUPLEX: Literal[3]
PIPE_ACCESS_INBOUND: Literal[1]
PIPE_READMODE_MESSAGE: Literal[2]
PIPE_TYPE_MESSAGE: Literal[4]
PIPE_UNLIMITED_INSTANCES: Literal[255]
PIPE_WAIT: Literal[0]
PAGE_EXECUTE: Final = 0x10
PAGE_EXECUTE_READ: Final = 0x20
PAGE_EXECUTE_READWRITE: Final = 0x40
PAGE_EXECUTE_WRITECOPY: Final = 0x80
PAGE_GUARD: Final = 0x100
PAGE_NOACCESS: Final = 0x1
PAGE_NOCACHE: Final = 0x200
PAGE_READONLY: Final = 0x2
PAGE_READWRITE: Final = 0x4
PAGE_WRITECOMBINE: Final = 0x400
PAGE_WRITECOPY: Final = 0x8
PAGE_EXECUTE: Literal[0x10]
PAGE_EXECUTE_READ: Literal[0x20]
PAGE_EXECUTE_READWRITE: Literal[0x40]
PAGE_EXECUTE_WRITECOPY: Literal[0x80]
PAGE_GUARD: Literal[0x100]
PAGE_NOACCESS: Literal[0x1]
PAGE_NOCACHE: Literal[0x200]
PAGE_READONLY: Literal[0x2]
PAGE_READWRITE: Literal[0x4]
PAGE_WRITECOMBINE: Literal[0x400]
PAGE_WRITECOPY: Literal[0x8]
PROCESS_ALL_ACCESS: Final = 0x1FFFFF
PROCESS_DUP_HANDLE: Final = 0x40
PROCESS_ALL_ACCESS: Literal[0x1FFFFF]
PROCESS_DUP_HANDLE: Literal[0x40]
SEC_COMMIT: Final = 0x8000000
SEC_IMAGE: Final = 0x1000000
SEC_LARGE_PAGES: Final = 0x80000000
SEC_NOCACHE: Final = 0x10000000
SEC_RESERVE: Final = 0x4000000
SEC_WRITECOMBINE: Final = 0x40000000
SEC_COMMIT: Literal[0x8000000]
SEC_IMAGE: Literal[0x1000000]
SEC_LARGE_PAGES: Literal[0x80000000]
SEC_NOCACHE: Literal[0x10000000]
SEC_RESERVE: Literal[0x4000000]
SEC_WRITECOMBINE: Literal[0x40000000]
STARTF_USESHOWWINDOW: Final = 0x1
STARTF_USESTDHANDLES: Final = 0x100
STARTF_USESHOWWINDOW: Literal[0x1]
STARTF_USESTDHANDLES: Literal[0x100]
STD_ERROR_HANDLE: Final = 0xFFFFFFF4
STD_OUTPUT_HANDLE: Final = 0xFFFFFFF5
STD_INPUT_HANDLE: Final = 0xFFFFFFF6
STD_ERROR_HANDLE: Literal[0xFFFFFFF4]
STD_OUTPUT_HANDLE: Literal[0xFFFFFFF5]
STD_INPUT_HANDLE: Literal[0xFFFFFFF6]
STILL_ACTIVE: Final = 259
SW_HIDE: Final = 0
SYNCHRONIZE: Final = 0x100000
WAIT_ABANDONED_0: Final = 128
WAIT_OBJECT_0: Final = 0
WAIT_TIMEOUT: Final = 258
STILL_ACTIVE: Literal[259]
SW_HIDE: Literal[0]
SYNCHRONIZE: Literal[0x100000]
WAIT_ABANDONED_0: Literal[128]
WAIT_OBJECT_0: Literal[0]
WAIT_TIMEOUT: Literal[258]
if sys.version_info >= (3, 10):
LOCALE_NAME_INVARIANT: str
@@ -131,32 +131,32 @@ if sys.platform == "win32":
LCMAP_UPPERCASE: int
if sys.version_info >= (3, 12):
COPYFILE2_CALLBACK_CHUNK_STARTED: Final = 1
COPYFILE2_CALLBACK_CHUNK_FINISHED: Final = 2
COPYFILE2_CALLBACK_STREAM_STARTED: Final = 3
COPYFILE2_CALLBACK_STREAM_FINISHED: Final = 4
COPYFILE2_CALLBACK_POLL_CONTINUE: Final = 5
COPYFILE2_CALLBACK_ERROR: Final = 6
COPYFILE2_CALLBACK_CHUNK_STARTED: Literal[1]
COPYFILE2_CALLBACK_CHUNK_FINISHED: Literal[2]
COPYFILE2_CALLBACK_STREAM_STARTED: Literal[3]
COPYFILE2_CALLBACK_STREAM_FINISHED: Literal[4]
COPYFILE2_CALLBACK_POLL_CONTINUE: Literal[5]
COPYFILE2_CALLBACK_ERROR: Literal[6]
COPYFILE2_PROGRESS_CONTINUE: Final = 0
COPYFILE2_PROGRESS_CANCEL: Final = 1
COPYFILE2_PROGRESS_STOP: Final = 2
COPYFILE2_PROGRESS_QUIET: Final = 3
COPYFILE2_PROGRESS_PAUSE: Final = 4
COPYFILE2_PROGRESS_CONTINUE: Literal[0]
COPYFILE2_PROGRESS_CANCEL: Literal[1]
COPYFILE2_PROGRESS_STOP: Literal[2]
COPYFILE2_PROGRESS_QUIET: Literal[3]
COPYFILE2_PROGRESS_PAUSE: Literal[4]
COPY_FILE_FAIL_IF_EXISTS: Final = 0x1
COPY_FILE_RESTARTABLE: Final = 0x2
COPY_FILE_OPEN_SOURCE_FOR_WRITE: Final = 0x4
COPY_FILE_ALLOW_DECRYPTED_DESTINATION: Final = 0x8
COPY_FILE_COPY_SYMLINK: Final = 0x800
COPY_FILE_NO_BUFFERING: Final = 0x1000
COPY_FILE_REQUEST_SECURITY_PRIVILEGES: Final = 0x2000
COPY_FILE_RESUME_FROM_PAUSE: Final = 0x4000
COPY_FILE_NO_OFFLOAD: Final = 0x40000
COPY_FILE_REQUEST_COMPRESSED_TRAFFIC: Final = 0x10000000
COPY_FILE_FAIL_IF_EXISTS: Literal[0x1]
COPY_FILE_RESTARTABLE: Literal[0x2]
COPY_FILE_OPEN_SOURCE_FOR_WRITE: Literal[0x4]
COPY_FILE_ALLOW_DECRYPTED_DESTINATION: Literal[0x8]
COPY_FILE_COPY_SYMLINK: Literal[0x800]
COPY_FILE_NO_BUFFERING: Literal[0x1000]
COPY_FILE_REQUEST_SECURITY_PRIVILEGES: Literal[0x2000]
COPY_FILE_RESUME_FROM_PAUSE: Literal[0x4000]
COPY_FILE_NO_OFFLOAD: Literal[0x40000]
COPY_FILE_REQUEST_COMPRESSED_TRAFFIC: Literal[0x10000000]
ERROR_ACCESS_DENIED: Final = 5
ERROR_PRIVILEGE_NOT_HELD: Final = 1314
ERROR_ACCESS_DENIED: Literal[5]
ERROR_PRIVILEGE_NOT_HELD: Literal[1314]
def CloseHandle(handle: int, /) -> None: ...
@overload

View File

@@ -2,7 +2,7 @@ import sys
from _typeshed import sentinel
from collections.abc import Callable, Generator, Iterable, Sequence
from re import Pattern
from typing import IO, Any, Final, Generic, NewType, NoReturn, Protocol, TypeVar, overload
from typing import IO, Any, Generic, Literal, NewType, NoReturn, Protocol, TypeVar, overload
from typing_extensions import Self, TypeAlias, deprecated
__all__ = [
@@ -43,15 +43,15 @@ _ActionStr: TypeAlias = str
# callers that don't use a literal argument
_NArgsStr: TypeAlias = str
ONE_OR_MORE: Final = "+"
OPTIONAL: Final = "?"
PARSER: Final = "A..."
REMAINDER: Final = "..."
ONE_OR_MORE: Literal["+"]
OPTIONAL: Literal["?"]
PARSER: Literal["A..."]
REMAINDER: Literal["..."]
_SUPPRESS_T = NewType("_SUPPRESS_T", str)
SUPPRESS: _SUPPRESS_T | str # not using Literal because argparse sometimes compares SUPPRESS with is
# the | str is there so that foo = argparse.SUPPRESS; foo = "test" checks out in mypy
ZERO_OR_MORE: Final = "*"
_UNRECOGNIZED_ARGS_ATTR: Final[str] # undocumented
ZERO_OR_MORE: Literal["*"]
_UNRECOGNIZED_ARGS_ATTR: str # undocumented
class ArgumentError(Exception):
argument_name: str | None

View File

@@ -1,6 +1,6 @@
from collections.abc import Callable, Sequence
from contextvars import Context
from typing import Any, Final
from typing import Any, Literal
from . import futures
@@ -11,9 +11,9 @@ __all__ = ()
# That's why the import order is reversed.
from .futures import isfuture as isfuture
_PENDING: Final = "PENDING" # undocumented
_CANCELLED: Final = "CANCELLED" # undocumented
_FINISHED: Final = "FINISHED" # undocumented
_PENDING: Literal["PENDING"] # undocumented
_CANCELLED: Literal["CANCELLED"] # undocumented
_FINISHED: Literal["FINISHED"] # undocumented
def _format_callbacks(cb: Sequence[tuple[Callable[[futures.Future[Any]], None], Context]]) -> str: ... # undocumented
def _future_repr_info(future: futures.Future[Any]) -> list[str]: ... # undocumented

View File

@@ -1,18 +1,18 @@
import enum
import sys
from typing import Final
from typing import Literal
LOG_THRESHOLD_FOR_CONNLOST_WRITES: Final = 5
ACCEPT_RETRY_DELAY: Final = 1
DEBUG_STACK_DEPTH: Final = 10
LOG_THRESHOLD_FOR_CONNLOST_WRITES: Literal[5]
ACCEPT_RETRY_DELAY: Literal[1]
DEBUG_STACK_DEPTH: Literal[10]
SSL_HANDSHAKE_TIMEOUT: float
SENDFILE_FALLBACK_READBUFFER_SIZE: Final = 262144
SENDFILE_FALLBACK_READBUFFER_SIZE: Literal[262144]
if sys.version_info >= (3, 11):
SSL_SHUTDOWN_TIMEOUT: float
FLOW_CONTROL_HIGH_WATER_SSL_READ: Final = 256
FLOW_CONTROL_HIGH_WATER_SSL_WRITE: Final = 512
FLOW_CONTROL_HIGH_WATER_SSL_READ: Literal[256]
FLOW_CONTROL_HIGH_WATER_SSL_WRITE: Literal[512]
if sys.version_info >= (3, 12):
THREAD_JOIN_TIMEOUT: Final = 300
THREAD_JOIN_TIMEOUT: Literal[300]
class _SendfileMode(enum.Enum):
UNSUPPORTED = 1

View File

@@ -3,7 +3,7 @@ import sys
from collections import deque
from collections.abc import Callable
from enum import Enum
from typing import Any, ClassVar, Final, Literal
from typing import Any, ClassVar, Literal
from typing_extensions import TypeAlias
from . import constants, events, futures, protocols, transports
@@ -29,10 +29,10 @@ if sys.version_info >= (3, 11):
def add_flowcontrol_defaults(high: int | None, low: int | None, kb: int) -> tuple[int, int]: ...
else:
_UNWRAPPED: Final = "UNWRAPPED"
_DO_HANDSHAKE: Final = "DO_HANDSHAKE"
_WRAPPED: Final = "WRAPPED"
_SHUTDOWN: Final = "SHUTDOWN"
_UNWRAPPED: Literal["UNWRAPPED"]
_DO_HANDSHAKE: Literal["DO_HANDSHAKE"]
_WRAPPED: Literal["WRAPPED"]
_SHUTDOWN: Literal["SHUTDOWN"]
if sys.version_info < (3, 11):
class _SSLPipe:

View File

@@ -429,11 +429,7 @@ class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportIn
self, coro: _TaskCompatibleCoro[_T_co], *, loop: AbstractEventLoop = ..., name: str | None = ...
) -> None: ...
if sys.version_info >= (3, 12):
def get_coro(self) -> _TaskCompatibleCoro[_T_co] | None: ...
else:
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
def get_coro(self) -> _TaskCompatibleCoro[_T_co]: ...
def get_name(self) -> str: ...
def set_name(self, value: object, /) -> None: ...
if sys.version_info >= (3, 12):

View File

@@ -2,7 +2,7 @@ import socket
import sys
from _typeshed import Incomplete, ReadableBuffer, WriteableBuffer
from collections.abc import Callable
from typing import IO, Any, ClassVar, Final, NoReturn
from typing import IO, Any, ClassVar, Literal, NoReturn
from . import events, futures, proactor_events, selector_events, streams, windows_utils
@@ -28,10 +28,10 @@ if sys.platform == "win32":
"WindowsProactorEventLoopPolicy",
)
NULL: Final = 0
INFINITE: Final = 0xFFFFFFFF
ERROR_CONNECTION_REFUSED: Final = 1225
ERROR_CONNECTION_ABORTED: Final = 1236
NULL: Literal[0]
INFINITE: Literal[0xFFFFFFFF]
ERROR_CONNECTION_REFUSED: Literal[1225]
ERROR_CONNECTION_ABORTED: Literal[1236]
CONNECT_PIPE_INIT_DELAY: float
CONNECT_PIPE_MAX_DELAY: float

View File

@@ -2,13 +2,13 @@ import subprocess
import sys
from collections.abc import Callable
from types import TracebackType
from typing import Any, AnyStr, Final
from typing import Any, AnyStr, Literal
from typing_extensions import Self
if sys.platform == "win32":
__all__ = ("pipe", "Popen", "PIPE", "PipeHandle")
BUFSIZE: Final = 8192
BUFSIZE: Literal[8192]
PIPE = subprocess.PIPE
STDOUT = subprocess.STDOUT
def pipe(*, duplex: bool = False, overlapped: tuple[bool, bool] = (True, True), bufsize: int = 8192) -> tuple[int, int]: ...

View File

@@ -2,7 +2,7 @@ import sys
from _typeshed import ExcInfo, TraceFunction, Unused
from collections.abc import Callable, Iterable, Mapping
from types import CodeType, FrameType, TracebackType
from typing import IO, Any, Final, SupportsInt, TypeVar
from typing import IO, Any, Literal, SupportsInt, TypeVar
from typing_extensions import ParamSpec
__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
@@ -10,10 +10,7 @@ __all__ = ["BdbQuit", "Bdb", "Breakpoint"]
_T = TypeVar("_T")
_P = ParamSpec("_P")
# A union of code-object flags at runtime.
# The exact values of code-object flags are implementation details,
# so we don't include the value of this constant in the stubs.
GENERATOR_AND_COROUTINE_FLAGS: Final[int]
GENERATOR_AND_COROUTINE_FLAGS: Literal[672]
class BdbQuit(Exception): ...

View File

@@ -1,14 +1,14 @@
from _typeshed import SizedBuffer
from typing import IO, Any, Final
from typing import IO, Any, Literal
from typing_extensions import TypeAlias
__all__ = ["binhex", "hexbin", "Error"]
class Error(Exception): ...
REASONABLY_LARGE: Final = 32768
LINELEN: Final = 64
RUNCHAR: Final = b"\x90"
REASONABLY_LARGE: Literal[32768]
LINELEN: Literal[64]
RUNCHAR: Literal[b"\x90"]
class FInfo:
Type: str

View File

@@ -1868,7 +1868,6 @@ class BaseException:
__suppress_context__: bool
__traceback__: TracebackType | None
def __init__(self, *args: object) -> None: ...
def __new__(cls, *args: Any, **kwds: Any) -> Self: ...
def __setstate__(self, state: dict[str, Any] | None, /) -> None: ...
def with_traceback(self, tb: TracebackType | None, /) -> Self: ...
if sys.version_info >= (3, 11):

View File

@@ -1,9 +1,9 @@
from collections.abc import Callable
from typing import IO, Any, Final
from typing import IO, Any, Literal
__all__ = ["Cmd"]
PROMPT: Final = "(Cmd) "
PROMPT: Literal["(Cmd) "]
IDENTCHARS: str # Too big to be `Literal`
class Cmd:

View File

@@ -3,7 +3,7 @@ from _codecs import *
from _typeshed import ReadableBuffer
from abc import abstractmethod
from collections.abc import Callable, Generator, Iterable
from typing import Any, BinaryIO, Final, Literal, Protocol, TextIO
from typing import Any, BinaryIO, Literal, Protocol, TextIO
from typing_extensions import Self
__all__ = [
@@ -53,10 +53,10 @@ __all__ = [
"lookup_error",
]
BOM32_BE: Final = b"\xfe\xff"
BOM32_LE: Final = b"\xff\xfe"
BOM64_BE: Final = b"\x00\x00\xfe\xff"
BOM64_LE: Final = b"\xff\xfe\x00\x00"
BOM32_BE: Literal[b"\xfe\xff"]
BOM32_LE: Literal[b"\xff\xfe"]
BOM64_BE: Literal[b"\x00\x00\xfe\xff"]
BOM64_LE: Literal[b"\xff\xfe\x00\x00"]
class _WritableStream(Protocol):
def write(self, data: bytes, /) -> object: ...
@@ -135,23 +135,23 @@ def EncodedFile(file: _Stream, data_encoding: str, file_encoding: str | None = N
def iterencode(iterator: Iterable[str], encoding: str, errors: str = "strict") -> Generator[bytes, None, None]: ...
def iterdecode(iterator: Iterable[bytes], encoding: str, errors: str = "strict") -> Generator[str, None, None]: ...
BOM: Final[Literal[b"\xff\xfe", b"\xfe\xff"]] # depends on `sys.byteorder`
BOM_BE: Final = b"\xfe\xff"
BOM_LE: Final = b"\xff\xfe"
BOM_UTF8: Final = b"\xef\xbb\xbf"
BOM_UTF16: Final[Literal[b"\xff\xfe", b"\xfe\xff"]] # depends on `sys.byteorder`
BOM_UTF16_BE: Final = b"\xfe\xff"
BOM_UTF16_LE: Final = b"\xff\xfe"
BOM_UTF32: Final[Literal[b"\xff\xfe\x00\x00", b"\x00\x00\xfe\xff"]] # depends on `sys.byteorder`
BOM_UTF32_BE: Final = b"\x00\x00\xfe\xff"
BOM_UTF32_LE: Final = b"\xff\xfe\x00\x00"
BOM: Literal[b"\xff\xfe", b"\xfe\xff"] # depends on `sys.byteorder`
BOM_BE: Literal[b"\xfe\xff"]
BOM_LE: Literal[b"\xff\xfe"]
BOM_UTF8: Literal[b"\xef\xbb\xbf"]
BOM_UTF16: Literal[b"\xff\xfe", b"\xfe\xff"] # depends on `sys.byteorder`
BOM_UTF16_BE: Literal[b"\xfe\xff"]
BOM_UTF16_LE: Literal[b"\xff\xfe"]
BOM_UTF32: Literal[b"\xff\xfe\x00\x00", b"\x00\x00\xfe\xff"] # depends on `sys.byteorder`
BOM_UTF32_BE: Literal[b"\x00\x00\xfe\xff"]
BOM_UTF32_LE: Literal[b"\xff\xfe\x00\x00"]
def strict_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def replace_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def ignore_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def xmlcharrefreplace_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def backslashreplace_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def namereplace_errors(exception: UnicodeError, /) -> tuple[str | bytes, int]: ...
def strict_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
def replace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
def ignore_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
def xmlcharrefreplace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
def backslashreplace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
def namereplace_errors(exception: UnicodeError) -> tuple[str | bytes, int]: ...
class Codec:
# These are sort of @abstractmethod but sort of not.

View File

@@ -4,20 +4,20 @@ from _typeshed import Unused
from collections.abc import Callable, Collection, Iterable, Iterator
from logging import Logger
from types import TracebackType
from typing import Any, Final, Generic, NamedTuple, Protocol, TypeVar
from typing import Any, Generic, Literal, NamedTuple, Protocol, TypeVar
from typing_extensions import ParamSpec, Self
if sys.version_info >= (3, 9):
from types import GenericAlias
FIRST_COMPLETED: Final = "FIRST_COMPLETED"
FIRST_EXCEPTION: Final = "FIRST_EXCEPTION"
ALL_COMPLETED: Final = "ALL_COMPLETED"
PENDING: Final = "PENDING"
RUNNING: Final = "RUNNING"
CANCELLED: Final = "CANCELLED"
CANCELLED_AND_NOTIFIED: Final = "CANCELLED_AND_NOTIFIED"
FINISHED: Final = "FINISHED"
FIRST_COMPLETED: Literal["FIRST_COMPLETED"]
FIRST_EXCEPTION: Literal["FIRST_EXCEPTION"]
ALL_COMPLETED: Literal["ALL_COMPLETED"]
PENDING: Literal["PENDING"]
RUNNING: Literal["RUNNING"]
CANCELLED: Literal["CANCELLED"]
CANCELLED_AND_NOTIFIED: Literal["CANCELLED_AND_NOTIFIED"]
FINISHED: Literal["FINISHED"]
_FUTURE_STATES: list[str]
_STATE_TO_DESCRIPTION_MAP: dict[str, str]
LOGGER: Logger

View File

@@ -2,7 +2,7 @@ import sys
from _typeshed import StrOrBytesPath, SupportsWrite
from collections.abc import Callable, ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence
from re import Pattern
from typing import Any, ClassVar, Final, Literal, TypeVar, overload
from typing import Any, ClassVar, Literal, TypeVar, overload
from typing_extensions import TypeAlias
if sys.version_info >= (3, 13):
@@ -83,8 +83,8 @@ _ConverterCallback: TypeAlias = Callable[[str], Any]
_ConvertersMap: TypeAlias = dict[str, _ConverterCallback]
_T = TypeVar("_T")
DEFAULTSECT: Final = "DEFAULT"
MAX_INTERPOLATION_DEPTH: Final = 10
DEFAULTSECT: Literal["DEFAULT"]
MAX_INTERPOLATION_DEPTH: Literal[10]
class Interpolation:
def before_get(self, parser: _Parser, section: str, option: str, value: str, defaults: _Section) -> str: ...

View File

@@ -1,16 +1,8 @@
import sys
from typing import Any, Protocol, TypeVar
from typing_extensions import ParamSpec, Self
from typing import Any, TypeVar
__all__ = ["Error", "copy", "deepcopy"]
_T = TypeVar("_T")
_SR = TypeVar("_SR", bound=_SupportsReplace[Any])
_P = ParamSpec("_P")
class _SupportsReplace(Protocol[_P]):
# In reality doesn't support args, but there's no other great way to express this.
def __replace__(self, *args: _P.args, **kwargs: _P.kwargs) -> Self: ...
# None in CPython but non-None in Jython
PyStringMap: Any
@@ -19,10 +11,6 @@ PyStringMap: Any
def deepcopy(x: _T, memo: dict[int, Any] | None = None, _nil: Any = []) -> _T: ...
def copy(x: _T) -> _T: ...
if sys.version_info >= (3, 13):
__all__ += ["replace"]
def replace(obj: _SR, /, **changes: Any) -> _SR: ...
class Error(Exception): ...
error = Error

View File

@@ -1,7 +1,7 @@
import sys
from abc import abstractmethod
from time import struct_time
from typing import ClassVar, Final, NamedTuple, NoReturn, SupportsIndex, final, overload
from typing import ClassVar, Literal, NamedTuple, NoReturn, SupportsIndex, final, overload
from typing_extensions import Self, TypeAlias, deprecated
if sys.version_info >= (3, 11):
@@ -9,8 +9,8 @@ if sys.version_info >= (3, 11):
elif sys.version_info >= (3, 9):
__all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", "MINYEAR", "MAXYEAR")
MINYEAR: Final = 1
MAXYEAR: Final = 9999
MINYEAR: Literal[1]
MAXYEAR: Literal[9999]
class tzinfo:
@abstractmethod

View File

@@ -1,11 +1,10 @@
from _typeshed import BytesPath, StrPath, Unused
from _typeshed import BytesPath, StrPath
from collections.abc import Callable, Iterable
from distutils.file_util import _BytesPathT, _StrPathT
from typing import Literal, overload
from typing_extensions import TypeAlias, TypeVarTuple, Unpack
from typing import Any, Literal, overload
from typing_extensions import TypeAlias
_Macro: TypeAlias = tuple[str] | tuple[str, str | None]
_Ts = TypeVarTuple("_Ts")
def gen_lib_options(
compiler: CCompiler, library_dirs: list[str], runtime_library_dirs: list[str], libraries: list[str]
@@ -162,9 +161,7 @@ class CCompiler:
def shared_object_filename(self, basename: str, strip_dir: Literal[0, False] = 0, output_dir: StrPath = "") -> str: ...
@overload
def shared_object_filename(self, basename: StrPath, strip_dir: Literal[1, True], output_dir: StrPath = "") -> str: ...
def execute(
self, func: Callable[[Unpack[_Ts]], Unused], args: tuple[Unpack[_Ts]], msg: str | None = None, level: int = 1
) -> None: ...
def execute(self, func: Callable[..., object], args: tuple[Any, ...], msg: str | None = None, level: int = 1) -> None: ...
def spawn(self, cmd: list[str]) -> None: ...
def mkpath(self, name: str, mode: int = 0o777) -> None: ...
@overload

View File

@@ -3,11 +3,7 @@ from abc import abstractmethod
from collections.abc import Callable, Iterable
from distutils.dist import Distribution
from distutils.file_util import _BytesPathT, _StrPathT
from typing import Any, ClassVar, Literal, TypeVar, overload
from typing_extensions import TypeVarTuple, Unpack
_CommandT = TypeVar("_CommandT", bound=Command)
_Ts = TypeVarTuple("_Ts")
from typing import Any, ClassVar, Literal, overload
class Command:
distribution: Distribution
@@ -23,22 +19,17 @@ class Command:
def announce(self, msg: str, level: int = 1) -> None: ...
def debug_print(self, msg: str) -> None: ...
def ensure_string(self, option: str, default: str | None = None) -> None: ...
def ensure_string_list(self, option: str) -> None: ...
def ensure_string_list(self, option: str | list[str]) -> None: ...
def ensure_filename(self, option: str) -> None: ...
def ensure_dirname(self, option: str) -> None: ...
def get_command_name(self) -> str: ...
def set_undefined_options(self, src_cmd: str, *option_pairs: tuple[str, str]) -> None: ...
def get_finalized_command(self, command: str, create: bool | Literal[0, 1] = 1) -> Command: ...
@overload
def reinitialize_command(self, command: str, reinit_subcommands: bool | Literal[0, 1] = 0) -> Command: ...
@overload
def reinitialize_command(self, command: _CommandT, reinit_subcommands: bool | Literal[0, 1] = 0) -> _CommandT: ...
def reinitialize_command(self, command: Command | str, reinit_subcommands: bool | Literal[0, 1] = 0) -> Command: ...
def run_command(self, command: str) -> None: ...
def get_sub_commands(self) -> list[str]: ...
def warn(self, msg: str) -> None: ...
def execute(
self, func: Callable[[Unpack[_Ts]], Unused], args: tuple[Unpack[_Ts]], msg: str | None = None, level: int = 1
) -> None: ...
def execute(self, func: Callable[..., object], args: Iterable[Any], msg: str | None = None, level: int = 1) -> None: ...
def mkpath(self, name: str, mode: int = 0o777) -> None: ...
@overload
def copy_file(
@@ -98,8 +89,8 @@ class Command:
self,
infiles: str | list[str] | tuple[str, ...],
outfile: StrOrBytesPath,
func: Callable[[Unpack[_Ts]], Unused],
args: tuple[Unpack[_Ts]],
func: Callable[..., object],
args: list[Any],
exec_msg: str | None = None,
skip_msg: str | None = None,
level: Unused = 1,

View File

@@ -1,6 +1,4 @@
from _typeshed import Unused
from collections.abc import Callable
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
@@ -8,13 +6,13 @@ def show_formats() -> None: ...
class bdist(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]]
no_format_option: ClassVar[tuple[str, ...]]
default_format: ClassVar[dict[str, str]]
format_commands: ClassVar[list[str]]
format_command: ClassVar[dict[str, tuple[str, str]]]
user_options: Any
boolean_options: Any
help_options: Any
no_format_option: Any
default_format: Any
format_commands: Any
format_command: Any
bdist_base: Any
plat_name: Any
formats: Any

View File

@@ -1,12 +1,12 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class bdist_dumb(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
default_format: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
default_format: Any
bdist_dir: Any
plat_name: Any
format: Any

View File

@@ -1,5 +1,5 @@
import sys
from typing import Any, ClassVar, Literal
from typing import Any, Literal
from ..cmd import Command
@@ -16,8 +16,8 @@ if sys.platform == "win32":
class bdist_msi(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
all_versions: Any
other_version: str
if sys.version_info >= (3, 9):

View File

@@ -1,12 +1,12 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class bdist_rpm(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
negative_opt: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
negative_opt: Any
bdist_base: Any
rpm_base: Any
dist_dir: Any

View File

@@ -1,10 +1,10 @@
from _typeshed import StrOrBytesPath
from distutils.cmd import Command
from typing import ClassVar
from typing import Any, ClassVar
class bdist_wininst(Command):
description: ClassVar[str]
user_options: ClassVar[list[tuple[str, str | None, str]]]
user_options: ClassVar[list[tuple[Any, ...]]]
boolean_options: ClassVar[list[str]]
def initialize_options(self) -> None: ...

View File

@@ -1,4 +1,3 @@
from _typeshed import Unused
from collections.abc import Callable
from typing import Any, ClassVar
@@ -8,9 +7,9 @@ def show_compilers() -> None: ...
class build(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]]
user_options: Any
boolean_options: Any
help_options: Any
build_base: str
build_purelib: Any
build_platlib: Any

View File

@@ -1,6 +1,4 @@
from _typeshed import Unused
from collections.abc import Callable
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
@@ -8,9 +6,9 @@ def show_compilers() -> None: ...
class build_clib(Command):
description: str
user_options: ClassVar[list[tuple[str, str, str]]]
boolean_options: ClassVar[list[str]]
help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]]
user_options: Any
boolean_options: Any
help_options: Any
build_clib: Any
build_temp: Any
libraries: Any

View File

@@ -1,6 +1,4 @@
from _typeshed import Unused
from collections.abc import Callable
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
@@ -11,9 +9,9 @@ def show_compilers() -> None: ...
class build_ext(Command):
description: str
sep_by: Any
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]]
user_options: Any
boolean_options: Any
help_options: Any
extensions: Any
build_lib: Any
plat_name: Any

View File

@@ -1,13 +1,13 @@
from typing import Any, ClassVar, Literal
from typing import Any, Literal
from ..cmd import Command
from ..util import Mixin2to3 as Mixin2to3
class build_py(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
negative_opt: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
negative_opt: Any
build_lib: Any
py_modules: Any
package: Any

View File

@@ -1,4 +1,4 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
from ..util import Mixin2to3 as Mixin2to3
@@ -7,8 +7,8 @@ first_line_re: Any
class build_scripts(Command):
description: str
user_options: ClassVar[list[tuple[str, str, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
build_dir: Any
scripts: Any
force: Any

View File

@@ -1,4 +1,4 @@
from typing import Any, ClassVar, Literal
from typing import Any, Literal
from typing_extensions import TypeAlias
from ..cmd import Command
@@ -26,8 +26,8 @@ HAS_DOCUTILS: bool
class check(Command):
description: str
user_options: ClassVar[list[tuple[str, str, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
restructuredtext: int
metadata: int
strict: int

View File

@@ -1,11 +1,11 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class clean(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
build_base: Any
build_lib: Any
build_temp: Any

View File

@@ -1,7 +1,7 @@
from _typeshed import StrOrBytesPath
from collections.abc import Sequence
from re import Pattern
from typing import Any, ClassVar, Literal
from typing import Any, Literal
from ..ccompiler import CCompiler
from ..cmd import Command
@@ -11,7 +11,7 @@ LANG_EXT: dict[str, str]
class config(Command):
description: str
# Tuple is full name, short name, description
user_options: ClassVar[list[tuple[str, str | None, str]]]
user_options: Sequence[tuple[str, str | None, str]]
compiler: str | CCompiler
cc: str | None
include_dirs: Sequence[str] | None

View File

@@ -9,9 +9,9 @@ INSTALL_SCHEMES: dict[str, dict[Any, Any]]
class install(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
negative_opt: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
negative_opt: Any
prefix: str | None
exec_prefix: Any
home: str | None

View File

@@ -1,11 +1,11 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class install_data(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
install_dir: Any
outfiles: Any
root: Any

View File

@@ -4,7 +4,7 @@ from ..cmd import Command
class install_egg_info(Command):
description: ClassVar[str]
user_options: ClassVar[list[tuple[str, str, str]]]
user_options: ClassVar[list[tuple[str, str | None, str]]]
install_dir: Any
def initialize_options(self) -> None: ...
target: Any

View File

@@ -1,11 +1,11 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class install_headers(Command):
description: str
user_options: ClassVar[list[tuple[str, str, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
install_dir: Any
force: int
outfiles: Any

View File

@@ -1,4 +1,4 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
@@ -6,9 +6,9 @@ PYTHON_SOURCE_EXTENSION: str
class install_lib(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
negative_opt: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
negative_opt: Any
install_dir: Any
build_dir: Any
force: int

View File

@@ -1,11 +1,11 @@
from typing import Any, ClassVar
from typing import Any
from ..cmd import Command
class install_scripts(Command):
description: str
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
user_options: Any
boolean_options: Any
install_dir: Any
force: int
build_dir: Any

View File

@@ -1,4 +1,3 @@
from _typeshed import Unused
from collections.abc import Callable
from typing import Any, ClassVar
@@ -9,13 +8,13 @@ def show_formats() -> None: ...
class sdist(Command):
description: str
def checking_metadata(self): ...
user_options: ClassVar[list[tuple[str, str | None, str]]]
boolean_options: ClassVar[list[str]]
help_options: ClassVar[list[tuple[str, str | None, str, Callable[[], Unused]]]]
negative_opt: ClassVar[dict[str, str]]
user_options: Any
boolean_options: Any
help_options: Any
negative_opt: Any
# Any to work around variance issues
sub_commands: ClassVar[list[tuple[str, Callable[[Any], bool] | None]]]
READMES: ClassVar[tuple[str, ...]]
READMES: Any
template: Any
manifest: Any
use_defaults: int

View File

@@ -1,8 +1,8 @@
from _typeshed import Incomplete, StrOrBytesPath, StrPath, SupportsWrite
from collections.abc import Iterable, MutableMapping
from collections.abc import Iterable, Mapping
from distutils.cmd import Command
from re import Pattern
from typing import IO, ClassVar, Literal, TypeVar, overload
from typing import IO, Any, ClassVar, Literal, TypeVar, overload
from typing_extensions import TypeAlias
command_re: Pattern[str]
@@ -60,7 +60,7 @@ class DistributionMetadata:
class Distribution:
cmdclass: dict[str, type[Command]]
metadata: DistributionMetadata
def __init__(self, attrs: MutableMapping[str, Incomplete] | None = None) -> None: ...
def __init__(self, attrs: Mapping[str, Any] | None = None) -> None: ...
def get_option_dict(self, command: str) -> dict[str, tuple[str, str]]: ...
def parse_config_files(self, filenames: Iterable[str] | None = None) -> None: ...
@overload

View File

@@ -1,9 +1,6 @@
from _typeshed import StrPath, Unused
from collections.abc import Callable, Container, Iterable, Mapping
from typing import Any, Literal
from typing_extensions import TypeVarTuple, Unpack
_Ts = TypeVarTuple("_Ts")
def get_host_platform() -> str: ...
def get_platform() -> str: ...
@@ -13,8 +10,8 @@ def check_environ() -> None: ...
def subst_vars(s: str, local_vars: Mapping[str, str]) -> None: ...
def split_quoted(s: str) -> list[str]: ...
def execute(
func: Callable[[Unpack[_Ts]], Unused],
args: tuple[Unpack[_Ts]],
func: Callable[..., object],
args: tuple[Any, ...],
msg: str | None = None,
verbose: bool | Literal[0, 1] = 0,
dry_run: bool | Literal[0, 1] = 0,

View File

@@ -1,12 +1,12 @@
from collections.abc import Callable, Iterator
from email.message import Message
from typing import Final, overload
from typing import overload
__all__ = ["Charset", "add_alias", "add_charset", "add_codec"]
QP: Final[int] # undocumented
BASE64: Final[int] # undocumented
SHORTEST: Final[int] # undocumented
QP: int # undocumented
BASE64: int # undocumented
SHORTEST: int # undocumented
class Charset:
input_charset: str

View File

@@ -1,6 +1,6 @@
import sys
from _typeshed import FileDescriptorLike, ReadOnlyBuffer, WriteableBuffer
from typing import Any, Final, Literal, overload
from typing import Any, Literal, overload
from typing_extensions import Buffer
if sys.platform != "win32":
@@ -44,10 +44,9 @@ if sys.platform != "win32":
F_SEAL_SHRINK: int
F_SEAL_WRITE: int
if sys.version_info >= (3, 9):
F_OFD_GETLK: Final[int]
F_OFD_SETLK: Final[int]
F_OFD_SETLKW: Final[int]
F_OFD_GETLK: int
F_OFD_SETLK: int
F_OFD_SETLKW: int
if sys.version_info >= (3, 10):
F_GETPIPE_SZ: int
F_SETPIPE_SZ: int
@@ -106,36 +105,6 @@ if sys.platform != "win32":
FICLONE: int
FICLONERANGE: int
if sys.version_info >= (3, 13) and sys.platform == "linux":
F_OWNER_TID: Final = 0
F_OWNER_PID: Final = 1
F_OWNER_PGRP: Final = 2
F_SETOWN_EX: Final = 15
F_GETOWN_EX: Final = 16
F_SEAL_FUTURE_WRITE: Final = 16
F_GET_RW_HINT: Final = 1035
F_SET_RW_HINT: Final = 1036
F_GET_FILE_RW_HINT: Final = 1037
F_SET_FILE_RW_HINT: Final = 1038
RWH_WRITE_LIFE_NOT_SET: Final = 0
RWH_WRITE_LIFE_NONE: Final = 1
RWH_WRITE_LIFE_SHORT: Final = 2
RWH_WRITE_LIFE_MEDIUM: Final = 3
RWH_WRITE_LIFE_LONG: Final = 4
RWH_WRITE_LIFE_EXTREME: Final = 5
if sys.version_info >= (3, 11) and sys.platform == "darwin":
F_OFD_SETLK: Final = 90
F_OFD_SETLKW: Final = 91
F_OFD_GETLK: Final = 92
if sys.version_info >= (3, 13) and sys.platform != "linux":
# OSx and NetBSD
F_GETNOSIGPIPE: Final[int]
F_SETNOSIGPIPE: Final[int]
# OSx and FreeBSD
F_RDAHEAD: Final[int]
@overload
def fcntl(fd: FileDescriptorLike, cmd: int, arg: int = 0, /) -> int: ...
@overload

View File

@@ -1,7 +1,7 @@
import sys
from _typeshed import GenericPath, StrOrBytesPath
from collections.abc import Callable, Iterable, Sequence
from typing import Any, AnyStr, Final, Generic, Literal
from typing import Any, AnyStr, Generic, Literal
if sys.version_info >= (3, 9):
from types import GenericAlias
@@ -9,7 +9,7 @@ if sys.version_info >= (3, 9):
__all__ = ["clear_cache", "cmp", "dircmp", "cmpfiles", "DEFAULT_IGNORES"]
DEFAULT_IGNORES: list[str]
BUFSIZE: Final = 8192
BUFSIZE: Literal[8192]
def cmp(f1: StrOrBytesPath, f2: StrOrBytesPath, shallow: bool | Literal[0, 1] = True) -> bool: ...
def cmpfiles(

View File

@@ -4,16 +4,16 @@ from collections.abc import Callable, Iterable, Iterator
from socket import socket
from ssl import SSLContext
from types import TracebackType
from typing import Any, Final, Literal, TextIO
from typing import Any, Literal, TextIO
from typing_extensions import Self
__all__ = ["FTP", "error_reply", "error_temp", "error_perm", "error_proto", "all_errors", "FTP_TLS"]
MSG_OOB: Final = 1
FTP_PORT: Final = 21
MAXLINE: Final = 8192
CRLF: Final = "\r\n"
B_CRLF: Final = b"\r\n"
MSG_OOB: Literal[1]
FTP_PORT: Literal[21]
MAXLINE: Literal[8192]
CRLF: Literal["\r\n"]
B_CRLF: Literal[b"\r\n"]
class Error(Exception): ...
class error_reply(Error): ...

View File

@@ -1,13 +1,13 @@
import sys
from collections.abc import Callable
from typing import Any, Final, Literal
from typing import Any, Literal
from typing_extensions import TypeAlias
DEBUG_COLLECTABLE: Final = 2
DEBUG_LEAK: Final = 38
DEBUG_SAVEALL: Final = 32
DEBUG_STATS: Final = 1
DEBUG_UNCOLLECTABLE: Final = 4
DEBUG_COLLECTABLE: Literal[2]
DEBUG_LEAK: Literal[38]
DEBUG_SAVEALL: Literal[32]
DEBUG_STATS: Literal[1]
DEBUG_UNCOLLECTABLE: Literal[4]
_CallbackType: TypeAlias = Callable[[Literal["start", "stop"], dict[str, int]], object]
@@ -34,4 +34,4 @@ if sys.version_info >= (3, 9):
def isenabled() -> bool: ...
def set_debug(flags: int, /) -> None: ...
def set_threshold(threshold0: int, threshold1: int = ..., threshold2: int = ..., /) -> None: ...
def set_threshold(threshold0: int, threshold1: int = ..., threshold2: int = ...) -> None: ...

View File

@@ -3,7 +3,7 @@ import sys
import zlib
from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath
from io import FileIO
from typing import Final, Literal, Protocol, TextIO, overload
from typing import Literal, Protocol, TextIO, overload
from typing_extensions import TypeAlias
__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
@@ -12,14 +12,14 @@ _ReadBinaryMode: TypeAlias = Literal["r", "rb"]
_WriteBinaryMode: TypeAlias = Literal["a", "ab", "w", "wb", "x", "xb"]
_OpenTextMode: TypeAlias = Literal["rt", "at", "wt", "xt"]
READ: Final[object] # undocumented
WRITE: Final[object] # undocumented
READ: object # undocumented
WRITE: object # undocumented
FTEXT: Final[int] # actually Literal[1] # undocumented
FHCRC: Final[int] # actually Literal[2] # undocumented
FEXTRA: Final[int] # actually Literal[4] # undocumented
FNAME: Final[int] # actually Literal[8] # undocumented
FCOMMENT: Final[int] # actually Literal[16] # undocumented
FTEXT: int # actually Literal[1] # undocumented
FHCRC: int # actually Literal[2] # undocumented
FEXTRA: int # actually Literal[4] # undocumented
FNAME: int # actually Literal[8] # undocumented
FCOMMENT: int # actually Literal[16] # undocumented
class _ReadableFileobj(Protocol):
def read(self, n: int, /) -> bytes: ...

View File

@@ -42,7 +42,7 @@ class CookieJar(Iterable[Cookie]):
def __len__(self) -> int: ...
class FileCookieJar(CookieJar):
filename: str | None
filename: str
delayload: bool
def __init__(self, filename: StrPath | None = None, delayload: bool = False, policy: CookiePolicy | None = None) -> None: ...
def save(self, filename: str | None = None, ignore_discard: bool = False, ignore_expires: bool = False) -> None: ...

View File

@@ -25,7 +25,7 @@ from types import (
TracebackType,
WrapperDescriptorType,
)
from typing import Any, ClassVar, Final, Literal, NamedTuple, Protocol, TypeVar, overload
from typing import Any, ClassVar, Literal, NamedTuple, Protocol, TypeVar, overload
from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs
if sys.version_info >= (3, 11):
@@ -161,17 +161,17 @@ class BlockFinder:
last: int
def tokeneater(self, type: int, token: str, srowcol: tuple[int, int], erowcol: tuple[int, int], line: str) -> None: ...
CO_OPTIMIZED: Final = 1
CO_NEWLOCALS: Final = 2
CO_VARARGS: Final = 4
CO_VARKEYWORDS: Final = 8
CO_NESTED: Final = 16
CO_GENERATOR: Final = 32
CO_NOFREE: Final = 64
CO_COROUTINE: Final = 128
CO_ITERABLE_COROUTINE: Final = 256
CO_ASYNC_GENERATOR: Final = 512
TPFLAGS_IS_ABSTRACT: Final = 1048576
CO_OPTIMIZED: Literal[1]
CO_NEWLOCALS: Literal[2]
CO_VARARGS: Literal[4]
CO_VARKEYWORDS: Literal[8]
CO_NESTED: Literal[16]
CO_GENERATOR: Literal[32]
CO_NOFREE: Literal[64]
CO_COROUTINE: Literal[128]
CO_ITERABLE_COROUTINE: Literal[256]
CO_ASYNC_GENERATOR: Literal[512]
TPFLAGS_IS_ABSTRACT: Literal[1048576]
modulesbyfile: dict[str, Any]
@@ -364,10 +364,10 @@ class _ParameterKind(enum.IntEnum):
def description(self) -> str: ...
if sys.version_info >= (3, 12):
AGEN_CREATED: Final = "AGEN_CREATED"
AGEN_RUNNING: Final = "AGEN_RUNNING"
AGEN_SUSPENDED: Final = "AGEN_SUSPENDED"
AGEN_CLOSED: Final = "AGEN_CLOSED"
AGEN_CREATED: Literal["AGEN_CREATED"]
AGEN_RUNNING: Literal["AGEN_RUNNING"]
AGEN_SUSPENDED: Literal["AGEN_SUSPENDED"]
AGEN_CLOSED: Literal["AGEN_CLOSED"]
def getasyncgenstate(
agen: AsyncGenerator[Any, Any]
@@ -584,19 +584,19 @@ def getattr_static(obj: object, attr: str, default: Any | None = ...) -> Any: ..
# Current State of Generators and Coroutines
#
GEN_CREATED: Final = "GEN_CREATED"
GEN_RUNNING: Final = "GEN_RUNNING"
GEN_SUSPENDED: Final = "GEN_SUSPENDED"
GEN_CLOSED: Final = "GEN_CLOSED"
GEN_CREATED: Literal["GEN_CREATED"]
GEN_RUNNING: Literal["GEN_RUNNING"]
GEN_SUSPENDED: Literal["GEN_SUSPENDED"]
GEN_CLOSED: Literal["GEN_CLOSED"]
def getgeneratorstate(
generator: Generator[Any, Any, Any]
) -> Literal["GEN_CREATED", "GEN_RUNNING", "GEN_SUSPENDED", "GEN_CLOSED"]: ...
CORO_CREATED: Final = "CORO_CREATED"
CORO_RUNNING: Final = "CORO_RUNNING"
CORO_SUSPENDED: Final = "CORO_SUSPENDED"
CORO_CLOSED: Final = "CORO_CLOSED"
CORO_CREATED: Literal["CORO_CREATED"]
CORO_RUNNING: Literal["CORO_RUNNING"]
CORO_SUSPENDED: Literal["CORO_SUSPENDED"]
CORO_CLOSED: Literal["CORO_CLOSED"]
def getcoroutinestate(
coroutine: Coroutine[Any, Any, Any]

View File

@@ -6,7 +6,7 @@ from _typeshed import FileDescriptorOrPath, ReadableBuffer, WriteableBuffer
from collections.abc import Callable, Iterable, Iterator
from os import _Opener
from types import TracebackType
from typing import IO, Any, BinaryIO, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only
from typing import IO, Any, BinaryIO, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only
from typing_extensions import Self
__all__ = [
@@ -36,11 +36,11 @@ if sys.version_info >= (3, 11):
_T = TypeVar("_T")
DEFAULT_BUFFER_SIZE: Final = 8192
DEFAULT_BUFFER_SIZE: Literal[8192]
SEEK_SET: Final = 0
SEEK_CUR: Final = 1
SEEK_END: Final = 2
SEEK_SET: Literal[0]
SEEK_CUR: Literal[1]
SEEK_END: Literal[2]
open = builtins.open
@@ -168,7 +168,7 @@ class _WrappedBuffer(Protocol):
def writable(self) -> bool: ...
def truncate(self, size: int, /) -> int: ...
def fileno(self) -> int: ...
def isatty(self) -> bool: ...
def isatty(self) -> int: ...
# Optional: Only needs to be present if seekable() returns True.
# def seek(self, offset: Literal[0], whence: Literal[2]) -> int: ...
# def tell(self) -> int: ...

View File

@@ -1,11 +1,11 @@
import sys
from collections.abc import Iterable, Iterator
from typing import Any, Final, Generic, Literal, SupportsInt, TypeVar, overload
from typing import Any, Generic, Literal, SupportsInt, TypeVar, overload
from typing_extensions import Self, TypeAlias
# Undocumented length constants
IPV4LENGTH: Final = 32
IPV6LENGTH: Final = 128
IPV4LENGTH: Literal[32]
IPV6LENGTH: Literal[128]
_A = TypeVar("_A", IPv4Address, IPv6Address)
_N = TypeVar("_N", IPv4Network, IPv6Network)

View File

@@ -1,8 +1,8 @@
from typing import ClassVar, Final, Literal
from typing import ClassVar, Literal
from ..fixer_base import BaseFix
NAMES: Final[dict[str, str]]
NAMES: dict[str, str]
class FixAsserts(BaseFix):
BM_compatible: ClassVar[Literal[False]]

View File

@@ -1,9 +1,9 @@
from typing import ClassVar, Final, Literal
from typing import ClassVar, Literal
from .. import fixer_base
CMP: Final[str]
TYPE: Final[str]
CMP: str
TYPE: str
class FixIdioms(fixer_base.BaseFix):
BM_compatible: ClassVar[Literal[False]]

View File

@@ -1,11 +1,11 @@
from _typeshed import StrPath
from collections.abc import Generator
from typing import ClassVar, Final, Literal
from typing import ClassVar, Literal
from .. import fixer_base
from ..pytree import Node
MAPPING: Final[dict[str, str]]
MAPPING: dict[str, str]
def alternates(members): ...
def build_pattern(mapping=...) -> Generator[str, None, None]: ...

View File

@@ -1,8 +1,6 @@
from typing import Final
from . import fix_imports
MAPPING: Final[dict[str, str]]
MAPPING: dict[str, str]
class FixImports2(fix_imports.FixImports):
mapping = MAPPING

View File

@@ -1,8 +1,8 @@
from typing import ClassVar, Final, Literal
from typing import ClassVar, Literal
from .. import fixer_base
MAP: Final[dict[str, str]]
MAP: dict[str, str]
class FixMethodattrs(fixer_base.BaseFix):
BM_compatible: ClassVar[Literal[True]]

View File

@@ -1,10 +1,10 @@
from collections.abc import Generator
from typing import ClassVar, Final, Literal
from typing import ClassVar, Literal
from .. import fixer_base
MAPPING: Final[dict[str, dict[str, str]]]
LOOKUP: Final[dict[tuple[str, str], str]]
MAPPING: dict[str, dict[str, str]]
LOOKUP: dict[tuple[str, str], str]
def alternates(members): ...
def build_pattern() -> Generator[str, None, None]: ...

View File

@@ -1,9 +1,9 @@
from collections.abc import Generator
from typing import Final, Literal
from typing import Literal
from .fix_imports import FixImports
MAPPING: Final[dict[str, list[tuple[Literal["urllib.request", "urllib.parse", "urllib.error"], list[str]]]]]
MAPPING: dict[str, list[tuple[Literal["urllib.request", "urllib.parse", "urllib.error"], list[str]]]]
def build_pattern() -> Generator[str, None, None]: ...

View File

@@ -1,67 +1,65 @@
from typing import Final
ENDMARKER: Final[int]
NAME: Final[int]
NUMBER: Final[int]
STRING: Final[int]
NEWLINE: Final[int]
INDENT: Final[int]
DEDENT: Final[int]
LPAR: Final[int]
RPAR: Final[int]
LSQB: Final[int]
RSQB: Final[int]
COLON: Final[int]
COMMA: Final[int]
SEMI: Final[int]
PLUS: Final[int]
MINUS: Final[int]
STAR: Final[int]
SLASH: Final[int]
VBAR: Final[int]
AMPER: Final[int]
LESS: Final[int]
GREATER: Final[int]
EQUAL: Final[int]
DOT: Final[int]
PERCENT: Final[int]
BACKQUOTE: Final[int]
LBRACE: Final[int]
RBRACE: Final[int]
EQEQUAL: Final[int]
NOTEQUAL: Final[int]
LESSEQUAL: Final[int]
GREATEREQUAL: Final[int]
TILDE: Final[int]
CIRCUMFLEX: Final[int]
LEFTSHIFT: Final[int]
RIGHTSHIFT: Final[int]
DOUBLESTAR: Final[int]
PLUSEQUAL: Final[int]
MINEQUAL: Final[int]
STAREQUAL: Final[int]
SLASHEQUAL: Final[int]
PERCENTEQUAL: Final[int]
AMPEREQUAL: Final[int]
VBAREQUAL: Final[int]
CIRCUMFLEXEQUAL: Final[int]
LEFTSHIFTEQUAL: Final[int]
RIGHTSHIFTEQUAL: Final[int]
DOUBLESTAREQUAL: Final[int]
DOUBLESLASH: Final[int]
DOUBLESLASHEQUAL: Final[int]
OP: Final[int]
COMMENT: Final[int]
NL: Final[int]
RARROW: Final[int]
AT: Final[int]
ATEQUAL: Final[int]
AWAIT: Final[int]
ASYNC: Final[int]
ERRORTOKEN: Final[int]
COLONEQUAL: Final[int]
N_TOKENS: Final[int]
NT_OFFSET: Final[int]
ENDMARKER: int
NAME: int
NUMBER: int
STRING: int
NEWLINE: int
INDENT: int
DEDENT: int
LPAR: int
RPAR: int
LSQB: int
RSQB: int
COLON: int
COMMA: int
SEMI: int
PLUS: int
MINUS: int
STAR: int
SLASH: int
VBAR: int
AMPER: int
LESS: int
GREATER: int
EQUAL: int
DOT: int
PERCENT: int
BACKQUOTE: int
LBRACE: int
RBRACE: int
EQEQUAL: int
NOTEQUAL: int
LESSEQUAL: int
GREATEREQUAL: int
TILDE: int
CIRCUMFLEX: int
LEFTSHIFT: int
RIGHTSHIFT: int
DOUBLESTAR: int
PLUSEQUAL: int
MINEQUAL: int
STAREQUAL: int
SLASHEQUAL: int
PERCENTEQUAL: int
AMPEREQUAL: int
VBAREQUAL: int
CIRCUMFLEXEQUAL: int
LEFTSHIFTEQUAL: int
RIGHTSHIFTEQUAL: int
DOUBLESTAREQUAL: int
DOUBLESLASH: int
DOUBLESLASHEQUAL: int
OP: int
COMMENT: int
NL: int
RARROW: int
AT: int
ATEQUAL: int
AWAIT: int
ASYNC: int
ERRORTOKEN: int
COLONEQUAL: int
N_TOKENS: int
NT_OFFSET: int
tok_name: dict[int, str]
def ISTERMINAL(x: int) -> bool: ...

View File

@@ -7,7 +7,7 @@ from re import Pattern
from string import Template
from time import struct_time
from types import FrameType, TracebackType
from typing import Any, ClassVar, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload
from typing import Any, ClassVar, Generic, Literal, Protocol, TextIO, TypeVar, overload
from typing_extensions import Self, TypeAlias, deprecated
if sys.version_info >= (3, 11):
@@ -236,14 +236,14 @@ class Logger(Filterer):
def hasHandlers(self) -> bool: ...
def callHandlers(self, record: LogRecord) -> None: ... # undocumented
CRITICAL: Final = 50
FATAL: Final = CRITICAL
ERROR: Final = 40
WARNING: Final = 30
WARN: Final = WARNING
INFO: Final = 20
DEBUG: Final = 10
NOTSET: Final = 0
CRITICAL: int
FATAL: int
ERROR: int
WARNING: int
WARN: int
INFO: int
DEBUG: int
NOTSET: int
class Handler(Filterer):
level: int # undocumented
@@ -684,6 +684,6 @@ class StrFormatStyle(PercentStyle): # undocumented
class StringTemplateStyle(PercentStyle): # undocumented
_tpl: Template
_STYLES: Final[dict[str, tuple[PercentStyle, str]]]
_STYLES: dict[str, tuple[PercentStyle, str]]
BASIC_FORMAT: Final[str]
BASIC_FORMAT: str

View File

@@ -4,14 +4,14 @@ from collections.abc import Callable, Hashable, Iterable, Sequence
from configparser import RawConfigParser
from re import Pattern
from threading import Thread
from typing import IO, Any, Final, Literal, SupportsIndex, TypedDict, overload
from typing import IO, Any, Literal, SupportsIndex, TypedDict, overload
from typing_extensions import Required, TypeAlias
from . import Filter, Filterer, Formatter, Handler, Logger, _FilterType, _FormatStyle, _Level
DEFAULT_LOGGING_CONFIG_PORT: int
RESET_ERROR: Final[int] # undocumented
IDENTIFIER: Final[Pattern[str]] # undocumented
RESET_ERROR: int # undocumented
IDENTIFIER: Pattern[str] # undocumented
if sys.version_info >= (3, 11):
class _RootLoggerConfiguration(TypedDict, total=False):

View File

@@ -8,16 +8,16 @@ from logging import FileHandler, Handler, LogRecord
from re import Pattern
from socket import SocketKind, socket
from threading import Thread
from typing import Any, ClassVar, Final, Protocol, TypeVar
from typing import Any, ClassVar, Protocol, TypeVar
_T = TypeVar("_T")
DEFAULT_TCP_LOGGING_PORT: Final[int]
DEFAULT_UDP_LOGGING_PORT: Final[int]
DEFAULT_HTTP_LOGGING_PORT: Final[int]
DEFAULT_SOAP_LOGGING_PORT: Final[int]
SYSLOG_UDP_PORT: Final[int]
SYSLOG_TCP_PORT: Final[int]
DEFAULT_TCP_LOGGING_PORT: int
DEFAULT_UDP_LOGGING_PORT: int
DEFAULT_HTTP_LOGGING_PORT: int
DEFAULT_SOAP_LOGGING_PORT: int
SYSLOG_UDP_PORT: int
SYSLOG_TCP_PORT: int
class WatchedFileHandler(FileHandler):
dev: int # undocumented

View File

@@ -1,7 +1,7 @@
from _compression import BaseStream
from _typeshed import ReadableBuffer, StrOrBytesPath
from collections.abc import Mapping, Sequence
from typing import IO, Any, Final, Literal, TextIO, final, overload
from typing import IO, Any, Literal, TextIO, final, overload
from typing_extensions import Self, TypeAlias
__all__ = [
@@ -50,33 +50,33 @@ _PathOrFile: TypeAlias = StrOrBytesPath | IO[bytes]
_FilterChain: TypeAlias = Sequence[Mapping[str, Any]]
FORMAT_AUTO: Final = 0
FORMAT_XZ: Final = 1
FORMAT_ALONE: Final = 2
FORMAT_RAW: Final = 3
CHECK_NONE: Final = 0
CHECK_CRC32: Final = 1
CHECK_CRC64: Final = 4
CHECK_SHA256: Final = 10
CHECK_ID_MAX: Final = 15
CHECK_UNKNOWN: Final = 16
FORMAT_AUTO: Literal[0]
FORMAT_XZ: Literal[1]
FORMAT_ALONE: Literal[2]
FORMAT_RAW: Literal[3]
CHECK_NONE: Literal[0]
CHECK_CRC32: Literal[1]
CHECK_CRC64: Literal[4]
CHECK_SHA256: Literal[10]
CHECK_ID_MAX: Literal[15]
CHECK_UNKNOWN: Literal[16]
FILTER_LZMA1: int # v big number
FILTER_LZMA2: Final = 33
FILTER_DELTA: Final = 3
FILTER_X86: Final = 4
FILTER_IA64: Final = 6
FILTER_ARM: Final = 7
FILTER_ARMTHUMB: Final = 8
FILTER_SPARC: Final = 9
FILTER_POWERPC: Final = 5
MF_HC3: Final = 3
MF_HC4: Final = 4
MF_BT2: Final = 18
MF_BT3: Final = 19
MF_BT4: Final = 20
MODE_FAST: Final = 1
MODE_NORMAL: Final = 2
PRESET_DEFAULT: Final = 6
FILTER_LZMA2: Literal[33]
FILTER_DELTA: Literal[3]
FILTER_X86: Literal[4]
FILTER_IA64: Literal[6]
FILTER_ARM: Literal[7]
FILTER_ARMTHUMB: Literal[8]
FILTER_SPARC: Literal[9]
FILTER_POWERPC: Literal[5]
MF_HC3: Literal[3]
MF_HC4: Literal[4]
MF_BT2: Literal[18]
MF_BT3: Literal[19]
MF_BT4: Literal[20]
MODE_FAST: Literal[1]
MODE_NORMAL: Literal[2]
PRESET_DEFAULT: Literal[6]
PRESET_EXTREME: int # v big number
# from _lzma.c

Some files were not shown because too many files have changed in this diff Show More