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",
|
"filetime",
|
||||||
"glob",
|
"glob",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"notify",
|
"notify",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ fern = { version = "0.6.1" }
|
||||||
filetime = { version = "0.2.17" }
|
filetime = { version = "0.2.17" }
|
||||||
glob = { version = "0.3.0" }
|
glob = { version = "0.3.0" }
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
log = { version = "0.4.17" }
|
log = { version = "0.4.17" }
|
||||||
notify = { version = "4.0.17" }
|
notify = { version = "4.0.17" }
|
||||||
once_cell = { version = "1.13.1" }
|
once_cell = { version = "1.13.1" }
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,13 @@ import multiprocessing.pool
|
||||||
import multiprocessing.process
|
import multiprocessing.process
|
||||||
import logging.config
|
import logging.config
|
||||||
import logging.handlers
|
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
|
from blah import ClassA, ClassB, ClassC
|
||||||
|
|
||||||
|
if TYPING_CHECK:
|
||||||
|
from models import Fruit, Nut, Vegetable
|
||||||
|
|
||||||
|
|
||||||
class X:
|
class X:
|
||||||
datetime: datetime
|
datetime: datetime
|
||||||
|
|
@ -32,3 +35,7 @@ __all__ += ["ClassC"]
|
||||||
X = TypeVar("X")
|
X = TypeVar("X")
|
||||||
Y = TypeVar("Y", bound="Dict")
|
Y = TypeVar("Y", bound="Dict")
|
||||||
Z = TypeVar("Z", "List", "Set")
|
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::visitor::{walk_excepthandler, Visitor};
|
||||||
use crate::ast::{checks, visitor};
|
use crate::ast::{checks, visitor};
|
||||||
use crate::autofix::fixer;
|
use crate::autofix::fixer;
|
||||||
use crate::builtins::{BUILTINS, MAGIC_GLOBALS};
|
|
||||||
use crate::checks::{Check, CheckCode, CheckKind};
|
use crate::checks::{Check, CheckCode, CheckKind};
|
||||||
|
use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||||
|
use crate::python::typing;
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
pub const GLOBAL_SCOPE_INDEX: usize = 0;
|
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>
|
impl<'a, 'b> Visitor<'b> for Checker<'a>
|
||||||
where
|
where
|
||||||
'b: 'a,
|
'b: 'a,
|
||||||
|
|
@ -544,7 +553,25 @@ where
|
||||||
args,
|
args,
|
||||||
keywords,
|
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);
|
self.visit_expr(func);
|
||||||
for expr in args.iter().skip(1) {
|
for expr in args.iter().skip(1) {
|
||||||
self.visit_annotation(expr);
|
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") {
|
} else if match_name_or_attr(func, "TypedDict") {
|
||||||
|
self.visit_expr(func);
|
||||||
|
|
||||||
// TypedDict("a", {"a": int})
|
// TypedDict("a", {"a": int})
|
||||||
if args.len() > 1 {
|
if args.len() > 1 {
|
||||||
if let ExprKind::Dict { keys, values } = &args[1].node {
|
if let ExprKind::Dict { keys, values } = &args[1].node {
|
||||||
|
|
@ -582,7 +640,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, ctx } => {
|
ExprKind::Subscript { value, slice, ctx } => {
|
||||||
if match_name_or_attr(value, "Type") {
|
if is_annotated_subscript(value) {
|
||||||
self.visit_expr(value);
|
self.visit_expr(value);
|
||||||
self.visit_annotation(slice);
|
self.visit_annotation(slice);
|
||||||
self.visit_expr_context(ctx);
|
self.visit_expr_context(ctx);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ extern crate core;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod autofix;
|
mod autofix;
|
||||||
mod builtins;
|
|
||||||
mod cache;
|
mod cache;
|
||||||
pub mod check_ast;
|
pub mod check_ast;
|
||||||
mod check_lines;
|
mod check_lines;
|
||||||
|
|
@ -12,4 +11,5 @@ pub mod linter;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
mod pyproject;
|
mod pyproject;
|
||||||
|
mod python;
|
||||||
pub mod settings;
|
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
|
// Globally defined names which are not attributes of the builtins module, or are only present on
|
||||||
// some platforms.
|
// some platforms.
|
||||||
pub const MAGIC_GLOBALS: &[&str] = &[
|
pub const MAGIC_GLOBALS: &[&str] = &[
|
||||||
"__file__",
|
|
||||||
"__builtins__",
|
|
||||||
"__annotations__",
|
|
||||||
"WindowsError",
|
"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