Path: blob/master/elisp/emacs-for-python/rope-dist/rope/base/oi/soi.py
1440 views
"""A module for inferring objects12For more information see the documentation in `rope.base.oi`3package.45"""6import rope.base.builtins7import rope.base.pynames8import rope.base.pyobjects9from rope.base import evaluate, utils, arguments101112_ignore_inferred = utils.ignore_exception(13rope.base.pyobjects.IsBeingInferredError)141516@_ignore_inferred17def infer_returned_object(pyfunction, args):18"""Infer the `PyObject` this `PyFunction` returns after calling"""19object_info = pyfunction.pycore.object_info20result = object_info.get_exact_returned(pyfunction, args)21if result is not None:22return result23result = _infer_returned(pyfunction, args)24if result is not None:25if args and pyfunction.get_module().get_resource() is not None:26params = args.get_arguments(27pyfunction.get_param_names(special_args=False))28object_info.function_called(pyfunction, params, result)29return result30return object_info.get_returned(pyfunction, args)3132@_ignore_inferred33def infer_parameter_objects(pyfunction):34"""Infer the `PyObject`\s of parameters of this `PyFunction`"""35object_info = pyfunction.pycore.object_info36result = object_info.get_parameter_objects(pyfunction)37if result is None:38result = _parameter_objects(pyfunction)39_handle_first_parameter(pyfunction, result)40return result4142def _handle_first_parameter(pyobject, parameters):43kind = pyobject.get_kind()44if parameters is None or kind not in ['method', 'classmethod']:45pass46if not parameters:47if not pyobject.get_param_names(special_args=False):48return49parameters.append(rope.base.pyobjects.get_unknown())50if kind == 'method':51parameters[0] = rope.base.pyobjects.PyObject(pyobject.parent)52if kind == 'classmethod':53parameters[0] = pyobject.parent5455@_ignore_inferred56def infer_assigned_object(pyname):57if not pyname.assignments:58return59for assignment in reversed(pyname.assignments):60result = _infer_assignment(assignment, pyname.module)61if result is not None:62return result6364def get_passed_objects(pyfunction, parameter_index):65object_info = pyfunction.pycore.object_info66result = object_info.get_passed_objects(pyfunction,67parameter_index)68if not result:69statically_inferred = _parameter_objects(pyfunction)70if len(statically_inferred) > parameter_index:71result.append(statically_inferred[parameter_index])72return result7374def _infer_returned(pyobject, args):75if args:76# HACK: Setting parameter objects manually77# This is not thread safe and might cause problems if `args`78# does not come from a good call site79pyobject.get_scope().invalidate_data()80pyobject._set_parameter_pyobjects(81args.get_arguments(pyobject.get_param_names(special_args=False)))82scope = pyobject.get_scope()83if not scope._get_returned_asts():84return85maxtries = 386for returned_node in reversed(scope._get_returned_asts()[-maxtries:]):87try:88resulting_pyname = evaluate.eval_node(scope, returned_node)89if resulting_pyname is None:90continue91pyobject = resulting_pyname.get_object()92if pyobject == rope.base.pyobjects.get_unknown():93continue94if not scope._is_generator():95return pyobject96else:97return rope.base.builtins.get_generator(pyobject)98except rope.base.pyobjects.IsBeingInferredError:99pass100101def _parameter_objects(pyobject):102params = pyobject.get_param_names(special_args=False)103return [rope.base.pyobjects.get_unknown()] * len(params)104105# handling `rope.base.pynames.AssignmentValue`106107@_ignore_inferred108def _infer_assignment(assignment, pymodule):109result = _follow_pyname(assignment, pymodule)110if result is None:111return None112pyname, pyobject = result113pyobject = _follow_evaluations(assignment, pyname, pyobject)114if pyobject is None:115return None116return _follow_levels(assignment, pyobject)117118def _follow_levels(assignment, pyobject):119for index in assignment.levels:120if isinstance(pyobject.get_type(), rope.base.builtins.Tuple):121holdings = pyobject.get_type().get_holding_objects()122if holdings:123pyobject = holdings[min(len(holdings) - 1, index)]124else:125pyobject = None126elif isinstance(pyobject.get_type(), rope.base.builtins.List):127pyobject = pyobject.get_type().holding128else:129pyobject = None130if pyobject is None:131break132return pyobject133134@_ignore_inferred135def _follow_pyname(assignment, pymodule, lineno=None):136assign_node = assignment.ast_node137if lineno is None:138lineno = _get_lineno_for_node(assign_node)139holding_scope = pymodule.get_scope().get_inner_scope_for_line(lineno)140pyname = evaluate.eval_node(holding_scope, assign_node)141if pyname is not None:142result = pyname.get_object()143if isinstance(result.get_type(), rope.base.builtins.Property) and \144holding_scope.get_kind() == 'Class':145arg = rope.base.pynames.UnboundName(146rope.base.pyobjects.PyObject(holding_scope.pyobject))147return pyname, result.get_type().get_property_object(148arguments.ObjectArguments([arg]))149return pyname, result150151@_ignore_inferred152def _follow_evaluations(assignment, pyname, pyobject):153new_pyname = pyname154tokens = assignment.evaluation.split('.')155for token in tokens:156call = token.endswith('()')157if call:158token = token[:-2]159if token:160pyname = new_pyname161new_pyname = _get_attribute(pyobject, token)162if new_pyname is not None:163pyobject = new_pyname.get_object()164if pyobject is not None and call:165if isinstance(pyobject, rope.base.pyobjects.AbstractFunction):166args = arguments.ObjectArguments([pyname])167pyobject = pyobject.get_returned_object(args)168else:169pyobject = None170if pyobject is None:171break172if pyobject is not None and assignment.assign_type:173return rope.base.pyobjects.PyObject(pyobject)174return pyobject175176177def _get_lineno_for_node(assign_node):178if hasattr(assign_node, 'lineno') and \179assign_node.lineno is not None:180return assign_node.lineno181return 1182183def _get_attribute(pyobject, name):184if pyobject is not None and name in pyobject:185return pyobject[name]186187188