Tweak interfaces to take Context

This commit is contained in:
Charlie Marsh 2023-03-05 18:17:49 -05:00
parent b307200e42
commit 5afe4bf711
2 changed files with 52 additions and 29 deletions

View File

@ -2084,17 +2084,30 @@ where
// If we're in a class or module scope, then the annotation needs to be
// available at runtime.
// See: https://docs.python.org/3/reference/simple_stmts.html#annotated-assignment-statements
let runtime_annotation = (!self.ctx.annotations_future_enabled
&& matches!(
let runtime_annotation = if self.ctx.annotations_future_enabled {
if matches!(self.ctx.current_scope().kind, ScopeKind::Class(..)) {
let baseclasses = &self
.settings
.flake8_type_checking
.runtime_evaluated_baseclasses;
let decorators = &self
.settings
.flake8_type_checking
.runtime_evaluated_decorators;
flake8_type_checking::helpers::runtime_evaluated(
&self.ctx,
baseclasses,
decorators,
)
} else {
false
}
} else {
matches!(
self.ctx.current_scope().kind,
ScopeKind::Class(..) | ScopeKind::Module
))
|| (self.ctx.annotations_future_enabled
&& matches!(self.current_scope().kind, ScopeKind::Class(..))
&& flake8_type_checking::helpers::runtime_evaluated(
self,
self.current_scope(),
));
)
};
if runtime_annotation {
visit_type_definition!(self, annotation);

View File

@ -1,8 +1,9 @@
use num_traits::Zero;
use rustpython_parser::ast::{Constant, Expr, ExprKind};
use crate::ast::context::Context;
use crate::ast::helpers::{map_callable, to_call_path};
use crate::ast::types::{Binding, BindingKind, ExecutionContext, Scope, ScopeKind};
use crate::ast::types::{Binding, BindingKind, ExecutionContext, ScopeKind};
use crate::checkers::ast::Checker;
/// Return `true` if [`Expr`] is a guard for a type-checking block.
@ -56,18 +57,29 @@ pub const fn is_valid_runtime_import(binding: &Binding) -> bool {
}
}
pub fn runtime_evaluated(checker: &Checker, scope: &Scope) -> bool {
runtime_evaluated_due_to_baseclass(checker, scope)
|| runtime_evaluated_due_to_decorator(checker, scope)
pub fn runtime_evaluated(
context: &Context,
base_classes: &[String],
decorators: &[String],
) -> bool {
if !base_classes.is_empty() {
if runtime_evaluated_baseclass(context, base_classes) {
return true;
}
pub fn runtime_evaluated_due_to_baseclass(checker: &Checker, scope: &Scope) -> bool {
if let ScopeKind::Class(def) = &scope.kind {
for base_class in def.bases.iter() {
if let Some(call_path) = checker.resolve_call_path(map_callable(base_class)) {
if checker
.settings
.flake8_type_checking
.runtime_evaluated_baseclasses
}
if !decorators.is_empty() {
if runtime_evaluated_decorators(context, decorators) {
return true;
}
}
false
}
fn runtime_evaluated_baseclass(context: &Context, base_classes: &[String]) -> bool {
if let ScopeKind::Class(class_def) = &context.current_scope().kind {
for base in class_def.bases.iter() {
if let Some(call_path) = context.resolve_call_path(base) {
if base_classes
.iter()
.any(|base_class| to_call_path(base_class) == call_path)
{
@ -78,14 +90,12 @@ pub fn runtime_evaluated_due_to_baseclass(checker: &Checker, scope: &Scope) -> b
}
false
}
pub fn runtime_evaluated_due_to_decorator(checker: &Checker, scope: &Scope) -> bool {
if let ScopeKind::Class(def) = &scope.kind {
for decorator in def.decorator_list.iter() {
if let Some(call_path) = checker.resolve_call_path(map_callable(decorator)) {
if checker
.settings
.flake8_type_checking
.runtime_evaluated_decorators
fn runtime_evaluated_decorators(context: &Context, decorators: &[String]) -> bool {
if let ScopeKind::Class(class_def) = &context.current_scope().kind {
for decorator in class_def.decorator_list.iter() {
if let Some(call_path) = context.resolve_call_path(map_callable(decorator)) {
if decorators
.iter()
.any(|decorator| to_call_path(decorator) == call_path)
{