Ignore stub file assignments to value-requiring targets (#4030)

This commit is contained in:
Charlie Marsh 2023-04-19 15:26:00 -04:00 committed by GitHub
parent 10d5415bcb
commit cc8b5a543b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 27 deletions

View File

@ -50,3 +50,37 @@ field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
# We shouldn't emit Y015 within functions
def f():
field26: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# We shouldn't emit Y015 for __slots__ or __match_args__
class Class1:
__slots__ = (
'_one',
'_two',
'_three',
'_four',
'_five',
'_six',
'_seven',
'_eight',
'_nine',
'_ten',
'_eleven',
)
__match_args__ = (
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
)
# We shouldn't emit Y015 for __all__
__all__ = ["Class1"]

View File

@ -57,3 +57,37 @@ field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
# We shouldn't emit Y015 within functions
def f():
field26: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# We shouldn't emit Y015 for __slots__ or __match_args__
class Class1:
__slots__ = (
'_one',
'_two',
'_three',
'_four',
'_five',
'_six',
'_seven',
'_eight',
'_nine',
'_ten',
'_eleven',
)
__match_args__ = (
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
)
# We shouldn't emit Y015 for __all__
__all__ = ["Class1"]

View File

@ -1842,7 +1842,7 @@ where
flake8_pyi::rules::prefix_type_params(self, value, targets);
}
if self.settings.rules.enabled(Rule::AssignmentDefaultInStub) {
flake8_pyi::rules::assignment_default_in_stub(self, value, None);
flake8_pyi::rules::assignment_default_in_stub(self, targets, value);
}
}
}
@ -1882,10 +1882,8 @@ where
if self.settings.rules.enabled(Rule::AssignmentDefaultInStub) {
// Ignore assignments in function bodies; those are covered by other rules.
if !self.ctx.scopes().any(|scope| scope.kind.is_function()) {
flake8_pyi::rules::assignment_default_in_stub(
self,
value,
Some(annotation),
flake8_pyi::rules::annotated_assignment_default_in_stub(
self, target, value, annotation,
);
}
}

View File

@ -6,8 +6,9 @@ pub use pass_in_class_body::{pass_in_class_body, PassInClassBody};
pub use pass_statement_stub_body::{pass_statement_stub_body, PassStatementStubBody};
pub use prefix_type_params::{prefix_type_params, UnprefixedTypeParam};
pub use simple_defaults::{
argument_simple_defaults, assignment_default_in_stub, typed_argument_simple_defaults,
ArgumentDefaultInStub, AssignmentDefaultInStub, TypedArgumentDefaultInStub,
annotated_assignment_default_in_stub, argument_simple_defaults, assignment_default_in_stub,
typed_argument_simple_defaults, ArgumentDefaultInStub, AssignmentDefaultInStub,
TypedArgumentDefaultInStub,
};
pub use type_comment_in_stub::{type_comment_in_stub, TypeCommentInStub};
pub use unrecognized_platform::{

View File

@ -11,7 +11,6 @@ use crate::registry::AsRule;
#[violation]
pub struct TypedArgumentDefaultInStub;
/// PYI011
impl AlwaysAutofixableViolation for TypedArgumentDefaultInStub {
#[derive_message_formats]
fn message(&self) -> String {
@ -26,7 +25,6 @@ impl AlwaysAutofixableViolation for TypedArgumentDefaultInStub {
#[violation]
pub struct ArgumentDefaultInStub;
/// PYI014
impl AlwaysAutofixableViolation for ArgumentDefaultInStub {
#[derive_message_formats]
fn message(&self) -> String {
@ -41,7 +39,6 @@ impl AlwaysAutofixableViolation for ArgumentDefaultInStub {
#[violation]
pub struct AssignmentDefaultInStub;
/// PYI015
impl AlwaysAutofixableViolation for AssignmentDefaultInStub {
#[derive_message_formats]
fn message(&self) -> String {
@ -239,6 +236,20 @@ fn is_type_var_like_call(context: &Context, expr: &Expr) -> bool {
})
}
/// Returns `true` if this is a "special" assignment which must have a value (e.g., an assignment to
/// `__all__`).
fn is_special_assignment(context: &Context, target: &Expr) -> bool {
if let ExprKind::Name { id, .. } = &target.node {
match id.as_str() {
"__all__" => context.scope().kind.is_module(),
"__match_args__" | "__slots__" => context.scope().kind.is_class(),
_ => false,
}
} else {
false
}
}
/// PYI011
pub fn typed_argument_simple_defaults(checker: &mut Checker, args: &Arguments) {
if !args.defaults.is_empty() {
@ -354,18 +365,18 @@ pub fn argument_simple_defaults(checker: &mut Checker, args: &Arguments) {
}
/// PYI015
pub fn assignment_default_in_stub(checker: &mut Checker, value: &Expr, annotation: Option<&Expr>) {
if annotation.map_or(false, |annotation| {
checker.ctx.match_typing_expr(annotation, "TypeAlias")
}) {
pub fn assignment_default_in_stub(checker: &mut Checker, targets: &[Expr], value: &Expr) {
if targets.len() == 1 && is_special_assignment(&checker.ctx, &targets[0]) {
return;
}
if is_type_var_like_call(&checker.ctx, value) {
return;
}
if !is_valid_default_value_with_annotation(value, checker, true) {
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, Range::from(value));
if is_valid_default_value_with_annotation(value, checker, true) {
return;
}
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, Range::from(value));
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Edit::replacement(
"...".to_string(),
@ -373,7 +384,36 @@ pub fn assignment_default_in_stub(checker: &mut Checker, value: &Expr, annotatio
value.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
}
/// PYI015
pub fn annotated_assignment_default_in_stub(
checker: &mut Checker,
target: &Expr,
value: &Expr,
annotation: &Expr,
) {
if checker.ctx.match_typing_expr(annotation, "TypeAlias") {
return;
}
if is_special_assignment(&checker.ctx, target) {
return;
}
if is_type_var_like_call(&checker.ctx, value) {
return;
}
if is_valid_default_value_with_annotation(value, checker, true) {
return;
}
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, Range::from(value));
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Edit::replacement(
"...".to_string(),
value.location,
value.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
}