def infer_return_types(function, arguments): """ Infers the type of a function's return value, according to type annotations. """ all_annotations = py__annotations__(function.tree_node) annotation = all_annotations.get("return", None) if annotation is None: # If there is no Python 3-type annotation, look for a Python 2-type annotation node = function.tree_node comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_VALUES match = re.match(r"^#\s*type:\s*\([^#]*\)\s*->\s*([^#]*)", comment) if not match: return NO_VALUES return _infer_annotation_string( function.get_default_param_context(), match.group(1).strip()).execute_annotation() context = function.get_default_param_context() unknown_type_vars = find_unknown_type_vars(context, annotation) annotation_values = infer_annotation(context, annotation) if not unknown_type_vars: return annotation_values.execute_annotation() type_var_dict = infer_type_vars_for_execution(function, arguments, all_annotations) return ValueSet.from_sets( ann.define_generics(type_var_dict) if isinstance( ann, (DefineGenericBaseClass, TypeVar)) else ValueSet({ann}) for ann in annotation_values).execute_annotation()
def _find_type_from_comment_hint(context, node, varlist, name): index = None if varlist.type in ("testlist_star_expr", "exprlist", "testlist"): # something like "a, b = 1, 2" index = 0 for child in varlist.children: if child == name: break if child.type == "operator": continue index += 1 else: return [] comment = parser_utils.get_following_comment_same_line(node) if comment is None: return [] match = re.match(r"^#\s*type:\s*([^#]*)", comment) if not match: return [] annotation = tree.String( repr(str(match.group(1).strip())), node.start_pos) annotation.parent = node.parent return _evaluate_for_annotation(context, annotation, index)
def _infer_param(function_value, param): """ Infers the type of a function parameter, using type annotations. """ annotation = param.annotation if annotation is None: # If no Python 3-style annotation, look for a Python 2-style comment # annotation. # Identify parameters to function in the same sequence as they would # appear in a type comment. all_params = [child for child in param.parent.children if child.type == 'param'] node = param.parent.parent comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_VALUES match = re.match(r"^#\s*type:\s*\(([^#]*)\)\s*->", comment) if not match: return NO_VALUES params_comments = _split_comment_param_declaration(match.group(1)) # Find the specific param being investigated index = all_params.index(param) # If the number of parameters doesn't match length of type comment, # ignore first parameter (assume it's self). if len(params_comments) != len(all_params): debug.warning( "Comments length != Params length %s %s", params_comments, all_params ) from jedi.inference.value.instance import InstanceArguments if function_value.is_bound_method(): if index == 0: # Assume it's self, which is already handled return NO_VALUES index -= 1 if index >= len(params_comments): return NO_VALUES param_comment = params_comments[index] return _infer_annotation_string( function_value.get_default_param_context(), param_comment ) # Annotations are like default params and resolve in the same way. context = function_value.get_default_param_context() return infer_annotation(context, annotation)
def infer_param(execution_context, param): """ Infers the type of a function parameter, using type annotations. """ annotation = param.annotation if annotation is None: # If no Python 3-style annotation, look for a Python 2-style comment # annotation. # Identify parameters to function in the same sequence as they would # appear in a type comment. all_params = [child for child in param.parent.children if child.type == 'param'] node = param.parent.parent comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_CONTEXTS match = re.match(r"^#\s*type:\s*\(([^#]*)\)\s*->", comment) if not match: return NO_CONTEXTS params_comments = _split_comment_param_declaration(match.group(1)) # Find the specific param being investigated index = all_params.index(param) # If the number of parameters doesn't match length of type comment, # ignore first parameter (assume it's self). if len(params_comments) != len(all_params): debug.warning( "Comments length != Params length %s %s", params_comments, all_params ) from jedi.evaluate.context.instance import InstanceArguments if isinstance(execution_context.var_args, InstanceArguments): if index == 0: # Assume it's self, which is already handled return NO_CONTEXTS index -= 1 if index >= len(params_comments): return NO_CONTEXTS param_comment = params_comments[index] return _evaluate_annotation_string( execution_context.get_root_context(), param_comment ) module_context = execution_context.get_root_context() return _evaluate_for_annotation(module_context, annotation)
def infer_param(execution_context, param): """ Infers the type of a function parameter, using type annotations. """ annotation = param.annotation if annotation is None: # If no Python 3-style annotation, look for a Python 2-style comment # annotation. # Identify parameters to function in the same sequence as they would # appear in a type comment. all_params = [child for child in param.parent.children if child.type == 'param'] node = param.parent.parent comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_CONTEXTS match = re.match(r"^#\s*type:\s*\(([^#]*)\)\s*->", comment) if not match: return NO_CONTEXTS params_comments = _split_comment_param_declaration(match.group(1)) # Find the specific param being investigated index = all_params.index(param) # If the number of parameters doesn't match length of type comment, # ignore first parameter (assume it's self). if len(params_comments) != len(all_params): debug.warning( "Comments length != Params length %s %s", params_comments, all_params ) from jedi.evaluate.context.instance import BaseInstanceFunctionExecution if isinstance(execution_context, BaseInstanceFunctionExecution): if index == 0: # Assume it's self, which is already handled return NO_CONTEXTS index -= 1 if index >= len(params_comments): return NO_CONTEXTS param_comment = params_comments[index] return _evaluate_annotation_string( execution_context.get_root_context(), param_comment ) module_context = execution_context.get_root_context() return _evaluate_for_annotation(module_context, annotation)
def _find_type_from_comment_hint(context, node, varlist, name): index = None if varlist.type in ("testlist_star_expr", "exprlist", "testlist"): # something like "a, b = 1, 2" index = 0 for child in varlist.children: if child == name: break if child.type == "operator": continue index += 1 else: return [] comment = parser_utils.get_following_comment_same_line(node) if comment is None: return [] match = re.match(r"^#\s*type:\s*([^#]*)", comment) if match is None: return [] return _evaluate_annotation_string(context, match.group(1).strip(), index)
def infer_return_types(function_context): """ Infers the type of a function's return value, according to type annotations. """ annotation = py__annotations__(function_context.tree_node).get( "return", None) if annotation is None: # If there is no Python 3-type annotation, look for a Python 2-type annotation node = function_context.tree_node comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_CONTEXTS match = re.match(r"^#\s*type:\s*\([^#]*\)\s*->\s*([^#]*)", comment) if not match: return NO_CONTEXTS return _evaluate_annotation_string(function_context.get_root_context(), match.group(1).strip()) module_context = function_context.get_root_context() return _evaluate_for_annotation(module_context, annotation)
def infer_return_types(function_context): """ Infers the type of a function's return value, according to type annotations. """ annotation = py__annotations__(function_context.tree_node).get("return", None) if annotation is None: # If there is no Python 3-type annotation, look for a Python 2-type annotation node = function_context.tree_node comment = parser_utils.get_following_comment_same_line(node) if comment is None: return NO_CONTEXTS match = re.match(r"^#\s*type:\s*\([^#]*\)\s*->\s*([^#]*)", comment) if not match: return NO_CONTEXTS return _evaluate_annotation_string( function_context.get_root_context(), match.group(1).strip() ) module_context = function_context.get_root_context() return _evaluate_for_annotation(module_context, annotation)