Skip to content

Commit

Permalink
[flake8-pyi] Add "replace with Self" fix (PYI019) (#14238)
Browse files Browse the repository at this point in the history
Co-authored-by: Micha Reiser <micha@reiser.io>
  • Loading branch information
InSyncWithFoo and MichaReiser authored Nov 12, 2024
1 parent be69f61 commit 13a1483
Show file tree
Hide file tree
Showing 9 changed files with 1,045 additions and 64 deletions.
35 changes: 35 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,38 @@ class CustomClassMethod:
# in the settings for this test:
@foo_classmethod
def foo[S](cls: type[S]) -> S: ... # PYI019


_S695 = TypeVar("_S695", bound="PEP695Fix")

# Only .pyi gets fixes, no fixes for .py
class PEP695Fix:
def __new__[S: PEP695Fix](cls: type[S]) -> S: ...

def __init_subclass__[S](cls: type[S]) -> S: ...

def __neg__[S: PEP695Fix](self: S) -> S: ...

def __pos__[S](self: S) -> S: ...

def __add__[S: PEP695Fix](self: S, other: S) -> S: ...

def __sub__[S](self: S, other: S) -> S: ...

@classmethod
def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...

@classmethod
def class_method_unbound[S](cls: type[S]) -> S: ...

def instance_method_bound[S: PEP695Fix](self: S) -> S: ...

def instance_method_unbound[S](self: S) -> S: ...

def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...

def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...

def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...

def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
35 changes: 35 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI019.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,38 @@ class CustomClassMethod:
# in the settings for this test:
@foo_classmethod
def foo[S](cls: type[S]) -> S: ... # PYI019


_S695 = TypeVar("_S695", bound="PEP695Fix")

# Only .pyi gets fixes, no fixes for .py
class PEP695Fix:
def __new__[S: PEP695Fix](cls: type[S]) -> S: ...

def __init_subclass__[S](cls: type[S]) -> S: ...

def __neg__[S: PEP695Fix](self: S) -> S: ...

def __pos__[S](self: S) -> S: ...

def __add__[S: PEP695Fix](self: S, other: S) -> S: ...

def __sub__[S](self: S, other: S) -> S: ...

@classmethod
def class_method_bound[S: PEP695Fix](cls: type[S]) -> S: ...

@classmethod
def class_method_unbound[S](cls: type[S]) -> S: ...

def instance_method_bound[S: PEP695Fix](self: S) -> S: ...

def instance_method_unbound[S](self: S) -> S: ...

def instance_method_bound_with_another_parameter[S: PEP695Fix](self: S, other: S) -> S: ...

def instance_method_unbound_with_another_parameter[S](self: S, other: S) -> S: ...

def multiple_type_vars[S, *Ts, T](self: S, other: S, /, *args: *Ts, a: T, b: list[T]) -> S: ...

def mixing_old_and_new_style_type_vars[T](self: _S695, a: T, b: T) -> _S695: ...
11 changes: 2 additions & 9 deletions crates/ruff_linter/src/checkers/ast/analyze/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
returns,
parameters,
body,
type_params,
type_params: _,
range: _,
},
) => {
Expand Down Expand Up @@ -160,14 +160,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
flake8_pyi::rules::bad_generator_return_type(function_def, checker);
}
if checker.enabled(Rule::CustomTypeVarReturnType) {
flake8_pyi::rules::custom_type_var_return_type(
checker,
name,
decorator_list,
returns.as_ref().map(AsRef::as_ref),
parameters,
type_params.as_deref(),
);
flake8_pyi::rules::custom_type_var_return_type(checker, function_def);
}
if checker.source_type.is_stub() {
if checker.enabled(Rule::StrOrReprDefinedInStub) {
Expand Down
17 changes: 17 additions & 0 deletions crates/ruff_linter/src/rules/flake8_pyi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,23 @@ mod tests {
Ok(())
}

#[test]
fn custom_classmethod_rules_preview() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_pyi/PYI019.pyi"),
&settings::LinterSettings {
pep8_naming: pep8_naming::settings::Settings {
classmethod_decorators: vec!["foo_classmethod".to_string()],
..pep8_naming::settings::Settings::default()
},
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(Rule::CustomTypeVarReturnType)
},
)?;
assert_messages!(diagnostics);
Ok(())
}

#[test_case(Rule::TypeAliasWithoutAnnotation, Path::new("PYI026.py"))]
#[test_case(Rule::TypeAliasWithoutAnnotation, Path::new("PYI026.pyi"))]
fn py38(rule_code: Rule, path: &Path) -> Result<()> {
Expand Down
Loading

0 comments on commit 13a1483

Please sign in to comment.