Compare commits

...

15 Commits

Author SHA1 Message Date
Charlie Marsh
324455f580 Bump version to 0.0.277 (#5515) 2023-07-04 17:31:32 -04:00
Charlie Marsh
da1c320bfa Add .ipynb_checkpoints, .pyenv, .pytest_cache, and .vscode to default excludes (#5513)
## Summary

VS Code extensions are
[recommended](https://code.visualstudio.com/docs/python/settings-reference#_linting-settings)
to exclude `.vscode` and `site-packages`. Black also now omits
`.vscode`, `.pytest_cache`, and `.ipynb_checkpoints` by default.
Omitting `.pyenv` is similar to omitting virtual environments, but
really only matters in the context of VS Code (see:
https://github.com/astral-sh/ruff/discussions/5509).

Closes: #5510.
2023-07-04 20:25:16 +00:00
Charlie Marsh
485d997d35 Tweak prefix match to use .all_rules() (#5512)
## Summary

No behavior change, but I think this is a little cleaner.
2023-07-04 20:02:57 +00:00
Aarni Koskela
d7214e77e6 Add ruff rule --all subcommand (with JSON output) (#5059)
## Summary

This adds a `ruff rule --all` switch that prints out a human-readable
Markdown or a machine-readable JSON document of the lint rules known to
Ruff.

I needed a machine-readable document of the rules [for a
project](https://github.com/astral-sh/ruff/discussions/5078), and
figured it could be useful for other people – or tooling! – to be able
to interrogate Ruff about its arcane knowledge.

The JSON output is an array of the same objects printed by `ruff rule
--format=json`.

## Test Plan

I ran `ruff rule --all --format=json`. I think more might be needed, but
maybe a snapshot test is overkill?
2023-07-04 19:45:38 +00:00
Charlie Marsh
952c623102 Avoid returning first-match for rule prefixes (#5511)
Closes #5495, but there's a TODO here to improve this further. The
current `from_code` implementation feels really indirect.
2023-07-04 19:23:05 +00:00
konsti
0a26201643 Merge clippy and clippy (wasm) jobs on CI (#5447)
## Summary

The clippy wasm job rarely fails if regular clippy doesn't, wasm clippy
still compiles a lot of native dependencies for the proc macro and we
have less CI jobs overall, so i think this an improvement to our CI.

```shell
$ CARGO_TARGET_DIR=target-wasm cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -j 2 -- -D warnings
$ du -sh target-wasm/*
12K	target-wasm/CACHEDIR.TAG
582M	target-wasm/debug
268M	target-wasm/wasm32-unknown-unknown
```

## Test plan

n/a
2023-07-04 15:22:00 -04:00
Tom Kuson
0e67757edb [pylint] Implement Pylint typevar-name-mismatch (C0132) (#5501)
## Summary

Implement Pylint `typevar-name-mismatch` (`C0132`) as
`type-param-name-mismatch` (`PLC0132`). Includes documentation. Related
to #970.

The Pylint implementation checks only `TypeVar`, but this PR checks
`TypeVarTuple`, `ParamSpec`, and `NewType` as well. This seems to better
represent the Pylint rule's [intended
behaviour](https://github.com/pylint-dev/pylint/issues/5224).

Full disclosure: I am not a fan of the translated name and think it
should probably be different.

## Test Plan

`cargo test`
2023-07-04 18:49:43 +00:00
Charlie Marsh
c395e44bd7 Avoid PERF rules for iteration-dependent assignments (#5508)
## Summary

We need to avoid raising "rewrite as a comprehension" violations in
cases like:

```python
d = defaultdict(list)

for i in [1, 2, 3]:
    d[i].append(i**2)
```

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

Closes https://github.com/astral-sh/ruff/issues/5500.
2023-07-04 18:21:05 +00:00
Charlie Marsh
75da72bd7f Update documentation to list double-quote preference first (#5507)
Closes https://github.com/astral-sh/ruff/issues/5496.
2023-07-04 18:06:01 +00:00
Charlie Marsh
521e6de2c8 Fix eval detection for suspicious-eval-usage (#5506)
Closes https://github.com/astral-sh/ruff/issues/5505.
2023-07-04 18:01:29 +00:00
Thomas de Zeeuw
0b963ddcfa Add unreachable code rule (#5384)
Co-authored-by: Thomas de Zeeuw <thomas@astral.sh>
Co-authored-by: Micha Reiser <micha@reiser.io>
2023-07-04 14:27:23 +00:00
konsti
937de121f3 check-formatter-stability: Remove newlines and add --error-file (#5491)
## Summary

This makes the output of `check-formatter-stability` more concise by
removing extraneous newlines. It also adds a `--error-file` option to
that script that allows creating a file with just the errors (without
the status messages) to share with others.

## Test Plan

I ran it over CPython and looked at the output. I then added the
`--error-file` option and looked at the contents of the file
2023-07-04 07:54:35 +00:00
konsti
787e2fd49d Format import statements (#5493)
## Summary

Format import statements in all their variants. Specifically, this
implemented formatting `StmtImport`, `StmtImportFrom` and `Alias`.

## Test Plan

I added some custom snapshots, even though this has been covered well by
black's tests.
2023-07-04 07:07:20 +00:00
Aarni Koskela
6acc316d19 Turn Linters', etc. implicit into_iter()s into explicit rules() (#5436)
## Summary

As discussed on ~IRC~ Discord, this will make it easier for e.g. the
docs generation stuff to get all rules for a linter (using
`all_rules()`) instead of just non-nursery ones, and it also makes it
more Explicit Is Better Than Implicit to iterate over linter rules.

Grepping for `Item = Rule` reveals some remaining implicit
`IntoIterator`s that I didn't feel were necessarily in scope for this
(and honestly, iterating over a `RuleSet` makes sense).
2023-07-03 19:35:16 -04:00
konsti
a647f31600 Don't add a magic trailing comma for a single entry (#5463)
## Summary

If a comma separated list has only one entry, black will respect the
magic trailing comma, but it will not add a new one.

The following code will remain as is:

```python
b1 = [
    aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
]
b2 = [
    aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
]
b3 = [
    aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
    aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
]
```

## Test Plan

This was first discovered in
7eeadc82c2/django/contrib/admin/checks.py (L674-L681),
which i've minimized into a call test.

I've added tests for the three cases (one entry + no comma, one entry +
comma, more than one entry) to the list tests.

The diffs from the black tests get smaller.
2023-07-03 21:48:44 +02:00
112 changed files with 5801 additions and 1353 deletions

1
.gitattributes vendored
View File

@@ -4,3 +4,4 @@ crates/ruff/resources/test/fixtures/isort/line_ending_crlf.py text eol=crlf
crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf
ruff.schema.json linguist-generated=true text=auto eol=lf
*.md.snap linguist-language=Markdown

View File

@@ -31,17 +31,6 @@ jobs:
cargo-clippy:
name: "cargo clippy"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: |
rustup component add clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo-clippy-wasm:
name: "cargo clippy (wasm)"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
@@ -49,7 +38,10 @@ jobs:
rustup component add clippy
rustup target add wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
- name: "Clippy"
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: "Clippy (wasm)"
run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
cargo-test:
strategy:

View File

@@ -1,5 +1,41 @@
# Breaking Changes
## 0.0.277
### `.ipynb_checkpoints`, `.pyenv`, `.pytest_cache`, and `.vscode` are now excluded by default ([#5513](https://github.com/astral-sh/ruff/pull/5513))
Ruff maintains a list of default exclusions, which now consists of the following patterns:
- `.bzr`
- `.direnv`
- `.eggs`
- `.git`
- `.git-rewrite`
- `.hg`
- `.ipynb_checkpoints`
- `.mypy_cache`
- `.nox`
- `.pants.d`
- `.pyenv`
- `.pytest_cache`
- `.pytype`
- `.ruff_cache`
- `.svn`
- `.tox`
- `.venv`
- `.vscode`
- `__pypackages__`
- `_build`
- `buck-out`
- `build`
- `dist`
- `node_modules`
- `venv`
Previously, the `.ipynb_checkpoints`, `.pyenv`, `.pytest_cache`, and `.vscode` directories were not
excluded by default. This change brings Ruff's default exclusions in line with other tools like
Black.
## 0.0.276
### The `keep-runtime-typing` setting has been reinstated ([#5470](https://github.com/astral-sh/ruff/pull/5470))

7
Cargo.lock generated
View File

@@ -746,7 +746,7 @@ dependencies = [
[[package]]
name = "flake8-to-ruff"
version = "0.0.276"
version = "0.0.277"
dependencies = [
"anyhow",
"clap",
@@ -1829,7 +1829,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.276"
version = "0.0.277"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1865,6 +1865,7 @@ dependencies = [
"result-like",
"ruff_cache",
"ruff_diagnostics",
"ruff_index",
"ruff_macros",
"ruff_python_ast",
"ruff_python_semantic",
@@ -1926,7 +1927,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.0.276"
version = "0.0.277"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",

View File

@@ -139,7 +139,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.0.276
rev: v0.0.277
hooks:
- id: ruff
```

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.276"
version = "0.0.277"
description = """
Convert Flake8 configuration files to Ruff configuration files.
"""

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.0.276"
version = "0.0.277"
publish = false
authors = { workspace = true }
edition = { workspace = true }
@@ -17,6 +17,7 @@ name = "ruff"
[dependencies]
ruff_cache = { path = "../ruff_cache" }
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
ruff_index = { path = "../ruff_index" }
ruff_macros = { path = "../ruff_macros" }
ruff_python_whitespace = { path = "../ruff_python_whitespace" }
ruff_python_ast = { path = "../ruff_python_ast", features = ["serde"] }
@@ -88,3 +89,5 @@ colored = { workspace = true, features = ["no-color"] }
[features]
default = []
schemars = ["dep:schemars"]
# Enables the UnreachableCode rule
unreachable-code = []

View File

@@ -0,0 +1,11 @@
def func():
assert True
def func():
assert False
def func():
assert True, "oops"
def func():
assert False, "oops"

View File

@@ -0,0 +1,41 @@
def func():
async for i in range(5):
print(i)
def func():
async for i in range(20):
print(i)
else:
return 0
def func():
async for i in range(10):
if i == 5:
return 1
return 0
def func():
async for i in range(111):
if i == 5:
return 1
else:
return 0
return 2
def func():
async for i in range(12):
continue
def func():
async for i in range(1110):
if True:
continue
def func():
async for i in range(13):
break
def func():
async for i in range(1110):
if True:
break

View File

@@ -0,0 +1,41 @@
def func():
for i in range(5):
print(i)
def func():
for i in range(20):
print(i)
else:
return 0
def func():
for i in range(10):
if i == 5:
return 1
return 0
def func():
for i in range(111):
if i == 5:
return 1
else:
return 0
return 2
def func():
for i in range(12):
continue
def func():
for i in range(1110):
if True:
continue
def func():
for i in range(13):
break
def func():
for i in range(1110):
if True:
break

View File

@@ -0,0 +1,108 @@
def func():
if False:
return 0
return 1
def func():
if True:
return 1
return 0
def func():
if False:
return 0
else:
return 1
def func():
if True:
return 1
else:
return 0
def func():
if False:
return 0
else:
return 1
return "unreachable"
def func():
if True:
return 1
else:
return 0
return "unreachable"
def func():
if True:
if True:
return 1
return 2
else:
return 3
return "unreachable2"
def func():
if False:
return 0
def func():
if True:
return 1
def func():
if True:
return 1
elif False:
return 2
else:
return 0
def func():
if False:
return 1
elif True:
return 2
else:
return 0
def func():
if True:
if False:
return 0
elif True:
return 1
else:
return 2
return 3
elif True:
return 4
else:
return 5
return 6
def func():
if False:
return "unreached"
elif False:
return "also unreached"
return "reached"
# Test case found in the Bokeh repository that trigger a false positive.
def func(self, obj: BytesRep) -> bytes:
data = obj["data"]
if isinstance(data, str):
return base64.b64decode(data)
elif isinstance(data, Buffer):
buffer = data
else:
id = data["id"]
if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f"can't resolve buffer '{id}'")
return buffer.data

View File

@@ -0,0 +1,131 @@
def func(status):
match status:
case _:
return 0
return "unreachable"
def func(status):
match status:
case 1:
return 1
return 0
def func(status):
match status:
case 1:
return 1
case _:
return 0
def func(status):
match status:
case 1 | 2 | 3:
return 5
return 6
def func(status):
match status:
case 1 | 2 | 3:
return 5
case _:
return 10
return 0
def func(status):
match status:
case 0:
return 0
case 1:
return 1
case 1:
return "1 again"
case _:
return 3
def func(status):
i = 0
match status, i:
case _, _:
return 0
def func(status):
i = 0
match status, i:
case _, 0:
return 0
case _, 2:
return 0
def func(point):
match point:
case (0, 0):
print("Origin")
case _:
raise ValueError("oops")
def func(point):
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
def where_is(point):
class Point:
x: int
y: int
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")
def func(points):
match points:
case []:
print("No points")
case [Point(0, 0)]:
print("The origin")
case [Point(x, y)]:
print(f"Single point {x}, {y}")
case [Point(0, y1), Point(0, y2)]:
print(f"Two on the Y axis at {y1}, {y2}")
case _:
print("Something else")
def func(point):
match point:
case Point(x, y) if x == y:
print(f"Y=X at {x}")
case Point(x, y):
print(f"Not on the diagonal")
def func():
from enum import Enum
class Color(Enum):
RED = 'red'
GREEN = 'green'
BLUE = 'blue'
color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))
match color:
case Color.RED:
print("I see red!")
case Color.GREEN:
print("Grass is green")
case Color.BLUE:
print("I'm feeling the blues :(")

View File

@@ -0,0 +1,5 @@
def func():
raise Exception
def func():
raise "a glass!"

View File

@@ -0,0 +1,23 @@
def func():
pass
def func():
pass
def func():
return
def func():
return 1
def func():
return 1
return "unreachable"
def func():
i = 0
def func():
i = 0
i += 2
return i

View File

@@ -0,0 +1,41 @@
def func():
try:
...
except Exception:
...
except OtherException as e:
...
else:
...
finally:
...
def func():
try:
...
except Exception:
...
def func():
try:
...
except Exception:
...
except OtherException as e:
...
def func():
try:
...
except Exception:
...
except OtherException as e:
...
else:
...
def func():
try:
...
finally:
...

View File

@@ -0,0 +1,121 @@
def func():
while False:
return "unreachable"
return 1
def func():
while False:
return "unreachable"
else:
return 1
def func():
while False:
return "unreachable"
else:
return 1
return "also unreachable"
def func():
while True:
return 1
return "unreachable"
def func():
while True:
return 1
else:
return "unreachable"
def func():
while True:
return 1
else:
return "unreachable"
return "also unreachable"
def func():
i = 0
while False:
i += 1
return i
def func():
i = 0
while True:
i += 1
return i
def func():
while True:
pass
return 1
def func():
i = 0
while True:
if True:
print("ok")
i += 1
return i
def func():
i = 0
while True:
if False:
print("ok")
i += 1
return i
def func():
while True:
if True:
return 1
return 0
def func():
while True:
continue
def func():
while False:
continue
def func():
while True:
break
def func():
while False:
break
def func():
while True:
if True:
continue
def func():
while True:
if True:
break
'''
TODO: because `try` statements aren't handled this triggers a false positive as
the last statement is reached, but the rules thinks it isn't (it doesn't
see/process the break statement).
# Test case found in the Bokeh repository that trigger a false positive.
def bokeh2(self, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> None:
self.stop_serving = False
while True:
try:
self.server = HTTPServer((host, port), HtmlOnlyHandler)
self.host = host
self.port = port
break
except OSError:
log.debug(f"port {port} is in use, trying to next one")
port += 1
self.thread = threading.Thread(target=self._run_web_server)
'''

View File

@@ -0,0 +1,12 @@
import os
print(eval("1+1")) # S307
print(eval("os.getcwd()")) # S307
class Class(object):
def eval(self):
print("hi")
def foo(self):
self.eval() # OK

View File

@@ -30,3 +30,10 @@ def f():
result = []
for i in items:
result.append(i) # OK
def f():
items = [1, 2, 3, 4]
result = {}
for i in items:
result[i].append(i) # OK

View File

@@ -17,3 +17,10 @@ def f():
result = []
for i in items:
result.append(i * i) # OK
def f():
items = [1, 2, 3, 4]
result = {}
for i in items:
result[i].append(i * i) # OK

View File

@@ -0,0 +1,56 @@
from typing import TypeVar, ParamSpec, NewType, TypeVarTuple
# Errors.
X = TypeVar("T")
X = TypeVar(name="T")
Y = ParamSpec("T")
Y = ParamSpec(name="T")
Z = NewType("T", int)
Z = NewType(name="T", tp=int)
Ws = TypeVarTuple("Ts")
Ws = TypeVarTuple(name="Ts")
# Non-errors.
T = TypeVar("T")
T = TypeVar(name="T")
T = ParamSpec("T")
T = ParamSpec(name="T")
T = NewType("T", int)
T = NewType(name="T", tp=int)
Ts = TypeVarTuple("Ts")
Ts = TypeVarTuple(name="Ts")
# Errors, but not covered by this rule.
# Non-string literal name.
T = TypeVar(some_str)
T = TypeVar(name=some_str)
T = TypeVar(1)
T = TypeVar(name=1)
T = ParamSpec(some_str)
T = ParamSpec(name=some_str)
T = ParamSpec(1)
T = ParamSpec(name=1)
T = NewType(some_str, int)
T = NewType(name=some_str, tp=int)
T = NewType(1, int)
T = NewType(name=1, tp=int)
Ts = TypeVarTuple(some_str)
Ts = TypeVarTuple(name=some_str)
Ts = TypeVarTuple(1)
Ts = TypeVarTuple(name=1)
# No names provided.
T = TypeVar()
T = ParamSpec()
T = NewType()
T = NewType(tp=int)
Ts = TypeVarTuple()

View File

@@ -0,0 +1,185 @@
def after_return():
return "reachable"
return "unreachable"
async def also_works_on_async_functions():
return "reachable"
return "unreachable"
def if_always_true():
if True:
return "reachable"
return "unreachable"
def if_always_false():
if False:
return "unreachable"
return "reachable"
def if_elif_always_false():
if False:
return "unreachable"
elif False:
return "also unreachable"
return "reachable"
def if_elif_always_true():
if False:
return "unreachable"
elif True:
return "reachable"
return "also unreachable"
def ends_with_if():
if False:
return "unreachable"
else:
return "reachable"
def infinite_loop():
while True:
continue
return "unreachable"
''' TODO: we could determine these, but we don't yet.
def for_range_return():
for i in range(10):
if i == 5:
return "reachable"
return "unreachable"
def for_range_else():
for i in range(111):
if i == 5:
return "reachable"
else:
return "unreachable"
return "also unreachable"
def for_range_break():
for i in range(13):
return "reachable"
return "unreachable"
def for_range_if_break():
for i in range(1110):
if True:
return "reachable"
return "unreachable"
'''
def match_wildcard(status):
match status:
case _:
return "reachable"
return "unreachable"
def match_case_and_wildcard(status):
match status:
case 1:
return "reachable"
case _:
return "reachable"
return "unreachable"
def raise_exception():
raise Exception
return "unreachable"
def while_false():
while False:
return "unreachable"
return "reachable"
def while_false_else():
while False:
return "unreachable"
else:
return "reachable"
def while_false_else_return():
while False:
return "unreachable"
else:
return "reachable"
return "also unreachable"
def while_true():
while True:
return "reachable"
return "unreachable"
def while_true_else():
while True:
return "reachable"
else:
return "unreachable"
def while_true_else_return():
while True:
return "reachable"
else:
return "unreachable"
return "also unreachable"
def while_false_var_i():
i = 0
while False:
i += 1
return i
def while_true_var_i():
i = 0
while True:
i += 1
return i
def while_infinite():
while True:
pass
return "unreachable"
def while_if_true():
while True:
if True:
return "reachable"
return "unreachable"
# Test case found in the Bokeh repository that trigger a false positive.
def bokeh1(self, obj: BytesRep) -> bytes:
data = obj["data"]
if isinstance(data, str):
return base64.b64decode(data)
elif isinstance(data, Buffer):
buffer = data
else:
id = data["id"]
if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f"can't resolve buffer '{id}'")
return buffer.data
'''
TODO: because `try` statements aren't handled this triggers a false positive as
the last statement is reached, but the rules thinks it isn't (it doesn't
see/process the break statement).
# Test case found in the Bokeh repository that trigger a false positive.
def bokeh2(self, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> None:
self.stop_serving = False
while True:
try:
self.server = HTTPServer((host, port), HtmlOnlyHandler)
self.host = host
self.port = port
break
except OSError:
log.debug(f"port {port} is in use, trying to next one")
port += 1
self.thread = threading.Thread(target=self._run_web_server)
'''

View File

@@ -619,6 +619,11 @@ where
);
}
}
#[cfg(feature = "unreachable-code")]
if self.enabled(Rule::UnreachableCode) {
self.diagnostics
.extend(ruff::rules::unreachable::in_function(name, body));
}
}
Stmt::Return(_) => {
if self.enabled(Rule::ReturnOutsideFunction) {
@@ -1650,6 +1655,9 @@ where
self.diagnostics.push(diagnostic);
}
}
if self.settings.rules.enabled(Rule::TypeParamNameMismatch) {
pylint::rules::type_param_name_mismatch(self, value, targets);
}
if self.is_stub {
if self.any_enabled(&[
Rule::UnprefixedTypeParam,
@@ -2579,9 +2587,7 @@ where
flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords);
}
if self.enabled(Rule::ExecBuiltin) {
if let Some(diagnostic) = flake8_bandit::rules::exec_used(expr, func) {
self.diagnostics.push(diagnostic);
}
flake8_bandit::rules::exec_used(self, func);
}
if self.enabled(Rule::BadFilePermissions) {
flake8_bandit::rules::bad_file_permissions(self, func, args, keywords);

View File

@@ -14,6 +14,18 @@ use crate::rules;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct NoqaCode(&'static str, &'static str);
impl NoqaCode {
/// Return the prefix for the [`NoqaCode`], e.g., `SIM` for `SIM101`.
pub fn prefix(&self) -> &str {
self.0
}
/// Return the suffix for the [`NoqaCode`], e.g., `101` for `SIM101`.
pub fn suffix(&self) -> &str {
self.1
}
}
impl std::fmt::Debug for NoqaCode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
@@ -156,6 +168,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pyflakes, "901") => (RuleGroup::Unspecified, rules::pyflakes::rules::RaiseNotImplemented),
// pylint
(Pylint, "C0132") => (RuleGroup::Unspecified, rules::pylint::rules::TypeParamNameMismatch),
(Pylint, "C0205") => (RuleGroup::Unspecified, rules::pylint::rules::SingleStringSlots),
(Pylint, "C0414") => (RuleGroup::Unspecified, rules::pylint::rules::UselessImportAlias),
(Pylint, "C1901") => (RuleGroup::Nursery, rules::pylint::rules::CompareToEmptyString),
@@ -761,6 +774,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "011") => (RuleGroup::Unspecified, rules::ruff::rules::StaticKeyDictComprehension),
(Ruff, "012") => (RuleGroup::Unspecified, rules::ruff::rules::MutableClassDefault),
(Ruff, "013") => (RuleGroup::Unspecified, rules::ruff::rules::ImplicitOptional),
#[cfg(feature = "unreachable-code")]
(Ruff, "014") => (RuleGroup::Nursery, rules::ruff::rules::UnreachableCode),
(Ruff, "100") => (RuleGroup::Unspecified, rules::ruff::rules::UnusedNOQA),
(Ruff, "200") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidPyprojectToml),

View File

@@ -333,7 +333,7 @@ pub(crate) fn infer_plugins_from_codes(selectors: &HashSet<RuleSelector>) -> Vec
for selector in selectors {
if selector
.into_iter()
.any(|rule| Linter::from(plugin).into_iter().any(|r| r == rule))
.any(|rule| Linter::from(plugin).rules().any(|r| r == rule))
{
return true;
}

View File

@@ -18,8 +18,10 @@ pub trait AsRule {
impl Rule {
pub fn from_code(code: &str) -> Result<Self, FromCodeError> {
let (linter, code) = Linter::parse_code(code).ok_or(FromCodeError::Unknown)?;
let prefix: RuleCodePrefix = RuleCodePrefix::parse(&linter, code)?;
Ok(prefix.into_iter().next().unwrap())
linter
.all_rules()
.find(|rule| rule.noqa_code().suffix() == code)
.ok_or(FromCodeError::Unknown)
}
}

View File

@@ -158,16 +158,16 @@ impl IntoIterator for &RuleSelector {
}
RuleSelector::C => RuleSelectorIter::Chain(
Linter::Flake8Comprehensions
.into_iter()
.chain(Linter::McCabe.into_iter()),
.rules()
.chain(Linter::McCabe.rules()),
),
RuleSelector::T => RuleSelectorIter::Chain(
Linter::Flake8Debugger
.into_iter()
.chain(Linter::Flake8Print.into_iter()),
.rules()
.chain(Linter::Flake8Print.rules()),
),
RuleSelector::Linter(linter) => RuleSelectorIter::Vec(linter.into_iter()),
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Vec(prefix.into_iter()),
RuleSelector::Linter(linter) => RuleSelectorIter::Vec(linter.rules()),
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Vec(prefix.clone().rules()),
}
}
}
@@ -346,7 +346,7 @@ mod clap_completion {
let prefix = p.linter().common_prefix();
let code = p.short_code();
let mut rules_iter = p.into_iter();
let mut rules_iter = p.rules();
let rule1 = rules_iter.next();
let rule2 = rules_iter.next();

View File

@@ -39,6 +39,7 @@ mod tests {
#[test_case(Rule::SubprocessPopenWithShellEqualsTrue, Path::new("S602.py"))]
#[test_case(Rule::SubprocessWithoutShellEqualsTrue, Path::new("S603.py"))]
#[test_case(Rule::SuspiciousPickleUsage, Path::new("S301.py"))]
#[test_case(Rule::SuspiciousEvalUsage, Path::new("S307.py"))]
#[test_case(Rule::SuspiciousTelnetUsage, Path::new("S312.py"))]
#[test_case(Rule::TryExceptContinue, Path::new("S112.py"))]
#[test_case(Rule::TryExceptPass, Path::new("S110.py"))]

View File

@@ -1,8 +1,10 @@
use rustpython_parser::ast::{self, Expr, Ranged};
use rustpython_parser::ast::{Expr, Ranged};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
#[violation]
pub struct ExecBuiltin;
@@ -14,12 +16,16 @@ impl Violation for ExecBuiltin {
}
/// S102
pub(crate) fn exec_used(expr: &Expr, func: &Expr) -> Option<Diagnostic> {
let Expr::Name(ast::ExprName { id, .. }) = func else {
return None;
};
if id != "exec" {
return None;
pub(crate) fn exec_used(checker: &mut Checker, func: &Expr) {
if checker
.semantic()
.resolve_call_path(func)
.map_or(false, |call_path| {
matches!(call_path.as_slice(), ["" | "builtin", "exec"])
})
{
checker
.diagnostics
.push(Diagnostic::new(ExecBuiltin, func.range()));
}
Some(Diagnostic::new(ExecBuiltin, expr.range()))
}

View File

@@ -219,7 +219,7 @@ impl Violation for SuspiciousFTPLibUsage {
}
}
/// S001
/// S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323
pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
return;
@@ -246,7 +246,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, expr: &Expr) {
// Mktemp
["tempfile", "mktemp"] => Some(SuspiciousMktempUsage.into()),
// Eval
["eval"] => Some(SuspiciousEvalUsage.into()),
["" | "builtins", "eval"] => Some(SuspiciousEvalUsage.into()),
// MarkSafe
["django", "utils", "safestring", "mark_safe"] => Some(SuspiciousMarkSafeUsage.into()),
// URLOpen

View File

@@ -6,7 +6,7 @@ S102.py:3:5: S102 Use of `exec` detected
1 | def fn():
2 | # Error
3 | exec('x = 2')
| ^^^^^^^^^^^^^ S102
| ^^^^ S102
4 |
5 | exec('y = 3')
|
@@ -16,7 +16,7 @@ S102.py:5:1: S102 Use of `exec` detected
3 | exec('x = 2')
4 |
5 | exec('y = 3')
| ^^^^^^^^^^^^^ S102
| ^^^^ S102
|

View File

@@ -0,0 +1,20 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S307.py:3:7: S307 Use of possibly insecure function; consider using `ast.literal_eval`
|
1 | import os
2 |
3 | print(eval("1+1")) # S307
| ^^^^^^^^^^^ S307
4 | print(eval("os.getcwd()")) # S307
|
S307.py:4:7: S307 Use of possibly insecure function; consider using `ast.literal_eval`
|
3 | print(eval("1+1")) # S307
4 | print(eval("os.getcwd()")) # S307
| ^^^^^^^^^^^^^^^^^^^ S307
|

View File

@@ -42,16 +42,16 @@ impl AlwaysAutofixableViolation for BadQuotesInlineString {
fn message(&self) -> String {
let BadQuotesInlineString { quote } = self;
match quote {
Quote::Single => format!("Double quotes found but single quotes preferred"),
Quote::Double => format!("Single quotes found but double quotes preferred"),
Quote::Single => format!("Double quotes found but single quotes preferred"),
}
}
fn autofix_title(&self) -> String {
let BadQuotesInlineString { quote } = self;
match quote {
Quote::Single => "Replace double quotes with single quotes".to_string(),
Quote::Double => "Replace single quotes with double quotes".to_string(),
Quote::Single => "Replace double quotes with single quotes".to_string(),
}
}
}
@@ -91,16 +91,16 @@ impl AlwaysAutofixableViolation for BadQuotesMultilineString {
fn message(&self) -> String {
let BadQuotesMultilineString { quote } = self;
match quote {
Quote::Single => format!("Double quote multiline found but single quotes preferred"),
Quote::Double => format!("Single quote multiline found but double quotes preferred"),
Quote::Single => format!("Double quote multiline found but single quotes preferred"),
}
}
fn autofix_title(&self) -> String {
let BadQuotesMultilineString { quote } = self;
match quote {
Quote::Single => "Replace double multiline quotes with single quotes".to_string(),
Quote::Double => "Replace single multiline quotes with double quotes".to_string(),
Quote::Single => "Replace double multiline quotes with single quotes".to_string(),
}
}
}
@@ -139,16 +139,16 @@ impl AlwaysAutofixableViolation for BadQuotesDocstring {
fn message(&self) -> String {
let BadQuotesDocstring { quote } = self;
match quote {
Quote::Single => format!("Double quote docstring found but single quotes preferred"),
Quote::Double => format!("Single quote docstring found but double quotes preferred"),
Quote::Single => format!("Double quote docstring found but single quotes preferred"),
}
}
fn autofix_title(&self) -> String {
let BadQuotesDocstring { quote } = self;
match quote {
Quote::Single => "Replace double quotes docstring with single quotes".to_string(),
Quote::Double => "Replace single quotes docstring with double quotes".to_string(),
Quote::Single => "Replace double quotes docstring with single quotes".to_string(),
}
}
}
@@ -186,8 +186,8 @@ impl AlwaysAutofixableViolation for AvoidableEscapedQuote {
const fn good_single(quote: Quote) -> char {
match quote {
Quote::Single => '\'',
Quote::Double => '"',
Quote::Single => '\'',
}
}
@@ -200,22 +200,22 @@ const fn bad_single(quote: Quote) -> char {
const fn good_multiline(quote: Quote) -> &'static str {
match quote {
Quote::Single => "'''",
Quote::Double => "\"\"\"",
Quote::Single => "'''",
}
}
const fn good_multiline_ending(quote: Quote) -> &'static str {
match quote {
Quote::Single => "'\"\"\"",
Quote::Double => "\"'''",
Quote::Single => "'\"\"\"",
}
}
const fn good_docstring(quote: Quote) -> &'static str {
match quote {
Quote::Single => "'",
Quote::Double => "\"",
Quote::Single => "'",
}
}

View File

@@ -8,10 +8,10 @@ use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions};
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Quote {
/// Use single quotes.
Single,
/// Use double quotes.
Double,
/// Use single quotes.
Single,
}
impl Default for Quote {

View File

@@ -327,7 +327,7 @@ mod tests {
fn contents(contents: &str, snapshot: &str) {
let diagnostics = test_snippet(
contents,
&settings::Settings::for_rules(&Linter::Flake8TypeChecking),
&settings::Settings::for_rules(Linter::Flake8TypeChecking.rules()),
);
assert_messages!(snapshot, diagnostics);
}

View File

@@ -353,8 +353,10 @@ mod tests {
"PD901_fail_df_var"
)]
fn contents(contents: &str, snapshot: &str) {
let diagnostics =
test_snippet(contents, &settings::Settings::for_rules(&Linter::PandasVet));
let diagnostics = test_snippet(
contents,
&settings::Settings::for_rules(Linter::PandasVet.rules()),
);
assert_messages!(snapshot, diagnostics);
}

View File

@@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Expr, Stmt};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::any_over_expr;
use crate::checkers::ast::Checker;
@@ -52,6 +53,10 @@ impl Violation for ManualListComprehension {
/// PERF401
pub(crate) fn manual_list_comprehension(checker: &mut Checker, target: &Expr, body: &[Stmt]) {
let Expr::Name(ast::ExprName { id, .. }) = target else {
return;
};
let (stmt, conditional) = match body {
// ```python
// for x in y:
@@ -99,22 +104,27 @@ pub(crate) fn manual_list_comprehension(checker: &mut Checker, target: &Expr, bo
// Ignore direct list copies (e.g., `for x in y: filtered.append(x)`).
if !conditional {
if arg.as_name_expr().map_or(false, |arg| {
target
.as_name_expr()
.map_or(false, |target| arg.id == target.id)
}) {
if arg.as_name_expr().map_or(false, |arg| arg.id == *id) {
return;
}
}
let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func.as_ref() else {
let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else {
return;
};
if attr.as_str() == "append" {
checker
.diagnostics
.push(Diagnostic::new(ManualListComprehension, *range));
if attr.as_str() != "append" {
return;
}
// Avoid, e.g., `for x in y: filtered[x].append(x * x)`.
if any_over_expr(value, &|expr| {
expr.as_name_expr().map_or(false, |expr| expr.id == *id)
}) {
return;
}
checker
.diagnostics
.push(Diagnostic::new(ManualListComprehension, *range));
}

View File

@@ -2,6 +2,7 @@ use rustpython_parser::ast::{self, Expr, Stmt};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::any_over_expr;
use crate::checkers::ast::Checker;
@@ -45,6 +46,10 @@ impl Violation for ManualListCopy {
/// PERF402
pub(crate) fn manual_list_copy(checker: &mut Checker, target: &Expr, body: &[Stmt]) {
let Expr::Name(ast::ExprName { id, .. }) = target else {
return;
};
let [stmt] = body else {
return;
};
@@ -72,21 +77,26 @@ pub(crate) fn manual_list_copy(checker: &mut Checker, target: &Expr, body: &[Stm
};
// Only flag direct list copies (e.g., `for x in y: filtered.append(x)`).
if !arg.as_name_expr().map_or(false, |arg| {
target
.as_name_expr()
.map_or(false, |target| arg.id == target.id)
if !arg.as_name_expr().map_or(false, |arg| arg.id == *id) {
return;
}
let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else {
return;
};
if !matches!(attr.as_str(), "append" | "insert") {
return;
}
// Avoid, e.g., `for x in y: filtered[x].append(x * x)`.
if any_over_expr(value, &|expr| {
expr.as_name_expr().map_or(false, |expr| expr.id == *id)
}) {
return;
}
let Expr::Attribute(ast::ExprAttribute { attr, .. }) = func.as_ref() else {
return;
};
if matches!(attr.as_str(), "append" | "insert") {
checker
.diagnostics
.push(Diagnostic::new(ManualListCopy, *range));
}
checker
.diagnostics
.push(Diagnostic::new(ManualListCopy, *range));
}

View File

@@ -490,7 +490,7 @@ mod tests {
"load_after_unbind_from_class_scope"
)]
fn contents(contents: &str, snapshot: &str) {
let diagnostics = test_snippet(contents, &Settings::for_rules(&Linter::Pyflakes));
let diagnostics = test_snippet(contents, &Settings::for_rules(Linter::Pyflakes.rules()));
assert_messages!(snapshot, diagnostics);
}
@@ -498,7 +498,7 @@ mod tests {
/// Note that all tests marked with `#[ignore]` should be considered TODOs.
fn flakes(contents: &str, expected: &[Rule]) {
let contents = dedent(contents);
let settings = Settings::for_rules(&Linter::Pyflakes);
let settings = Settings::for_rules(Linter::Pyflakes.rules());
let tokens: Vec<LexResult> = ruff_rustpython::tokenize(&contents);
let locator = Locator::new(&contents);
let stylist = Stylist::from_tokens(&tokens, &locator);

View File

@@ -85,6 +85,7 @@ mod tests {
Path::new("too_many_return_statements.py")
)]
#[test_case(Rule::TooManyStatements, Path::new("too_many_statements.py"))]
#[test_case(Rule::TypeParamNameMismatch, Path::new("type_param_name_mismatch.py"))]
#[test_case(
Rule::UnexpectedSpecialMethodSignature,
Path::new("unexpected_special_method_signature.py")

View File

@@ -37,6 +37,7 @@ pub(crate) use too_many_arguments::*;
pub(crate) use too_many_branches::*;
pub(crate) use too_many_return_statements::*;
pub(crate) use too_many_statements::*;
pub(crate) use type_param_name_mismatch::*;
pub(crate) use unexpected_special_method_signature::*;
pub(crate) use unnecessary_direct_lambda_call::*;
pub(crate) use useless_else_on_loop::*;
@@ -84,6 +85,7 @@ mod too_many_arguments;
mod too_many_branches;
mod too_many_return_statements;
mod too_many_statements;
mod type_param_name_mismatch;
mod unexpected_special_method_signature;
mod unnecessary_direct_lambda_call;
mod useless_else_on_loop;

View File

@@ -0,0 +1,166 @@
use std::fmt;
use rustpython_parser::ast::{self, Constant, Expr, Ranged};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for `TypeVar`, `TypeVarTuple`, `ParamSpec`, and `NewType`
/// definitions in which the name of the type parameter does not match the name
/// of the variable to which it is assigned.
///
/// ## Why is this bad?
/// When defining a `TypeVar` or a related type parameter, Python allows you to
/// provide a name for the type parameter. According to [PEP 484], the name
/// provided to the `TypeVar` constructor must be equal to the name of the
/// variable to which it is assigned.
///
/// ## Example
/// ```python
/// from typing import TypeVar
///
/// T = TypeVar("U")
/// ```
///
/// Use instead:
/// ```python
/// from typing import TypeVar
///
/// T = TypeVar("T")
/// ```
///
/// ## References
/// - [Python documentation: `typing` — Support for type hints](https://docs.python.org/3/library/typing.html)
/// - [PEP 484 Type Hints: Generics](https://peps.python.org/pep-0484/#generics)
///
/// [PEP 484]:https://peps.python.org/pep-0484/#generics
#[violation]
pub struct TypeParamNameMismatch {
kind: VarKind,
var_name: String,
param_name: String,
}
impl Violation for TypeParamNameMismatch {
#[derive_message_formats]
fn message(&self) -> String {
let TypeParamNameMismatch {
kind,
var_name,
param_name,
} = self;
format!("`{kind}` name `{param_name}` does not match assigned variable name `{var_name}`")
}
}
/// PLC0132
pub(crate) fn type_param_name_mismatch(checker: &mut Checker, value: &Expr, targets: &[Expr]) {
let [target] = targets else {
return;
};
let Expr::Name(ast::ExprName { id: var_name, .. }) = &target else {
return;
};
let Some(param_name) = param_name(value) else {
return;
};
if var_name == param_name {
return;
}
let Expr::Call(ast::ExprCall { func, .. }) = value else {
return;
};
let Some(kind) = checker
.semantic()
.resolve_call_path(func)
.and_then(|call_path| {
if checker
.semantic()
.match_typing_call_path(&call_path, "ParamSpec")
{
Some(VarKind::ParamSpec)
} else if checker
.semantic()
.match_typing_call_path(&call_path, "TypeVar")
{
Some(VarKind::TypeVar)
} else if checker
.semantic()
.match_typing_call_path(&call_path, "TypeVarTuple")
{
Some(VarKind::TypeVarTuple)
} else if checker
.semantic()
.match_typing_call_path(&call_path, "NewType")
{
Some(VarKind::NewType)
} else {
None
}
})
else {
return;
};
checker.diagnostics.push(Diagnostic::new(
TypeParamNameMismatch {
kind,
var_name: var_name.to_string(),
param_name: param_name.to_string(),
},
value.range(),
));
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum VarKind {
TypeVar,
ParamSpec,
TypeVarTuple,
NewType,
}
impl fmt::Display for VarKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
VarKind::TypeVar => fmt.write_str("TypeVar"),
VarKind::ParamSpec => fmt.write_str("ParamSpec"),
VarKind::TypeVarTuple => fmt.write_str("TypeVarTuple"),
VarKind::NewType => fmt.write_str("NewType"),
}
}
}
/// Returns the value of the `name` parameter to, e.g., a `TypeVar` constructor.
fn param_name(value: &Expr) -> Option<&str> {
// Handle both `TypeVar("T")` and `TypeVar(name="T")`.
let call = value.as_call_expr()?;
let name_param = call
.keywords
.iter()
.find(|keyword| {
keyword
.arg
.as_ref()
.map_or(false, |keyword| keyword.as_str() == "name")
})
.map(|keyword| &keyword.value)
.or_else(|| call.args.get(0))?;
if let Expr::Constant(ast::ExprConstant {
value: Constant::Str(name),
..
}) = &name_param
{
Some(name)
} else {
None
}
}

View File

@@ -0,0 +1,76 @@
---
source: crates/ruff/src/rules/pylint/mod.rs
---
type_param_name_mismatch.py:5:5: PLC0132 `TypeVar` name `T` does not match assigned variable name `X`
|
3 | # Errors.
4 |
5 | X = TypeVar("T")
| ^^^^^^^^^^^^ PLC0132
6 | X = TypeVar(name="T")
|
type_param_name_mismatch.py:6:5: PLC0132 `TypeVar` name `T` does not match assigned variable name `X`
|
5 | X = TypeVar("T")
6 | X = TypeVar(name="T")
| ^^^^^^^^^^^^^^^^^ PLC0132
7 |
8 | Y = ParamSpec("T")
|
type_param_name_mismatch.py:8:5: PLC0132 `ParamSpec` name `T` does not match assigned variable name `Y`
|
6 | X = TypeVar(name="T")
7 |
8 | Y = ParamSpec("T")
| ^^^^^^^^^^^^^^ PLC0132
9 | Y = ParamSpec(name="T")
|
type_param_name_mismatch.py:9:5: PLC0132 `ParamSpec` name `T` does not match assigned variable name `Y`
|
8 | Y = ParamSpec("T")
9 | Y = ParamSpec(name="T")
| ^^^^^^^^^^^^^^^^^^^ PLC0132
10 |
11 | Z = NewType("T", int)
|
type_param_name_mismatch.py:11:5: PLC0132 `NewType` name `T` does not match assigned variable name `Z`
|
9 | Y = ParamSpec(name="T")
10 |
11 | Z = NewType("T", int)
| ^^^^^^^^^^^^^^^^^ PLC0132
12 | Z = NewType(name="T", tp=int)
|
type_param_name_mismatch.py:12:5: PLC0132 `NewType` name `T` does not match assigned variable name `Z`
|
11 | Z = NewType("T", int)
12 | Z = NewType(name="T", tp=int)
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLC0132
13 |
14 | Ws = TypeVarTuple("Ts")
|
type_param_name_mismatch.py:14:6: PLC0132 `TypeVarTuple` name `Ts` does not match assigned variable name `Ws`
|
12 | Z = NewType(name="T", tp=int)
13 |
14 | Ws = TypeVarTuple("Ts")
| ^^^^^^^^^^^^^^^^^^ PLC0132
15 | Ws = TypeVarTuple(name="Ts")
|
type_param_name_mismatch.py:15:6: PLC0132 `TypeVarTuple` name `Ts` does not match assigned variable name `Ws`
|
14 | Ws = TypeVarTuple("Ts")
15 | Ws = TypeVarTuple(name="Ts")
| ^^^^^^^^^^^^^^^^^^^^^^^ PLC0132
16 |
17 | # Non-errors.
|

View File

@@ -30,6 +30,10 @@ mod tests {
#[test_case(Rule::MutableDataclassDefault, Path::new("RUF008.py"))]
#[test_case(Rule::PairwiseOverZipped, Path::new("RUF007.py"))]
#[test_case(Rule::StaticKeyDictComprehension, Path::new("RUF011.py"))]
#[cfg_attr(
feature = "unreachable-code",
test_case(Rule::UnreachableCode, Path::new("RUF014.py"))
)]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(

View File

@@ -9,6 +9,8 @@ pub(crate) use mutable_class_default::*;
pub(crate) use mutable_dataclass_default::*;
pub(crate) use pairwise_over_zipped::*;
pub(crate) use static_key_dict_comprehension::*;
#[cfg(feature = "unreachable-code")]
pub(crate) use unreachable::*;
pub(crate) use unused_noqa::*;
mod ambiguous_unicode_character;
@@ -24,6 +26,8 @@ mod mutable_class_default;
mod mutable_dataclass_default;
mod pairwise_over_zipped;
mod static_key_dict_comprehension;
#[cfg(feature = "unreachable-code")]
pub(crate) mod unreachable;
mod unused_noqa;
#[derive(Clone, Copy)]

View File

@@ -0,0 +1,97 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
assert True
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert True\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 1
### Source
```python
def func():
assert False
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert False\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func():
assert True, "oops"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert True, #quot;oops#quot;\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 3
### Source
```python
def func():
assert False, "oops"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Exception raised"]]
block2["assert False, #quot;oops#quot;\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```

View File

@@ -0,0 +1,241 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
async for i in range(5):
print(i)
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(i)\n"]
block2["async for i in range(5):
print(i)\n"]
start --> block2
block2 -- "range(5)" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 1
### Source
```python
def func():
async for i in range(20):
print(i)
else:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["print(i)\n"]
block1["return 0\n"]
block2["async for i in range(20):
print(i)
else:
return 0\n"]
start --> block2
block2 -- "range(20)" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func():
async for i in range(10):
if i == 5:
return 1
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["if i == 5:
return 1\n"]
block3["async for i in range(10):
if i == 5:
return 1\n"]
start --> block3
block3 -- "range(10)" --> block2
block3 -- "else" --> block0
block2 -- "i == 5" --> block1
block2 -- "else" --> block3
block1 --> return
block0 --> return
```
## Function 3
### Source
```python
def func():
async for i in range(111):
if i == 5:
return 1
else:
return 0
return 2
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 2\n"]
block1["return 1\n"]
block2["if i == 5:
return 1\n"]
block3["return 0\n"]
block4["async for i in range(111):
if i == 5:
return 1
else:
return 0\n"]
start --> block4
block4 -- "range(111)" --> block2
block4 -- "else" --> block3
block3 --> return
block2 -- "i == 5" --> block1
block2 -- "else" --> block4
block1 --> return
block0 --> return
```
## Function 4
### Source
```python
def func():
async for i in range(12):
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["async for i in range(12):
continue\n"]
start --> block2
block2 -- "range(12)" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 5
### Source
```python
def func():
async for i in range(1110):
if True:
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["if True:
continue\n"]
block3["async for i in range(1110):
if True:
continue\n"]
start --> block3
block3 -- "range(1110)" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block3
block0 --> return
```
## Function 6
### Source
```python
def func():
async for i in range(13):
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["async for i in range(13):
break\n"]
start --> block2
block2 -- "range(13)" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```
## Function 7
### Source
```python
def func():
async for i in range(1110):
if True:
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["if True:
break\n"]
block3["async for i in range(1110):
if True:
break\n"]
start --> block3
block3 -- "range(1110)" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block0
block0 --> return
```

View File

@@ -0,0 +1,241 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
for i in range(5):
print(i)
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(i)\n"]
block2["for i in range(5):
print(i)\n"]
start --> block2
block2 -- "range(5)" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 1
### Source
```python
def func():
for i in range(20):
print(i)
else:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["print(i)\n"]
block1["return 0\n"]
block2["for i in range(20):
print(i)
else:
return 0\n"]
start --> block2
block2 -- "range(20)" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func():
for i in range(10):
if i == 5:
return 1
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["if i == 5:
return 1\n"]
block3["for i in range(10):
if i == 5:
return 1\n"]
start --> block3
block3 -- "range(10)" --> block2
block3 -- "else" --> block0
block2 -- "i == 5" --> block1
block2 -- "else" --> block3
block1 --> return
block0 --> return
```
## Function 3
### Source
```python
def func():
for i in range(111):
if i == 5:
return 1
else:
return 0
return 2
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 2\n"]
block1["return 1\n"]
block2["if i == 5:
return 1\n"]
block3["return 0\n"]
block4["for i in range(111):
if i == 5:
return 1
else:
return 0\n"]
start --> block4
block4 -- "range(111)" --> block2
block4 -- "else" --> block3
block3 --> return
block2 -- "i == 5" --> block1
block2 -- "else" --> block4
block1 --> return
block0 --> return
```
## Function 4
### Source
```python
def func():
for i in range(12):
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["for i in range(12):
continue\n"]
start --> block2
block2 -- "range(12)" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 5
### Source
```python
def func():
for i in range(1110):
if True:
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["if True:
continue\n"]
block3["for i in range(1110):
if True:
continue\n"]
start --> block3
block3 -- "range(1110)" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block3
block0 --> return
```
## Function 6
### Source
```python
def func():
for i in range(13):
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["for i in range(13):
break\n"]
start --> block2
block2 -- "range(13)" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```
## Function 7
### Source
```python
def func():
for i in range(1110):
if True:
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["if True:
break\n"]
block3["for i in range(1110):
if True:
break\n"]
start --> block3
block3 -- "range(1110)" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block0
block0 --> return
```

View File

@@ -0,0 +1,535 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
if False:
return 0
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return 0\n"]
block2["if False:
return 0\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 1
### Source
```python
def func():
if True:
return 1
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["if True:
return 1\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func():
if False:
return 0
else:
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["if False:
return 0
else:
return 1\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 3
### Source
```python
def func():
if True:
return 1
else:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return 0\n"]
block2["if True:
return 1
else:
return 0\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 4
### Source
```python
def func():
if False:
return 0
else:
return 1
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 0\n"]
block2["return 1\n"]
block3["if False:
return 0
else:
return 1\n"]
start --> block3
block3 -- "False" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 5
### Source
```python
def func():
if True:
return 1
else:
return 0
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 1\n"]
block2["return 0\n"]
block3["if True:
return 1
else:
return 0\n"]
start --> block3
block3 -- "True" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 6
### Source
```python
def func():
if True:
if True:
return 1
return 2
else:
return 3
return "unreachable2"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable2#quot;\n"]
block1["return 2\n"]
block2["return 1\n"]
block3["if True:
return 1\n"]
block4["return 3\n"]
block5["if True:
if True:
return 1
return 2
else:
return 3\n"]
start --> block5
block5 -- "True" --> block3
block5 -- "else" --> block4
block4 --> return
block3 -- "True" --> block2
block3 -- "else" --> block1
block2 --> return
block1 --> return
block0 --> return
```
## Function 7
### Source
```python
def func():
if False:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["return 0\n"]
block2["if False:
return 0\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 8
### Source
```python
def func():
if True:
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["return 1\n"]
block2["if True:
return 1\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 9
### Source
```python
def func():
if True:
return 1
elif False:
return 2
else:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return 2\n"]
block2["return 0\n"]
block3["elif False:
return 2
else:
return 0\n"]
block4["if True:
return 1
elif False:
return 2
else:
return 0\n"]
start --> block4
block4 -- "True" --> block0
block4 -- "else" --> block3
block3 -- "False" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 10
### Source
```python
def func():
if False:
return 1
elif True:
return 2
else:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return 2\n"]
block2["return 0\n"]
block3["elif True:
return 2
else:
return 0\n"]
block4["if False:
return 1
elif True:
return 2
else:
return 0\n"]
start --> block4
block4 -- "False" --> block0
block4 -- "else" --> block3
block3 -- "True" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 11
### Source
```python
def func():
if True:
if False:
return 0
elif True:
return 1
else:
return 2
return 3
elif True:
return 4
else:
return 5
return 6
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 6\n"]
block1["return 3\n"]
block2["return 0\n"]
block3["return 1\n"]
block4["return 2\n"]
block5["elif True:
return 1
else:
return 2\n"]
block6["if False:
return 0
elif True:
return 1
else:
return 2\n"]
block7["return 4\n"]
block8["return 5\n"]
block9["elif True:
return 4
else:
return 5\n"]
block10["if True:
if False:
return 0
elif True:
return 1
else:
return 2
return 3
elif True:
return 4
else:
return 5\n"]
start --> block10
block10 -- "True" --> block6
block10 -- "else" --> block9
block9 -- "True" --> block7
block9 -- "else" --> block8
block8 --> return
block7 --> return
block6 -- "False" --> block2
block6 -- "else" --> block5
block5 -- "True" --> block3
block5 -- "else" --> block4
block4 --> return
block3 --> return
block2 --> return
block1 --> return
block0 --> return
```
## Function 12
### Source
```python
def func():
if False:
return "unreached"
elif False:
return "also unreached"
return "reached"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;reached#quot;\n"]
block1["return #quot;unreached#quot;\n"]
block2["return #quot;also unreached#quot;\n"]
block3["elif False:
return #quot;also unreached#quot;\n"]
block4["if False:
return #quot;unreached#quot;
elif False:
return #quot;also unreached#quot;\n"]
start --> block4
block4 -- "False" --> block1
block4 -- "else" --> block3
block3 -- "False" --> block2
block3 -- "else" --> block0
block2 --> return
block1 --> return
block0 --> return
```
## Function 13
### Source
```python
def func(self, obj: BytesRep) -> bytes:
data = obj["data"]
if isinstance(data, str):
return base64.b64decode(data)
elif isinstance(data, Buffer):
buffer = data
else:
id = data["id"]
if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f"can't resolve buffer '{id}'")
return buffer.data
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return buffer.data\n"]
block1["return base64.b64decode(data)\n"]
block2["buffer = data\n"]
block3["buffer = self._buffers[id]\n"]
block4["self.error(f#quot;can't resolve buffer '{id}'#quot;)\n"]
block5["id = data[#quot;id#quot;]\nif id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f#quot;can't resolve buffer '{id}'#quot;)\n"]
block6["elif isinstance(data, Buffer):
buffer = data
else:
id = data[#quot;id#quot;]
if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f#quot;can't resolve buffer '{id}'#quot;)\n"]
block7["data = obj[#quot;data#quot;]\nif isinstance(data, str):
return base64.b64decode(data)
elif isinstance(data, Buffer):
buffer = data
else:
id = data[#quot;id#quot;]
if id in self._buffers:
buffer = self._buffers[id]
else:
self.error(f#quot;can't resolve buffer '{id}'#quot;)\n"]
start --> block7
block7 -- "isinstance(data, str)" --> block1
block7 -- "else" --> block6
block6 -- "isinstance(data, Buffer)" --> block2
block6 -- "else" --> block5
block5 -- "id in self._buffers" --> block3
block5 -- "else" --> block4
block4 --> block0
block3 --> block0
block2 --> block0
block1 --> return
block0 --> return
```

View File

@@ -0,0 +1,776 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func(status):
match status:
case _:
return 0
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 0\n"]
block2["match status:
case _:
return 0\n"]
start --> block2
block2 --> block1
block1 --> return
block0 --> return
```
## Function 1
### Source
```python
def func(status):
match status:
case 1:
return 1
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["match status:
case 1:
return 1\n"]
start --> block2
block2 -- "case 1" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func(status):
match status:
case 1:
return 1
case _:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["match status:
case 1:
return 1
case _:
return 0\n"]
block2["return 1\n"]
block3["match status:
case 1:
return 1
case _:
return 0\n"]
start --> block3
block3 -- "case 1" --> block2
block3 -- "else" --> block1
block2 --> return
block1 --> block0
block0 --> return
```
## Function 3
### Source
```python
def func(status):
match status:
case 1 | 2 | 3:
return 5
return 6
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 6\n"]
block1["return 5\n"]
block2["match status:
case 1 | 2 | 3:
return 5\n"]
start --> block2
block2 -- "case 1 | 2 | 3" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 4
### Source
```python
def func(status):
match status:
case 1 | 2 | 3:
return 5
case _:
return 10
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 10\n"]
block2["match status:
case 1 | 2 | 3:
return 5
case _:
return 10\n"]
block3["return 5\n"]
block4["match status:
case 1 | 2 | 3:
return 5
case _:
return 10\n"]
start --> block4
block4 -- "case 1 | 2 | 3" --> block3
block4 -- "else" --> block2
block3 --> return
block2 --> block1
block1 --> return
block0 --> return
```
## Function 5
### Source
```python
def func(status):
match status:
case 0:
return 0
case 1:
return 1
case 1:
return "1 again"
case _:
return 3
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 3\n"]
block1["match status:
case 0:
return 0
case 1:
return 1
case 1:
return #quot;1 again#quot;
case _:
return 3\n"]
block2["return #quot;1 again#quot;\n"]
block3["match status:
case 0:
return 0
case 1:
return 1
case 1:
return #quot;1 again#quot;
case _:
return 3\n"]
block4["return 1\n"]
block5["match status:
case 0:
return 0
case 1:
return 1
case 1:
return #quot;1 again#quot;
case _:
return 3\n"]
block6["return 0\n"]
block7["match status:
case 0:
return 0
case 1:
return 1
case 1:
return #quot;1 again#quot;
case _:
return 3\n"]
start --> block7
block7 -- "case 0" --> block6
block7 -- "else" --> block5
block6 --> return
block5 -- "case 1" --> block4
block5 -- "else" --> block3
block4 --> return
block3 -- "case 1" --> block2
block3 -- "else" --> block1
block2 --> return
block1 --> block0
block0 --> return
```
## Function 6
### Source
```python
def func(status):
i = 0
match status, i:
case _, _:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["return 0\n"]
block2["match status, i:
case _, _:
return 0\n"]
block3["i = 0\n"]
start --> block3
block3 --> block2
block2 -- "case _, _" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 7
### Source
```python
def func(status):
i = 0
match status, i:
case _, 0:
return 0
case _, 2:
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["return 0\n"]
block2["match status, i:
case _, 0:
return 0
case _, 2:
return 0\n"]
block3["return 0\n"]
block4["match status, i:
case _, 0:
return 0
case _, 2:
return 0\n"]
block5["i = 0\n"]
start --> block5
block5 --> block4
block4 -- "case _, 0" --> block3
block4 -- "else" --> block2
block3 --> return
block2 -- "case _, 2" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 8
### Source
```python
def func(point):
match point:
case (0, 0):
print("Origin")
case _:
raise ValueError("oops")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["raise ValueError(#quot;oops#quot;)\n"]
block2["match point:
case (0, 0):
print(#quot;Origin#quot;)
case _:
raise ValueError(#quot;oops#quot;)\n"]
block3["print(#quot;Origin#quot;)\n"]
block4["match point:
case (0, 0):
print(#quot;Origin#quot;)
case _:
raise ValueError(#quot;oops#quot;)\n"]
start --> block4
block4 -- "case (0, 0)" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 --> block1
block1 --> return
block0 --> return
```
## Function 9
### Source
```python
def func(point):
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["raise ValueError(#quot;Not a point#quot;)\n"]
block2["match point:
case (0, 0):
print(#quot;Origin#quot;)
case (0, y):
print(f#quot;Y={y}#quot;)
case (x, 0):
print(f#quot;X={x}#quot;)
case (x, y):
print(f#quot;X={x}, Y={y}#quot;)
case _:
raise ValueError(#quot;Not a point#quot;)\n"]
block3["print(f#quot;X={x}, Y={y}#quot;)\n"]
block4["match point:
case (0, 0):
print(#quot;Origin#quot;)
case (0, y):
print(f#quot;Y={y}#quot;)
case (x, 0):
print(f#quot;X={x}#quot;)
case (x, y):
print(f#quot;X={x}, Y={y}#quot;)
case _:
raise ValueError(#quot;Not a point#quot;)\n"]
block5["print(f#quot;X={x}#quot;)\n"]
block6["match point:
case (0, 0):
print(#quot;Origin#quot;)
case (0, y):
print(f#quot;Y={y}#quot;)
case (x, 0):
print(f#quot;X={x}#quot;)
case (x, y):
print(f#quot;X={x}, Y={y}#quot;)
case _:
raise ValueError(#quot;Not a point#quot;)\n"]
block7["print(f#quot;Y={y}#quot;)\n"]
block8["match point:
case (0, 0):
print(#quot;Origin#quot;)
case (0, y):
print(f#quot;Y={y}#quot;)
case (x, 0):
print(f#quot;X={x}#quot;)
case (x, y):
print(f#quot;X={x}, Y={y}#quot;)
case _:
raise ValueError(#quot;Not a point#quot;)\n"]
block9["print(#quot;Origin#quot;)\n"]
block10["match point:
case (0, 0):
print(#quot;Origin#quot;)
case (0, y):
print(f#quot;Y={y}#quot;)
case (x, 0):
print(f#quot;X={x}#quot;)
case (x, y):
print(f#quot;X={x}, Y={y}#quot;)
case _:
raise ValueError(#quot;Not a point#quot;)\n"]
start --> block10
block10 -- "case (0, 0)" --> block9
block10 -- "else" --> block8
block9 --> block0
block8 -- "case (0, y)" --> block7
block8 -- "else" --> block6
block7 --> block0
block6 -- "case (x, 0)" --> block5
block6 -- "else" --> block4
block5 --> block0
block4 -- "case (x, y)" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 --> block1
block1 --> return
block0 --> return
```
## Function 10
### Source
```python
def where_is(point):
class Point:
x: int
y: int
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(#quot;Not a point#quot;)\n"]
block2["match point:
case Point(x=0, y=0):
print(#quot;Origin#quot;)
case Point(x=0, y=y):
print(f#quot;Y={y}#quot;)
case Point(x=x, y=0):
print(f#quot;X={x}#quot;)
case Point():
print(#quot;Somewhere else#quot;)
case _:
print(#quot;Not a point#quot;)\n"]
block3["print(#quot;Somewhere else#quot;)\n"]
block4["match point:
case Point(x=0, y=0):
print(#quot;Origin#quot;)
case Point(x=0, y=y):
print(f#quot;Y={y}#quot;)
case Point(x=x, y=0):
print(f#quot;X={x}#quot;)
case Point():
print(#quot;Somewhere else#quot;)
case _:
print(#quot;Not a point#quot;)\n"]
block5["print(f#quot;X={x}#quot;)\n"]
block6["match point:
case Point(x=0, y=0):
print(#quot;Origin#quot;)
case Point(x=0, y=y):
print(f#quot;Y={y}#quot;)
case Point(x=x, y=0):
print(f#quot;X={x}#quot;)
case Point():
print(#quot;Somewhere else#quot;)
case _:
print(#quot;Not a point#quot;)\n"]
block7["print(f#quot;Y={y}#quot;)\n"]
block8["match point:
case Point(x=0, y=0):
print(#quot;Origin#quot;)
case Point(x=0, y=y):
print(f#quot;Y={y}#quot;)
case Point(x=x, y=0):
print(f#quot;X={x}#quot;)
case Point():
print(#quot;Somewhere else#quot;)
case _:
print(#quot;Not a point#quot;)\n"]
block9["print(#quot;Origin#quot;)\n"]
block10["match point:
case Point(x=0, y=0):
print(#quot;Origin#quot;)
case Point(x=0, y=y):
print(f#quot;Y={y}#quot;)
case Point(x=x, y=0):
print(f#quot;X={x}#quot;)
case Point():
print(#quot;Somewhere else#quot;)
case _:
print(#quot;Not a point#quot;)\n"]
block11["class Point:
x: int
y: int\n"]
start --> block11
block11 --> block10
block10 -- "case Point(x=0, y=0)" --> block9
block10 -- "else" --> block8
block9 --> block0
block8 -- "case Point(x=0, y=y)" --> block7
block8 -- "else" --> block6
block7 --> block0
block6 -- "case Point(x=x, y=0)" --> block5
block6 -- "else" --> block4
block5 --> block0
block4 -- "case Point()" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 --> block1
block1 --> block0
block0 --> return
```
## Function 11
### Source
```python
def func(points):
match points:
case []:
print("No points")
case [Point(0, 0)]:
print("The origin")
case [Point(x, y)]:
print(f"Single point {x}, {y}")
case [Point(0, y1), Point(0, y2)]:
print(f"Two on the Y axis at {y1}, {y2}")
case _:
print("Something else")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(#quot;Something else#quot;)\n"]
block2["match points:
case []:
print(#quot;No points#quot;)
case [Point(0, 0)]:
print(#quot;The origin#quot;)
case [Point(x, y)]:
print(f#quot;Single point {x}, {y}#quot;)
case [Point(0, y1), Point(0, y2)]:
print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)
case _:
print(#quot;Something else#quot;)\n"]
block3["print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)\n"]
block4["match points:
case []:
print(#quot;No points#quot;)
case [Point(0, 0)]:
print(#quot;The origin#quot;)
case [Point(x, y)]:
print(f#quot;Single point {x}, {y}#quot;)
case [Point(0, y1), Point(0, y2)]:
print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)
case _:
print(#quot;Something else#quot;)\n"]
block5["print(f#quot;Single point {x}, {y}#quot;)\n"]
block6["match points:
case []:
print(#quot;No points#quot;)
case [Point(0, 0)]:
print(#quot;The origin#quot;)
case [Point(x, y)]:
print(f#quot;Single point {x}, {y}#quot;)
case [Point(0, y1), Point(0, y2)]:
print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)
case _:
print(#quot;Something else#quot;)\n"]
block7["print(#quot;The origin#quot;)\n"]
block8["match points:
case []:
print(#quot;No points#quot;)
case [Point(0, 0)]:
print(#quot;The origin#quot;)
case [Point(x, y)]:
print(f#quot;Single point {x}, {y}#quot;)
case [Point(0, y1), Point(0, y2)]:
print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)
case _:
print(#quot;Something else#quot;)\n"]
block9["print(#quot;No points#quot;)\n"]
block10["match points:
case []:
print(#quot;No points#quot;)
case [Point(0, 0)]:
print(#quot;The origin#quot;)
case [Point(x, y)]:
print(f#quot;Single point {x}, {y}#quot;)
case [Point(0, y1), Point(0, y2)]:
print(f#quot;Two on the Y axis at {y1}, {y2}#quot;)
case _:
print(#quot;Something else#quot;)\n"]
start --> block10
block10 -- "case []" --> block9
block10 -- "else" --> block8
block9 --> block0
block8 -- "case [Point(0, 0)]" --> block7
block8 -- "else" --> block6
block7 --> block0
block6 -- "case [Point(x, y)]" --> block5
block6 -- "else" --> block4
block5 --> block0
block4 -- "case [Point(0, y1), Point(0, y2)]" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 --> block1
block1 --> block0
block0 --> return
```
## Function 12
### Source
```python
def func(point):
match point:
case Point(x, y) if x == y:
print(f"Y=X at {x}")
case Point(x, y):
print(f"Not on the diagonal")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(f#quot;Not on the diagonal#quot;)\n"]
block2["match point:
case Point(x, y) if x == y:
print(f#quot;Y=X at {x}#quot;)
case Point(x, y):
print(f#quot;Not on the diagonal#quot;)\n"]
block3["print(f#quot;Y=X at {x}#quot;)\n"]
block4["match point:
case Point(x, y) if x == y:
print(f#quot;Y=X at {x}#quot;)
case Point(x, y):
print(f#quot;Not on the diagonal#quot;)\n"]
start --> block4
block4 -- "case Point(x, y) if x == y" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 -- "case Point(x, y)" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```
## Function 13
### Source
```python
def func():
from enum import Enum
class Color(Enum):
RED = 'red'
GREEN = 'green'
BLUE = 'blue'
color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))
match color:
case Color.RED:
print("I see red!")
case Color.GREEN:
print("Grass is green")
case Color.BLUE:
print("I'm feeling the blues :(")
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["print(#quot;I'm feeling the blues :(#quot;)\n"]
block2["match color:
case Color.RED:
print(#quot;I see red!#quot;)
case Color.GREEN:
print(#quot;Grass is green#quot;)
case Color.BLUE:
print(#quot;I'm feeling the blues :(#quot;)\n"]
block3["print(#quot;Grass is green#quot;)\n"]
block4["match color:
case Color.RED:
print(#quot;I see red!#quot;)
case Color.GREEN:
print(#quot;Grass is green#quot;)
case Color.BLUE:
print(#quot;I'm feeling the blues :(#quot;)\n"]
block5["print(#quot;I see red!#quot;)\n"]
block6["match color:
case Color.RED:
print(#quot;I see red!#quot;)
case Color.GREEN:
print(#quot;Grass is green#quot;)
case Color.BLUE:
print(#quot;I'm feeling the blues :(#quot;)\n"]
block7["from enum import Enum\nclass Color(Enum):
RED = 'red'
GREEN = 'green'
BLUE = 'blue'\ncolor = Color(input(#quot;Enter your choice of 'red', 'blue' or 'green': #quot;))\n"]
start --> block7
block7 --> block6
block6 -- "case Color.RED" --> block5
block6 -- "else" --> block4
block5 --> block0
block4 -- "case Color.GREEN" --> block3
block4 -- "else" --> block2
block3 --> block0
block2 -- "case Color.BLUE" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```

View File

@@ -0,0 +1,41 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
raise Exception
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["raise Exception\n"]
start --> block0
block0 --> return
```
## Function 1
### Source
```python
def func():
raise "a glass!"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["raise #quot;a glass!#quot;\n"]
start --> block0
block0 --> return
```

View File

@@ -0,0 +1,136 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
pass
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["pass\n"]
start --> block0
block0 --> return
```
## Function 1
### Source
```python
def func():
pass
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["pass\n"]
start --> block0
block0 --> return
```
## Function 2
### Source
```python
def func():
return
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return\n"]
start --> block0
block0 --> return
```
## Function 3
### Source
```python
def func():
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
start --> block0
block0 --> return
```
## Function 4
### Source
```python
def func():
return 1
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 1\n"]
start --> block1
block1 --> return
block0 --> return
```
## Function 5
### Source
```python
def func():
i = 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["i = 0\n"]
start --> block0
block0 --> return
```
## Function 6
### Source
```python
def func():
i = 0
i += 2
return i
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["i = 0\ni += 2\nreturn i\n"]
start --> block0
block0 --> return
```

View File

@@ -0,0 +1,527 @@
---
source: crates/ruff/src/rules/ruff/rules/unreachable.rs
description: "This is a Mermaid graph. You can use https://mermaid.live to visualize it as a diagram."
---
## Function 0
### Source
```python
def func():
while False:
return "unreachable"
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return #quot;unreachable#quot;\n"]
block2["while False:
return #quot;unreachable#quot;\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 1
### Source
```python
def func():
while False:
return "unreachable"
else:
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 1\n"]
block2["while False:
return #quot;unreachable#quot;
else:
return 1\n"]
start --> block2
block2 -- "False" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 2
### Source
```python
def func():
while False:
return "unreachable"
else:
return 1
return "also unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;also unreachable#quot;\n"]
block1["return #quot;unreachable#quot;\n"]
block2["return 1\n"]
block3["while False:
return #quot;unreachable#quot;
else:
return 1\n"]
start --> block3
block3 -- "False" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 3
### Source
```python
def func():
while True:
return 1
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;unreachable#quot;\n"]
block1["return 1\n"]
block2["while True:
return 1\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> return
block0 --> return
```
## Function 4
### Source
```python
def func():
while True:
return 1
else:
return "unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["return #quot;unreachable#quot;\n"]
block2["while True:
return 1
else:
return #quot;unreachable#quot;\n"]
start --> block2
block2 -- "True" --> block0
block2 -- "else" --> block1
block1 --> return
block0 --> return
```
## Function 5
### Source
```python
def func():
while True:
return 1
else:
return "unreachable"
return "also unreachable"
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return #quot;also unreachable#quot;\n"]
block1["return 1\n"]
block2["return #quot;unreachable#quot;\n"]
block3["while True:
return 1
else:
return #quot;unreachable#quot;\n"]
start --> block3
block3 -- "True" --> block1
block3 -- "else" --> block2
block2 --> return
block1 --> return
block0 --> return
```
## Function 6
### Source
```python
def func():
i = 0
while False:
i += 1
return i
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return i\n"]
block1["i += 1\n"]
block2["i = 0\nwhile False:
i += 1\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 7
### Source
```python
def func():
i = 0
while True:
i += 1
return i
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return i\n"]
block1["i += 1\n"]
block2["i = 0\nwhile True:
i += 1\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 8
### Source
```python
def func():
while True:
pass
return 1
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 1\n"]
block1["pass\n"]
block2["while True:
pass\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 9
### Source
```python
def func():
i = 0
while True:
if True:
print("ok")
i += 1
return i
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return i\n"]
block1["i += 1\n"]
block2["print(#quot;ok#quot;)\n"]
block3["if True:
print(#quot;ok#quot;)\n"]
block4["i = 0\nwhile True:
if True:
print(#quot;ok#quot;)
i += 1\n"]
start --> block4
block4 -- "True" --> block3
block4 -- "else" --> block0
block3 -- "True" --> block2
block3 -- "else" --> block1
block2 --> block1
block1 --> block4
block0 --> return
```
## Function 10
### Source
```python
def func():
i = 0
while True:
if False:
print("ok")
i += 1
return i
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return i\n"]
block1["i += 1\n"]
block2["print(#quot;ok#quot;)\n"]
block3["if False:
print(#quot;ok#quot;)\n"]
block4["i = 0\nwhile True:
if False:
print(#quot;ok#quot;)
i += 1\n"]
start --> block4
block4 -- "True" --> block3
block4 -- "else" --> block0
block3 -- "False" --> block2
block3 -- "else" --> block1
block2 --> block1
block1 --> block4
block0 --> return
```
## Function 11
### Source
```python
def func():
while True:
if True:
return 1
return 0
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0["return 0\n"]
block1["return 1\n"]
block2["if True:
return 1\n"]
block3["while True:
if True:
return 1\n"]
start --> block3
block3 -- "True" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> return
block0 --> return
```
## Function 12
### Source
```python
def func():
while True:
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["while True:
continue\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 13
### Source
```python
def func():
while False:
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["while False:
continue\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> block2
block0 --> return
```
## Function 14
### Source
```python
def func():
while True:
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["while True:
break\n"]
start --> block2
block2 -- "True" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```
## Function 15
### Source
```python
def func():
while False:
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["while False:
break\n"]
start --> block2
block2 -- "False" --> block1
block2 -- "else" --> block0
block1 --> block0
block0 --> return
```
## Function 16
### Source
```python
def func():
while True:
if True:
continue
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["continue\n"]
block2["if True:
continue\n"]
block3["while True:
if True:
continue\n"]
start --> block3
block3 -- "True" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block3
block0 --> return
```
## Function 17
### Source
```python
def func():
while True:
if True:
break
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1["break\n"]
block2["if True:
break\n"]
block3["while True:
if True:
break\n"]
start --> block3
block3 -- "True" --> block2
block3 -- "else" --> block0
block2 -- "True" --> block1
block2 -- "else" --> block3
block1 --> block0
block0 --> return
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
---
source: crates/ruff/src/rules/ruff/mod.rs
---
RUF014.py:3:5: RUF014 Unreachable code in after_return
|
1 | def after_return():
2 | return "reachable"
3 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
4 |
5 | async def also_works_on_async_functions():
|
RUF014.py:7:5: RUF014 Unreachable code in also_works_on_async_functions
|
5 | async def also_works_on_async_functions():
6 | return "reachable"
7 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
8 |
9 | def if_always_true():
|
RUF014.py:12:5: RUF014 Unreachable code in if_always_true
|
10 | if True:
11 | return "reachable"
12 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
13 |
14 | def if_always_false():
|
RUF014.py:16:9: RUF014 Unreachable code in if_always_false
|
14 | def if_always_false():
15 | if False:
16 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
17 | return "reachable"
|
RUF014.py:21:9: RUF014 Unreachable code in if_elif_always_false
|
19 | def if_elif_always_false():
20 | if False:
21 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
22 | elif False:
23 | return "also unreachable"
|
RUF014.py:23:9: RUF014 Unreachable code in if_elif_always_false
|
21 | return "unreachable"
22 | elif False:
23 | return "also unreachable"
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF014
24 | return "reachable"
|
RUF014.py:28:9: RUF014 Unreachable code in if_elif_always_true
|
26 | def if_elif_always_true():
27 | if False:
28 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
29 | elif True:
30 | return "reachable"
|
RUF014.py:31:5: RUF014 Unreachable code in if_elif_always_true
|
29 | elif True:
30 | return "reachable"
31 | return "also unreachable"
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF014
32 |
33 | def ends_with_if():
|
RUF014.py:35:9: RUF014 Unreachable code in ends_with_if
|
33 | def ends_with_if():
34 | if False:
35 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
36 | else:
37 | return "reachable"
|
RUF014.py:42:5: RUF014 Unreachable code in infinite_loop
|
40 | while True:
41 | continue
42 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
43 |
44 | ''' TODO: we could determine these, but we don't yet.
|
RUF014.py:75:5: RUF014 Unreachable code in match_wildcard
|
73 | case _:
74 | return "reachable"
75 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
76 |
77 | def match_case_and_wildcard(status):
|
RUF014.py:83:5: RUF014 Unreachable code in match_case_and_wildcard
|
81 | case _:
82 | return "reachable"
83 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
84 |
85 | def raise_exception():
|
RUF014.py:87:5: RUF014 Unreachable code in raise_exception
|
85 | def raise_exception():
86 | raise Exception
87 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
88 |
89 | def while_false():
|
RUF014.py:91:9: RUF014 Unreachable code in while_false
|
89 | def while_false():
90 | while False:
91 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
92 | return "reachable"
|
RUF014.py:96:9: RUF014 Unreachable code in while_false_else
|
94 | def while_false_else():
95 | while False:
96 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
97 | else:
98 | return "reachable"
|
RUF014.py:102:9: RUF014 Unreachable code in while_false_else_return
|
100 | def while_false_else_return():
101 | while False:
102 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
103 | else:
104 | return "reachable"
|
RUF014.py:105:5: RUF014 Unreachable code in while_false_else_return
|
103 | else:
104 | return "reachable"
105 | return "also unreachable"
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF014
106 |
107 | def while_true():
|
RUF014.py:110:5: RUF014 Unreachable code in while_true
|
108 | while True:
109 | return "reachable"
110 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
111 |
112 | def while_true_else():
|
RUF014.py:116:9: RUF014 Unreachable code in while_true_else
|
114 | return "reachable"
115 | else:
116 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
117 |
118 | def while_true_else_return():
|
RUF014.py:122:9: RUF014 Unreachable code in while_true_else_return
|
120 | return "reachable"
121 | else:
122 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
123 | return "also unreachable"
|
RUF014.py:123:5: RUF014 Unreachable code in while_true_else_return
|
121 | else:
122 | return "unreachable"
123 | return "also unreachable"
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF014
124 |
125 | def while_false_var_i():
|
RUF014.py:128:9: RUF014 Unreachable code in while_false_var_i
|
126 | i = 0
127 | while False:
128 | i += 1
| ^^^^^^ RUF014
129 | return i
|
RUF014.py:135:5: RUF014 Unreachable code in while_true_var_i
|
133 | while True:
134 | i += 1
135 | return i
| ^^^^^^^^ RUF014
136 |
137 | def while_infinite():
|
RUF014.py:140:5: RUF014 Unreachable code in while_infinite
|
138 | while True:
139 | pass
140 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
141 |
142 | def while_if_true():
|
RUF014.py:146:5: RUF014 Unreachable code in while_if_true
|
144 | if True:
145 | return "reachable"
146 | return "unreachable"
| ^^^^^^^^^^^^^^^^^^^^ RUF014
147 |
148 | # Test case found in the Bokeh repository that trigger a false positive.
|

View File

@@ -39,14 +39,18 @@ pub static EXCLUDE: Lazy<Vec<FilePattern>> = Lazy::new(|| {
FilePattern::Builtin(".git"),
FilePattern::Builtin(".git-rewrite"),
FilePattern::Builtin(".hg"),
FilePattern::Builtin(".ipynb_checkpoints"),
FilePattern::Builtin(".mypy_cache"),
FilePattern::Builtin(".nox"),
FilePattern::Builtin(".pants.d"),
FilePattern::Builtin(".pyenv"),
FilePattern::Builtin(".pytest_cache"),
FilePattern::Builtin(".pytype"),
FilePattern::Builtin(".ruff_cache"),
FilePattern::Builtin(".svn"),
FilePattern::Builtin(".tox"),
FilePattern::Builtin(".venv"),
FilePattern::Builtin(".vscode"),
FilePattern::Builtin("__pypackages__"),
FilePattern::Builtin("_build"),
FilePattern::Builtin("buck-out"),

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.0.276"
version = "0.0.277"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -35,11 +35,17 @@ pub struct Args {
pub enum Command {
/// Run Ruff on the given files or directories (default).
Check(CheckArgs),
/// Explain a rule.
/// Explain a rule (or all rules).
#[clap(alias = "--explain")]
#[command(group = clap::ArgGroup::new("selector").multiple(false).required(true))]
Rule {
#[arg(value_parser=Rule::from_code)]
rule: Rule,
/// Rule to explain
#[arg(value_parser=Rule::from_code, group = "selector")]
rule: Option<Rule>,
/// Explain all rules
#[arg(long, conflicts_with = "rule", group = "selector")]
all: bool,
/// Output format
#[arg(long, value_enum, default_value = "text")]

View File

@@ -1,7 +1,9 @@
use std::io::{self, BufWriter, Write};
use anyhow::Result;
use serde::Serialize;
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
use strum::IntoEnumIterator;
use ruff::registry::{Linter, Rule, RuleNamespace};
use ruff_diagnostics::AutofixKind;
@@ -11,73 +13,106 @@ use crate::args::HelpFormat;
#[derive(Serialize)]
struct Explanation<'a> {
name: &'a str,
code: &'a str,
code: String,
linter: &'a str,
summary: &'a str,
message_formats: &'a [&'a str],
autofix: &'a str,
autofix: String,
explanation: Option<&'a str>,
nursery: bool,
}
impl<'a> Explanation<'a> {
fn from_rule(rule: &'a Rule) -> Self {
let code = rule.noqa_code().to_string();
let (linter, _) = Linter::parse_code(&code).unwrap();
let autofix = rule.autofixable().to_string();
Self {
name: rule.as_ref(),
code,
linter: linter.name(),
summary: rule.message_formats()[0],
message_formats: rule.message_formats(),
autofix,
explanation: rule.explanation(),
nursery: rule.is_nursery(),
}
}
}
fn format_rule_text(rule: Rule) -> String {
let mut output = String::new();
output.push_str(&format!("# {} ({})", rule.as_ref(), rule.noqa_code()));
output.push('\n');
output.push('\n');
let (linter, _) = Linter::parse_code(&rule.noqa_code().to_string()).unwrap();
output.push_str(&format!("Derived from the **{}** linter.", linter.name()));
output.push('\n');
output.push('\n');
let autofix = rule.autofixable();
if matches!(autofix, AutofixKind::Always | AutofixKind::Sometimes) {
output.push_str(&autofix.to_string());
output.push('\n');
output.push('\n');
}
if rule.is_nursery() {
output.push_str(&format!(
r#"This rule is part of the **nursery**, a collection of newer lints that are
still under development. As such, it must be enabled by explicitly selecting
{}."#,
rule.noqa_code()
));
output.push('\n');
output.push('\n');
}
if let Some(explanation) = rule.explanation() {
output.push_str(explanation.trim());
} else {
output.push_str("Message formats:");
for format in rule.message_formats() {
output.push('\n');
output.push_str(&format!("* {format}"));
}
}
output
}
/// Explain a `Rule` to the user.
pub(crate) fn rule(rule: Rule, format: HelpFormat) -> Result<()> {
let (linter, _) = Linter::parse_code(&rule.noqa_code().to_string()).unwrap();
let mut stdout = BufWriter::new(io::stdout().lock());
let mut output = String::new();
match format {
HelpFormat::Text => {
output.push_str(&format!("# {} ({})", rule.as_ref(), rule.noqa_code()));
output.push('\n');
output.push('\n');
writeln!(stdout, "{}", format_rule_text(rule))?;
}
HelpFormat::Json => {
serde_json::to_writer_pretty(stdout, &Explanation::from_rule(&rule))?;
}
};
Ok(())
}
let (linter, _) = Linter::parse_code(&rule.noqa_code().to_string()).unwrap();
output.push_str(&format!("Derived from the **{}** linter.", linter.name()));
output.push('\n');
output.push('\n');
let autofix = rule.autofixable();
if matches!(autofix, AutofixKind::Always | AutofixKind::Sometimes) {
output.push_str(&autofix.to_string());
output.push('\n');
output.push('\n');
}
if rule.is_nursery() {
output.push_str(&format!(
r#"This rule is part of the **nursery**, a collection of newer lints that are
still under development. As such, it must be enabled by explicitly selecting
{}."#,
rule.noqa_code()
));
output.push('\n');
output.push('\n');
}
if let Some(explanation) = rule.explanation() {
output.push_str(explanation.trim());
} else {
output.push_str("Message formats:");
for format in rule.message_formats() {
output.push('\n');
output.push_str(&format!("* {format}"));
}
/// Explain all rules to the user.
pub(crate) fn rules(format: HelpFormat) -> Result<()> {
let mut stdout = BufWriter::new(io::stdout().lock());
match format {
HelpFormat::Text => {
for rule in Rule::iter() {
writeln!(stdout, "{}", format_rule_text(rule))?;
writeln!(stdout)?;
}
}
HelpFormat::Json => {
output.push_str(&serde_json::to_string_pretty(&Explanation {
name: rule.as_ref(),
code: &rule.noqa_code().to_string(),
linter: linter.name(),
summary: rule.message_formats()[0],
message_formats: rule.message_formats(),
autofix: &rule.autofixable().to_string(),
explanation: rule.explanation(),
})?);
let mut serializer = serde_json::Serializer::pretty(stdout);
let mut seq = serializer.serialize_seq(None)?;
for rule in Rule::iter() {
seq.serialize_element(&Explanation::from_rule(&rule))?;
}
seq.end()?;
}
};
writeln!(stdout, "{output}")?;
}
Ok(())
}

View File

@@ -134,7 +134,14 @@ quoting the executed command, along with the relevant file contents and `pyproje
set_up_logging(&log_level)?;
match command {
Command::Rule { rule, format } => commands::rule::rule(rule, format)?,
Command::Rule { rule, all, format } => {
if all {
commands::rule::rules(format)?;
}
if let Some(rule) = rule {
commands::rule::rule(rule, format)?;
}
}
Command::Config { option } => return Ok(commands::config::config(option.as_deref())),
Command::Linter { format } => commands::linter::linter(format)?,
Command::Clean => commands::clean::clean(log_level)?,

View File

@@ -4,8 +4,9 @@
//! checking entire repositories.
use std::fmt::{Display, Formatter};
use std::io::stdout;
use std::fs::File;
use std::io::Write;
use std::io::{stdout, BufWriter};
use std::panic::catch_unwind;
use std::path::{Path, PathBuf};
use std::process::ExitCode;
@@ -49,6 +50,9 @@ pub(crate) struct Args {
/// Checks each project inside a directory
#[arg(long)]
pub(crate) multi_project: bool,
/// Write all errors to this file in addition to stdout
#[arg(long)]
pub(crate) error_file: Option<PathBuf>,
}
/// Generate ourself a `try_parse_from` impl for `CheckArgs`. This is a strange way to use clap but
@@ -69,6 +73,12 @@ pub(crate) fn main(args: &Args) -> anyhow::Result<ExitCode> {
#[allow(clippy::print_stdout)]
{
print!("{}", result.display(args.format));
println!(
"Found {} stability errors in {} files in {:.2}s",
result.diagnostics.len(),
result.file_count,
result.duration.as_secs_f32(),
);
}
result.is_success()
@@ -114,6 +124,7 @@ fn check_multi_project(args: &Args) -> bool {
match check_repo(&Args {
files: vec![path.clone()],
error_file: args.error_file.clone(),
..*args
}) {
Ok(result) => sender.send(Message::Finished { result, path }),
@@ -126,6 +137,9 @@ fn check_multi_project(args: &Args) -> bool {
scope.spawn(|_| {
let mut stdout = stdout().lock();
let mut error_file = args.error_file.as_ref().map(|error_file| {
BufWriter::new(File::create(error_file).expect("Couldn't open error file"))
});
for message in receiver {
match message {
@@ -135,13 +149,19 @@ fn check_multi_project(args: &Args) -> bool {
Message::Finished { path, result } => {
total_errors += result.diagnostics.len();
total_files += result.file_count;
writeln!(
stdout,
"Finished {}\n{}\n",
"Finished {} with {} files in {:.2}s",
path.display(),
result.display(args.format)
result.file_count,
result.duration.as_secs_f32(),
)
.unwrap();
write!(stdout, "{}", result.display(args.format)).unwrap();
if let Some(error_file) = &mut error_file {
write!(error_file, "{}", result.display(args.format)).unwrap();
}
all_success = all_success && result.is_success();
}
Message::Failed { path, error } => {
@@ -157,8 +177,10 @@ fn check_multi_project(args: &Args) -> bool {
#[allow(clippy::print_stdout)]
{
println!("{total_errors} stability errors in {total_files} files");
println!("Finished in {}s", duration.as_secs_f32());
println!(
"{total_errors} stability errors in {total_files} files in {}s",
duration.as_secs_f32()
);
}
all_success
@@ -295,23 +317,11 @@ struct DisplayCheckRepoResult<'a> {
}
impl Display for DisplayCheckRepoResult<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let CheckRepoResult {
duration,
file_count,
diagnostics,
} = self.result;
for diagnostic in diagnostics {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for diagnostic in &self.result.diagnostics {
write!(f, "{}", diagnostic.display(self.format))?;
}
writeln!(
f,
"Formatting {} files twice took {:.2}s",
file_count,
duration.as_secs_f32()
)
Ok(())
}
}

View File

@@ -61,7 +61,7 @@ mod tests {
use super::{main, Args};
#[test]
#[cfg_attr(not(feature = "unreachable-code"), test)]
fn test_generate_json_schema() -> Result<()> {
let mode = if env::var("RUFF_UPDATE_SCHEMA").as_deref() == Ok("1") {
Mode::Write

View File

@@ -102,10 +102,10 @@ pub(crate) fn generate() -> String {
));
table_out.push('\n');
table_out.push('\n');
generate_table(&mut table_out, prefix, &linter);
generate_table(&mut table_out, prefix.clone().rules(), &linter);
}
} else {
generate_table(&mut table_out, &linter, &linter);
generate_table(&mut table_out, linter.rules(), &linter);
}
}

View File

@@ -40,6 +40,11 @@ impl<I: Idx, T> IndexSlice<I, T> {
}
}
#[inline]
pub const fn first(&self) -> Option<&T> {
self.raw.first()
}
#[inline]
pub const fn len(&self) -> usize {
self.raw.len()
@@ -63,6 +68,13 @@ impl<I: Idx, T> IndexSlice<I, T> {
(0..self.len()).map(|n| I::new(n))
}
#[inline]
pub fn iter_enumerated(
&self,
) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator + '_ {
self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
}
#[inline]
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
self.raw.iter_mut()

View File

@@ -155,30 +155,13 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
}
output.extend(quote! {
impl IntoIterator for &#linter {
type Item = Rule;
type IntoIter = ::std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
impl #linter {
pub fn rules(self) -> ::std::vec::IntoIter<Rule> {
match self { #prefix_into_iter_match_arms }
}
}
});
}
output.extend(quote! {
impl IntoIterator for &RuleCodePrefix {
type Item = Rule;
type IntoIter = ::std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
match self {
#(RuleCodePrefix::#linter_idents(prefix) => prefix.into_iter(),)*
}
}
}
});
output.extend(quote! {
impl RuleCodePrefix {
pub fn parse(linter: &Linter, code: &str) -> Result<Self, crate::registry::FromCodeError> {
@@ -188,6 +171,12 @@ pub(crate) fn map_codes(func: &ItemFn) -> syn::Result<TokenStream> {
#(Linter::#linter_idents => RuleCodePrefix::#linter_idents(#linter_idents::from_str(code).map_err(|_| crate::registry::FromCodeError::Unknown)?),)*
})
}
pub fn rules(self) -> ::std::vec::IntoIter<Rule> {
match self {
#(RuleCodePrefix::#linter_idents(prefix) => prefix.clone().rules(),)*
}
}
}
});
@@ -344,32 +333,39 @@ fn generate_iter_impl(
linter_to_rules: &BTreeMap<Ident, BTreeMap<String, Rule>>,
linter_idents: &[&Ident],
) -> TokenStream {
let mut linter_into_iter_match_arms = quote!();
let mut linter_rules_match_arms = quote!();
let mut linter_all_rules_match_arms = quote!();
for (linter, map) in linter_to_rules {
let rule_paths = map
.values()
.filter(|rule| {
// Nursery rules have to be explicitly selected, so we ignore them when looking at
// linter-level selectors (e.g., `--select SIM`).
!is_nursery(&rule.group)
})
.map(|Rule { attrs, path, .. }| {
let rule_paths = map.values().filter(|rule| !is_nursery(&rule.group)).map(
|Rule { attrs, path, .. }| {
let rule_name = path.segments.last().unwrap();
quote!(#(#attrs)* Rule::#rule_name)
});
linter_into_iter_match_arms.extend(quote! {
},
);
linter_rules_match_arms.extend(quote! {
Linter::#linter => vec![#(#rule_paths,)*].into_iter(),
});
let rule_paths = map.values().map(|Rule { attrs, path, .. }| {
let rule_name = path.segments.last().unwrap();
quote!(#(#attrs)* Rule::#rule_name)
});
linter_all_rules_match_arms.extend(quote! {
Linter::#linter => vec![#(#rule_paths,)*].into_iter(),
});
}
quote! {
impl IntoIterator for &Linter {
type Item = Rule;
type IntoIter = ::std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
impl Linter {
/// Rules not in the nursery.
pub fn rules(self: &Linter) -> ::std::vec::IntoIter<Rule> {
match self {
#linter_into_iter_match_arms
#linter_rules_match_arms
}
}
/// All rules, including those in the nursery.
pub fn all_rules(self: &Linter) -> ::std::vec::IntoIter<Rule> {
match self {
#linter_all_rules_match_arms
}
}
}

View File

@@ -36,10 +36,11 @@ pub(super) fn generate_newtype_index(item: ItemStruct) -> syn::Result<proc_macro
#vis #struct_token #ident(std::num::NonZeroU32)#semi_token
impl #ident {
const MAX: u32 = u32::MAX - 1;
const MAX_VALUE: u32 = u32::MAX - 1;
const MAX: Self = Self::from_u32(Self::MAX_VALUE);
#vis const fn from_usize(value: usize) -> Self {
assert!(value <= Self::MAX as usize);
assert!(value <= Self::MAX_VALUE as usize);
// SAFETY:
// * The `value < u32::MAX` guarantees that the add doesn't overflow.
@@ -49,7 +50,7 @@ pub(super) fn generate_newtype_index(item: ItemStruct) -> syn::Result<proc_macro
}
#vis const fn from_u32(value: u32) -> Self {
assert!(value <= Self::MAX);
assert!(value <= Self::MAX_VALUE);
// SAFETY:
// * The `value < u32::MAX` guarantees that the add doesn't overflow.

View File

@@ -81,3 +81,8 @@ f(
dict()
)
# Don't add a magic trailing comma when there is only one entry
# Minimized from https://github.com/django/django/blob/7eeadc82c2f7d7a778e3bb43c34d642e6275dacf/django/contrib/admin/checks.py#L674-L681
f(
a.very_long_function_function_that_is_so_long_that_it_expands_the_parent_but_its_only_a_single_argument()
)

View File

@@ -8,3 +8,16 @@ a2 = [ # a
a3 = [
# b
]
# Add magic trailing comma only if there is more than one entry, but respect it if it's
# already there
b1 = [
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
]
b2 = [
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
]
b3 = [
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
]

View File

@@ -0,0 +1,3 @@
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
from a import aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd, aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd

View File

@@ -0,0 +1,16 @@
from a import aksjdhflsakhdflkjsadlfajkslhf
from a import (
aksjdhflsakhdflkjsadlfajkslhf,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
)
from a import (
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as dfgsdfgsd,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa as sdkjflsdjlahlfd,
)
from aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa import *

View File

@@ -182,7 +182,10 @@ impl<'fmt, 'ast, 'buf> JoinNodesBuilder<'fmt, 'ast, 'buf> {
pub(crate) struct JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
result: FormatResult<()>,
fmt: &'fmt mut PyFormatter<'ast, 'buf>,
last_end: Option<TextSize>,
end_of_last_entry: Option<TextSize>,
/// We need to track whether we have more than one entry since a sole entry doesn't get a
/// magic trailing comma even when expanded
len: usize,
}
impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
@@ -190,7 +193,8 @@ impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
Self {
fmt: f,
result: Ok(()),
last_end: None,
end_of_last_entry: None,
len: 0,
}
}
@@ -203,11 +207,12 @@ impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
T: Ranged,
{
self.result = self.result.and_then(|_| {
if self.last_end.is_some() {
if self.end_of_last_entry.is_some() {
write!(self.fmt, [text(","), soft_line_break_or_space()])?;
}
self.last_end = Some(node.end());
self.end_of_last_entry = Some(node.end());
self.len += 1;
content.fmt(self.fmt)
});
@@ -243,18 +248,23 @@ impl<'fmt, 'ast, 'buf> JoinCommaSeparatedBuilder<'fmt, 'ast, 'buf> {
pub(crate) fn finish(&mut self) -> FormatResult<()> {
self.result.and_then(|_| {
if let Some(last_end) = self.last_end.take() {
if_group_breaks(&text(",")).fmt(self.fmt)?;
if self.fmt.options().magic_trailing_comma().is_respect()
if let Some(last_end) = self.end_of_last_entry.take() {
let magic_trailing_comma = self.fmt.options().magic_trailing_comma().is_respect()
&& matches!(
first_non_trivia_token(last_end, self.fmt.context().contents()),
Some(Token {
kind: TokenKind::Comma,
..
})
)
{
);
// If there is a single entry, only keep the magic trailing comma, don't add it if
// it wasn't there. If there is more than one entry, always add it.
if magic_trailing_comma || self.len > 1 {
if_group_breaks(&text(",")).fmt(self.fmt)?;
}
if magic_trailing_comma {
expand_parent().fmt(self.fmt)?;
}
}

View File

@@ -1,5 +1,6 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::Alias;
#[derive(Default)]
@@ -7,6 +8,15 @@ pub struct FormatAlias;
impl FormatNodeRule<Alias> for FormatAlias {
fn fmt_fields(&self, item: &Alias, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let Alias {
range: _,
name,
asname,
} = item;
name.format().fmt(f)?;
if let Some(asname) = asname {
write!(f, [space(), text("as"), space(), asname.format()])?;
}
Ok(())
}
}

View File

@@ -1,4 +1,5 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use crate::{FormatNodeRule, FormattedIterExt, PyFormatter};
use ruff_formatter::prelude::{format_args, format_with, space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use rustpython_parser::ast::StmtImport;
@@ -7,6 +8,12 @@ pub struct FormatStmtImport;
impl FormatNodeRule<StmtImport> for FormatStmtImport {
fn fmt_fields(&self, item: &StmtImport, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let StmtImport { names, range: _ } = item;
let names = format_with(|f| {
f.join_with(&format_args![text(","), space()])
.entries(names.iter().formatted())
.finish()
});
write!(f, [text("import"), space(), names])
}
}

View File

@@ -1,5 +1,7 @@
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use crate::builders::{optional_parentheses, PyFormatterExtensions};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{dynamic_text, format_with, space, text};
use ruff_formatter::{write, Buffer, Format, FormatResult};
use rustpython_parser::ast::StmtImportFrom;
#[derive(Default)]
@@ -7,6 +9,40 @@ pub struct FormatStmtImportFrom;
impl FormatNodeRule<StmtImportFrom> for FormatStmtImportFrom {
fn fmt_fields(&self, item: &StmtImportFrom, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [not_yet_implemented(item)])
let StmtImportFrom {
module,
names,
range: _,
level,
} = item;
let level_str = level
.map(|level| ".".repeat(level.to_usize()))
.unwrap_or(String::default());
write!(
f,
[
text("from"),
space(),
dynamic_text(&level_str, None),
module.as_ref().map(AsFormat::format),
space(),
text("import"),
space(),
]
)?;
if let [name] = names.as_slice() {
// star can't be surrounded by parentheses
if name.name.as_str() == "*" {
return text("*").fmt(f);
}
}
let names = format_with(|f| {
f.join_comma_separated()
.entries(names.iter().map(|name| (name, name.format())))
.finish()
});
optional_parentheses(&names).fmt(f)
}
}

View File

@@ -43,21 +43,20 @@ def eggs() -> Union[str, int]: ...
--- Black
+++ Ruff
@@ -1,32 +1,58 @@
-from typing import Union
+NOT_YET_IMPLEMENTED_StmtImportFrom
+
from typing import Union
+
@bird
-def zoo(): ...
+def zoo():
+ ...
+
+
+class A:
+ ...
-class A: ...
+class A:
+ ...
+
+
@bar
class B:
- def BMethod(self) -> None: ...
@@ -94,14 +93,14 @@ def eggs() -> Union[str, int]: ...
+
+class F(A, C):
+ ...
+
+
+def spam() -> None:
+ ...
-class F(A, C): ...
-def spam() -> None: ...
+def spam() -> None:
+ ...
+
+
@overload
-def spam(arg: str) -> str: ...
+def spam(arg: str) -> str:
@@ -120,7 +119,7 @@ def eggs() -> Union[str, int]: ...
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from typing import Union
@bird

View File

@@ -312,15 +312,6 @@ long_unmergable_string_with_pragma = (
y = "Short string"
@@ -12,7 +12,7 @@
)
print(
- "This is a really long string inside of a print statement with no extra arguments attached at the end of it."
+ "This is a really long string inside of a print statement with no extra arguments attached at the end of it.",
)
D1 = {
@@ -70,8 +70,8 @@
bad_split3 = (
"What if we have inline comments on " # First Comment
@@ -367,7 +358,7 @@ long_unmergable_string_with_pragma = (
comment_string = "Long lines with inline comments should have their comments appended to the reformatted string's enclosing right parentheses." # This comment gets thrown to the top.
@@ -165,30 +163,18 @@
@@ -165,25 +163,13 @@
triple_quote_string = """This is a really really really long triple quote string assignment and it should not be touched."""
@@ -397,12 +388,6 @@ long_unmergable_string_with_pragma = (
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
- + " to a variable and then added to another string."
+ + " to a variable and then added to another string.",
)
some_function_call(
@@ -212,29 +198,25 @@
)
@@ -412,7 +397,7 @@ long_unmergable_string_with_pragma = (
- " which should NOT be there."
- ),
+ "This is a really long string argument to a function that has a trailing comma"
+ " which should NOT be there.",
+ " which should NOT be there."
)
func_with_bad_comma(
@@ -421,7 +406,7 @@ long_unmergable_string_with_pragma = (
- " which should NOT be there."
- ), # comment after comma
+ "This is a really long string argument to a function that has a trailing comma"
+ " which should NOT be there.", # comment after comma
+ " which should NOT be there." # comment after comma
)
func_with_bad_parens_that_wont_fit_in_one_line(
@@ -498,7 +483,7 @@ print(
)
print(
"This is a really long string inside of a print statement with no extra arguments attached at the end of it.",
"This is a really long string inside of a print statement with no extra arguments attached at the end of it."
)
D1 = {
@@ -660,7 +645,7 @@ NOT_YET_IMPLEMENTED_StmtAssert
some_function_call(
"With a reallly generic name and with a really really long string that is, at some point down the line, "
+ added
+ " to a variable and then added to another string.",
+ " to a variable and then added to another string."
)
some_function_call(
@@ -685,12 +670,12 @@ func_with_bad_comma(
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.",
" which should NOT be there."
)
func_with_bad_comma(
"This is a really long string argument to a function that has a trailing comma"
" which should NOT be there.", # comment after comma
" which should NOT be there." # comment after comma
)
func_with_bad_parens_that_wont_fit_in_one_line(

View File

@@ -132,8 +132,7 @@ match bar1:
--- Black
+++ Ruff
@@ -1,119 +1,43 @@
-import match
+NOT_YET_IMPLEMENTED_StmtImport
import match
-match something:
- case [a as b]:
@@ -208,10 +207,11 @@ match bar1:
- ),
- ):
- pass
-
+NOT_YET_IMPLEMENTED_StmtMatch
- case [a as match]:
- pass
-
- case case:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
@@ -220,8 +220,9 @@ match bar1:
-match match:
- case case:
- pass
-
-
+NOT_YET_IMPLEMENTED_StmtMatch
-match a, *b(), c:
- case d, *f, g:
- pass
@@ -236,30 +237,28 @@ match bar1:
- pass
- case {"maybe": something(complicated as this) as that}:
- pass
-
+NOT_YET_IMPLEMENTED_StmtMatch
-match something:
- case 1 as a:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
- case 2 as b, 3 as c:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
- case 4 as d, (5 as e), (6 | 7 as g), *h:
- pass
+NOT_YET_IMPLEMENTED_StmtMatch
-
-match bar1:
- case Foo(aa=Callable() as aa, bb=int()):
- print(bar1.aa, bar1.bb)
- case _:
- print("no match", "\n")
+NOT_YET_IMPLEMENTED_StmtMatch
-
-
-match bar1:
- case Foo(
- normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
@@ -271,7 +270,7 @@ match bar1:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import match
NOT_YET_IMPLEMENTED_StmtMatch

View File

@@ -84,7 +84,7 @@ match match(
-match(arg) # comment
+match(
+ arg, # comment
+ arg # comment
+)
match()
@@ -93,7 +93,7 @@ match match(
-case(arg) # comment
+case(
+ arg, # comment
+ arg # comment
+)
case()
@@ -103,7 +103,7 @@ match match(
-re.match(something) # fast
+re.match(
+ something, # fast
+ something # fast
+)
re.match()
-match match():
@@ -120,7 +120,7 @@ match match(
NOT_YET_IMPLEMENTED_StmtMatch
match(
arg, # comment
arg # comment
)
match()
@@ -128,7 +128,7 @@ match()
match()
case(
arg, # comment
arg # comment
)
case()
@@ -137,7 +137,7 @@ case()
re.match(
something, # fast
something # fast
)
re.match()
NOT_YET_IMPLEMENTED_StmtMatch

View File

@@ -83,31 +83,9 @@ if True:
```diff
--- Black
+++ Ruff
@@ -1,40 +1,22 @@
-import core, time, a
+NOT_YET_IMPLEMENTED_StmtImport
-from . import A, B, C
+NOT_YET_IMPLEMENTED_StmtImportFrom
# keeps existing trailing comma
-from foo import (
- bar,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
# also keeps existing structure
-from foo import (
- baz,
- qux,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
# `as` works as well
-from foo import (
- xyzzy as magic,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
@@ -18,23 +18,12 @@
xyzzy as magic,
)
-a = {
- 1,
@@ -132,7 +110,7 @@ if True:
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
nested_long_lines = [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -52,10 +34,7 @@
@@ -52,10 +41,7 @@
y = {
"oneple": (1,),
}
@@ -149,18 +127,25 @@ if True:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import core, time, a
NOT_YET_IMPLEMENTED_StmtImportFrom
from . import A, B, C
# keeps existing trailing comma
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
bar,
)
# also keeps existing structure
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
baz,
qux,
)
# `as` works as well
NOT_YET_IMPLEMENTED_StmtImportFrom
from foo import (
xyzzy as magic,
)
a = {1, 2, 3}
b = {1, 2, 3}

View File

@@ -1,347 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py
---
## Input
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -9,16 +9,16 @@
Possibly also many, many lines.
"""
-import os.path
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
-import a
-from b.c import X # some noqa comment
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment
try:
- import fast
+ NOT_YET_IMPLEMENTED_StmtImport
except ImportError:
- import slow as fast
+ NOT_YET_IMPLEMENTED_StmtImport
# Some comment before a function.
@@ -35,7 +35,7 @@
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
- import inner_imports
+ NOT_YET_IMPLEMENTED_StmtImport
if inner_imports.are_evil():
# Explains why we have this if.
```
## Ruff Output
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImportFrom # some noqa comment
try:
NOT_YET_IMPLEMENTED_StmtImport
except ImportError:
NOT_YET_IMPLEMENTED_StmtImport
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
NOT_YET_IMPLEMENTED_StmtImport
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```
## Black Output
```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
```

View File

@@ -177,19 +177,18 @@ instruction()#comment with bad spacing
```diff
--- Black
+++ Ruff
@@ -1,9 +1,5 @@
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
@@ -1,8 +1,8 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
-)
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
+ MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent as component, # DRY
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+ MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.
@@ -45,7 +41,7 @@
@@ -45,7 +45,7 @@
# user-defined types and objects
Cheese,
Cheese("Wensleydale"),
@@ -198,7 +197,7 @@ instruction()#comment with bad spacing
]
if "PYTHON" in os.environ:
@@ -60,8 +56,12 @@
@@ -60,8 +60,12 @@
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
@@ -212,7 +211,7 @@ instruction()#comment with bad spacing
children[0],
body,
children[-1], # type: ignore
@@ -72,7 +72,11 @@
@@ -72,7 +76,11 @@
body,
parameters.children[-1], # )2
]
@@ -225,7 +224,7 @@ instruction()#comment with bad spacing
if (
self._proc is not None
# has the child process finished?
@@ -114,25 +118,9 @@
@@ -114,25 +122,9 @@
# yup
arg3=True,
)
@@ -254,7 +253,7 @@ instruction()#comment with bad spacing
while True:
if False:
continue
@@ -143,7 +131,10 @@
@@ -143,7 +135,10 @@
# let's return
return Node(
syms.simple_stmt,
@@ -266,7 +265,7 @@ instruction()#comment with bad spacing
)
@@ -158,7 +149,11 @@
@@ -158,7 +153,11 @@
class Test:
def _init_host(self, parsed) -> None:
@@ -284,8 +283,12 @@ instruction()#comment with bad spacing
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.

View File

@@ -76,15 +76,6 @@ def func():
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
@@ -29,7 +22,7 @@
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
- )
+ ),
# This should be left alone (after)
)
```
## Ruff Output
@@ -114,7 +105,7 @@ def func():
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
),
)
# This should be left alone (after)
)

View File

@@ -106,19 +106,7 @@ def foo3(list_a, list_b):
```diff
--- Black
+++ Ruff
@@ -1,9 +1,5 @@
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
-)
-from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent as component, # DRY
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
class C:
@@ -58,37 +54,28 @@
@@ -58,37 +58,28 @@
def foo(list_a, list_b):
results = (
@@ -172,8 +160,12 @@ def foo3(list_a, list_b):
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:

View File

@@ -1,255 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
---
## Input
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -27,7 +27,7 @@
except OSError:
print("problems")
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
# leading function comment
```
## Ruff Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
NOT_YET_IMPLEMENTED_StmtImport
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```

View File

@@ -130,12 +130,6 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-from typing import Any, Tuple
+NOT_YET_IMPLEMENTED_StmtImportFrom
def f(
@@ -49,9 +49,7 @@
element = 0 # type: int
another_element = 1 # type: float
@@ -192,7 +186,7 @@ aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*ite
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from typing import Any, Tuple
def f(

View File

@@ -31,18 +31,7 @@ def function(a:int=42):
```diff
--- Black
+++ Ruff
@@ -1,9 +1,4 @@
-from .config import (
- ConfigTypeAttributes,
- Int,
- Path, # String,
- # DEFAULT_TYPE_ATTRIBUTES,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
result = 1 # A simple comment
result = (1,) # Another one
@@ -14,9 +9,9 @@
@@ -14,9 +14,9 @@
def function(a: int = 42):
@@ -60,7 +49,12 @@ def function(a:int=42):
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from .config import (
ConfigTypeAttributes,
Int,
Path, # String,
# DEFAULT_TYPE_ATTRIBUTES,
)
result = 1 # A simple comment
result = (1,) # Another one

View File

@@ -203,15 +203,6 @@ class C:
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
@@ -37,7 +37,7 @@
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
- items=items[:num_items]
+ items=items[:num_items],
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
@@ -47,113 +47,46 @@
def omitting_trailers(self) -> None:
get_collection(
@@ -418,7 +409,7 @@ class C:
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items],
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'

View File

@@ -203,15 +203,6 @@ class C:
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
@@ -37,7 +37,7 @@
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
- items=items[:num_items]
+ items=items[:num_items],
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
@@ -47,113 +47,46 @@
def omitting_trailers(self) -> None:
get_collection(
@@ -418,7 +409,7 @@ class C:
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items],
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'

View File

@@ -198,22 +198,13 @@ d={'a':1,
```diff
--- Black
+++ Ruff
@@ -1,15 +1,14 @@
#!/usr/bin/env python3
-import asyncio
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
@@ -6,10 +6,9 @@
-from third_party import X, Y, Z
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from library import some_connection, some_decorator
+NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
# fmt: off
-from third_party import (X,
- Y, Z)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+from third_party import X, Y, Z
# fmt: on
-f"trigger 3.6 mode"
+NOT_YET_IMPLEMENTED_ExprJoinedStr
@@ -336,7 +327,7 @@ d={'a':1,
# fmt: off
- from hello import a, b
- 'unformatted'
+ NOT_YET_IMPLEMENTED_StmtImportFrom
+ from hello import a, b
+ "unformatted"
# fmt: on
@@ -395,12 +386,8 @@ d={'a':1,
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
@@ -150,12 +172,10 @@
ast_args.kw_defaults,
parameters,
implicit_default=True,
- )
+ ),
@@ -153,9 +175,7 @@
)
)
# fmt: off
- a = (
@@ -437,14 +424,14 @@ d={'a':1,
```py
#!/usr/bin/env python3
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
import sys
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
# fmt: off
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
# fmt: on
NOT_YET_IMPLEMENTED_ExprJoinedStr
# Comment 1
@@ -543,7 +530,7 @@ def subscriptlist():
def import_as_names():
# fmt: off
NOT_YET_IMPLEMENTED_StmtImportFrom
from hello import a, b
"unformatted"
# fmt: on
@@ -610,7 +597,7 @@ def long_lines():
ast_args.kw_defaults,
parameters,
implicit_default=True,
),
)
)
# fmt: off
a = unnecessary_bracket()

View File

@@ -52,12 +52,7 @@ def test_calculate_fades():
```diff
--- Black
+++ Ruff
@@ -1,40 +1,44 @@
-import pytest
+NOT_YET_IMPLEMENTED_StmtImport
TmSt = 1
TmEx = 2
@@ -5,36 +5,40 @@
# fmt: off
@@ -113,7 +108,7 @@ def test_calculate_fades():
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import pytest
TmSt = 1
TmEx = 2

View File

@@ -37,20 +37,11 @@ def f(): pass
+ 2,
+ 3,
+ 4,
+ ],
+ ]
+)
# fmt: on
def f():
pass
@@ -14,7 +18,7 @@
2,
3,
4,
- ]
+ ],
)
def f():
pass
```
## Ruff Output
@@ -63,7 +54,7 @@ def f(): pass
2,
3,
4,
],
]
)
# fmt: on
def f():
@@ -76,7 +67,7 @@ def f():
2,
3,
4,
],
]
)
def f():
pass

View File

@@ -103,7 +103,7 @@ elif unformatted:
- # fmt: on
- ] # Includes an formatted indentation.
+ # fmt: on
+ ], # Includes an formatted indentation.
+ ] # Includes an formatted indentation.
},
)
@@ -186,7 +186,7 @@ setup(
"foo-bar"
"=foo.bar.:main",
# fmt: on
], # Includes an formatted indentation.
] # Includes an formatted indentation.
},
)

View File

@@ -1,114 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtpass_imports.py
---
## Input
```py
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,19 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
-import ast
-import collections # fmt: skip
-import dataclasses
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
-import os
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
-import pathlib
+NOT_YET_IMPLEMENTED_StmtImport
-import re # fmt: skip
-import secrets
+NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
-import sys
+NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
-import tempfile
-import zoneinfo
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
```
## Ruff Output
```py
# Regression test for https://github.com/psf/black/issues/3438
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport # fmt: skip
NOT_YET_IMPLEMENTED_StmtImport
# fmt: off
NOT_YET_IMPLEMENTED_StmtImport
# fmt: on
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
```
## Black Output
```py
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo
```

View File

@@ -107,20 +107,12 @@ def __await__(): return (yield)
```diff
--- Black
+++ Ruff
@@ -1,12 +1,11 @@
#!/usr/bin/env python3
-import asyncio
-import sys
@@ -5,8 +5,7 @@
from third_party import X, Y, Z
from library import some_connection, some_decorator
-
-from third_party import X, Y, Z
+NOT_YET_IMPLEMENTED_StmtImport
+NOT_YET_IMPLEMENTED_StmtImport
-from library import some_connection, some_decorator
+NOT_YET_IMPLEMENTED_StmtImportFrom
-f"trigger 3.6 mode"
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_ExprJoinedStr
@@ -198,24 +190,6 @@ def __await__(): return (yield)
def long_lines():
@@ -87,7 +94,7 @@
ast_args.kw_defaults,
parameters,
implicit_default=True,
- )
+ ),
)
typedargslist.extend(
gen_annotated_params(
@@ -96,7 +103,7 @@
parameters,
implicit_default=True,
# trailing standalone comment
- )
+ ),
)
_type_comment_re = re.compile(
r"""
@@ -135,14 +142,8 @@
a,
**kwargs,
@@ -239,12 +213,12 @@ def __await__(): return (yield)
```py
#!/usr/bin/env python3
NOT_YET_IMPLEMENTED_StmtImport
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
import sys
NOT_YET_IMPLEMENTED_StmtImportFrom
from third_party import X, Y, Z
NOT_YET_IMPLEMENTED_StmtImportFrom
from library import some_connection, some_decorator
NOT_YET_IMPLEMENTED_ExprJoinedStr
@@ -334,7 +308,7 @@ def long_lines():
ast_args.kw_defaults,
parameters,
implicit_default=True,
),
)
)
typedargslist.extend(
gen_annotated_params(
@@ -343,7 +317,7 @@ def long_lines():
parameters,
implicit_default=True,
# trailing standalone comment
),
)
)
_type_comment_re = re.compile(
r"""

View File

@@ -65,22 +65,15 @@ with hmm_but_this_should_get_two_preceding_newlines():
```diff
--- Black
+++ Ruff
@@ -32,34 +32,28 @@
if os.name == "posix":
- import termios
+ NOT_YET_IMPLEMENTED_StmtImport
@@ -36,7 +36,6 @@
def i_should_be_followed_by_only_one_newline():
pass
-
elif os.name == "nt":
try:
- import msvcrt
+ NOT_YET_IMPLEMENTED_StmtImport
def i_should_be_followed_by_only_one_newline():
import msvcrt
@@ -45,21 +44,16 @@
pass
except ImportError:
@@ -141,13 +134,13 @@ def h():
if os.name == "posix":
NOT_YET_IMPLEMENTED_StmtImport
import termios
def i_should_be_followed_by_only_one_newline():
pass
elif os.name == "nt":
try:
NOT_YET_IMPLEMENTED_StmtImport
import msvcrt
def i_should_be_followed_by_only_one_newline():
pass

View File

@@ -73,15 +73,6 @@ some_module.some_function(
```diff
--- Black
+++ Ruff
@@ -27,7 +27,7 @@
call(
arg={
"explode": "this",
- }
+ },
)
call2(
arg=[1, 2, 3],
@@ -35,7 +35,9 @@
x = {
"a": 1,
@@ -93,7 +84,7 @@ some_module.some_function(
if (
a
== {
@@ -47,22 +49,24 @@
@@ -47,14 +49,16 @@
"f": 6,
"g": 7,
"h": 8,
@@ -114,17 +105,6 @@ some_module.some_function(
json = {
"k": {
"k2": {
"k3": [
1,
- ]
- }
- }
+ ],
+ },
+ },
}
@@ -80,18 +84,14 @@
pass
@@ -182,7 +162,7 @@ def f(
call(
arg={
"explode": "this",
},
}
)
call2(
arg=[1, 2, 3],
@@ -219,9 +199,9 @@ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
"k2": {
"k3": [
1,
],
},
},
]
}
}
}

View File

@@ -61,79 +61,15 @@ __all__ = (
```diff
--- Black
+++ Ruff
@@ -2,53 +2,31 @@
# flake8: noqa
-from logging import WARNING
-from logging import (
- ERROR,
-)
-import sys
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImport
# This relies on each of the submodules having an __all__ variable.
-from .base_events import *
-from .coroutines import *
-from .events import * # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
-from .futures import *
-from .locks import * # comment here
-from .protocols import *
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from ..runners import * # comment here
-from ..queues import *
-from ..streams import *
+NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
-from some_library import (
- Just,
- Enough,
- Libraries,
- To,
- Fit,
- In,
- This,
- Nice,
- Split,
- Which,
- We,
- No,
- Longer,
- Use,
-)
-from name_of_a_company.extremely_long_project_name.component.ttypes import (
@@ -38,7 +38,7 @@
Use,
)
from name_of_a_company.extremely_long_project_name.component.ttypes import (
- CuteLittleServiceHandlerFactoryyy,
-)
-from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+ CuteLittleServiceHandlerFactoryyy
)
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
-from .a.b.c.subprocess import *
-from . import tasks
-from . import A, B, C
-from . import (
- SomeVeryLongNameAndAllOfItsAdditionalLetters1,
- SomeVeryLongNameAndAllOfItsAdditionalLetters2,
-)
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
+NOT_YET_IMPLEMENTED_StmtImportFrom
__all__ = (
base_events.__all__
```
## Ruff Output
@@ -143,31 +79,53 @@ __all__ = (
# flake8: noqa
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImport
from logging import WARNING
from logging import (
ERROR,
)
import sys
# This relies on each of the submodules having an __all__ variable.
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
from .base_events import *
from .coroutines import *
from .events import * # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
from .futures import *
from .locks import * # comment here
from .protocols import *
NOT_YET_IMPLEMENTED_StmtImportFrom # comment here
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from ..runners import * # comment here
from ..queues import *
from ..streams import *
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from some_library import (
Just,
Enough,
Libraries,
To,
Fit,
In,
This,
Nice,
Split,
Which,
We,
No,
Longer,
Use,
)
from name_of_a_company.extremely_long_project_name.component.ttypes import (
CuteLittleServiceHandlerFactoryyy
)
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
NOT_YET_IMPLEMENTED_StmtImportFrom
from .a.b.c.subprocess import *
from . import tasks
from . import A, B, C
from . import (
SomeVeryLongNameAndAllOfItsAdditionalLetters1,
SomeVeryLongNameAndAllOfItsAdditionalLetters2,
)
__all__ = (
base_events.__all__

View File

@@ -93,12 +93,6 @@ async def main():
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-import asyncio
+NOT_YET_IMPLEMENTED_StmtImport
# Control example
@@ -8,59 +8,70 @@
# Remove brackets for short coroutine/task
@@ -219,7 +213,7 @@ async def main():
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import asyncio
# Control example

View File

@@ -120,12 +120,6 @@ with open("/path/to/file.txt", mode="r") as read_file:
```diff
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
-import random
+NOT_YET_IMPLEMENTED_StmtImport
def foo1():
@@ -27,16 +27,16 @@
@@ -151,7 +145,7 @@ with open("/path/to/file.txt", mode="r") as read_file:
## Ruff Output
```py
NOT_YET_IMPLEMENTED_StmtImport
import random
def foo1():

View File

@@ -111,7 +111,7 @@ x53 = (
## Output
```py
NOT_YET_IMPLEMENTED_StmtImportFrom
from argparse import Namespace
a = Namespace()

View File

@@ -299,9 +299,9 @@ not (aaaaaaaaaaaaaa + {NOT_IMPLEMENTED_set_value for value in NOT_IMPLEMENTED_se
[
a
+ [
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
]
in c,
in c
]

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