mirror of https://github.com/astral-sh/ruff
Support remaining typing module members
This commit is contained in:
parent
4fc68e0310
commit
30fb86aab2
|
|
@ -1759,6 +1759,7 @@ dependencies = [
|
|||
"filetime",
|
||||
"glob",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"notify",
|
||||
"once_cell",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ fern = { version = "0.6.1" }
|
|||
filetime = { version = "0.2.17" }
|
||||
glob = { version = "0.3.0" }
|
||||
itertools = "0.10.3"
|
||||
lazy_static = "1.4.0"
|
||||
log = { version = "0.4.17" }
|
||||
notify = { version = "4.0.17" }
|
||||
once_cell = { version = "1.13.1" }
|
||||
|
|
|
|||
|
|
@ -11,10 +11,13 @@ import multiprocessing.pool
|
|||
import multiprocessing.process
|
||||
import logging.config
|
||||
import logging.handlers
|
||||
from typing import NamedTuple, Dict, Type, TypeVar, List, Set
|
||||
from typing import TYPING_CHECK, NamedTuple, Dict, Type, TypeVar, List, Set, Union, cast
|
||||
|
||||
from blah import ClassA, ClassB, ClassC
|
||||
|
||||
if TYPING_CHECK:
|
||||
from models import Fruit, Nut, Vegetable
|
||||
|
||||
|
||||
class X:
|
||||
datetime: datetime
|
||||
|
|
@ -32,3 +35,7 @@ __all__ += ["ClassC"]
|
|||
X = TypeVar("X")
|
||||
Y = TypeVar("Y", bound="Dict")
|
||||
Z = TypeVar("Z", "List", "Set")
|
||||
|
||||
a = list["Fruit"]
|
||||
b = Union["Nut", None]
|
||||
c = cast("Vegetable", b)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ use crate::ast::types::{Binding, BindingKind, Scope, ScopeKind};
|
|||
use crate::ast::visitor::{walk_excepthandler, Visitor};
|
||||
use crate::ast::{checks, visitor};
|
||||
use crate::autofix::fixer;
|
||||
use crate::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use crate::python::typing;
|
||||
use crate::settings::Settings;
|
||||
|
||||
pub const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
|
|
@ -82,6 +83,14 @@ fn match_name_or_attr(expr: &Expr, target: &str) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_annotated_subscript(expr: &Expr) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Attribute { attr, .. } => typing::is_annotated_subscript(attr),
|
||||
ExprKind::Name { id, .. } => typing::is_annotated_subscript(id),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'b> for Checker<'a>
|
||||
where
|
||||
'b: 'a,
|
||||
|
|
@ -544,7 +553,25 @@ where
|
|||
args,
|
||||
keywords,
|
||||
} => {
|
||||
if match_name_or_attr(func, "TypeVar") {
|
||||
if match_name_or_attr(func, "ForwardRef") {
|
||||
self.visit_expr(func);
|
||||
for expr in args {
|
||||
self.visit_annotation(expr);
|
||||
}
|
||||
} else if match_name_or_attr(func, "cast") {
|
||||
self.visit_expr(func);
|
||||
if !args.is_empty() {
|
||||
self.visit_annotation(&args[0]);
|
||||
}
|
||||
for expr in args.iter().skip(1) {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
} else if match_name_or_attr(func, "NewType") {
|
||||
self.visit_expr(func);
|
||||
for expr in args.iter().skip(1) {
|
||||
self.visit_annotation(expr);
|
||||
}
|
||||
} else if match_name_or_attr(func, "TypeVar") {
|
||||
self.visit_expr(func);
|
||||
for expr in args.iter().skip(1) {
|
||||
self.visit_annotation(expr);
|
||||
|
|
@ -559,7 +586,38 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if match_name_or_attr(func, "NamedTuple") {
|
||||
self.visit_expr(func);
|
||||
|
||||
// NamedTuple("a", [("a", int)])
|
||||
if args.len() > 1 {
|
||||
match &args[1].node {
|
||||
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
|
||||
for elt in elts {
|
||||
match &elt.node {
|
||||
ExprKind::List { elts, .. }
|
||||
| ExprKind::Tuple { elts, .. } => {
|
||||
if elts.len() == 2 {
|
||||
self.visit_expr(&elts[0]);
|
||||
self.visit_annotation(&elts[1]);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// NamedTuple("a", a=int)
|
||||
for keyword in keywords {
|
||||
let KeywordData { value, .. } = &keyword.node;
|
||||
self.visit_annotation(value);
|
||||
}
|
||||
} else if match_name_or_attr(func, "TypedDict") {
|
||||
self.visit_expr(func);
|
||||
|
||||
// TypedDict("a", {"a": int})
|
||||
if args.len() > 1 {
|
||||
if let ExprKind::Dict { keys, values } = &args[1].node {
|
||||
|
|
@ -582,7 +640,7 @@ where
|
|||
}
|
||||
}
|
||||
ExprKind::Subscript { value, slice, ctx } => {
|
||||
if match_name_or_attr(value, "Type") {
|
||||
if is_annotated_subscript(value) {
|
||||
self.visit_expr(value);
|
||||
self.visit_annotation(slice);
|
||||
self.visit_expr_context(ctx);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ extern crate core;
|
|||
|
||||
mod ast;
|
||||
mod autofix;
|
||||
mod builtins;
|
||||
mod cache;
|
||||
pub mod check_ast;
|
||||
mod check_lines;
|
||||
|
|
@ -12,4 +11,5 @@ pub mod linter;
|
|||
pub mod logging;
|
||||
pub mod message;
|
||||
mod pyproject;
|
||||
mod python;
|
||||
pub mod settings;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
pub mod builtins;
|
||||
pub mod typing;
|
||||
|
|
@ -156,8 +156,8 @@ pub const BUILTINS: &[&str] = &[
|
|||
// Globally defined names which are not attributes of the builtins module, or are only present on
|
||||
// some platforms.
|
||||
pub const MAGIC_GLOBALS: &[&str] = &[
|
||||
"__file__",
|
||||
"__builtins__",
|
||||
"__annotations__",
|
||||
"WindowsError",
|
||||
"__annotations__",
|
||||
"__builtins__",
|
||||
"__file__",
|
||||
];
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
lazy_static! {
|
||||
static ref ANNOTATED_SUBSCRIPTS: BTreeSet<&'static str> = BTreeSet::from([
|
||||
"AbstractAsyncContextManager",
|
||||
"AbstractContextManager",
|
||||
"AbstractSet",
|
||||
"AsyncContextManager",
|
||||
"AsyncGenerator",
|
||||
"AsyncIterable",
|
||||
"AsyncIterator",
|
||||
"Awaitable",
|
||||
"BinaryIO",
|
||||
"BsdDbShelf",
|
||||
"ByteString",
|
||||
"Callable",
|
||||
"ChainMap",
|
||||
"ClassVar",
|
||||
"Collection",
|
||||
"Concatenate",
|
||||
"Container",
|
||||
"ContextManager",
|
||||
"Coroutine",
|
||||
"Counter",
|
||||
"Counter",
|
||||
"DbfilenameShelf",
|
||||
"DefaultDict",
|
||||
"Deque",
|
||||
"Dict",
|
||||
"Field",
|
||||
"Final",
|
||||
"FrozenSet",
|
||||
"Generator",
|
||||
"Iterator",
|
||||
"Generic",
|
||||
"IO",
|
||||
"ItemsView",
|
||||
"Iterable",
|
||||
"Iterator",
|
||||
"KeysView",
|
||||
"LifoQueue",
|
||||
"List",
|
||||
"Mapping",
|
||||
"MappingProxyType",
|
||||
"MappingView",
|
||||
"Match",
|
||||
"MutableMapping",
|
||||
"MutableSequence",
|
||||
"MutableSet",
|
||||
"Optional",
|
||||
"OrderedDict",
|
||||
"PathLike",
|
||||
"Pattern",
|
||||
"PriorityQueue",
|
||||
"Protocol",
|
||||
"Queue",
|
||||
"Reversible",
|
||||
"Sequence",
|
||||
"Set",
|
||||
"Shelf",
|
||||
"SimpleQueue",
|
||||
"TextIO",
|
||||
"Tuple",
|
||||
"Type",
|
||||
"TypeGuard",
|
||||
"Union",
|
||||
"ValuesView",
|
||||
"WeakKeyDictionary",
|
||||
"WeakMethod",
|
||||
"WeakSet",
|
||||
"WeakValueDictionary",
|
||||
"cached_property",
|
||||
"defaultdict",
|
||||
"deque",
|
||||
"dict",
|
||||
"frozenset",
|
||||
"list",
|
||||
"partialmethod",
|
||||
"set",
|
||||
"tuple",
|
||||
"type",
|
||||
]);
|
||||
}
|
||||
|
||||
pub fn is_annotated_subscript(name: &str) -> bool {
|
||||
ANNOTATED_SUBSCRIPTS.contains(name)
|
||||
}
|
||||
Loading…
Reference in New Issue