Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
marvel
GitHub Repository: marvel/qnf
Path: blob/master/elisp/emacs-for-python/rope-dist/rope/base/oi/soi.py
1440 views
1
"""A module for inferring objects
2
3
For more information see the documentation in `rope.base.oi`
4
package.
5
6
"""
7
import rope.base.builtins
8
import rope.base.pynames
9
import rope.base.pyobjects
10
from rope.base import evaluate, utils, arguments
11
12
13
_ignore_inferred = utils.ignore_exception(
14
rope.base.pyobjects.IsBeingInferredError)
15
16
17
@_ignore_inferred
18
def infer_returned_object(pyfunction, args):
19
"""Infer the `PyObject` this `PyFunction` returns after calling"""
20
object_info = pyfunction.pycore.object_info
21
result = object_info.get_exact_returned(pyfunction, args)
22
if result is not None:
23
return result
24
result = _infer_returned(pyfunction, args)
25
if result is not None:
26
if args and pyfunction.get_module().get_resource() is not None:
27
params = args.get_arguments(
28
pyfunction.get_param_names(special_args=False))
29
object_info.function_called(pyfunction, params, result)
30
return result
31
return object_info.get_returned(pyfunction, args)
32
33
@_ignore_inferred
34
def infer_parameter_objects(pyfunction):
35
"""Infer the `PyObject`\s of parameters of this `PyFunction`"""
36
object_info = pyfunction.pycore.object_info
37
result = object_info.get_parameter_objects(pyfunction)
38
if result is None:
39
result = _parameter_objects(pyfunction)
40
_handle_first_parameter(pyfunction, result)
41
return result
42
43
def _handle_first_parameter(pyobject, parameters):
44
kind = pyobject.get_kind()
45
if parameters is None or kind not in ['method', 'classmethod']:
46
pass
47
if not parameters:
48
if not pyobject.get_param_names(special_args=False):
49
return
50
parameters.append(rope.base.pyobjects.get_unknown())
51
if kind == 'method':
52
parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent)
53
if kind == 'classmethod':
54
parameters[0] = pyobject.parent
55
56
@_ignore_inferred
57
def infer_assigned_object(pyname):
58
if not pyname.assignments:
59
return
60
for assignment in reversed(pyname.assignments):
61
result = _infer_assignment(assignment, pyname.module)
62
if result is not None:
63
return result
64
65
def get_passed_objects(pyfunction, parameter_index):
66
object_info = pyfunction.pycore.object_info
67
result = object_info.get_passed_objects(pyfunction,
68
parameter_index)
69
if not result:
70
statically_inferred = _parameter_objects(pyfunction)
71
if len(statically_inferred) > parameter_index:
72
result.append(statically_inferred[parameter_index])
73
return result
74
75
def _infer_returned(pyobject, args):
76
if args:
77
# HACK: Setting parameter objects manually
78
# This is not thread safe and might cause problems if `args`
79
# does not come from a good call site
80
pyobject.get_scope().invalidate_data()
81
pyobject._set_parameter_pyobjects(
82
args.get_arguments(pyobject.get_param_names(special_args=False)))
83
scope = pyobject.get_scope()
84
if not scope._get_returned_asts():
85
return
86
maxtries = 3
87
for returned_node in reversed(scope._get_returned_asts()[-maxtries:]):
88
try:
89
resulting_pyname = evaluate.eval_node(scope, returned_node)
90
if resulting_pyname is None:
91
continue
92
pyobject = resulting_pyname.get_object()
93
if pyobject == rope.base.pyobjects.get_unknown():
94
continue
95
if not scope._is_generator():
96
return pyobject
97
else:
98
return rope.base.builtins.get_generator(pyobject)
99
except rope.base.pyobjects.IsBeingInferredError:
100
pass
101
102
def _parameter_objects(pyobject):
103
params = pyobject.get_param_names(special_args=False)
104
return [rope.base.pyobjects.get_unknown()] * len(params)
105
106
# handling `rope.base.pynames.AssignmentValue`
107
108
@_ignore_inferred
109
def _infer_assignment(assignment, pymodule):
110
result = _follow_pyname(assignment, pymodule)
111
if result is None:
112
return None
113
pyname, pyobject = result
114
pyobject = _follow_evaluations(assignment, pyname, pyobject)
115
if pyobject is None:
116
return None
117
return _follow_levels(assignment, pyobject)
118
119
def _follow_levels(assignment, pyobject):
120
for index in assignment.levels:
121
if isinstance(pyobject.get_type(), rope.base.builtins.Tuple):
122
holdings = pyobject.get_type().get_holding_objects()
123
if holdings:
124
pyobject = holdings[min(len(holdings) - 1, index)]
125
else:
126
pyobject = None
127
elif isinstance(pyobject.get_type(), rope.base.builtins.List):
128
pyobject = pyobject.get_type().holding
129
else:
130
pyobject = None
131
if pyobject is None:
132
break
133
return pyobject
134
135
@_ignore_inferred
136
def _follow_pyname(assignment, pymodule, lineno=None):
137
assign_node = assignment.ast_node
138
if lineno is None:
139
lineno = _get_lineno_for_node(assign_node)
140
holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)
141
pyname = evaluate.eval_node(holding_scope, assign_node)
142
if pyname is not None:
143
result = pyname.get_object()
144
if isinstance(result.get_type(), rope.base.builtins.Property) and \
145
holding_scope.get_kind() == 'Class':
146
arg = rope.base.pynames.UnboundName(
147
rope.base.pyobjects.PyObject(holding_scope.pyobject))
148
return pyname, result.get_type().get_property_object(
149
arguments.ObjectArguments([arg]))
150
return pyname, result
151
152
@_ignore_inferred
153
def _follow_evaluations(assignment, pyname, pyobject):
154
new_pyname = pyname
155
tokens = assignment.evaluation.split('.')
156
for token in tokens:
157
call = token.endswith('()')
158
if call:
159
token = token[:-2]
160
if token:
161
pyname = new_pyname
162
new_pyname = _get_attribute(pyobject, token)
163
if new_pyname is not None:
164
pyobject = new_pyname.get_object()
165
if pyobject is not None and call:
166
if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):
167
args = arguments.ObjectArguments([pyname])
168
pyobject = pyobject.get_returned_object(args)
169
else:
170
pyobject = None
171
if pyobject is None:
172
break
173
if pyobject is not None and assignment.assign_type:
174
return rope.base.pyobjects.PyObject(pyobject)
175
return pyobject
176
177
178
def _get_lineno_for_node(assign_node):
179
if hasattr(assign_node, 'lineno') and \
180
assign_node.lineno is not None:
181
return assign_node.lineno
182
return 1
183
184
def _get_attribute(pyobject, name):
185
if pyobject is not None and name in pyobject:
186
return pyobject[name]
187
188