示例#1
0
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()
示例#2
0
文件: function.py 项目: yuan-xy/medi
 def py__get__(self, instance, class_value):
     from medi.inference.value.instance import BoundMethod
     if instance is None:
         # Calling the Foo.bar results in the original bar function.
         return ValueSet([self])
     return ValueSet(
         [BoundMethod(instance, class_value.as_context(), self)])
示例#3
0
def _infer_subscript_list(context, index):
    """
    Handles slices in subscript nodes.
    """
    if index == ':':
        # Like array[:]
        return ValueSet([iterable.Slice(context, None, None, None)])

    elif index.type == 'subscript' and not index.children[0] == '.':
        # subscript basically implies a slice operation, except for Python 2's
        # Ellipsis.
        # e.g. array[:3]
        result = []
        for el in index.children:
            if el == ':':
                if not result:
                    result.append(None)
            elif el.type == 'sliceop':
                if len(el.children) == 2:
                    result.append(el.children[1])
            else:
                result.append(el)
        result += [None] * (3 - len(result))

        return ValueSet([iterable.Slice(context, *result)])
    elif index.type == 'subscriptlist':
        return ValueSet([iterable.SequenceLiteralValue(context.inference_state, context, index)])

    # No slices
    return context.infer_node(index)
示例#4
0
文件: typing.py 项目: yuan-xy/medi
    def execute_annotation(self):
        string_name = self._tree_name.value

        if string_name == 'Union':
            # This is kind of a special case, because we have Unions (in Medi
            # ValueSets).
            return self.gather_annotation_classes().execute_annotation()
        elif string_name == 'Optional':
            # Optional is basically just saying it's either None or the actual
            # type.
            return self.gather_annotation_classes().execute_annotation() \
                | ValueSet([builtin_from_name(self.inference_state, u'None')])
        elif string_name == 'Type':
            # The type is actually already given in the index_value
            return self._generics_manager[0]
        elif string_name == 'ClassVar':
            # For now don't do anything here, ClassVars are always used.
            return self._generics_manager[0].execute_annotation()

        mapped = {
            'Tuple': Tuple,
            'Generic': Generic,
            'Protocol': Protocol,
            'Callable': Callable,
        }
        cls = mapped[string_name]
        return ValueSet([
            cls(
                self.parent_context,
                self,
                self._tree_name,
                generics_manager=self._generics_manager,
            )
        ])
示例#5
0
    def define_generics(self, type_var_dict):
        from medi.inference.gradual.type_var import TypeVar
        changed = False
        new_generics = []
        for generic_set in self.get_generics():
            values = NO_VALUES
            for generic in generic_set:
                if isinstance(generic, (DefineGenericBaseClass, TypeVar)):
                    result = generic.define_generics(type_var_dict)
                    values |= result
                    if result != ValueSet({generic}):
                        changed = True
                else:
                    values |= ValueSet([generic])
            new_generics.append(values)

        if not changed:
            # There might not be any type vars that change. In that case just
            # return itself, because it does not make sense to potentially lose
            # cached results.
            return ValueSet([self])

        return ValueSet([
            self._create_instance_with_generics(
                TupleGenericManager(tuple(new_generics)))
        ])
示例#6
0
文件: klass.py 项目: yuan-xy/medi
    def py__call__(self, arguments=None):
        from medi.inference.value import TreeInstance

        from medi.inference.gradual.typing import TypedDict
        if self.is_typeddict():
            return ValueSet([TypedDict(self)])
        return ValueSet([
            TreeInstance(self.inference_state, self.parent_context, self,
                         arguments)
        ])
示例#7
0
文件: klass.py 项目: yuan-xy/medi
 def py__getitem__(self, index_value_set, contextualized_node):
     from medi.inference.gradual.base import GenericClass
     if not index_value_set:
         return ValueSet([self])
     return ValueSet(
         GenericClass(
             self,
             LazyGenericManager(
                 context_of_index=contextualized_node.context,
                 index_value=index_value,
             )) for index_value in index_value_set)
示例#8
0
def infer_return_for_callable(arguments, param_values, result_values):
    all_type_vars = {}
    for pv in param_values:
        if pv.array_type == 'list':
            type_var_dict = _infer_type_vars_for_callable(
                arguments, pv.py__iter__())
            all_type_vars.update(type_var_dict)

    return ValueSet.from_sets(
        v.define_generics(all_type_vars) if isinstance(v, (
            DefineGenericBaseClass, TypeVar)) else ValueSet({v})
        for v in result_values).execute_annotation()
示例#9
0
    def _tuple(self):
        def lambda_scoping_in_for_loop_sucks(lazy_value):
            return lambda: ValueSet(_resolve_forward_references(
                self._context_of_index,
                lazy_value.infer()
            ))

        if isinstance(self._index_value, SequenceLiteralValue):
            for lazy_value in self._index_value.py__iter__(contextualized_node=None):
                yield lambda_scoping_in_for_loop_sucks(lazy_value)
        else:
            yield lambda: ValueSet(_resolve_forward_references(
                self._context_of_index,
                ValueSet([self._index_value])
            ))
示例#10
0
 def _remap_type_vars(self, base):
     from medi.inference.gradual.type_var import TypeVar
     filter = self._class_value.get_type_var_filter()
     for type_var_set in base.get_generics():
         new = NO_VALUES
         for type_var in type_var_set:
             if isinstance(type_var, TypeVar):
                 names = filter.get(type_var.py__name__())
                 new |= ValueSet.from_sets(name.infer() for name in names)
             else:
                 # Mostly will be type vars, except if in some cases
                 # a concrete type will already be there. In that
                 # case just add it to the value set.
                 new |= ValueSet([type_var])
         yield new
示例#11
0
文件: imports.py 项目: yuan-xy/medi
def load_module_from_path(inference_state,
                          file_io,
                          import_names=None,
                          is_package=None):
    """
    This should pretty much only be used for get_modules_containing_name. It's
    here to ensure that a random path is still properly loaded into the Medi
    module structure.
    """
    path = file_io.path
    if import_names is None:
        e_sys_path = inference_state.get_sys_path()
        import_names, is_package = sys_path.transform_path_to_dotted(
            e_sys_path, path)
    else:
        assert isinstance(is_package, bool)

    is_stub = file_io.path.endswith('.pyi')
    if is_stub:
        folder_io = file_io.get_parent_folder()
        if folder_io.path.endswith('-stubs'):
            folder_io = FolderIO(folder_io.path[:-6])
        if file_io.path.endswith('__init__.pyi'):
            python_file_io = folder_io.get_file_io('__init__.py')
        else:
            python_file_io = folder_io.get_file_io(import_names[-1] + '.py')

        try:
            v = load_module_from_path(inference_state,
                                      python_file_io,
                                      import_names,
                                      is_package=is_package)
            values = ValueSet([v])
        except FileNotFoundError:
            values = NO_VALUES

        return create_stub_module(inference_state, values,
                                  parse_stub_module(inference_state, file_io),
                                  file_io, import_names)
    else:
        module = _load_python_module(
            inference_state,
            file_io,
            import_names=import_names,
            is_package=is_package,
        )
        inference_state.module_cache.add(import_names, ValueSet([module]))
        return module
示例#12
0
def convert_values(values,
                   only_stubs=False,
                   prefer_stubs=False,
                   ignore_compiled=True):
    assert not (only_stubs and prefer_stubs)
    with debug.increase_indent_cm('convert values'):
        if only_stubs or prefer_stubs:
            return ValueSet.from_sets(
                to_stub(value) or (
                    ValueSet({value}) if prefer_stubs else NO_VALUES)
                for value in values)
        else:
            return ValueSet.from_sets(
                _stub_to_python_value_set(stub_value,
                                          ignore_compiled=ignore_compiled)
                or ValueSet({stub_value}) for stub_value in values)
示例#13
0
    def infer(self, context, name):
        def_ = name.get_definition(import_name_always=True)
        if def_ is not None:
            type_ = def_.type
            is_classdef = type_ == 'classdef'
            if is_classdef or type_ == 'funcdef':
                if is_classdef:
                    c = ClassValue(self, context, name.parent)
                else:
                    c = FunctionValue.from_context(context, name.parent)
                return ValueSet([c])

            if type_ == 'expr_stmt':
                is_simple_name = name.parent.type not in ('power', 'trailer')
                if is_simple_name:
                    return infer_expr_stmt(context, def_, name)
            if type_ == 'for_stmt':
                container_types = context.infer_node(def_.children[3])
                cn = ContextualizedNode(context, def_.children[3])
                for_types = iterate_values(container_types, cn)
                n = TreeNameDefinition(context, name)
                return check_tuple_assignments(n, for_types)
            if type_ in ('import_from', 'import_name'):
                return imports.infer_import(context, name)
            if type_ == 'with_stmt':
                return tree_name_to_values(self, context, name)
            elif type_ == 'param':
                return context.py__getattribute__(name.value, position=name.end_pos)
        else:
            result = follow_error_node_imports_if_possible(context, name)
            if result is not None:
                return result

        return helpers.infer_call_of_leaf(context, name)
示例#14
0
 def infer(self):
     inferred = super(StubName, self).infer()
     if self.string_name == 'version_info' and self.get_root_context(
     ).py__name__() == 'sys':
         from medi.inference.gradual.stub_value import VersionInfo
         return ValueSet(VersionInfo(c) for c in inferred)
     return inferred
示例#15
0
文件: imports.py 项目: yuan-xy/medi
def import_module_by_names(inference_state,
                           import_names,
                           sys_path=None,
                           module_context=None,
                           prefer_stubs=True):
    if sys_path is None:
        sys_path = inference_state.get_sys_path()

    str_import_names = tuple(
        force_unicode(i.value if isinstance(i, tree.Name) else i)
        for i in import_names)
    value_set = [None]
    for i, name in enumerate(import_names):
        value_set = ValueSet.from_sets([
            import_module(
                inference_state,
                str_import_names[:i + 1],
                parent_module_value,
                sys_path,
                prefer_stubs=prefer_stubs,
            ) for parent_module_value in value_set
        ])
        if not value_set:
            message = 'No module named ' + '.'.join(str_import_names)
            if module_context is not None:
                _add_error(module_context, name, message)
            else:
                debug.warning(message)
            return NO_VALUES
    return value_set
示例#16
0
def _apply_decorators(context, node):
    """
    Returns the function, that should to be executed in the end.
    This is also the places where the decorators are processed.
    """
    if node.type == 'classdef':
        decoratee_value = ClassValue(
            context.inference_state,
            parent_context=context,
            tree_node=node
        )
    else:
        decoratee_value = FunctionValue.from_context(context, node)
    initial = values = ValueSet([decoratee_value])

    if is_big_annoying_library(context):
        return values

    for dec in reversed(node.get_decorators()):
        debug.dbg('decorator: %s %s', dec, values, color="MAGENTA")
        with debug.increase_indent_cm():
            dec_values = context.infer_node(dec.children[1])
            trailer_nodes = dec.children[2:-1]
            if trailer_nodes:
                # Create a trailer and infer it.
                trailer = tree.PythonNode('trailer', trailer_nodes)
                trailer.parent = dec
                dec_values = infer_trailer(context, dec_values, trailer)

            if not len(dec_values):
                code = dec.get_code(include_prefix=False)
                # For the short future, we don't want to hear about the runtime
                # decorator in typing that was intentionally omitted. This is not
                # "correct", but helps with debugging.
                if code != '@runtime\n':
                    debug.warning('decorator not found: %s on %s', dec, node)
                return initial

            values = dec_values.execute(arguments.ValuesArguments([values]))
            if not len(values):
                debug.warning('not possible to resolve wrappers found %s', node)
                return initial

        debug.dbg('decorator end %s', values, color="MAGENTA")
    if values != initial:
        return ValueSet([Decoratee(c, decoratee_value) for c in values])
    return values
示例#17
0
    def get_key_values(self):
        values = NO_VALUES
        if self.array_type == 'dict':
            for i, (key, instance) in enumerate(self._arguments.unpack()):
                if key is None and i == 0:
                    values |= ValueSet.from_sets(v.get_key_values()
                                                 for v in instance.infer()
                                                 if v.array_type == 'dict')
                if key:
                    values |= ValueSet([
                        compiled.create_simple_object(
                            self.inference_state,
                            key,
                        )
                    ])

        return values
示例#18
0
    def py__call__(self, arguments):
        names = self.get_function_slot_names(u'__call__')
        if not names:
            # Means the Instance is not callable.
            return super(_BaseTreeInstance, self).py__call__(arguments)

        return ValueSet.from_sets(name.infer().execute(arguments)
                                  for name in names)
示例#19
0
文件: typing.py 项目: yuan-xy/medi
 def get_key_values(self):
     filtered_values = itertools.chain.from_iterable(
         (f.values()
          for f in self._definition_class.get_filters(is_instance=True)))
     return ValueSet({
         create_simple_object(self.inference_state, v.string_name)
         for v in filtered_values
     })
示例#20
0
文件: klass.py 项目: yuan-xy/medi
    def get_metaclasses(self):
        args = self._get_bases_arguments()
        if args is not None:
            m = [value for key, value in args.unpack() if key == 'metaclass']
            metaclasses = ValueSet.from_sets(lazy_value.infer()
                                             for lazy_value in m)
            metaclasses = ValueSet(m for m in metaclasses if m.is_class())
            if metaclasses:
                return metaclasses

        for lazy_base in self.py__bases__():
            for value in lazy_base.infer():
                if value.is_class():
                    values = value.get_metaclasses()
                    if values:
                        return values
        return NO_VALUES
示例#21
0
    def py__getattribute__(self,
                           name_or_str,
                           name_context=None,
                           position=None,
                           analysis_errors=True):
        """
        :param position: Position of the last statement -> tuple of line, column
        """
        if name_context is None:
            name_context = self
        names = self.goto(name_or_str, position)

        string_name = name_or_str.value if isinstance(name_or_str,
                                                      Name) else name_or_str

        # This paragraph is currently needed for proper branch type inference
        # (static analysis).
        found_predefined_types = None
        if self.predefined_names and isinstance(name_or_str, Name):
            node = name_or_str
            while node is not None and not parser_utils.is_scope(node):
                node = node.parent
                if node.type in ("if_stmt", "for_stmt", "comp_for",
                                 'sync_comp_for'):
                    try:
                        name_dict = self.predefined_names[node]
                        types = name_dict[string_name]
                    except KeyError:
                        continue
                    else:
                        found_predefined_types = types
                        break
        if found_predefined_types is not None and names:
            from medi.inference import flow_analysis
            check = flow_analysis.reachability_check(
                context=self,
                value_scope=self.tree_node,
                node=name_or_str,
            )
            if check is flow_analysis.UNREACHABLE:
                values = NO_VALUES
            else:
                values = found_predefined_types
        else:
            values = ValueSet.from_sets(name.infer() for name in names)

        if not names and not values and analysis_errors:
            if isinstance(name_or_str, Name):
                from medi.inference import analysis
                message = ("NameError: name '%s' is not defined." %
                           string_name)
                analysis.add(name_context, 'name-error', name_or_str, message)

        debug.dbg('context.names_to_types: %s -> %s', names, values)
        if values:
            return values
        return self._check_for_additional_knowledge(name_or_str, name_context,
                                                    position)
示例#22
0
文件: type_var.py 项目: yuan-xy/medi
 def define_generics(self, type_var_dict):
     try:
         found = type_var_dict[self.py__name__()]
     except KeyError:
         pass
     else:
         if found:
             return found
     return self._get_classes() or ValueSet({self})
示例#23
0
    def py__getitem__(self, index_value_set, contextualized_node):
        names = self.get_function_slot_names(u'__getitem__')
        if not names:
            return super(_BaseTreeInstance, self).py__getitem__(
                index_value_set,
                contextualized_node,
            )

        args = ValuesArguments([index_value_set])
        return ValueSet.from_sets(name.infer().execute(args) for name in names)
示例#24
0
文件: typing.py 项目: yuan-xy/medi
 def py__getitem__(self, index_value_set, contextualized_node):
     return ValueSet(
         self.index_class.create_cached(
             self.inference_state,
             self.parent_context,
             self._tree_name,
             generics_manager=LazyGenericManager(
                 context_of_index=contextualized_node.context,
                 index_value=index_value,
             )) for index_value in index_value_set)
示例#25
0
文件: value.py 项目: yuan-xy/medi
 def execute_operation(self, other, operator):
     try:
         return ValueSet([
             create_from_access_path(
                 self.inference_state,
                 self.access_handle.execute_operation(
                     other.access_handle, operator))
         ])
     except TypeError:
         return NO_VALUES
示例#26
0
def _load_stub_module(module):
    if module.is_stub():
        return module
    return try_to_load_stub_cached(
        module.inference_state,
        import_names=module.string_names,
        python_value_set=ValueSet([module]),
        parent_module_value=None,
        sys_path=module.inference_state.get_sys_path(),
    )
示例#27
0
文件: module.py 项目: yuan-xy/medi
 def infer(self):
     if self._string_value is not None:
         s = self._string_value
         if self.parent_context.inference_state.environment.version_info.major == 2 \
                 and not isinstance(s, bytes):
             s = s.encode('utf-8')
         return ValueSet([
             create_simple_object(self.parent_context.inference_state, s)
         ])
     return compiled.get_string_value_set(self.parent_context.inference_state)
示例#28
0
    def infer(self):
        compiled_value = self._wrapped_name.infer_compiled_value()
        tree_value = self._parent_tree_value
        if tree_value.is_instance() or tree_value.is_class():
            tree_values = tree_value.py__getattribute__(self.string_name)
            if compiled_value.is_function():
                return ValueSet({MixedObject(compiled_value, v) for v in tree_values})

        module_context = tree_value.get_root_context()
        return _create(self._inference_state, compiled_value, module_context)
示例#29
0
文件: value.py 项目: yuan-xy/medi
    def py__call__(self, arguments):
        return_annotation = self.access_handle.get_return_annotation()
        if return_annotation is not None:
            # TODO the return annotation may also be a string.
            return create_from_access_path(
                self.inference_state, return_annotation).execute_annotation()

        try:
            self.access_handle.getattr_paths(u'__call__')
        except AttributeError:
            return super(CompiledValue, self).py__call__(arguments)
        else:
            if self.access_handle.is_class():
                from medi.inference.value import CompiledInstance
                return ValueSet([
                    CompiledInstance(self.inference_state, self.parent_context,
                                     self, arguments)
                ])
            else:
                return ValueSet(self._execute_function(arguments))
示例#30
0
文件: value.py 项目: yuan-xy/medi
 def infer(self):
     p = self._signature_param
     inference_state = self.parent_context.inference_state
     values = NO_VALUES
     if p.has_default:
         values = ValueSet(
             [create_from_access_path(inference_state, p.default)])
     if p.has_annotation:
         annotation = create_from_access_path(inference_state, p.annotation)
         values |= annotation.execute_with_values()
     return values