Compare commits

..

25 Commits

Author SHA1 Message Date
Brent Westbrook
83a3bc4ee9 Bump 0.14.2 (#21051) 2025-10-23 15:17:22 -04:00
Brent Westbrook
155fd603e8 Document when a rule was added (#21035)
Summary
--

Inspired by #20859, this PR adds the version a rule was added, and the
file and line where it was defined, to `ViolationMetadata`. The file and
line just use the standard `file!` and `line!` macros, while the more
interesting version field uses a new `violation_metadata` attribute
parsed by our `ViolationMetadata` derive macro.

I moved the commit modifying all of the rule files to the end, so it
should be a lot easier to review by omitting that one.

As a curiosity and a bit of a sanity check, I also plotted the rule
numbers over time:

<img width="640" height="480" alt="image"
src="https://github.com/user-attachments/assets/75b0b5cc-3521-4d40-a395-8807e6f4925f"
/>

I think this looks pretty reasonable and avoids some of the artifacts
the earlier versions of the script ran into, such as the `rule`
sub-command not being available or `--explain` requiring a file
argument.

<details><summary>Script and summary data</summary>

```shell
gawk --csv '
NR > 1 {
    split($2, a, ".")
    major = a[1]; minor = a[2]; micro = a[3]
    # sum the number of rules added per minor version
    versions[minor] += 1
}
END {
    tot = 0
    for (i = 0; i <= 14; i++) {
        tot += versions[i]
        print i, tot
    }
}
' ruff_rules_metadata.csv > summary.dat
```

```
0 696
1 768
2 778
3 803
4 822
5 848
6 855
7 865
8 893
9 915
10 916
11 924
12 929
13 932
14 933
```

</details>

Test Plan
--

I built and viewed the documentation locally, and it looks pretty good!

<img width="1466" height="676" alt="image"
src="https://github.com/user-attachments/assets/5e227df4-7294-4d12-bdaa-31cac4e9ad5c"
/>

The spacing seems a bit awkward following the `h1` at the top, so I'm
wondering if this might look nicer as a footer in Ruff. The links work
well too:
- [v0.0.271](https://github.com/astral-sh/ruff/releases/tag/v0.0.271)
- [Related
issues](https://github.com/astral-sh/ruff/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20airflow-variable-name-task-id-mismatch)
- [View
source](https://github.com/astral-sh/ruff/blob/main/crates%2Fruff_linter%2Fsrc%2Frules%2Fairflow%2Frules%2Ftask_variable_name.rs#L34)

The last one even works on `main` now since it points to the
`derive(ViolationMetadata)` line.

In terms of binary size, this branch is a bit bigger than main with
38,654,520 bytes compared to 38,635,728 (+20 KB). I guess that's not
_too_ much of an increase, but I wanted to check since we're generating
a lot more code with macros.

---------

Co-authored-by: GiGaGon <107241144+MeGaGiGaGon@users.noreply.github.com>
2025-10-23 14:48:41 -04:00
Shunsuke Shibayama
48f1771877 [ty] fix infinite recursion with generic type aliases (#20969)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-10-23 14:14:30 +00:00
decorator-factory
4ca74593dd [ty] Consider type_check_only when ranking completions (#20910) 2025-10-23 15:09:13 +01:00
Alex Waygood
dab3d4e917 [ty] Improve invalid-argument-type diagnostics where a union type was provided (#21044) 2025-10-23 13:16:21 +00:00
Micha Reiser
01695513ce Disable npm caching for playground (#21039) 2025-10-23 11:51:29 +02:00
Micha Reiser
e92fd51a2c [ty] Add cycle handling to lazy_default (#20967) 2025-10-23 10:05:08 +02:00
Eric Mark Martin
c3631c78bd [ty] Add docstrings for ty_extensions functions (#21036)
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2025-10-23 09:50:21 +02:00
David Peter
589e8ac0d9 [ty] Infer type for implicit self parameters in method bodies (#20922)
## Summary

Infer a type of `Self` for unannotated `self` parameters in methods of
classes.

part of https://github.com/astral-sh/ty/issues/159

closes https://github.com/astral-sh/ty/issues/1081

## Conformance tests changes

```diff
+enums_member_values.py:85:9: error[invalid-assignment] Object of type `int` is not assignable to attribute `_value_` of type `str`
```
A true positive ✔️ 

```diff
-generics_self_advanced.py:35:9: error[type-assertion-failure] Argument does not have asserted type `Self@method2`
-generics_self_basic.py:14:9: error[type-assertion-failure] Argument does not have asserted type `Self@set_scale
```

Two false positives going away ✔️ 

```diff
+generics_syntax_infer_variance.py:82:9: error[invalid-assignment] Cannot assign to final attribute `x` on type `Self@__init__`
```

This looks like a true positive to me, even if it's not marked with `#
E` ✔️

```diff
+protocols_explicit.py:56:9: error[invalid-assignment] Object of type `tuple[int, int, str]` is not assignable to attribute `rgb` of type `tuple[int, int, int]`
```

True positive ✔️ 

```
+protocols_explicit.py:85:9: error[invalid-attribute-access] Cannot assign to ClassVar `cm1` from an instance of type `Self@__init__`
```

This looks like a true positive to me, even if it's not marked with `#
E`. But this is consistent with our understanding of `ClassVar`, I
think. ✔️

```py
+qualifiers_final_annotation.py:52:9: error[invalid-assignment] Cannot assign to final attribute `ID4` on type `Self@__init__`
+qualifiers_final_annotation.py:65:9: error[invalid-assignment] Cannot assign to final attribute `ID7` on type `Self@method1`
```

New true positives ✔️ 

```py
+qualifiers_final_annotation.py:52:9: error[invalid-assignment] Cannot assign to final attribute `ID4` on type `Self@__init__`
+qualifiers_final_annotation.py:57:13: error[invalid-assignment] Cannot assign to final attribute `ID6` on type `Self@__init__`
+qualifiers_final_annotation.py:59:13: error[invalid-assignment] Cannot assign to final attribute `ID6` on type `Self@__init__`
```

This is a new false positive, but that's a pre-existing issue on main
(if you annotate with `Self`):
https://play.ty.dev/3ee1c56d-7e13-43bb-811a-7a81e236e6ab  => reported
as https://github.com/astral-sh/ty/issues/1409

## Ecosystem

* There are 5931 new `unresolved-attribute` and 3292 new
`possibly-missing-attribute` attribute errors, way too many to look at
all of them. I randomly sampled 15 of these errors and found:
* 13 instances where there was simply no such attribute that we could
plausibly see. Sometimes [I didn't find it
anywhere](8644d886c6/openlibrary/plugins/openlibrary/tests/test_listapi.py (L33)).
Sometimes it was set externally on the object. Sometimes there was some
[`setattr` dynamicness going
on](a49f6b927d/setuptools/wheel.py (L88-L94)).
I would consider all of them to be true positives.
* 1 instance where [attribute was set on `obj` in
`__new__`](9e87b44fd4/sympy/tensor/array/array_comprehension.py (L45C1-L45C36)),
which we don't support yet
  * 1 instance [where the attribute was defined via `__slots__`

](e250ec0fc8/lib/spack/spack/vendor/pyrsistent/_pdeque.py (L48C5-L48C14))
* I see 44 instances [of the false positive
above](https://github.com/astral-sh/ty/issues/1409) with `Final`
instance attributes being set in `__init__`. I don't think this should
block this PR.

## Test Plan

New Markdown tests.

---------

Co-authored-by: Shaygan Hooshyari <sh.hooshyari@gmail.com>
2025-10-23 09:34:39 +02:00
Micha Reiser
76a55314e4 Fix rare multithreaded related hang (#21038) 2025-10-23 09:25:16 +02:00
Takayuki Maeda
6c18f18450 [ruff] Fix UP032 conversion for decimal ints with underscores (#21022)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Fixes #21017

Taught UP032’s parenthesize check to ignore underscores when inspecting
decimal integer literals so the converter emits `f"{(1_2).real}"`
instead of invalid syntax.

## Test Plan

Added test cases to UP032_2.py.

<!-- How was it tested? -->
2025-10-22 18:11:50 -04:00
William Woodruff
7ba176d395 ci: adjust zizmor config, bump dist (#20999)
## Summary

Also bumps `cargo dist` to 0.30, and moves us
back to the upstream copy of `dist` now that
the latest version has integrated our fork's
patches.

## Test Plan

See what happens in CI 🙂

---------

Signed-off-by: William Woodruff <william@astral.sh>
2025-10-22 17:48:17 -04:00
Douglas Creager
766ed5b5f3 [ty] Some more simplifications when rendering constraint sets (#21009)
This PR adds another useful simplification when rendering constraint
sets: `T = int` instead of `T = int ∧ T ≠ str`. (The "smaller"
constraint `T = int` implies the "larger" constraint `T ≠ str`.
Constraint set clauses are intersections, and if one constraint in a
clause implies another, we can throw away the "larger" constraint.)

While we're here, we also normalize the bounds of a constraint, so that
we equate e.g. `T ≤ int | str` with `T ≤ str | int`, and change the
ordering of BDD variables so that all constraints with the same typevar
are ordered adjacent to each other.

Lastly, we also add a new `display_graph` helper method that prints out
the full graph structure of a BDD.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-10-22 13:38:44 -04:00
David Peter
81c1d36088 [ty] Make attributes.md mdtests faster (#21030)
## Summary

That example was too extreme for debug mode.
2025-10-22 16:40:58 +02:00
Alex Waygood
20510e1d71 [ty] Set INSTA_FORCE_PASS and INSTA_OUTPUT environment variables from mdtest.py (#21029) 2025-10-22 15:32:14 +01:00
David Peter
58a68f1bbd [ty] Fall back to Divergent for deeply nested specializations (#20988)
## Summary

Fall back to `C[Divergent]` if we are trying to specialize `C[T]` with a
type that itself already contains deeply nested specialized generic
classes. This is a way to prevent infinite recursion for cases like
`self.x = [self.x]` where type inference for the implicit instance
attribute would not converge.

closes https://github.com/astral-sh/ty/issues/1383
closes https://github.com/astral-sh/ty/issues/837

## Test Plan

Regression tests.
2025-10-22 14:29:10 +02:00
Takayuki Maeda
2c9433796a [ruff] Autogenerate TypeParam nodes (#21028) 2025-10-22 14:06:24 +02:00
Alex Waygood
40148d7b11 [ty] Add assertions to ensure that we never call KnownClass::Tuple.to_instance() or similar (#21027) 2025-10-22 11:07:01 +00:00
Takayuki Maeda
6271fba1e1 [ruff] Auto generate ast Pattern nodes (#21024) 2025-10-22 08:24:34 +02:00
Takayuki Maeda
a51a0f16e4 [flake8-simplify] Skip SIM911 when unknown arguments are present (#20697)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
  requests.)
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Fixes #18778

Prevent SIM911 from triggering when zip() is called on .keys()/.values()
that take any positional or keyword arguments, so Ruff
never suggests the lossy rewrite.

## Test Plan

<!-- How was it tested? -->

Added a test case to SIM911.py.
2025-10-21 16:58:48 -04:00
Brent Westbrook
4b0fa5f270 Render a diagnostic for syntax errors introduced in formatter tests (#21021)
## Summary

I spun this out from #21005 because I thought it might be helpful
separately. It just renders a nice `Diagnostic` for syntax errors
pointing to the source of the error. This seemed a bit more helpful to
me than just the byte offset when working on #21005, and we had most of
the code around after #20443 anyway.

## Test Plan

This doesn't actually affect any passing tests, but here's an example of
the additional output I got when I broke the spacing after the `in`
token:

```
    error[internal-error]: Expected 'in', found name
      --> /home/brent/astral/ruff/crates/ruff_python_formatter/resources/test/fixtures/black/cases/cantfit.py:50:79
       |
    48 |     need_more_to_make_the_line_long_enough,
    49 | )
    50 | del ([], name_1, name_2), [(), [], name_4, name_3], name_1[[name_2 for name_1 inname_0]]
       |                                                                               ^^^^^^^^
    51 | del ()
       |
```

I just appended this to the other existing output for now.
2025-10-21 13:47:26 -04:00
Aria Desires
2e13b13012 [ty] Support goto-definition on vendored typeshed stubs (#21020)
This is an alternative to #21012 that more narrowly handles this logic
in the stub-mapping machinery rather than pervasively allowing us to
identify cached files as typeshed stubs. Much of the logic is the same
(pulling the logic out of ty_server so it can be reused).

I don't have a good sense for if one approach is "better" or "worse" in
terms of like, semantics and Weird Bugs that this can cause. This one is
just "less spooky in its broad consequences" and "less muddying of
separation of concerns" and puts the extra logic on a much colder path.
I won't be surprised if one day the previous implementation needs to be
revisited for its more sweeping effects but for now this is good.

Fixes https://github.com/astral-sh/ty/issues/1054
2025-10-21 13:38:40 -04:00
Micha Reiser
9d1ffd605c [ty] Implement go-to for binary and unary operators (#21001)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-10-21 19:25:41 +02:00
David Peter
2dbca6370b [ty] Avoid ever-growing default types (#20991)
## Summary

We currently panic in the seemingly rare case where the type of a
default value of a parameter depends on the callable itself:
```py
class C:
    def f(self: C):
        self.x = lambda a=self.x: a
```

Types of default values are only used for display reasons, and it's
unclear if we even want to track them (or if we should rather track the
actual value). So it didn't seem to me that we should spend a lot of
effort (and runtime) trying to achieve a theoretically correct type here
(which would be infinite).

Instead, we simply replace *nested* default types with `Unknown`, i.e.
only if the type of the default value is a callable itself.

closes https://github.com/astral-sh/ty/issues/1402

## Test Plan

Regression tests
2025-10-21 19:13:36 +02:00
Bhuminjay Soni
3dd78e711e [syntax-errors] Name is parameter and global (#20426)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->
This PR implements a new semantic syntax error where name is parameter &
global.

## Test Plan

<!-- How was it tested? -->
I have written inline test as directed in #17412

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-10-21 16:51:16 +00:00
889 changed files with 6118 additions and 3238 deletions

View File

@@ -18,6 +18,8 @@ env:
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
permissions: {}
jobs:
publish:
runs-on: ubuntu-latest
@@ -32,8 +34,7 @@ jobs:
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 22
cache: "npm"
cache-dependency-path: playground/package-lock.json
package-manager-cache: false
- uses: jetli/wasm-bindgen-action@20b33e20595891ab1a0ed73145d8a21fc96e7c29 # v0.2.0
- name: "Install Node dependencies"
run: npm ci

View File

@@ -38,6 +38,7 @@ jobs:
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: 22
package-manager-cache: false
- uses: jetli/wasm-bindgen-action@20b33e20595891ab1a0ed73145d8a21fc96e7c29 # v0.2.0
- name: "Install Node dependencies"
run: npm ci

View File

@@ -1,7 +1,6 @@
# This file was autogenerated by dist: https://github.com/astral-sh/cargo-dist
# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist
#
# Copyright 2022-2024, axodotdev
# Copyright 2025 Astral Software Inc.
# SPDX-License-Identifier: MIT or Apache-2.0
#
# CI that:
@@ -69,7 +68,7 @@ jobs:
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/cargo-dist/releases/download/v0.28.5-prerelease.1/cargo-dist-installer.sh | sh"
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.30.0/cargo-dist-installer.sh | sh"
- name: Cache dist
uses: actions/upload-artifact@6027e3dd177782cd8ab9af838c04fd81a07f1d47
with:

View File

@@ -34,10 +34,13 @@ jobs:
- name: Install the latest version of uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1
with:
workspaces: "ruff"
lookup-only: false # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
- name: Install Rust toolchain
run: rustup show

View File

@@ -30,10 +30,13 @@ jobs:
- name: Install the latest version of uv
uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
enable-cache: true # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1
with:
workspaces: "ruff"
lookup-only: false # zizmor: ignore[cache-poisoning] acceptable risk for CloudFlare pages artifact
- name: Install Rust toolchain
run: rustup show

13
.github/zizmor.yml vendored
View File

@@ -9,13 +9,18 @@ rules:
cache-poisoning:
ignore:
- build-docker.yml
- publish-playground.yml
- ty-ecosystem-analyzer.yaml
- ty-ecosystem-report.yaml
excessive-permissions:
# it's hard to test what the impact of removing these ignores would be
# without actually running the release workflow...
ignore:
- build-docker.yml
- publish-playground.yml
- publish-docs.yml
secrets-inherit:
# `cargo dist` makes extensive use of `secrets: inherit`,
# and we can't easily fix that until an upstream release changes that.
disable: true
template-injection:
ignore:
# like with `secrets-inherit`, `cargo dist` introduces some
# template injections. We've manually audited these usages for safety.
- release.yml

View File

@@ -101,8 +101,8 @@ repos:
# zizmor detects security vulnerabilities in GitHub Actions workflows.
# Additional configuration for the tool is found in `.github/zizmor.yml`
- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.11.0
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: v1.15.2
hooks:
- id: zizmor

View File

@@ -1,5 +1,53 @@
# Changelog
## 0.14.2
Released on 2025-10-23.
### Preview features
- \[`flake8-gettext`\] Resolve qualified names and built-in bindings (`INT001`, `INT002`, `INT003`) ([#19045](https://github.com/astral-sh/ruff/pull/19045))
### Bug fixes
- Avoid reusing nested, interpolated quotes before Python 3.12 ([#20930](https://github.com/astral-sh/ruff/pull/20930))
- Catch syntax errors in nested interpolations before Python 3.12 ([#20949](https://github.com/astral-sh/ruff/pull/20949))
- \[`fastapi`\] Handle ellipsis defaults in `FAST002` autofix ([#20810](https://github.com/astral-sh/ruff/pull/20810))
- \[`flake8-simplify`\] Skip `SIM911` when unknown arguments are present ([#20697](https://github.com/astral-sh/ruff/pull/20697))
- \[`pyupgrade`\] Always parenthesize assignment expressions in fix for `f-string` (`UP032`) ([#21003](https://github.com/astral-sh/ruff/pull/21003))
- \[`pyupgrade`\] Fix `UP032` conversion for decimal ints with underscores ([#21022](https://github.com/astral-sh/ruff/pull/21022))
- \[`fastapi`\] Skip autofix for keyword and `__debug__` path params (`FAST003`) ([#20960](https://github.com/astral-sh/ruff/pull/20960))
### Rule changes
- \[`flake8-bugbear`\] Skip `B905` and `B912` for fewer than two iterables and no starred arguments ([#20998](https://github.com/astral-sh/ruff/pull/20998))
- \[`ruff`\] Use `DiagnosticTag` for more `pyflakes` and `pandas` rules ([#20801](https://github.com/astral-sh/ruff/pull/20801))
### CLI
- Improve JSON output from `ruff rule` ([#20168](https://github.com/astral-sh/ruff/pull/20168))
### Documentation
- Add source to testimonial ([#20971](https://github.com/astral-sh/ruff/pull/20971))
- Document when a rule was added ([#21035](https://github.com/astral-sh/ruff/pull/21035))
### Other changes
- [syntax-errors] Name is parameter and global ([#20426](https://github.com/astral-sh/ruff/pull/20426))
- [syntax-errors] Alternative `match` patterns bind different names ([#20682](https://github.com/astral-sh/ruff/pull/20682))
### Contributors
- [@hengky-kurniawan-1](https://github.com/hengky-kurniawan-1)
- [@ShalokShalom](https://github.com/ShalokShalom)
- [@robsdedude](https://github.com/robsdedude)
- [@LoicRiegel](https://github.com/LoicRiegel)
- [@TaKO8Ki](https://github.com/TaKO8Ki)
- [@dylwil3](https://github.com/dylwil3)
- [@11happy](https://github.com/11happy)
- [@ntBre](https://github.com/ntBre)
## 0.14.1
Released on 2025-10-16.

16
Cargo.lock generated
View File

@@ -2835,7 +2835,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.14.1"
version = "0.14.2"
dependencies = [
"anyhow",
"argfile",
@@ -3092,7 +3092,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.14.1"
version = "0.14.2"
dependencies = [
"aho-corasick",
"anyhow",
@@ -3447,7 +3447,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.14.1"
version = "0.14.2"
dependencies = [
"console_error_panic_hook",
"console_log",
@@ -3563,7 +3563,7 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "salsa"
version = "0.24.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=ef9f9329be6923acd050c8dddd172e3bc93e8051#ef9f9329be6923acd050c8dddd172e3bc93e8051"
source = "git+https://github.com/salsa-rs/salsa.git?rev=d38145c29574758de7ffbe8a13cd4584c3b09161#d38145c29574758de7ffbe8a13cd4584c3b09161"
dependencies = [
"boxcar",
"compact_str",
@@ -3587,12 +3587,12 @@ dependencies = [
[[package]]
name = "salsa-macro-rules"
version = "0.24.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=ef9f9329be6923acd050c8dddd172e3bc93e8051#ef9f9329be6923acd050c8dddd172e3bc93e8051"
source = "git+https://github.com/salsa-rs/salsa.git?rev=d38145c29574758de7ffbe8a13cd4584c3b09161#d38145c29574758de7ffbe8a13cd4584c3b09161"
[[package]]
name = "salsa-macros"
version = "0.24.0"
source = "git+https://github.com/salsa-rs/salsa.git?rev=ef9f9329be6923acd050c8dddd172e3bc93e8051#ef9f9329be6923acd050c8dddd172e3bc93e8051"
source = "git+https://github.com/salsa-rs/salsa.git?rev=d38145c29574758de7ffbe8a13cd4584c3b09161#d38145c29574758de7ffbe8a13cd4584c3b09161"
dependencies = [
"proc-macro2",
"quote",
@@ -4376,6 +4376,7 @@ dependencies = [
"tracing",
"ty_project",
"ty_python_semantic",
"ty_vendored",
]
[[package]]
@@ -4433,10 +4434,12 @@ dependencies = [
"glob",
"hashbrown 0.16.0",
"indexmap",
"indoc",
"insta",
"itertools 0.14.0",
"memchr",
"ordermap",
"pretty_assertions",
"quickcheck",
"quickcheck_macros",
"ruff_annotate_snippets",
@@ -4504,7 +4507,6 @@ dependencies = [
"ty_ide",
"ty_project",
"ty_python_semantic",
"ty_vendored",
]
[[package]]

View File

@@ -146,7 +146,7 @@ regex-automata = { version = "0.4.9" }
rustc-hash = { version = "2.0.0" }
rustc-stable-hash = { version = "0.1.2" }
# When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml`
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "ef9f9329be6923acd050c8dddd172e3bc93e8051", default-features = false, features = [
salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "d38145c29574758de7ffbe8a13cd4584c3b09161", default-features = false, features = [
"compact_str",
"macros",
"salsa_unstable",

View File

@@ -147,8 +147,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.14.1/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.1/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.14.2/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.14.2/install.ps1 | iex"
```
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -181,7 +181,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.14.1
rev: v0.14.2
hooks:
# Run the linter.
- id: ruff-check

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.14.1"
version = "0.14.2"
publish = true
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -879,19 +879,7 @@ impl From<&FormatCommandError> for Diagnostic {
| FormatCommandError::Write(_, source_error) => {
Diagnostic::new(DiagnosticId::Io, Severity::Error, source_error)
}
FormatCommandError::Format(_, format_module_error) => match format_module_error {
FormatModuleError::ParseError(parse_error) => Diagnostic::new(
DiagnosticId::InternalError,
Severity::Error,
&parse_error.error,
),
FormatModuleError::FormatError(format_error) => {
Diagnostic::new(DiagnosticId::InternalError, Severity::Error, format_error)
}
FormatModuleError::PrintError(print_error) => {
Diagnostic::new(DiagnosticId::InternalError, Severity::Error, print_error)
}
},
FormatCommandError::Format(_, format_module_error) => format_module_error.into(),
FormatCommandError::RangeFormatNotebook(_) => Diagnostic::new(
DiagnosticId::InvalidCliOption,
Severity::Error,

View File

@@ -25,6 +25,7 @@ struct Explanation<'a> {
explanation: Option<&'a str>,
preview: bool,
status: RuleGroup,
source_location: SourceLocation,
}
impl<'a> Explanation<'a> {
@@ -43,6 +44,10 @@ impl<'a> Explanation<'a> {
explanation: rule.explanation(),
preview: rule.is_preview(),
status: rule.group(),
source_location: SourceLocation {
file: rule.file(),
line: rule.line(),
},
}
}
}
@@ -127,3 +132,14 @@ pub(crate) fn rules(format: HelpFormat) -> Result<()> {
}
Ok(())
}
/// The location of the rule's implementation in the Ruff source tree, relative to the repository
/// root.
///
/// For most rules this will point to the `#[derive(ViolationMetadata)]` line above the rule's
/// struct.
#[derive(Serialize)]
struct SourceLocation {
file: &'static str,
line: u32,
}

View File

@@ -953,7 +953,11 @@ fn rule_f401() {
#[test]
fn rule_f401_output_json() {
assert_cmd_snapshot!(ruff_cmd().args(["rule", "F401", "--output-format", "json"]));
insta::with_settings!({filters => vec![
(r#"("file": ")[^"]+(",)"#, "$1<FILE>$2"),
]}, {
assert_cmd_snapshot!(ruff_cmd().args(["rule", "F401", "--output-format", "json"]));
});
}
#[test]

View File

@@ -25,6 +25,14 @@ exit_code: 0
"fix_availability": "Sometimes",
"explanation": "## What it does\nChecks for unused imports.\n\n## Why is this bad?\nUnused imports add a performance overhead at runtime, and risk creating\nimport cycles. They also increase the cognitive load of reading the code.\n\nIf an import statement is used to check for the availability or existence\nof a module, consider using `importlib.util.find_spec` instead.\n\nIf an import statement is used to re-export a symbol as part of a module's\npublic interface, consider using a \"redundant\" import alias, which\ninstructs Ruff (and other tools) to respect the re-export, and avoid\nmarking it as unused, as in:\n\n```python\nfrom module import member as member\n```\n\nAlternatively, you can use `__all__` to declare a symbol as part of the module's\ninterface, as in:\n\n```python\n# __init__.py\nimport some_module\n\n__all__ = [\"some_module\"]\n```\n\n## Preview\nWhen [preview] is enabled (and certain simplifying assumptions\nare met), we analyze all import statements for a given module\nwhen determining whether an import is used, rather than simply\nthe last of these statements. This can result in both different and\nmore import statements being marked as unused.\n\nFor example, if a module consists of\n\n```python\nimport a\nimport a.b\n```\n\nthen both statements are marked as unused under [preview], whereas\nonly the second is marked as unused under stable behavior.\n\nAs another example, if a module consists of\n\n```python\nimport a.b\nimport a\n\na.b.foo()\n```\n\nthen a diagnostic will only be emitted for the first line under [preview],\nwhereas a diagnostic would only be emitted for the second line under\nstable behavior.\n\nNote that this behavior is somewhat subjective and is designed\nto conform to the developer's intuition rather than Python's actual\nexecution. To wit, the statement `import a.b` automatically executes\n`import a`, so in some sense `import a` is _always_ redundant\nin the presence of `import a.b`.\n\n\n## Fix safety\n\nFixes to remove unused imports are safe, except in `__init__.py` files.\n\nApplying fixes to `__init__.py` files is currently in preview. The fix offered depends on the\ntype of the unused import. Ruff will suggest a safe fix to export first-party imports with\neither a redundant alias or, if already present in the file, an `__all__` entry. If multiple\n`__all__` declarations are present, Ruff will not offer a fix. Ruff will suggest an unsafe fix\nto remove third-party and standard library imports -- the fix is unsafe because the module's\ninterface changes.\n\nSee [this FAQ section](https://docs.astral.sh/ruff/faq/#how-does-ruff-determine-which-of-my-imports-are-first-party-third-party-etc)\nfor more details on how Ruff\ndetermines whether an import is first or third-party.\n\n## Example\n\n```python\nimport numpy as np # unused import\n\n\ndef area(radius):\n return 3.14 * radius**2\n```\n\nUse instead:\n\n```python\ndef area(radius):\n return 3.14 * radius**2\n```\n\nTo check the availability of a module, use `importlib.util.find_spec`:\n\n```python\nfrom importlib.util import find_spec\n\nif find_spec(\"numpy\") is not None:\n print(\"numpy is installed\")\nelse:\n print(\"numpy is not installed\")\n```\n\n## Options\n- `lint.ignore-init-module-imports`\n- `lint.pyflakes.allowed-unused-imports`\n\n## References\n- [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement)\n- [Python documentation: `importlib.util.find_spec`](https://docs.python.org/3/library/importlib.html#importlib.util.find_spec)\n- [Typing documentation: interface conventions](https://typing.python.org/en/latest/spec/distributing.html#library-interface-public-and-private-symbols)\n\n[preview]: https://docs.astral.sh/ruff/preview/\n",
"preview": false,
"status": "Stable"
"status": {
"Stable": {
"since": "v0.0.18"
}
},
"source_location": {
"file": "<FILE>",
"line": 145
}
}
----- stderr -----

View File

@@ -667,7 +667,7 @@ fn attrs(criterion: &mut Criterion) {
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY313,
},
100,
110,
);
bench_project(&benchmark, criterion);
@@ -684,7 +684,7 @@ fn anyio(criterion: &mut Criterion) {
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY313,
},
100,
150,
);
bench_project(&benchmark, criterion);

View File

@@ -210,7 +210,7 @@ static TANJUN: Benchmark = Benchmark::new(
max_dep_date: "2025-06-17",
python_version: PythonVersion::PY312,
},
100,
320,
);
static STATIC_FRAME: Benchmark = Benchmark::new(
@@ -226,7 +226,7 @@ static STATIC_FRAME: Benchmark = Benchmark::new(
max_dep_date: "2025-08-09",
python_version: PythonVersion::PY311,
},
630,
750,
);
#[track_caller]

View File

@@ -8,6 +8,7 @@ use std::path::PathBuf;
use anyhow::Result;
use itertools::Itertools;
use regex::{Captures, Regex};
use ruff_linter::codes::RuleGroup;
use strum::IntoEnumIterator;
use ruff_linter::FixAvailability;
@@ -31,6 +32,47 @@ pub(crate) fn main(args: &Args) -> Result<()> {
let _ = writeln!(&mut output, "# {} ({})", rule.name(), rule.noqa_code());
let status_text = match rule.group() {
RuleGroup::Stable { since } => {
format!(
r#"Added in <a href="https://github.com/astral-sh/ruff/releases/tag/{since}">{since}</a>"#
)
}
RuleGroup::Preview { since } => {
format!(
r#"Preview (since <a href="https://github.com/astral-sh/ruff/releases/tag/{since}">{since}</a>)"#
)
}
RuleGroup::Deprecated { since } => {
format!(
r#"Deprecated (since <a href="https://github.com/astral-sh/ruff/releases/tag/{since}">{since}</a>)"#
)
}
RuleGroup::Removed { since } => {
format!(
r#"Removed (since <a href="https://github.com/astral-sh/ruff/releases/tag/{since}">{since}</a>)"#
)
}
};
let _ = writeln!(
&mut output,
r#"<small>
{status_text} ·
<a href="https://github.com/astral-sh/ruff/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20(%27{encoded_name}%27%20OR%20{rule_code})" target="_blank">Related issues</a> ·
<a href="https://github.com/astral-sh/ruff/blob/main/{file}#L{line}" target="_blank">View source</a>
</small>
"#,
encoded_name =
url::form_urlencoded::byte_serialize(rule.name().as_str().as_bytes())
.collect::<String>(),
rule_code = rule.noqa_code(),
file =
url::form_urlencoded::byte_serialize(rule.file().replace('\\', "/").as_bytes())
.collect::<String>(),
line = rule.line(),
);
let (linter, _) = Linter::parse_code(&rule.noqa_code().to_string()).unwrap();
if linter.url().is_some() {
let common_prefix: String = match linter.common_prefix() {

View File

@@ -32,20 +32,24 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
table_out.push('\n');
for rule in rules {
let status_token = match rule.group() {
RuleGroup::Removed => {
RuleGroup::Removed { since } => {
format!(
"<span {SYMBOL_STYLE} title='Rule has been removed'>{REMOVED_SYMBOL}</span>"
"<span {SYMBOL_STYLE} title='Rule was removed in {since}'>{REMOVED_SYMBOL}</span>"
)
}
RuleGroup::Deprecated => {
RuleGroup::Deprecated { since } => {
format!(
"<span {SYMBOL_STYLE} title='Rule has been deprecated'>{WARNING_SYMBOL}</span>"
"<span {SYMBOL_STYLE} title='Rule has been deprecated since {since}'>{WARNING_SYMBOL}</span>"
)
}
RuleGroup::Preview => {
format!("<span {SYMBOL_STYLE} title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
RuleGroup::Preview { since } => {
format!(
"<span {SYMBOL_STYLE} title='Rule has been in preview since {since}'>{PREVIEW_SYMBOL}</span>"
)
}
RuleGroup::Stable { since } => {
format!("<span {SYMBOL_STYLE} title='Rule has been stable since {since}'></span>")
}
RuleGroup::Stable => format!("<span {SYMBOL_STYLE}></span>"),
};
let fix_token = match rule.fixable() {

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_linter"
version = "0.14.1"
version = "0.14.2"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -34,3 +34,7 @@ def foo():
# https://github.com/astral-sh/ruff/issues/18776
flag_stars = {}
for country, stars in(zip)(flag_stars.keys(), flag_stars.values()):...
# Regression test for https://github.com/astral-sh/ruff/issues/18778
d = {}
for country, stars in zip(d.keys(*x), d.values("hello")):...

View File

@@ -26,3 +26,8 @@
"{.real}".format({1, 2})
"{.real}".format({1: 2, 3: 4})
"{}".format((i for i in range(2)))
# https://github.com/astral-sh/ruff/issues/21017
"{.real}".format(1_2)
"{0.real}".format(1_2)
"{a.real}".format(a=1_2)

View File

@@ -725,6 +725,7 @@ impl SemanticSyntaxContext for Checker<'_> {
| SemanticSyntaxErrorKind::WriteToDebug(_)
| SemanticSyntaxErrorKind::DifferentMatchPatternBindings
| SemanticSyntaxErrorKind::InvalidExpression(..)
| SemanticSyntaxErrorKind::GlobalParameter(_)
| SemanticSyntaxErrorKind::DuplicateMatchKey(_)
| SemanticSyntaxErrorKind::DuplicateMatchClassAttribute(_)
| SemanticSyntaxErrorKind::InvalidStarExpression
@@ -846,6 +847,26 @@ impl SemanticSyntaxContext for Checker<'_> {
}
false
}
fn is_bound_parameter(&self, name: &str) -> bool {
for scope in self.semantic.current_scopes() {
match scope.kind {
ScopeKind::Class(_) => return false,
ScopeKind::Function(ast::StmtFunctionDef { parameters, .. })
| ScopeKind::Lambda(ast::ExprLambda {
parameters: Some(parameters),
..
}) => return parameters.includes(name),
ScopeKind::Lambda(_)
| ScopeKind::Generator { .. }
| ScopeKind::Module
| ScopeKind::Type
| ScopeKind::DunderClassCell => {}
}
}
false
}
}
impl<'a> Visitor<'a> for Checker<'a> {

File diff suppressed because it is too large Load Diff

View File

@@ -1040,6 +1040,42 @@ mod tests {
PythonVersion::PY310,
"DuplicateMatchKey"
)]
#[test_case(
"global_parameter",
"
def f(a):
global a
def g(a):
if True:
global a
def h(a):
def inner():
global a
def i(a):
try:
global a
except Exception:
pass
def f(a):
a = 1
global a
def f(a):
a = 1
a = 2
global a
def f(a):
class Inner:
global a # ok
",
PythonVersion::PY310,
"GlobalParameter"
)]
#[test_case(
"duplicate_match_class_attribute",
"

View File

@@ -150,7 +150,7 @@ mod tests {
for rule in Rule::iter() {
let (code, group) = (rule.noqa_code(), rule.group());
if matches!(group, RuleGroup::Removed) {
if matches!(group, RuleGroup::Removed { .. }) {
continue;
}

View File

@@ -209,15 +209,15 @@ impl RuleSelector {
self.all_rules().filter(move |rule| {
match rule.group() {
// Always include stable rules
RuleGroup::Stable => true,
RuleGroup::Stable { .. } => true,
// Enabling preview includes all preview rules unless explicit selection is turned on
RuleGroup::Preview => {
RuleGroup::Preview { .. } => {
preview_enabled && (self.is_exact() || !preview_require_explicit)
}
// Deprecated rules are excluded by default unless explicitly selected
RuleGroup::Deprecated => !preview_enabled && self.is_exact(),
RuleGroup::Deprecated { .. } => !preview_enabled && self.is_exact(),
// Removed rules are included if explicitly selected but will error downstream
RuleGroup::Removed => self.is_exact(),
RuleGroup::Removed { .. } => self.is_exact(),
}
})
}

View File

@@ -41,6 +41,7 @@ use crate::checkers::ast::Checker;
/// dag = DAG(dag_id="my_dag", schedule=timedelta(days=1))
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct AirflowDagNoScheduleArgument;
impl Violation for AirflowDagNoScheduleArgument {

View File

@@ -35,6 +35,7 @@ use crate::{FixAvailability, Violation};
/// fab_auth_manager_app = FabAuthManager().get_fastapi_app()
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct Airflow3MovedToProvider<'a> {
deprecated: QualifiedName<'a>,
replacement: ProviderReplacement,

View File

@@ -41,6 +41,7 @@ use ruff_text_size::TextRange;
/// yesterday = today - timedelta(days=1)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct Airflow3Removal {
deprecated: String,
replacement: Replacement,

View File

@@ -51,6 +51,7 @@ use ruff_text_size::TextRange;
/// )
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct Airflow3SuggestedToMoveToProvider<'a> {
deprecated: QualifiedName<'a>,
replacement: ProviderReplacement,

View File

@@ -37,6 +37,7 @@ use ruff_text_size::TextRange;
/// Asset(uri="test://test/")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct Airflow3SuggestedUpdate {
deprecated: String,
replacement: Replacement,

View File

@@ -32,6 +32,7 @@ use crate::checkers::ast::Checker;
/// my_task = PythonOperator(task_id="my_task")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.271")]
pub(crate) struct AirflowVariableNameTaskIdMismatch {
task_id: String,
}

View File

@@ -30,6 +30,7 @@ use crate::rules::eradicate::detection::comment_contains_code;
///
/// [#4845]: https://github.com/astral-sh/ruff/issues/4845
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.145")]
pub(crate) struct CommentedOutCode;
impl Violation for CommentedOutCode {

View File

@@ -79,6 +79,7 @@ use ruff_python_ast::PythonVersion;
/// [typing-annotated]: https://docs.python.org/3/library/typing.html#typing.Annotated
/// [typing-extensions]: https://typing-extensions.readthedocs.io/en/stable/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.8.0")]
pub(crate) struct FastApiNonAnnotatedDependency {
py_version: PythonVersion,
}

View File

@@ -59,6 +59,7 @@ use crate::{AlwaysFixableViolation, Fix};
/// return item
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.8.0")]
pub(crate) struct FastApiRedundantResponseModel;
impl AlwaysFixableViolation for FastApiRedundantResponseModel {

View File

@@ -64,6 +64,7 @@ use crate::{FixAvailability, Violation};
/// This rule's fix is marked as unsafe, as modifying a function signature can
/// change the behavior of the code.
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.10.0")]
pub(crate) struct FastApiUnusedPathParameter {
arg_name: String,
function_name: String,

View File

@@ -41,6 +41,7 @@ use crate::rules::flake8_2020::helpers::is_sys;
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionCmpStr3;
impl Violation for SysVersionCmpStr3 {
@@ -91,6 +92,7 @@ impl Violation for SysVersionCmpStr3 {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionInfo0Eq3 {
eq: bool,
}
@@ -137,6 +139,7 @@ impl Violation for SysVersionInfo0Eq3 {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionInfo1CmpInt;
impl Violation for SysVersionInfo1CmpInt {
@@ -179,6 +182,7 @@ impl Violation for SysVersionInfo1CmpInt {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionInfoMinorCmpInt;
impl Violation for SysVersionInfoMinorCmpInt {
@@ -222,6 +226,7 @@ impl Violation for SysVersionInfoMinorCmpInt {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionCmpStr10;
impl Violation for SysVersionCmpStr10 {

View File

@@ -36,6 +36,7 @@ use crate::checkers::ast::Checker;
/// - [Six documentation: `six.PY2`](https://six.readthedocs.io/#six.PY2)
/// - [Six documentation: `six.PY3`](https://six.readthedocs.io/#six.PY3)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SixPY3;
impl Violation for SixPY3 {

View File

@@ -38,6 +38,7 @@ use crate::rules::flake8_2020::helpers::is_sys;
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionSlice3;
impl Violation for SysVersionSlice3 {
@@ -78,6 +79,7 @@ impl Violation for SysVersionSlice3 {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersion2;
impl Violation for SysVersion2 {
@@ -118,6 +120,7 @@ impl Violation for SysVersion2 {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersion0;
impl Violation for SysVersion0 {
@@ -158,6 +161,7 @@ impl Violation for SysVersion0 {
/// - [Python documentation: `sys.version`](https://docs.python.org/3/library/sys.html#sys.version)
/// - [Python documentation: `sys.version_info`](https://docs.python.org/3/library/sys.html#sys.version_info)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.113")]
pub(crate) struct SysVersionSlice1;
impl Violation for SysVersionSlice1 {

View File

@@ -38,6 +38,7 @@ use crate::{Edit, Fix, FixAvailability, Violation};
/// ## Options
/// - `lint.flake8-annotations.suppress-dummy-args`
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingTypeFunctionArgument {
name: String,
}
@@ -73,6 +74,7 @@ impl Violation for MissingTypeFunctionArgument {
/// ## Options
/// - `lint.flake8-annotations.suppress-dummy-args`
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingTypeArgs {
name: String,
}
@@ -108,6 +110,7 @@ impl Violation for MissingTypeArgs {
/// ## Options
/// - `lint.flake8-annotations.suppress-dummy-args`
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingTypeKwargs {
name: String,
}
@@ -149,6 +152,7 @@ impl Violation for MissingTypeKwargs {
/// ```
#[derive(ViolationMetadata)]
#[deprecated(note = "ANN101 has been removed")]
#[violation_metadata(removed_since = "0.8.0")]
pub(crate) struct MissingTypeSelf;
#[expect(deprecated)]
@@ -193,6 +197,7 @@ impl Violation for MissingTypeSelf {
/// ```
#[derive(ViolationMetadata)]
#[deprecated(note = "ANN102 has been removed")]
#[violation_metadata(removed_since = "0.8.0")]
pub(crate) struct MissingTypeCls;
#[expect(deprecated)]
@@ -236,6 +241,7 @@ impl Violation for MissingTypeCls {
///
/// - `lint.typing-extensions`
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingReturnTypeUndocumentedPublicFunction {
name: String,
annotation: Option<String>,
@@ -289,6 +295,7 @@ impl Violation for MissingReturnTypeUndocumentedPublicFunction {
///
/// - `lint.typing-extensions`
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingReturnTypePrivateFunction {
name: String,
annotation: Option<String>,
@@ -345,6 +352,7 @@ impl Violation for MissingReturnTypePrivateFunction {
/// self.x = x
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingReturnTypeSpecialMethod {
name: String,
annotation: Option<String>,
@@ -392,6 +400,7 @@ impl Violation for MissingReturnTypeSpecialMethod {
/// return 1
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingReturnTypeStaticMethod {
name: String,
annotation: Option<String>,
@@ -439,6 +448,7 @@ impl Violation for MissingReturnTypeStaticMethod {
/// return 1
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.105")]
pub(crate) struct MissingReturnTypeClassMethod {
name: String,
annotation: Option<String>,
@@ -508,6 +518,7 @@ impl Violation for MissingReturnTypeClassMethod {
/// - [Python documentation: `typing.Any`](https://docs.python.org/3/library/typing.html#typing.Any)
/// - [Mypy documentation: The Any type](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.108")]
pub(crate) struct AnyType {
name: String,
}

View File

@@ -42,6 +42,7 @@ use crate::rules::flake8_async::helpers::AsyncModule;
/// - [`anyio` events](https://anyio.readthedocs.io/en/latest/api.html#anyio.Event)
/// - [`trio` events](https://trio.readthedocs.io/en/latest/reference-core.html#trio.Event)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct AsyncBusyWait {
module: AsyncModule,
}

View File

@@ -65,6 +65,7 @@ use ruff_python_ast::PythonVersion;
///
/// ["structured concurrency"]: https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/#timeouts-and-cancellation
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct AsyncFunctionWithTimeout {
module: AsyncModule,
}

View File

@@ -49,6 +49,7 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
/// )
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct AsyncZeroSleep {
module: AsyncModule,
}

View File

@@ -38,6 +38,7 @@ use crate::checkers::ast::Checker;
/// ...
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct BlockingHttpCallInAsyncFunction;
impl Violation for BlockingHttpCallInAsyncFunction {

View File

@@ -37,6 +37,7 @@ use crate::checkers::ast::Checker;
/// response = await client.get(...)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.12.11")]
pub(crate) struct BlockingHttpCallHttpxInAsyncFunction {
name: String,
call: String,

View File

@@ -33,6 +33,7 @@ use crate::checkers::ast::Checker;
/// username = await loop.run_in_executor(None, input, "Username:")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.12.12")]
pub(crate) struct BlockingInputInAsyncFunction;
impl Violation for BlockingInputInAsyncFunction {

View File

@@ -34,6 +34,7 @@ use crate::checkers::ast::Checker;
/// contents = await f.read()
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct BlockingOpenCallInAsyncFunction;
impl Violation for BlockingOpenCallInAsyncFunction {

View File

@@ -47,6 +47,7 @@ use ruff_text_size::Ranged;
/// new_path = os.path.join("/tmp/src/", path)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.13.2")]
pub(crate) struct BlockingPathMethodInAsyncFunction {
path_library: String,
}

View File

@@ -37,6 +37,7 @@ use crate::checkers::ast::Checker;
/// asyncio.create_subprocess_shell(cmd)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct CreateSubprocessInAsyncFunction;
impl Violation for CreateSubprocessInAsyncFunction {
@@ -76,6 +77,7 @@ impl Violation for CreateSubprocessInAsyncFunction {
/// asyncio.create_subprocess_shell(cmd)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct RunProcessInAsyncFunction;
impl Violation for RunProcessInAsyncFunction {
@@ -120,6 +122,7 @@ impl Violation for RunProcessInAsyncFunction {
/// await asyncio.loop.run_in_executor(None, wait_for_process)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct WaitForProcessInAsyncFunction;
impl Violation for WaitForProcessInAsyncFunction {

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// await asyncio.sleep(1)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct BlockingSleepInAsyncFunction;
impl Violation for BlockingSleepInAsyncFunction {

View File

@@ -45,6 +45,7 @@ use crate::rules::flake8_async::helpers::MethodName;
/// - [`anyio` timeouts](https://anyio.readthedocs.io/en/stable/cancellation.html)
/// - [`trio` timeouts](https://trio.readthedocs.io/en/stable/reference-core.html#cancellation-and-timeouts)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.269")]
pub(crate) struct CancelScopeNoCheckpoint {
method_name: MethodName,
}

View File

@@ -39,6 +39,7 @@ use crate::{Edit, Fix, FixAvailability, Violation};
///
/// This fix is marked as unsafe as it changes program behavior.
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.13.0")]
pub(crate) struct LongSleepNotForever {
module: AsyncModule,
}

View File

@@ -38,6 +38,7 @@ use crate::{Edit, Fix, FixAvailability, Violation};
/// This rule's fix is marked as unsafe, as adding an `await` to a function
/// call changes its semantics and runtime behavior.
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct TrioSyncCall {
method_name: MethodName,
}

View File

@@ -33,6 +33,7 @@ use crate::checkers::ast::Checker;
/// raise ValueError("Expected positive value.")
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct Assert;
impl Violation for Assert {

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `stat`](https://docs.python.org/3/library/stat.html)
/// - [Common Weakness Enumeration: CWE-732](https://cwe.mitre.org/data/definitions/732.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.211")]
pub(crate) struct BadFilePermissions {
reason: Reason,
}

View File

@@ -34,6 +34,7 @@ use crate::checkers::ast::Checker;
/// - [Django documentation: SQL injection protection](https://docs.djangoproject.com/en/dev/topics/security/#sql-injection-protection)
/// - [Common Weakness Enumeration: CWE-89](https://cwe.mitre.org/data/definitions/89.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.5.0")]
pub(crate) struct DjangoExtra;
impl Violation for DjangoExtra {

View File

@@ -25,6 +25,7 @@ use crate::checkers::ast::Checker;
/// - [Django documentation: SQL injection protection](https://docs.djangoproject.com/en/dev/topics/security/#sql-injection-protection)
/// - [Common Weakness Enumeration: CWE-89](https://cwe.mitre.org/data/definitions/89.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct DjangoRawSql;
impl Violation for DjangoRawSql {

View File

@@ -22,6 +22,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `exec`](https://docs.python.org/3/library/functions.html#exec)
/// - [Common Weakness Enumeration: CWE-78](https://cwe.mitre.org/data/definitions/78.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct ExecBuiltin;
impl Violation for ExecBuiltin {

View File

@@ -39,6 +39,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Flask documentation: Debug Mode](https://flask.palletsprojects.com/en/latest/quickstart/#debug-mode)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct FlaskDebugTrue;
impl Violation for FlaskDebugTrue {

View File

@@ -27,6 +27,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Common Weakness Enumeration: CWE-200](https://cwe.mitre.org/data/definitions/200.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct HardcodedBindAllInterfaces;
impl Violation for HardcodedBindAllInterfaces {

View File

@@ -39,6 +39,7 @@ use crate::rules::flake8_bandit::helpers::{matches_password_name, string_literal
/// ## References
/// - [Common Weakness Enumeration: CWE-259](https://cwe.mitre.org/data/definitions/259.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct HardcodedPasswordDefault {
name: String,
}

View File

@@ -35,6 +35,7 @@ use crate::rules::flake8_bandit::helpers::{matches_password_name, string_literal
/// ## References
/// - [Common Weakness Enumeration: CWE-259](https://cwe.mitre.org/data/definitions/259.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct HardcodedPasswordFuncArg {
name: String,
}

View File

@@ -34,6 +34,7 @@ use crate::rules::flake8_bandit::helpers::{matches_password_name, string_literal
/// ## References
/// - [Common Weakness Enumeration: CWE-259](https://cwe.mitre.org/data/definitions/259.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.116")]
pub(crate) struct HardcodedPasswordString {
name: String,
}

View File

@@ -45,6 +45,7 @@ static SQL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
/// - [B608: Test for SQL injection](https://bandit.readthedocs.io/en/latest/plugins/b608_hardcoded_sql_expressions.html)
/// - [psycopg3: Server-side binding](https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html#server-side-binding)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.245")]
pub(crate) struct HardcodedSQLExpression;
impl Violation for HardcodedSQLExpression {

View File

@@ -40,6 +40,7 @@ use crate::checkers::ast::Checker;
/// - [Common Weakness Enumeration: CWE-379](https://cwe.mitre.org/data/definitions/379.html)
/// - [Python documentation: `tempfile`](https://docs.python.org/3/library/tempfile.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.211")]
pub(crate) struct HardcodedTempFile {
string: String,
}

View File

@@ -74,6 +74,7 @@ use crate::rules::flake8_bandit::helpers::string_literal;
/// - [Common Weakness Enumeration: CWE-328](https://cwe.mitre.org/data/definitions/328.html)
/// - [Common Weakness Enumeration: CWE-916](https://cwe.mitre.org/data/definitions/916.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.212")]
pub(crate) struct HashlibInsecureHashFunction {
library: String,
string: String,

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// - [Jinja documentation: API](https://jinja.palletsprojects.com/en/latest/api/#autoescaping)
/// - [Common Weakness Enumeration: CWE-94](https://cwe.mitre.org/data/definitions/94.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.220")]
pub(crate) struct Jinja2AutoescapeFalse {
value: bool,
}

View File

@@ -25,6 +25,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Python documentation: `logging.config.listen()`](https://docs.python.org/3/library/logging.config.html#logging.config.listen)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.231")]
pub(crate) struct LoggingConfigInsecureListen;
impl Violation for LoggingConfigInsecureListen {

View File

@@ -33,6 +33,7 @@ use crate::checkers::ast::Checker;
/// - [OpenStack security: Cross site scripting XSS](https://security.openstack.org/guidelines/dg_cross-site-scripting-xss.html)
/// - [Common Weakness Enumeration: CWE-80](https://cwe.mitre.org/data/definitions/80.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct MakoTemplates;
impl Violation for MakoTemplates {

View File

@@ -26,6 +26,7 @@ use crate::checkers::ast::Checker;
/// - [Common Weakness Enumeration: CWE-78](https://cwe.mitre.org/data/definitions/78.html)
/// - [Paramiko documentation: `SSHClient.exec_command()`](https://docs.paramiko.org/en/stable/api/client.html#paramiko.client.SSHClient.exec_command)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.270")]
pub(crate) struct ParamikoCall;
impl Violation for ParamikoCall {

View File

@@ -31,6 +31,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Common Weakness Enumeration: CWE-295](https://cwe.mitre.org/data/definitions/295.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.213")]
pub(crate) struct RequestWithNoCertValidation {
string: String,
}

View File

@@ -33,6 +33,7 @@ use crate::checkers::ast::Checker;
/// - [Requests documentation: Timeouts](https://requests.readthedocs.io/en/latest/user/advanced/#timeouts)
/// - [httpx documentation: Timeouts](https://www.python-httpx.org/advanced/timeouts/)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.213")]
pub(crate) struct RequestWithoutTimeout {
implicit: bool,
module: String,

View File

@@ -37,6 +37,7 @@ use crate::{
/// - [Python documentation: `subprocess` — Subprocess management](https://docs.python.org/3/library/subprocess.html)
/// - [Common Weakness Enumeration: CWE-78](https://cwe.mitre.org/data/definitions/78.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct SubprocessPopenWithShellEqualsTrue {
safety: Safety,
is_exact: bool,
@@ -79,6 +80,7 @@ impl Violation for SubprocessPopenWithShellEqualsTrue {
///
/// [#4045]: https://github.com/astral-sh/ruff/issues/4045
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct SubprocessWithoutShellEqualsTrue;
impl Violation for SubprocessWithoutShellEqualsTrue {
@@ -117,6 +119,7 @@ impl Violation for SubprocessWithoutShellEqualsTrue {
/// ## References
/// - [Python documentation: Security Considerations](https://docs.python.org/3/library/subprocess.html#security-considerations)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct CallWithShellEqualsTrue {
is_exact: bool,
}
@@ -169,6 +172,7 @@ impl Violation for CallWithShellEqualsTrue {
/// ## References
/// - [Python documentation: `subprocess`](https://docs.python.org/3/library/subprocess.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct StartProcessWithAShell {
safety: Safety,
}
@@ -210,6 +214,7 @@ impl Violation for StartProcessWithAShell {
///
/// [S605]: https://docs.astral.sh/ruff/rules/start-process-with-a-shell
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct StartProcessWithNoShell;
impl Violation for StartProcessWithNoShell {
@@ -245,6 +250,7 @@ impl Violation for StartProcessWithNoShell {
/// - [Python documentation: `subprocess.Popen()`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen)
/// - [Common Weakness Enumeration: CWE-426](https://cwe.mitre.org/data/definitions/426.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.262")]
pub(crate) struct StartProcessWithPartialPath;
impl Violation for StartProcessWithPartialPath {
@@ -278,6 +284,7 @@ impl Violation for StartProcessWithPartialPath {
/// ## References
/// - [Common Weakness Enumeration: CWE-78](https://cwe.mitre.org/data/definitions/78.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.271")]
pub(crate) struct UnixCommandWildcardInjection;
impl Violation for UnixCommandWildcardInjection {

View File

@@ -31,6 +31,7 @@ use crate::checkers::ast::Checker;
/// - [Cybersecurity and Infrastructure Security Agency (CISA): Alert TA17-156A](https://www.cisa.gov/news-events/alerts/2017/06/05/reducing-risk-snmp-abuse)
/// - [Common Weakness Enumeration: CWE-319](https://cwe.mitre.org/data/definitions/319.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.218")]
pub(crate) struct SnmpInsecureVersion;
impl Violation for SnmpInsecureVersion {

View File

@@ -29,6 +29,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Common Weakness Enumeration: CWE-319](https://cwe.mitre.org/data/definitions/319.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.218")]
pub(crate) struct SnmpWeakCryptography;
impl Violation for SnmpWeakCryptography {

View File

@@ -34,6 +34,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [Paramiko documentation: set_missing_host_key_policy](https://docs.paramiko.org/en/latest/api/client.html#paramiko.client.SSHClient.set_missing_host_key_policy)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct SSHNoHostKeyVerification;
impl Violation for SSHNoHostKeyVerification {

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct SslInsecureVersion {
protocol: String,
}

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// def func(version=ssl.PROTOCOL_TLSv1_2): ...
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct SslWithBadDefaults {
protocol: String,
}

View File

@@ -26,6 +26,7 @@ use crate::checkers::ast::Checker;
/// ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct SslWithNoVersion;
impl Violation for SslWithNoVersion {

View File

@@ -51,6 +51,7 @@ use crate::preview::is_suspicious_function_reference_enabled;
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousPickleUsage;
impl Violation for SuspiciousPickleUsage {
@@ -100,6 +101,7 @@ impl Violation for SuspiciousPickleUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousMarshalUsage;
impl Violation for SuspiciousMarshalUsage {
@@ -150,6 +152,7 @@ impl Violation for SuspiciousMarshalUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousInsecureHashUsage;
impl Violation for SuspiciousInsecureHashUsage {
@@ -192,6 +195,7 @@ impl Violation for SuspiciousInsecureHashUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousInsecureCipherUsage;
impl Violation for SuspiciousInsecureCipherUsage {
@@ -236,6 +240,7 @@ impl Violation for SuspiciousInsecureCipherUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousInsecureCipherModeUsage;
impl Violation for SuspiciousInsecureCipherModeUsage {
@@ -285,6 +290,7 @@ impl Violation for SuspiciousInsecureCipherModeUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousMktempUsage;
impl Violation for SuspiciousMktempUsage {
@@ -325,6 +331,7 @@ impl Violation for SuspiciousMktempUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousEvalUsage;
impl Violation for SuspiciousEvalUsage {
@@ -378,6 +385,7 @@ impl Violation for SuspiciousEvalUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousMarkSafeUsage;
impl Violation for SuspiciousMarkSafeUsage {
@@ -430,6 +438,7 @@ impl Violation for SuspiciousMarkSafeUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousURLOpenUsage;
impl Violation for SuspiciousURLOpenUsage {
@@ -472,6 +481,7 @@ impl Violation for SuspiciousURLOpenUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousNonCryptographicRandomUsage;
impl Violation for SuspiciousNonCryptographicRandomUsage {
@@ -516,6 +526,7 @@ impl Violation for SuspiciousNonCryptographicRandomUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLCElementTreeUsage;
impl Violation for SuspiciousXMLCElementTreeUsage {
@@ -560,6 +571,7 @@ impl Violation for SuspiciousXMLCElementTreeUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLElementTreeUsage;
impl Violation for SuspiciousXMLElementTreeUsage {
@@ -604,6 +616,7 @@ impl Violation for SuspiciousXMLElementTreeUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLExpatReaderUsage;
impl Violation for SuspiciousXMLExpatReaderUsage {
@@ -648,6 +661,7 @@ impl Violation for SuspiciousXMLExpatReaderUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLExpatBuilderUsage;
impl Violation for SuspiciousXMLExpatBuilderUsage {
@@ -692,6 +706,7 @@ impl Violation for SuspiciousXMLExpatBuilderUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLSaxUsage;
impl Violation for SuspiciousXMLSaxUsage {
@@ -736,6 +751,7 @@ impl Violation for SuspiciousXMLSaxUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLMiniDOMUsage;
impl Violation for SuspiciousXMLMiniDOMUsage {
@@ -780,6 +796,7 @@ impl Violation for SuspiciousXMLMiniDOMUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousXMLPullDOMUsage;
impl Violation for SuspiciousXMLPullDOMUsage {
@@ -821,6 +838,7 @@ impl Violation for SuspiciousXMLPullDOMUsage {
/// [preview]: https://docs.astral.sh/ruff/preview/
/// [deprecated]: https://pypi.org/project/defusedxml/0.8.0rc2/#defusedxml-lxml
#[derive(ViolationMetadata)]
#[violation_metadata(removed_since = "0.12.0")]
pub(crate) struct SuspiciousXMLETreeUsage;
impl Violation for SuspiciousXMLETreeUsage {
@@ -867,6 +885,7 @@ impl Violation for SuspiciousXMLETreeUsage {
/// [PEP 476]: https://peps.python.org/pep-0476/
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousUnverifiedContextUsage;
impl Violation for SuspiciousUnverifiedContextUsage {
@@ -892,6 +911,7 @@ impl Violation for SuspiciousUnverifiedContextUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousTelnetUsage;
impl Violation for SuspiciousTelnetUsage {
@@ -917,6 +937,7 @@ impl Violation for SuspiciousTelnetUsage {
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.258")]
pub(crate) struct SuspiciousFTPLibUsage;
impl Violation for SuspiciousFTPLibUsage {

View File

@@ -25,6 +25,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `telnetlib` - Telnet client](https://docs.python.org/3.12/library/telnetlib.html#module-telnetlib)
/// - [PEP 594: `telnetlib`](https://peps.python.org/pep-0594/#telnetlib)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousTelnetlibImport;
impl Violation for SuspiciousTelnetlibImport {
@@ -49,6 +50,7 @@ impl Violation for SuspiciousTelnetlibImport {
/// ## References
/// - [Python documentation: `ftplib` - FTP protocol client](https://docs.python.org/3/library/ftplib.html)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousFtplibImport;
impl Violation for SuspiciousFtplibImport {
@@ -74,6 +76,7 @@ impl Violation for SuspiciousFtplibImport {
/// ## References
/// - [Python documentation: `pickle` — Python object serialization](https://docs.python.org/3/library/pickle.html)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousPickleImport;
impl Violation for SuspiciousPickleImport {
@@ -95,6 +98,7 @@ impl Violation for SuspiciousPickleImport {
/// import subprocess
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousSubprocessImport;
impl Violation for SuspiciousSubprocessImport {
@@ -118,6 +122,7 @@ impl Violation for SuspiciousSubprocessImport {
/// import xml.etree.cElementTree
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlEtreeImport;
impl Violation for SuspiciousXmlEtreeImport {
@@ -141,6 +146,7 @@ impl Violation for SuspiciousXmlEtreeImport {
/// import xml.sax
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlSaxImport;
impl Violation for SuspiciousXmlSaxImport {
@@ -164,6 +170,7 @@ impl Violation for SuspiciousXmlSaxImport {
/// import xml.dom.expatbuilder
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlExpatImport;
impl Violation for SuspiciousXmlExpatImport {
@@ -187,6 +194,7 @@ impl Violation for SuspiciousXmlExpatImport {
/// import xml.dom.minidom
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlMinidomImport;
impl Violation for SuspiciousXmlMinidomImport {
@@ -210,6 +218,7 @@ impl Violation for SuspiciousXmlMinidomImport {
/// import xml.dom.pulldom
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlPulldomImport;
impl Violation for SuspiciousXmlPulldomImport {
@@ -240,6 +249,7 @@ impl Violation for SuspiciousXmlPulldomImport {
///
/// [deprecated]: https://github.com/tiran/defusedxml/blob/c7445887f5e1bcea470a16f61369d29870cfcfe1/README.md#defusedxmllxml
#[derive(ViolationMetadata)]
#[violation_metadata(removed_since = "v0.3.0")]
pub(crate) struct SuspiciousLxmlImport;
impl Violation for SuspiciousLxmlImport {
@@ -263,6 +273,7 @@ impl Violation for SuspiciousLxmlImport {
/// import xmlrpc
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousXmlrpcImport;
impl Violation for SuspiciousXmlrpcImport {
@@ -289,6 +300,7 @@ impl Violation for SuspiciousXmlrpcImport {
/// ## References
/// - [httpoxy website](https://httpoxy.org/)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousHttpoxyImport;
impl Violation for SuspiciousHttpoxyImport {
@@ -314,6 +326,7 @@ impl Violation for SuspiciousHttpoxyImport {
/// ## References
/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousPycryptoImport;
impl Violation for SuspiciousPycryptoImport {
@@ -339,6 +352,7 @@ impl Violation for SuspiciousPycryptoImport {
/// ## References
/// - [Buffer Overflow Issue](https://github.com/pycrypto/pycrypto/issues/176)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "v0.1.12")]
pub(crate) struct SuspiciousPyghmiImport;
impl Violation for SuspiciousPyghmiImport {

View File

@@ -38,6 +38,7 @@ use crate::checkers::ast::Checker;
///
/// [PEP 706]: https://peps.python.org/pep-0706/#backporting-forward-compatibility
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct TarfileUnsafeMembers;
impl Violation for TarfileUnsafeMembers {

View File

@@ -45,6 +45,7 @@ use crate::rules::flake8_bandit::helpers::is_untyped_exception;
/// - [Common Weakness Enumeration: CWE-703](https://cwe.mitre.org/data/definitions/703.html)
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.245")]
pub(crate) struct TryExceptContinue;
impl Violation for TryExceptContinue {

View File

@@ -41,6 +41,7 @@ use crate::rules::flake8_bandit::helpers::is_untyped_exception;
/// - [Common Weakness Enumeration: CWE-703](https://cwe.mitre.org/data/definitions/703.html)
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.237")]
pub(crate) struct TryExceptPass;
impl Violation for TryExceptPass {

View File

@@ -75,6 +75,7 @@ use crate::{checkers::ast::Checker, settings::LinterSettings};
/// [markupsafe-markup]: https://markupsafe.palletsprojects.com/en/stable/escaping/#markupsafe.Markup
/// [flake8-markupsafe]: https://github.com/vmagamedov/flake8-markupsafe
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.10.0")]
pub(crate) struct UnsafeMarkupUse {
name: String,
}

View File

@@ -35,6 +35,7 @@ use crate::checkers::ast::Checker;
/// - [PyYAML documentation: Loading YAML](https://pyyaml.org/wiki/PyYAMLDocumentation)
/// - [Common Weakness Enumeration: CWE-20](https://cwe.mitre.org/data/definitions/20.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.212")]
pub(crate) struct UnsafeYAMLLoad {
pub loader: Option<String>,
}

View File

@@ -33,6 +33,7 @@ use crate::checkers::ast::Checker;
/// ## References
/// - [CSRC: Transitioning the Use of Cryptographic Algorithms and Key Lengths](https://csrc.nist.gov/pubs/sp/800/131/a/r2/final)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.2.0")]
pub(crate) struct WeakCryptographicKey {
cryptographic_key: CryptographicKey,
}

View File

@@ -63,6 +63,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: Exception hierarchy](https://docs.python.org/3/library/exceptions.html#exception-hierarchy)
/// - [PEP 8: Programming Recommendations on bare `except`](https://peps.python.org/pep-0008/#programming-recommendations)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.127")]
pub(crate) struct BlindExcept {
name: String,
}

View File

@@ -90,6 +90,7 @@ use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
/// - [Python documentation: Calls](https://docs.python.org/3/reference/expressions.html#calls)
/// - [_How to Avoid “The Boolean Trap”_ by Adam Johnson](https://adamj.eu/tech/2021/07/10/python-type-hints-how-to-avoid-the-boolean-trap/)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.127")]
pub(crate) struct BooleanDefaultValuePositionalArgument;
impl Violation for BooleanDefaultValuePositionalArgument {

View File

@@ -42,6 +42,7 @@ use crate::rules::flake8_boolean_trap::helpers::allow_boolean_trap;
/// - [Python documentation: Calls](https://docs.python.org/3/reference/expressions.html#calls)
/// - [_How to Avoid “The Boolean Trap”_ by Adam Johnson](https://adamj.eu/tech/2021/07/10/python-type-hints-how-to-avoid-the-boolean-trap/)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.127")]
pub(crate) struct BooleanPositionalValueInCall;
impl Violation for BooleanPositionalValueInCall {

View File

@@ -94,6 +94,7 @@ use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
/// - [Python documentation: Calls](https://docs.python.org/3/reference/expressions.html#calls)
/// - [_How to Avoid “The Boolean Trap”_ by Adam Johnson](https://adamj.eu/tech/2021/07/10/python-type-hints-how-to-avoid-the-boolean-trap/)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.127")]
pub(crate) struct BooleanTypeHintPositionalArgument;
impl Violation for BooleanTypeHintPositionalArgument {

View File

@@ -54,6 +54,7 @@ use crate::registry::Rule;
/// - [Python documentation: `abc`](https://docs.python.org/3/library/abc.html)
/// - [Python documentation: `typing.ClassVar`](https://docs.python.org/3/library/typing.html#typing.ClassVar)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.118")]
pub(crate) struct AbstractBaseClassWithoutAbstractMethod {
name: String,
}
@@ -99,6 +100,7 @@ impl Violation for AbstractBaseClassWithoutAbstractMethod {
/// ## References
/// - [Python documentation: `abc`](https://docs.python.org/3/library/abc.html)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.118")]
pub(crate) struct EmptyMethodWithoutAbstractDecorator {
name: String,
}

View File

@@ -35,6 +35,7 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
/// ## References
/// - [Python documentation: `assert`](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.67")]
pub(crate) struct AssertFalse;
impl AlwaysFixableViolation for AssertFalse {

View File

@@ -29,6 +29,7 @@ use crate::checkers::ast::Checker;
/// self.assertRaises(SomeSpecificException, foo)
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.83")]
pub(crate) struct AssertRaisesException {
exception: ExceptionKind,
}

View File

@@ -40,6 +40,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `os.environ`](https://docs.python.org/3/library/os.html#os.environ)
/// - [Python documentation: `subprocess.Popen`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.102")]
pub(crate) struct AssignmentToOsEnviron;
impl Violation for AssignmentToOsEnviron {

View File

@@ -49,6 +49,7 @@ use crate::{FixAvailability, Violation};
/// ## References
/// - [Python documentation: `batched`](https://docs.python.org/3/library/itertools.html#batched)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "0.10.0")]
pub(crate) struct BatchedWithoutExplicitStrict;
impl Violation for BatchedWithoutExplicitStrict {

View File

@@ -63,6 +63,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `functools.cache`](https://docs.python.org/3/library/functools.html#functools.cache)
/// - [don't lru_cache methods!](https://www.youtube.com/watch?v=sVjtp6tGo0g)
#[derive(ViolationMetadata)]
#[violation_metadata(stable_since = "v0.0.114")]
pub(crate) struct CachedInstanceMethod;
impl Violation for CachedInstanceMethod {

View File

@@ -34,6 +34,7 @@ use ruff_python_ast::PythonVersion;
/// y: float
/// ```
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.9.0")]
pub(crate) struct ClassAsDataStructure;
impl Violation for ClassAsDataStructure {

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