forked from python-mode/python-mode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbrain_typing.py
More file actions
89 lines (70 loc) · 2.43 KB
/
brain_typing.py
File metadata and controls
89 lines (70 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Copyright (c) 2016 David Euresti <david@dropbox.com>
"""Astroid hooks for typing.py support."""
import textwrap
from astroid import (
MANAGER, UseInferenceDefault, extract_node, inference_tip,
nodes, InferenceError)
from astroid.nodes import List, Tuple
TYPING_NAMEDTUPLE_BASENAMES = {
'NamedTuple',
'typing.NamedTuple'
}
def infer_typing_namedtuple(node, context=None):
"""Infer a typing.NamedTuple(...) call."""
# This is essentially a namedtuple with different arguments
# so we extract the args and infer a named tuple.
try:
func = next(node.func.infer())
except InferenceError:
raise UseInferenceDefault
if func.qname() != 'typing.NamedTuple':
raise UseInferenceDefault
if len(node.args) != 2:
raise UseInferenceDefault
if not isinstance(node.args[1], (List, Tuple)):
raise UseInferenceDefault
names = []
for elt in node.args[1].elts:
if not isinstance(elt, (List, Tuple)):
raise UseInferenceDefault
if len(elt.elts) != 2:
raise UseInferenceDefault
names.append(elt.elts[0].as_string())
typename = node.args[0].as_string()
node = extract_node('namedtuple(%(typename)s, (%(fields)s,)) ' %
{'typename': typename, 'fields': ",".join(names)})
return node.infer(context=context)
def infer_typing_namedtuple_class(node, context=None):
"""Infer a subclass of typing.NamedTuple"""
# Check if it has the corresponding bases
if not set(node.basenames) & TYPING_NAMEDTUPLE_BASENAMES:
raise UseInferenceDefault
annassigns_fields = [
annassign.target.name for annassign in node.body
if isinstance(annassign, nodes.AnnAssign)
]
code = textwrap.dedent('''
from collections import namedtuple
namedtuple({typename!r}, {fields!r})
''').format(
typename=node.name,
fields=",".join(annassigns_fields)
)
node = extract_node(code)
return node.infer(context=context)
def looks_like_typing_namedtuple(node):
func = node.func
if isinstance(func, nodes.Attribute):
return func.attrname == 'NamedTuple'
if isinstance(func, nodes.Name):
return func.name == 'NamedTuple'
return False
MANAGER.register_transform(
nodes.Call,
inference_tip(infer_typing_namedtuple),
looks_like_typing_namedtuple
)
MANAGER.register_transform(
nodes.ClassDef,
inference_tip(infer_typing_namedtuple_class)
)