Compare commits

...

44 Commits

Author SHA1 Message Date
Micha Reiser
c1c0d1baa8 [pygrep-hooks]: Detect file-level suppressions comments without rule codes (PGH004) 2025-03-13 09:36:00 +01:00
Micha Reiser
d6221371f7 [pylint] Better inference for str.strip (PLE310) (#16671)
## Summary
This PR stabilizes the behavior introduced in
https://github.com/astral-sh/ruff/pull/15985

The new behavior improves the inference of `str.strip` calls:

* before: The rule only considered calls on string or byte literals
(`"abcd".strip`)
* now: The rule also catches calls to `strip` on object where the type
is known to be a `str` or `bytes` (e.g. `a = "abc"; a.strip("//")`)


The new behavior shipped as part of Ruff 0.9.6 on the 10th of Feb which
is a little more than a month ago.
There have been now new issues or PRs related to the new behavior.
2025-03-13 09:35:41 +01:00
Micha Reiser
6fc3434397 [pylint] Improve repeated-equality-comparison fix to use a set when all elements are hashable (PLR1714) (#16685)
## Summary

This PR promotes the fix improvements for `PLR1714` that were introduced
in https://github.com/astral-sh/ruff/pull/14372/ to stable.

The improvement is that the fix now proposes to use a set if all
elements are hashable:

```
foo == "bar" or foo == "baz" or foo == "qux"
```

Gets fixed to 

```py
foo in {"bar", "baz", "qux"}
```

where it previously always got fixed to a tuple.

The new fix was first released in ruff 0.8.0 (Nov last year). This is
not a breaking change. The change was preview gated only to get some
extra test coverage.


There are no open issues or PRs related to this changed fix behavior.
2025-03-13 09:22:29 +01:00
Micha Reiser
5a40aee73f [pylint/pep8-naming] Check __new__ argument name in bad-staticmethod-argument and not invalid-first-argument-name-for-class-method (PLW0211/N804) (#16676)
## Summary

This PR stabilizes the behavior changes introduced by
https://github.com/astral-sh/ruff/pull/13305 that were gated behind
preview.
The change is that `__new__` methods are now no longer flagged by
`invalid-first-argument-name-for-class-method` (`N804`) but instead by
`bad-staticmethod-argument` (`PLW0211`)

> __new__ methods are technically static methods, with cls as their
first argument. However, Ruff currently classifies them as classmethod,
which causes two issues:

## Test Plan

There have been no new issues or PRs related to `N804` or `PLW0211`
since the behavior change was released in Ruff 0.9.7 (about 3 weeks
ago).
This is a somewhat recent change but I don't think it's necessary to
leave this in preview for another 2 months. The main reason why it was
in preview
is that it is breaking, not because it is a risky change.
2025-03-13 08:59:48 +01:00
Micha Reiser
b93f8292d5 [flake8-pyi] Stabilize fix for unused-private-type-var (PYI018) (#16682)
## Summary

This PR stabilizes the fix for `PYI018` introduced in
https://github.com/astral-sh/ruff/pull/15999/ (first released with Ruff
0.9.5 early February)

There are no known issues with the fix or open PRs.
2025-03-13 08:47:59 +01:00
Micha Reiser
f49b10a450 [flake8-bandit] Deprecate suspicious-xmle-tree-usage (S320) (#16680)
## Summary
Deprecate `S320` because defusedxml has deprecated there `lxml` module
and `lxml` has been hardened since.

flake8-bandit has removed their implementation as well
(https://github.com/PyCQA/bandit/pull/1212).

Addresses https://github.com/astral-sh/ruff/issues/13707


## Test Plan

I verified that selecting `S320` prints a warning and fails if the
preview mode is enabled.
2025-03-13 08:46:23 +01:00
Micha Reiser
796627997e [flake8-simplify] Avoid double negation in fixes (SIM103) (#16684)
## Summary

This PR stabilizes the fixes improvements made in
https://github.com/astral-sh/ruff/pull/15562 (released with ruff 0.9.3
in mid January).

There's no open issue or PR related to the changed fix behavior.

This is not a breaking change. The fix was only gated behind preview to
get some more test coverage before releasing.
2025-03-13 08:45:50 +01:00
Micha Reiser
396fe3f7f0 [pyupgrade]: Improve diagnostic range for redundant-open-mode (UP015) (#16672)
## Summary

This PR stabilizes the behavior change introduced in
https://github.com/astral-sh/ruff/pull/15872/

The diagnostic range is now the range of the redundant `mode` argument
where it previously was the range of the entire `open` call:

Before:

```
UP015.py:2:1: UP015 [*] Unnecessary mode argument
  |
1 | open("foo", "U")
2 | open("foo", "Ur")
  | ^^^^^^^^^^^^^^^^^ UP015
3 | open("foo", "Ub")
4 | open("foo", "rUb")
  |
  = help: Remove mode argument
```


Now:

```
UP015.py:2:13: UP015 [*] Unnecessary mode argument
  |
1 | open("foo", "U")
2 | open("foo", "Ur")
  |             ^^^^ UP015
3 | open("foo", "Ub")
4 | open("foo", "rUb")
  |
  = help: Remove mode argument
```

This is a breaking change because it may require moving a `noqa` comment
onto a different line, e.g if you have

```py
open(
    "foo",
    "Ur",
) # noqa: UP015
```

Needs to be rewritten to 

```py
open(
    "foo",
    "Ur", # noqa: UP015
)
```

There have been now new issues or PRs since the new preview behavior was
implemented. It first was released as part of Ruff 0.9.5 on the 5th of
Feb (a little more than a month ago)

## Test Plan

I reviewed the snapshot tests
2025-03-13 08:45:22 +01:00
Micha Reiser
1fd0ea3f24 Consider all TYPE_CHECKING symbols for type-checking blocks (#16669)
## Summary

This PR stabilizes the preview behavior introduced in
https://github.com/astral-sh/ruff/pull/15719 to recognize all symbols
named `TYPE_CHECKING` as type-checking
checks in `if TYPE_CHECKING` conditions. This ensures compatibility with
mypy and pyright.

This PR also stabilizes the new behavior that removes `if 0:` and `if
False` to be no longer considered type checking blocks.
Since then, this syntax has been removed from the typing spec and was
only used for Python modules that don't have a `typing` module
([comment](https://github.com/astral-sh/ruff/pull/15719#issuecomment-2612787793)).

The preview behavior was first released with Ruff 0.9.5 (6th of
February), which was about a month ago. There are no open issues or PRs
for the changed behavior


## Test Plan

The snapshots for `SIM108` change because `SIM108` ignored type checking
blocks but it can no
simplify `if 0` or `if False` blocks again because they're no longer
considered type checking blocks.

The changes in the `TC005` snapshot or only due to that `if 0` and `if
False` are no longer recognized as type checking blocks

<!-- How was it tested? -->
2025-03-13 08:44:04 +01:00
Micha Reiser
4c4d43d168 [pep8-naming]: Ignore methods decorated with @typing.override (invalid-argument-name) (#16667)
## Summary

This PR stabilizes the preview behavior for `invalid-argument-name`
(`N803`)
to ignore argument names of functions decorated with `typing.override`
because
these methods are *out of the authors* control. 

This behavior was introduced in
https://github.com/astral-sh/ruff/pull/15954
and released as part of Ruff 0.9.5 (6th of February). 

There have been no new issues or PRs since this behavior change
(preview) was introduced.
2025-03-13 08:43:46 +01:00
Micha Reiser
7672dd0889 Stabilize FURB169 preview behavior (#16666)
## Summary

This PR stabilizes the preview behavior introduced in
https://github.com/astral-sh/ruff/pull/15905

The behavior change is that the rule now also recognizes `type(expr) is
type(None)` comparisons where `expr` isn't a name expression.
For example, the rule now detects `type(a.b) is type(None)` and suggests
rewriting the comparison to `a.b is None`.

The new behavior was introduced with Ruff 0.9.5 (6th of February), about
a month ago. There are no open issues or PRs related to this rule (or
behavior change).
2025-03-13 08:43:29 +01:00
Micha Reiser
b4809b7562 [pylint] Detect invalid default value type for os.environ.get (PLW1508) (#16674)
## Summary
This PR stabilizes the new behavior introduced in
https://github.com/astral-sh/ruff/pull/14512 to also detect defalut
value arguemnts to `os.environ.get` that have an invalid type (not
`str`).
There's an upstream issue for this behavior change
https://github.com/pylint-dev/pylint/issues/10092 that was accepted and
a PR, but it hasn't been merged yet.

This behavior change was first shipped with Ruff 0.8.1 (Nov 22). 

There has only be one PR since the new behavior was introduced but it
was unrelated to the scope increase
(https://github.com/astral-sh/ruff/pull/14841).
2025-03-13 08:43:08 +01:00
Micha Reiser
3d9fd7b4a5 [flake8-pytest-style] Allow for loops with empty bodies (PT012, PT031) (#16678)
## Summary

This PR stabilizes the behavior change introduced in
https://github.com/astral-sh/ruff/pull/15542 to allow
for statements with an empty body in `pytest.raises` and `pytest.warns`
with statements.

This raised an error before but is now allowed:

```py
with pytest.raises(KeyError, match='unknown'):
    async for _ in gpt.generate(gpt_request):
        pass
```

The same applies to 

```py
with pytest.raises(KeyError, match='unknown'):
    async for _ in gpt.generate(gpt_request):
        ...
```


There have been now new issues or PRs related to PT012 or PT031 since
this behavior change was introduced in ruff 0.9.3 (January 23rd).
2025-03-13 08:42:49 +01:00
Micha Reiser
2f2bcbb590 [pyupgrade]: Deprecate non-pep604-isinstance (UP038) (#16681)
## Summary

This PR deprecates UP038. Using PEP 604 syntax in `isinstance` and
`issubclass` calls isn't a recommended pattern (or community agreed best
practice)
and it negatively impacts performance. 

Resolves https://github.com/astral-sh/ruff/issues/7871

## Test Plan

I tested that selecting `UP038` results in a warning in no-preview mode
and an error in preview mode
2025-03-13 08:42:14 +01:00
Brent Westbrook
2daa9da0ca [flake8-type-checking] Stabilize runtime-cast-value (TC006) (#16637)
Summary
--

Stabilizes TC006. The test was already in the right place.

Test Plan
--

No open issues or PRs. The last related [issue] was closed on
2025-02-09.

[issue]: https://github.com/astral-sh/ruff/issues/16037
2025-03-12 14:54:02 -04:00
Brent Westbrook
5f05012905 [flake8-bandit] Stabilize unsafe-markup-use (S704) (#16643)
Summary
--

Stabilizes S704, which is also being recoded from RUF035 in 0.10.

Test Plan
--
Existing tests with `PreviewMode` removed from the settings.

There was one issue closed on 2024-12-20 calling the rule noisy and
asking for a config option, but the option was added and then there were
no more issues or PRs.
2025-03-12 14:48:35 -04:00
Brent Westbrook
2cada23145 [flake8-datetimez] Stabilize datetime-min-max (DTZ901) (#16635)
Summary
--

Stabilizes DTZ901, renames the rule function to match the rule name,
removes the `preview_rules` test, and handles some nits in the docs
(mention `min` first to match the rule name too).

Test Plan
--

1 closed issue on 2024-11-12, 4 days after the rule was added. No issues
since
2025-03-12 14:43:34 -04:00
InSync
78164abd19 Use inline snapshots in # noqa unit tests (#16687)
## Summary

Follow-up to #16677.

This change converts all unit tests (69 of them) in `noqa.rs` to use
inline snapshots instead. It extends the file by more than 1000 lines,
but the tests are now much easier to read and reason about.

## Test Plan

`cargo insta test`.
2025-03-12 13:16:27 -05:00
Brent Westbrook
29a2779e8b [ruff] Stabilize unnecessary-nested-literal (RUF041) (#16648)
Summary
--

Stabilizes RUF041. The tests are already in the right place, and the
docs look good.

Test Plan
--

0 issues, 1 [PR] fixing nested literals and unions the day after the
rule was added. No changes since then

I wonder if the fix in that PR could be relevant for
https://github.com/astral-sh/ruff/pull/16639, where I noticed a
potential issue with `Union`. It could be unrelated, though.

[PR]: https://github.com/astral-sh/ruff/pull/14641
2025-03-12 14:12:28 -04:00
Brent Westbrook
7bc8bb277b [flake8-use-pathlib] Stabilize invalid-pathlib-with-suffix (PTH210) (#16656)
Summary
--

Stabilizes PTH210. Tests and docs looked good.

Test Plan
--

Mentioned in 1 open issue around Python 3.14 support (`"."` becomes a
valid suffix in 3.14). Otherwise no issues or PRs since 2024-12-12, 6
days after the rule was added.
2025-03-12 13:07:05 -04:00
InSync
464ea4a5e4 Add missing unit tests for # noqa: A-like cases (#16677)
## Summary

Follow-up to #16659.

This change adds tests for these three cases, which are (also) not
covered by existing tests:

* `# noqa: A` (lone incomplete code)
* `# noqa: A123, B` (complete codes, last one incomplete)
* `# noqa: A123B` (squashed codes, last one incomplete)
2025-03-12 09:40:24 -05:00
Brent Westbrook
e9bfdfda6b [ruff] Stabilize if-key-in-dict-del (RUF051) (#16658)
Summary
--

Stabilizes RUF051. The tests and docs looked good.

Test Plan
--

1 closed documentation issue from 4 days after the rule was added and 1
typo fix from the same day it was added, but no other issues or PRs.
2025-03-12 08:37:11 -04:00
Brent Westbrook
7585d43b8b [flake8-bugbear] Stabilize batched-without-explicit-strict (B911) (#16655)
Summary
--

Stabilizes B911. Tests and docs looked good.

Test Plan
--

0 issues or PRs, open or closed
2025-03-12 08:36:01 -04:00
Brent Westbrook
406402bd0c [flake8-logging] Stabilize root-logger-call (LOG015) (#16654)
Summary
--

Stabilizes LOG015. The tests and docs looked good.

Test Plan
--

1 closed documentation issue from 4 days after the rule was added, but
no other issues or PRs.
2025-03-12 08:35:19 -04:00
Brent Westbrook
57bf330139 [ruff] Stabilize map-int-version-parsing (RUF048) (#16653)
Summary
--

Stabilizes RUF048 and moves its test to the right place. The docs look
good.

Test Plan
--

0 closed or open issues. There was 1 [PR] related to an extension to the
rule, but it was closed without comment.

[PR]: https://github.com/astral-sh/ruff/pull/14701
2025-03-12 08:34:18 -04:00
Brent Westbrook
0ced1cb2db [ruff] Stabilize unnecessary-cast-to-int (RUF046) (#16649)
Summary
--

Stabilizes RUF046 and moves its test to the right place. The docs look
good.

Test Plan
--

2 closed newline/whitespace issues from early January and 1 closed issue
about really being multiple rules, but otherwise no recent issues or
PRs.
2025-03-12 08:14:10 -04:00
Brent Westbrook
7690b339cf [ruff] Stabilize invalid-assert-message-literal-argument (RUF040) (#16646)
Summary
--

Stabilizes RUF040 and fixes a very minor typo in the docs. The tests are
already in the right place.

Test Plan
--

0 issues or PRs
2025-03-12 08:11:29 -04:00
Brent Westbrook
26cf0fea5b [flake8-use-pathlib] Stabilize os-listdir (PTH208) (#16642)
Summary
--

Stabilizes PTH208. The test was already in the right place, and the docs
look good.

Test Plan
--

0 issues and PRs, open or closed
2025-03-12 08:09:33 -04:00
Brent Westbrook
e261f633ca [flake8-type-checking] Stabilize unquoted-type-alias (TC007) (#16638)
Summary
--

Stabilizes TC007. The test was already in the right place.

Test Plan
--

No open issues or PRs.
2025-03-12 08:08:52 -04:00
InSync
948435d5b3 Add missing unit tests for # noqa:-like cases (#16659) 2025-03-12 05:08:55 -05:00
Dylan
b8f128442e Make noqa parsing consistent and more robust (#16483)
# Summary
The goal of this PR is to address various issues around parsing
suppression comments by

1. Unifying the logic used to parse in-line (`# noqa`) and file-level
(`# ruff: noqa`) noqa comments
2. Recovering from certain errors and surfacing warnings in these cases

Closes #15682 
Supersedes #12811 
Addresses
https://github.com/astral-sh/ruff/pull/14229#discussion_r1835481018
Related: #14229 , #12809
2025-03-11 14:50:32 -05:00
Brent Westbrook
85f7871754 [flake8-builtins] Default to non-strict checking (A005) (#16125)
## Summary

This PR changes the default value of
`lint.flake8-builtins.builtins-strict-checking` added in
https://github.com/astral-sh/ruff/pull/15951 from `true` to `false`.
This also allows simplifying the default option logic and removes the
dependence on preview mode.

https://github.com/astral-sh/ruff/issues/15399 was already closed by
#15951, but this change will finalize the behavior mentioned in
https://github.com/astral-sh/ruff/issues/15399#issuecomment-2587017147.

As an example, strict checking flags modules based on their last
component, so `utils/logging.py` triggers A005. Non-strict checking
checks the path to the module, so `utils/logging.py` is allowed (this is
the example and desired behavior from #15399 exactly) but a top-level
`logging.py` or `logging/__init__.py` is still disallowed.

## Test Plan

Existing tests from #15951 and #16006, with the snapshot updated in
`a005_module_shadowing_strict_default` to reflect the new default.
2025-03-11 14:10:01 -04:00
Brent Westbrook
daeb8f11f2 [pyupgrade] Stabilize non-pep646-unpack (UP044) (#16632)
Summary
--

Stabilizes UP044, renames the module to match the rule name, and removes
the `PreviewMode` from the test settings.

Test Plan
--

2 closed issues in November, just after the rule was added, otherwise no
issues
2025-03-11 14:01:10 -04:00
Brent Westbrook
1898702a36 [flake8-simplify] Stabilize split-static-string (SIM905) (#16631)
Summary
--

Stabilizes SIM905 and adds a small addition to the docs. The test was
already in the right place.

Test Plan
--

No issues except 2 recent, general issues about whitespace
normalization.
2025-03-11 13:53:33 -04:00
Alex Waygood
5ec7c138f6 [ruff-0.10] [flake8-pyi] Stabilize preview-mode behaviours for custom-type-var-for-self(PYI019) (#16607)
## Summary

This PR stabilizes several preview-only behaviours for
`custom-typevar-for-self` (`PYI019`). Namely:
- A new, more accurate technique is now employed for detecting custom
TypeVars that are replaceable with `Self`. See
https://github.com/astral-sh/ruff/pull/15888 for details.
- The range of the diagnostic is now the full function header rather
than just the return annotation. (Previously, the rule only applied to
methods with return annotations, but this is no longer true due to the
changes in the first bullet point.)
- The fix is now available even when preview mode is not enabled.

## Test Plan

- Existing snapshots that do not have preview mode enabled are updated
- Preview-specific snapshots are removed
- I'll check the ecosystem report on this PR to verify everything's as
expected
2025-03-11 16:05:25 +00:00
Brent Westbrook
303b061f7b [pylint] Stabilize len-test (PLC1802) (#16626)
Summary
--

Stabilizes PLC1802. The tests were already in the right place, and I
just tidied the docs a little bit.

Test Plan
--

1 issue closed 4 days after the rule was added, no other issues
2025-03-11 11:30:43 -04:00
Brent Westbrook
f1014ce451 [pylint] Stabilize shallow-copy-environ (PLW1507) (#16627)
Summary
--

Stabilizes PLW1507. The tests were already in the right place, and I
just tidied the docs a little bit.

Test Plan
--

1 issue from 2 weeks ago but just suggesting to mark the fix unsafe. The
shallow vs deep copy *does* change the program behavior, just usually in
a preferable way.
2025-03-11 11:30:16 -04:00
Brent Westbrook
afb7da860f [FastAPI] Stabilize fast-api-unused-path-parameter (FAST003) (#16625)
## Summary

Stabilizes FAST003, completing the group with FAST001 and FAST002.

## Test Plan

Last bug fix (false positive) was fixed on 2025-01-13, almost 2 months
ago.

The test case was already in the right place.
2025-03-11 10:59:45 -04:00
Brent Westbrook
f1afd6edd8 [flake8-comprehensions] Stabilize unnecessary-dict-comprehension-for-iterable (C420) (#16624)
## Summary

Stabilizes C420 for the 0.10 release.

## Test Plan

No open issues or PRs (except a general issue about [string
normalization](https://github.com/astral-sh/ruff/issues/16579)). The
last (and only) false-negative bug fix was over a month ago.

The tests for this rule were already not on the `preview_rules` test, so
I just changed the `RuleGroup`. The documentation looked okay to me.
2025-03-11 10:59:13 -04:00
InSync
80a3221c6a [flake8-builtins] Remove builtins- prefix from option names (#16092)
## Summary

Resolves #15368.

The following options have been renamed:

* `builtins-allowed-modules` &rarr; `allowed-modules`
* `builtins-ignorelist` &rarr; `ignorelist`
* `builtins-strict-checking` &rarr; `strict-checking`

To preserve compatibility, the old names are kept as Serde aliases.

## Test Plan

`cargo nextest run` and `cargo insta test`.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-03-11 13:29:19 +01:00
David Salvisberg
2ae5344708 [flake8-bandit] Move unsafe-markup-use from RUF035 to S704 (#15957)
## Summary

`RUF035` has been backported into bandit as `S704` in this
[PR](https://github.com/PyCQA/bandit/pull/1225)

This moves the rule and its corresponding setting to the `flake8-bandit`
category

## Test Plan

`cargo nextest run`

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
2025-03-11 13:19:18 +01:00
Dhruv Manilawala
6ba6cfd37c Server: Remove log notification for printDebugInformation command (#16617)
## Summary

For context, the initial implementation started out by sending a log
notification to the client to include this information in the client
channel. This is a bit ineffective because it doesn't allow the client
to display this information in a more obvious way. In addition to that,
it isn't obvious from a users perspective as to where the information is
being printed unless they actually open the output channel.

The change was to actually return this formatted string that contains
the information and let the client handle how it should display this
information. For example, in the Ruff VS Code extension we open a split
window and show this information which is similar to what rust-analyzer
does.

The notification request was kept as a precaution in case there are
users who are actually utilizing this way. If they exists, it should a
minority as it requires the user to actually dive into the code to
understand how to hook into this notification. With 0.10, we're removing
the old way as it only clobbers the output channel with a long message.

fixes: #16225

## Test Plan

Tested it out locally that the information is not being logged to the
output channel of VS Code.
2025-03-11 13:53:07 +05:30
Micha Reiser
41cd905fda [formatter] Stabilize fix for single-with-item formatting with trailing comment (#16603)
## Summary

This PR stabilizies the fix for
https://github.com/astral-sh/ruff/issues/14001

We try to only make breaking formatting changes once a year. However,
the plan was to release this fix as part of Ruff 0.9 but I somehow
missed it when promoting all other formatter changes.
I think it's worth making an exception here considering that this is a
bug fix, it improves readability, and it should be rare
(very few files in a single project). Our version policy explicitly
allows breaking formatter changes in any minor release and the idea of
only making breaking formatter changes once a year is mainly to avoid
multiple releases throughout the year that introduce large formatter
changes

Closes https://github.com/astral-sh/ruff/issues/14001

## Test Plan

Updated snapshot
2025-03-10 19:31:35 +01:00
samypr100
e4e1c58152 Bump alpine default tag to 3.21 (#16456)
## Summary

Alpine 3.21 has been released for a few months and `uv` has already
migrated in https://github.com/astral-sh/uv/pull/11157
2025-03-10 15:28:05 +01:00
159 changed files with 4130 additions and 7076 deletions

View File

@@ -163,7 +163,7 @@ jobs:
# Mapping of base image followed by a comma followed by one or more base tags (comma separated)
# Note, org.opencontainers.image.version label will use the first base tag (use the most specific tag first)
image-mapping:
- alpine:3.20,alpine3.20,alpine
- alpine:3.21,alpine3.21,alpine
- debian:bookworm-slim,bookworm-slim,debian-slim
- buildpack-deps:bookworm,bookworm,debian
steps:

View File

@@ -2470,7 +2470,7 @@ fn create_a005_module_structure(tempdir: &TempDir) -> Result<()> {
Ok(())
}
/// Test A005 with `builtins-strict-checking = true`
/// Test A005 with `strict-checking = true`
#[test]
fn a005_module_shadowing_strict() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -2482,7 +2482,7 @@ fn a005_module_shadowing_strict() -> Result<()> {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.arg("--config")
.arg(r#"lint.flake8-builtins.builtins-strict-checking = true"#)
.arg(r#"lint.flake8-builtins.strict-checking = true"#)
.args(["--select", "A005"])
.current_dir(tempdir.path()),
@r"
@@ -2504,7 +2504,7 @@ fn a005_module_shadowing_strict() -> Result<()> {
Ok(())
}
/// Test A005 with `builtins-strict-checking = false`
/// Test A005 with `strict-checking = false`
#[test]
fn a005_module_shadowing_non_strict() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -2516,7 +2516,7 @@ fn a005_module_shadowing_non_strict() -> Result<()> {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.arg("--config")
.arg(r#"lint.flake8-builtins.builtins-strict-checking = false"#)
.arg(r#"lint.flake8-builtins.strict-checking = false"#)
.args(["--select", "A005"])
.current_dir(tempdir.path()),
@r"
@@ -2535,7 +2535,7 @@ fn a005_module_shadowing_non_strict() -> Result<()> {
Ok(())
}
/// Test A005 with `builtins-strict-checking` unset
/// Test A005 with `strict-checking` unset
/// TODO(brent) This should currently match the strict version, but after the next minor
/// release it will match the non-strict version directly above
#[test]
@@ -2556,11 +2556,7 @@ fn a005_module_shadowing_strict_default() -> Result<()> {
----- stdout -----
abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
collections/__init__.py:1:1: A005 Module `collections` shadows a Python standard-library module
collections/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
foobar/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
foobar/collections/__init__.py:1:1: A005 Module `collections` shadows a Python standard-library module
foobar/collections/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
Found 6 errors.
Found 2 errors.
----- stderr -----
");

View File

@@ -226,10 +226,12 @@ linter.flake8_bandit.hardcoded_tmp_directory = [
/dev/shm,
]
linter.flake8_bandit.check_typed_exception = false
linter.flake8_bandit.extend_markup_names = []
linter.flake8_bandit.allowed_markup_calls = []
linter.flake8_bugbear.extend_immutable_calls = []
linter.flake8_builtins.builtins_allowed_modules = []
linter.flake8_builtins.builtins_ignorelist = []
linter.flake8_builtins.builtins_strict_checking = true
linter.flake8_builtins.allowed_modules = []
linter.flake8_builtins.ignorelist = []
linter.flake8_builtins.strict_checking = false
linter.flake8_comprehensions.allow_dict_calls_with_keyword_arguments = false
linter.flake8_copyright.notice_rgx = (?i)Copyright\s+((?:\(C\)|©)\s+)?\d{4}((-|,\s)\d{4})*
linter.flake8_copyright.author = none
@@ -369,8 +371,6 @@ linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false
linter.ruff.extend_markup_names = []
linter.ruff.allowed_markup_calls = []
# Formatter Settings
formatter.exclude = []

View File

@@ -2,17 +2,17 @@ import flask
from markupsafe import Markup, escape
content = "<script>alert('Hello, world!')</script>"
Markup(f"unsafe {content}") # RUF035
flask.Markup("unsafe {}".format(content)) # RUF035
Markup(f"unsafe {content}") # S704
flask.Markup("unsafe {}".format(content)) # S704
Markup("safe {}").format(content)
flask.Markup(b"safe {}", encoding='utf-8').format(content)
escape(content)
Markup(content) # RUF035
flask.Markup("unsafe %s" % content) # RUF035
Markup(content) # S704
flask.Markup("unsafe %s" % content) # S704
Markup(object="safe")
Markup(object="unsafe {}".format(content)) # Not currently detected
# NOTE: We may be able to get rid of these false positives with red-knot
# if it includes comprehensive constant expression detection/evaluation.
Markup("*" * 8) # RUF035 (false positive)
flask.Markup("hello {}".format("world")) # RUF035 (false positive)
Markup("*" * 8) # S704 (false positive)
flask.Markup("hello {}".format("world")) # S704 (false positive)

View File

@@ -2,5 +2,5 @@ from markupsafe import Markup
from webhelpers.html import literal
content = "<script>alert('Hello, world!')</script>"
Markup(f"unsafe {content}") # RUF035
literal(f"unsafe {content}") # RUF035
Markup(f"unsafe {content}") # S704
literal(f"unsafe {content}") # S704

View File

@@ -4,4 +4,4 @@ from webhelpers.html import literal
# additional markup names to be skipped if we don't import either
# markupsafe or flask first.
content = "<script>alert('Hello, world!')</script>"
literal(f"unsafe {content}") # RUF035
literal(f"unsafe {content}") # S704

View File

@@ -6,4 +6,4 @@ Markup(clean(content))
# indirect assignments are currently not supported
cleaned = clean(content)
Markup(cleaned) # RUF035
Markup(cleaned) # S704

View File

@@ -4,13 +4,6 @@ if TYPE_CHECKING:
pass # TC005
if False:
pass # TC005
if 0:
pass # TC005
def example():
if TYPE_CHECKING:
pass # TC005
@@ -32,13 +25,6 @@ if TYPE_CHECKING:
x: List
if False:
x: List
if 0:
x: List
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:

View File

@@ -19,5 +19,6 @@ def f():
def f():
# Only `E741` should be ignored by the `noqa`.
# Neither of these are ignored and warning is
# logged to user
I = 1 # noqa: E741.F841

View File

@@ -428,7 +428,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
flake8_2020::rules::name_or_attribute(checker, expr);
}
if checker.enabled(Rule::DatetimeMinMax) {
flake8_datetimez::rules::datetime_max_min(checker, expr);
flake8_datetimez::rules::datetime_min_max(checker, expr);
}
if checker.enabled(Rule::BannedApi) {
flake8_tidy_imports::rules::banned_attribute_access(checker, expr);
@@ -1129,7 +1129,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
refurb::rules::int_on_sliced_str(checker, call);
}
if checker.enabled(Rule::UnsafeMarkupUse) {
ruff::rules::unsafe_markup_call(checker, call);
flake8_bandit::rules::unsafe_markup_call(checker, call);
}
if checker.enabled(Rule::MapIntVersionParsing) {
ruff::rules::map_int_version_parsing(checker, call);

View File

@@ -246,11 +246,7 @@ impl<'a> Checker<'a> {
notebook_index: Option<&'a NotebookIndex>,
target_version: PythonVersion,
) -> Checker<'a> {
let mut semantic = SemanticModel::new(&settings.typing_modules, path, module);
if settings.preview.is_enabled() {
// Set the feature flag to test `TYPE_CHECKING` semantic changes
semantic.flags |= SemanticModelFlags::NEW_TYPE_CHECKING_BLOCK_DETECTION;
}
let semantic = SemanticModel::new(&settings.typing_modules, path, module);
Self {
parsed,
parsed_type_annotation: None,
@@ -293,7 +289,14 @@ impl<'a> Checker<'a> {
if !self.noqa.is_enabled() {
return false;
}
noqa::rule_is_ignored(code, offset, self.noqa_line_for, self.locator)
noqa::rule_is_ignored(
code,
offset,
self.noqa_line_for,
self.comment_ranges(),
self.locator,
)
}
/// Create a [`Generator`] to generate source code based on the current AST state.

View File

@@ -38,7 +38,8 @@ pub(crate) fn check_noqa(
let exemption = FileExemption::from(&file_noqa_directives);
// Extract all `noqa` directives.
let mut noqa_directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator);
let mut noqa_directives =
NoqaDirectives::from_commented_ranges(comment_ranges, &settings.external, path, locator);
// Indices of diagnostics that were ignored by a `noqa` directive.
let mut ignored_diagnostics = vec![];
@@ -223,7 +224,6 @@ pub(crate) fn check_noqa(
&noqa_directives,
locator,
&file_noqa_directives,
settings.preview,
);
}

View File

@@ -192,7 +192,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
(Pylint, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
(Pylint, "C1802") => (RuleGroup::Preview, rules::pylint::rules::LenTest),
(Pylint, "C1802") => (RuleGroup::Stable, rules::pylint::rules::LenTest),
(Pylint, "C1901") => (RuleGroup::Preview, rules::pylint::rules::CompareToEmptyString),
(Pylint, "C2401") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiName),
(Pylint, "C2403") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiImportName),
@@ -288,7 +288,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "W0642") => (RuleGroup::Stable, rules::pylint::rules::SelfOrClsAssignment),
(Pylint, "W0711") => (RuleGroup::Stable, rules::pylint::rules::BinaryOpException),
(Pylint, "W1501") => (RuleGroup::Stable, rules::pylint::rules::BadOpenMode),
(Pylint, "W1507") => (RuleGroup::Preview, rules::pylint::rules::ShallowCopyEnviron),
(Pylint, "W1507") => (RuleGroup::Stable, rules::pylint::rules::ShallowCopyEnviron),
(Pylint, "W1508") => (RuleGroup::Stable, rules::pylint::rules::InvalidEnvvarDefault),
(Pylint, "W1509") => (RuleGroup::Stable, rules::pylint::rules::SubprocessPopenPreexecFn),
(Pylint, "W1510") => (RuleGroup::Stable, rules::pylint::rules::SubprocessRunWithoutCheck),
@@ -362,7 +362,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bugbear, "904") => (RuleGroup::Stable, rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept),
(Flake8Bugbear, "905") => (RuleGroup::Stable, rules::flake8_bugbear::rules::ZipWithoutExplicitStrict),
(Flake8Bugbear, "909") => (RuleGroup::Preview, rules::flake8_bugbear::rules::LoopIteratorMutation),
(Flake8Bugbear, "911") => (RuleGroup::Preview, rules::flake8_bugbear::rules::BatchedWithoutExplicitStrict),
(Flake8Bugbear, "911") => (RuleGroup::Stable, rules::flake8_bugbear::rules::BatchedWithoutExplicitStrict),
// flake8-blind-except
(Flake8BlindExcept, "001") => (RuleGroup::Stable, rules::flake8_blind_except::rules::BlindExcept),
@@ -386,7 +386,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Comprehensions, "17") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryMap),
(Flake8Comprehensions, "18") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinDictCall),
(Flake8Comprehensions, "19") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryComprehensionInCall),
(Flake8Comprehensions, "20") => (RuleGroup::Preview, rules::flake8_comprehensions::rules::UnnecessaryDictComprehensionForIterable),
(Flake8Comprehensions, "20") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryDictComprehensionForIterable),
// flake8-debugger
(Flake8Debugger, "0") => (RuleGroup::Stable, rules::flake8_debugger::rules::Debugger),
@@ -489,7 +489,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Simplify, "223") => (RuleGroup::Stable, rules::flake8_simplify::rules::ExprAndFalse),
(Flake8Simplify, "300") => (RuleGroup::Stable, rules::flake8_simplify::rules::YodaConditions),
(Flake8Simplify, "401") => (RuleGroup::Stable, rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet),
(Flake8Simplify, "905") => (RuleGroup::Preview, rules::flake8_simplify::rules::SplitStaticString),
(Flake8Simplify, "905") => (RuleGroup::Stable, rules::flake8_simplify::rules::SplitStaticString),
(Flake8Simplify, "910") => (RuleGroup::Stable, rules::flake8_simplify::rules::DictGetWithNoneDefault),
(Flake8Simplify, "911") => (RuleGroup::Stable, rules::flake8_simplify::rules::ZipDictKeysAndValues),
@@ -532,13 +532,13 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pyupgrade, "035") => (RuleGroup::Stable, rules::pyupgrade::rules::DeprecatedImport),
(Pyupgrade, "036") => (RuleGroup::Stable, rules::pyupgrade::rules::OutdatedVersionBlock),
(Pyupgrade, "037") => (RuleGroup::Stable, rules::pyupgrade::rules::QuotedAnnotation),
(Pyupgrade, "038") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP604Isinstance),
(Pyupgrade, "038") => (RuleGroup::Deprecated, rules::pyupgrade::rules::NonPEP604Isinstance),
(Pyupgrade, "039") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryClassParentheses),
(Pyupgrade, "040") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP695TypeAlias),
(Pyupgrade, "041") => (RuleGroup::Stable, rules::pyupgrade::rules::TimeoutErrorAlias),
(Pyupgrade, "042") => (RuleGroup::Preview, rules::pyupgrade::rules::ReplaceStrEnum),
(Pyupgrade, "043") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryDefaultTypeArgs),
(Pyupgrade, "044") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP646Unpack),
(Pyupgrade, "044") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP646Unpack),
(Pyupgrade, "045") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP604AnnotationOptional),
(Pyupgrade, "046") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericClass),
(Pyupgrade, "047") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericFunction),
@@ -649,7 +649,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bandit, "317") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLSaxUsage),
(Flake8Bandit, "318") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLMiniDOMUsage),
(Flake8Bandit, "319") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLPullDOMUsage),
(Flake8Bandit, "320") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLETreeUsage),
(Flake8Bandit, "320") => (RuleGroup::Deprecated, rules::flake8_bandit::rules::SuspiciousXMLETreeUsage),
(Flake8Bandit, "321") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFTPLibUsage),
(Flake8Bandit, "323") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousUnverifiedContextUsage),
(Flake8Bandit, "324") => (RuleGroup::Stable, rules::flake8_bandit::rules::HashlibInsecureHashFunction),
@@ -690,6 +690,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
(Flake8Bandit, "702") => (RuleGroup::Stable, rules::flake8_bandit::rules::MakoTemplates),
(Flake8Bandit, "704") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnsafeMarkupUse),
// flake8-boolean-trap
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),
@@ -718,7 +719,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Datetimez, "007") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDatetimeStrptimeWithoutZone),
(Flake8Datetimez, "011") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDateToday),
(Flake8Datetimez, "012") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDateFromtimestamp),
(Flake8Datetimez, "901") => (RuleGroup::Preview, rules::flake8_datetimez::rules::DatetimeMinMax),
(Flake8Datetimez, "901") => (RuleGroup::Stable, rules::flake8_datetimez::rules::DatetimeMinMax),
// pygrep-hooks
(PygrepHooks, "001") => (RuleGroup::Removed, rules::pygrep_hooks::rules::Eval),
@@ -870,8 +871,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8TypeChecking, "003") => (RuleGroup::Stable, rules::flake8_type_checking::rules::TypingOnlyStandardLibraryImport),
(Flake8TypeChecking, "004") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeImportInTypeCheckingBlock),
(Flake8TypeChecking, "005") => (RuleGroup::Stable, rules::flake8_type_checking::rules::EmptyTypeCheckingBlock),
(Flake8TypeChecking, "006") => (RuleGroup::Preview, rules::flake8_type_checking::rules::RuntimeCastValue),
(Flake8TypeChecking, "007") => (RuleGroup::Preview, rules::flake8_type_checking::rules::UnquotedTypeAlias),
(Flake8TypeChecking, "006") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeCastValue),
(Flake8TypeChecking, "007") => (RuleGroup::Stable, rules::flake8_type_checking::rules::UnquotedTypeAlias),
(Flake8TypeChecking, "008") => (RuleGroup::Preview, rules::flake8_type_checking::rules::QuotedTypeAlias),
(Flake8TypeChecking, "010") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeStringUnion),
@@ -921,8 +922,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8UsePathlib, "205") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::OsPathGetctime),
(Flake8UsePathlib, "206") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::OsSepSplit),
(Flake8UsePathlib, "207") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::Glob),
(Flake8UsePathlib, "208") => (RuleGroup::Preview, rules::flake8_use_pathlib::violations::OsListdir),
(Flake8UsePathlib, "210") => (RuleGroup::Preview, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
(Flake8UsePathlib, "208") => (RuleGroup::Stable, rules::flake8_use_pathlib::violations::OsListdir),
(Flake8UsePathlib, "210") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
// flake8-logging-format
(Flake8LoggingFormat, "001") => (RuleGroup::Stable, rules::flake8_logging_format::violations::LoggingStringFormat),
@@ -949,7 +950,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
// fastapi
(FastApi, "001") => (RuleGroup::Stable, rules::fastapi::rules::FastApiRedundantResponseModel),
(FastApi, "002") => (RuleGroup::Stable, rules::fastapi::rules::FastApiNonAnnotatedDependency),
(FastApi, "003") => (RuleGroup::Preview, rules::fastapi::rules::FastApiUnusedPathParameter),
(FastApi, "003") => (RuleGroup::Stable, rules::fastapi::rules::FastApiUnusedPathParameter),
// pydoclint
(Pydoclint, "201") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingReturns),
@@ -991,20 +992,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "032") => (RuleGroup::Stable, rules::ruff::rules::DecimalFromFloatLiteral),
(Ruff, "033") => (RuleGroup::Stable, rules::ruff::rules::PostInitDefault),
(Ruff, "034") => (RuleGroup::Stable, rules::ruff::rules::UselessIfElse),
(Ruff, "035") => (RuleGroup::Preview, rules::ruff::rules::UnsafeMarkupUse),
(Ruff, "035") => (RuleGroup::Removed, rules::ruff::rules::RuffUnsafeMarkupUse),
(Ruff, "036") => (RuleGroup::Preview, rules::ruff::rules::NoneNotAtEndOfUnion),
(Ruff, "037") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryEmptyIterableWithinDequeCall),
(Ruff, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
(Ruff, "039") => (RuleGroup::Preview, rules::ruff::rules::UnrawRePattern),
(Ruff, "040") => (RuleGroup::Preview, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
(Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "040") => (RuleGroup::Stable, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
(Ruff, "041") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "043") => (RuleGroup::Preview, rules::ruff::rules::PytestRaisesAmbiguousPattern),
(Ruff, "045") => (RuleGroup::Preview, rules::ruff::rules::ImplicitClassVarInDataclass),
(Ruff, "046") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryCastToInt),
(Ruff, "046") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryCastToInt),
(Ruff, "047") => (RuleGroup::Preview, rules::ruff::rules::NeedlessElse),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "048") => (RuleGroup::Stable, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "049") => (RuleGroup::Preview, rules::ruff::rules::DataclassEnum),
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
(Ruff, "051") => (RuleGroup::Stable, rules::ruff::rules::IfKeyInDictDel),
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
(Ruff, "053") => (RuleGroup::Preview, rules::ruff::rules::ClassWithMixedTypeVars),
(Ruff, "054") => (RuleGroup::Preview, rules::ruff::rules::IndentedFormFeed),
@@ -1135,7 +1136,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Logging, "007") => (RuleGroup::Stable, rules::flake8_logging::rules::ExceptionWithoutExcInfo),
(Flake8Logging, "009") => (RuleGroup::Stable, rules::flake8_logging::rules::UndocumentedWarn),
(Flake8Logging, "014") => (RuleGroup::Preview, rules::flake8_logging::rules::ExcInfoOutsideExceptHandler),
(Flake8Logging, "015") => (RuleGroup::Preview, rules::flake8_logging::rules::RootLoggerCall),
(Flake8Logging, "015") => (RuleGroup::Stable, rules::flake8_logging::rules::RootLoggerCall),
_ => return None,
})

File diff suppressed because it is too large Load Diff

View File

@@ -134,6 +134,7 @@ static REDIRECTS: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(
("TCH005", "TC005"),
("TCH006", "TC010"),
("TCH010", "TC010"),
("RUF035", "S704"),
])
});

View File

@@ -87,6 +87,7 @@ mod tests {
#[test_case(Rule::DjangoExtra, Path::new("S610.py"))]
#[test_case(Rule::DjangoRawSql, Path::new("S611.py"))]
#[test_case(Rule::TarfileUnsafeMembers, Path::new("S202.py"))]
#[test_case(Rule::UnsafeMarkupUse, Path::new("S704.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
@@ -120,6 +121,49 @@ mod tests {
Ok(())
}
#[test_case(Rule::UnsafeMarkupUse, Path::new("S704_extend_markup_names.py"))]
#[test_case(Rule::UnsafeMarkupUse, Path::new("S704_skip_early_out.py"))]
fn extend_allowed_callable(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"extend_allow_callables__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_bandit").join(path).as_path(),
&LinterSettings {
flake8_bandit: super::settings::Settings {
extend_markup_names: vec!["webhelpers.html.literal".to_string()],
..Default::default()
},
..LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test_case(Rule::UnsafeMarkupUse, Path::new("S704_whitelisted_markup_calls.py"))]
fn whitelisted_markup_calls(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"whitelisted_markup_calls__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_bandit").join(path).as_path(),
&LinterSettings {
flake8_bandit: super::settings::Settings {
allowed_markup_calls: vec!["bleach.clean".to_string()],
..Default::default()
},
..LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn check_hardcoded_tmp_additional_dirs() -> Result<()> {
let diagnostics = test_path(
@@ -132,7 +176,7 @@ mod tests {
"/dev/shm".to_string(),
"/foo".to_string(),
],
check_typed_exception: false,
..Default::default()
},
..LinterSettings::for_rule(Rule::HardcodedTempFile)
},

View File

@@ -29,6 +29,7 @@ pub(crate) use suspicious_imports::*;
pub(crate) use tarfile_unsafe_members::*;
pub(crate) use try_except_continue::*;
pub(crate) use try_except_pass::*;
pub(crate) use unsafe_markup_use::*;
pub(crate) use unsafe_yaml_load::*;
pub(crate) use weak_cryptographic_key::*;
@@ -63,5 +64,6 @@ mod suspicious_imports;
mod tarfile_unsafe_members;
mod try_except_continue;
mod try_except_pass;
mod unsafe_markup_use;
mod unsafe_yaml_load;
mod weak_cryptographic_key;

View File

@@ -779,6 +779,13 @@ impl Violation for SuspiciousXMLPullDOMUsage {
}
}
/// ## Deprecation
///
/// This rule was deprecated as the `lxml` library has been modified to address
/// known vulnerabilities and unsafe defaults. As such, the `defusedxml`
/// library is no longer necessary, `defusedxml` has [deprecated] its `lxml`
/// module.
///
/// ## What it does
/// Checks for uses of insecure XML parsers.
///
@@ -802,6 +809,7 @@ impl Violation for SuspiciousXMLPullDOMUsage {
/// - [Common Weakness Enumeration: CWE-776](https://cwe.mitre.org/data/definitions/776.html)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
/// [deprecated]: https://pypi.org/project/defusedxml/0.8.0rc2/#defusedxml-lxml
#[derive(ViolationMetadata)]
pub(crate) struct SuspiciousXMLETreeUsage;

View File

@@ -0,0 +1,160 @@
use ruff_python_ast::{Expr, ExprCall};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::name::QualifiedName;
use ruff_python_semantic::{Modules, SemanticModel};
use ruff_text_size::Ranged;
use crate::{checkers::ast::Checker, settings::LinterSettings};
/// ## What it does
/// Checks for non-literal strings being passed to [`markupsafe.Markup`][markupsafe-markup].
///
/// ## Why is this bad?
/// [`markupsafe.Markup`] does not perform any escaping, so passing dynamic
/// content, like f-strings, variables or interpolated strings will potentially
/// lead to XSS vulnerabilities.
///
/// Instead you should interpolate the `Markup` object.
///
/// Using [`lint.flake8-bandit.extend-markup-names`] additional objects can be
/// treated like `Markup`.
///
/// This rule was originally inspired by [flake8-markupsafe] but doesn't carve
/// out any exceptions for i18n related calls by default.
///
/// You can use [`lint.flake8-bandit.allowed-markup-calls`] to specify exceptions.
///
/// ## Example
/// Given:
/// ```python
/// from markupsafe import Markup
///
/// content = "<script>alert('Hello, world!')</script>"
/// html = Markup(f"<b>{content}</b>") # XSS
/// ```
///
/// Use instead:
/// ```python
/// from markupsafe import Markup
///
/// content = "<script>alert('Hello, world!')</script>"
/// html = Markup("<b>{}</b>").format(content) # Safe
/// ```
///
/// Given:
/// ```python
/// from markupsafe import Markup
///
/// lines = [
/// Markup("<b>heading</b>"),
/// "<script>alert('XSS attempt')</script>",
/// ]
/// html = Markup("<br>".join(lines)) # XSS
/// ```
///
/// Use instead:
/// ```python
/// from markupsafe import Markup
///
/// lines = [
/// Markup("<b>heading</b>"),
/// "<script>alert('XSS attempt')</script>",
/// ]
/// html = Markup("<br>").join(lines) # Safe
/// ```
/// ## Options
/// - `lint.flake8-bandit.extend-markup-names`
/// - `lint.flake8-bandit.allowed-markup-calls`
///
/// ## References
/// - [MarkupSafe on PyPI](https://pypi.org/project/MarkupSafe/)
/// - [`markupsafe.Markup` API documentation](https://markupsafe.palletsprojects.com/en/stable/escaping/#markupsafe.Markup)
///
/// [markupsafe-markup]: https://markupsafe.palletsprojects.com/en/stable/escaping/#markupsafe.Markup
/// [flake8-markupsafe]: https://github.com/vmagamedov/flake8-markupsafe
#[derive(ViolationMetadata)]
pub(crate) struct UnsafeMarkupUse {
name: String,
}
impl Violation for UnsafeMarkupUse {
#[derive_message_formats]
fn message(&self) -> String {
let UnsafeMarkupUse { name } = self;
format!("Unsafe use of `{name}` detected")
}
}
/// S704
pub(crate) fn unsafe_markup_call(checker: &Checker, call: &ExprCall) {
if checker
.settings
.flake8_bandit
.extend_markup_names
.is_empty()
&& !(checker.semantic().seen_module(Modules::MARKUPSAFE)
|| checker.semantic().seen_module(Modules::FLASK))
{
return;
}
if !is_unsafe_call(call, checker.semantic(), checker.settings) {
return;
}
let Some(qualified_name) = checker.semantic().resolve_qualified_name(&call.func) else {
return;
};
if !is_markup_call(&qualified_name, checker.settings) {
return;
}
checker.report_diagnostic(Diagnostic::new(
UnsafeMarkupUse {
name: qualified_name.to_string(),
},
call.range(),
));
}
fn is_markup_call(qualified_name: &QualifiedName, settings: &LinterSettings) -> bool {
matches!(
qualified_name.segments(),
["markupsafe" | "flask", "Markup"]
) || settings
.flake8_bandit
.extend_markup_names
.iter()
.map(|target| QualifiedName::from_dotted_name(target))
.any(|target| *qualified_name == target)
}
fn is_unsafe_call(call: &ExprCall, semantic: &SemanticModel, settings: &LinterSettings) -> bool {
// technically this could be circumvented by using a keyword argument
// but without type-inference we can't really know which keyword argument
// corresponds to the first positional argument and either way it is
// unlikely that someone will actually use a keyword argument here
// TODO: Eventually we may want to allow dynamic values, as long as they
// have a __html__ attribute, since that is part of the API
matches!(&*call.arguments.args, [first] if !first.is_string_literal_expr() && !first.is_bytes_literal_expr() && !is_whitelisted_call(first, semantic, settings))
}
fn is_whitelisted_call(expr: &Expr, semantic: &SemanticModel, settings: &LinterSettings) -> bool {
let Expr::Call(ExprCall { func, .. }) = expr else {
return false;
};
let Some(qualified_name) = semantic.resolve_qualified_name(func) else {
return false;
};
settings
.flake8_bandit
.allowed_markup_calls
.iter()
.map(|target| QualifiedName::from_dotted_name(target))
.any(|target| qualified_name == target)
}

View File

@@ -14,6 +14,8 @@ pub fn default_tmp_dirs() -> Vec<String> {
pub struct Settings {
pub hardcoded_tmp_directory: Vec<String>,
pub check_typed_exception: bool,
pub extend_markup_names: Vec<String>,
pub allowed_markup_calls: Vec<String>,
}
impl Default for Settings {
@@ -21,6 +23,8 @@ impl Default for Settings {
Self {
hardcoded_tmp_directory: default_tmp_dirs(),
check_typed_exception: false,
extend_markup_names: vec![],
allowed_markup_calls: vec![],
}
}
}
@@ -32,7 +36,9 @@ impl Display for Settings {
namespace = "linter.flake8_bandit",
fields = [
self.hardcoded_tmp_directory | array,
self.check_typed_exception
self.check_typed_exception,
self.extend_markup_names | array,
self.allowed_markup_calls | array,
]
}
Ok(())

View File

@@ -0,0 +1,58 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S704.py:5:1: S704 Unsafe use of `markupsafe.Markup` detected
|
4 | content = "<script>alert('Hello, world!')</script>"
5 | Markup(f"unsafe {content}") # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
6 | flask.Markup("unsafe {}".format(content)) # S704
7 | Markup("safe {}").format(content)
|
S704.py:6:1: S704 Unsafe use of `flask.Markup` detected
|
4 | content = "<script>alert('Hello, world!')</script>"
5 | Markup(f"unsafe {content}") # S704
6 | flask.Markup("unsafe {}".format(content)) # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
7 | Markup("safe {}").format(content)
8 | flask.Markup(b"safe {}", encoding='utf-8').format(content)
|
S704.py:10:1: S704 Unsafe use of `markupsafe.Markup` detected
|
8 | flask.Markup(b"safe {}", encoding='utf-8').format(content)
9 | escape(content)
10 | Markup(content) # S704
| ^^^^^^^^^^^^^^^ S704
11 | flask.Markup("unsafe %s" % content) # S704
12 | Markup(object="safe")
|
S704.py:11:1: S704 Unsafe use of `flask.Markup` detected
|
9 | escape(content)
10 | Markup(content) # S704
11 | flask.Markup("unsafe %s" % content) # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
12 | Markup(object="safe")
13 | Markup(object="unsafe {}".format(content)) # Not currently detected
|
S704.py:17:1: S704 Unsafe use of `markupsafe.Markup` detected
|
15 | # NOTE: We may be able to get rid of these false positives with red-knot
16 | # if it includes comprehensive constant expression detection/evaluation.
17 | Markup("*" * 8) # S704 (false positive)
| ^^^^^^^^^^^^^^^ S704
18 | flask.Markup("hello {}".format("world")) # S704 (false positive)
|
S704.py:18:1: S704 Unsafe use of `flask.Markup` detected
|
16 | # if it includes comprehensive constant expression detection/evaluation.
17 | Markup("*" * 8) # S704 (false positive)
18 | flask.Markup("hello {}".format("world")) # S704 (false positive)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
|

View File

@@ -0,0 +1,18 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S704_extend_markup_names.py:5:1: S704 Unsafe use of `markupsafe.Markup` detected
|
4 | content = "<script>alert('Hello, world!')</script>"
5 | Markup(f"unsafe {content}") # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
6 | literal(f"unsafe {content}") # S704
|
S704_extend_markup_names.py:6:1: S704 Unsafe use of `webhelpers.html.literal` detected
|
4 | content = "<script>alert('Hello, world!')</script>"
5 | Markup(f"unsafe {content}") # S704
6 | literal(f"unsafe {content}") # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
|

View File

@@ -0,0 +1,10 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S704_skip_early_out.py:7:1: S704 Unsafe use of `webhelpers.html.literal` detected
|
5 | # markupsafe or flask first.
6 | content = "<script>alert('Hello, world!')</script>"
7 | literal(f"unsafe {content}") # S704
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S704
|

View File

@@ -0,0 +1,10 @@
---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
---
S704_whitelisted_markup_calls.py:9:1: S704 Unsafe use of `markupsafe.Markup` detected
|
7 | # indirect assignments are currently not supported
8 | cleaned = clean(content)
9 | Markup(cleaned) # S704
| ^^^^^^^^^^^^^^^ S704
|

View File

@@ -53,7 +53,7 @@ mod tests {
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
flake8_builtins: flake8_builtins::settings::Settings {
builtins_strict_checking: true,
strict_checking: true,
..Default::default()
},
..LinterSettings::for_rule(rule_code)
@@ -83,7 +83,7 @@ mod tests {
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
flake8_builtins: flake8_builtins::settings::Settings {
builtins_strict_checking: strict,
strict_checking: strict,
..Default::default()
},
..LinterSettings::for_rule(rule_code)
@@ -106,7 +106,7 @@ mod tests {
&LinterSettings {
src: vec![test_resource_path(src.join(path.parent().unwrap()))],
flake8_builtins: flake8_builtins::settings::Settings {
builtins_strict_checking: false,
strict_checking: false,
..Default::default()
},
..LinterSettings::for_rule(rule_code)
@@ -130,7 +130,7 @@ mod tests {
&LinterSettings {
project_root: test_resource_path(src.join(path.parent().unwrap())),
flake8_builtins: flake8_builtins::settings::Settings {
builtins_strict_checking: false,
strict_checking: false,
..Default::default()
},
..LinterSettings::for_rule(rule_code)
@@ -156,7 +156,7 @@ mod tests {
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
flake8_builtins: super::settings::Settings {
builtins_ignorelist: vec!["id".to_string(), "dir".to_string()],
ignorelist: vec!["id".to_string(), "dir".to_string()],
..Default::default()
},
..LinterSettings::for_rules(vec![rule_code])
@@ -199,8 +199,8 @@ mod tests {
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
flake8_builtins: super::settings::Settings {
builtins_allowed_modules: vec!["xml".to_string(), "logging".to_string()],
builtins_strict_checking: true,
allowed_modules: vec!["xml".to_string(), "logging".to_string()],
strict_checking: true,
..Default::default()
},
..LinterSettings::for_rules(vec![rule_code])

View File

@@ -19,7 +19,7 @@ use super::super::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.ignorelist`] configuration option.
///
/// ## Example
/// ```python
@@ -44,7 +44,7 @@ use super::super::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `lint.flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.ignorelist`
///
/// ## References
/// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide)
@@ -67,7 +67,7 @@ pub(crate) fn builtin_argument_shadowing(checker: &Checker, parameter: &Paramete
if shadows_builtin(
parameter.name(),
checker.source_type,
&checker.settings.flake8_builtins.builtins_ignorelist,
&checker.settings.flake8_builtins.ignorelist,
checker.target_version(),
) {
// Ignore parameters in lambda expressions.

View File

@@ -37,7 +37,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// Builtins can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option, or
/// [`lint.flake8-builtins.ignorelist`] configuration option, or
/// converted to the appropriate dunder method. Methods decorated with
/// `@typing.override` or `@typing_extensions.override` are also
/// ignored.
@@ -55,7 +55,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `lint.flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.ignorelist`
#[derive(ViolationMetadata)]
pub(crate) struct BuiltinAttributeShadowing {
kind: Kind,
@@ -98,7 +98,7 @@ pub(crate) fn builtin_attribute_shadowing(
if shadows_builtin(
name,
checker.source_type,
&checker.settings.flake8_builtins.builtins_ignorelist,
&checker.settings.flake8_builtins.ignorelist,
checker.target_version(),
) {
// Ignore explicit overrides.

View File

@@ -14,7 +14,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// as readers may mistake the variable for the builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.ignorelist`] configuration option.
///
/// ## Example
/// ```python
@@ -38,7 +38,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `lint.flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.ignorelist`
/// - `target-version`
///
#[derive(ViolationMetadata)]
@@ -60,7 +60,7 @@ pub(crate) fn builtin_import_shadowing(checker: &Checker, alias: &Alias) {
if shadows_builtin(
name.as_str(),
checker.source_type,
&checker.settings.flake8_builtins.builtins_ignorelist,
&checker.settings.flake8_builtins.ignorelist,
checker.target_version(),
) {
checker.report_diagnostic(Diagnostic::new(

View File

@@ -16,10 +16,10 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// builtin, and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.ignorelist`] configuration option.
///
/// ## Options
/// - `lint.flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.ignorelist`
#[derive(ViolationMetadata)]
pub(crate) struct BuiltinLambdaArgumentShadowing {
name: String,
@@ -43,7 +43,7 @@ pub(crate) fn builtin_lambda_argument_shadowing(checker: &Checker, lambda: &Expr
if shadows_builtin(
name,
checker.source_type,
&checker.settings.flake8_builtins.builtins_ignorelist,
&checker.settings.flake8_builtins.ignorelist,
checker.target_version(),
) {
checker.report_diagnostic(Diagnostic::new(

View File

@@ -17,7 +17,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.ignorelist`] configuration option.
///
/// ## Example
/// ```python
@@ -40,7 +40,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `lint.flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.ignorelist`
///
/// ## References
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
@@ -71,7 +71,7 @@ pub(crate) fn builtin_variable_shadowing(checker: &Checker, name: &str, range: T
if shadows_builtin(
name,
checker.source_type,
&checker.settings.flake8_builtins.builtins_ignorelist,
&checker.settings.flake8_builtins.ignorelist,
checker.target_version(),
) {
checker.report_diagnostic(Diagnostic::new(

View File

@@ -21,15 +21,14 @@ use crate::settings::LinterSettings;
/// standard-library module and vice versa.
///
/// Standard-library modules can be marked as exceptions to this rule via the
/// [`lint.flake8-builtins.builtins-allowed-modules`] configuration option.
/// [`lint.flake8-builtins.allowed-modules`] configuration option.
///
/// By default, only the last component of the module name is considered, so `logging.py`,
/// `utils/logging.py`, and `utils/logging/__init__.py` would all clash with the builtin `logging`
/// module. With the [`lint.flake8-builtins.builtins-strict-checking`] option set to `false`, the
/// module path is considered, so only a top-level `logging.py` or `logging/__init__.py` will
/// trigger the rule and `utils/logging.py`, for example, would not. In preview mode, the default
/// value of [`lint.flake8-builtins.builtins-strict-checking`] is `false` rather than `true` in
/// stable mode.
/// By default, the module path relative to the project root or [`src`] directories is considered,
/// so a top-level `logging.py` or `logging/__init__.py` will clash with the builtin `logging`
/// module, but `utils/logging.py`, for example, will not. With the
/// [`lint.flake8-builtins.strict-checking`] option set to `true`, only the last component
/// of the module name is considered, so `logging.py`, `utils/logging.py`, and
/// `utils/logging/__init__.py` will all trigger the rule.
///
/// This rule is not applied to stub files, as the name of a stub module is out
/// of the control of the author of the stub file. Instead, a stub should aim to
@@ -50,8 +49,8 @@ use crate::settings::LinterSettings;
/// ```
///
/// ## Options
/// - `lint.flake8-builtins.builtins-allowed-modules`
/// - `lint.flake8-builtins.builtins-strict-checking`
/// - `lint.flake8-builtins.allowed-modules`
/// - `lint.flake8-builtins.strict-checking`
#[derive(ViolationMetadata)]
pub(crate) struct StdlibModuleShadowing {
name: String,
@@ -104,7 +103,7 @@ pub(crate) fn stdlib_module_shadowing(
}
// not allowed generally, but check for a parent in non-strict mode
if !settings.flake8_builtins.builtins_strict_checking && components.next().is_some() {
if !settings.flake8_builtins.strict_checking && components.next().is_some() {
return None;
}
@@ -136,7 +135,7 @@ fn is_allowed_module(settings: &LinterSettings, version: PythonVersion, module:
if settings
.flake8_builtins
.builtins_allowed_modules
.allowed_modules
.iter()
.any(|allowed_module| allowed_module == module)
{

View File

@@ -1,24 +1,14 @@
//! Settings for the `flake8-builtins` plugin.
use crate::{display_settings, settings::types::PreviewMode};
use crate::display_settings;
use ruff_macros::CacheKey;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, Default, CacheKey)]
pub struct Settings {
pub builtins_ignorelist: Vec<String>,
pub builtins_allowed_modules: Vec<String>,
pub builtins_strict_checking: bool,
}
impl Settings {
pub fn new(preview: PreviewMode) -> Self {
Self {
builtins_ignorelist: Vec::new(),
builtins_allowed_modules: Vec::new(),
builtins_strict_checking: preview.is_disabled(),
}
}
pub ignorelist: Vec<String>,
pub allowed_modules: Vec<String>,
pub strict_checking: bool,
}
impl Display for Settings {
@@ -27,9 +17,9 @@ impl Display for Settings {
formatter = f,
namespace = "linter.flake8_builtins",
fields = [
self.builtins_allowed_modules | array,
self.builtins_ignorelist | array,
self.builtins_strict_checking,
self.allowed_modules | array,
self.ignorelist | array,
self.strict_checking,
]
}
Ok(())

View File

@@ -9,7 +9,6 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -22,6 +21,7 @@ mod tests {
#[test_case(Rule::CallDatetimeStrptimeWithoutZone, Path::new("DTZ007.py"))]
#[test_case(Rule::CallDateToday, Path::new("DTZ011.py"))]
#[test_case(Rule::CallDateFromtimestamp, Path::new("DTZ012.py"))]
#[test_case(Rule::DatetimeMinMax, Path::new("DTZ901.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
@@ -31,18 +31,4 @@ mod tests {
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test_case(Rule::DatetimeMinMax, Path::new("DTZ901.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_datetimez").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -9,18 +9,18 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for uses of `datetime.datetime.max` and `datetime.datetime.min`.
/// Checks for uses of `datetime.datetime.min` and `datetime.datetime.max`.
///
/// ## Why is this bad?
/// `datetime.max` and `datetime.min` are non-timezone-aware datetime objects.
/// `datetime.min` and `datetime.max` are non-timezone-aware datetime objects.
///
/// As such, operations on `datetime.max` and `datetime.min` may behave
/// As such, operations on `datetime.min` and `datetime.max` may behave
/// unexpectedly, as in:
///
/// ```python
/// # Timezone: UTC-14
/// datetime.max.timestamp() # ValueError: year 10000 is out of range
/// datetime.min.timestamp() # ValueError: year 0 is out of range
/// datetime.max.timestamp() # ValueError: year 10000 is out of range
/// ```
///
/// ## Example
@@ -53,7 +53,7 @@ impl Violation for DatetimeMinMax {
}
/// DTZ901
pub(crate) fn datetime_max_min(checker: &Checker, expr: &Expr) {
pub(crate) fn datetime_min_max(checker: &Checker, expr: &Expr) {
let semantic = checker.semantic();
if !semantic.seen_module(Modules::DATETIME) {

View File

@@ -156,30 +156,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::CustomTypeVarForSelf, Path::new("PYI019_0.py"))]
#[test_case(Rule::CustomTypeVarForSelf, Path::new("PYI019_0.pyi"))]
#[test_case(Rule::CustomTypeVarForSelf, Path::new("PYI019_1.pyi"))]
fn custom_classmethod_rules_preview(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview_{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_pyi").join(path).as_path(),
&settings::LinterSettings {
pep8_naming: pep8_naming::settings::Settings {
classmethod_decorators: vec!["foo_classmethod".to_string()],
..pep8_naming::settings::Settings::default()
},
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test_case(Rule::TypeAliasWithoutAnnotation, Path::new("PYI026.py"))]
#[test_case(Rule::TypeAliasWithoutAnnotation, Path::new("PYI026.pyi"))]
#[test_case(Rule::RedundantNoneLiteral, Path::new("PYI061.py"))]
@@ -198,8 +174,6 @@ mod tests {
}
#[test_case(Rule::FutureAnnotationsInStub, Path::new("PYI044.pyi"))]
#[test_case(Rule::UnusedPrivateTypeVar, Path::new("PYI018.py"))]
#[test_case(Rule::UnusedPrivateTypeVar, Path::new("PYI018.pyi"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",

View File

@@ -71,20 +71,8 @@ use ruff_python_ast::PythonVersion;
/// The fix is only marked as unsafe if there is the possibility that it might delete a comment
/// from your code.
///
/// ## Preview-mode behaviour
/// This rule's behaviour has several differences when [`preview`] mode is enabled:
/// 1. The fix for this rule is currently only available if `preview` mode is enabled.
/// 2. By default, this rule is only applied to methods that have return-type annotations,
/// and the range of the diagnostic is the range of the return-type annotation.
/// In preview mode, this rule is also applied to some methods that do not have
/// return-type annotations. The range of the diagnostic is the range of the function
/// header (from the end of the function name to the end of the parameters).
/// 3. In `preview` mode, the rule uses different logic to determine whether an annotation
/// refers to a type variable. The `preview`-mode logic is more accurate, but may lead
/// to more methods being flagged than if `preview` mode is disabled.
///
/// [PEP 673]: https://peps.python.org/pep-0673/#motivation
/// [PEP 695]: https://peps.python.org/pep-0695/
/// [PEP-695]: https://peps.python.org/pep-0695/
/// [PYI018]: https://docs.astral.sh/ruff/rules/unused-private-type-var/
/// [type parameter list]: https://docs.python.org/3/reference/compound_stmts.html#type-params
/// [Self]: https://docs.python.org/3/library/typing.html#typing.Self
@@ -162,73 +150,33 @@ pub(crate) fn custom_type_var_instead_of_self(
&checker.settings.pep8_naming.staticmethod_decorators,
);
let function_header_end = returns
.as_deref()
.map(Ranged::end)
.unwrap_or_else(|| parameters.end());
// In stable mode, we only emit the diagnostic on methods that have a return type annotation.
// In preview mode, we have a more principled approach to determine if an annotation refers
// to a type variable, and we emit the diagnostic on some methods that do not have return
// annotations.
let (method, diagnostic_range) = match function_kind {
FunctionType::ClassMethod | FunctionType::NewMethod => {
if checker.settings.preview.is_enabled() {
(
Method::PreviewClass(PreviewClassMethod {
cls_annotation: self_or_cls_annotation,
type_params,
}),
TextRange::new(function_name.end(), function_header_end),
)
} else {
returns.as_deref().map(|returns| {
(
Method::Class(ClassMethod {
cls_annotation: self_or_cls_annotation,
returns,
type_params,
}),
returns.range(),
)
})?
}
}
FunctionType::Method => {
if checker.settings.preview.is_enabled() {
(
Method::PreviewInstance(PreviewInstanceMethod {
self_annotation: self_or_cls_annotation,
type_params,
}),
TextRange::new(function_name.end(), function_header_end),
)
} else {
returns.as_deref().map(|returns| {
(
Method::Instance(InstanceMethod {
self_annotation: self_or_cls_annotation,
returns,
type_params,
}),
returns.range(),
)
})?
}
}
let method = match function_kind {
FunctionType::ClassMethod | FunctionType::NewMethod => Method::Class(ClassMethod {
cls_annotation: self_or_cls_annotation,
type_params,
}),
FunctionType::Method => Method::Instance(InstanceMethod {
self_annotation: self_or_cls_annotation,
type_params,
}),
FunctionType::Function | FunctionType::StaticMethod => return None,
};
let custom_typevar = method.custom_typevar(semantic, binding.scope)?;
let function_header_end = returns
.as_deref()
.map(Ranged::end)
.unwrap_or_else(|| parameters.end());
let mut diagnostic = Diagnostic::new(
CustomTypeVarForSelf {
typevar_name: custom_typevar.name(checker.source()).to_string(),
},
diagnostic_range,
TextRange::new(function_name.end(), function_header_end),
);
diagnostic.try_set_optional_fix(|| {
diagnostic.try_set_fix(|| {
replace_custom_typevar_with_self(
checker,
function_def,
@@ -244,9 +192,7 @@ pub(crate) fn custom_type_var_instead_of_self(
#[derive(Debug)]
enum Method<'a> {
Class(ClassMethod<'a>),
PreviewClass(PreviewClassMethod<'a>),
Instance(InstanceMethod<'a>),
PreviewInstance(PreviewInstanceMethod<'a>),
}
impl Method<'_> {
@@ -257,9 +203,7 @@ impl Method<'_> {
) -> Option<TypeVar<'a>> {
match self {
Self::Class(class_method) => class_method.custom_typevar(semantic, scope),
Self::PreviewClass(class_method) => class_method.custom_typevar(semantic, scope),
Self::Instance(instance_method) => instance_method.custom_typevar(semantic),
Self::PreviewInstance(instance_method) => instance_method.custom_typevar(semantic),
}
}
}
@@ -267,76 +211,10 @@ impl Method<'_> {
#[derive(Debug)]
struct ClassMethod<'a> {
cls_annotation: &'a ast::Expr,
returns: &'a ast::Expr,
type_params: Option<&'a ast::TypeParams>,
}
impl ClassMethod<'_> {
/// Returns `Some(typevar)` if the class method is annotated with
/// a custom `TypeVar` that is likely private.
fn custom_typevar<'a>(
&'a self,
semantic: &'a SemanticModel<'a>,
scope: ScopeId,
) -> Option<TypeVar<'a>> {
let ast::ExprSubscript {
value: cls_annotation_value,
slice: cls_annotation_typevar,
..
} = self.cls_annotation.as_subscript_expr()?;
let cls_annotation_typevar = cls_annotation_typevar.as_name_expr()?;
let cls_annotation_typevar_name = &cls_annotation_typevar.id;
let ast::ExprName { id, .. } = cls_annotation_value.as_name_expr()?;
if id != "type" {
return None;
}
if !semantic.has_builtin_binding_in_scope("type", scope) {
return None;
}
let return_annotation_typevar = match self.returns {
ast::Expr::Name(ast::ExprName { id, .. }) => id,
ast::Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => {
let return_annotation_typevar = slice.as_name_expr()?;
let ast::ExprName { id, .. } = value.as_name_expr()?;
if id != "type" {
return None;
}
&return_annotation_typevar.id
}
_ => return None,
};
if cls_annotation_typevar_name != return_annotation_typevar {
return None;
}
if !is_likely_private_typevar(cls_annotation_typevar_name, self.type_params) {
return None;
}
semantic
.resolve_name(cls_annotation_typevar)
.map(|binding_id| TypeVar(semantic.binding(binding_id)))
}
}
/// Struct for implementing this rule as applied to classmethods in preview mode.
///
/// In stable mode, we only emit this diagnostic on methods that have return annotations,
/// so the stable-mode version of this struct has a `returns: &ast::Expr` field. In preview
/// mode, we also emit this diagnostic on methods that do not have return annotations, so
/// the preview-mode version of this struct does not have a `returns` field.
#[derive(Debug)]
struct PreviewClassMethod<'a> {
cls_annotation: &'a ast::Expr,
type_params: Option<&'a ast::TypeParams>,
}
impl PreviewClassMethod<'_> {
/// Returns `Some(typevar)` if the class method is annotated with
/// a custom `TypeVar` for the `cls` parameter
fn custom_typevar<'a>(
@@ -360,59 +238,21 @@ impl PreviewClassMethod<'_> {
return None;
}
custom_typevar_preview(cls_annotation_typevar, self.type_params, semantic)
custom_typevar(cls_annotation_typevar, self.type_params, semantic)
}
}
#[derive(Debug)]
struct InstanceMethod<'a> {
self_annotation: &'a ast::Expr,
returns: &'a ast::Expr,
type_params: Option<&'a ast::TypeParams>,
}
impl InstanceMethod<'_> {
/// Returns `Some(typevar)` if the instance method is annotated with
/// a custom `TypeVar` that is likely private.
fn custom_typevar<'a>(&'a self, semantic: &'a SemanticModel<'a>) -> Option<TypeVar<'a>> {
let self_annotation = self.self_annotation.as_name_expr()?;
let first_arg_type = &self_annotation.id;
let ast::ExprName {
id: return_type, ..
} = self.returns.as_name_expr()?;
if first_arg_type != return_type {
return None;
}
if !is_likely_private_typevar(first_arg_type, self.type_params) {
return None;
}
semantic
.resolve_name(self_annotation)
.map(|binding_id| TypeVar(semantic.binding(binding_id)))
}
}
/// Struct for implementing this rule as applied to instance methods in preview mode.
///
/// In stable mode, we only emit this diagnostic on methods that have return annotations,
/// so the stable-mode version of this struct has a `returns: &ast::Expr` field. In preview
/// mode, we also emit this diagnostic on methods that do not have return annotations, so
/// the preview-mode version of this struct does not have a `returns` field.
#[derive(Debug)]
struct PreviewInstanceMethod<'a> {
self_annotation: &'a ast::Expr,
type_params: Option<&'a ast::TypeParams>,
}
impl PreviewInstanceMethod<'_> {
/// Returns `Some(typevar)` if the instance method is annotated with
/// a custom `TypeVar` for the `self` parameter
fn custom_typevar<'a>(&'a self, semantic: &'a SemanticModel<'a>) -> Option<TypeVar<'a>> {
custom_typevar_preview(
custom_typevar(
self.self_annotation.as_name_expr()?,
self.type_params,
semantic,
@@ -420,30 +260,8 @@ impl PreviewInstanceMethod<'_> {
}
}
/// Returns `true` if the type variable is likely private.
///
/// This routine is only used if `--preview` is not enabled,
/// as it uses heuristics to determine if an annotation uses a type variable.
/// In preview mode, we apply a more principled approach.
fn is_likely_private_typevar(type_var_name: &str, type_params: Option<&ast::TypeParams>) -> bool {
// Ex) `_T`
if type_var_name.starts_with('_') {
return true;
}
// Ex) `class Foo[T]: ...`
type_params.is_some_and(|type_params| {
type_params.iter().any(|type_param| {
if let ast::TypeParam::TypeVar(ast::TypeParamTypeVar { name, .. }) = type_param {
name == type_var_name
} else {
false
}
})
})
}
/// Returns `Some(TypeVar)` if `typevar_expr` refers to a `TypeVar` binding
fn custom_typevar_preview<'a>(
fn custom_typevar<'a>(
typevar_expr: &'a ast::ExprName,
type_params: Option<&ast::TypeParams>,
semantic: &'a SemanticModel<'a>,
@@ -497,11 +315,7 @@ fn replace_custom_typevar_with_self(
custom_typevar: TypeVar,
self_or_cls_parameter: &ast::ParameterWithDefault,
self_or_cls_annotation: &ast::Expr,
) -> anyhow::Result<Option<Fix>> {
if checker.settings.preview.is_disabled() {
return Ok(None);
}
) -> anyhow::Result<Fix> {
// (1) Import `Self` (if necessary)
let (import_edit, self_symbol_binding) = import_self(checker, function_def.start())?;
@@ -513,9 +327,9 @@ fn replace_custom_typevar_with_self(
// (3) If it was a PEP-695 type variable, remove that `TypeVar` from the PEP-695 type-parameter list
if custom_typevar.is_pep695_typevar() {
let Some(type_params) = function_def.type_params.as_deref() else {
bail!("Should not be possible to have a type parameter without a type parameter list");
};
let type_params = function_def.type_params.as_deref().context(
"Should not be possible to have a type parameter without a type parameter list",
)?;
let deletion_edit = remove_pep695_typevar_declaration(type_params, custom_typevar)
.context("Failed to find a `TypeVar` in the type params that matches the binding")?;
other_edits.push(deletion_edit);
@@ -546,11 +360,11 @@ fn replace_custom_typevar_with_self(
Applicability::Safe
};
Ok(Some(Fix::applicable_edits(
Ok(Fix::applicable_edits(
import_edit,
other_edits,
applicability,
)))
))
}
/// Attempt to create an [`Edit`] that imports `Self`.

View File

@@ -26,9 +26,8 @@ use crate::fix;
/// _Ts = typing_extensions.TypeVarTuple("_Ts")
/// ```
///
/// ## Fix safety and availability
/// This rule's fix is available when [`preview`] mode is enabled.
/// It is always marked as unsafe, as it would break your code if the type
/// ## Fix safety
/// The fix is always marked as unsafe, as it would break your code if the type
/// variable is imported by another module.
#[derive(ViolationMetadata)]
pub(crate) struct UnusedPrivateTypeVar {
@@ -225,18 +224,19 @@ pub(crate) fn unused_private_type_var(checker: &Checker, scope: &Scope) {
continue;
};
let mut diagnostic = Diagnostic::new(
let diagnostic = Diagnostic::new(
UnusedPrivateTypeVar {
type_var_like_name: id.to_string(),
type_var_like_kind: type_var_like_kind.to_string(),
},
binding.range(),
);
if checker.settings.preview.is_enabled() {
let edit = fix::edits::delete_stmt(stmt, None, checker.locator(), checker.indexer());
diagnostic.set_fix(Fix::unsafe_edit(edit));
}
)
.with_fix(Fix::unsafe_edit(fix::edits::delete_stmt(
stmt,
None,
checker.locator(),
checker.indexer(),
)));
checker.report_diagnostic(diagnostic);
}

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI018.py:6:1: PYI018 Private TypeVar `_T` is never used
PYI018.py:6:1: PYI018 [*] Private TypeVar `_T` is never used
|
4 | from typing_extensions import ParamSpec, TypeVarTuple
5 |
@@ -12,7 +12,16 @@ PYI018.py:6:1: PYI018 Private TypeVar `_T` is never used
|
= help: Remove unused private TypeVar `_T`
PYI018.py:7:1: PYI018 Private TypeVarTuple `_Ts` is never used
Unsafe fix
3 3 | from typing import TypeVar
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 |-_T = typing.TypeVar("_T")
7 6 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
PYI018.py:7:1: PYI018 [*] Private TypeVarTuple `_Ts` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
@@ -22,7 +31,16 @@ PYI018.py:7:1: PYI018 Private TypeVarTuple `_Ts` is never used
|
= help: Remove unused private TypeVarTuple `_Ts`
PYI018.py:8:1: PYI018 Private ParamSpec `_P` is never used
Unsafe fix
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 |-_Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
PYI018.py:8:1: PYI018 [*] Private ParamSpec `_P` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
@@ -33,7 +51,16 @@ PYI018.py:8:1: PYI018 Private ParamSpec `_P` is never used
|
= help: Remove unused private ParamSpec `_P`
PYI018.py:9:1: PYI018 Private ParamSpec `_P2` is never used
Unsafe fix
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 |-_P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
PYI018.py:9:1: PYI018 [*] Private ParamSpec `_P2` is never used
|
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
@@ -43,7 +70,16 @@ PYI018.py:9:1: PYI018 Private ParamSpec `_P2` is never used
|
= help: Remove unused private ParamSpec `_P2`
PYI018.py:10:1: PYI018 Private TypeVarTuple `_Ts2` is never used
Unsafe fix
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 |-_P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
PYI018.py:10:1: PYI018 [*] Private TypeVarTuple `_Ts2` is never used
|
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
@@ -53,3 +89,12 @@ PYI018.py:10:1: PYI018 Private TypeVarTuple `_Ts2` is never used
12 | # OK
|
= help: Remove unused private TypeVarTuple `_Ts2`
Unsafe fix
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 9 | _P2 = typing.ParamSpec("_P2")
10 |-_Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
13 12 | _UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI018.pyi:6:1: PYI018 Private TypeVar `_T` is never used
PYI018.pyi:6:1: PYI018 [*] Private TypeVar `_T` is never used
|
4 | from typing_extensions import ParamSpec, TypeVarTuple
5 |
@@ -12,7 +12,16 @@ PYI018.pyi:6:1: PYI018 Private TypeVar `_T` is never used
|
= help: Remove unused private TypeVar `_T`
PYI018.pyi:7:1: PYI018 Private TypeVarTuple `_Ts` is never used
Unsafe fix
3 3 | from typing import TypeVar
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 |-_T = typing.TypeVar("_T")
7 6 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
PYI018.pyi:7:1: PYI018 [*] Private TypeVarTuple `_Ts` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
@@ -22,7 +31,16 @@ PYI018.pyi:7:1: PYI018 Private TypeVarTuple `_Ts` is never used
|
= help: Remove unused private TypeVarTuple `_Ts`
PYI018.pyi:8:1: PYI018 Private ParamSpec `_P` is never used
Unsafe fix
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 |-_Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
PYI018.pyi:8:1: PYI018 [*] Private ParamSpec `_P` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
@@ -33,7 +51,16 @@ PYI018.pyi:8:1: PYI018 Private ParamSpec `_P` is never used
|
= help: Remove unused private ParamSpec `_P`
PYI018.pyi:9:1: PYI018 Private ParamSpec `_P2` is never used
Unsafe fix
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 |-_P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
PYI018.pyi:9:1: PYI018 [*] Private ParamSpec `_P2` is never used
|
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
@@ -43,7 +70,16 @@ PYI018.pyi:9:1: PYI018 Private ParamSpec `_P2` is never used
|
= help: Remove unused private ParamSpec `_P2`
PYI018.pyi:10:1: PYI018 Private TypeVarTuple `_Ts2` is never used
Unsafe fix
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 |-_P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
PYI018.pyi:10:1: PYI018 [*] Private TypeVarTuple `_Ts2` is never used
|
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
@@ -53,3 +89,12 @@ PYI018.pyi:10:1: PYI018 Private TypeVarTuple `_Ts2` is never used
12 | # OK
|
= help: Remove unused private TypeVarTuple `_Ts2`
Unsafe fix
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 9 | _P2 = typing.ParamSpec("_P2")
10 |-_Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
13 12 | _UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -1,316 +1,692 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_0.py:7:62: PYI019 Use `Self` instead of custom TypeVar `_S`
PYI019_0.py:7:16: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:10:54: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
4 4 | _S2 = TypeVar("_S2", BadClass, GoodClass)
5 5 |
6 6 | class BadClass:
7 |- def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
7 |+ def __new__(cls, *args: str, **kwargs: int) -> Self: ... # PYI019
8 8 |
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019_0.py:10:28: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:14:54: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
7 7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
8 8 |
9 9 |
10 |- def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
10 |+ def bad_instance_method(self, arg: bytes) -> Self: ... # PYI019
11 11 |
12 12 |
13 13 | @classmethod
PYI019_0.py:14:25: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:18:55: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
11 11 |
12 12 |
13 13 | @classmethod
14 |- def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
14 |+ def bad_class_method(cls, arg: int) -> Self: ... # PYI019
15 15 |
16 16 |
17 17 | @classmethod
PYI019_0.py:18:33: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.py:39:63: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
15 15 |
16 16 |
17 17 | @classmethod
18 |- def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
18 |+ def bad_posonly_class_method(cls, /) -> Self: ... # PYI019
19 19 |
20 20 |
21 21 | @classmethod
PYI019_0.py:39:14: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:42:46: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
36 36 |
37 37 | # Python > 3.12
38 38 | class PEP695BadDunderNew[T]:
39 |- def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
39 |+ def __new__(cls, *args: Any, ** kwargs: Any) -> Self: ... # PYI019
40 40 |
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019_0.py:42:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:54:32: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
39 39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
40 40 |
41 41 |
42 |- def generic_instance_method[S](self: S) -> S: ... # PYI019
42 |+ def generic_instance_method(self) -> Self: ... # PYI019
43 43 |
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019_0.py:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
52 | # in the settings for this test:
53 | @foo_classmethod
54 | def foo[S](cls: type[S]) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:61:48: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
51 51 | # due to `foo_classmethod being listed in `pep8_naming.classmethod-decorators`
52 52 | # in the settings for this test:
53 53 | @foo_classmethod
54 |- def foo[S](cls: type[S]) -> S: ... # PYI019
54 |+ def foo(cls) -> Self: ... # PYI019
55 55 |
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019_0.py:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:63:47: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
58 58 |
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019_0.py:63:26: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:65:43: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
60 60 | class PEP695Fix:
61 61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 62 |
63 |- def __init_subclass__[S](cls: type[S]) -> S: ...
63 |+ def __init_subclass__(cls) -> Self: ...
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019_0.py:65:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
66 |
67 | def __pos__[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:67:32: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
65 |- def __neg__[S: PEP695Fix](self: S) -> S: ...
65 |+ def __neg__(self) -> Self: ...
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019_0.py:67:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
67 | def __pos__[S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:69:53: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
67 |- def __pos__[S](self: S) -> S: ...
67 |+ def __pos__(self) -> Self: ...
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019_0.py:69:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:71:42: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
69 |- def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
69 |+ def __add__(self, other: Self) -> Self: ...
70 70 |
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019_0.py:71:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
72 |
73 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:74:59: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
71 |- def __sub__[S](self: S, other: S) -> S: ...
71 |+ def __sub__(self, other: Self) -> Self: ...
72 72 |
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019_0.py:74:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
75 |
76 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:77:50: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
73 73 | @classmethod
74 |- def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
74 |+ def class_method_bound(cls) -> Self: ...
75 75 |
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019_0.py:77:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:79:57: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
75 75 |
76 76 | @classmethod
77 |- def class_method_unbound[S](cls: type[S]) -> S: ...
77 |+ def class_method_unbound(cls) -> Self: ...
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019_0.py:79:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:81:48: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 78 |
79 |- def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
79 |+ def instance_method_bound(self) -> Self: ...
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019_0.py:81:32: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:83:90: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
81 |- def instance_method_unbound[S](self: S) -> S: ...
81 |+ def instance_method_unbound(self) -> Self: ...
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019_0.py:83:53: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:85:81: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
83 |- def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
83 |+ def instance_method_bound_with_another_parameter(self, other: Self) -> Self: ...
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019_0.py:85:55: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:87:94: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
85 |- def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
85 |+ def instance_method_unbound_with_another_parameter(self, other: Self) -> Self: ...
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019_0.py:87:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:89:75: PYI019 Use `Self` instead of custom TypeVar `_S695`
Safe fix
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
87 |- def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
87 |+ def multiple_type_vars[*Ts, T](self, other: Self, /, *args: *Ts, a: T, b: list[T]) -> Self: ...
88 88 |
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019_0.py:89:43: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
| ^^^^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S695` with `Self`
PYI019_0.py:114:31: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
89 |- def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
89 |+ def mixing_old_and_new_style_type_vars[T](self, a: T, b: T) -> Self: ...
90 90 |
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019_0.py:94:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
92 | class InvalidButWeDoNotPanic:
93 | @classmethod
94 | def m[S](cls: type[S], /) -> S[int]: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
95 | def n(self: S) -> S[int]: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
91 91 |
92 92 | class InvalidButWeDoNotPanic:
93 93 | @classmethod
94 |- def m[S](cls: type[S], /) -> S[int]: ...
94 |+ def m(cls, /) -> Self[int]: ...
95 95 | def n(self: S) -> S[int]: ...
96 96 |
97 97 |
PYI019_0.py:114:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
112 | class SubscriptReturnType:
113 | @classmethod
114 | def m[S](cls: type[S]) -> type[S]: ... # PYI019
| ^^^^^^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:129:34: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
|
127 | # but our preview-mode logic is smarter about this.
128 | class Foo:
129 | def x(self: _NotATypeVar) -> _NotATypeVar: ...
| ^^^^^^^^^^^^ PYI019
130 | @classmethod
131 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
Safe fix
111 111 |
112 112 | class SubscriptReturnType:
113 113 | @classmethod
114 |- def m[S](cls: type[S]) -> type[S]: ... # PYI019
114 |+ def m(cls) -> type[Self]: ... # PYI019
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
PYI019_0.py:131:40: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
PYI019_0.py:118:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
129 | def x(self: _NotATypeVar) -> _NotATypeVar: ...
130 | @classmethod
131 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
| ^^^^^^^^^^^^ PYI019
117 | class SelfNotUsedInReturnAnnotation:
118 | def m[S](self: S, other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
119 | @classmethod
120 | def n[S](cls: type[S], other: S) -> int: ...
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:140:49: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
118 |- def m[S](self: S, other: S) -> int: ...
118 |+ def m(self, other: Self) -> int: ...
119 119 | @classmethod
120 120 | def n[S](cls: type[S], other: S) -> int: ...
121 121 |
PYI019_0.py:120:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
118 | def m[S](self: S, other: S) -> int: ...
119 | @classmethod
120 | def n[S](cls: type[S], other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
117 117 | class SelfNotUsedInReturnAnnotation:
118 118 | def m[S](self: S, other: S) -> int: ...
119 119 | @classmethod
120 |- def n[S](cls: type[S], other: S) -> int: ...
120 |+ def n(cls, other: Self) -> int: ...
121 121 |
122 122 |
123 123 | class _NotATypeVar: ...
PYI019_0.py:135:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
134 | class NoReturnAnnotations:
135 | def m[S](self: S, other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
136 | @classmethod
137 | def n[S](cls: type[S], other: S): ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
132 132 |
133 133 |
134 134 | class NoReturnAnnotations:
135 |- def m[S](self: S, other: S): ...
135 |+ def m(self, other: Self): ...
136 136 | @classmethod
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
PYI019_0.py:137:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
135 | def m[S](self: S, other: S): ...
136 | @classmethod
137 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
138 |
139 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
134 134 | class NoReturnAnnotations:
135 135 | def m[S](self: S, other: S): ...
136 136 | @classmethod
137 |- def n[S](cls: type[S], other: S): ...
137 |+ def n(cls, other: Self): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.py:140:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:141:63: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 |- def m[S: int, T: int](self: S, other: T) -> S: ...
140 |+ def m[T: int](self, other: T) -> Self: ...
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
PYI019_0.py:141:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
142 |
143 | class MethodsWithBody:
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:144:36: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
141 |+ def n[T: (int, str)](self, other: T) -> Self: ...
142 142 |
143 143 | class MethodsWithBody:
144 144 | def m[S](self: S, other: S) -> S:
PYI019_0.py:144:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
143 | class MethodsWithBody:
144 | def m[S](self: S, other: S) -> S:
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
145 | x: S = other
146 | return x
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:149:41: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
144 |- def m[S](self: S, other: S) -> S:
145 |- x: S = other
144 |+ def m(self, other: Self) -> Self:
145 |+ x: Self = other
146 146 | return x
147 147 |
148 148 | @classmethod
PYI019_0.py:149:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
148 | @classmethod
149 | def n[S](cls: type[S], other: S) -> S:
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
150 | x: type[S] = type(other)
151 | return x()
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:154:26: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
146 146 | return x
147 147 |
148 148 | @classmethod
149 |- def n[S](cls: type[S], other: S) -> S:
150 |- x: type[S] = type(other)
149 |+ def n(cls, other: Self) -> Self:
150 |+ x: type[Self] = type(other)
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
PYI019_0.py:154:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
153 | class StringizedReferencesCanBeFixed:
154 | def m[S](self: S) -> S:
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
155 | x = cast("list[tuple[S, S]]", self)
156 | return x
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:159:28: PYI019 Use `Self` instead of custom TypeVar `_T`
Safe fix
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
154 |- def m[S](self: S) -> S:
155 |- x = cast("list[tuple[S, S]]", self)
154 |+ def m(self) -> Self:
155 |+ x = cast("list[tuple[Self, Self]]", self)
156 156 | return x
157 157 |
158 158 | class ButStrangeStringizedReferencesCannotBeFixed:
PYI019_0.py:159:10: PYI019 Use `Self` instead of custom TypeVar `_T`
|
158 | class ButStrangeStringizedReferencesCannotBeFixed:
159 | def m[_T](self: _T) -> _T:
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^ PYI019
160 | x = cast('list[_\x54]', self)
161 | return x
|
= help: Replace TypeVar `_T` with `Self`
PYI019_0.py:164:26: PYI019 Use `Self` instead of custom TypeVar `S`
PYI019_0.py:164:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
163 | class DeletionsAreNotTouched:
164 | def m[S](self: S) -> S:
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 | # so `del S` here is not actually a reference to the type variable `S`.
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.py:173:26: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
161 161 | return x
162 162 |
163 163 | class DeletionsAreNotTouched:
164 |- def m[S](self: S) -> S:
164 |+ def m(self) -> Self:
165 165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 166 | # so `del S` here is not actually a reference to the type variable `S`.
167 167 | # This `del` statement is therefore not touched by the autofix (it raises `UnboundLocalError`
PYI019_0.py:173:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
172 | class NamesShadowingTypeVarAreNotTouched:
173 | def m[S](self: S) -> S:
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
174 | type S = int
175 | print(S) # not a reference to the type variable, so not touched by the autofix
|
= help: Replace TypeVar `S` with `Self`
Safe fix
170 170 | return self
171 171 |
172 172 | class NamesShadowingTypeVarAreNotTouched:
173 |- def m[S](self: S) -> S:
173 |+ def m(self) -> Self:
174 174 | type S = int
175 175 | print(S) # not a reference to the type variable, so not touched by the autofix
176 176 | return 42

View File

@@ -1,293 +1,684 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_0.pyi:7:62: PYI019 Use `Self` instead of custom TypeVar `_S`
PYI019_0.pyi:7:16: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.pyi:10:54: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
4 4 | _S2 = TypeVar("_S2", BadClass, GoodClass)
5 5 |
6 6 | class BadClass:
7 |- def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
7 |+ def __new__(cls, *args: str, **kwargs: int) -> Self: ... # PYI019
8 8 |
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019_0.pyi:10:28: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.pyi:14:54: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
7 7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
8 8 |
9 9 |
10 |- def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
10 |+ def bad_instance_method(self, arg: bytes) -> Self: ... # PYI019
11 11 |
12 12 |
13 13 | @classmethod
PYI019_0.pyi:14:25: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.pyi:18:55: PYI019 Use `Self` instead of custom TypeVar `_S`
Safe fix
11 11 |
12 12 |
13 13 | @classmethod
14 |- def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
14 |+ def bad_class_method(cls, arg: int) -> Self: ... # PYI019
15 15 |
16 16 |
17 17 | @classmethod
PYI019_0.pyi:18:33: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
| ^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
PYI019_0.pyi:39:63: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
15 15 |
16 16 |
17 17 | @classmethod
18 |- def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
18 |+ def bad_posonly_class_method(cls, /) -> Self: ... # PYI019
19 19 |
20 20 |
21 21 | @classmethod
PYI019_0.pyi:39:14: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:42:46: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
36 36 |
37 37 | # Python > 3.12
38 38 | class PEP695BadDunderNew[T]:
39 |- def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
39 |+ def __new__(cls, *args: Any, ** kwargs: Any) -> Self: ... # PYI019
40 40 |
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019_0.pyi:42:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:54:32: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
39 39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
40 40 |
41 41 |
42 |- def generic_instance_method[S](self: S) -> S: ... # PYI019
42 |+ def generic_instance_method(self) -> Self: ... # PYI019
43 43 |
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019_0.pyi:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
52 | # in the settings for this test:
53 | @foo_classmethod
54 | def foo[S](cls: type[S]) -> S: ... # PYI019
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:61:48: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
51 51 | # due to `foo_classmethod being listed in `pep8_naming.classmethod-decorators`
52 52 | # in the settings for this test:
53 53 | @foo_classmethod
54 |- def foo[S](cls: type[S]) -> S: ... # PYI019
54 |+ def foo(cls) -> Self: ... # PYI019
55 55 |
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019_0.pyi:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:63:47: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
58 58 |
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019_0.pyi:63:26: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:65:43: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
60 60 | class PEP695Fix:
61 61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 62 |
63 |- def __init_subclass__[S](cls: type[S]) -> S: ...
63 |+ def __init_subclass__(cls) -> Self: ...
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019_0.pyi:65:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
66 |
67 | def __pos__[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:67:32: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
65 |- def __neg__[S: PEP695Fix](self: S) -> S: ...
65 |+ def __neg__(self) -> Self: ...
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019_0.pyi:67:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
67 | def __pos__[S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:69:53: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
67 |- def __pos__[S](self: S) -> S: ...
67 |+ def __pos__(self) -> Self: ...
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019_0.pyi:69:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:71:42: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
69 |- def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
69 |+ def __add__(self, other: Self) -> Self: ...
70 70 |
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019_0.pyi:71:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
72 |
73 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:74:59: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
71 |- def __sub__[S](self: S, other: S) -> S: ...
71 |+ def __sub__(self, other: Self) -> Self: ...
72 72 |
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019_0.pyi:74:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
75 |
76 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:77:50: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
73 73 | @classmethod
74 |- def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
74 |+ def class_method_bound(cls) -> Self: ...
75 75 |
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019_0.pyi:77:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:79:57: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
75 75 |
76 76 | @classmethod
77 |- def class_method_unbound[S](cls: type[S]) -> S: ...
77 |+ def class_method_unbound(cls) -> Self: ...
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019_0.pyi:79:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:81:48: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 78 |
79 |- def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
79 |+ def instance_method_bound(self) -> Self: ...
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019_0.pyi:81:32: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:83:90: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
81 |- def instance_method_unbound[S](self: S) -> S: ...
81 |+ def instance_method_unbound(self) -> Self: ...
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019_0.pyi:83:53: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:85:81: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
83 |- def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
83 |+ def instance_method_bound_with_another_parameter(self, other: Self) -> Self: ...
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019_0.pyi:85:55: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:87:94: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
85 |- def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
85 |+ def instance_method_unbound_with_another_parameter(self, other: Self) -> Self: ...
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019_0.pyi:87:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:89:75: PYI019 Use `Self` instead of custom TypeVar `_S695`
Safe fix
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
87 |- def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
87 |+ def multiple_type_vars[*Ts, T](self, other: Self, /, *args: *Ts, a: T, b: list[T]) -> Self: ...
88 88 |
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019_0.pyi:89:43: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
| ^^^^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S695` with `Self`
PYI019_0.pyi:114:31: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
89 |- def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
89 |+ def mixing_old_and_new_style_type_vars[T](self, a: T, b: T) -> Self: ...
90 90 |
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019_0.pyi:94:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
92 | class InvalidButWeDoNotPanic:
93 | @classmethod
94 | def m[S](cls: type[S], /) -> S[int]: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
95 | def n(self: S) -> S[int]: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
91 91 |
92 92 | class InvalidButWeDoNotPanic:
93 93 | @classmethod
94 |- def m[S](cls: type[S], /) -> S[int]: ...
94 |+ def m(cls, /) -> Self[int]: ...
95 95 | def n(self: S) -> S[int]: ...
96 96 |
97 97 |
PYI019_0.pyi:114:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
112 | class SubscriptReturnType:
113 | @classmethod
114 | def m[S](cls: type[S]) -> type[S]: ... # PYI019
| ^^^^^^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:118:29: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
111 111 |
112 112 | class SubscriptReturnType:
113 113 | @classmethod
114 |- def m[S](cls: type[S]) -> type[S]: ... # PYI019
114 |+ def m(cls) -> type[Self]: ... # PYI019
115 115 |
116 116 |
117 117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
PYI019_0.pyi:118:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 | def f[T, S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:122:100: PYI019 Use `Self` instead of custom TypeVar `_S695`
Safe fix
115 115 |
116 116 |
117 117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 |- def f[T, S](self: S) -> S: ...
118 |+ def f[T](self) -> Self: ...
119 119 |
120 120 |
121 121 | class PEP695Again:
PYI019_0.pyi:122:26: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
121 | class PEP695Again:
122 | def mixing_and_nested[T](self: _S695, a: list[_S695], b: dict[_S695, str | T | set[_S695]]) -> _S695: ...
| ^^^^^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
|
= help: Replace TypeVar `_S695` with `Self`
PYI019_0.pyi:132:10: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
119 119 |
120 120 |
121 121 | class PEP695Again:
122 |- def mixing_and_nested[T](self: _S695, a: list[_S695], b: dict[_S695, str | T | set[_S695]]) -> _S695: ...
122 |+ def mixing_and_nested[T](self, a: list[Self], b: dict[Self, str | T | set[Self]]) -> Self: ...
123 123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
124 124 |
125 125 | @classmethod
PYI019_0.pyi:126:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
130 | a: T,
131 | b: tuple[S, T]
132 | ) -> S: ...
| ^ PYI019
125 | @classmethod
126 | def comment_in_fix_range[T, S](
| _____________________________^
127 | | cls: type[ # Lorem ipsum
128 | | S
129 | | ],
130 | | a: T,
131 | | b: tuple[S, T]
132 | | ) -> S: ...
| |__________^ PYI019
133 |
134 | def comment_outside_fix_range[T, S](
134 | def comment_outside_fix_range[T, S](
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:141:10: PYI019 Use `Self` instead of custom TypeVar `S`
Unsafe fix
123 123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
124 124 |
125 125 | @classmethod
126 |- def comment_in_fix_range[T, S](
127 |- cls: type[ # Lorem ipsum
128 |- S
129 |- ],
126 |+ def comment_in_fix_range[T](
127 |+ cls,
130 128 | a: T,
131 |- b: tuple[S, T]
132 |- ) -> S: ...
129 |+ b: tuple[Self, T]
130 |+ ) -> Self: ...
133 131 |
134 132 | def comment_outside_fix_range[T, S](
135 133 | self: S,
PYI019_0.pyi:134:34: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | S, T
140 | ]
141 | ) -> S: ...
| ^ PYI019
132 | ) -> S: ...
133 |
134 | def comment_outside_fix_range[T, S](
| __________________________________^
135 | | self: S,
136 | | a: T,
137 | | b: tuple[
138 | | # Lorem ipsum
139 | | S, T
140 | | ]
141 | | ) -> S: ...
| |__________^ PYI019
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:156:34: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
|
154 | # but our preview-mode logic is smarter about this.
155 | class Foo:
156 | def x(self: _NotATypeVar) -> _NotATypeVar: ...
| ^^^^^^^^^^^^ PYI019
157 | @classmethod
158 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
Safe fix
131 131 | b: tuple[S, T]
132 132 | ) -> S: ...
133 133 |
134 |- def comment_outside_fix_range[T, S](
135 |- self: S,
134 |+ def comment_outside_fix_range[T](
135 |+ self,
136 136 | a: T,
137 137 | b: tuple[
138 138 | # Lorem ipsum
139 |- S, T
139 |+ Self, T
140 140 | ]
141 |- ) -> S: ...
141 |+ ) -> Self: ...
142 142 |
143 143 |
144 144 | class SelfNotUsedInReturnAnnotation:
PYI019_0.pyi:158:40: PYI019 Use `Self` instead of custom TypeVar `_NotATypeVar`
PYI019_0.pyi:145:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
144 | class SelfNotUsedInReturnAnnotation:
145 | def m[S](self: S, other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
146 | @classmethod
147 | def n[S](cls: type[S], other: S) -> int: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
142 142 |
143 143 |
144 144 | class SelfNotUsedInReturnAnnotation:
145 |- def m[S](self: S, other: S) -> int: ...
145 |+ def m(self, other: Self) -> int: ...
146 146 | @classmethod
147 147 | def n[S](cls: type[S], other: S) -> int: ...
148 148 |
PYI019_0.pyi:147:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
145 | def m[S](self: S, other: S) -> int: ...
146 | @classmethod
147 | def n[S](cls: type[S], other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
144 144 | class SelfNotUsedInReturnAnnotation:
145 145 | def m[S](self: S, other: S) -> int: ...
146 146 | @classmethod
147 |- def n[S](cls: type[S], other: S) -> int: ...
147 |+ def n(cls, other: Self) -> int: ...
148 148 |
149 149 |
150 150 | class _NotATypeVar: ...
PYI019_0.pyi:161:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
156 | def x(self: _NotATypeVar) -> _NotATypeVar: ...
157 | @classmethod
158 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
| ^^^^^^^^^^^^ PYI019
159 |
160 | class NoReturnAnnotations:
161 | def m[S](self: S, other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
162 | @classmethod
163 | def n[S](cls: type[S], other: S): ...
|
= help: Replace TypeVar `_NotATypeVar` with `Self`
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:166:49: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
158 158 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
159 159 |
160 160 | class NoReturnAnnotations:
161 |- def m[S](self: S, other: S): ...
161 |+ def m(self, other: Self): ...
162 162 | @classmethod
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
PYI019_0.pyi:163:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
161 | def m[S](self: S, other: S): ...
162 | @classmethod
163 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
164 |
165 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
160 160 | class NoReturnAnnotations:
161 161 | def m[S](self: S, other: S): ...
162 162 | @classmethod
163 |- def n[S](cls: type[S], other: S): ...
163 |+ def n(cls, other: Self): ...
164 164 |
165 165 | class MultipleBoundParameters:
166 166 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.pyi:166:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
PYI019_0.pyi:167:63: PYI019 Use `Self` instead of custom TypeVar `S`
Safe fix
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
165 165 | class MultipleBoundParameters:
166 |- def m[S: int, T: int](self: S, other: T) -> S: ...
166 |+ def m[T: int](self, other: T) -> Self: ...
167 167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
168 168 |
169 169 |
PYI019_0.pyi:167:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
164 164 |
165 165 | class MultipleBoundParameters:
166 166 | def m[S: int, T: int](self: S, other: T) -> S: ...
167 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
167 |+ def n[T: (int, str)](self, other: T) -> Self: ...
168 168 |
169 169 |
170 170 | MetaType = TypeVar("MetaType")

View File

@@ -1,10 +1,17 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_1.pyi:4:26: PYI019 Use `Self` instead of custom TypeVar `S`
PYI019_1.pyi:4:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
3 | class F:
4 | def m[S](self: S) -> S: ...
| ^ PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
1 1 | import typing
2 2 |
3 3 | class F:
4 |- def m[S](self: S) -> S: ...
4 |+ def m(self) -> typing.Self: ...

View File

@@ -1,692 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_0.py:7:16: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
4 4 | _S2 = TypeVar("_S2", BadClass, GoodClass)
5 5 |
6 6 | class BadClass:
7 |- def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
7 |+ def __new__(cls, *args: str, **kwargs: int) -> Self: ... # PYI019
8 8 |
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019_0.py:10:28: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
7 7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
8 8 |
9 9 |
10 |- def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
10 |+ def bad_instance_method(self, arg: bytes) -> Self: ... # PYI019
11 11 |
12 12 |
13 13 | @classmethod
PYI019_0.py:14:25: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
11 11 |
12 12 |
13 13 | @classmethod
14 |- def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
14 |+ def bad_class_method(cls, arg: int) -> Self: ... # PYI019
15 15 |
16 16 |
17 17 | @classmethod
PYI019_0.py:18:33: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
15 15 |
16 16 |
17 17 | @classmethod
18 |- def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
18 |+ def bad_posonly_class_method(cls, /) -> Self: ... # PYI019
19 19 |
20 20 |
21 21 | @classmethod
PYI019_0.py:39:14: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
36 36 |
37 37 | # Python > 3.12
38 38 | class PEP695BadDunderNew[T]:
39 |- def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
39 |+ def __new__(cls, *args: Any, ** kwargs: Any) -> Self: ... # PYI019
40 40 |
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019_0.py:42:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
39 39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
40 40 |
41 41 |
42 |- def generic_instance_method[S](self: S) -> S: ... # PYI019
42 |+ def generic_instance_method(self) -> Self: ... # PYI019
43 43 |
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019_0.py:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
52 | # in the settings for this test:
53 | @foo_classmethod
54 | def foo[S](cls: type[S]) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
51 51 | # due to `foo_classmethod being listed in `pep8_naming.classmethod-decorators`
52 52 | # in the settings for this test:
53 53 | @foo_classmethod
54 |- def foo[S](cls: type[S]) -> S: ... # PYI019
54 |+ def foo(cls) -> Self: ... # PYI019
55 55 |
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019_0.py:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
58 58 |
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019_0.py:63:26: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
60 60 | class PEP695Fix:
61 61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 62 |
63 |- def __init_subclass__[S](cls: type[S]) -> S: ...
63 |+ def __init_subclass__(cls) -> Self: ...
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019_0.py:65:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
66 |
67 | def __pos__[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
65 |- def __neg__[S: PEP695Fix](self: S) -> S: ...
65 |+ def __neg__(self) -> Self: ...
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019_0.py:67:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
67 | def __pos__[S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^ PYI019
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
67 |- def __pos__[S](self: S) -> S: ...
67 |+ def __pos__(self) -> Self: ...
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019_0.py:69:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
69 |- def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
69 |+ def __add__(self, other: Self) -> Self: ...
70 70 |
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019_0.py:71:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
72 |
73 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
Safe fix
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
71 |- def __sub__[S](self: S, other: S) -> S: ...
71 |+ def __sub__(self, other: Self) -> Self: ...
72 72 |
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019_0.py:74:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
75 |
76 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
Safe fix
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
73 73 | @classmethod
74 |- def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
74 |+ def class_method_bound(cls) -> Self: ...
75 75 |
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019_0.py:77:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
75 75 |
76 76 | @classmethod
77 |- def class_method_unbound[S](cls: type[S]) -> S: ...
77 |+ def class_method_unbound(cls) -> Self: ...
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019_0.py:79:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 78 |
79 |- def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
79 |+ def instance_method_bound(self) -> Self: ...
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019_0.py:81:32: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^ PYI019
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
81 |- def instance_method_unbound[S](self: S) -> S: ...
81 |+ def instance_method_unbound(self) -> Self: ...
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019_0.py:83:53: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
83 |- def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
83 |+ def instance_method_bound_with_another_parameter(self, other: Self) -> Self: ...
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019_0.py:85:55: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
85 |- def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
85 |+ def instance_method_unbound_with_another_parameter(self, other: Self) -> Self: ...
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019_0.py:87:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
87 |- def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
87 |+ def multiple_type_vars[*Ts, T](self, other: Self, /, *args: *Ts, a: T, b: list[T]) -> Self: ...
88 88 |
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019_0.py:89:43: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S695` with `Self`
Safe fix
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
89 |- def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
89 |+ def mixing_old_and_new_style_type_vars[T](self, a: T, b: T) -> Self: ...
90 90 |
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019_0.py:94:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
92 | class InvalidButWeDoNotPanic:
93 | @classmethod
94 | def m[S](cls: type[S], /) -> S[int]: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
95 | def n(self: S) -> S[int]: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
91 91 |
92 92 | class InvalidButWeDoNotPanic:
93 93 | @classmethod
94 |- def m[S](cls: type[S], /) -> S[int]: ...
94 |+ def m(cls, /) -> Self[int]: ...
95 95 | def n(self: S) -> S[int]: ...
96 96 |
97 97 |
PYI019_0.py:114:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
112 | class SubscriptReturnType:
113 | @classmethod
114 | def m[S](cls: type[S]) -> type[S]: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
111 111 |
112 112 | class SubscriptReturnType:
113 113 | @classmethod
114 |- def m[S](cls: type[S]) -> type[S]: ... # PYI019
114 |+ def m(cls) -> type[Self]: ... # PYI019
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
PYI019_0.py:118:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
117 | class SelfNotUsedInReturnAnnotation:
118 | def m[S](self: S, other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
119 | @classmethod
120 | def n[S](cls: type[S], other: S) -> int: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
115 115 |
116 116 |
117 117 | class SelfNotUsedInReturnAnnotation:
118 |- def m[S](self: S, other: S) -> int: ...
118 |+ def m(self, other: Self) -> int: ...
119 119 | @classmethod
120 120 | def n[S](cls: type[S], other: S) -> int: ...
121 121 |
PYI019_0.py:120:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
118 | def m[S](self: S, other: S) -> int: ...
119 | @classmethod
120 | def n[S](cls: type[S], other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
117 117 | class SelfNotUsedInReturnAnnotation:
118 118 | def m[S](self: S, other: S) -> int: ...
119 119 | @classmethod
120 |- def n[S](cls: type[S], other: S) -> int: ...
120 |+ def n(cls, other: Self) -> int: ...
121 121 |
122 122 |
123 123 | class _NotATypeVar: ...
PYI019_0.py:135:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
134 | class NoReturnAnnotations:
135 | def m[S](self: S, other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
136 | @classmethod
137 | def n[S](cls: type[S], other: S): ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
132 132 |
133 133 |
134 134 | class NoReturnAnnotations:
135 |- def m[S](self: S, other: S): ...
135 |+ def m(self, other: Self): ...
136 136 | @classmethod
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
PYI019_0.py:137:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
135 | def m[S](self: S, other: S): ...
136 | @classmethod
137 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
138 |
139 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
134 134 | class NoReturnAnnotations:
135 135 | def m[S](self: S, other: S): ...
136 136 | @classmethod
137 |- def n[S](cls: type[S], other: S): ...
137 |+ def n(cls, other: Self): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.py:140:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
137 137 | def n[S](cls: type[S], other: S): ...
138 138 |
139 139 | class MultipleBoundParameters:
140 |- def m[S: int, T: int](self: S, other: T) -> S: ...
140 |+ def m[T: int](self, other: T) -> Self: ...
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
PYI019_0.py:141:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
139 | class MultipleBoundParameters:
140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
142 |
143 | class MethodsWithBody:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
138 138 |
139 139 | class MultipleBoundParameters:
140 140 | def m[S: int, T: int](self: S, other: T) -> S: ...
141 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
141 |+ def n[T: (int, str)](self, other: T) -> Self: ...
142 142 |
143 143 | class MethodsWithBody:
144 144 | def m[S](self: S, other: S) -> S:
PYI019_0.py:144:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
143 | class MethodsWithBody:
144 | def m[S](self: S, other: S) -> S:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
145 | x: S = other
146 | return x
|
= help: Replace TypeVar `S` with `Self`
Safe fix
141 141 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
142 142 |
143 143 | class MethodsWithBody:
144 |- def m[S](self: S, other: S) -> S:
145 |- x: S = other
144 |+ def m(self, other: Self) -> Self:
145 |+ x: Self = other
146 146 | return x
147 147 |
148 148 | @classmethod
PYI019_0.py:149:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
148 | @classmethod
149 | def n[S](cls: type[S], other: S) -> S:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
150 | x: type[S] = type(other)
151 | return x()
|
= help: Replace TypeVar `S` with `Self`
Safe fix
146 146 | return x
147 147 |
148 148 | @classmethod
149 |- def n[S](cls: type[S], other: S) -> S:
150 |- x: type[S] = type(other)
149 |+ def n(cls, other: Self) -> Self:
150 |+ x: type[Self] = type(other)
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
PYI019_0.py:154:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
153 | class StringizedReferencesCanBeFixed:
154 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
155 | x = cast("list[tuple[S, S]]", self)
156 | return x
|
= help: Replace TypeVar `S` with `Self`
Safe fix
151 151 | return x()
152 152 |
153 153 | class StringizedReferencesCanBeFixed:
154 |- def m[S](self: S) -> S:
155 |- x = cast("list[tuple[S, S]]", self)
154 |+ def m(self) -> Self:
155 |+ x = cast("list[tuple[Self, Self]]", self)
156 156 | return x
157 157 |
158 158 | class ButStrangeStringizedReferencesCannotBeFixed:
PYI019_0.py:159:10: PYI019 Use `Self` instead of custom TypeVar `_T`
|
158 | class ButStrangeStringizedReferencesCannotBeFixed:
159 | def m[_T](self: _T) -> _T:
| ^^^^^^^^^^^^^^^^^^^^ PYI019
160 | x = cast('list[_\x54]', self)
161 | return x
|
= help: Replace TypeVar `_T` with `Self`
PYI019_0.py:164:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
163 | class DeletionsAreNotTouched:
164 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 | # so `del S` here is not actually a reference to the type variable `S`.
|
= help: Replace TypeVar `S` with `Self`
Safe fix
161 161 | return x
162 162 |
163 163 | class DeletionsAreNotTouched:
164 |- def m[S](self: S) -> S:
164 |+ def m(self) -> Self:
165 165 | # `S` is not a local variable here, and `del` can only be used with local variables,
166 166 | # so `del S` here is not actually a reference to the type variable `S`.
167 167 | # This `del` statement is therefore not touched by the autofix (it raises `UnboundLocalError`
PYI019_0.py:173:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
172 | class NamesShadowingTypeVarAreNotTouched:
173 | def m[S](self: S) -> S:
| ^^^^^^^^^^^^^^^^^ PYI019
174 | type S = int
175 | print(S) # not a reference to the type variable, so not touched by the autofix
|
= help: Replace TypeVar `S` with `Self`
Safe fix
170 170 | return self
171 171 |
172 172 | class NamesShadowingTypeVarAreNotTouched:
173 |- def m[S](self: S) -> S:
173 |+ def m(self) -> Self:
174 174 | type S = int
175 175 | print(S) # not a reference to the type variable, so not touched by the autofix
176 176 | return 42

View File

@@ -1,684 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_0.pyi:7:16: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
6 | class BadClass:
7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
4 4 | _S2 = TypeVar("_S2", BadClass, GoodClass)
5 5 |
6 6 | class BadClass:
7 |- def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
7 |+ def __new__(cls, *args: str, **kwargs: int) -> Self: ... # PYI019
8 8 |
9 9 |
10 10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
PYI019_0.pyi:10:28: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
10 | def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
7 7 | def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S: ... # PYI019
8 8 |
9 9 |
10 |- def bad_instance_method(self: _S, arg: bytes) -> _S: ... # PYI019
10 |+ def bad_instance_method(self, arg: bytes) -> Self: ... # PYI019
11 11 |
12 12 |
13 13 | @classmethod
PYI019_0.pyi:14:25: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
13 | @classmethod
14 | def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
11 11 |
12 12 |
13 13 | @classmethod
14 |- def bad_class_method(cls: type[_S], arg: int) -> _S: ... # PYI019
14 |+ def bad_class_method(cls, arg: int) -> Self: ... # PYI019
15 15 |
16 16 |
17 17 | @classmethod
PYI019_0.pyi:18:33: PYI019 [*] Use `Self` instead of custom TypeVar `_S`
|
17 | @classmethod
18 | def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S` with `Self`
Safe fix
15 15 |
16 16 |
17 17 | @classmethod
18 |- def bad_posonly_class_method(cls: type[_S], /) -> _S: ... # PYI019
18 |+ def bad_posonly_class_method(cls, /) -> Self: ... # PYI019
19 19 |
20 20 |
21 21 | @classmethod
PYI019_0.pyi:39:14: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
37 | # Python > 3.12
38 | class PEP695BadDunderNew[T]:
39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
36 36 |
37 37 | # Python > 3.12
38 38 | class PEP695BadDunderNew[T]:
39 |- def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
39 |+ def __new__(cls, *args: Any, ** kwargs: Any) -> Self: ... # PYI019
40 40 |
41 41 |
42 42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
PYI019_0.pyi:42:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
42 | def generic_instance_method[S](self: S) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
39 39 | def __new__[S](cls: type[S], *args: Any, ** kwargs: Any) -> S: ... # PYI019
40 40 |
41 41 |
42 |- def generic_instance_method[S](self: S) -> S: ... # PYI019
42 |+ def generic_instance_method(self) -> Self: ... # PYI019
43 43 |
44 44 |
45 45 | class PEP695GoodDunderNew[T]:
PYI019_0.pyi:54:11: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
52 | # in the settings for this test:
53 | @foo_classmethod
54 | def foo[S](cls: type[S]) -> S: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
51 51 | # due to `foo_classmethod being listed in `pep8_naming.classmethod-decorators`
52 52 | # in the settings for this test:
53 53 | @foo_classmethod
54 |- def foo[S](cls: type[S]) -> S: ... # PYI019
54 |+ def foo(cls) -> Self: ... # PYI019
55 55 |
56 56 |
57 57 | _S695 = TypeVar("_S695", bound="PEP695Fix")
PYI019_0.pyi:61:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
60 | class PEP695Fix:
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
58 58 |
59 59 |
60 60 | class PEP695Fix:
61 |- def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
61 |+ def __new__(cls) -> Self: ...
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
PYI019_0.pyi:63:26: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 |
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
60 60 | class PEP695Fix:
61 61 | def __new__[S: PEP695Fix](cls: type[S]) -> S: ...
62 62 |
63 |- def __init_subclass__[S](cls: type[S]) -> S: ...
63 |+ def __init_subclass__(cls) -> Self: ...
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
PYI019_0.pyi:65:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 |
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
66 |
67 | def __pos__[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
62 62 |
63 63 | def __init_subclass__[S](cls: type[S]) -> S: ...
64 64 |
65 |- def __neg__[S: PEP695Fix](self: S) -> S: ...
65 |+ def __neg__(self) -> Self: ...
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
PYI019_0.pyi:67:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 |
67 | def __pos__[S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^ PYI019
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
64 64 |
65 65 | def __neg__[S: PEP695Fix](self: S) -> S: ...
66 66 |
67 |- def __pos__[S](self: S) -> S: ...
67 |+ def __pos__(self) -> Self: ...
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
PYI019_0.pyi:69:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
67 | def __pos__[S](self: S) -> S: ...
68 |
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
66 66 |
67 67 | def __pos__[S](self: S) -> S: ...
68 68 |
69 |- def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
69 |+ def __add__(self, other: Self) -> Self: ...
70 70 |
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
PYI019_0.pyi:71:16: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 |
71 | def __sub__[S](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
72 |
73 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
Safe fix
68 68 |
69 69 | def __add__[S: PEP695Fix](self: S, other: S) -> S: ...
70 70 |
71 |- def __sub__[S](self: S, other: S) -> S: ...
71 |+ def __sub__(self, other: Self) -> Self: ...
72 72 |
73 73 | @classmethod
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
PYI019_0.pyi:74:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
73 | @classmethod
74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
75 |
76 | @classmethod
|
= help: Replace TypeVar `S` with `Self`
Safe fix
71 71 | def __sub__[S](self: S, other: S) -> S: ...
72 72 |
73 73 | @classmethod
74 |- def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
74 |+ def class_method_bound(cls) -> Self: ...
75 75 |
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
PYI019_0.pyi:77:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
76 | @classmethod
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
74 74 | def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...
75 75 |
76 76 | @classmethod
77 |- def class_method_unbound[S](cls: type[S]) -> S: ...
77 |+ def class_method_unbound(cls) -> Self: ...
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
PYI019_0.pyi:79:30: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 |
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
76 76 | @classmethod
77 77 | def class_method_unbound[S](cls: type[S]) -> S: ...
78 78 |
79 |- def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
79 |+ def instance_method_bound(self) -> Self: ...
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
PYI019_0.pyi:81:32: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 |
81 | def instance_method_unbound[S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^ PYI019
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
78 78 |
79 79 | def instance_method_bound[S: PEP695Fix](self: S) -> S: ...
80 80 |
81 |- def instance_method_unbound[S](self: S) -> S: ...
81 |+ def instance_method_unbound(self) -> Self: ...
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
PYI019_0.pyi:83:53: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
81 | def instance_method_unbound[S](self: S) -> S: ...
82 |
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
80 80 |
81 81 | def instance_method_unbound[S](self: S) -> S: ...
82 82 |
83 |- def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
83 |+ def instance_method_bound_with_another_parameter(self, other: Self) -> Self: ...
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
PYI019_0.pyi:85:55: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 |
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
82 82 |
83 83 | def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...
84 84 |
85 |- def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
85 |+ def instance_method_unbound_with_another_parameter(self, other: Self) -> Self: ...
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
PYI019_0.pyi:87:27: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 |
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
84 84 |
85 85 | def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...
86 86 |
87 |- def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
87 |+ def multiple_type_vars[*Ts, T](self, other: Self, /, *args: *Ts, a: T, b: list[T]) -> Self: ...
88 88 |
89 89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
90 90 |
PYI019_0.pyi:89:43: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 |
89 | def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `_S695` with `Self`
Safe fix
86 86 |
87 87 | def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...
88 88 |
89 |- def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
89 |+ def mixing_old_and_new_style_type_vars[T](self, a: T, b: T) -> Self: ...
90 90 |
91 91 |
92 92 | class InvalidButWeDoNotPanic:
PYI019_0.pyi:94:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
92 | class InvalidButWeDoNotPanic:
93 | @classmethod
94 | def m[S](cls: type[S], /) -> S[int]: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
95 | def n(self: S) -> S[int]: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
91 91 |
92 92 | class InvalidButWeDoNotPanic:
93 93 | @classmethod
94 |- def m[S](cls: type[S], /) -> S[int]: ...
94 |+ def m(cls, /) -> Self[int]: ...
95 95 | def n(self: S) -> S[int]: ...
96 96 |
97 97 |
PYI019_0.pyi:114:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
112 | class SubscriptReturnType:
113 | @classmethod
114 | def m[S](cls: type[S]) -> type[S]: ... # PYI019
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
111 111 |
112 112 | class SubscriptReturnType:
113 113 | @classmethod
114 |- def m[S](cls: type[S]) -> type[S]: ... # PYI019
114 |+ def m(cls) -> type[Self]: ... # PYI019
115 115 |
116 116 |
117 117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
PYI019_0.pyi:118:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 | def f[T, S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
115 115 |
116 116 |
117 117 | class PEP695TypeParameterAtTheVeryEndOfTheList:
118 |- def f[T, S](self: S) -> S: ...
118 |+ def f[T](self) -> Self: ...
119 119 |
120 120 |
121 121 | class PEP695Again:
PYI019_0.pyi:122:26: PYI019 [*] Use `Self` instead of custom TypeVar `_S695`
|
121 | class PEP695Again:
122 | def mixing_and_nested[T](self: _S695, a: list[_S695], b: dict[_S695, str | T | set[_S695]]) -> _S695: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
|
= help: Replace TypeVar `_S695` with `Self`
Safe fix
119 119 |
120 120 |
121 121 | class PEP695Again:
122 |- def mixing_and_nested[T](self: _S695, a: list[_S695], b: dict[_S695, str | T | set[_S695]]) -> _S695: ...
122 |+ def mixing_and_nested[T](self, a: list[Self], b: dict[Self, str | T | set[Self]]) -> Self: ...
123 123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
124 124 |
125 125 | @classmethod
PYI019_0.pyi:126:29: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
125 | @classmethod
126 | def comment_in_fix_range[T, S](
| _____________________________^
127 | | cls: type[ # Lorem ipsum
128 | | S
129 | | ],
130 | | a: T,
131 | | b: tuple[S, T]
132 | | ) -> S: ...
| |__________^ PYI019
133 |
134 | def comment_outside_fix_range[T, S](
|
= help: Replace TypeVar `S` with `Self`
Unsafe fix
123 123 | def also_uses_s695_but_should_not_be_edited(self, v: set[tuple[_S695]]) -> _S695: ...
124 124 |
125 125 | @classmethod
126 |- def comment_in_fix_range[T, S](
127 |- cls: type[ # Lorem ipsum
128 |- S
129 |- ],
126 |+ def comment_in_fix_range[T](
127 |+ cls,
130 128 | a: T,
131 |- b: tuple[S, T]
132 |- ) -> S: ...
129 |+ b: tuple[Self, T]
130 |+ ) -> Self: ...
133 131 |
134 132 | def comment_outside_fix_range[T, S](
135 133 | self: S,
PYI019_0.pyi:134:34: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
132 | ) -> S: ...
133 |
134 | def comment_outside_fix_range[T, S](
| __________________________________^
135 | | self: S,
136 | | a: T,
137 | | b: tuple[
138 | | # Lorem ipsum
139 | | S, T
140 | | ]
141 | | ) -> S: ...
| |__________^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
131 131 | b: tuple[S, T]
132 132 | ) -> S: ...
133 133 |
134 |- def comment_outside_fix_range[T, S](
135 |- self: S,
134 |+ def comment_outside_fix_range[T](
135 |+ self,
136 136 | a: T,
137 137 | b: tuple[
138 138 | # Lorem ipsum
139 |- S, T
139 |+ Self, T
140 140 | ]
141 |- ) -> S: ...
141 |+ ) -> Self: ...
142 142 |
143 143 |
144 144 | class SelfNotUsedInReturnAnnotation:
PYI019_0.pyi:145:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
144 | class SelfNotUsedInReturnAnnotation:
145 | def m[S](self: S, other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
146 | @classmethod
147 | def n[S](cls: type[S], other: S) -> int: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
142 142 |
143 143 |
144 144 | class SelfNotUsedInReturnAnnotation:
145 |- def m[S](self: S, other: S) -> int: ...
145 |+ def m(self, other: Self) -> int: ...
146 146 | @classmethod
147 147 | def n[S](cls: type[S], other: S) -> int: ...
148 148 |
PYI019_0.pyi:147:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
145 | def m[S](self: S, other: S) -> int: ...
146 | @classmethod
147 | def n[S](cls: type[S], other: S) -> int: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
144 144 | class SelfNotUsedInReturnAnnotation:
145 145 | def m[S](self: S, other: S) -> int: ...
146 146 | @classmethod
147 |- def n[S](cls: type[S], other: S) -> int: ...
147 |+ def n(cls, other: Self) -> int: ...
148 148 |
149 149 |
150 150 | class _NotATypeVar: ...
PYI019_0.pyi:161:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
160 | class NoReturnAnnotations:
161 | def m[S](self: S, other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^ PYI019
162 | @classmethod
163 | def n[S](cls: type[S], other: S): ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
158 158 | def y(self: type[_NotATypeVar]) -> _NotATypeVar: ...
159 159 |
160 160 | class NoReturnAnnotations:
161 |- def m[S](self: S, other: S): ...
161 |+ def m(self, other: Self): ...
162 162 | @classmethod
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
PYI019_0.pyi:163:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
161 | def m[S](self: S, other: S): ...
162 | @classmethod
163 | def n[S](cls: type[S], other: S): ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
164 |
165 | class MultipleBoundParameters:
|
= help: Replace TypeVar `S` with `Self`
Safe fix
160 160 | class NoReturnAnnotations:
161 161 | def m[S](self: S, other: S): ...
162 162 | @classmethod
163 |- def n[S](cls: type[S], other: S): ...
163 |+ def n(cls, other: Self): ...
164 164 |
165 165 | class MultipleBoundParameters:
166 166 | def m[S: int, T: int](self: S, other: T) -> S: ...
PYI019_0.pyi:166:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
|
= help: Replace TypeVar `S` with `Self`
Safe fix
163 163 | def n[S](cls: type[S], other: S): ...
164 164 |
165 165 | class MultipleBoundParameters:
166 |- def m[S: int, T: int](self: S, other: T) -> S: ...
166 |+ def m[T: int](self, other: T) -> Self: ...
167 167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
168 168 |
169 169 |
PYI019_0.pyi:167:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
165 | class MultipleBoundParameters:
166 | def m[S: int, T: int](self: S, other: T) -> S: ...
167 | def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
164 164 |
165 165 | class MultipleBoundParameters:
166 166 | def m[S: int, T: int](self: S, other: T) -> S: ...
167 |- def n[T: (int, str), S: (int, str)](self: S, other: T) -> S: ...
167 |+ def n[T: (int, str)](self, other: T) -> Self: ...
168 168 |
169 169 |
170 170 | MetaType = TypeVar("MetaType")

View File

@@ -1,17 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI019_1.pyi:4:10: PYI019 [*] Use `Self` instead of custom TypeVar `S`
|
3 | class F:
4 | def m[S](self: S) -> S: ...
| ^^^^^^^^^^^^^^^^^ PYI019
|
= help: Replace TypeVar `S` with `Self`
Safe fix
1 1 | import typing
2 2 |
3 3 | class F:
4 |- def m[S](self: S) -> S: ...
4 |+ def m(self) -> typing.Self: ...

View File

@@ -1,100 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI018.py:6:1: PYI018 [*] Private TypeVar `_T` is never used
|
4 | from typing_extensions import ParamSpec, TypeVarTuple
5 |
6 | _T = typing.TypeVar("_T")
| ^^ PYI018
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
|
= help: Remove unused private TypeVar `_T`
Unsafe fix
3 3 | from typing import TypeVar
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 |-_T = typing.TypeVar("_T")
7 6 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
PYI018.py:7:1: PYI018 [*] Private TypeVarTuple `_Ts` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
| ^^^ PYI018
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
|
= help: Remove unused private TypeVarTuple `_Ts`
Unsafe fix
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 |-_Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
PYI018.py:8:1: PYI018 [*] Private ParamSpec `_P` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
| ^^ PYI018
9 | _P2 = typing.ParamSpec("_P2")
10 | _Ts2 = TypeVarTuple("_Ts2")
|
= help: Remove unused private ParamSpec `_P`
Unsafe fix
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 |-_P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
PYI018.py:9:1: PYI018 [*] Private ParamSpec `_P2` is never used
|
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
| ^^^ PYI018
10 | _Ts2 = TypeVarTuple("_Ts2")
|
= help: Remove unused private ParamSpec `_P2`
Unsafe fix
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 |-_P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
PYI018.py:10:1: PYI018 [*] Private TypeVarTuple `_Ts2` is never used
|
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
10 | _Ts2 = TypeVarTuple("_Ts2")
| ^^^^ PYI018
11 |
12 | # OK
|
= help: Remove unused private TypeVarTuple `_Ts2`
Unsafe fix
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 9 | _P2 = typing.ParamSpec("_P2")
10 |-_Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
13 12 | _UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -1,100 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI018.pyi:6:1: PYI018 [*] Private TypeVar `_T` is never used
|
4 | from typing_extensions import ParamSpec, TypeVarTuple
5 |
6 | _T = typing.TypeVar("_T")
| ^^ PYI018
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
|
= help: Remove unused private TypeVar `_T`
Unsafe fix
3 3 | from typing import TypeVar
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 |-_T = typing.TypeVar("_T")
7 6 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
PYI018.pyi:7:1: PYI018 [*] Private TypeVarTuple `_Ts` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
| ^^^ PYI018
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
|
= help: Remove unused private TypeVarTuple `_Ts`
Unsafe fix
4 4 | from typing_extensions import ParamSpec, TypeVarTuple
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 |-_Ts = typing_extensions.TypeVarTuple("_Ts")
8 7 | _P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
PYI018.pyi:8:1: PYI018 [*] Private ParamSpec `_P` is never used
|
6 | _T = typing.TypeVar("_T")
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
| ^^ PYI018
9 | _P2 = typing.ParamSpec("_P2")
10 | _Ts2 = TypeVarTuple("_Ts2")
|
= help: Remove unused private ParamSpec `_P`
Unsafe fix
5 5 |
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 |-_P = ParamSpec("_P")
9 8 | _P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
PYI018.pyi:9:1: PYI018 [*] Private ParamSpec `_P2` is never used
|
7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
| ^^^ PYI018
10 | _Ts2 = TypeVarTuple("_Ts2")
|
= help: Remove unused private ParamSpec `_P2`
Unsafe fix
6 6 | _T = typing.TypeVar("_T")
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 |-_P2 = typing.ParamSpec("_P2")
10 9 | _Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
PYI018.pyi:10:1: PYI018 [*] Private TypeVarTuple `_Ts2` is never used
|
8 | _P = ParamSpec("_P")
9 | _P2 = typing.ParamSpec("_P2")
10 | _Ts2 = TypeVarTuple("_Ts2")
| ^^^^ PYI018
11 |
12 | # OK
|
= help: Remove unused private TypeVarTuple `_Ts2`
Unsafe fix
7 7 | _Ts = typing_extensions.TypeVarTuple("_Ts")
8 8 | _P = ParamSpec("_P")
9 9 | _P2 = typing.ParamSpec("_P2")
10 |-_Ts2 = TypeVarTuple("_Ts2")
11 10 |
12 11 | # OK
13 12 | _UsedTypeVar = TypeVar("_UsedTypeVar")

View File

@@ -11,7 +11,7 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::{IdentifierPattern, PreviewMode};
use crate::settings::types::IdentifierPattern;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -358,36 +358,6 @@ mod tests {
Ok(())
}
#[test_case(
Rule::PytestRaisesWithMultipleStatements,
Path::new("PT012.py"),
Settings::default(),
"PT012_preview"
)]
#[test_case(
Rule::PytestWarnsWithMultipleStatements,
Path::new("PT031.py"),
Settings::default(),
"PT031_preview"
)]
fn test_pytest_style_preview(
rule_code: Rule,
path: &Path,
plugin_settings: Settings,
name: &str,
) -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_pytest_style").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
flake8_pytest_style: plugin_settings,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(name, diagnostics);
Ok(())
}
/// This test ensure that PT006 and PT007 don't conflict when both of them suggest a fix that
/// edits `argvalues` for `pytest.mark.parametrize`.
#[test]

View File

@@ -13,6 +13,10 @@ use super::helpers::is_empty_or_null_string;
/// ## What it does
/// Checks for `pytest.raises` context managers with multiple statements.
///
/// This rule allows `pytest.raises` bodies to contain `for`
/// loops with empty bodies (e.g., `pass` or `...` statements), to test
/// iterator behavior.
///
/// ## Why is this bad?
/// When a `pytest.raises` is used as a context manager and contains multiple
/// statements, it can lead to the test passing when it actually should fail.
@@ -20,10 +24,6 @@ use super::helpers::is_empty_or_null_string;
/// A `pytest.raises` context manager should only contain a single simple
/// statement that raises the expected exception.
///
/// In [preview], this rule allows `pytest.raises` bodies to contain `for`
/// loops with empty bodies (e.g., `pass` or `...` statements), to test
/// iterator behavior.
///
/// ## Example
/// ```python
/// import pytest
@@ -50,8 +50,6 @@ use super::helpers::is_empty_or_null_string;
///
/// ## References
/// - [`pytest` documentation: `pytest.raises`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-raises)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
pub(crate) struct PytestRaisesWithMultipleStatements;
@@ -206,14 +204,12 @@ pub(crate) fn complex_raises(checker: &Checker, stmt: &Stmt, items: &[WithItem],
// Check body for `pytest.raises` context manager
if raises_called {
let is_too_complex = if let [stmt] = body {
let in_preview = checker.settings.preview.is_enabled();
match stmt {
Stmt::With(ast::StmtWith { body, .. }) => is_non_trivial_with_body(body),
// Allow function and class definitions to test decorators.
Stmt::ClassDef(_) | Stmt::FunctionDef(_) => false,
// Allow empty `for` loops to test iterators.
Stmt::For(ast::StmtFor { body, .. }) if in_preview => match &body[..] {
Stmt::For(ast::StmtFor { body, .. }) => match &body[..] {
[Stmt::Pass(_)] => false,
[Stmt::Expr(ast::StmtExpr { value, .. })] => !value.is_ellipsis_literal_expr(),
_ => true,

View File

@@ -13,6 +13,10 @@ use super::helpers::is_empty_or_null_string;
/// ## What it does
/// Checks for `pytest.warns` context managers with multiple statements.
///
/// This rule allows `pytest.warns` bodies to contain `for`
/// loops with empty bodies (e.g., `pass` or `...` statements), to test
/// iterator behavior.
///
/// ## Why is this bad?
/// When `pytest.warns` is used as a context manager and contains multiple
/// statements, it can lead to the test passing when it should instead fail.
@@ -20,9 +24,6 @@ use super::helpers::is_empty_or_null_string;
/// A `pytest.warns` context manager should only contain a single
/// simple statement that triggers the expected warning.
///
/// In [preview], this rule allows `pytest.warns` bodies to contain `for`
/// loops with empty bodies (e.g., `pass` or `...` statements), to test
/// iterator behavior.
///
/// ## Example
/// ```python
@@ -48,8 +49,6 @@ use super::helpers::is_empty_or_null_string;
///
/// ## References
/// - [`pytest` documentation: `pytest.warns`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-warns)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
pub(crate) struct PytestWarnsWithMultipleStatements;
@@ -206,14 +205,12 @@ pub(crate) fn complex_warns(checker: &Checker, stmt: &Stmt, items: &[WithItem],
// Check body for `pytest.warns` context manager
if warns_called {
let is_too_complex = if let [stmt] = body {
let in_preview = checker.settings.preview.is_enabled();
match stmt {
Stmt::With(ast::StmtWith { body, .. }) => is_non_trivial_with_body(body),
// Allow function and class definitions to test decorators.
Stmt::ClassDef(_) | Stmt::FunctionDef(_) => false,
// Allow empty `for` loops to test iterators.
Stmt::For(ast::StmtFor { body, .. }) if in_preview => match &body[..] {
Stmt::For(ast::StmtFor { body, .. }) => match &body[..] {
[Stmt::Pass(_)] => false,
[Stmt::Expr(ast::StmtExpr { value, .. })] => !value.is_ellipsis_literal_expr(),
_ => true,

View File

@@ -124,49 +124,3 @@ PT012.py:95:5: PT012 `pytest.raises()` block should contain a single simple stat
97 | | assert foo
| |______________________^ PT012
|
PT012.py:102:5: PT012 `pytest.raises()` block should contain a single simple statement
|
100 | ## No errors in preview
101 |
102 | / with pytest.raises(RuntimeError):
103 | | for a in b:
104 | | pass
| |________________^ PT012
105 |
106 | with pytest.raises(RuntimeError):
|
PT012.py:106:5: PT012 `pytest.raises()` block should contain a single simple statement
|
104 | pass
105 |
106 | / with pytest.raises(RuntimeError):
107 | | for a in b:
108 | | ...
| |_______________^ PT012
109 |
110 | with pytest.raises(RuntimeError):
|
PT012.py:110:5: PT012 `pytest.raises()` block should contain a single simple statement
|
108 | ...
109 |
110 | / with pytest.raises(RuntimeError):
111 | | async for a in b:
112 | | pass
| |________________^ PT012
113 |
114 | with pytest.raises(RuntimeError):
|
PT012.py:114:5: PT012 `pytest.raises()` block should contain a single simple statement
|
112 | pass
113 |
114 | / with pytest.raises(RuntimeError):
115 | | async for a in b:
116 | | ...
| |_______________^ PT012
|

View File

@@ -1,126 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
---
PT012.py:42:5: PT012 `pytest.raises()` block should contain a single simple statement
|
41 | def test_error_multiple_statements():
42 | / with pytest.raises(AttributeError):
43 | | len([])
44 | | [].size
| |_______________^ PT012
|
PT012.py:48:5: PT012 `pytest.raises()` block should contain a single simple statement
|
47 | async def test_error_complex_statement():
48 | / with pytest.raises(AttributeError):
49 | | if True:
50 | | [].size
| |___________________^ PT012
51 |
52 | with pytest.raises(AttributeError):
|
PT012.py:52:5: PT012 `pytest.raises()` block should contain a single simple statement
|
50 | [].size
51 |
52 | / with pytest.raises(AttributeError):
53 | | for i in []:
54 | | [].size
| |___________________^ PT012
55 |
56 | with pytest.raises(AttributeError):
|
PT012.py:56:5: PT012 `pytest.raises()` block should contain a single simple statement
|
54 | [].size
55 |
56 | / with pytest.raises(AttributeError):
57 | | async for i in []:
58 | | [].size
| |___________________^ PT012
59 |
60 | with pytest.raises(AttributeError):
|
PT012.py:60:5: PT012 `pytest.raises()` block should contain a single simple statement
|
58 | [].size
59 |
60 | / with pytest.raises(AttributeError):
61 | | while True:
62 | | [].size
| |___________________^ PT012
63 |
64 | with pytest.raises(AttributeError):
|
PT012.py:64:5: PT012 `pytest.raises()` block should contain a single simple statement
|
62 | [].size
63 |
64 | / with pytest.raises(AttributeError):
65 | | async with context_manager_under_test():
66 | | if True:
67 | | raise Exception
| |_______________________________^ PT012
|
PT012.py:71:5: PT012 `pytest.raises()` block should contain a single simple statement
|
70 | def test_error_try():
71 | / with pytest.raises(AttributeError):
72 | | try:
73 | | [].size
74 | | except:
75 | | raise
| |_________________^ PT012
|
PT012.py:83:5: PT012 `pytest.raises()` block should contain a single simple statement
|
81 | ## Errors
82 |
83 | / with pytest.raises(RuntimeError):
84 | | for a in b:
85 | | print()
| |___________________^ PT012
86 |
87 | with pytest.raises(RuntimeError):
|
PT012.py:87:5: PT012 `pytest.raises()` block should contain a single simple statement
|
85 | print()
86 |
87 | / with pytest.raises(RuntimeError):
88 | | for a in b:
89 | | assert foo
| |______________________^ PT012
90 |
91 | with pytest.raises(RuntimeError):
|
PT012.py:91:5: PT012 `pytest.raises()` block should contain a single simple statement
|
89 | assert foo
90 |
91 | / with pytest.raises(RuntimeError):
92 | | async for a in b:
93 | | print()
| |___________________^ PT012
94 |
95 | with pytest.raises(RuntimeError):
|
PT012.py:95:5: PT012 `pytest.raises()` block should contain a single simple statement
|
93 | print()
94 |
95 | / with pytest.raises(RuntimeError):
96 | | async for a in b:
97 | | assert foo
| |______________________^ PT012
|

View File

@@ -124,49 +124,3 @@ PT031.py:95:5: PT031 `pytest.warns()` block should contain a single simple state
97 | | assert foo
| |______________________^ PT031
|
PT031.py:102:5: PT031 `pytest.warns()` block should contain a single simple statement
|
100 | ## No errors in preview
101 |
102 | / with pytest.warns(RuntimeError):
103 | | for a in b:
104 | | pass
| |________________^ PT031
105 |
106 | with pytest.warns(RuntimeError):
|
PT031.py:106:5: PT031 `pytest.warns()` block should contain a single simple statement
|
104 | pass
105 |
106 | / with pytest.warns(RuntimeError):
107 | | for a in b:
108 | | ...
| |_______________^ PT031
109 |
110 | with pytest.warns(RuntimeError):
|
PT031.py:110:5: PT031 `pytest.warns()` block should contain a single simple statement
|
108 | ...
109 |
110 | / with pytest.warns(RuntimeError):
111 | | async for a in b:
112 | | pass
| |________________^ PT031
113 |
114 | with pytest.warns(RuntimeError):
|
PT031.py:114:5: PT031 `pytest.warns()` block should contain a single simple statement
|
112 | pass
113 |
114 | / with pytest.warns(RuntimeError):
115 | | async for a in b:
116 | | ...
| |_______________^ PT031
|

View File

@@ -1,126 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pytest_style/mod.rs
---
PT031.py:42:5: PT031 `pytest.warns()` block should contain a single simple statement
|
41 | def test_error_multiple_statements():
42 | / with pytest.warns(UserWarning):
43 | | foo()
44 | | bar()
| |_____________^ PT031
|
PT031.py:48:5: PT031 `pytest.warns()` block should contain a single simple statement
|
47 | async def test_error_complex_statement():
48 | / with pytest.warns(UserWarning):
49 | | if True:
50 | | foo()
| |_________________^ PT031
51 |
52 | with pytest.warns(UserWarning):
|
PT031.py:52:5: PT031 `pytest.warns()` block should contain a single simple statement
|
50 | foo()
51 |
52 | / with pytest.warns(UserWarning):
53 | | for i in []:
54 | | foo()
| |_________________^ PT031
55 |
56 | with pytest.warns(UserWarning):
|
PT031.py:56:5: PT031 `pytest.warns()` block should contain a single simple statement
|
54 | foo()
55 |
56 | / with pytest.warns(UserWarning):
57 | | async for i in []:
58 | | foo()
| |_________________^ PT031
59 |
60 | with pytest.warns(UserWarning):
|
PT031.py:60:5: PT031 `pytest.warns()` block should contain a single simple statement
|
58 | foo()
59 |
60 | / with pytest.warns(UserWarning):
61 | | while True:
62 | | foo()
| |_________________^ PT031
63 |
64 | with pytest.warns(UserWarning):
|
PT031.py:64:5: PT031 `pytest.warns()` block should contain a single simple statement
|
62 | foo()
63 |
64 | / with pytest.warns(UserWarning):
65 | | async with context_manager_under_test():
66 | | if True:
67 | | foo()
| |_____________________^ PT031
|
PT031.py:71:5: PT031 `pytest.warns()` block should contain a single simple statement
|
70 | def test_error_try():
71 | / with pytest.warns(UserWarning):
72 | | try:
73 | | foo()
74 | | except:
75 | | raise
| |_________________^ PT031
|
PT031.py:83:5: PT031 `pytest.warns()` block should contain a single simple statement
|
81 | ## Errors
82 |
83 | / with pytest.warns(RuntimeError):
84 | | for a in b:
85 | | print()
| |___________________^ PT031
86 |
87 | with pytest.warns(RuntimeError):
|
PT031.py:87:5: PT031 `pytest.warns()` block should contain a single simple statement
|
85 | print()
86 |
87 | / with pytest.warns(RuntimeError):
88 | | for a in b:
89 | | assert foo
| |______________________^ PT031
90 |
91 | with pytest.warns(RuntimeError):
|
PT031.py:91:5: PT031 `pytest.warns()` block should contain a single simple statement
|
89 | assert foo
90 |
91 | / with pytest.warns(RuntimeError):
92 | | async for a in b:
93 | | print()
| |___________________^ PT031
94 |
95 | with pytest.warns(RuntimeError):
|
PT031.py:95:5: PT031 `pytest.warns()` block should contain a single simple statement
|
93 | print()
94 |
95 | / with pytest.warns(RuntimeError):
96 | | async for a in b:
97 | | assert foo
| |______________________^ PT031
|

View File

@@ -58,7 +58,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::NeedlessBool, Path::new("SIM103.py"))]
#[test_case(Rule::IfElseBlockInsteadOfIfExp, Path::new("SIM108.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(

View File

@@ -14,7 +14,7 @@ use crate::fix::snippet::SourceCodeSnippet;
///
/// ## Why is this bad?
/// `if` statements that return `True` for a truthy condition and `False` for
/// a falsey condition can be replaced with boolean casts.
/// a falsy condition can be replaced with boolean casts.
///
/// ## Example
/// Given:
@@ -42,10 +42,6 @@ use crate::fix::snippet::SourceCodeSnippet;
/// return x > 0
/// ```
///
/// ## Preview
/// In preview, double negations such as `not a != b`, `not a not in b`, `not a is not b`
/// will be simplified to `a == b`, `a in b` and `a is b`, respectively.
///
/// ## References
/// - [Python documentation: Truth Value Testing](https://docs.python.org/3/library/stdtypes.html#truth-value-testing)
#[derive(ViolationMetadata)]
@@ -222,16 +218,15 @@ pub(crate) fn needless_bool(checker: &Checker, stmt: &Stmt) {
left,
comparators,
..
}) if checker.settings.preview.is_enabled()
&& matches!(
ops.as_ref(),
[ast::CmpOp::Eq
| ast::CmpOp::NotEq
| ast::CmpOp::In
| ast::CmpOp::NotIn
| ast::CmpOp::Is
| ast::CmpOp::IsNot]
) =>
}) if matches!(
ops.as_ref(),
[ast::CmpOp::Eq
| ast::CmpOp::NotEq
| ast::CmpOp::In
| ast::CmpOp::NotIn
| ast::CmpOp::Is
| ast::CmpOp::IsNot]
) =>
{
let ([op], [right]) = (ops.as_ref(), comparators.as_ref()) else {
unreachable!("Single comparison with multiple comparators");

View File

@@ -39,6 +39,8 @@ use crate::checkers::ast::Checker;
/// ).split(",")
/// ```
///
/// as this is converted to `["a", "b"]` without any of the comments.
///
/// ## References
/// - [Python documentation: `str.split`](https://docs.python.org/3/library/stdtypes.html#str.split)
#[derive(ViolationMetadata)]

View File

@@ -252,7 +252,7 @@ SIM103.py:123:5: SIM103 [*] Return the condition `not 10 < a` directly
127 125 |
128 126 | def f():
SIM103.py:129:5: SIM103 [*] Return the condition `not 10 in a` directly
SIM103.py:129:5: SIM103 [*] Return the condition `10 not in a` directly
|
128 | def f():
129 | / if 10 in a:
@@ -260,7 +260,7 @@ SIM103.py:129:5: SIM103 [*] Return the condition `not 10 in a` directly
131 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not 10 in a`
= help: Replace with `return 10 not in a`
Unsafe fix
126 126 |
@@ -269,12 +269,12 @@ SIM103.py:129:5: SIM103 [*] Return the condition `not 10 in a` directly
129 |- if 10 in a:
130 |- return False
131 |- return True
129 |+ return not 10 in a
129 |+ return 10 not in a
132 130 |
133 131 |
134 132 | def f():
SIM103.py:135:5: SIM103 [*] Return the condition `not 10 not in a` directly
SIM103.py:135:5: SIM103 [*] Return the condition `10 in a` directly
|
134 | def f():
135 | / if 10 not in a:
@@ -282,7 +282,7 @@ SIM103.py:135:5: SIM103 [*] Return the condition `not 10 not in a` directly
137 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not 10 not in a`
= help: Replace with `return 10 in a`
Unsafe fix
132 132 |
@@ -291,12 +291,12 @@ SIM103.py:135:5: SIM103 [*] Return the condition `not 10 not in a` directly
135 |- if 10 not in a:
136 |- return False
137 |- return True
135 |+ return not 10 not in a
135 |+ return 10 in a
138 136 |
139 137 |
140 138 | def f():
SIM103.py:141:5: SIM103 [*] Return the condition `not a is 10` directly
SIM103.py:141:5: SIM103 [*] Return the condition `a is not 10` directly
|
140 | def f():
141 | / if a is 10:
@@ -304,7 +304,7 @@ SIM103.py:141:5: SIM103 [*] Return the condition `not a is 10` directly
143 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not a is 10`
= help: Replace with `return a is not 10`
Unsafe fix
138 138 |
@@ -313,12 +313,12 @@ SIM103.py:141:5: SIM103 [*] Return the condition `not a is 10` directly
141 |- if a is 10:
142 |- return False
143 |- return True
141 |+ return not a is 10
141 |+ return a is not 10
144 142 |
145 143 |
146 144 | def f():
SIM103.py:147:5: SIM103 [*] Return the condition `not a is not 10` directly
SIM103.py:147:5: SIM103 [*] Return the condition `a is 10` directly
|
146 | def f():
147 | / if a is not 10:
@@ -326,7 +326,7 @@ SIM103.py:147:5: SIM103 [*] Return the condition `not a is not 10` directly
149 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not a is not 10`
= help: Replace with `return a is 10`
Unsafe fix
144 144 |
@@ -335,12 +335,12 @@ SIM103.py:147:5: SIM103 [*] Return the condition `not a is not 10` directly
147 |- if a is not 10:
148 |- return False
149 |- return True
147 |+ return not a is not 10
147 |+ return a is 10
150 148 |
151 149 |
152 150 | def f():
SIM103.py:153:5: SIM103 [*] Return the condition `not a == 10` directly
SIM103.py:153:5: SIM103 [*] Return the condition `a != 10` directly
|
152 | def f():
153 | / if a == 10:
@@ -348,7 +348,7 @@ SIM103.py:153:5: SIM103 [*] Return the condition `not a == 10` directly
155 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not a == 10`
= help: Replace with `return a != 10`
Unsafe fix
150 150 |
@@ -357,12 +357,12 @@ SIM103.py:153:5: SIM103 [*] Return the condition `not a == 10` directly
153 |- if a == 10:
154 |- return False
155 |- return True
153 |+ return not a == 10
153 |+ return a != 10
156 154 |
157 155 |
158 156 | def f():
SIM103.py:159:5: SIM103 [*] Return the condition `not a != 10` directly
SIM103.py:159:5: SIM103 [*] Return the condition `a == 10` directly
|
158 | def f():
159 | / if a != 10:
@@ -370,7 +370,7 @@ SIM103.py:159:5: SIM103 [*] Return the condition `not a != 10` directly
161 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not a != 10`
= help: Replace with `return a == 10`
Unsafe fix
156 156 |
@@ -379,4 +379,4 @@ SIM103.py:159:5: SIM103 [*] Return the condition `not a != 10` directly
159 |- if a != 10:
160 |- return False
161 |- return True
159 |+ return not a != 10
159 |+ return a == 10

View File

@@ -226,6 +226,33 @@ SIM108.py:167:1: SIM108 [*] Use ternary operator `z = 1 if True else other` inst
172 169 | if False:
173 170 | z = 1
SIM108.py:172:1: SIM108 [*] Use ternary operator `z = 1 if False else other` instead of `if`-`else`-block
|
170 | z = other
171 |
172 | / if False:
173 | | z = 1
174 | | else:
175 | | z = other
| |_____________^ SIM108
176 |
177 | if 1:
|
= help: Replace `if`-`else`-block with `z = 1 if False else other`
Unsafe fix
169 169 | else:
170 170 | z = other
171 171 |
172 |-if False:
173 |- z = 1
174 |-else:
175 |- z = other
172 |+z = 1 if False else other
176 173 |
177 174 | if 1:
178 175 | z = True
SIM108.py:177:1: SIM108 [*] Use ternary operator `z = True if 1 else other` instead of `if`-`else`-block
|
175 | z = other

View File

@@ -1,382 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM103.py:3:5: SIM103 [*] Return the condition `bool(a)` directly
|
1 | def f():
2 | # SIM103
3 | / if a:
4 | | return True
5 | | else:
6 | | return False
| |____________________^ SIM103
|
= help: Replace with `return bool(a)`
Unsafe fix
1 1 | def f():
2 2 | # SIM103
3 |- if a:
4 |- return True
5 |- else:
6 |- return False
3 |+ return bool(a)
7 4 |
8 5 |
9 6 | def f():
SIM103.py:11:5: SIM103 [*] Return the condition `a == b` directly
|
9 | def f():
10 | # SIM103
11 | / if a == b:
12 | | return True
13 | | else:
14 | | return False
| |____________________^ SIM103
|
= help: Replace with `return a == b`
Unsafe fix
8 8 |
9 9 | def f():
10 10 | # SIM103
11 |- if a == b:
12 |- return True
13 |- else:
14 |- return False
11 |+ return a == b
15 12 |
16 13 |
17 14 | def f():
SIM103.py:21:5: SIM103 [*] Return the condition `bool(b)` directly
|
19 | if a:
20 | return 1
21 | / elif b:
22 | | return True
23 | | else:
24 | | return False
| |____________________^ SIM103
|
= help: Replace with `return bool(b)`
Unsafe fix
18 18 | # SIM103
19 19 | if a:
20 20 | return 1
21 |- elif b:
22 |- return True
23 |- else:
24 |- return False
21 |+ return bool(b)
25 22 |
26 23 |
27 24 | def f():
SIM103.py:32:9: SIM103 [*] Return the condition `bool(b)` directly
|
30 | return 1
31 | else:
32 | / if b:
33 | | return True
34 | | else:
35 | | return False
| |________________________^ SIM103
|
= help: Replace with `return bool(b)`
Unsafe fix
29 29 | if a:
30 30 | return 1
31 31 | else:
32 |- if b:
33 |- return True
34 |- else:
35 |- return False
32 |+ return bool(b)
36 33 |
37 34 |
38 35 | def f():
SIM103.py:57:5: SIM103 [*] Return the condition `not a` directly
|
55 | def f():
56 | # SIM103
57 | / if a:
58 | | return False
59 | | else:
60 | | return True
| |___________________^ SIM103
|
= help: Replace with `return not a`
Unsafe fix
54 54 |
55 55 | def f():
56 56 | # SIM103
57 |- if a:
58 |- return False
59 |- else:
60 |- return True
57 |+ return not a
61 58 |
62 59 |
63 60 | def f():
SIM103.py:83:5: SIM103 Return the condition directly
|
81 | def bool():
82 | return False
83 | / if a:
84 | | return True
85 | | else:
86 | | return False
| |____________________^ SIM103
|
= help: Inline condition
SIM103.py:91:5: SIM103 [*] Return the condition `not (keys is not None and notice.key not in keys)` directly
|
89 | def f():
90 | # SIM103
91 | / if keys is not None and notice.key not in keys:
92 | | return False
93 | | else:
94 | | return True
| |___________________^ SIM103
|
= help: Replace with `return not (keys is not None and notice.key not in keys)`
Unsafe fix
88 88 |
89 89 | def f():
90 90 | # SIM103
91 |- if keys is not None and notice.key not in keys:
92 |- return False
93 |- else:
94 |- return True
91 |+ return not (keys is not None and notice.key not in keys)
95 92 |
96 93 |
97 94 | ###
SIM103.py:104:5: SIM103 [*] Return the condition `bool(a)` directly
|
102 | def f():
103 | # SIM103
104 | / if a:
105 | | return True
106 | | return False
| |________________^ SIM103
|
= help: Replace with `return bool(a)`
Unsafe fix
101 101 |
102 102 | def f():
103 103 | # SIM103
104 |- if a:
105 |- return True
106 |- return False
104 |+ return bool(a)
107 105 |
108 106 |
109 107 | def f():
SIM103.py:111:5: SIM103 [*] Return the condition `not a` directly
|
109 | def f():
110 | # SIM103
111 | / if a:
112 | | return False
113 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not a`
Unsafe fix
108 108 |
109 109 | def f():
110 110 | # SIM103
111 |- if a:
112 |- return False
113 |- return True
111 |+ return not a
114 112 |
115 113 |
116 114 | def f():
SIM103.py:117:5: SIM103 [*] Return the condition `10 < a` directly
|
116 | def f():
117 | / if not 10 < a:
118 | | return False
119 | | return True
| |_______________^ SIM103
|
= help: Replace with `return 10 < a`
Unsafe fix
114 114 |
115 115 |
116 116 | def f():
117 |- if not 10 < a:
118 |- return False
119 |- return True
117 |+ return 10 < a
120 118 |
121 119 |
122 120 | def f():
SIM103.py:123:5: SIM103 [*] Return the condition `not 10 < a` directly
|
122 | def f():
123 | / if 10 < a:
124 | | return False
125 | | return True
| |_______________^ SIM103
|
= help: Replace with `return not 10 < a`
Unsafe fix
120 120 |
121 121 |
122 122 | def f():
123 |- if 10 < a:
124 |- return False
125 |- return True
123 |+ return not 10 < a
126 124 |
127 125 |
128 126 | def f():
SIM103.py:129:5: SIM103 [*] Return the condition `10 not in a` directly
|
128 | def f():
129 | / if 10 in a:
130 | | return False
131 | | return True
| |_______________^ SIM103
|
= help: Replace with `return 10 not in a`
Unsafe fix
126 126 |
127 127 |
128 128 | def f():
129 |- if 10 in a:
130 |- return False
131 |- return True
129 |+ return 10 not in a
132 130 |
133 131 |
134 132 | def f():
SIM103.py:135:5: SIM103 [*] Return the condition `10 in a` directly
|
134 | def f():
135 | / if 10 not in a:
136 | | return False
137 | | return True
| |_______________^ SIM103
|
= help: Replace with `return 10 in a`
Unsafe fix
132 132 |
133 133 |
134 134 | def f():
135 |- if 10 not in a:
136 |- return False
137 |- return True
135 |+ return 10 in a
138 136 |
139 137 |
140 138 | def f():
SIM103.py:141:5: SIM103 [*] Return the condition `a is not 10` directly
|
140 | def f():
141 | / if a is 10:
142 | | return False
143 | | return True
| |_______________^ SIM103
|
= help: Replace with `return a is not 10`
Unsafe fix
138 138 |
139 139 |
140 140 | def f():
141 |- if a is 10:
142 |- return False
143 |- return True
141 |+ return a is not 10
144 142 |
145 143 |
146 144 | def f():
SIM103.py:147:5: SIM103 [*] Return the condition `a is 10` directly
|
146 | def f():
147 | / if a is not 10:
148 | | return False
149 | | return True
| |_______________^ SIM103
|
= help: Replace with `return a is 10`
Unsafe fix
144 144 |
145 145 |
146 146 | def f():
147 |- if a is not 10:
148 |- return False
149 |- return True
147 |+ return a is 10
150 148 |
151 149 |
152 150 | def f():
SIM103.py:153:5: SIM103 [*] Return the condition `a != 10` directly
|
152 | def f():
153 | / if a == 10:
154 | | return False
155 | | return True
| |_______________^ SIM103
|
= help: Replace with `return a != 10`
Unsafe fix
150 150 |
151 151 |
152 152 | def f():
153 |- if a == 10:
154 |- return False
155 |- return True
153 |+ return a != 10
156 154 |
157 155 |
158 156 | def f():
SIM103.py:159:5: SIM103 [*] Return the condition `a == 10` directly
|
158 | def f():
159 | / if a != 10:
160 | | return False
161 | | return True
| |_______________^ SIM103
|
= help: Replace with `return a == 10`
Unsafe fix
156 156 |
157 157 |
158 158 | def f():
159 |- if a != 10:
160 |- return False
161 |- return True
159 |+ return a == 10

View File

@@ -16,102 +16,64 @@ TC005.py:4:5: TC005 [*] Found empty type-checking block
4 |- pass # TC005
5 3 |
6 4 |
7 5 | if False:
7 5 | def example():
TC005.py:8:5: TC005 [*] Found empty type-checking block
TC005.py:9:9: TC005 [*] Found empty type-checking block
|
7 | if False:
8 | pass # TC005
| ^^^^ TC005
9 |
10 | if 0:
7 | def example():
8 | if TYPE_CHECKING:
9 | pass # TC005
| ^^^^ TC005
10 | return
|
= help: Delete empty type-checking block
Safe fix
4 4 | pass # TC005
5 5 |
6 6 |
7 |-if False:
8 |- pass # TC005
9 7 |
10 8 | if 0:
11 9 | pass # TC005
TC005.py:11:5: TC005 [*] Found empty type-checking block
|
10 | if 0:
11 | pass # TC005
| ^^^^ TC005
|
= help: Delete empty type-checking block
Safe fix
7 7 | if False:
8 8 | pass # TC005
9 9 |
10 |-if 0:
11 |- pass # TC005
5 5 |
6 6 |
7 7 | def example():
8 |- if TYPE_CHECKING:
9 |- pass # TC005
10 8 | return
11 9 |
12 10 |
13 11 |
14 12 | def example():
TC005.py:16:9: TC005 [*] Found empty type-checking block
TC005.py:15:9: TC005 [*] Found empty type-checking block
|
14 | def example():
15 | if TYPE_CHECKING:
16 | pass # TC005
13 | class Test:
14 | if TYPE_CHECKING:
15 | pass # TC005
| ^^^^ TC005
17 | return
16 | x = 2
|
= help: Delete empty type-checking block
Safe fix
11 11 |
12 12 |
13 13 |
14 14 | def example():
15 |- if TYPE_CHECKING:
16 |- pass # TC005
17 15 | return
13 13 | class Test:
14 |- if TYPE_CHECKING:
15 |- pass # TC005
16 14 | x = 2
17 15 |
18 16 |
19 17 |
TC005.py:22:9: TC005 [*] Found empty type-checking block
TC005.py:31:5: TC005 [*] Found empty type-checking block
|
20 | class Test:
21 | if TYPE_CHECKING:
22 | pass # TC005
| ^^^^ TC005
23 | x = 2
|
= help: Delete empty type-checking block
Safe fix
18 18 |
19 19 |
20 20 | class Test:
21 |- if TYPE_CHECKING:
22 |- pass # TC005
23 21 | x = 2
24 22 |
25 23 |
TC005.py:45:5: TC005 [*] Found empty type-checking block
|
44 | if TYPE_CHECKING:
45 | pass # TC005
30 | if TYPE_CHECKING:
31 | pass # TC005
| ^^^^ TC005
46 |
47 | # https://github.com/astral-sh/ruff/issues/11368
32 |
33 | # https://github.com/astral-sh/ruff/issues/11368
|
= help: Delete empty type-checking block
Safe fix
41 41 |
42 42 | from typing_extensions import TYPE_CHECKING
43 43 |
44 |-if TYPE_CHECKING:
45 |- pass # TC005
46 44 |
47 45 | # https://github.com/astral-sh/ruff/issues/11368
48 46 | if TYPE_CHECKING:
27 27 |
28 28 | from typing_extensions import TYPE_CHECKING
29 29 |
30 |-if TYPE_CHECKING:
31 |- pass # TC005
32 30 |
33 31 | # https://github.com/astral-sh/ruff/issues/11368
34 32 | if TYPE_CHECKING:

View File

@@ -14,13 +14,13 @@ mod tests {
use crate::registry::Rule;
use crate::rules::pep8_naming::settings::IgnoreNames;
use crate::rules::{flake8_import_conventions, pep8_naming};
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
#[test_case(Rule::InvalidClassName, Path::new("N801.py"))]
#[test_case(Rule::InvalidFunctionName, Path::new("N802.py"))]
#[test_case(Rule::InvalidArgumentName, Path::new("N803.py"))]
#[test_case(Rule::InvalidArgumentName, Path::new("N804.py"))]
#[test_case(Rule::InvalidFirstArgumentNameForClassMethod, Path::new("N804.py"))]
#[test_case(Rule::InvalidFirstArgumentNameForMethod, Path::new("N805.py"))]
#[test_case(Rule::NonLowercaseVariableInFunction, Path::new("N806.py"))]
@@ -89,25 +89,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::InvalidArgumentName, Path::new("N803.py"))]
#[test_case(Rule::InvalidArgumentName, Path::new("N804.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pep8_naming").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn camelcase_imported_as_incorrect_convention() -> Result<()> {
let diagnostics = test_path(

View File

@@ -23,7 +23,7 @@ use crate::checkers::ast::Checker;
/// > mixedCase is allowed only in contexts where thats already the
/// > prevailing style (e.g. threading.py), to retain backwards compatibility.
///
/// In [preview], overridden methods are ignored.
/// Methods decorated with `@typing.override` are ignored.
///
/// ## Example
/// ```python
@@ -61,8 +61,7 @@ pub(crate) fn invalid_argument_name_function(checker: &Checker, function_def: &S
let semantic = checker.semantic();
let scope = semantic.current_scope();
if checker.settings.preview.is_enabled()
&& matches!(scope.kind, ScopeKind::Class(_))
if matches!(scope.kind, ScopeKind::Class(_))
&& is_override(&function_def.decorator_list, semantic)
{
return;

View File

@@ -82,8 +82,8 @@ impl Violation for InvalidFirstArgumentNameForMethod {
/// Checks for class methods that use a name other than `cls` for their
/// first argument.
///
/// With [`preview`] enabled, the method `__new__` is exempted from this
/// check and the corresponding violation is then caught by
/// The method `__new__` is exempted from this
/// check and the corresponding violation is caught by
/// [`bad-staticmethod-argument`][PLW0211].
///
/// ## Why is this bad?
@@ -164,8 +164,6 @@ enum FunctionType {
Method,
/// The function is a class method.
ClassMethod,
/// The function is the method `__new__`
NewMethod,
}
impl FunctionType {
@@ -177,11 +175,6 @@ impl FunctionType {
is_new: false,
}
.into(),
Self::NewMethod => InvalidFirstArgumentNameForClassMethod {
argument_name,
is_new: true,
}
.into(),
}
}
@@ -189,7 +182,6 @@ impl FunctionType {
match self {
Self::Method => "self",
Self::ClassMethod => "cls",
Self::NewMethod => "cls",
}
}
@@ -197,7 +189,6 @@ impl FunctionType {
match self {
Self::Method => Rule::InvalidFirstArgumentNameForMethod,
Self::ClassMethod => Rule::InvalidFirstArgumentNameForClassMethod,
Self::NewMethod => Rule::InvalidFirstArgumentNameForClassMethod,
}
}
}
@@ -241,11 +232,10 @@ pub(crate) fn invalid_first_argument_name(checker: &Checker, scope: &Scope) {
IsMetaclass::Maybe => return,
},
function_type::FunctionType::ClassMethod => FunctionType::ClassMethod,
// In preview, this violation is caught by `PLW0211` instead
function_type::FunctionType::NewMethod if checker.settings.preview.is_enabled() => {
// This violation is caught by `PLW0211` instead
function_type::FunctionType::NewMethod => {
return;
}
function_type::FunctionType::NewMethod => FunctionType::NewMethod,
};
if !checker.enabled(function_type.rule()) {
return;

View File

@@ -16,14 +16,6 @@ N803.py:6:28: N803 Argument name `A` should be lowercase
7 | return _, a, A
|
N803.py:18:28: N803 Argument name `A` should be lowercase
|
16 | class Extended(Class):
17 | @override
18 | def method(self, _, a, A): ...
| ^ N803
|
N803.py:22:16: N803 Argument name `A` should be lowercase
|
21 | @override # Incorrect usage

View File

@@ -1,37 +0,0 @@
---
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
---
N803.py:1:16: N803 Argument name `A` should be lowercase
|
1 | def func(_, a, A):
| ^ N803
2 | return _, a, A
|
N803.py:6:28: N803 Argument name `A` should be lowercase
|
5 | class Class:
6 | def method(self, _, a, A):
| ^ N803
7 | return _, a, A
|
N803.py:22:16: N803 Argument name `A` should be lowercase
|
21 | @override # Incorrect usage
22 | def func(_, a, A): ...
| ^ N803
|
N803.py:25:21: N803 Argument name `A` should be lowercase
|
25 | func = lambda _, a, A: ...
| ^ N803
|
N803.py:29:42: N803 Argument name `A` should be lowercase
|
28 | class Extended(Class):
29 | method = override(lambda self, _, a, A: ...) # Incorrect usage
| ^ N803
|

View File

@@ -10,7 +10,6 @@ mod tests {
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -30,22 +29,4 @@ mod tests {
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test_case(Rule::BlanketNOQA, Path::new("PGH004_2.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pygrep_hooks").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -3,8 +3,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_trivia::Cursor;
use ruff_text_size::{Ranged, TextRange};
use crate::noqa::{Directive, FileNoqaDirectives, NoqaDirectives, ParsedFileExemption};
use crate::settings::types::PreviewMode;
use crate::noqa::{self, Directive, FileNoqaDirectives, NoqaDirectives};
use crate::Locator;
/// ## What it does
@@ -18,9 +17,6 @@ use crate::Locator;
/// maintain, as the annotation does not clarify which diagnostics are intended
/// to be suppressed.
///
/// In [preview], this rule also checks for blanket file-level annotations (e.g.,
/// `# ruff: noqa`, as opposed to `# ruff: noqa: F401`).
///
/// ## Example
/// ```python
/// from .base import * # noqa
@@ -41,12 +37,9 @@ use crate::Locator;
///
/// ## References
/// - [Ruff documentation](https://docs.astral.sh/ruff/configuration/#error-suppression)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
pub(crate) struct BlanketNOQA {
missing_colon: bool,
space_before_colon: bool,
file_exemption: bool,
}
@@ -57,27 +50,22 @@ impl Violation for BlanketNOQA {
fn message(&self) -> String {
let BlanketNOQA {
missing_colon,
space_before_colon,
file_exemption,
} = self;
// This awkward branching is necessary to ensure that the generic message is picked up by
// `derive_message_formats`.
if !missing_colon && !space_before_colon && !file_exemption {
if !missing_colon && !file_exemption {
"Use specific rule codes when using `noqa`".to_string()
} else if *file_exemption {
"Use specific rule codes when using `ruff: noqa`".to_string()
} else if *missing_colon {
"Use a colon when specifying `noqa` rule codes".to_string()
} else {
"Do not add spaces between `noqa` and its colon".to_string()
"Use a colon when specifying `noqa` rule codes".to_string()
}
}
fn fix_title(&self) -> Option<String> {
if self.missing_colon {
Some("Add missing colon".to_string())
} else if self.space_before_colon {
Some("Remove space(s) before colon".to_string())
} else {
None
}
@@ -90,20 +78,16 @@ pub(crate) fn blanket_noqa(
noqa_directives: &NoqaDirectives,
locator: &Locator,
file_noqa_directives: &FileNoqaDirectives,
preview: PreviewMode,
) {
if preview.is_enabled() {
for line in file_noqa_directives.lines() {
if let ParsedFileExemption::All = line.parsed_file_exemption {
diagnostics.push(Diagnostic::new(
BlanketNOQA {
missing_colon: false,
space_before_colon: false,
file_exemption: true,
},
line.range(),
));
}
for line in file_noqa_directives.lines() {
if let Directive::All(_) = line.parsed_file_exemption {
diagnostics.push(Diagnostic::new(
BlanketNOQA {
missing_colon: false,
file_exemption: true,
},
line.range(),
));
}
}
@@ -116,22 +100,7 @@ pub(crate) fn blanket_noqa(
let mut cursor = Cursor::new(&line[noqa_end.to_usize()..]);
cursor.eat_while(char::is_whitespace);
// Check for extraneous spaces before the colon.
// Ex) `# noqa : F401`
if cursor.first() == ':' {
let start = all.end();
let end = start + cursor.token_len();
let mut diagnostic = Diagnostic::new(
BlanketNOQA {
missing_colon: false,
space_before_colon: true,
file_exemption: false,
},
TextRange::new(all.start(), end),
);
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(start, end)));
diagnostics.push(diagnostic);
} else if Directive::lex_code(cursor.chars().as_str()).is_some() {
if noqa::lex_codes(cursor.chars().as_str()).is_ok_and(|codes| !codes.is_empty()) {
// Check for a missing colon.
// Ex) `# noqa F401`
let start = all.end();
@@ -139,7 +108,6 @@ pub(crate) fn blanket_noqa(
let mut diagnostic = Diagnostic::new(
BlanketNOQA {
missing_colon: true,
space_before_colon: false,
file_exemption: false,
},
TextRange::new(all.start(), end),
@@ -151,7 +119,6 @@ pub(crate) fn blanket_noqa(
diagnostics.push(Diagnostic::new(
BlanketNOQA {
missing_colon: false,
space_before_colon: false,
file_exemption: false,
},
all.range(),

View File

@@ -68,58 +68,3 @@ PGH004_0.py:21:8: PGH004 [*] Use a colon when specifying `noqa` rule codes
22 22 |
23 23 | # PGH004
24 24 | x = 2 # noqa : X300
PGH004_0.py:24:8: PGH004 [*] Do not add spaces between `noqa` and its colon
|
23 | # PGH004
24 | x = 2 # noqa : X300
| ^^^^^^^ PGH004
25 |
26 | # PGH004
|
= help: Remove space(s) before colon
Unsafe fix
21 21 | x = 2 # noqa X100, X200
22 22 |
23 23 | # PGH004
24 |-x = 2 # noqa : X300
24 |+x = 2 # noqa: X300
25 25 |
26 26 | # PGH004
27 27 | x = 2 # noqa : X400
PGH004_0.py:27:8: PGH004 [*] Do not add spaces between `noqa` and its colon
|
26 | # PGH004
27 | x = 2 # noqa : X400
| ^^^^^^^^ PGH004
28 |
29 | # PGH004
|
= help: Remove space(s) before colon
Unsafe fix
24 24 | x = 2 # noqa : X300
25 25 |
26 26 | # PGH004
27 |-x = 2 # noqa : X400
27 |+x = 2 # noqa: X400
28 28 |
29 29 | # PGH004
30 30 | x = 2 # noqa :X500
PGH004_0.py:30:8: PGH004 [*] Do not add spaces between `noqa` and its colon
|
29 | # PGH004
30 | x = 2 # noqa :X500
| ^^^^^^^ PGH004
|
= help: Remove space(s) before colon
Unsafe fix
27 27 | x = 2 # noqa : X400
28 28 |
29 29 | # PGH004
30 |-x = 2 # noqa :X500
30 |+x = 2 # noqa:X500

View File

@@ -1,6 +1,5 @@
---
source: crates/ruff_linter/src/rules/pygrep_hooks/mod.rs
snapshot_kind: text
---
PGH004_2.py:1:1: PGH004 Use specific rule codes when using `noqa`
|
@@ -9,3 +8,18 @@ PGH004_2.py:1:1: PGH004 Use specific rule codes when using `noqa`
2 | # ruff : noqa
3 | # ruff: noqa: F401
|
PGH004_2.py:2:1: PGH004 Use specific rule codes when using `ruff: noqa`
|
1 | # noqa
2 | # ruff : noqa
| ^^^^^^^^^^^^^ PGH004
3 | # ruff: noqa: F401
|
PGH004_2.py:6:1: PGH004 Use specific rule codes when using `ruff: noqa`
|
6 | # flake8: noqa
| ^^^^^^^^^^^^^^ PGH004
7 | import math as m
|

View File

@@ -1,26 +0,0 @@
---
source: crates/ruff_linter/src/rules/pygrep_hooks/mod.rs
snapshot_kind: text
---
PGH004_2.py:1:1: PGH004 Use specific rule codes when using `noqa`
|
1 | # noqa
| ^^^^^^ PGH004
2 | # ruff : noqa
3 | # ruff: noqa: F401
|
PGH004_2.py:2:1: PGH004 Use specific rule codes when using `ruff: noqa`
|
1 | # noqa
2 | # ruff : noqa
| ^^^^^^^^^^^^^ PGH004
3 | # ruff: noqa: F401
|
PGH004_2.py:6:1: PGH004 Use specific rule codes when using `ruff: noqa`
|
6 | # flake8: noqa
| ^^^^^^^^^^^^^^ PGH004
7 | import math as m
|

View File

@@ -16,10 +16,10 @@ mod tests {
use crate::registry::Rule;
use crate::rules::{flake8_tidy_imports, pylint};
use crate::assert_messages;
use crate::settings::types::PreviewMode;
use crate::settings::LinterSettings;
use crate::test::test_path;
use crate::{assert_messages, settings};
#[test_case(Rule::SingledispatchMethod, Path::new("singledispatch_method.py"))]
#[test_case(
@@ -440,31 +440,4 @@ mod tests {
assert_messages!(diagnostics);
Ok(())
}
#[test_case(
Rule::RepeatedEqualityComparison,
Path::new("repeated_equality_comparison.py")
)]
#[test_case(Rule::InvalidEnvvarDefault, Path::new("invalid_envvar_default.py"))]
#[test_case(Rule::BadStrStripCall, Path::new("bad_str_strip_call.py"))]
#[test_case(
Rule::BadStaticmethodArgument,
Path::new("bad_staticmethod_argument.py")
)]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pylint").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast as ast;
use ruff_python_ast::ParameterWithDefault;
use ruff_python_semantic::analyze::function_type;
use ruff_python_semantic::analyze::function_type::FunctionType;
use ruff_python_semantic::Scope;
use ruff_text_size::Ranged;
@@ -10,9 +11,7 @@ use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for static methods that use `self` or `cls` as their first argument.
///
/// If [`preview`] mode is enabled, this rule also applies to
/// `__new__` methods, which are implicitly static.
/// This rule also applies to `__new__` methods, which are implicitly static.
///
/// ## Why is this bad?
/// [PEP 8] recommends the use of `self` and `cls` as the first arguments for
@@ -77,9 +76,8 @@ pub(crate) fn bad_staticmethod_argument(checker: &Checker, scope: &Scope) {
);
match type_ {
function_type::FunctionType::StaticMethod => {}
function_type::FunctionType::NewMethod if checker.settings.preview.is_enabled() => {}
_ => {
FunctionType::StaticMethod | FunctionType::NewMethod => {}
FunctionType::Function | FunctionType::Method | FunctionType::ClassMethod => {
return;
}
};

View File

@@ -187,12 +187,6 @@ pub(crate) fn bad_str_strip_call(checker: &Checker, call: &ast::ExprCall) {
let value = &**value;
if checker.settings.preview.is_disabled()
&& !matches!(value, Expr::StringLiteral(_) | Expr::BytesLiteral(_))
{
return;
}
let Some(value_kind) = ValueKind::from(value, checker.semantic()) else {
return;
};

View File

@@ -52,14 +52,10 @@ pub(crate) fn invalid_envvar_default(checker: &Checker, call: &ast::ExprCall) {
.semantic()
.resolve_qualified_name(&call.func)
.is_some_and(|qualified_name| {
if checker.settings.preview.is_enabled() {
matches!(
qualified_name.segments(),
["os", "getenv"] | ["os", "environ", "get"]
)
} else {
matches!(qualified_name.segments(), ["os", "getenv"])
}
matches!(
qualified_name.segments(),
["os", "getenv"] | ["os", "environ", "get"]
)
})
{
// Find the `default` argument, if it exists.

View File

@@ -9,12 +9,11 @@ use ruff_python_semantic::{BindingId, SemanticModel};
use ruff_text_size::Ranged;
/// ## What it does
/// Checks for usage of call of 'len' on sequences
/// in boolean test context.
/// Checks for `len` calls on sequences in a boolean test context.
///
/// ## Why is this bad?
/// Empty sequences are considered false in a boolean context.
/// You can either remove the call to 'len'
/// You can either remove the call to `len`
/// or compare the length against a scalar.
///
/// ## Example

View File

@@ -15,9 +15,13 @@ use crate::fix::snippet::SourceCodeSnippet;
use crate::Locator;
/// ## What it does
/// Checks for repeated equality comparisons that can rewritten as a membership
/// Checks for repeated equality comparisons that can be rewritten as a membership
/// test.
///
/// This rule will try to determine if the values are hashable
/// and the fix will use a `set` if they are. If unable to determine, the fix
/// will use a `tuple` and suggest the use of a `set`.
///
/// ## Why is this bad?
/// To check if a variable is equal to one of many values, it is common to
/// write a series of equality comparisons (e.g.,
@@ -28,10 +32,6 @@ use crate::Locator;
/// If the items are hashable, use a `set` for efficiency; otherwise, use a
/// `tuple`.
///
/// In [preview], this rule will try to determine if the values are hashable
/// and the fix will use a `set` if they are. If unable to determine, the fix
/// will use a `tuple` and continue to suggest the use of a `set`.
///
/// ## Example
/// ```python
/// foo == "bar" or foo == "baz" or foo == "qux"
@@ -46,8 +46,6 @@ use crate::Locator;
/// - [Python documentation: Comparisons](https://docs.python.org/3/reference/expressions.html#comparisons)
/// - [Python documentation: Membership test operations](https://docs.python.org/3/reference/expressions.html#membership-test-operations)
/// - [Python documentation: `set`](https://docs.python.org/3/library/stdtypes.html#set)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
pub(crate) struct RepeatedEqualityComparison {
expression: SourceCodeSnippet,
@@ -135,10 +133,9 @@ pub(crate) fn repeated_equality_comparison(checker: &Checker, bool_op: &ast::Exp
// if we can determine that all the values are hashable, we can use a set
// TODO: improve with type inference
let all_hashable = checker.settings.preview.is_enabled()
&& comparators
.iter()
.all(|comparator| comparator.is_literal_expr());
let all_hashable = comparators
.iter()
.all(|comparator| comparator.is_literal_expr());
let mut diagnostic = Diagnostic::new(
RepeatedEqualityComparison {

View File

@@ -13,7 +13,7 @@ use crate::checkers::ast::Checker;
/// `os.environ` is not a `dict` object, but rather, a proxy object. As such, mutating a shallow
/// copy of `os.environ` will also mutate the original object.
///
/// See: [#15373] for more information.
/// See [BPO 15373] for more information.
///
/// ## Example
/// ```python
@@ -41,7 +41,7 @@ use crate::checkers::ast::Checker;
/// - [Python documentation: `copy` — Shallow and deep copy operations](https://docs.python.org/3/library/copy.html)
/// - [Python documentation: `os.environ`](https://docs.python.org/3/library/os.html#os.environ)
///
/// [#15373]: https://bugs.python.org/issue15373
/// [BPO 15373]: https://bugs.python.org/issue15373
#[derive(ViolationMetadata)]
pub(crate) struct ShallowCopyEnviron;

View File

@@ -181,3 +181,30 @@ bad_str_strip_call.py:81:10: PLE1310 String `strip` call contains duplicate char
82 |
83 | # Errors: Type inference
|
bad_str_strip_call.py:85:9: PLE1310 String `strip` call contains duplicate characters
|
83 | # Errors: Type inference
84 | b = b''
85 | b.strip(b'//')
| ^^^^^ PLE1310
86 |
87 | # Errors: Type inference (preview)
|
bad_str_strip_call.py:89:12: PLE1310 String `rstrip` call contains duplicate characters (did you mean `removesuffix`?)
|
87 | # Errors: Type inference (preview)
88 | foo: str = ""; bar: bytes = b""
89 | foo.rstrip("//")
| ^^^^ PLE1310
90 | bar.lstrip(b"//")
|
bad_str_strip_call.py:90:12: PLE1310 String `lstrip` call contains duplicate characters (did you mean `removeprefix`?)
|
88 | foo: str = ""; bar: bytes = b""
89 | foo.rstrip("//")
90 | bar.lstrip(b"//")
| ^^^^^ PLE1310
|

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
1 | # Errors.
2 | foo == "a" or foo == "b"
@@ -14,12 +14,12 @@ repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple compa
Unsafe fix
1 1 | # Errors.
2 |-foo == "a" or foo == "b"
2 |+foo in ("a", "b")
2 |+foo in {"a", "b"}
3 3 |
4 4 | foo != "a" and foo != "b"
5 5 |
repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b"}`.
|
2 | foo == "a" or foo == "b"
3 |
@@ -35,12 +35,12 @@ repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple compa
2 2 | foo == "a" or foo == "b"
3 3 |
4 |-foo != "a" and foo != "b"
4 |+foo not in ("a", "b")
4 |+foo not in {"a", "b"}
5 5 |
6 6 | foo == "a" or foo == "b" or foo == "c"
7 7 |
repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
4 | foo != "a" and foo != "b"
5 |
@@ -56,12 +56,12 @@ repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple compa
4 4 | foo != "a" and foo != "b"
5 5 |
6 |-foo == "a" or foo == "b" or foo == "c"
6 |+foo in ("a", "b", "c")
6 |+foo in {"a", "b", "c"}
7 7 |
8 8 | foo != "a" and foo != "b" and foo != "c"
9 9 |
repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
6 | foo == "a" or foo == "b" or foo == "c"
7 |
@@ -77,7 +77,7 @@ repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple compa
6 6 | foo == "a" or foo == "b" or foo == "c"
7 7 |
8 |-foo != "a" and foo != "b" and foo != "c"
8 |+foo not in ("a", "b", "c")
8 |+foo not in {"a", "b", "c"}
9 9 |
10 10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 11 |
@@ -103,7 +103,7 @@ repeated_equality_comparison.py:10:1: PLR1714 [*] Consider merging multiple comp
12 12 | "a" == foo or "b" == foo or "c" == foo
13 13 |
repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 |
@@ -119,12 +119,12 @@ repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comp
10 10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 11 |
12 |-"a" == foo or "b" == foo or "c" == foo
12 |+foo in ("a", "b", "c")
12 |+foo in {"a", "b", "c"}
13 13 |
14 14 | "a" != foo and "b" != foo and "c" != foo
15 15 |
repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
12 | "a" == foo or "b" == foo or "c" == foo
13 |
@@ -140,12 +140,12 @@ repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comp
12 12 | "a" == foo or "b" == foo or "c" == foo
13 13 |
14 |-"a" != foo and "b" != foo and "c" != foo
14 |+foo not in ("a", "b", "c")
14 |+foo not in {"a", "b", "c"}
15 15 |
16 16 | "a" == foo or foo == "b" or "c" == foo
17 17 |
repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
14 | "a" != foo and "b" != foo and "c" != foo
15 |
@@ -161,7 +161,7 @@ repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comp
14 14 | "a" != foo and "b" != foo and "c" != foo
15 15 |
16 |-"a" == foo or foo == "b" or "c" == foo
16 |+foo in ("a", "b", "c")
16 |+foo in {"a", "b", "c"}
17 17 |
18 18 | foo == bar or baz == foo or qux == foo
19 19 |
@@ -187,7 +187,7 @@ repeated_equality_comparison.py:18:1: PLR1714 [*] Consider merging multiple comp
20 20 | foo == "a" or "b" == foo or foo == "c"
21 21 |
repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
18 | foo == bar or baz == foo or qux == foo
19 |
@@ -203,12 +203,12 @@ repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comp
18 18 | foo == bar or baz == foo or qux == foo
19 19 |
20 |-foo == "a" or "b" == foo or foo == "c"
20 |+foo in ("a", "b", "c")
20 |+foo in {"a", "b", "c"}
21 21 |
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in ("a", "b", "c")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
20 | foo == "a" or "b" == foo or foo == "c"
21 |
@@ -224,12 +224,12 @@ repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comp
20 20 | foo == "a" or "b" == foo or foo == "c"
21 21 |
22 |-foo != "a" and "b" != foo and foo != "c"
22 |+foo not in ("a", "b", "c")
22 |+foo not in {"a", "b", "c"}
23 23 |
24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 25 |
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
22 | foo != "a" and "b" != foo and foo != "c"
23 |
@@ -245,12 +245,12 @@ repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comp
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
24 |+foo in ("a", "b") or "c" == bar or "d" == bar # Multiple targets
24 |+foo in {"a", "b"} or "c" == bar or "d" == bar # Multiple targets
25 25 |
26 26 | foo.bar == "a" or foo.bar == "b" # Attributes.
27 27 |
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `bar in ("c", "d")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`.
|
22 | foo != "a" and "b" != foo and foo != "c"
23 |
@@ -266,12 +266,12 @@ repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comp
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
24 |+foo == "a" or foo == "b" or bar in ("c", "d") # Multiple targets
24 |+foo == "a" or foo == "b" or bar in {"c", "d"} # Multiple targets
25 25 |
26 26 | foo.bar == "a" or foo.bar == "b" # Attributes.
27 27 |
repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comparisons: `foo.bar in ("a", "b")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comparisons: `foo.bar in {"a", "b"}`.
|
24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 |
@@ -287,12 +287,12 @@ repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comp
24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 25 |
26 |-foo.bar == "a" or foo.bar == "b" # Attributes.
26 |+foo.bar in ("a", "b") # Attributes.
26 |+foo.bar in {"a", "b"} # Attributes.
27 27 |
28 28 | # OK
29 29 | foo == "a" and foo == "b" and foo == "c" # `and` mixed with `==`.
repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple comparisons: `bar in ("c", "d")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`.
|
59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets
60 |
@@ -308,12 +308,12 @@ repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple com
59 59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets
60 60 |
61 |-foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
61 |+foo == "a" or (bar in ("c", "d")) or foo == "b" # Multiple targets
61 |+foo == "a" or (bar in {"c", "d"}) or foo == "b" # Multiple targets
62 62 |
63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 64 |
repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comparisons: `foo in ("a", "b")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 |
@@ -329,12 +329,12 @@ repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comp
61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 62 |
63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
63 |+foo in ("a", "b") or "c" != bar and "d" != bar # Multiple targets
63 |+foo in {"a", "b"} or "c" != bar and "d" != bar # Multiple targets
64 64 |
65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
66 66 |
repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple comparisons: `bar not in ("c", "d")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`.
|
61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 |
@@ -350,12 +350,12 @@ repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple com
61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 62 |
63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
63 |+foo == "a" or foo == "b" or bar not in ("c", "d") # Multiple targets
63 |+foo == "a" or foo == "b" or bar not in {"c", "d"} # Multiple targets
64 64 |
65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
66 66 |
repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple comparisons: `bar not in ("c", "d")`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`.
|
63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 |
@@ -371,12 +371,12 @@ repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple com
63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 64 |
65 |-foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
65 |+foo == "a" or (bar not in ("c", "d")) or foo == "b" # Multiple targets
65 |+foo == "a" or (bar not in {"c", "d"}) or foo == "b" # Multiple targets
66 66 |
67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 68 |
repeated_equality_comparison.py:69:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (1, True)`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:69:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {1, True}`.
|
67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 |
@@ -392,12 +392,12 @@ repeated_equality_comparison.py:69:1: PLR1714 [*] Consider merging multiple comp
67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 68 |
69 |-foo == 1 or foo == True # Different types, same hashed value
69 |+foo in (1, True) # Different types, same hashed value
69 |+foo in {1, True} # Different types, same hashed value
70 70 |
71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 72 |
repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (1, 1.0)`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {1, 1.0}`.
|
69 | foo == 1 or foo == True # Different types, same hashed value
70 |
@@ -413,12 +413,12 @@ repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comp
69 69 | foo == 1 or foo == True # Different types, same hashed value
70 70 |
71 |-foo == 1 or foo == 1.0 # Different types, same hashed value
71 |+foo in (1, 1.0) # Different types, same hashed value
71 |+foo in {1, 1.0} # Different types, same hashed value
72 72 |
73 73 | foo == False or foo == 0 # Different types, same hashed value
74 74 |
repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (False, 0)`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {False, 0}`.
|
71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 |
@@ -434,11 +434,11 @@ repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comp
71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 72 |
73 |-foo == False or foo == 0 # Different types, same hashed value
73 |+foo in (False, 0) # Different types, same hashed value
73 |+foo in {False, 0} # Different types, same hashed value
74 74 |
75 75 | foo == 0.0 or foo == 0j # Different types, same hashed value
repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (0.0, 0j)`. Use a `set` if the elements are hashable.
repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {0.0, 0j}`.
|
73 | foo == False or foo == 0 # Different types, same hashed value
74 |
@@ -452,4 +452,4 @@ repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comp
73 73 | foo == False or foo == 0 # Different types, same hashed value
74 74 |
75 |-foo == 0.0 or foo == 0j # Different types, same hashed value
75 |+foo in (0.0, 0j) # Different types, same hashed value
75 |+foo in {0.0, 0j} # Different types, same hashed value

View File

@@ -26,3 +26,12 @@ bad_staticmethod_argument.py:19:15: PLW0211 First argument of a static method sh
| ^^^^ PLW0211
20 | pass
|
bad_staticmethod_argument.py:55:17: PLW0211 First argument of a static method should not be named `self`
|
53 | # `self` but not with `cls` as first argument - see above).
54 | class Foo:
55 | def __new__(self, x, y, z): # [bad-staticmethod-argument]
| ^^^^ PLW0211
56 | pass
|

View File

@@ -50,3 +50,13 @@ invalid_envvar_default.py:14:17: PLW1508 Invalid type for environment variable d
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
16 | os.environ.get("TEST", "AA" * 12)
|
invalid_envvar_default.py:15:24: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
13 | os.getenv("AA", "GOOD" if Z else "BAR")
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
| ^^ PLW1508
16 | os.environ.get("TEST", "AA" * 12)
17 | os.environ.get("TEST", 13 * "AA")
|

View File

@@ -1,210 +0,0 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
bad_str_strip_call.py:2:21: PLE1310 String `strip` call contains duplicate characters
|
1 | # PLE1310
2 | "Hello World".strip("Hello")
| ^^^^^^^ PLE1310
3 |
4 | # PLE1310
|
bad_str_strip_call.py:5:21: PLE1310 String `strip` call contains duplicate characters
|
4 | # PLE1310
5 | "Hello World".strip("Hello")
| ^^^^^^^ PLE1310
6 |
7 | # PLE1310
|
bad_str_strip_call.py:8:21: PLE1310 String `strip` call contains duplicate characters
|
7 | # PLE1310
8 | "Hello World".strip(u"Hello")
| ^^^^^^^^ PLE1310
9 |
10 | # PLE1310
|
bad_str_strip_call.py:11:21: PLE1310 String `strip` call contains duplicate characters
|
10 | # PLE1310
11 | "Hello World".strip(r"Hello")
| ^^^^^^^^ PLE1310
12 |
13 | # PLE1310
|
bad_str_strip_call.py:14:21: PLE1310 String `strip` call contains duplicate characters
|
13 | # PLE1310
14 | "Hello World".strip("Hello\t")
| ^^^^^^^^^ PLE1310
15 |
16 | # PLE1310
|
bad_str_strip_call.py:17:21: PLE1310 String `strip` call contains duplicate characters
|
16 | # PLE1310
17 | "Hello World".strip(r"Hello\t")
| ^^^^^^^^^^ PLE1310
18 |
19 | # PLE1310
|
bad_str_strip_call.py:20:21: PLE1310 String `strip` call contains duplicate characters
|
19 | # PLE1310
20 | "Hello World".strip("Hello\\")
| ^^^^^^^^^ PLE1310
21 |
22 | # PLE1310
|
bad_str_strip_call.py:23:21: PLE1310 String `strip` call contains duplicate characters
|
22 | # PLE1310
23 | "Hello World".strip(r"Hello\\")
| ^^^^^^^^^^ PLE1310
24 |
25 | # PLE1310
|
bad_str_strip_call.py:26:21: PLE1310 String `strip` call contains duplicate characters
|
25 | # PLE1310
26 | "Hello World".strip("🤣🤣🤣🤣🙃👀😀")
| ^^^^^^^^^^^^^^^^ PLE1310
27 |
28 | # PLE1310
|
bad_str_strip_call.py:30:5: PLE1310 String `strip` call contains duplicate characters
|
28 | # PLE1310
29 | "Hello World".strip(
30 | / """
31 | | there are a lot of characters to strip
32 | | """
| |___^ PLE1310
33 | )
|
bad_str_strip_call.py:36:21: PLE1310 String `strip` call contains duplicate characters
|
35 | # PLE1310
36 | "Hello World".strip("can we get a long " \
| _____________________^
37 | | "string of characters to strip " \
38 | | "please?")
| |_____________________________^ PLE1310
39 |
40 | # PLE1310
|
bad_str_strip_call.py:42:5: PLE1310 String `strip` call contains duplicate characters
|
40 | # PLE1310
41 | "Hello World".strip(
42 | / "can we get a long "
43 | | "string of characters to strip "
44 | | "please?"
| |_____________^ PLE1310
45 | )
|
bad_str_strip_call.py:49:5: PLE1310 String `strip` call contains duplicate characters
|
47 | # PLE1310
48 | "Hello World".strip(
49 | / "can \t we get a long"
50 | | "string \t of characters to strip"
51 | | "please?"
| |_____________^ PLE1310
52 | )
|
bad_str_strip_call.py:61:11: PLE1310 String `strip` call contains duplicate characters
|
60 | # PLE1310
61 | u''.strip('http://')
| ^^^^^^^^^ PLE1310
62 |
63 | # PLE1310
|
bad_str_strip_call.py:64:12: PLE1310 String `lstrip` call contains duplicate characters (did you mean `removeprefix`?)
|
63 | # PLE1310
64 | u''.lstrip('http://')
| ^^^^^^^^^ PLE1310
65 |
66 | # PLE1310
|
bad_str_strip_call.py:67:12: PLE1310 String `rstrip` call contains duplicate characters (did you mean `removesuffix`?)
|
66 | # PLE1310
67 | b''.rstrip(b'http://')
| ^^^^^^^^^^ PLE1310
68 |
69 | # OK
|
bad_str_strip_call.py:79:10: PLE1310 String `strip` call contains duplicate characters
|
78 | # Errors: Multiple backslashes
79 | ''.strip('\\b\\x09')
| ^^^^^^^^^^ PLE1310
80 | ''.strip(r'\b\x09')
81 | ''.strip('\\\x5C')
|
bad_str_strip_call.py:80:10: PLE1310 String `strip` call contains duplicate characters
|
78 | # Errors: Multiple backslashes
79 | ''.strip('\\b\\x09')
80 | ''.strip(r'\b\x09')
| ^^^^^^^^^ PLE1310
81 | ''.strip('\\\x5C')
|
bad_str_strip_call.py:81:10: PLE1310 String `strip` call contains duplicate characters
|
79 | ''.strip('\\b\\x09')
80 | ''.strip(r'\b\x09')
81 | ''.strip('\\\x5C')
| ^^^^^^^^ PLE1310
82 |
83 | # Errors: Type inference
|
bad_str_strip_call.py:85:9: PLE1310 String `strip` call contains duplicate characters
|
83 | # Errors: Type inference
84 | b = b''
85 | b.strip(b'//')
| ^^^^^ PLE1310
86 |
87 | # Errors: Type inference (preview)
|
bad_str_strip_call.py:89:12: PLE1310 String `rstrip` call contains duplicate characters (did you mean `removesuffix`?)
|
87 | # Errors: Type inference (preview)
88 | foo: str = ""; bar: bytes = b""
89 | foo.rstrip("//")
| ^^^^ PLE1310
90 | bar.lstrip(b"//")
|
bad_str_strip_call.py:90:12: PLE1310 String `lstrip` call contains duplicate characters (did you mean `removeprefix`?)
|
88 | foo: str = ""; bar: bytes = b""
89 | foo.rstrip("//")
90 | bar.lstrip(b"//")
| ^^^^^ PLE1310
|

View File

@@ -1,455 +0,0 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
repeated_equality_comparison.py:2:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
1 | # Errors.
2 | foo == "a" or foo == "b"
| ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
3 |
4 | foo != "a" and foo != "b"
|
= help: Merge multiple comparisons
Unsafe fix
1 1 | # Errors.
2 |-foo == "a" or foo == "b"
2 |+foo in {"a", "b"}
3 3 |
4 4 | foo != "a" and foo != "b"
5 5 |
repeated_equality_comparison.py:4:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b"}`.
|
2 | foo == "a" or foo == "b"
3 |
4 | foo != "a" and foo != "b"
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
5 |
6 | foo == "a" or foo == "b" or foo == "c"
|
= help: Merge multiple comparisons
Unsafe fix
1 1 | # Errors.
2 2 | foo == "a" or foo == "b"
3 3 |
4 |-foo != "a" and foo != "b"
4 |+foo not in {"a", "b"}
5 5 |
6 6 | foo == "a" or foo == "b" or foo == "c"
7 7 |
repeated_equality_comparison.py:6:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
4 | foo != "a" and foo != "b"
5 |
6 | foo == "a" or foo == "b" or foo == "c"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
7 |
8 | foo != "a" and foo != "b" and foo != "c"
|
= help: Merge multiple comparisons
Unsafe fix
3 3 |
4 4 | foo != "a" and foo != "b"
5 5 |
6 |-foo == "a" or foo == "b" or foo == "c"
6 |+foo in {"a", "b", "c"}
7 7 |
8 8 | foo != "a" and foo != "b" and foo != "c"
9 9 |
repeated_equality_comparison.py:8:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
6 | foo == "a" or foo == "b" or foo == "c"
7 |
8 | foo != "a" and foo != "b" and foo != "c"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
9 |
10 | foo == a or foo == "b" or foo == 3 # Mixed types.
|
= help: Merge multiple comparisons
Unsafe fix
5 5 |
6 6 | foo == "a" or foo == "b" or foo == "c"
7 7 |
8 |-foo != "a" and foo != "b" and foo != "c"
8 |+foo not in {"a", "b", "c"}
9 9 |
10 10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 11 |
repeated_equality_comparison.py:10:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (a, "b", 3)`. Use a `set` if the elements are hashable.
|
8 | foo != "a" and foo != "b" and foo != "c"
9 |
10 | foo == a or foo == "b" or foo == 3 # Mixed types.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
11 |
12 | "a" == foo or "b" == foo or "c" == foo
|
= help: Merge multiple comparisons
Unsafe fix
7 7 |
8 8 | foo != "a" and foo != "b" and foo != "c"
9 9 |
10 |-foo == a or foo == "b" or foo == 3 # Mixed types.
10 |+foo in (a, "b", 3) # Mixed types.
11 11 |
12 12 | "a" == foo or "b" == foo or "c" == foo
13 13 |
repeated_equality_comparison.py:12:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 |
12 | "a" == foo or "b" == foo or "c" == foo
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
13 |
14 | "a" != foo and "b" != foo and "c" != foo
|
= help: Merge multiple comparisons
Unsafe fix
9 9 |
10 10 | foo == a or foo == "b" or foo == 3 # Mixed types.
11 11 |
12 |-"a" == foo or "b" == foo or "c" == foo
12 |+foo in {"a", "b", "c"}
13 13 |
14 14 | "a" != foo and "b" != foo and "c" != foo
15 15 |
repeated_equality_comparison.py:14:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
12 | "a" == foo or "b" == foo or "c" == foo
13 |
14 | "a" != foo and "b" != foo and "c" != foo
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
15 |
16 | "a" == foo or foo == "b" or "c" == foo
|
= help: Merge multiple comparisons
Unsafe fix
11 11 |
12 12 | "a" == foo or "b" == foo or "c" == foo
13 13 |
14 |-"a" != foo and "b" != foo and "c" != foo
14 |+foo not in {"a", "b", "c"}
15 15 |
16 16 | "a" == foo or foo == "b" or "c" == foo
17 17 |
repeated_equality_comparison.py:16:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
14 | "a" != foo and "b" != foo and "c" != foo
15 |
16 | "a" == foo or foo == "b" or "c" == foo
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
17 |
18 | foo == bar or baz == foo or qux == foo
|
= help: Merge multiple comparisons
Unsafe fix
13 13 |
14 14 | "a" != foo and "b" != foo and "c" != foo
15 15 |
16 |-"a" == foo or foo == "b" or "c" == foo
16 |+foo in {"a", "b", "c"}
17 17 |
18 18 | foo == bar or baz == foo or qux == foo
19 19 |
repeated_equality_comparison.py:18:1: PLR1714 [*] Consider merging multiple comparisons: `foo in (bar, baz, qux)`. Use a `set` if the elements are hashable.
|
16 | "a" == foo or foo == "b" or "c" == foo
17 |
18 | foo == bar or baz == foo or qux == foo
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
19 |
20 | foo == "a" or "b" == foo or foo == "c"
|
= help: Merge multiple comparisons
Unsafe fix
15 15 |
16 16 | "a" == foo or foo == "b" or "c" == foo
17 17 |
18 |-foo == bar or baz == foo or qux == foo
18 |+foo in (bar, baz, qux)
19 19 |
20 20 | foo == "a" or "b" == foo or foo == "c"
21 21 |
repeated_equality_comparison.py:20:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b", "c"}`.
|
18 | foo == bar or baz == foo or qux == foo
19 |
20 | foo == "a" or "b" == foo or foo == "c"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
21 |
22 | foo != "a" and "b" != foo and foo != "c"
|
= help: Merge multiple comparisons
Unsafe fix
17 17 |
18 18 | foo == bar or baz == foo or qux == foo
19 19 |
20 |-foo == "a" or "b" == foo or foo == "c"
20 |+foo in {"a", "b", "c"}
21 21 |
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
repeated_equality_comparison.py:22:1: PLR1714 [*] Consider merging multiple comparisons: `foo not in {"a", "b", "c"}`.
|
20 | foo == "a" or "b" == foo or foo == "c"
21 |
22 | foo != "a" and "b" != foo and foo != "c"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
23 |
24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
|
= help: Merge multiple comparisons
Unsafe fix
19 19 |
20 20 | foo == "a" or "b" == foo or foo == "c"
21 21 |
22 |-foo != "a" and "b" != foo and foo != "c"
22 |+foo not in {"a", "b", "c"}
23 23 |
24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 25 |
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
22 | foo != "a" and "b" != foo and foo != "c"
23 |
24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
25 |
26 | foo.bar == "a" or foo.bar == "b" # Attributes.
|
= help: Merge multiple comparisons
Unsafe fix
21 21 |
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
24 |+foo in {"a", "b"} or "c" == bar or "d" == bar # Multiple targets
25 25 |
26 26 | foo.bar == "a" or foo.bar == "b" # Attributes.
27 27 |
repeated_equality_comparison.py:24:1: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`.
|
22 | foo != "a" and "b" != foo and foo != "c"
23 |
24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
25 |
26 | foo.bar == "a" or foo.bar == "b" # Attributes.
|
= help: Merge multiple comparisons
Unsafe fix
21 21 |
22 22 | foo != "a" and "b" != foo and foo != "c"
23 23 |
24 |-foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
24 |+foo == "a" or foo == "b" or bar in {"c", "d"} # Multiple targets
25 25 |
26 26 | foo.bar == "a" or foo.bar == "b" # Attributes.
27 27 |
repeated_equality_comparison.py:26:1: PLR1714 [*] Consider merging multiple comparisons: `foo.bar in {"a", "b"}`.
|
24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 |
26 | foo.bar == "a" or foo.bar == "b" # Attributes.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
27 |
28 | # OK
|
= help: Merge multiple comparisons
Unsafe fix
23 23 |
24 24 | foo == "a" or foo == "b" or "c" == bar or "d" == bar # Multiple targets
25 25 |
26 |-foo.bar == "a" or foo.bar == "b" # Attributes.
26 |+foo.bar in {"a", "b"} # Attributes.
27 27 |
28 28 | # OK
29 29 | foo == "a" and foo == "b" and foo == "c" # `and` mixed with `==`.
repeated_equality_comparison.py:61:16: PLR1714 [*] Consider merging multiple comparisons: `bar in {"c", "d"}`.
|
59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets
60 |
61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
62 |
63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
|
= help: Merge multiple comparisons
Unsafe fix
58 58 |
59 59 | foo == "a" or "c" == bar or foo == "b" or "d" == bar # Multiple targets
60 60 |
61 |-foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
61 |+foo == "a" or (bar in {"c", "d"}) or foo == "b" # Multiple targets
62 62 |
63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 64 |
repeated_equality_comparison.py:63:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {"a", "b"}`.
|
61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 |
63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
64 |
65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
|
= help: Merge multiple comparisons
Unsafe fix
60 60 |
61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 62 |
63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
63 |+foo in {"a", "b"} or "c" != bar and "d" != bar # Multiple targets
64 64 |
65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
66 66 |
repeated_equality_comparison.py:63:29: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`.
|
61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 |
63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
64 |
65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
|
= help: Merge multiple comparisons
Unsafe fix
60 60 |
61 61 | foo == "a" or ("c" == bar or "d" == bar) or foo == "b" # Multiple targets
62 62 |
63 |-foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
63 |+foo == "a" or foo == "b" or bar not in {"c", "d"} # Multiple targets
64 64 |
65 65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
66 66 |
repeated_equality_comparison.py:65:16: PLR1714 [*] Consider merging multiple comparisons: `bar not in {"c", "d"}`.
|
63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 |
65 | foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
66 |
67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
|
= help: Merge multiple comparisons
Unsafe fix
62 62 |
63 63 | foo == "a" or foo == "b" or "c" != bar and "d" != bar # Multiple targets
64 64 |
65 |-foo == "a" or ("c" != bar and "d" != bar) or foo == "b" # Multiple targets
65 |+foo == "a" or (bar not in {"c", "d"}) or foo == "b" # Multiple targets
66 66 |
67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 68 |
repeated_equality_comparison.py:69:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {1, True}`.
|
67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 |
69 | foo == 1 or foo == True # Different types, same hashed value
| ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
70 |
71 | foo == 1 or foo == 1.0 # Different types, same hashed value
|
= help: Merge multiple comparisons
Unsafe fix
66 66 |
67 67 | foo == "a" and "c" != bar or foo == "b" and "d" != bar # Multiple targets
68 68 |
69 |-foo == 1 or foo == True # Different types, same hashed value
69 |+foo in {1, True} # Different types, same hashed value
70 70 |
71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 72 |
repeated_equality_comparison.py:71:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {1, 1.0}`.
|
69 | foo == 1 or foo == True # Different types, same hashed value
70 |
71 | foo == 1 or foo == 1.0 # Different types, same hashed value
| ^^^^^^^^^^^^^^^^^^^^^^ PLR1714
72 |
73 | foo == False or foo == 0 # Different types, same hashed value
|
= help: Merge multiple comparisons
Unsafe fix
68 68 |
69 69 | foo == 1 or foo == True # Different types, same hashed value
70 70 |
71 |-foo == 1 or foo == 1.0 # Different types, same hashed value
71 |+foo in {1, 1.0} # Different types, same hashed value
72 72 |
73 73 | foo == False or foo == 0 # Different types, same hashed value
74 74 |
repeated_equality_comparison.py:73:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {False, 0}`.
|
71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 |
73 | foo == False or foo == 0 # Different types, same hashed value
| ^^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
74 |
75 | foo == 0.0 or foo == 0j # Different types, same hashed value
|
= help: Merge multiple comparisons
Unsafe fix
70 70 |
71 71 | foo == 1 or foo == 1.0 # Different types, same hashed value
72 72 |
73 |-foo == False or foo == 0 # Different types, same hashed value
73 |+foo in {False, 0} # Different types, same hashed value
74 74 |
75 75 | foo == 0.0 or foo == 0j # Different types, same hashed value
repeated_equality_comparison.py:75:1: PLR1714 [*] Consider merging multiple comparisons: `foo in {0.0, 0j}`.
|
73 | foo == False or foo == 0 # Different types, same hashed value
74 |
75 | foo == 0.0 or foo == 0j # Different types, same hashed value
| ^^^^^^^^^^^^^^^^^^^^^^^ PLR1714
|
= help: Merge multiple comparisons
Unsafe fix
72 72 |
73 73 | foo == False or foo == 0 # Different types, same hashed value
74 74 |
75 |-foo == 0.0 or foo == 0j # Different types, same hashed value
75 |+foo in {0.0, 0j} # Different types, same hashed value

View File

@@ -1,37 +0,0 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
bad_staticmethod_argument.py:3:13: PLW0211 First argument of a static method should not be named `self`
|
1 | class Wolf:
2 | @staticmethod
3 | def eat(self): # [bad-staticmethod-argument]
| ^^^^ PLW0211
4 | pass
|
bad_staticmethod_argument.py:15:13: PLW0211 First argument of a static method should not be named `cls`
|
13 | class Sheep:
14 | @staticmethod
15 | def eat(cls, x, y, z): # [bad-staticmethod-argument]
| ^^^ PLW0211
16 | pass
|
bad_staticmethod_argument.py:19:15: PLW0211 First argument of a static method should not be named `self`
|
18 | @staticmethod
19 | def sleep(self, x, y, z): # [bad-staticmethod-argument]
| ^^^^ PLW0211
20 | pass
|
bad_staticmethod_argument.py:55:17: PLW0211 First argument of a static method should not be named `self`
|
53 | # `self` but not with `cls` as first argument - see above).
54 | class Foo:
55 | def __new__(self, x, y, z): # [bad-staticmethod-argument]
| ^^^^ PLW0211
56 | pass
|

View File

@@ -1,62 +0,0 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
invalid_envvar_default.py:3:29: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
1 | import os
2 |
3 | tempVar = os.getenv("TEST", 12) # [invalid-envvar-default]
| ^^ PLW1508
4 | goodVar = os.getenv("TESTING", None)
5 | dictVarBad = os.getenv("AAA", {"a", 7}) # [invalid-envvar-default]
|
invalid_envvar_default.py:5:31: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
3 | tempVar = os.getenv("TEST", 12) # [invalid-envvar-default]
4 | goodVar = os.getenv("TESTING", None)
5 | dictVarBad = os.getenv("AAA", {"a", 7}) # [invalid-envvar-default]
| ^^^^^^^^ PLW1508
6 | print(os.getenv("TEST", False)) # [invalid-envvar-default]
7 | os.getenv("AA", "GOOD")
|
invalid_envvar_default.py:6:25: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
4 | goodVar = os.getenv("TESTING", None)
5 | dictVarBad = os.getenv("AAA", {"a", 7}) # [invalid-envvar-default]
6 | print(os.getenv("TEST", False)) # [invalid-envvar-default]
| ^^^^^ PLW1508
7 | os.getenv("AA", "GOOD")
8 | os.getenv("AA", f"GOOD")
|
invalid_envvar_default.py:10:17: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
8 | os.getenv("AA", f"GOOD")
9 | os.getenv("AA", "GOOD" + "BAR")
10 | os.getenv("AA", "GOOD" + 1)
| ^^^^^^^^^^ PLW1508
11 | os.getenv("AA", "GOOD %s" % "BAR")
12 | os.getenv("B", Z)
|
invalid_envvar_default.py:14:17: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
12 | os.getenv("B", Z)
13 | os.getenv("AA", "GOOD" if Z else "BAR")
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
| ^^^^^^^^^^^^^^^^^ PLW1508
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
16 | os.environ.get("TEST", "AA" * 12)
|
invalid_envvar_default.py:15:24: PLW1508 Invalid type for environment variable default; expected `str` or `None`
|
13 | os.getenv("AA", "GOOD" if Z else "BAR")
14 | os.getenv("AA", 1 if Z else "BAR") # [invalid-envvar-default]
15 | os.environ.get("TEST", 12) # [invalid-envvar-default]
| ^^ PLW1508
16 | os.environ.get("TEST", "AA" * 12)
17 | os.environ.get("TEST", 13 * "AA")
|

View File

@@ -119,25 +119,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::RedundantOpenModes, Path::new("UP015.py"))]
#[test_case(Rule::RedundantOpenModes, Path::new("UP015_1.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pyupgrade").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn up007_preview() -> Result<()> {
let diagnostics = test_path(
@@ -285,7 +266,6 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/UP044.py"),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
unresolved_target_version: PythonVersion::PY311,
..settings::LinterSettings::for_rule(Rule::NonPEP646Unpack)
},

View File

@@ -11,6 +11,7 @@ pub(crate) use format_literals::*;
pub(crate) use lru_cache_with_maxsize_none::*;
pub(crate) use lru_cache_without_parameters::*;
pub(crate) use native_literals::*;
pub(crate) use non_pep646_unpack::*;
pub(crate) use open_alias::*;
pub(crate) use os_error_alias::*;
pub(crate) use outdated_version_block::*;
@@ -36,7 +37,6 @@ pub(crate) use unpacked_list_comprehension::*;
pub(crate) use use_pep585_annotation::*;
pub(crate) use use_pep604_annotation::*;
pub(crate) use use_pep604_isinstance::*;
pub(crate) use use_pep646_unpack::*;
pub(crate) use useless_metaclass_type::*;
pub(crate) use useless_object_inheritance::*;
pub(crate) use yield_in_for_loop::*;
@@ -54,6 +54,7 @@ mod format_literals;
mod lru_cache_with_maxsize_none;
mod lru_cache_without_parameters;
mod native_literals;
mod non_pep646_unpack;
mod open_alias;
mod os_error_alias;
mod outdated_version_block;
@@ -79,7 +80,6 @@ mod unpacked_list_comprehension;
mod use_pep585_annotation;
mod use_pep604_annotation;
mod use_pep604_isinstance;
mod use_pep646_unpack;
mod useless_metaclass_type;
mod useless_object_inheritance;
mod yield_in_for_loop;

View File

@@ -91,17 +91,11 @@ fn create_diagnostic(
mode: OpenMode,
checker: &Checker,
) -> Diagnostic {
let range = if checker.settings.preview.is_enabled() {
mode_arg.range()
} else {
call.range
};
let mut diagnostic = Diagnostic::new(
RedundantOpenModes {
replacement: mode.to_string(),
},
range,
mode_arg.range(),
);
if mode.is_empty() {

View File

@@ -33,6 +33,12 @@ impl CallKind {
}
}
/// ## Deprecation
/// This rule was deprecated as using [PEP 604] syntax in `isinstance` and `issubclass` calls
/// isn't recommended practice, and it incorrectly suggests that other typing syntaxes like [PEP 695]
/// would be supported by `isinstance` and `issubclass`. Using the [PEP 604] syntax
/// is also slightly slower.
///
/// ## What it does
/// Checks for uses of `isinstance` and `issubclass` that take a tuple
/// of types for comparison.
@@ -64,6 +70,7 @@ impl CallKind {
/// - [Python documentation: `issubclass`](https://docs.python.org/3/library/functions.html#issubclass)
///
/// [PEP 604]: https://peps.python.org/pep-0604/
/// [PEP 695]: https://peps.python.org/pep-0695/
#[derive(ViolationMetadata)]
pub(crate) struct NonPEP604Isinstance {
kind: CallKind,

View File

@@ -1,10 +1,10 @@
---
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
---
UP015.py:1:1: UP015 [*] Unnecessary mode argument
UP015.py:1:13: UP015 [*] Unnecessary mode argument
|
1 | open("foo", "U")
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
2 | open("foo", "Ur")
3 | open("foo", "Ub")
|
@@ -17,11 +17,11 @@ UP015.py:1:1: UP015 [*] Unnecessary mode argument
3 3 | open("foo", "Ub")
4 4 | open("foo", "rUb")
UP015.py:2:1: UP015 [*] Unnecessary mode argument
UP015.py:2:13: UP015 [*] Unnecessary mode argument
|
1 | open("foo", "U")
2 | open("foo", "Ur")
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
3 | open("foo", "Ub")
4 | open("foo", "rUb")
|
@@ -35,12 +35,12 @@ UP015.py:2:1: UP015 [*] Unnecessary mode argument
4 4 | open("foo", "rUb")
5 5 | open("foo", "r")
UP015.py:3:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:3:13: UP015 [*] Unnecessary modes, use `rb`
|
1 | open("foo", "U")
2 | open("foo", "Ur")
3 | open("foo", "Ub")
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
4 | open("foo", "rUb")
5 | open("foo", "r")
|
@@ -55,12 +55,12 @@ UP015.py:3:1: UP015 [*] Unnecessary modes, use `rb`
5 5 | open("foo", "r")
6 6 | open("foo", "rt")
UP015.py:4:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:4:13: UP015 [*] Unnecessary modes, use `rb`
|
2 | open("foo", "Ur")
3 | open("foo", "Ub")
4 | open("foo", "rUb")
| ^^^^^^^^^^^^^^^^^^ UP015
| ^^^^^ UP015
5 | open("foo", "r")
6 | open("foo", "rt")
|
@@ -76,12 +76,12 @@ UP015.py:4:1: UP015 [*] Unnecessary modes, use `rb`
6 6 | open("foo", "rt")
7 7 | open("f", "r", encoding="UTF-8")
UP015.py:5:1: UP015 [*] Unnecessary mode argument
UP015.py:5:13: UP015 [*] Unnecessary mode argument
|
3 | open("foo", "Ub")
4 | open("foo", "rUb")
5 | open("foo", "r")
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
|
@@ -97,12 +97,12 @@ UP015.py:5:1: UP015 [*] Unnecessary mode argument
7 7 | open("f", "r", encoding="UTF-8")
8 8 | open("f", "wt")
UP015.py:6:1: UP015 [*] Unnecessary mode argument
UP015.py:6:13: UP015 [*] Unnecessary mode argument
|
4 | open("foo", "rUb")
5 | open("foo", "r")
6 | open("foo", "rt")
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
|
@@ -118,12 +118,12 @@ UP015.py:6:1: UP015 [*] Unnecessary mode argument
8 8 | open("f", "wt")
9 9 | open("f", "tw")
UP015.py:7:1: UP015 [*] Unnecessary mode argument
UP015.py:7:11: UP015 [*] Unnecessary mode argument
|
5 | open("foo", "r")
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
8 | open("f", "wt")
9 | open("f", "tw")
|
@@ -139,12 +139,12 @@ UP015.py:7:1: UP015 [*] Unnecessary mode argument
9 9 | open("f", "tw")
10 10 |
UP015.py:8:1: UP015 [*] Unnecessary modes, use `w`
UP015.py:8:11: UP015 [*] Unnecessary modes, use `w`
|
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
| ^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
9 | open("f", "tw")
|
= help: Replace with `w`
@@ -159,12 +159,12 @@ UP015.py:8:1: UP015 [*] Unnecessary modes, use `w`
10 10 |
11 11 | with open("foo", "U") as f:
UP015.py:9:1: UP015 [*] Unnecessary modes, use `w`
UP015.py:9:11: UP015 [*] Unnecessary modes, use `w`
|
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
9 | open("f", "tw")
| ^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
10 |
11 | with open("foo", "U") as f:
|
@@ -180,12 +180,12 @@ UP015.py:9:1: UP015 [*] Unnecessary modes, use `w`
11 11 | with open("foo", "U") as f:
12 12 | pass
UP015.py:11:6: UP015 [*] Unnecessary mode argument
UP015.py:11:18: UP015 [*] Unnecessary mode argument
|
9 | open("f", "tw")
10 |
11 | with open("foo", "U") as f:
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
12 | pass
13 | with open("foo", "Ur") as f:
|
@@ -201,12 +201,12 @@ UP015.py:11:6: UP015 [*] Unnecessary mode argument
13 13 | with open("foo", "Ur") as f:
14 14 | pass
UP015.py:13:6: UP015 [*] Unnecessary mode argument
UP015.py:13:18: UP015 [*] Unnecessary mode argument
|
11 | with open("foo", "U") as f:
12 | pass
13 | with open("foo", "Ur") as f:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
14 | pass
15 | with open("foo", "Ub") as f:
|
@@ -222,12 +222,12 @@ UP015.py:13:6: UP015 [*] Unnecessary mode argument
15 15 | with open("foo", "Ub") as f:
16 16 | pass
UP015.py:15:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:15:18: UP015 [*] Unnecessary modes, use `rb`
|
13 | with open("foo", "Ur") as f:
14 | pass
15 | with open("foo", "Ub") as f:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
16 | pass
17 | with open("foo", "rUb") as f:
|
@@ -243,12 +243,12 @@ UP015.py:15:6: UP015 [*] Unnecessary modes, use `rb`
17 17 | with open("foo", "rUb") as f:
18 18 | pass
UP015.py:17:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:17:18: UP015 [*] Unnecessary modes, use `rb`
|
15 | with open("foo", "Ub") as f:
16 | pass
17 | with open("foo", "rUb") as f:
| ^^^^^^^^^^^^^^^^^^ UP015
| ^^^^^ UP015
18 | pass
19 | with open("foo", "r") as f:
|
@@ -264,12 +264,12 @@ UP015.py:17:6: UP015 [*] Unnecessary modes, use `rb`
19 19 | with open("foo", "r") as f:
20 20 | pass
UP015.py:19:6: UP015 [*] Unnecessary mode argument
UP015.py:19:18: UP015 [*] Unnecessary mode argument
|
17 | with open("foo", "rUb") as f:
18 | pass
19 | with open("foo", "r") as f:
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
20 | pass
21 | with open("foo", "rt") as f:
|
@@ -285,12 +285,12 @@ UP015.py:19:6: UP015 [*] Unnecessary mode argument
21 21 | with open("foo", "rt") as f:
22 22 | pass
UP015.py:21:6: UP015 [*] Unnecessary mode argument
UP015.py:21:18: UP015 [*] Unnecessary mode argument
|
19 | with open("foo", "r") as f:
20 | pass
21 | with open("foo", "rt") as f:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
22 | pass
23 | with open("foo", "r", encoding="UTF-8") as f:
|
@@ -306,12 +306,12 @@ UP015.py:21:6: UP015 [*] Unnecessary mode argument
23 23 | with open("foo", "r", encoding="UTF-8") as f:
24 24 | pass
UP015.py:23:6: UP015 [*] Unnecessary mode argument
UP015.py:23:18: UP015 [*] Unnecessary mode argument
|
21 | with open("foo", "rt") as f:
22 | pass
23 | with open("foo", "r", encoding="UTF-8") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
24 | pass
25 | with open("foo", "wt") as f:
|
@@ -327,12 +327,12 @@ UP015.py:23:6: UP015 [*] Unnecessary mode argument
25 25 | with open("foo", "wt") as f:
26 26 | pass
UP015.py:25:6: UP015 [*] Unnecessary modes, use `w`
UP015.py:25:18: UP015 [*] Unnecessary modes, use `w`
|
23 | with open("foo", "r", encoding="UTF-8") as f:
24 | pass
25 | with open("foo", "wt") as f:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
26 | pass
|
= help: Replace with `w`
@@ -347,12 +347,12 @@ UP015.py:25:6: UP015 [*] Unnecessary modes, use `w`
27 27 |
28 28 | open(f("a", "b", "c"), "U")
UP015.py:28:1: UP015 [*] Unnecessary mode argument
UP015.py:28:24: UP015 [*] Unnecessary mode argument
|
26 | pass
27 |
28 | open(f("a", "b", "c"), "U")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
29 | open(f("a", "b", "c"), "Ub")
|
= help: Remove mode argument
@@ -367,11 +367,11 @@ UP015.py:28:1: UP015 [*] Unnecessary mode argument
30 30 |
31 31 | with open(f("a", "b", "c"), "U") as f:
UP015.py:29:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:29:24: UP015 [*] Unnecessary modes, use `rb`
|
28 | open(f("a", "b", "c"), "U")
29 | open(f("a", "b", "c"), "Ub")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
30 |
31 | with open(f("a", "b", "c"), "U") as f:
|
@@ -387,12 +387,12 @@ UP015.py:29:1: UP015 [*] Unnecessary modes, use `rb`
31 31 | with open(f("a", "b", "c"), "U") as f:
32 32 | pass
UP015.py:31:6: UP015 [*] Unnecessary mode argument
UP015.py:31:29: UP015 [*] Unnecessary mode argument
|
29 | open(f("a", "b", "c"), "Ub")
30 |
31 | with open(f("a", "b", "c"), "U") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
32 | pass
33 | with open(f("a", "b", "c"), "Ub") as f:
|
@@ -408,12 +408,12 @@ UP015.py:31:6: UP015 [*] Unnecessary mode argument
33 33 | with open(f("a", "b", "c"), "Ub") as f:
34 34 | pass
UP015.py:33:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:33:29: UP015 [*] Unnecessary modes, use `rb`
|
31 | with open(f("a", "b", "c"), "U") as f:
32 | pass
33 | with open(f("a", "b", "c"), "Ub") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
34 | pass
|
= help: Replace with `rb`
@@ -428,12 +428,12 @@ UP015.py:33:6: UP015 [*] Unnecessary modes, use `rb`
35 35 |
36 36 | with open("foo", "U") as fa, open("bar", "U") as fb:
UP015.py:36:6: UP015 [*] Unnecessary mode argument
UP015.py:36:18: UP015 [*] Unnecessary mode argument
|
34 | pass
35 |
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
|
@@ -449,12 +449,12 @@ UP015.py:36:6: UP015 [*] Unnecessary mode argument
38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
39 39 | pass
UP015.py:36:30: UP015 [*] Unnecessary mode argument
UP015.py:36:42: UP015 [*] Unnecessary mode argument
|
34 | pass
35 |
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
|
@@ -470,12 +470,12 @@ UP015.py:36:30: UP015 [*] Unnecessary mode argument
38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
39 39 | pass
UP015.py:38:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:38:18: UP015 [*] Unnecessary modes, use `rb`
|
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
39 | pass
|
= help: Replace with `rb`
@@ -490,12 +490,12 @@ UP015.py:38:6: UP015 [*] Unnecessary modes, use `rb`
40 40 |
41 41 | open("foo", mode="U")
UP015.py:38:31: UP015 [*] Unnecessary modes, use `rb`
UP015.py:38:43: UP015 [*] Unnecessary modes, use `rb`
|
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
| ^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
39 | pass
|
= help: Replace with `rb`
@@ -510,12 +510,12 @@ UP015.py:38:31: UP015 [*] Unnecessary modes, use `rb`
40 40 |
41 41 | open("foo", mode="U")
UP015.py:41:1: UP015 [*] Unnecessary mode argument
UP015.py:41:18: UP015 [*] Unnecessary mode argument
|
39 | pass
40 |
41 | open("foo", mode="U")
| ^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
42 | open(name="foo", mode="U")
43 | open(mode="U", name="foo")
|
@@ -531,11 +531,11 @@ UP015.py:41:1: UP015 [*] Unnecessary mode argument
43 43 | open(mode="U", name="foo")
44 44 |
UP015.py:42:1: UP015 [*] Unnecessary mode argument
UP015.py:42:23: UP015 [*] Unnecessary mode argument
|
41 | open("foo", mode="U")
42 | open(name="foo", mode="U")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
43 | open(mode="U", name="foo")
|
= help: Remove mode argument
@@ -550,12 +550,12 @@ UP015.py:42:1: UP015 [*] Unnecessary mode argument
44 44 |
45 45 | with open("foo", mode="U") as f:
UP015.py:43:1: UP015 [*] Unnecessary mode argument
UP015.py:43:11: UP015 [*] Unnecessary mode argument
|
41 | open("foo", mode="U")
42 | open(name="foo", mode="U")
43 | open(mode="U", name="foo")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
44 |
45 | with open("foo", mode="U") as f:
|
@@ -571,12 +571,12 @@ UP015.py:43:1: UP015 [*] Unnecessary mode argument
45 45 | with open("foo", mode="U") as f:
46 46 | pass
UP015.py:45:6: UP015 [*] Unnecessary mode argument
UP015.py:45:23: UP015 [*] Unnecessary mode argument
|
43 | open(mode="U", name="foo")
44 |
45 | with open("foo", mode="U") as f:
| ^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
46 | pass
47 | with open(name="foo", mode="U") as f:
|
@@ -592,12 +592,12 @@ UP015.py:45:6: UP015 [*] Unnecessary mode argument
47 47 | with open(name="foo", mode="U") as f:
48 48 | pass
UP015.py:47:6: UP015 [*] Unnecessary mode argument
UP015.py:47:28: UP015 [*] Unnecessary mode argument
|
45 | with open("foo", mode="U") as f:
46 | pass
47 | with open(name="foo", mode="U") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
48 | pass
49 | with open(mode="U", name="foo") as f:
|
@@ -613,12 +613,12 @@ UP015.py:47:6: UP015 [*] Unnecessary mode argument
49 49 | with open(mode="U", name="foo") as f:
50 50 | pass
UP015.py:49:6: UP015 [*] Unnecessary mode argument
UP015.py:49:16: UP015 [*] Unnecessary mode argument
|
47 | with open(name="foo", mode="U") as f:
48 | pass
49 | with open(mode="U", name="foo") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
50 | pass
|
= help: Remove mode argument
@@ -633,12 +633,12 @@ UP015.py:49:6: UP015 [*] Unnecessary mode argument
51 51 |
52 52 | open("foo", mode="Ub")
UP015.py:52:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:52:18: UP015 [*] Unnecessary modes, use `rb`
|
50 | pass
51 |
52 | open("foo", mode="Ub")
| ^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
53 | open(name="foo", mode="Ub")
54 | open(mode="Ub", name="foo")
|
@@ -654,11 +654,11 @@ UP015.py:52:1: UP015 [*] Unnecessary modes, use `rb`
54 54 | open(mode="Ub", name="foo")
55 55 |
UP015.py:53:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:53:23: UP015 [*] Unnecessary modes, use `rb`
|
52 | open("foo", mode="Ub")
53 | open(name="foo", mode="Ub")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
54 | open(mode="Ub", name="foo")
|
= help: Replace with `rb`
@@ -673,12 +673,12 @@ UP015.py:53:1: UP015 [*] Unnecessary modes, use `rb`
55 55 |
56 56 | with open("foo", mode="Ub") as f:
UP015.py:54:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:54:11: UP015 [*] Unnecessary modes, use `rb`
|
52 | open("foo", mode="Ub")
53 | open(name="foo", mode="Ub")
54 | open(mode="Ub", name="foo")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
55 |
56 | with open("foo", mode="Ub") as f:
|
@@ -694,12 +694,12 @@ UP015.py:54:1: UP015 [*] Unnecessary modes, use `rb`
56 56 | with open("foo", mode="Ub") as f:
57 57 | pass
UP015.py:56:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:56:23: UP015 [*] Unnecessary modes, use `rb`
|
54 | open(mode="Ub", name="foo")
55 |
56 | with open("foo", mode="Ub") as f:
| ^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
57 | pass
58 | with open(name="foo", mode="Ub") as f:
|
@@ -715,12 +715,12 @@ UP015.py:56:6: UP015 [*] Unnecessary modes, use `rb`
58 58 | with open(name="foo", mode="Ub") as f:
59 59 | pass
UP015.py:58:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:58:28: UP015 [*] Unnecessary modes, use `rb`
|
56 | with open("foo", mode="Ub") as f:
57 | pass
58 | with open(name="foo", mode="Ub") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
59 | pass
60 | with open(mode="Ub", name="foo") as f:
|
@@ -736,12 +736,12 @@ UP015.py:58:6: UP015 [*] Unnecessary modes, use `rb`
60 60 | with open(mode="Ub", name="foo") as f:
61 61 | pass
UP015.py:60:6: UP015 [*] Unnecessary modes, use `rb`
UP015.py:60:16: UP015 [*] Unnecessary modes, use `rb`
|
58 | with open(name="foo", mode="Ub") as f:
59 | pass
60 | with open(mode="Ub", name="foo") as f:
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
61 | pass
|
= help: Replace with `rb`
@@ -756,12 +756,12 @@ UP015.py:60:6: UP015 [*] Unnecessary modes, use `rb`
62 62 |
63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:63:1: UP015 [*] Unnecessary mode argument
UP015.py:63:23: UP015 [*] Unnecessary mode argument
|
61 | pass
62 |
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
|
@@ -777,11 +777,11 @@ UP015.py:63:1: UP015 [*] Unnecessary mode argument
65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:64:1: UP015 [*] Unnecessary mode argument
UP015.py:64:106: UP015 [*] Unnecessary mode argument
|
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
@@ -797,12 +797,12 @@ UP015.py:64:1: UP015 [*] Unnecessary mode argument
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
UP015.py:65:1: UP015 [*] Unnecessary mode argument
UP015.py:65:65: UP015 [*] Unnecessary mode argument
|
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Remove mode argument
@@ -817,12 +817,12 @@ UP015.py:65:1: UP015 [*] Unnecessary mode argument
67 67 |
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:66:1: UP015 [*] Unnecessary mode argument
UP015.py:66:11: UP015 [*] Unnecessary mode argument
|
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
67 |
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
@@ -838,12 +838,12 @@ UP015.py:66:1: UP015 [*] Unnecessary mode argument
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
UP015.py:68:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:68:23: UP015 [*] Unnecessary modes, use `rb`
|
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 |
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
|
@@ -859,11 +859,11 @@ UP015.py:68:1: UP015 [*] Unnecessary modes, use `rb`
70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:69:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:69:106: UP015 [*] Unnecessary modes, use `rb`
|
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
@@ -879,12 +879,12 @@ UP015.py:69:1: UP015 [*] Unnecessary modes, use `rb`
71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
72 72 |
UP015.py:70:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:70:65: UP015 [*] Unnecessary modes, use `rb`
|
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Replace with `rb`
@@ -899,12 +899,12 @@ UP015.py:70:1: UP015 [*] Unnecessary modes, use `rb`
72 72 |
73 73 | import aiofiles
UP015.py:71:1: UP015 [*] Unnecessary modes, use `rb`
UP015.py:71:11: UP015 [*] Unnecessary modes, use `rb`
|
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^^ UP015
72 |
73 | import aiofiles
|
@@ -920,12 +920,12 @@ UP015.py:71:1: UP015 [*] Unnecessary modes, use `rb`
73 73 | import aiofiles
74 74 |
UP015.py:75:1: UP015 [*] Unnecessary mode argument
UP015.py:75:22: UP015 [*] Unnecessary mode argument
|
73 | import aiofiles
74 |
75 | aiofiles.open("foo", "U")
| ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
76 | aiofiles.open("foo", "r")
77 | aiofiles.open("foo", mode="r")
|
@@ -941,11 +941,11 @@ UP015.py:75:1: UP015 [*] Unnecessary mode argument
77 77 | aiofiles.open("foo", mode="r")
78 78 |
UP015.py:76:1: UP015 [*] Unnecessary mode argument
UP015.py:76:22: UP015 [*] Unnecessary mode argument
|
75 | aiofiles.open("foo", "U")
76 | aiofiles.open("foo", "r")
| ^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
77 | aiofiles.open("foo", mode="r")
|
= help: Remove mode argument
@@ -960,12 +960,12 @@ UP015.py:76:1: UP015 [*] Unnecessary mode argument
78 78 |
79 79 | open("foo", "r+")
UP015.py:77:1: UP015 [*] Unnecessary mode argument
UP015.py:77:27: UP015 [*] Unnecessary mode argument
|
75 | aiofiles.open("foo", "U")
76 | aiofiles.open("foo", "r")
77 | aiofiles.open("foo", mode="r")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
78 |
79 | open("foo", "r+")
|

View File

@@ -1,12 +1,12 @@
---
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
---
UP015_1.py:3:5: UP015 [*] Unnecessary mode argument
UP015_1.py:3:17: UP015 [*] Unnecessary mode argument
|
1 | # Not a valid type annotation but this test shouldn't result in a panic.
2 | # Refer: https://github.com/astral-sh/ruff/issues/11736
3 | x: 'open("foo", "r")'
| ^^^^^^^^^^^^^^^^ UP015
| ^^^ UP015
|
= help: Remove mode argument

View File

@@ -1,982 +0,0 @@
---
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
---
UP015.py:1:13: UP015 [*] Unnecessary mode argument
|
1 | open("foo", "U")
| ^^^ UP015
2 | open("foo", "Ur")
3 | open("foo", "Ub")
|
= help: Remove mode argument
Safe fix
1 |-open("foo", "U")
1 |+open("foo")
2 2 | open("foo", "Ur")
3 3 | open("foo", "Ub")
4 4 | open("foo", "rUb")
UP015.py:2:13: UP015 [*] Unnecessary mode argument
|
1 | open("foo", "U")
2 | open("foo", "Ur")
| ^^^^ UP015
3 | open("foo", "Ub")
4 | open("foo", "rUb")
|
= help: Remove mode argument
Safe fix
1 1 | open("foo", "U")
2 |-open("foo", "Ur")
2 |+open("foo")
3 3 | open("foo", "Ub")
4 4 | open("foo", "rUb")
5 5 | open("foo", "r")
UP015.py:3:13: UP015 [*] Unnecessary modes, use `rb`
|
1 | open("foo", "U")
2 | open("foo", "Ur")
3 | open("foo", "Ub")
| ^^^^ UP015
4 | open("foo", "rUb")
5 | open("foo", "r")
|
= help: Replace with `rb`
Safe fix
1 1 | open("foo", "U")
2 2 | open("foo", "Ur")
3 |-open("foo", "Ub")
3 |+open("foo", "rb")
4 4 | open("foo", "rUb")
5 5 | open("foo", "r")
6 6 | open("foo", "rt")
UP015.py:4:13: UP015 [*] Unnecessary modes, use `rb`
|
2 | open("foo", "Ur")
3 | open("foo", "Ub")
4 | open("foo", "rUb")
| ^^^^^ UP015
5 | open("foo", "r")
6 | open("foo", "rt")
|
= help: Replace with `rb`
Safe fix
1 1 | open("foo", "U")
2 2 | open("foo", "Ur")
3 3 | open("foo", "Ub")
4 |-open("foo", "rUb")
4 |+open("foo", "rb")
5 5 | open("foo", "r")
6 6 | open("foo", "rt")
7 7 | open("f", "r", encoding="UTF-8")
UP015.py:5:13: UP015 [*] Unnecessary mode argument
|
3 | open("foo", "Ub")
4 | open("foo", "rUb")
5 | open("foo", "r")
| ^^^ UP015
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
|
= help: Remove mode argument
Safe fix
2 2 | open("foo", "Ur")
3 3 | open("foo", "Ub")
4 4 | open("foo", "rUb")
5 |-open("foo", "r")
5 |+open("foo")
6 6 | open("foo", "rt")
7 7 | open("f", "r", encoding="UTF-8")
8 8 | open("f", "wt")
UP015.py:6:13: UP015 [*] Unnecessary mode argument
|
4 | open("foo", "rUb")
5 | open("foo", "r")
6 | open("foo", "rt")
| ^^^^ UP015
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
|
= help: Remove mode argument
Safe fix
3 3 | open("foo", "Ub")
4 4 | open("foo", "rUb")
5 5 | open("foo", "r")
6 |-open("foo", "rt")
6 |+open("foo")
7 7 | open("f", "r", encoding="UTF-8")
8 8 | open("f", "wt")
9 9 | open("f", "tw")
UP015.py:7:11: UP015 [*] Unnecessary mode argument
|
5 | open("foo", "r")
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
| ^^^ UP015
8 | open("f", "wt")
9 | open("f", "tw")
|
= help: Remove mode argument
Safe fix
4 4 | open("foo", "rUb")
5 5 | open("foo", "r")
6 6 | open("foo", "rt")
7 |-open("f", "r", encoding="UTF-8")
7 |+open("f", encoding="UTF-8")
8 8 | open("f", "wt")
9 9 | open("f", "tw")
10 10 |
UP015.py:8:11: UP015 [*] Unnecessary modes, use `w`
|
6 | open("foo", "rt")
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
| ^^^^ UP015
9 | open("f", "tw")
|
= help: Replace with `w`
Safe fix
5 5 | open("foo", "r")
6 6 | open("foo", "rt")
7 7 | open("f", "r", encoding="UTF-8")
8 |-open("f", "wt")
8 |+open("f", "w")
9 9 | open("f", "tw")
10 10 |
11 11 | with open("foo", "U") as f:
UP015.py:9:11: UP015 [*] Unnecessary modes, use `w`
|
7 | open("f", "r", encoding="UTF-8")
8 | open("f", "wt")
9 | open("f", "tw")
| ^^^^ UP015
10 |
11 | with open("foo", "U") as f:
|
= help: Replace with `w`
Safe fix
6 6 | open("foo", "rt")
7 7 | open("f", "r", encoding="UTF-8")
8 8 | open("f", "wt")
9 |-open("f", "tw")
9 |+open("f", "w")
10 10 |
11 11 | with open("foo", "U") as f:
12 12 | pass
UP015.py:11:18: UP015 [*] Unnecessary mode argument
|
9 | open("f", "tw")
10 |
11 | with open("foo", "U") as f:
| ^^^ UP015
12 | pass
13 | with open("foo", "Ur") as f:
|
= help: Remove mode argument
Safe fix
8 8 | open("f", "wt")
9 9 | open("f", "tw")
10 10 |
11 |-with open("foo", "U") as f:
11 |+with open("foo") as f:
12 12 | pass
13 13 | with open("foo", "Ur") as f:
14 14 | pass
UP015.py:13:18: UP015 [*] Unnecessary mode argument
|
11 | with open("foo", "U") as f:
12 | pass
13 | with open("foo", "Ur") as f:
| ^^^^ UP015
14 | pass
15 | with open("foo", "Ub") as f:
|
= help: Remove mode argument
Safe fix
10 10 |
11 11 | with open("foo", "U") as f:
12 12 | pass
13 |-with open("foo", "Ur") as f:
13 |+with open("foo") as f:
14 14 | pass
15 15 | with open("foo", "Ub") as f:
16 16 | pass
UP015.py:15:18: UP015 [*] Unnecessary modes, use `rb`
|
13 | with open("foo", "Ur") as f:
14 | pass
15 | with open("foo", "Ub") as f:
| ^^^^ UP015
16 | pass
17 | with open("foo", "rUb") as f:
|
= help: Replace with `rb`
Safe fix
12 12 | pass
13 13 | with open("foo", "Ur") as f:
14 14 | pass
15 |-with open("foo", "Ub") as f:
15 |+with open("foo", "rb") as f:
16 16 | pass
17 17 | with open("foo", "rUb") as f:
18 18 | pass
UP015.py:17:18: UP015 [*] Unnecessary modes, use `rb`
|
15 | with open("foo", "Ub") as f:
16 | pass
17 | with open("foo", "rUb") as f:
| ^^^^^ UP015
18 | pass
19 | with open("foo", "r") as f:
|
= help: Replace with `rb`
Safe fix
14 14 | pass
15 15 | with open("foo", "Ub") as f:
16 16 | pass
17 |-with open("foo", "rUb") as f:
17 |+with open("foo", "rb") as f:
18 18 | pass
19 19 | with open("foo", "r") as f:
20 20 | pass
UP015.py:19:18: UP015 [*] Unnecessary mode argument
|
17 | with open("foo", "rUb") as f:
18 | pass
19 | with open("foo", "r") as f:
| ^^^ UP015
20 | pass
21 | with open("foo", "rt") as f:
|
= help: Remove mode argument
Safe fix
16 16 | pass
17 17 | with open("foo", "rUb") as f:
18 18 | pass
19 |-with open("foo", "r") as f:
19 |+with open("foo") as f:
20 20 | pass
21 21 | with open("foo", "rt") as f:
22 22 | pass
UP015.py:21:18: UP015 [*] Unnecessary mode argument
|
19 | with open("foo", "r") as f:
20 | pass
21 | with open("foo", "rt") as f:
| ^^^^ UP015
22 | pass
23 | with open("foo", "r", encoding="UTF-8") as f:
|
= help: Remove mode argument
Safe fix
18 18 | pass
19 19 | with open("foo", "r") as f:
20 20 | pass
21 |-with open("foo", "rt") as f:
21 |+with open("foo") as f:
22 22 | pass
23 23 | with open("foo", "r", encoding="UTF-8") as f:
24 24 | pass
UP015.py:23:18: UP015 [*] Unnecessary mode argument
|
21 | with open("foo", "rt") as f:
22 | pass
23 | with open("foo", "r", encoding="UTF-8") as f:
| ^^^ UP015
24 | pass
25 | with open("foo", "wt") as f:
|
= help: Remove mode argument
Safe fix
20 20 | pass
21 21 | with open("foo", "rt") as f:
22 22 | pass
23 |-with open("foo", "r", encoding="UTF-8") as f:
23 |+with open("foo", encoding="UTF-8") as f:
24 24 | pass
25 25 | with open("foo", "wt") as f:
26 26 | pass
UP015.py:25:18: UP015 [*] Unnecessary modes, use `w`
|
23 | with open("foo", "r", encoding="UTF-8") as f:
24 | pass
25 | with open("foo", "wt") as f:
| ^^^^ UP015
26 | pass
|
= help: Replace with `w`
Safe fix
22 22 | pass
23 23 | with open("foo", "r", encoding="UTF-8") as f:
24 24 | pass
25 |-with open("foo", "wt") as f:
25 |+with open("foo", "w") as f:
26 26 | pass
27 27 |
28 28 | open(f("a", "b", "c"), "U")
UP015.py:28:24: UP015 [*] Unnecessary mode argument
|
26 | pass
27 |
28 | open(f("a", "b", "c"), "U")
| ^^^ UP015
29 | open(f("a", "b", "c"), "Ub")
|
= help: Remove mode argument
Safe fix
25 25 | with open("foo", "wt") as f:
26 26 | pass
27 27 |
28 |-open(f("a", "b", "c"), "U")
28 |+open(f("a", "b", "c"))
29 29 | open(f("a", "b", "c"), "Ub")
30 30 |
31 31 | with open(f("a", "b", "c"), "U") as f:
UP015.py:29:24: UP015 [*] Unnecessary modes, use `rb`
|
28 | open(f("a", "b", "c"), "U")
29 | open(f("a", "b", "c"), "Ub")
| ^^^^ UP015
30 |
31 | with open(f("a", "b", "c"), "U") as f:
|
= help: Replace with `rb`
Safe fix
26 26 | pass
27 27 |
28 28 | open(f("a", "b", "c"), "U")
29 |-open(f("a", "b", "c"), "Ub")
29 |+open(f("a", "b", "c"), "rb")
30 30 |
31 31 | with open(f("a", "b", "c"), "U") as f:
32 32 | pass
UP015.py:31:29: UP015 [*] Unnecessary mode argument
|
29 | open(f("a", "b", "c"), "Ub")
30 |
31 | with open(f("a", "b", "c"), "U") as f:
| ^^^ UP015
32 | pass
33 | with open(f("a", "b", "c"), "Ub") as f:
|
= help: Remove mode argument
Safe fix
28 28 | open(f("a", "b", "c"), "U")
29 29 | open(f("a", "b", "c"), "Ub")
30 30 |
31 |-with open(f("a", "b", "c"), "U") as f:
31 |+with open(f("a", "b", "c")) as f:
32 32 | pass
33 33 | with open(f("a", "b", "c"), "Ub") as f:
34 34 | pass
UP015.py:33:29: UP015 [*] Unnecessary modes, use `rb`
|
31 | with open(f("a", "b", "c"), "U") as f:
32 | pass
33 | with open(f("a", "b", "c"), "Ub") as f:
| ^^^^ UP015
34 | pass
|
= help: Replace with `rb`
Safe fix
30 30 |
31 31 | with open(f("a", "b", "c"), "U") as f:
32 32 | pass
33 |-with open(f("a", "b", "c"), "Ub") as f:
33 |+with open(f("a", "b", "c"), "rb") as f:
34 34 | pass
35 35 |
36 36 | with open("foo", "U") as fa, open("bar", "U") as fb:
UP015.py:36:18: UP015 [*] Unnecessary mode argument
|
34 | pass
35 |
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
| ^^^ UP015
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
|
= help: Remove mode argument
Safe fix
33 33 | with open(f("a", "b", "c"), "Ub") as f:
34 34 | pass
35 35 |
36 |-with open("foo", "U") as fa, open("bar", "U") as fb:
36 |+with open("foo") as fa, open("bar", "U") as fb:
37 37 | pass
38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
39 39 | pass
UP015.py:36:42: UP015 [*] Unnecessary mode argument
|
34 | pass
35 |
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
| ^^^ UP015
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
|
= help: Remove mode argument
Safe fix
33 33 | with open(f("a", "b", "c"), "Ub") as f:
34 34 | pass
35 35 |
36 |-with open("foo", "U") as fa, open("bar", "U") as fb:
36 |+with open("foo", "U") as fa, open("bar") as fb:
37 37 | pass
38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
39 39 | pass
UP015.py:38:18: UP015 [*] Unnecessary modes, use `rb`
|
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
| ^^^^ UP015
39 | pass
|
= help: Replace with `rb`
Safe fix
35 35 |
36 36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 37 | pass
38 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
38 |+with open("foo", "rb") as fa, open("bar", "Ub") as fb:
39 39 | pass
40 40 |
41 41 | open("foo", mode="U")
UP015.py:38:43: UP015 [*] Unnecessary modes, use `rb`
|
36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 | pass
38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
| ^^^^ UP015
39 | pass
|
= help: Replace with `rb`
Safe fix
35 35 |
36 36 | with open("foo", "U") as fa, open("bar", "U") as fb:
37 37 | pass
38 |-with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
38 |+with open("foo", "Ub") as fa, open("bar", "rb") as fb:
39 39 | pass
40 40 |
41 41 | open("foo", mode="U")
UP015.py:41:18: UP015 [*] Unnecessary mode argument
|
39 | pass
40 |
41 | open("foo", mode="U")
| ^^^ UP015
42 | open(name="foo", mode="U")
43 | open(mode="U", name="foo")
|
= help: Remove mode argument
Safe fix
38 38 | with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
39 39 | pass
40 40 |
41 |-open("foo", mode="U")
41 |+open("foo")
42 42 | open(name="foo", mode="U")
43 43 | open(mode="U", name="foo")
44 44 |
UP015.py:42:23: UP015 [*] Unnecessary mode argument
|
41 | open("foo", mode="U")
42 | open(name="foo", mode="U")
| ^^^ UP015
43 | open(mode="U", name="foo")
|
= help: Remove mode argument
Safe fix
39 39 | pass
40 40 |
41 41 | open("foo", mode="U")
42 |-open(name="foo", mode="U")
42 |+open(name="foo")
43 43 | open(mode="U", name="foo")
44 44 |
45 45 | with open("foo", mode="U") as f:
UP015.py:43:11: UP015 [*] Unnecessary mode argument
|
41 | open("foo", mode="U")
42 | open(name="foo", mode="U")
43 | open(mode="U", name="foo")
| ^^^ UP015
44 |
45 | with open("foo", mode="U") as f:
|
= help: Remove mode argument
Safe fix
40 40 |
41 41 | open("foo", mode="U")
42 42 | open(name="foo", mode="U")
43 |-open(mode="U", name="foo")
43 |+open(name="foo")
44 44 |
45 45 | with open("foo", mode="U") as f:
46 46 | pass
UP015.py:45:23: UP015 [*] Unnecessary mode argument
|
43 | open(mode="U", name="foo")
44 |
45 | with open("foo", mode="U") as f:
| ^^^ UP015
46 | pass
47 | with open(name="foo", mode="U") as f:
|
= help: Remove mode argument
Safe fix
42 42 | open(name="foo", mode="U")
43 43 | open(mode="U", name="foo")
44 44 |
45 |-with open("foo", mode="U") as f:
45 |+with open("foo") as f:
46 46 | pass
47 47 | with open(name="foo", mode="U") as f:
48 48 | pass
UP015.py:47:28: UP015 [*] Unnecessary mode argument
|
45 | with open("foo", mode="U") as f:
46 | pass
47 | with open(name="foo", mode="U") as f:
| ^^^ UP015
48 | pass
49 | with open(mode="U", name="foo") as f:
|
= help: Remove mode argument
Safe fix
44 44 |
45 45 | with open("foo", mode="U") as f:
46 46 | pass
47 |-with open(name="foo", mode="U") as f:
47 |+with open(name="foo") as f:
48 48 | pass
49 49 | with open(mode="U", name="foo") as f:
50 50 | pass
UP015.py:49:16: UP015 [*] Unnecessary mode argument
|
47 | with open(name="foo", mode="U") as f:
48 | pass
49 | with open(mode="U", name="foo") as f:
| ^^^ UP015
50 | pass
|
= help: Remove mode argument
Safe fix
46 46 | pass
47 47 | with open(name="foo", mode="U") as f:
48 48 | pass
49 |-with open(mode="U", name="foo") as f:
49 |+with open(name="foo") as f:
50 50 | pass
51 51 |
52 52 | open("foo", mode="Ub")
UP015.py:52:18: UP015 [*] Unnecessary modes, use `rb`
|
50 | pass
51 |
52 | open("foo", mode="Ub")
| ^^^^ UP015
53 | open(name="foo", mode="Ub")
54 | open(mode="Ub", name="foo")
|
= help: Replace with `rb`
Safe fix
49 49 | with open(mode="U", name="foo") as f:
50 50 | pass
51 51 |
52 |-open("foo", mode="Ub")
52 |+open("foo", mode="rb")
53 53 | open(name="foo", mode="Ub")
54 54 | open(mode="Ub", name="foo")
55 55 |
UP015.py:53:23: UP015 [*] Unnecessary modes, use `rb`
|
52 | open("foo", mode="Ub")
53 | open(name="foo", mode="Ub")
| ^^^^ UP015
54 | open(mode="Ub", name="foo")
|
= help: Replace with `rb`
Safe fix
50 50 | pass
51 51 |
52 52 | open("foo", mode="Ub")
53 |-open(name="foo", mode="Ub")
53 |+open(name="foo", mode="rb")
54 54 | open(mode="Ub", name="foo")
55 55 |
56 56 | with open("foo", mode="Ub") as f:
UP015.py:54:11: UP015 [*] Unnecessary modes, use `rb`
|
52 | open("foo", mode="Ub")
53 | open(name="foo", mode="Ub")
54 | open(mode="Ub", name="foo")
| ^^^^ UP015
55 |
56 | with open("foo", mode="Ub") as f:
|
= help: Replace with `rb`
Safe fix
51 51 |
52 52 | open("foo", mode="Ub")
53 53 | open(name="foo", mode="Ub")
54 |-open(mode="Ub", name="foo")
54 |+open(mode="rb", name="foo")
55 55 |
56 56 | with open("foo", mode="Ub") as f:
57 57 | pass
UP015.py:56:23: UP015 [*] Unnecessary modes, use `rb`
|
54 | open(mode="Ub", name="foo")
55 |
56 | with open("foo", mode="Ub") as f:
| ^^^^ UP015
57 | pass
58 | with open(name="foo", mode="Ub") as f:
|
= help: Replace with `rb`
Safe fix
53 53 | open(name="foo", mode="Ub")
54 54 | open(mode="Ub", name="foo")
55 55 |
56 |-with open("foo", mode="Ub") as f:
56 |+with open("foo", mode="rb") as f:
57 57 | pass
58 58 | with open(name="foo", mode="Ub") as f:
59 59 | pass
UP015.py:58:28: UP015 [*] Unnecessary modes, use `rb`
|
56 | with open("foo", mode="Ub") as f:
57 | pass
58 | with open(name="foo", mode="Ub") as f:
| ^^^^ UP015
59 | pass
60 | with open(mode="Ub", name="foo") as f:
|
= help: Replace with `rb`
Safe fix
55 55 |
56 56 | with open("foo", mode="Ub") as f:
57 57 | pass
58 |-with open(name="foo", mode="Ub") as f:
58 |+with open(name="foo", mode="rb") as f:
59 59 | pass
60 60 | with open(mode="Ub", name="foo") as f:
61 61 | pass
UP015.py:60:16: UP015 [*] Unnecessary modes, use `rb`
|
58 | with open(name="foo", mode="Ub") as f:
59 | pass
60 | with open(mode="Ub", name="foo") as f:
| ^^^^ UP015
61 | pass
|
= help: Replace with `rb`
Safe fix
57 57 | pass
58 58 | with open(name="foo", mode="Ub") as f:
59 59 | pass
60 |-with open(mode="Ub", name="foo") as f:
60 |+with open(mode="rb", name="foo") as f:
61 61 | pass
62 62 |
63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:63:23: UP015 [*] Unnecessary mode argument
|
61 | pass
62 |
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^ UP015
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
|
= help: Remove mode argument
Safe fix
60 60 | with open(mode="Ub", name="foo") as f:
61 61 | pass
62 62 |
63 |-open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
63 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:64:106: UP015 [*] Unnecessary mode argument
|
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
| ^^^ UP015
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Remove mode argument
Safe fix
61 61 | pass
62 62 |
63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
64 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
UP015.py:65:65: UP015 [*] Unnecessary mode argument
|
63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
| ^^^ UP015
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Remove mode argument
Safe fix
62 62 |
63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
65 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:66:11: UP015 [*] Unnecessary mode argument
|
64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^ UP015
67 |
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Remove mode argument
Safe fix
63 63 | open(file="foo", mode='U', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
64 64 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 |-open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
66 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
UP015.py:68:23: UP015 [*] Unnecessary modes, use `rb`
|
66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 |
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^ UP015
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
|
= help: Replace with `rb`
Safe fix
65 65 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
68 |-open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
68 |+open(file="foo", mode="rb", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
UP015.py:69:106: UP015 [*] Unnecessary modes, use `rb`
|
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
| ^^^^ UP015
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Replace with `rb`
Safe fix
66 66 | open(mode='U', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
67 67 |
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 |-open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
69 |+open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode="rb")
70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
72 72 |
UP015.py:70:65: UP015 [*] Unnecessary modes, use `rb`
|
68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
| ^^^^ UP015
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
= help: Replace with `rb`
Safe fix
67 67 |
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 |-open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
70 |+open(file="foo", buffering=-1, encoding=None, errors=None, mode="rb", newline=None, closefd=True, opener=None)
71 71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
72 72 |
73 73 | import aiofiles
UP015.py:71:11: UP015 [*] Unnecessary modes, use `rb`
|
69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 | open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
| ^^^^ UP015
72 |
73 | import aiofiles
|
= help: Replace with `rb`
Safe fix
68 68 | open(file="foo", mode='Ub', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
69 69 | open(file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
70 70 | open(file="foo", buffering=-1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
71 |-open(mode='Ub', file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
71 |+open(mode="rb", file="foo", buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
72 72 |
73 73 | import aiofiles
74 74 |
UP015.py:75:22: UP015 [*] Unnecessary mode argument
|
73 | import aiofiles
74 |
75 | aiofiles.open("foo", "U")
| ^^^ UP015
76 | aiofiles.open("foo", "r")
77 | aiofiles.open("foo", mode="r")
|
= help: Remove mode argument
Safe fix
72 72 |
73 73 | import aiofiles
74 74 |
75 |-aiofiles.open("foo", "U")
75 |+aiofiles.open("foo")
76 76 | aiofiles.open("foo", "r")
77 77 | aiofiles.open("foo", mode="r")
78 78 |
UP015.py:76:22: UP015 [*] Unnecessary mode argument
|
75 | aiofiles.open("foo", "U")
76 | aiofiles.open("foo", "r")
| ^^^ UP015
77 | aiofiles.open("foo", mode="r")
|
= help: Remove mode argument
Safe fix
73 73 | import aiofiles
74 74 |
75 75 | aiofiles.open("foo", "U")
76 |-aiofiles.open("foo", "r")
76 |+aiofiles.open("foo")
77 77 | aiofiles.open("foo", mode="r")
78 78 |
79 79 | open("foo", "r+")
UP015.py:77:27: UP015 [*] Unnecessary mode argument
|
75 | aiofiles.open("foo", "U")
76 | aiofiles.open("foo", "r")
77 | aiofiles.open("foo", mode="r")
| ^^^ UP015
78 |
79 | open("foo", "r+")
|
= help: Remove mode argument
Safe fix
74 74 |
75 75 | aiofiles.open("foo", "U")
76 76 | aiofiles.open("foo", "r")
77 |-aiofiles.open("foo", mode="r")
77 |+aiofiles.open("foo")
78 78 |
79 79 | open("foo", "r+")
80 80 | open("foo", "rb")

View File

@@ -1,18 +0,0 @@
---
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
---
UP015_1.py:3:17: UP015 [*] Unnecessary mode argument
|
1 | # Not a valid type annotation but this test shouldn't result in a panic.
2 | # Refer: https://github.com/astral-sh/ruff/issues/11736
3 | x: 'open("foo", "r")'
| ^^^ UP015
|
= help: Remove mode argument
Safe fix
1 1 | # Not a valid type annotation but this test shouldn't result in a panic.
2 2 | # Refer: https://github.com/astral-sh/ruff/issues/11736
3 |-x: 'open("foo", "r")'
3 |+x: 'open("foo")'
4 4 |

View File

@@ -12,7 +12,6 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -62,24 +61,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::TypeNoneComparison, Path::new("FURB169.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("refurb").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn write_whole_file_python_39() -> Result<()> {
let diagnostics = test_path(

View File

@@ -13,9 +13,6 @@ use crate::rules::refurb::helpers::replace_with_identity_check;
/// There is only ever one instance of `None`, so it is more efficient and
/// readable to use the `is` operator to check if an object is `None`.
///
/// Only name expressions (e.g., `type(foo) == type(None)`) are reported.
/// In [preview], the rule will also report other kinds of expressions.
///
/// ## Example
/// ```python
/// type(obj) is type(None)
@@ -34,8 +31,6 @@ use crate::rules::refurb::helpers::replace_with_identity_check;
/// - [Python documentation: `None`](https://docs.python.org/3/library/constants.html#None)
/// - [Python documentation: `type`](https://docs.python.org/3/library/functions.html#type)
/// - [Python documentation: Identity comparisons](https://docs.python.org/3/reference/expressions.html#is-not)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[derive(ViolationMetadata)]
pub(crate) struct TypeNoneComparison {
replacement: IdentityCheck,
@@ -80,12 +75,6 @@ pub(crate) fn type_none_comparison(checker: &Checker, compare: &ast::ExprCompare
_ => return,
};
if checker.settings.preview.is_disabled()
&& !matches!(other_arg, Expr::Name(_) | Expr::NoneLiteral(_))
{
return;
}
let diagnostic = Diagnostic::new(TypeNoneComparison { replacement }, compare.range);
let negate = replacement == IdentityCheck::IsNot;

View File

@@ -251,4 +251,102 @@ FURB169.py:27:1: FURB169 [*] When checking against `None`, use `is not` instead
27 |+None is not None
28 28 |
29 29 | type(a.b) is type(None)
30 30 |
30 30 |
FURB169.py:29:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
27 | type(None) != type(None)
28 |
29 | type(a.b) is type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
30 |
31 | type(
|
= help: Replace with `is None`
Safe fix
26 26 |
27 27 | type(None) != type(None)
28 28 |
29 |-type(a.b) is type(None)
29 |+a.b is None
30 30 |
31 31 | type(
32 32 | a(
FURB169.py:31:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
29 | type(a.b) is type(None)
30 |
31 | / type(
32 | | a(
33 | | # Comment
34 | | )
35 | | ) != type(None)
| |_______________^ FURB169
36 |
37 | type(
|
= help: Replace with `is not None`
Unsafe fix
28 28 |
29 29 | type(a.b) is type(None)
30 30 |
31 |-type(
32 |- a(
33 |- # Comment
34 |- )
35 |-) != type(None)
31 |+a() is not None
36 32 |
37 33 | type(
38 34 | a := 1
FURB169.py:37:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
35 | ) != type(None)
36 |
37 | / type(
38 | | a := 1
39 | | ) == type(None)
| |_______________^ FURB169
40 |
41 | type(
|
= help: Replace with `is None`
Safe fix
34 34 | )
35 35 | ) != type(None)
36 36 |
37 |-type(
38 |- a := 1
39 |-) == type(None)
37 |+(a := 1) is None
40 38 |
41 39 | type(
42 40 | a for a in range(0)
FURB169.py:41:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
39 | ) == type(None)
40 |
41 | / type(
42 | | a for a in range(0)
43 | | ) is not type(None)
| |___________________^ FURB169
|
= help: Replace with `is not None`
Safe fix
38 38 | a := 1
39 39 | ) == type(None)
40 40 |
41 |-type(
42 |- a for a in range(0)
43 |-) is not type(None)
41 |+(a for a in range(0)) is not None
44 42 |
45 43 |
46 44 | # Ok.

View File

@@ -1,352 +0,0 @@
---
source: crates/ruff_linter/src/rules/refurb/mod.rs
---
FURB169.py:5:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
3 | # Error.
4 |
5 | type(foo) is type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
6 |
7 | type(None) is type(foo)
|
= help: Replace with `is None`
Safe fix
2 2 |
3 3 | # Error.
4 4 |
5 |-type(foo) is type(None)
5 |+foo is None
6 6 |
7 7 | type(None) is type(foo)
8 8 |
FURB169.py:7:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
5 | type(foo) is type(None)
6 |
7 | type(None) is type(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
8 |
9 | type(None) is type(None)
|
= help: Replace with `is None`
Safe fix
4 4 |
5 5 | type(foo) is type(None)
6 6 |
7 |-type(None) is type(foo)
7 |+foo is None
8 8 |
9 9 | type(None) is type(None)
10 10 |
FURB169.py:9:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
7 | type(None) is type(foo)
8 |
9 | type(None) is type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
10 |
11 | type(foo) is not type(None)
|
= help: Replace with `is None`
Safe fix
6 6 |
7 7 | type(None) is type(foo)
8 8 |
9 |-type(None) is type(None)
9 |+None is None
10 10 |
11 11 | type(foo) is not type(None)
12 12 |
FURB169.py:11:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
9 | type(None) is type(None)
10 |
11 | type(foo) is not type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
12 |
13 | type(None) is not type(foo)
|
= help: Replace with `is not None`
Safe fix
8 8 |
9 9 | type(None) is type(None)
10 10 |
11 |-type(foo) is not type(None)
11 |+foo is not None
12 12 |
13 13 | type(None) is not type(foo)
14 14 |
FURB169.py:13:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
11 | type(foo) is not type(None)
12 |
13 | type(None) is not type(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
14 |
15 | type(None) is not type(None)
|
= help: Replace with `is not None`
Safe fix
10 10 |
11 11 | type(foo) is not type(None)
12 12 |
13 |-type(None) is not type(foo)
13 |+foo is not None
14 14 |
15 15 | type(None) is not type(None)
16 16 |
FURB169.py:15:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
13 | type(None) is not type(foo)
14 |
15 | type(None) is not type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
16 |
17 | type(foo) == type(None)
|
= help: Replace with `is not None`
Safe fix
12 12 |
13 13 | type(None) is not type(foo)
14 14 |
15 |-type(None) is not type(None)
15 |+None is not None
16 16 |
17 17 | type(foo) == type(None)
18 18 |
FURB169.py:17:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
15 | type(None) is not type(None)
16 |
17 | type(foo) == type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
18 |
19 | type(None) == type(foo)
|
= help: Replace with `is None`
Safe fix
14 14 |
15 15 | type(None) is not type(None)
16 16 |
17 |-type(foo) == type(None)
17 |+foo is None
18 18 |
19 19 | type(None) == type(foo)
20 20 |
FURB169.py:19:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
17 | type(foo) == type(None)
18 |
19 | type(None) == type(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
20 |
21 | type(None) == type(None)
|
= help: Replace with `is None`
Safe fix
16 16 |
17 17 | type(foo) == type(None)
18 18 |
19 |-type(None) == type(foo)
19 |+foo is None
20 20 |
21 21 | type(None) == type(None)
22 22 |
FURB169.py:21:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
19 | type(None) == type(foo)
20 |
21 | type(None) == type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
22 |
23 | type(foo) != type(None)
|
= help: Replace with `is None`
Safe fix
18 18 |
19 19 | type(None) == type(foo)
20 20 |
21 |-type(None) == type(None)
21 |+None is None
22 22 |
23 23 | type(foo) != type(None)
24 24 |
FURB169.py:23:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
21 | type(None) == type(None)
22 |
23 | type(foo) != type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
24 |
25 | type(None) != type(foo)
|
= help: Replace with `is not None`
Safe fix
20 20 |
21 21 | type(None) == type(None)
22 22 |
23 |-type(foo) != type(None)
23 |+foo is not None
24 24 |
25 25 | type(None) != type(foo)
26 26 |
FURB169.py:25:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
23 | type(foo) != type(None)
24 |
25 | type(None) != type(foo)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
26 |
27 | type(None) != type(None)
|
= help: Replace with `is not None`
Safe fix
22 22 |
23 23 | type(foo) != type(None)
24 24 |
25 |-type(None) != type(foo)
25 |+foo is not None
26 26 |
27 27 | type(None) != type(None)
28 28 |
FURB169.py:27:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
25 | type(None) != type(foo)
26 |
27 | type(None) != type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^^ FURB169
28 |
29 | type(a.b) is type(None)
|
= help: Replace with `is not None`
Safe fix
24 24 |
25 25 | type(None) != type(foo)
26 26 |
27 |-type(None) != type(None)
27 |+None is not None
28 28 |
29 29 | type(a.b) is type(None)
30 30 |
FURB169.py:29:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
27 | type(None) != type(None)
28 |
29 | type(a.b) is type(None)
| ^^^^^^^^^^^^^^^^^^^^^^^ FURB169
30 |
31 | type(
|
= help: Replace with `is None`
Safe fix
26 26 |
27 27 | type(None) != type(None)
28 28 |
29 |-type(a.b) is type(None)
29 |+a.b is None
30 30 |
31 31 | type(
32 32 | a(
FURB169.py:31:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
29 | type(a.b) is type(None)
30 |
31 | / type(
32 | | a(
33 | | # Comment
34 | | )
35 | | ) != type(None)
| |_______________^ FURB169
36 |
37 | type(
|
= help: Replace with `is not None`
Unsafe fix
28 28 |
29 29 | type(a.b) is type(None)
30 30 |
31 |-type(
32 |- a(
33 |- # Comment
34 |- )
35 |-) != type(None)
31 |+a() is not None
36 32 |
37 33 | type(
38 34 | a := 1
FURB169.py:37:1: FURB169 [*] When checking against `None`, use `is` instead of comparison with `type(None)`
|
35 | ) != type(None)
36 |
37 | / type(
38 | | a := 1
39 | | ) == type(None)
| |_______________^ FURB169
40 |
41 | type(
|
= help: Replace with `is None`
Safe fix
34 34 | )
35 35 | ) != type(None)
36 36 |
37 |-type(
38 |- a := 1
39 |-) == type(None)
37 |+(a := 1) is None
40 38 |
41 39 | type(
42 40 | a for a in range(0)
FURB169.py:41:1: FURB169 [*] When checking against `None`, use `is not` instead of comparison with `type(None)`
|
39 | ) == type(None)
40 |
41 | / type(
42 | | a for a in range(0)
43 | | ) is not type(None)
| |___________________^ FURB169
|
= help: Replace with `is not None`
Safe fix
38 38 | a := 1
39 39 | ) == type(None)
40 40 |
41 |-type(
42 |- a for a in range(0)
43 |-) is not type(None)
41 |+(a for a in range(0)) is not None
44 42 |
45 43 |
46 44 | # Ok.

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