Skip to content
Merged
Show file tree
Hide file tree
Changes from 201 commits
Commits
Show all changes
203 commits
Select commit Hold shift + click to select a range
db6fe35
[ruff] #19982 add isolation rule for PYI021
second-ed Aug 20, 2025
a50b389
[flake8-pyi] add new test for isolation check for rule (PYI021)
second-ed Aug 21, 2025
3264d63
[flake8-pyi] isolation level hardcode for poc (PYI021)
second-ed Aug 22, 2025
8af4168
[flake8-pyi] revert body_len variable (PYI021)
second-ed Aug 22, 2025
7800db2
feat: statement_id method
second-ed Sep 3, 2025
f849dd7
[flake8-pyi] move PYI021 check to ast stage (PYI021)
second-ed Sep 4, 2025
d068e13
[flake8-pyi] use docstring_from fn (PYI021)
second-ed Sep 4, 2025
d5a2e80
[`pyupgrade`] Avoid reporting `__future__` features as unnecessary wh…
IDrokin117 Aug 20, 2025
7888e0c
[ty] add docstrings to completions based on type (#20008)
Gankra Aug 20, 2025
84db505
[ty] Add link for namespaces being partial (#20015)
Gankra Aug 21, 2025
ebcf493
[ty] Avoid unnecessary argument type expansion (#19999)
dhruvmanila Aug 21, 2025
be4823f
Fix rust feature activation (#20012)
ntBre Aug 21, 2025
cfff126
[ty] Use `dedent` in cursor tests (#20019)
MichaReiser Aug 21, 2025
91b4241
[ty] Perform assignability etc checks using new `Constraints` trait (…
dcreager Aug 21, 2025
5354fac
Move diff rendering to `ruff_db` (#20006)
ntBre Aug 21, 2025
8abb95d
[ty] Stop running every mdtest twice
BurntSushi Aug 21, 2025
94040a9
Bump 0.12.10 (#20025)
dylwil3 Aug 21, 2025
34b218e
[ty] fix GotoTargets for keyword args in nested function calls (#20013)
Gankra Aug 21, 2025
e44bb15
[ty] Fix incorrect docstring in call signature completion (#20021)
MichaReiser Aug 21, 2025
a363bb8
[ty] Improve diagnostics for bad calls to functions (#20022)
AlexWaygood Aug 21, 2025
6c5719e
[ty] Sync vendored typeshed stubs (#20031)
github-actions[bot] Aug 21, 2025
15a3739
[ty] Cancel background tasks when shutdown is requested (#20039)
MichaReiser Aug 22, 2025
6876231
[ty] Close signature help after `)` (#20017)
MichaReiser Aug 22, 2025
5d95dcd
[`ruff`] Fix false positive for t-strings in `default-factory-kwarg` …
maxmynter Aug 22, 2025
43d7463
[ty] rename BareTypeAliasType to ManualPEP695TypeAliasType (#20037)
carljm Aug 22, 2025
6e68f91
Fix incorrect lsp inlay hint type (#20044)
MatthewMckee4 Aug 22, 2025
c2a80b9
[`ruff`] Handle empty t-strings in `unnecessary-empty-iterable-within…
dylwil3 Aug 22, 2025
d12f57c
[ty] Add type as detail to completion items (#20047)
MichaReiser Aug 22, 2025
df57afa
[`flake8-use-pathlib`] Add autofix for `PTH211` (#20009)
chirizxc Aug 22, 2025
0a35b03
Add testing helper to compare stable vs preview snapshots (#19715)
vivster7 Aug 22, 2025
82eb353
[ty] Disallow std::env and io methods in most ty crates (#20046)
MichaReiser Aug 22, 2025
ac8784e
[ty] Add precise iteration and unpacking inference for string literal…
AlexWaygood Aug 22, 2025
31de0dd
[`flake8-use-pathlib`] Fix `PTH211` autofix (#20049)
chirizxc Aug 22, 2025
6768657
[ty] Shrink size of `AstNodeRef` (#20028)
ibraheemdev Aug 22, 2025
1ecabd1
[ty] Remove duplicate global lint registry (#20053)
ibraheemdev Aug 22, 2025
789f38a
[ty] Add a TODO for linting on `todo!`
BurntSushi Aug 22, 2025
2dbc45a
[ty] Add debug trace for workspace symbol elapsed time
BurntSushi Aug 21, 2025
03be2ed
[ty] Move query filtering outside of symbol visitor
BurntSushi Aug 21, 2025
02044a5
[ty] Add some unit tests for "query matches symbol"
BurntSushi Aug 21, 2025
a722c40
[ty] Optimize query string matching
BurntSushi Aug 21, 2025
f378db7
[ty] Optimize "workspace symbols" retrieval
BurntSushi Aug 21, 2025
7e84da5
[ty] Parallelize workspace symbols
BurntSushi Aug 22, 2025
de2fc0a
[ty] Rejigger workspace symbols for more efficient caching
BurntSushi Aug 23, 2025
883cc23
[ty] Lightly refactor document symbols AST visitor
BurntSushi Aug 23, 2025
218684c
[ty] Add Top[] and Bottom[] special forms, replacing top_materializat…
JelleZijlstra Aug 23, 2025
85dea0e
Update Rust crate filetime to v0.2.26 (#20064)
renovate[bot] Aug 25, 2025
e2a218a
Update dependency ruff to v0.12.10 (#20062)
renovate[bot] Aug 25, 2025
4c19e05
Update Rust crate bitflags to v2.9.3 (#20063)
renovate[bot] Aug 25, 2025
adf3e7b
Update Rust crate ordermap to v0.5.9 (#20065)
renovate[bot] Aug 25, 2025
5cece85
Update Rust crate proc-macro2 to v1.0.101 (#20066)
renovate[bot] Aug 25, 2025
7a142ad
Update Rust crate serde_json to v1.0.143 (#20069)
renovate[bot] Aug 25, 2025
e322e6e
Update astral-sh/setup-uv action to v6.6.0 (#20074)
renovate[bot] Aug 25, 2025
ef666dc
Update Rust crate thiserror to v2.0.16 (#20071)
renovate[bot] Aug 25, 2025
46dbabd
Update Rust crate tracing-indicatif to v0.3.13 (#20072)
renovate[bot] Aug 25, 2025
a7e1390
Update Rust crate syn to v2.0.106 (#20070)
renovate[bot] Aug 25, 2025
d4cb5dd
Update Rust crate url to v2.5.7 (#20073)
renovate[bot] Aug 25, 2025
e8ca459
Update cargo-bins/cargo-binstall action to v1.15.1 (#20075)
renovate[bot] Aug 25, 2025
d11d9cc
Update Rust crate regex to v1.11.2 (#20067)
renovate[bot] Aug 25, 2025
b6d0865
Update Rust crate regex-automata to v0.4.10 (#20068)
renovate[bot] Aug 25, 2025
51e8324
Update actions/checkout digest to ff7abcd (#20061)
renovate[bot] Aug 25, 2025
a4b9b18
[ty] Limit argument expansion size for overload call evaluation (#20041)
dhruvmanila Aug 25, 2025
ddacc6f
[ty] validate constructor call of `TypedDict` (#19810)
PrettyWood Aug 25, 2025
a136e54
Improve diff rendering for notebooks (#20036)
ntBre Aug 25, 2025
6bc40d0
[ty] Completely ignore typeshed's stub for `Any` (#20079)
AlexWaygood Aug 25, 2025
6dc4233
[`airflow`] replace wrong path `airflow.io.stroage` as `airflow.io.st…
Lee-W Aug 25, 2025
16b34a9
[ty] Sync vendored typeshed stubs (#20083)
github-actions[bot] Aug 25, 2025
153d3c6
[ty] don't mark entire type-alias scopes as Deferred (#20086)
carljm Aug 25, 2025
a3fc78a
[ty] Add support for PEP 800 (#20084)
AlexWaygood Aug 25, 2025
81c0f9d
[ty] Add support for PEP 750 t-strings (#20085)
dylwil3 Aug 25, 2025
711de3c
[ty] Refactor inlay hints structure to use separate parts (#20052)
MatthewMckee4 Aug 26, 2025
ef10020
Fix incorrect D413 links in docstrings convention FAQ (#20089)
Avasam Aug 26, 2025
3cc1e24
Add a `ScopeKind` for the `__class__` cell (#20048)
ntBre Aug 26, 2025
a8d4758
[`flake8-logging-format`] Add auto-fix for f-string logging calls (`G…
hamirmahal Aug 26, 2025
fc140ce
[ty] Add search paths info to unresolved import diagnostics (#20040)
Renkai Aug 26, 2025
db1f50e
[`flake8-use-pathlib`] Delete unused `Rule::OsSymlink` enabled check …
chirizxc Aug 26, 2025
61eabcc
[`flake8-use-pathlib`] Make `PTH100` fix unsafe because it can change…
chirizxc Aug 26, 2025
e5651ed
[`flake8-use-pathlib`] Update links to the table showing the correspo…
chirizxc Aug 26, 2025
abb215b
[ty] don't eagerly unpack aliases in user-authored unions (#20055)
carljm Aug 26, 2025
6dcca17
[ty] Add more tests for protocols (#20095)
AlexWaygood Aug 27, 2025
09fb798
[ty] Infer slightly more precise types for comprehensions (#20111)
AlexWaygood Aug 27, 2025
a867935
[ty] Fix the inferred interface of specialized generic protocols (#19…
AlexWaygood Aug 27, 2025
8eb7394
[ty] Preserve qualifiers when accessing attributes on unions/intersec…
sharkdp Aug 27, 2025
178b902
[`airflow`] Extend `AIR311` and `AIR312` rules (#20082)
Lee-W Aug 27, 2025
eb59daf
[ty] Optimize TDD atom ordering (#20098)
sharkdp Aug 27, 2025
8e9da9a
[`ruff`] Preserve relative whitespace in multi-line expressions (`RUF…
danparizher Aug 27, 2025
a75a589
[ty] print diagnostics with fully qualified name to disambiguate some…
leandrobbraga Aug 27, 2025
7de87bb
[`flake8-async`] Implement `blocking-http-call-httpx` (`ASYNC212`) (#…
amyreese Aug 27, 2025
c740403
[ty] Introduce a representation for the top/bottom materialization of…
JelleZijlstra Aug 28, 2025
8922255
[ty] Evaluate reachability of non-definitely-bound to Ambiguous (#19579)
Glyphack Aug 28, 2025
cb1db5e
Move GitLab output rendering to `ruff_db` (#20117)
ntBre Aug 28, 2025
d2ffe00
[`pyflakes`] Fix `allowed-unused-imports` matching for top-level modu…
TaKO8Ki Aug 28, 2025
6f67b0e
[ty] Benchmarks for problematic implicit instance attributes cases (#…
sharkdp Aug 28, 2025
b439986
Bump 0.12.11 (#20136)
ntBre Aug 28, 2025
b0856d6
[ty] No boundness analysis for implicit instance attributes (#20128)
sharkdp Aug 28, 2025
eb32ba3
[ty] Fix 'too many cycle iterations' for unions of literals (#20137)
sharkdp Aug 28, 2025
696784b
Use new diff rendering format in tests (#20101)
ntBre Aug 28, 2025
fe4114e
[ty] add cycle detection for find_legacy_typevars (#20124)
carljm Aug 28, 2025
d0b7055
[ty] add support for cyclic legacy generic protocols (#20125)
carljm Aug 28, 2025
e835b45
Fix mdtest ignore python code blocks (#20139)
MatthewMckee4 Aug 28, 2025
dafd6ef
[`flake8-async`] Implement `blocking-input` rule (`ASYNC250`) (#20122)
amyreese Aug 28, 2025
2bcbc3e
[ty] Simplify materialization of specialized generics (#20121)
JelleZijlstra Aug 28, 2025
ba446a4
[`pycodestyle`] Preserve return type annotation for `ParamSpec` (`E73…
danparizher Aug 28, 2025
5a94fd7
[`pylint`] Add U+061C to `PLE2502` (#20106)
kotx Aug 28, 2025
859f968
[`ruff`] Fix false negative for empty f-strings in `deque` calls (`RU…
danparizher Aug 28, 2025
b2ec901
[`perflint`] Handle tuples in dictionary comprehensions (`PERF403`) (…
liortct Aug 28, 2025
1ea3e2b
[ty] Add constraint set implementation (#19997)
dcreager Aug 29, 2025
cc101f6
[ty] Unpack variadic argument type in specialization (#20130)
dhruvmanila Aug 29, 2025
c6bbb33
[ty] Enforce that an attribute on a class `X` must be callable in ord…
AlexWaygood Aug 29, 2025
b44952b
[ty] Improve disambiguation of types via fully qualified names (#20141)
AlexWaygood Aug 29, 2025
8438cc2
[ty] Better error message for attempting to assign to a read-only pro…
AlexWaygood Aug 29, 2025
e682390
[`fastapi`] Fix false positive for paths with spaces around parameter…
danparizher Aug 29, 2025
08f3f22
[`refurb`] Add fix safety section (`FURB105`) (#17499)
Kalmaegi Aug 29, 2025
f272eb8
Show fixes by default (#19919)
ntBre Aug 29, 2025
e592973
[`pyupgrade`] Add fix safety section to docs (`UP029`) (#17490)
Kalmaegi Aug 29, 2025
3bf43d9
[ty] typecheck dict methods for `TypedDict` (#19874)
PrettyWood Aug 29, 2025
3db8edd
[ty] ensure union normalization really normalizes (#20147)
carljm Aug 29, 2025
6768220
[ty] minor TypedDict fixes (#20146)
carljm Aug 29, 2025
34a6862
[ty] Use `invalid-assignment` error code for invalid assignments to `…
AlexWaygood Aug 29, 2025
e2085a6
[ty] add six ecosystem projects to good.txt (#20157)
carljm Aug 29, 2025
b12bfda
Revert "[ty] Use `invalid-assignment` error code for invalid assignme…
AlexWaygood Aug 29, 2025
d2822e1
[ty] skip a slow seed in fuzzer (#20161)
carljm Aug 29, 2025
83261a0
Less confidently mark f-strings as empty when inferring truthiness (#…
dylwil3 Aug 29, 2025
2c857c3
[ty] don't assume that deferred type inference means deferred name re…
carljm Aug 29, 2025
1da9e47
[ty] improve cycle-detection coverage for apply_type_mapping (#20159)
carljm Aug 29, 2025
5fdbc0c
[ty] Sync vendored typeshed stubs (#20188)
github-actions[bot] Sep 1, 2025
a0da738
Update Rust crate mimalloc to v0.1.48 (#20187)
renovate[bot] Sep 1, 2025
9e4370f
Update Rust crate clap to v4.5.46 (#20186)
renovate[bot] Sep 1, 2025
df02b42
Update Rust crate camino to v1.1.12 (#20185)
renovate[bot] Sep 1, 2025
06bf0b9
Update cargo-bins/cargo-binstall action to v1.15.3 (#20182)
renovate[bot] Sep 1, 2025
3eee9d3
Update CodSpeedHQ/action action to v3.8.1 (#20183)
renovate[bot] Sep 1, 2025
eed6a1f
Update rui314/setup-mold digest to 725a879 (#20181)
renovate[bot] Sep 1, 2025
135d464
Update dependency ruff to v0.12.11 (#20184)
renovate[bot] Sep 1, 2025
60f149d
[ty] Support `__init_subclass__` (#20190)
sharkdp Sep 1, 2025
c85a1a1
[ty] `__class_getitem__` is a classmethod (#20192)
sharkdp Sep 1, 2025
aa5beb3
[ty] add more lsp tests for overloads (#20148)
Gankra Sep 2, 2025
18ceec5
[`flake8-use-pathlib`] Make `PTH119` and `PTH120` fixes unsafe becaus…
chirizxc Sep 2, 2025
1b6d00c
[ty] Make initializer calls GotoTargets (#20014)
Gankra Sep 2, 2025
8f5d225
[ty] Update ecosystem-analyzer (#20209)
sharkdp Sep 3, 2025
5ac5305
[ty] Run ecosystem-analyzer in release mode (#20210)
sharkdp Sep 3, 2025
a2ec8a9
[ty] Add GitLab output format (#20155)
ntBre Sep 3, 2025
9def095
[`airflow`] Improve the `AIR002` error message (#20173)
Lee-W Sep 3, 2025
d000a3d
[ty] Require that we can find a root when listing sub-modules
BurntSushi Aug 26, 2025
2091d18
[ty] Make `Module::all_submodules` return `Module` instead of `Name`
BurntSushi Aug 28, 2025
8030713
[ty] Add base for "all symbols" implementation
BurntSushi Aug 26, 2025
1c99d8a
[ty] Add naive implementation of completions for unimported symbols
BurntSushi Aug 28, 2025
1497f09
[ty] Make auto-import completions opt-in via an experimental option
BurntSushi Aug 29, 2025
e4d4307
[ty] Pick up typed text as a query for unimported completions
BurntSushi Sep 2, 2025
3250f2e
[ty] Correct default value for experimental rename setting
BurntSushi Sep 3, 2025
2414829
[`airflow`] Convert `DatasetOrTimeSchedule(datasets=...)` to `AssetOr…
Lee-W Sep 3, 2025
de3714a
[syntax-errors] Detect `yield from` inside async function (#20051)
11happy Sep 3, 2025
2fb4499
[`airflow`] Move `airflow.operators.postgres_operator.Mapping` from `…
Lee-W Sep 3, 2025
40a1e4b
Update Rust crate tracing-subscriber to v0.3.20 (#20162)
renovate[bot] Sep 3, 2025
5d048d4
[ty]eliminate definitely-impossible types from union in equality narr…
Renkai Sep 3, 2025
e26c701
Expose `Indentation` in `ruff_python_codegen` (#20216)
ShaharNaveh Sep 3, 2025
da56213
[ty] Treat `__new__` as a static method (#20212)
sharkdp Sep 3, 2025
f1298b2
[`flake8-comprehensions`] Skip `C417` when lambda contains `yield`/`y…
danparizher Sep 3, 2025
969ce80
[ty] Add functions for revealing assignability/subtyping constraints …
dcreager Sep 3, 2025
c5db2a4
[ty] Fix small test typo (#20220)
s-rigaud Sep 3, 2025
6db395d
Split LICENSE addendum by derivation type (#20222)
charliermarsh Sep 4, 2025
98edce4
[ty] More tests for TypedDict (#20205)
sharkdp Sep 4, 2025
4a8e2cd
Bump 0.12.12 (#20242)
dylwil3 Sep 4, 2025
e65f868
[ty] Minor cleanups (#20240)
AlexWaygood Sep 4, 2025
c6ebb93
[ty] Attribute access on top/bottom materializations (#20221)
JelleZijlstra Sep 4, 2025
06f38c0
[`ruff`] Use helper function for empty f-string detection in `in-empt…
TaKO8Ki Sep 4, 2025
a078253
[ty] Narrow specialized generics using isinstance() (#20256)
JelleZijlstra Sep 4, 2025
c71e05d
[ty] Reduce false positives for `ParamSpec`s and `TypeVarTuple`s (#20…
AlexWaygood Sep 4, 2025
3ea99e8
[ty] TypedDict: Add support for `typing.ReadOnly` (#20241)
sharkdp Sep 4, 2025
1e3bbd8
[ty] Minor: 'can not' => cannot (#20260)
sharkdp Sep 5, 2025
7437a77
[ty] Cover full range of annotated assignments (#20261)
sharkdp Sep 5, 2025
b0ac987
[ty] Add backreferences to TypedDict items in diagnostics (#20262)
sharkdp Sep 5, 2025
f56e08c
[ty] Include `python` folder in `environment.root` if it exists (#20263)
sharkdp Sep 5, 2025
b73ffac
[ty] Update mypy_primer, add egglog-python project (#20078)
sharkdp Sep 5, 2025
29b0bae
[ty] add doc-comments for some variance stuff (#20189)
ericmarkmartin Sep 5, 2025
f583551
[ty] Implement the legacy PEP-484 convention for indicating positiona…
AlexWaygood Sep 5, 2025
6061f3a
Add support for sorting diagnostics without a range (#20257)
amyreese Sep 5, 2025
39b3b9f
[ty] propagate visitors and constraints through has_relation_in_invar…
carljm Sep 6, 2025
577c180
[ty] initial support for `slots=True` in dataclasses (#20278)
thejchap Sep 7, 2025
1be758b
Update Rust crate insta to v1.43.2 (#20296)
renovate[bot] Sep 8, 2025
0c385a1
Update Rust crate log to v0.4.28 (#20297)
renovate[bot] Sep 8, 2025
8d70991
Update Rust crate wasm-bindgen-test to v0.3.51 (#20298)
renovate[bot] Sep 8, 2025
51fc1ea
Update Rust crate clap to v4.5.47 (#20295)
renovate[bot] Sep 8, 2025
0bc2112
Update Rust crate bitflags to v2.9.4 (#20294)
renovate[bot] Sep 8, 2025
7c926d1
Update astral-sh/setup-uv action to v6.6.1 (#20291)
renovate[bot] Sep 8, 2025
e2b4e25
Update dependency mdformat-mkdocs to v4.4.1 (#20299)
renovate[bot] Sep 8, 2025
4318f79
Update cargo-bins/cargo-binstall action to v1.15.4 (#20292)
renovate[bot] Sep 8, 2025
850f35c
Update dependency ruff to v0.12.12 (#20293)
renovate[bot] Sep 8, 2025
464edf2
CI: Eliminate warning in fuzz build workflow (#20290)
ferdnyc Sep 8, 2025
55d7c47
[ty] Fall back to `object` for attribute access on synthesized protoc…
AlexWaygood Sep 8, 2025
0df3741
[ty] Fix signature of `NamedTupleLike._make` (#20302)
sharkdp Sep 8, 2025
1211217
[`pep8-naming`] Fix formatting of `__all__` (`N816`) (#20301)
onerandomusername Sep 8, 2025
c76b9aa
[ty] Support "legacy" `typing.Self` in combination with PEP 695 gener…
sharkdp Sep 8, 2025
3dcbad7
[ty] Add support for generic PEP695 type aliases (#20219)
ibraheemdev Sep 8, 2025
897e05f
[ty] more precise lazy scope place lookup (#19932)
mtshiba Sep 8, 2025
65f9f72
[ty] equality narrowing on enums that don't override `__eq__` or `__n…
Renkai Sep 8, 2025
2ea22da
Allow the `if_not_else` Clippy lint
BurntSushi Sep 9, 2025
87738ff
[`pyupgrade`] Enable rule triggering for stub files (`UP043`) (#20027)
IDrokin117 Sep 9, 2025
c4d0eb6
Add support for using uv as an alternative formatter backend (#19665)
zanieb Sep 9, 2025
1af1457
[ruff] #19982 add isolation rule for PYI021
second-ed Aug 20, 2025
1dc7435
[flake8-pyi] add new test for isolation check for rule (PYI021)
second-ed Aug 21, 2025
2150937
[flake8-pyi] update snapshots for tests (PYI021)
second-ed Sep 9, 2025
73e2ccd
Merge branch 'main' into fix/PYI021_isolation_level
second-ed Sep 9, 2025
0ecb545
[flake8-pyi] fix comments from review (PYI021)
second-ed Sep 24, 2025
3f51950
nits
ntBre Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def check_isolation_level(mode: int) -> None:
"""Shouldn't try to fix either.""" # ERROR PYI021
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring seems slightly misleading since the snapshot shows it trying to fix both diagnostics 😄

In testing this locally in the CLI, the net effect is that we still emit both diagnostics when checking, but the isolation level means only the first diagnostic actually gets fixed. Since we sort by diagnostic range, that means PYI021 gets fixed and PIE790 does not. You don't need to write all of that in the docstring, to be clear, just recording my observations!

... # ERROR PIE790
3 changes: 0 additions & 3 deletions crates/ruff_linter/src/checkers/ast/analyze/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,6 @@ pub(crate) fn definitions(checker: &mut Checker) {
}

// flake8-pyi
if enforce_stubs {
flake8_pyi::rules::docstring_in_stubs(checker, definition, docstring);
}
if enforce_stubs_and_runtime {
flake8_pyi::rules::iter_method_return_iterable(checker, definition);
}
Expand Down
5 changes: 4 additions & 1 deletion crates/ruff_linter/src/checkers/ast/analyze/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use ruff_python_ast::Stmt;

use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::flake8_pie;
use crate::rules::refurb;
use crate::rules::{flake8_pie, flake8_pyi};

/// Run lint rules over a suite of [`Stmt`] syntax nodes.
pub(crate) fn suite(suite: &[Stmt], checker: &Checker) {
if checker.is_rule_enabled(Rule::UnnecessaryPlaceholder) {
flake8_pie::rules::unnecessary_placeholder(checker, suite);
}
if checker.source_type.is_stub() && checker.is_rule_enabled(Rule::DocstringInStub) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I didn't realize about moving this here is that it now gets called for non-function (or -class or -module) suites, such as context managers or if statements:

with foo():
    """docstring"""
    pass

if True:
    """docstring"""
    pass

I tested these locally, and we flag both of these. Fortunately, it looks like we already track a docstring_state field on Checker. We'd have to add a pub(crate) getter function for this and make the DocstringState and ExpectedDocstringKind enums pub(crate) too, but I think we can use that to check that we're in an actual docstring.

There's an existing SemanticModel::in_pep_257_docstring method, but unfortunately that flag only gets set on the SemanticModel once we're actually visiting the docstring.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey thanks for this, I think I've addressed all of the comments from the review, please let me know if I've missed anything!

flake8_pyi::rules::docstring_in_stubs(checker, suite);
}
if checker.is_rule_enabled(Rule::RepeatedGlobal) {
refurb::rules::repeated_global(checker, suite);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::helpers::map_subscript;
use ruff_python_ast::whitespace::trailing_comment_start_offset;
use ruff_python_ast::{Expr, ExprStringLiteral, Stmt, StmtExpr};
use ruff_python_semantic::{ScopeKind, SemanticModel};
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
Expand Down Expand Up @@ -100,7 +98,7 @@ pub(crate) fn unnecessary_placeholder(checker: &Checker, body: &[Stmt]) {
// Ellipses are significant in protocol methods and abstract methods.
// Specifically, Pyright uses the presence of an ellipsis to indicate that
// a method is a stub, rather than a default implementation.
if in_protocol_or_abstract_method(checker.semantic()) {
if checker.semantic().in_protocol_or_abstract_method() {
return;
}
Placeholder::Ellipsis
Expand Down Expand Up @@ -162,21 +160,3 @@ impl std::fmt::Display for Placeholder {
}
}
}

/// Return `true` if the [`SemanticModel`] is in a `typing.Protocol` subclass or an abstract
/// method.
fn in_protocol_or_abstract_method(semantic: &SemanticModel) -> bool {
semantic.current_scopes().any(|scope| match scope.kind {
ScopeKind::Class(class_def) => class_def
.bases()
.iter()
.any(|base| semantic.match_typing_expr(map_subscript(base), "Protocol")),
ScopeKind::Function(function_def) => {
ruff_python_semantic::analyze::visibility::is_abstract(
&function_def.decorator_list,
semantic,
)
}
_ => false,
})
}
13 changes: 13 additions & 0 deletions crates/ruff_linter/src/rules/flake8_pyi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,17 @@ mod tests {
assert_diagnostics!(snapshot, diagnostics);
Ok(())
}

#[test_case(Path::new("PYI021_1.pyi"))]
fn pyi021_pie790_isolation_check(path: &Path) -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_pyi").join(path).as_path(),
&settings::LinterSettings::for_rules([
Rule::DocstringInStub,
Rule::UnnecessaryPlaceholder,
]),
)?;
assert_diagnostics!(diagnostics);
Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use ruff_python_ast::ExprStringLiteral;
use ruff_python_semantic::Definition;
use ruff_python_ast::{ExprStringLiteral, Stmt};
use ruff_text_size::Ranged;

use crate::checkers::ast::Checker;
use crate::docstrings::extraction::docstring_from;
use crate::{AlwaysFixableViolation, Edit, Fix};

/// ## What it does
Expand Down Expand Up @@ -41,26 +41,23 @@ impl AlwaysFixableViolation for DocstringInStub {
}

/// PYI021
pub(crate) fn docstring_in_stubs(
checker: &Checker,
definition: &Definition,
docstring: Option<&ExprStringLiteral>,
) {
pub(crate) fn docstring_in_stubs(checker: &Checker, body: &[Stmt]) {
let docstring = docstring_from(body);

let Some(docstring_range) = docstring.map(ExprStringLiteral::range) else {
return;
};

let statements = match definition {
Definition::Module(module) => module.python_ast,
Definition::Member(member) => member.body(),
};

let edit = if statements.len() == 1 {
let edit = if body.len() == 1 {
Edit::range_replacement("...".to_string(), docstring_range)
} else {
Edit::range_deletion(docstring_range)
};

let mut diagnostic = checker.report_diagnostic(DocstringInStub, docstring_range);
diagnostic.set_fix(Fix::unsafe_edit(edit));
let isolation_level = Checker::isolation(checker.semantic().current_statement_id());
let fix = Fix::unsafe_edit(edit).isolate(isolation_level);

checker
.report_diagnostic(DocstringInStub, docstring_range)
.set_fix(fix);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI021 [*] Docstrings should not be included in stubs
--> PYI021_1.pyi:2:5
|
1 | def check_isolation_level(mode: int) -> None:
2 | """Shouldn't try to fix either.""" # ERROR PYI021
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 | ... # ERROR PIE790
|
help: Remove docstring
1 | def check_isolation_level(mode: int) -> None:
- """Shouldn't try to fix either.""" # ERROR PYI021
2 + # ERROR PYI021
3 | ... # ERROR PIE790
note: This is an unsafe fix and may change runtime behavior

PIE790 [*] Unnecessary `...` literal
--> PYI021_1.pyi:3:5
|
1 | def check_isolation_level(mode: int) -> None:
2 | """Shouldn't try to fix either.""" # ERROR PYI021
3 | ... # ERROR PIE790
| ^^^
|
help: Remove unnecessary `...`
1 | def check_isolation_level(mode: int) -> None:
2 | """Shouldn't try to fix either.""" # ERROR PYI021
- ... # ERROR PIE790
3 + # ERROR PIE790
29 changes: 28 additions & 1 deletion crates/ruff_python_semantic/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ use std::path::Path;
use bitflags::bitflags;
use rustc_hash::FxHashMap;

use ruff_python_ast::helpers::from_relative_import;
use ruff_python_ast::helpers::{from_relative_import, map_subscript};
use ruff_python_ast::name::{QualifiedName, UnqualifiedName};
use ruff_python_ast::{self as ast, Expr, ExprContext, PySourceType, Stmt};
use ruff_text_size::{Ranged, TextRange, TextSize};

use crate::Imported;
use crate::analyze::visibility;
use crate::binding::{
Binding, BindingFlags, BindingId, BindingKind, Bindings, Exceptions, FromImport, Import,
SubmoduleImport,
Expand Down Expand Up @@ -1406,6 +1407,17 @@ impl<'a> SemanticModel<'a> {
.expect("No statement found")
}

/// Return the [`NodeId`] for the given [`Stmt`].
pub fn statement_id(&self, stmt: &ast::Stmt) -> Option<NodeId> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this called anywhere now? I think we can revert this.

match self.node_id {
Some(node_id) => self
.nodes
.ancestor_ids(node_id)
.find(|node| self.statement(*node) == stmt),
None => None,
}
}

/// Returns an [`Iterator`] over the statements, starting from the given [`NodeId`].
/// through to any parents.
pub fn statements(&self, node_id: NodeId) -> impl Iterator<Item = &'a Stmt> + '_ {
Expand Down Expand Up @@ -1654,6 +1666,21 @@ impl<'a> SemanticModel<'a> {
}
}

/// Return `true` if the model is in a `typing.Protocol` subclass or an abstract
/// method.
pub fn in_protocol_or_abstract_method(&self) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably lean toward leaving this in the same file as before, unless there's a specific reason to move it out.

self.current_scopes().any(|scope| match scope.kind {
ScopeKind::Class(class_def) => class_def
.bases()
.iter()
.any(|base| self.match_typing_expr(map_subscript(base), "Protocol")),
ScopeKind::Function(function_def) => {
visibility::is_abstract(&function_def.decorator_list, self)
}
_ => false,
})
}

/// Returns `true` if `left` and `right` are in the same branches of an `if`, `match`, or
/// `try` statement.
///
Expand Down
Loading