Skip to content

Commit

Permalink
Implement NumPy 2.0 migration rule (#7702)
Browse files Browse the repository at this point in the history
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

Hi! Currently NumPy Python API is undergoing a cleanup process that will
be delivered in NumPy 2.0 (release is planned for the end of the year).
Most changes are rather simple (renaming, removing or moving a member of
the main namespace to a new place), and they could be flagged/fixed by
an additional ruff rule for numpy (e.g. changing occurrences of
`np.float_` to `np.float64`).

Would you accept such rule?  

I named it `NPY201` in the existing group, so people will receive a
heads-up for changes arriving in 2.0 before actually migrating to it.

~~This is still a draft PR.~~ I'm not an expert in rust so if any part
of code can be done better please share!

NumPy 2.0 migration guide:
https://numpy.org/devdocs/numpy_2_0_migration_guide.html
NEP 52: https://numpy.org/neps/nep-0052-python-api-cleanup.html
NumPy cleanup tracking issue:
numpy/numpy#23999


## Test Plan

A unit test is provided that checks all rule's fix cases.
  • Loading branch information
mtsokol committed Nov 3, 2023
1 parent f64c389 commit d04d964
Show file tree
Hide file tree
Showing 8 changed files with 1,460 additions and 0 deletions.
106 changes: 106 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/numpy/NPY201.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
def func():
import numpy as np

np.add_docstring

np.add_newdoc

np.add_newdoc_ufunc

np.asfarray([1,2,3])

np.byte_bounds(np.array([1,2,3]))

np.cast

np.cfloat(12+34j)

np.clongfloat(12+34j)

np.compat

np.complex_(12+34j)

np.DataSource

np.deprecate

np.deprecate_with_doc

np.disp(10)

np.fastCopyAndTranspose

np.find_common_type

np.get_array_wrap

np.float_

np.geterrobj

np.Inf

np.Infinity

np.infty

np.issctype

np.issubclass_(np.int32, np.integer)

np.issubsctype

np.mat

np.maximum_sctype

np.NaN

np.nbytes[np.int64]

np.NINF

np.NZERO

np.longcomplex(12+34j)

np.longfloat(12+34j)

np.lookfor

np.obj2sctype(int)

np.PINF

np.PZERO

np.recfromcsv

np.recfromtxt

np.round_(12.34)

np.safe_eval

np.sctype2char

np.sctypes

np.seterrobj

np.set_numeric_ops

np.set_string_function

np.singlecomplex(12+1j)

np.string_("asdf")

np.source

np.tracemalloc_domain

np.unicode_("asf")

np.who()
6 changes: 6 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::NumpyDeprecatedFunction) {
numpy::rules::deprecated_function(checker, expr);
}
if checker.enabled(Rule::Numpy2Deprecation) {
numpy::rules::numpy_2_0_deprecation(checker, expr);
}
if checker.enabled(Rule::CollectionsNamedTuple) {
flake8_pyi::rules::collections_named_tuple(checker, expr);
}
Expand Down Expand Up @@ -314,6 +317,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::NumpyDeprecatedFunction) {
numpy::rules::deprecated_function(checker, expr);
}
if checker.enabled(Rule::Numpy2Deprecation) {
numpy::rules::numpy_2_0_deprecation(checker, expr);
}
if checker.enabled(Rule::DeprecatedMockImport) {
pyupgrade::rules::deprecated_mock_attribute(checker, expr);
}
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Numpy, "001") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedTypeAlias),
(Numpy, "002") => (RuleGroup::Stable, rules::numpy::rules::NumpyLegacyRandom),
(Numpy, "003") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedFunction),
(Numpy, "201") => (RuleGroup::Preview, rules::numpy::rules::Numpy2Deprecation),

// ruff
(Ruff, "001") => (RuleGroup::Stable, rules::ruff::rules::AmbiguousUnicodeCharacterString),
Expand Down
1 change: 1 addition & 0 deletions crates/ruff_linter/src/rules/numpy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod tests {
#[test_case(Rule::NumpyDeprecatedTypeAlias, Path::new("NPY001.py"))]
#[test_case(Rule::NumpyLegacyRandom, Path::new("NPY002.py"))]
#[test_case(Rule::NumpyDeprecatedFunction, Path::new("NPY003.py"))]
#[test_case(Rule::Numpy2Deprecation, Path::new("NPY201.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path(
Expand Down
2 changes: 2 additions & 0 deletions crates/ruff_linter/src/rules/numpy/rules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub(crate) use deprecated_function::*;
pub(crate) use deprecated_type_alias::*;
pub(crate) use legacy_random::*;
pub(crate) use numpy_2_0_deprecation::*;

mod deprecated_function;
mod deprecated_type_alias;
mod legacy_random;
mod numpy_2_0_deprecation;
Loading

0 comments on commit d04d964

Please sign in to comment.