mirror of https://github.com/astral-sh/ruff
fix-20874
This commit is contained in:
parent
e1e3eb7209
commit
b0a9f51753
|
|
@ -269,6 +269,45 @@ mod tests {
|
||||||
",
|
",
|
||||||
"PD011_pass_node_name"
|
"PD011_pass_node_name"
|
||||||
)]
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r"
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
unique = np.unique_inverse([1, 2, 3, 2, 1])
|
||||||
|
result = unique.values
|
||||||
|
",
|
||||||
|
"PD011_pass_numpy_unique_inverse"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r"
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
unique = np.unique_all([1, 2, 3, 2, 1])
|
||||||
|
result = unique.values
|
||||||
|
",
|
||||||
|
"PD011_pass_numpy_unique_all"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r"
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
unique = np.unique_counts([1, 2, 3, 2, 1])
|
||||||
|
result = unique.values
|
||||||
|
",
|
||||||
|
"PD011_pass_numpy_unique_counts"
|
||||||
|
)]
|
||||||
|
#[test_case(
|
||||||
|
r"
|
||||||
|
import pandas as pd
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from numpy.lib._arraysetops_impl import UniqueInverseResult
|
||||||
|
import numpy as np
|
||||||
|
unique: UniqueInverseResult[np.uint64] = np.unique_inverse([1, 2, 3, 2, 1])
|
||||||
|
result = unique.values
|
||||||
|
",
|
||||||
|
"PD011_pass_numpy_typed_unique_inverse"
|
||||||
|
)]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
r#"
|
r#"
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
use ruff_macros::{ViolationMetadata, derive_message_formats};
|
||||||
use ruff_python_ast::{self as ast, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_python_semantic::Modules;
|
use ruff_python_semantic::{Modules, analyze::typing::find_binding_value};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::Violation;
|
use crate::Violation;
|
||||||
|
|
@ -43,6 +43,38 @@ impl Violation for PandasUseOfDotValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a binding comes from a NumPy function that returns a `NamedTuple` with a `.values` field.
|
||||||
|
fn is_numpy_namedtuple_binding(
|
||||||
|
expr: &Expr,
|
||||||
|
semantic: &ruff_python_semantic::SemanticModel,
|
||||||
|
) -> bool {
|
||||||
|
let Expr::Name(name) = expr else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(binding_id) = semantic.resolve_name(name) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let binding = semantic.binding(binding_id);
|
||||||
|
|
||||||
|
let Some(assigned_value) = find_binding_value(binding, semantic) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(call_expr) = assigned_value.as_call_expr() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(qualified_name) = semantic.resolve_qualified_name(&call_expr.func) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
matches!(
|
||||||
|
qualified_name.segments(),
|
||||||
|
["numpy", "unique_inverse" | "unique_all" | "unique_counts"]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// PD011
|
/// PD011
|
||||||
pub(crate) fn attr(checker: &Checker, attribute: &ast::ExprAttribute) {
|
pub(crate) fn attr(checker: &Checker, attribute: &ast::ExprAttribute) {
|
||||||
if !checker.semantic().seen_module(Modules::PANDAS) {
|
if !checker.semantic().seen_module(Modules::PANDAS) {
|
||||||
|
|
@ -77,5 +109,10 @@ pub(crate) fn attr(checker: &Checker, attribute: &ast::ExprAttribute) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid flagging on NumPy `NamedTuples` that have a legitimate `.values` field
|
||||||
|
if is_numpy_namedtuple_binding(attribute.value.as_ref(), checker.semantic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
checker.report_diagnostic(PandasUseOfDotValues, attribute.range());
|
checker.report_diagnostic(PandasUseOfDotValues, attribute.range());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pandas_vet/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pandas_vet/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pandas_vet/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/pandas_vet/mod.rs
|
||||||
|
---
|
||||||
|
|
||||||
Loading…
Reference in New Issue