From d7ff214df6dda830fe1acdb7336398595227c6c2 Mon Sep 17 00:00:00 2001 From: lucascolley Date: Wed, 29 Nov 2023 16:52:43 +0000 Subject: [PATCH 1/8] [`XP`] Implement `not-array-agnostic-numpy` (`XP001`) --- .../src/checkers/ast/analyze/expression.rs | 7 ++ crates/ruff_linter/src/codes.rs | 3 + crates/ruff_linter/src/registry.rs | 3 + crates/ruff_linter/src/rules/mod.rs | 1 + crates/ruff_linter/src/rules/xp/mod.rs | 26 ++++ crates/ruff_linter/src/rules/xp/rules/mod.rs | 3 + .../xp/rules/not_array_agnostic_numpy.rs | 119 ++++++++++++++++++ ruff.schema.json | 4 + 8 files changed, 166 insertions(+) create mode 100644 crates/ruff_linter/src/rules/xp/mod.rs create mode 100644 crates/ruff_linter/src/rules/xp/rules/mod.rs create mode 100644 crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 7a158449bfcc1..41e748e352c48 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -17,6 +17,7 @@ use crate::rules::{ flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self, flake8_simplify, flake8_tidy_imports, flake8_trio, flake8_use_pathlib, flynt, numpy, pandas_vet, pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, + xp, }; use crate::settings::types::PythonVersion; @@ -164,6 +165,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::CollectionsNamedTuple) { flake8_pyi::rules::collections_named_tuple(checker, expr); } + if checker.enabled(Rule::NotArrayAgnosticNumPy) { + xp::rules::not_array_agnostic_numpy(checker, expr); + } // Ex) List[...] if checker.any_enabled(&[ @@ -338,6 +342,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) { if checker.enabled(Rule::UndocumentedWarn) { flake8_logging::rules::undocumented_warn(checker, expr); } + if checker.enabled(Rule::NotArrayAgnosticNumPy) { + xp::rules::not_array_agnostic_numpy(checker, expr); + } pandas_vet::rules::attr(checker, attribute); } Expr::Call( diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs index 4dc1f13c55e05..92429f24681b2 100644 --- a/crates/ruff_linter/src/codes.rs +++ b/crates/ruff_linter/src/codes.rs @@ -967,6 +967,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Logging, "007") => (RuleGroup::Preview, rules::flake8_logging::rules::ExceptionWithoutExcInfo), (Flake8Logging, "009") => (RuleGroup::Preview, rules::flake8_logging::rules::UndocumentedWarn), + // array-agnosticism (xp) + (XP, "001") => (RuleGroup::Preview, rules::xp::rules::NotArrayAgnosticNumPy), + _ => return None, }) } diff --git a/crates/ruff_linter/src/registry.rs b/crates/ruff_linter/src/registry.rs index 2e6fcc199580e..83172fc6bae72 100644 --- a/crates/ruff_linter/src/registry.rs +++ b/crates/ruff_linter/src/registry.rs @@ -208,6 +208,9 @@ pub enum Linter { /// Ruff-specific rules #[prefix = "RUF"] Ruff, + /// [Array-agnosticism](https://data-apis.org/array-api/latest/) + #[prefix = "XP"] + XP, } pub trait RuleNamespace: Sized { diff --git a/crates/ruff_linter/src/rules/mod.rs b/crates/ruff_linter/src/rules/mod.rs index 64b0128cae164..eb4fe09618f8b 100644 --- a/crates/ruff_linter/src/rules/mod.rs +++ b/crates/ruff_linter/src/rules/mod.rs @@ -57,3 +57,4 @@ pub mod pyupgrade; pub mod refurb; pub mod ruff; pub mod tryceratops; +pub mod xp; diff --git a/crates/ruff_linter/src/rules/xp/mod.rs b/crates/ruff_linter/src/rules/xp/mod.rs new file mode 100644 index 0000000000000..4586234f617aa --- /dev/null +++ b/crates/ruff_linter/src/rules/xp/mod.rs @@ -0,0 +1,26 @@ +//! NumPy-specific rules. +pub(crate) mod rules; + +#[cfg(test)] +mod tests { + use std::convert::AsRef; + use std::path::Path; + + use anyhow::Result; + use test_case::test_case; + + use crate::registry::Rule; + use crate::test::test_path; + use crate::{assert_messages, settings}; + + #[test_case(Rule::NotArrayAgnosticNumPy, Path::new("XP001.py"))] + fn rules(rule_code: Rule, path: &Path) -> Result<()> { + let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy()); + let diagnostics = test_path( + Path::new("xp").join(path).as_path(), + &settings::LinterSettings::for_rule(rule_code), + )?; + assert_messages!(snapshot, diagnostics); + Ok(()) + } +} diff --git a/crates/ruff_linter/src/rules/xp/rules/mod.rs b/crates/ruff_linter/src/rules/xp/rules/mod.rs new file mode 100644 index 0000000000000..bfc3ec00276b9 --- /dev/null +++ b/crates/ruff_linter/src/rules/xp/rules/mod.rs @@ -0,0 +1,3 @@ +pub(crate) use not_array_agnostic_numpy::*; + +mod not_array_agnostic_numpy; diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs new file mode 100644 index 0000000000000..5bdb256f1ef1d --- /dev/null +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -0,0 +1,119 @@ +/// use ... +use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; +use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::Expr; +use ruff_text_size::Ranged; + +use crate::checkers::ast::Checker; +use crate::importer::ImportRequest; + +/// ## What it does +/// + +#[violation] +pub struct NotArrayAgnosticNumPy { + existing: String, + migration_guide: Option, + code_action: Option, +} + +impl Violation for NotArrayAgnosticNumPy { + const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes; + + #[derive_message_formats] + fn message(&self) -> String { + let NotArrayAgnosticNumPy { + existing, + migration_guide, + code_action: _, + } = self; + match migration_guide { + Some(migration_guide) => { + format!("`{existing}` is not in the array API standard. {migration_guide}",) + } + None => format!("`{existing}` is not in the array API standard."), + } + } + + fn fix_title(&self) -> Option { + let NotArrayAgnosticNumPy { + existing: _, + migration_guide: _, + code_action, + } = self; + code_action.clone() + } +} + +#[derive(Debug)] +struct Replacement<'a> { + existing: &'a str, + details: Details<'a>, +} + +#[derive(Debug)] +enum Details<'a> { + /// There is a direct replacement in the array API standard. + AutoImport { path: &'a str, name: &'a str }, + /// There is no direct replacement in the standard. + Manual { guideline: Option<&'a str> }, +} + +impl Details<'_> { + fn guideline(&self) -> Option { + match self { + Details::AutoImport { path, name } => Some(format!("Use `{path}.{name}` instead.")), + Details::Manual { guideline } => guideline.map(ToString::to_string), + } + } + + fn code_action(&self) -> Option { + match self { + Details::AutoImport { path, name } => Some(format!("Replace with `{path}.{name}`")), + Details::Manual { guideline: _ } => None, + } + } +} + +///XP001 +pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { + let maybe_replacement = checker + .semantic() + .resolve_call_path(expr) + .and_then(|call_path| match call_path.as_slice() { + ["numpy", "arccos"] => Some(Replacement { + existing: "arccos", + details: Details::AutoImport { + path: "numpy", + name: "acos", + }, + }), + _ => None, + }); + + if let Some(replacement) = maybe_replacement { + let mut diagnostic = Diagnostic::new( + NotArrayAgnosticNumPy { + existing: replacement.existing.to_string(), + migration_guide: replacement.details.guideline(), + code_action: replacement.details.code_action(), + }, + expr.range(), + ); + match replacement.details { + Details::AutoImport { path, name } => { + diagnostic.try_set_fix(|| { + let (import_edit, binding) = checker.importer().get_or_import_symbol( + &ImportRequest::import_from(path, name), + expr.start(), + checker.semantic(), + )?; + let replacement_edit = Edit::range_replacement(binding, expr.range()); + Ok(Fix::unsafe_edits(import_edit, [replacement_edit])) + }); + } + Details::Manual { guideline: _ } => {} + }; + checker.diagnostics.push(diagnostic); + } +} diff --git a/ruff.schema.json b/ruff.schema.json index cb37f44161c40..f7c584611b1f1 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -3608,6 +3608,10 @@ "W6", "W60", "W605", + "XP", + "XP0", + "XP00", + "XP001", "YTT", "YTT1", "YTT10", From c4cc567535454b6eab77036a9843629481d7e5b7 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Sun, 3 Dec 2023 10:24:25 +0000 Subject: [PATCH 2/8] Update registry.rs --- crates/ruff_linter/src/registry.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/registry.rs b/crates/ruff_linter/src/registry.rs index 83172fc6bae72..e7d4cb06b007a 100644 --- a/crates/ruff_linter/src/registry.rs +++ b/crates/ruff_linter/src/registry.rs @@ -208,7 +208,7 @@ pub enum Linter { /// Ruff-specific rules #[prefix = "RUF"] Ruff, - /// [Array-agnosticism](https://data-apis.org/array-api/latest/) + /// [Array-agnosticism](https://github.com/data-apis/array-api) #[prefix = "XP"] XP, } From 1dea25deea86186bb21a98f95d7bb25f41f76982 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 15:36:59 +0000 Subject: [PATCH 3/8] add alias cases --- .../xp/rules/not_array_agnostic_numpy.rs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index 5bdb256f1ef1d..f5de1bfa5c25a 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -88,6 +88,97 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { name: "acos", }, }), + ["numpy", "arccosh"] => Some(Replacement { + existing: "arccosh", + details: Details::AutoImport { + path: "numpy", + name: "acosh", + }, + }), + ["numpy", "arcsin"] => Some(Replacement { + existing: "arcsin", + details: Details::AutoImport { + path: "numpy", + name: "asin", + }, + }), + ["numpy", "arcsinh"] => Some(Replacement { + existing: "arcsinh", + details: Details::AutoImport { + path: "numpy", + name: "asinh", + }, + }), + ["numpy", "arctan"] => Some(Replacement { + existing: "arctan", + details: Details::AutoImport { + path: "numpy", + name: "atan", + }, + }), + ["numpy", "arctan2"] => Some(Replacement { + existing: "arctan2", + details: Details::AutoImport { + path: "numpy", + name: "atan2", + }, + }), + ["numpy", "arctanh"] => Some(Replacement { + existing: "arctanh", + details: Details::AutoImport { + path: "numpy", + name: "atanh", + }, + }), + ["numpy", "left_shift"] => Some(Replacement { + existing: "left_shift", + details: Details::AutoImport { + path: "numpy", + name: "bitwise_left_shift", + }, + }), + ["numpy", "arccos"] => Some(Replacement { + existing: "arccos", + details: Details::AutoImport { + path: "numpy", + name: "acos", + }, + }), + ["numpy", "invert"] => Some(Replacement { + existing: "invert", + details: Details::AutoImport { + path: "numpy", + name: "bitwise_invert", + }, + }), + ["numpy", "right_shift"] => Some(Replacement { + existing: "right_shift", + details: Details::AutoImport { + path: "numpy", + name: "bitwise_right_shift", + }, + }), + ["numpy", "bool_"] => Some(Replacement { + existing: "bool_", + details: Details::AutoImport { + path: "numpy", + name: "bool", + }, + }), + ["numpy", "concatenate"] => Some(Replacement { + existing: "concatenate", + details: Details::AutoImport { + path: "numpy", + name: "concat", + }, + }), + ["numpy", "power"] => Some(Replacement { + existing: "power", + details: Details::AutoImport { + path: "numpy", + name: "pow", + }, + }), _ => None, }); From 700e3a0b303dc5a576a3d4e0c4c21a7b68a71951 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 17:14:02 +0000 Subject: [PATCH 4/8] add `array_api_functions` --- .../xp/rules/not_array_agnostic_numpy.rs | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index f5de1bfa5c25a..3d28385ebd0dc 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -75,6 +75,191 @@ impl Details<'_> { } } +const array_api_functions: [&str; ...] = [ + // methods + "__abs__", + "__add__", + "__and__", + "__array_namespace__", + "__bool__", + "__complex__", + "__dlpack__", + "__dlpack_device__", + "__eq__", + "__float__", + "__floordiv__", + "__ge__", + "__getitem__", + "__gt__", + "__index__", + "__int__", + "__invert__", + "__le__", + "__lshift__", + "__lt__", + "__matmul__", + "__mod__", + "__mul__", + "__ne__", + "__neg__", + "__or__", + "__pos__", + "__pow__", + "__rshift__", + "__setitem__", + "__sub__", + "__truediv__", + "__xor__", + "to_device", + // constants + "e", + "inf", + "nan", + "newaxis", + "pi", + // creation functions + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", + // data type functions + "astype", + "can_cast", + "finfo", + "iinfo", + "isdtype", + "result_type", + // data types + "bool", + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "float32", + "float64", + "complex64", + "complex128", + // element-wise functions + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "conj", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", + // indexing functions + "take", + // linear algebra functions + "matmul", + "matrix_transpose", + "tensordot", + "vecdot", + // manipulation functions + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", + // searching functions + "argmax", + "argmin", + "nonzero", + "where", + // set functions + "unique_all", + "unique_counts", + "unique_inverse", + "unique_values", + // sorting functions + "argsort", + "sort", + // statistical functions + "max", + "mean", + "min", + "prod", + "std", + "sum", + "var", + "all", + "any", + // version + "__array_api_version__" +] + ///XP001 pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { let maybe_replacement = checker @@ -179,6 +364,15 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { name: "pow", }, }), + ["numpy", func] if &array_api_functions.contains(func) => None, + ["numpy", func] => Some(Replacement { + existing: func, + details: Details::Manual { + guideline: Some( + format!("xp.{} is not in the array API standard", func) + ), + }, + }), _ => None, }); From 24f4713d3d37bd68154099d666a72afcaa1b1024 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 17:55:48 +0000 Subject: [PATCH 5/8] try to fix bugs --- .../rules/xp/rules/not_array_agnostic_numpy.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index 3d28385ebd0dc..ef765f55f876d 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -75,7 +75,7 @@ impl Details<'_> { } } -const array_api_functions: [&str; ...] = [ +const ARRAY_API_FUNCTIONS: [&str; 168] = [ // methods "__abs__", "__add__", @@ -257,8 +257,8 @@ const array_api_functions: [&str; ...] = [ "all", "any", // version - "__array_api_version__" -] + "__array_api_version__", +]; ///XP001 pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { @@ -364,13 +364,15 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { name: "pow", }, }), - ["numpy", func] if &array_api_functions.contains(func) => None, + ["numpy", func] if ARRAY_API_FUNCTIONS.contains(func) => None, ["numpy", func] => Some(Replacement { existing: func, details: Details::Manual { - guideline: Some( - format!("xp.{} is not in the array API standard", func) - ), + guideline: Some(concat!( + "xp.", + stringify!($func), + "is not in the array API standard" + )), }, }), _ => None, From 9f2eeee932aae3f926b1c097b4401dc723425950 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 20:02:35 +0000 Subject: [PATCH 6/8] Apply suggestions from code review --- .../src/rules/xp/rules/not_array_agnostic_numpy.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index ef765f55f876d..b1465b7efc1c8 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -322,13 +322,6 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { name: "bitwise_left_shift", }, }), - ["numpy", "arccos"] => Some(Replacement { - existing: "arccos", - details: Details::AutoImport { - path: "numpy", - name: "acos", - }, - }), ["numpy", "invert"] => Some(Replacement { existing: "invert", details: Details::AutoImport { @@ -371,7 +364,7 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { guideline: Some(concat!( "xp.", stringify!($func), - "is not in the array API standard" + " is not in the array API standard" )), }, }), From 3d9e222c7b1d199ebdf862354ae7e0bd27cee639 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 21:34:54 +0000 Subject: [PATCH 7/8] add `is_array_api_function` --- .../src/rules/xp/rules/not_array_agnostic_numpy.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index b1465b7efc1c8..7a4f0a191b8fe 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -262,6 +262,10 @@ const ARRAY_API_FUNCTIONS: [&str; 168] = [ ///XP001 pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { + fn is_array_api_function(func: &str) -> bool { + matches!(func, _ if ARRAY_API_FUNCTIONS.contains(&func)) + } + let maybe_replacement = checker .semantic() .resolve_call_path(expr) @@ -357,7 +361,7 @@ pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { name: "pow", }, }), - ["numpy", func] if ARRAY_API_FUNCTIONS.contains(func) => None, + ["numpy", func] if is_array_api_function(func) => None, ["numpy", func] => Some(Replacement { existing: func, details: Details::Manual { From a1b9c26f633693b8d6e63546a2d32e97637339d3 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 6 Dec 2023 21:50:26 +0000 Subject: [PATCH 8/8] use matches macro --- .../xp/rules/not_array_agnostic_numpy.rs | 371 +++++++++--------- 1 file changed, 185 insertions(+), 186 deletions(-) diff --git a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs index 7a4f0a191b8fe..508a75e4e2ff7 100644 --- a/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs +++ b/crates/ruff_linter/src/rules/xp/rules/not_array_agnostic_numpy.rs @@ -75,195 +75,194 @@ impl Details<'_> { } } -const ARRAY_API_FUNCTIONS: [&str; 168] = [ - // methods - "__abs__", - "__add__", - "__and__", - "__array_namespace__", - "__bool__", - "__complex__", - "__dlpack__", - "__dlpack_device__", - "__eq__", - "__float__", - "__floordiv__", - "__ge__", - "__getitem__", - "__gt__", - "__index__", - "__int__", - "__invert__", - "__le__", - "__lshift__", - "__lt__", - "__matmul__", - "__mod__", - "__mul__", - "__ne__", - "__neg__", - "__or__", - "__pos__", - "__pow__", - "__rshift__", - "__setitem__", - "__sub__", - "__truediv__", - "__xor__", - "to_device", - // constants - "e", - "inf", - "nan", - "newaxis", - "pi", - // creation functions - "arange", - "asarray", - "empty", - "empty_like", - "eye", - "from_dlpack", - "full", - "full_like", - "linspace", - "meshgrid", - "ones", - "ones_like", - "tril", - "triu", - "zeros", - "zeros_like", - // data type functions - "astype", - "can_cast", - "finfo", - "iinfo", - "isdtype", - "result_type", - // data types - "bool", - "int8", - "int16", - "int32", - "int64", - "uint8", - "uint16", - "uint32", - "uint64", - "float32", - "float64", - "complex64", - "complex128", - // element-wise functions - "abs", - "acos", - "acosh", - "add", - "asin", - "asinh", - "atan", - "atan2", - "atanh", - "bitwise_and", - "bitwise_left_shift", - "bitwise_invert", - "bitwise_or", - "bitwise_right_shift", - "bitwise_xor", - "ceil", - "conj", - "cos", - "cosh", - "divide", - "equal", - "exp", - "expm1", - "floor", - "floor_divide", - "greater", - "greater_equal", - "imag", - "isfinite", - "isinf", - "isnan", - "less", - "less_equal", - "log", - "log1p", - "log2", - "log10", - "logaddexp", - "logical_and", - "logical_not", - "logical_or", - "logical_xor", - "multiply", - "negative", - "not_equal", - "positive", - "pow", - "real", - "remainder", - "round", - "sign", - "sin", - "sinh", - "square", - "sqrt", - "subtract", - "tan", - "tanh", - "trunc", - // indexing functions - "take", - // linear algebra functions - "matmul", - "matrix_transpose", - "tensordot", - "vecdot", - // manipulation functions - "broadcast_arrays", - "broadcast_to", - "concat", - "expand_dims", - "flip", - "permute_dims", - "reshape", - "roll", - "squeeze", - "stack", - // searching functions - "argmax", - "argmin", - "nonzero", - "where", - // set functions - "unique_all", - "unique_counts", - "unique_inverse", - "unique_values", - // sorting functions - "argsort", - "sort", - // statistical functions - "max", - "mean", - "min", - "prod", - "std", - "sum", - "var", - "all", - "any", - // version - "__array_api_version__", -]; - ///XP001 pub(crate) fn not_array_agnostic_numpy(checker: &mut Checker, expr: &Expr) { fn is_array_api_function(func: &str) -> bool { - matches!(func, _ if ARRAY_API_FUNCTIONS.contains(&func)) + matches!( + func, + // methods + "__abs__" | + "__add__" | + "__and__" | + "__array_namespace__" | + "__bool__" | + "__complex__" | + "__dlpack__" | + "__dlpack_device__" | + "__eq__" | + "__float__" | + "__floordiv__" | + "__ge__" | + "__getitem__" | + "__gt__" | + "__index__" | + "__int__" | + "__invert__" | + "__le__" | + "__lshift__" | + "__lt__" | + "__matmul__" | + "__mod__" | + "__mul__" | + "__ne__" | + "__neg__" | + "__or__" | + "__pos__" | + "__pow__" | + "__rshift__" | + "__setitem__" | + "__sub__" | + "__truediv__" | + "__xor__" | + "to_device" | + // constants + "e" | + "inf" | + "nan" | + "newaxis" | + "pi" | + // creation functions + "arange" | + "asarray" | + "empty" | + "empty_like" | + "eye" | + "from_dlpack" | + "full" | + "full_like" | + "linspace" | + "meshgrid" | + "ones" | + "ones_like" | + "tril" | + "triu" | + "zeros" | + "zeros_like" | + // data type functions + "astype" | + "can_cast" | + "finfo" | + "iinfo" | + "isdtype" | + "result_type" | + // data types + "bool" | + "int8" | + "int16" | + "int32" | + "int64" | + "uint8" | + "uint16" | + "uint32" | + "uint64" | + "float32" | + "float64" | + "complex64" | + "complex128" | + // element-wise functions + "abs" | + "acos" | + "acosh" | + "add" | + "asin" | + "asinh" | + "atan" | + "atan2" | + "atanh" | + "bitwise_and" | + "bitwise_left_shift" | + "bitwise_invert" | + "bitwise_or" | + "bitwise_right_shift" | + "bitwise_xor" | + "ceil" | + "conj" | + "cos" | + "cosh" | + "divide" | + "equal" | + "exp" | + "expm1" | + "floor" | + "floor_divide" | + "greater" | + "greater_equal" | + "imag" | + "isfinite" | + "isinf" | + "isnan" | + "less" | + "less_equal" | + "log" | + "log1p" | + "log2" | + "log10" | + "logaddexp" | + "logical_and" | + "logical_not" | + "logical_or" | + "logical_xor" | + "multiply" | + "negative" | + "not_equal" | + "positive" | + "pow" | + "real" | + "remainder" | + "round" | + "sign" | + "sin" | + "sinh" | + "square" | + "sqrt" | + "subtract" | + "tan" | + "tanh" | + "trunc" | + // indexing functions + "take" | + // linear algebra functions + "matmul" | + "matrix_transpose" | + "tensordot" | + "vecdot" | + // manipulation functions + "broadcast_arrays" | + "broadcast_to" | + "concat" | + "expand_dims" | + "flip" | + "permute_dims" | + "reshape" | + "roll" | + "squeeze" | + "stack" | + // searching functions + "argmax" | + "argmin" | + "nonzero" | + "where" | + // set functions + "unique_all" | + "unique_counts" | + "unique_inverse" | + "unique_values" | + // sorting functions + "argsort" | + "sort" | + // statistical functions + "max" | + "mean" | + "min" | + "prod" | + "std" | + "sum" | + "var" | + "all" | + "any" | + // version + "__array_api_version__" + ) } let maybe_replacement = checker