Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexWaygood committed Jul 24, 2024
1 parent bc79d9c commit e3ffb37
Showing 1 changed file with 56 additions and 14 deletions.
70 changes: 56 additions & 14 deletions crates/ruff_linter/src/rules/numpy/rules/numpy_2_0_deprecation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,38 @@ pub(crate) fn numpy_2_0_deprecation(checker: &mut Checker, expr: &Expr) {
checker.diagnostics.push(diagnostic);
}

/// Ignore attempts to access a `numpy` member via its deprecated name
/// if the access takes place in an `except` block that provides compatibility
/// with older numpy versions.
///
/// For attribute accesses (e.g. `np.ComplexWarning`), we only ignore the violation
/// if it's inside an `except AttributeError` block, and the member is accessed
/// through its non-deprecated name in the associated `try` block.
///
/// For uses of the `numpy` member where it's simply an `ExprName` node,
/// we check to see how the `numpy` member was bound. If it was bound via a
/// `from numpy import foo` statement, we check to see if that import statement
/// took place inside an `except ImportError` or `except ModuleNotFoundError` block.
/// If so, and if the `numpy` member was imported through its non-deprecated name
/// in the associated try block, we ignore the violation in the same way.
///
/// Examples:
///
/// ```py
/// import numpy as np
///
/// try:
/// np.all([True, True])
/// except AttributError:
/// np.alltrue([True, True]) # Okay
///
/// try:
/// from numpy.exceptions import ComplexWarning
/// except ImportError:
/// from numpy import ComplexWarning
///
/// x = ComplexWarning() # Okay
/// ```
fn is_guarded_by_try_except(
expr: &Expr,
replacement: &Replacement,
Expand Down Expand Up @@ -743,7 +775,7 @@ fn is_guarded_by_try_except(
}
let Some(try_node) = binding
.source
.and_then(|import_id| try_node_parent_of_import_stmt(import_id, semantic))
.and_then(|import_id| enclosing_try_node(import_id, semantic))
else {
return false;
};
Expand All @@ -759,11 +791,13 @@ fn is_guarded_by_try_except(
}
}

fn try_node_parent_of_import_stmt<'a>(
import_id: NodeId,
/// Given the `NodeId` of a node that is known to be inside an exception handler,
/// find the [`ast::StmtTry`] node in which the node resides.
fn enclosing_try_node<'a>(
node_id: NodeId,
semantic: &'a SemanticModel,
) -> Option<&'a ast::StmtTry> {
let mut node_id = import_id;
let mut node_id = node_id;
loop {
node_id = semantic.parent_statement_id(node_id)?;
if let ast::Stmt::Try(try_node) = semantic.statement(node_id) {
Expand All @@ -772,15 +806,9 @@ fn try_node_parent_of_import_stmt<'a>(
}
}

fn undeprecated_qualified_name<'a>(path: &'a str, name: &'a str) -> QualifiedName<'a> {
let mut builder = QualifiedNameBuilder::default();
for part in path.split('.') {
builder.push(part);
}
builder.push(name);
builder.build()
}

/// Given an [`ast::StmtTry`] node, does the `try` branch of that node
/// contain any [`ast::ExprAttribute`] nodes that indicate the numpy
/// member is being accessed from the non-deprecated location?
fn try_block_contains_undeprecated_attribute(
try_node: &ast::StmtTry,
replacement_details: &Details,
Expand All @@ -794,7 +822,14 @@ fn try_block_contains_undeprecated_attribute(
else {
return false;
};
let undeprecated_qualified_name = undeprecated_qualified_name(path, name);
let undeprecated_qualified_name = {
let mut builder = QualifiedNameBuilder::default();
for part in path.split('.') {
builder.push(part);
}
builder.push(name);
builder.build()
};
let mut attribute_searcher = AttributeSearcher::new(undeprecated_qualified_name, semantic);
for stmt in &try_node.body {
attribute_searcher.visit_stmt(stmt);
Expand All @@ -805,6 +840,8 @@ fn try_block_contains_undeprecated_attribute(
false
}

/// AST visitor that searches an AST tree for [`ast::ExprAttribute`] nodes
/// that match a certain [`QualifiedName`].
struct AttributeSearcher<'a> {
attribute_to_find: QualifiedName<'a>,
semantic: &'a SemanticModel<'a>,
Expand Down Expand Up @@ -839,6 +876,9 @@ impl Visitor<'_> for AttributeSearcher<'_> {
}
}

/// Given an [`ast::StmtTry`] node, does the `try` branch of that node
/// contain any [`ast::StmtImportFrom`] nodes that indicate the numpy
/// member is being imported from the non-deprecated location?
fn try_block_contains_undeprecated_import(
try_node: &ast::StmtTry,
replacement_details: &Details,
Expand All @@ -861,6 +901,8 @@ fn try_block_contains_undeprecated_import(
false
}

/// AST visitor that searches an AST tree for [`ast::StmtImportFrom`] nodes
/// that match a certain [`QualifiedName`].
struct ImportSearcher<'a> {
module: &'a str,
name: &'a str,
Expand Down

0 comments on commit e3ffb37

Please sign in to comment.