mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 06:11:43 +00:00

## Summary This PR updates Ruff to **not** generate auto-fixes if the source code contains syntax errors as determined by the parser. The main motivation behind this is to avoid infinite autofix loop when the token-based rules are run over any source with syntax errors in #11950. Although even after this, it's not certain that there won't be an infinite autofix loop because the logic might be incorrect. For example, https://github.com/astral-sh/ruff/issues/12094 and https://github.com/astral-sh/ruff/pull/12136. This requires updating the test infrastructure to not validate for fix availability status when the source contained syntax errors. This is required because otherwise the fuzzer might fail as it uses the test function to run the linter and validate the source code. resolves: #11455 ## Test Plan `cargo insta test`
652 lines
6.6 KiB
Python
652 lines
6.6 KiB
Python
# ==> bad_function_call.py <==
|
|
bad_function_call(
|
|
param1='test',
|
|
param2='test'
|
|
)
|
|
# ==> bad_list.py <==
|
|
bad_list = [
|
|
1,
|
|
2,
|
|
3
|
|
]
|
|
|
|
bad_list_with_comment = [
|
|
1,
|
|
2,
|
|
3
|
|
# still needs a comma!
|
|
]
|
|
|
|
bad_list_with_extra_empty = [
|
|
1,
|
|
2,
|
|
3
|
|
|
|
|
|
|
|
]
|
|
|
|
# ==> bare.py <==
|
|
bar = 1, 2
|
|
|
|
foo = 1
|
|
|
|
foo = (1,)
|
|
|
|
foo = 1,
|
|
|
|
bar = 1; foo = bar,
|
|
|
|
foo = (
|
|
3,
|
|
4,
|
|
)
|
|
|
|
foo = 3,
|
|
|
|
class A(object):
|
|
foo = 3
|
|
bar = 10,
|
|
foo_bar = 2
|
|
|
|
a = ('a',)
|
|
|
|
from foo import bar, baz
|
|
|
|
group_by = function_call('arg'),
|
|
|
|
group_by = ('foobar' * 3),
|
|
|
|
def foo():
|
|
return False,
|
|
|
|
# ==> callable_before_parenth_form.py <==
|
|
def foo(
|
|
bar,
|
|
):
|
|
pass
|
|
|
|
{'foo': foo}['foo'](
|
|
bar
|
|
)
|
|
|
|
{'foo': foo}['foo'](
|
|
bar,
|
|
)
|
|
|
|
(foo)(
|
|
bar
|
|
)
|
|
|
|
(foo)[0](
|
|
bar,
|
|
)
|
|
|
|
[foo][0](
|
|
bar
|
|
)
|
|
|
|
[foo][0](
|
|
bar,
|
|
)
|
|
|
|
# ==> comment_good_dict.py <==
|
|
multiline_good_dict = {
|
|
"good": 123, # this is a good number
|
|
}
|
|
|
|
# ==> dict_comprehension.py <==
|
|
not_a_dict = {
|
|
x: y
|
|
for x, y in ((1, 2), (3, 4))
|
|
}
|
|
|
|
# ==> good_empty_comma_context.py <==
|
|
def func2(
|
|
):
|
|
pass
|
|
|
|
|
|
func2(
|
|
|
|
)
|
|
|
|
func2(
|
|
)
|
|
|
|
[
|
|
]
|
|
|
|
[
|
|
|
|
]
|
|
|
|
(
|
|
)
|
|
|
|
(
|
|
|
|
)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
# ==> good_list.py <==
|
|
stuff = [
|
|
'a',
|
|
'b',
|
|
# more stuff will go here
|
|
]
|
|
|
|
more_stuff = [
|
|
'a',
|
|
'b',
|
|
|
|
|
|
|
|
]
|
|
|
|
# ==> keyword_before_parenth_form/base_bad.py <==
|
|
from x import (
|
|
y
|
|
)
|
|
|
|
assert(
|
|
SyntaxWarning,
|
|
ThrownHere,
|
|
Anyway
|
|
)
|
|
|
|
# async await is fine outside an async def
|
|
# ruff: RustPython tokenizer treats async/await as keywords, not applicable.
|
|
|
|
# def await(
|
|
# foo
|
|
# ):
|
|
# async(
|
|
# foo
|
|
# )
|
|
|
|
# def async(
|
|
# foo
|
|
# ):
|
|
# await(
|
|
# foo
|
|
# )
|
|
|
|
# ==> keyword_before_parenth_form/base.py <==
|
|
from x import (
|
|
y,
|
|
)
|
|
|
|
assert(
|
|
SyntaxWarning,
|
|
ThrownHere,
|
|
Anyway,
|
|
)
|
|
|
|
assert (
|
|
foo
|
|
)
|
|
|
|
assert (
|
|
foo and
|
|
bar
|
|
)
|
|
|
|
if(
|
|
foo and
|
|
bar
|
|
):
|
|
pass
|
|
elif(
|
|
foo and
|
|
bar
|
|
):
|
|
pass
|
|
|
|
for x in(
|
|
[1,2,3]
|
|
):
|
|
print(x)
|
|
|
|
|
|
(x for x in (
|
|
[1, 2, 3]
|
|
))
|
|
|
|
(
|
|
'foo'
|
|
) is (
|
|
'foo'
|
|
)
|
|
|
|
if (
|
|
foo and
|
|
bar
|
|
) or not (
|
|
foo
|
|
) or (
|
|
spam
|
|
):
|
|
pass
|
|
|
|
def xyz():
|
|
raise(
|
|
Exception()
|
|
)
|
|
|
|
def abc():
|
|
return(
|
|
3
|
|
)
|
|
|
|
while(
|
|
False
|
|
):
|
|
pass
|
|
|
|
with(
|
|
loop
|
|
):
|
|
pass
|
|
|
|
def foo():
|
|
yield (
|
|
"foo"
|
|
)
|
|
|
|
# async await is fine outside an async def
|
|
# ruff: RustPython tokenizer treats async/await as keywords, not applicable.
|
|
|
|
# def await(
|
|
# foo,
|
|
# ):
|
|
# async(
|
|
# foo,
|
|
# )
|
|
|
|
# def async(
|
|
# foo,
|
|
# ):
|
|
# await(
|
|
# foo,
|
|
# )
|
|
|
|
# ==> keyword_before_parenth_form/py3.py <==
|
|
# Syntax error in Py2
|
|
|
|
def foo():
|
|
yield from (
|
|
foo
|
|
)
|
|
|
|
# ==> list_comprehension.py <==
|
|
not_a_list = [
|
|
s.strip()
|
|
for s in 'foo, bar, baz'.split(',')
|
|
]
|
|
|
|
# ==> multiline_bad_dict.py <==
|
|
multiline_bad_dict = {
|
|
"bad": 123
|
|
}
|
|
# ==> multiline_bad_function_def.py <==
|
|
def func_good(
|
|
a = 3,
|
|
b = 2):
|
|
pass
|
|
|
|
|
|
def func_bad(
|
|
a = 3,
|
|
b = 2
|
|
):
|
|
pass
|
|
|
|
# ==> multiline_bad_function_one_param.py <==
|
|
def func(
|
|
a = 3
|
|
):
|
|
pass
|
|
|
|
|
|
func(
|
|
a = 3
|
|
)
|
|
|
|
# ==> multiline_bad_or_dict.py <==
|
|
multiline_bad_or_dict = {
|
|
"good": True or False,
|
|
"bad": 123
|
|
}
|
|
|
|
# ==> multiline_good_dict.py <==
|
|
multiline_good_dict = {
|
|
"good": 123,
|
|
}
|
|
# ==> multiline_good_single_keyed_for_dict.py <==
|
|
good_dict = {
|
|
"good": x for x in y
|
|
}
|
|
|
|
# ==> multiline_if.py <==
|
|
if (
|
|
foo
|
|
and bar
|
|
):
|
|
print("Baz")
|
|
|
|
# ==> multiline_index_access.py <==
|
|
multiline_index_access[
|
|
"good"
|
|
]
|
|
|
|
multiline_index_access_after_function()[
|
|
"good"
|
|
]
|
|
|
|
multiline_index_access_after_inline_index_access['first'][
|
|
"good"
|
|
]
|
|
|
|
multiline_index_access[
|
|
"probably fine",
|
|
]
|
|
|
|
[0, 1, 2][
|
|
"good"
|
|
]
|
|
|
|
[0, 1, 2][
|
|
"probably fine",
|
|
]
|
|
|
|
multiline_index_access[
|
|
"probably fine",
|
|
"not good"
|
|
]
|
|
|
|
multiline_index_access[
|
|
"fine",
|
|
"fine",
|
|
:
|
|
"not good"
|
|
]
|
|
|
|
# ==> multiline_string.py <==
|
|
s = (
|
|
'this' +
|
|
'is a string'
|
|
)
|
|
|
|
s2 = (
|
|
'this'
|
|
'is also a string'
|
|
)
|
|
|
|
t = (
|
|
'this' +
|
|
'is a tuple',
|
|
)
|
|
|
|
t2 = (
|
|
'this'
|
|
'is also a tuple',
|
|
)
|
|
|
|
# ==> multiline_subscript_slice.py <==
|
|
multiline_index_access[
|
|
"fine",
|
|
"fine"
|
|
:
|
|
"not fine"
|
|
]
|
|
|
|
multiline_index_access[
|
|
"fine"
|
|
"fine"
|
|
:
|
|
"fine"
|
|
:
|
|
"fine"
|
|
]
|
|
|
|
multiline_index_access[
|
|
"fine"
|
|
"fine",
|
|
:
|
|
"fine",
|
|
:
|
|
"fine",
|
|
]
|
|
|
|
multiline_index_access[
|
|
"fine"
|
|
"fine",
|
|
:
|
|
"fine"
|
|
:
|
|
"fine",
|
|
"not fine"
|
|
]
|
|
|
|
multiline_index_access[
|
|
"fine"
|
|
"fine",
|
|
:
|
|
"fine",
|
|
"fine"
|
|
:
|
|
"fine",
|
|
]
|
|
|
|
multiline_index_access[
|
|
lambda fine1,
|
|
fine2,
|
|
fine3: (0,)
|
|
:
|
|
lambda fine1,
|
|
fine2,
|
|
fine3: (0,),
|
|
"fine"
|
|
:
|
|
"fine",
|
|
]
|
|
|
|
# ==> one_line_dict.py <==
|
|
one_line_dict = {"good": 123}
|
|
# ==> parenth_form.py <==
|
|
parenth_form = (
|
|
a +
|
|
b +
|
|
c
|
|
)
|
|
|
|
parenth_form_with_lambda = (
|
|
lambda x, y: 0
|
|
)
|
|
|
|
parenth_form_with_default_lambda = (
|
|
lambda x=(
|
|
lambda
|
|
x,
|
|
y,
|
|
:
|
|
0
|
|
),
|
|
y = {a: b},
|
|
:
|
|
0
|
|
)
|
|
|
|
# ==> prohibited.py <==
|
|
foo = ['a', 'b', 'c',]
|
|
|
|
bar = { a: b,}
|
|
|
|
def bah(ham, spam,):
|
|
pass
|
|
|
|
(0,)
|
|
|
|
(0, 1,)
|
|
|
|
foo = ['a', 'b', 'c', ]
|
|
|
|
bar = { a: b, }
|
|
|
|
def bah(ham, spam, ):
|
|
pass
|
|
|
|
(0, )
|
|
|
|
(0, 1, )
|
|
|
|
image[:, :, 0]
|
|
|
|
image[:,]
|
|
|
|
image[:,:,]
|
|
|
|
lambda x, : x
|
|
|
|
# ==> unpack.py <==
|
|
def function(
|
|
foo,
|
|
bar,
|
|
**kwargs
|
|
):
|
|
pass
|
|
|
|
def function(
|
|
foo,
|
|
bar,
|
|
*args
|
|
):
|
|
pass
|
|
|
|
def function(
|
|
foo,
|
|
bar,
|
|
*args,
|
|
extra_kwarg
|
|
):
|
|
pass
|
|
|
|
result = function(
|
|
foo,
|
|
bar,
|
|
**kwargs
|
|
)
|
|
|
|
result = function(
|
|
foo,
|
|
bar,
|
|
**not_called_kwargs
|
|
)
|
|
|
|
def foo(
|
|
ham,
|
|
spam,
|
|
*args,
|
|
kwarg_only
|
|
):
|
|
pass
|
|
|
|
# In python 3.5 if it's not a function def, commas are mandatory.
|
|
|
|
foo(
|
|
**kwargs
|
|
)
|
|
|
|
{
|
|
**kwargs
|
|
}
|
|
|
|
{
|
|
*args
|
|
}
|
|
|
|
[
|
|
*args
|
|
]
|
|
|
|
def foo(
|
|
ham,
|
|
spam,
|
|
*args
|
|
):
|
|
pass
|
|
|
|
def foo(
|
|
ham,
|
|
spam,
|
|
**kwargs
|
|
):
|
|
pass
|
|
|
|
def foo(
|
|
ham,
|
|
spam,
|
|
*args,
|
|
kwarg_only
|
|
):
|
|
pass
|
|
|
|
# In python 3.5 if it's not a function def, commas are mandatory.
|
|
|
|
foo(
|
|
**kwargs,
|
|
)
|
|
|
|
{
|
|
**kwargs,
|
|
}
|
|
|
|
(
|
|
*args,
|
|
)
|
|
|
|
{
|
|
*args,
|
|
}
|
|
|
|
[
|
|
*args,
|
|
]
|
|
|
|
result = function(
|
|
foo,
|
|
bar,
|
|
**{'ham': spam}
|
|
)
|
|
|
|
# Make sure the COM812 and UP034 rules don't fix simultaneously and cause a syntax error.
|
|
the_first_one = next(
|
|
(i for i in range(10) if i // 2 == 0) # COM812 fix should include the final bracket
|
|
)
|
|
|
|
foo = namedtuple(
|
|
name="foo",
|
|
status="bar",
|
|
message="sfdsdfsdgs fsdfsdf output!dsfdfsdjkg ghfskdjghkdssd sd fsdf s\n"[
|
|
:20
|
|
],
|
|
)
|
|
|
|
# F-strings
|
|
kwargs.pop("remove", f"this {trailing_comma}",)
|
|
|
|
raise Exception(
|
|
"first", extra=f"Add trailing comma here ->"
|
|
)
|
|
|
|
assert False, f"<- This is not a trailing comma"
|
|
|
|
f"""This is a test. {
|
|
"Another sentence."
|
|
if True else
|
|
"Don't add a trailing comma here ->"
|
|
}"""
|