Skip to content

Commit

Permalink
Improve other areas of the semantic model also
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexWaygood committed Apr 15, 2024
1 parent ce2b014 commit 08c5e30
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 15 deletions.
16 changes: 16 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/refurb/FURB129.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ def func():
pass


import builtins


with builtins.open("FURB129.py") as f:
for line in f.readlines():
pass


from builtins import open as o


with o("FURB129.py") as f:
for line in f.readlines():
pass


# False positives
def func(f):
for _line in f.readlines():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,40 @@ FURB129.py:38:22: FURB129 [*] Instead of calling `readlines()`, iterate over fil
40 40 | for _line in bar.readlines():
41 41 | pass

FURB129.py:48:17: FURB129 [*] Instead of calling `readlines()`, iterate over file object directly
|
47 | with builtins.open("FURB129.py") as f:
48 | for line in f.readlines():
| ^^^^^^^^^^^^^ FURB129
49 | pass
|
= help: Remove `readlines()`

Unsafe fix
45 45 |
46 46 |
47 47 | with builtins.open("FURB129.py") as f:
48 |- for line in f.readlines():
48 |+ for line in f:
49 49 | pass
50 50 |
51 51 |

FURB129.py:56:17: FURB129 [*] Instead of calling `readlines()`, iterate over file object directly
|
55 | with o("FURB129.py") as f:
56 | for line in f.readlines():
| ^^^^^^^^^^^^^ FURB129
57 | pass
|
= help: Remove `readlines()`

Unsafe fix
53 53 |
54 54 |
55 55 | with o("FURB129.py") as f:
56 |- for line in f.readlines():
56 |+ for line in f:
57 57 | pass
58 58 |
59 59 |
6 changes: 3 additions & 3 deletions crates/ruff_python_semantic/src/analyze/function_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn classify(
semantic
.resolve_qualified_name(map_callable(expr))
.is_some_and( |qualified_name| {
matches!(qualified_name.segments(), ["", "type"] | ["abc", "ABCMeta"])
matches!(qualified_name.segments(), ["" | "builtins", "type"] | ["abc", "ABCMeta"])
})
})
|| decorator_list.iter().any(|decorator| is_class_method(decorator, semantic, classmethod_decorators))
Expand All @@ -63,7 +63,7 @@ fn is_static_method(
.is_some_and(|qualified_name| {
matches!(
qualified_name.segments(),
["", "staticmethod"] | ["abc", "abstractstaticmethod"]
["" | "builtins", "staticmethod"] | ["abc", "abstractstaticmethod"]
) || staticmethod_decorators
.iter()
.any(|decorator| qualified_name == QualifiedName::from_dotted_name(decorator))
Expand Down Expand Up @@ -103,7 +103,7 @@ fn is_class_method(
.is_some_and(|qualified_name| {
matches!(
qualified_name.segments(),
["", "classmethod"] | ["abc", "abstractclassmethod"]
["" | "builtins", "classmethod"] | ["abc", "abstractclassmethod"]
) || classmethod_decorators
.iter()
.any(|decorator| qualified_name == QualifiedName::from_dotted_name(decorator))
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff_python_semantic/src/analyze/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ impl TypeChecker for IoBaseChecker {
.is_some_and(|qualified_name| {
matches!(
qualified_name.segments(),
["io", "open" | "open_code"] | ["os" | "", "open"]
["io", "open" | "open_code"] | ["os" | "" | "builtins", "open"]
)
})
}
Expand Down
18 changes: 7 additions & 11 deletions crates/ruff_python_semantic/src/analyze/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,16 @@ pub enum Visibility {

/// Returns `true` if a function is a "static method".
pub fn is_staticmethod(decorator_list: &[Decorator], semantic: &SemanticModel) -> bool {
decorator_list.iter().any(|decorator| {
semantic
.resolve_qualified_name(map_callable(&decorator.expression))
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["", "staticmethod"]))
})
decorator_list
.iter()
.any(|decorator| semantic.match_builtin_expr(&decorator.expression, "staticmethod"))
}

/// Returns `true` if a function is a "class method".
pub fn is_classmethod(decorator_list: &[Decorator], semantic: &SemanticModel) -> bool {
decorator_list.iter().any(|decorator| {
semantic
.resolve_qualified_name(map_callable(&decorator.expression))
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["", "classmethod"]))
})
decorator_list
.iter()
.any(|decorator| semantic.match_builtin_expr(&decorator.expression, "classmethod"))
}

/// Returns `true` if a function definition is an `@overload`.
Expand Down Expand Up @@ -79,7 +75,7 @@ pub fn is_property(
.is_some_and(|qualified_name| {
matches!(
qualified_name.segments(),
["", "property"] | ["functools", "cached_property"]
["" | "builtins", "property"] | ["functools", "cached_property"]
) || extra_properties
.iter()
.any(|extra_property| extra_property.segments() == qualified_name.segments())
Expand Down

0 comments on commit 08c5e30

Please sign in to comment.