Пример #1
0
    def _report_implementation_problems(
        self,
        impl_type: Instance,
        iface_type: Instance,
        api: CheckerPluginInterface,
        context: Context,
    ) -> None:
        # This mimicks mypy's MessageBuilder.report_protocol_problems with
        # simplifications for zope interfaces.

        # Blatantly assume we are dealing with this particular implementation
        # of CheckerPluginInterface, because it has functionality we want to
        # reuse.
        assert isinstance(api, TypeChecker)

        impl_info = impl_type.type
        iface_info = iface_type.type
        iface_members = self._index_members(iface_info)
        impl_members = self._index_members(impl_info)

        # Report missing members
        missing: Dict[str, List[str]] = defaultdict(list)
        for member, member_iface in iface_members.items():
            if find_member(member, impl_type, impl_type) is None:
                iface_name = member_iface.fullname
                if member_iface == iface_info:
                    # Since interface is directly implemented by this class, we
                    # can use shorter name.
                    iface_name = member_iface.name
                missing[iface_name].append(member)

        if missing:
            for iface_name, members in missing.items():
                missing_fmt = ", ".join(members)
                api.fail(
                    f"'{impl_info.name}' is missing following "
                    f"'{iface_name}' interface members: {missing_fmt}.",
                    context,
                )

        # Report member type conflicts
        for member, member_iface in iface_members.items():
            iface_mtype = find_member(member, iface_type, iface_type)
            assert iface_mtype is not None
            impl_mtype = find_member(member, impl_type, impl_type)
            if impl_mtype is None:
                continue

            # Find out context for error reporting. If the member is not
            # defined inside the class that declares interface implementation,
            # show the error near the class definition. Otherwise, show it near
            # the member definition.
            ctx: Context = impl_info
            impl_member_def_info = impl_members.get(member)
            impl_name = impl_info.name
            if impl_member_def_info is not None:
                if impl_member_def_info == impl_info:
                    ctx = impl_mtype
                else:
                    impl_name = impl_member_def_info.fullname

            iface_name = iface_info.name
            if member_iface != iface_info:
                iface_name = member_iface.fullname

            if isinstance(impl_mtype, PartialType):
                # We don't know how to deal with partial type here. Partial
                # types will be resolved later when the implementation class is
                # fully type-checked. We are doing our job before that, so all
                # we can do is to skip checking of such members.
                continue

            if isinstance(iface_mtype, FunctionLike) and isinstance(
                    impl_mtype, FunctionLike):
                api.check_override(
                    override=impl_mtype,
                    original=iface_mtype,
                    name=impl_name,
                    name_in_super=member,
                    supertype=iface_name,
                    original_class_or_static=False,
                    override_class_or_static=False,
                    node=ctx,
                )

            else:
                # We could check the field type for compatibility with the code
                # below, however this yields too many false-positives in
                # real-life projects. The problem is that we can only check
                # types defined on a class, instead of instance types, so all
                # "descriptor" properties will be falsly reported as type
                # mismatches. Instead we opt-out from property type checking
                # until we figure out the workaround.

                # api.check_subtype(
                #     impl_mtype,
                #     iface_mtype,
                #     context=ctx,
                #     subtype_label=f'"{impl_name}" has type',
                #     supertype_label=f'interface "{iface_name}" defines "{member}" as',
                # )
                pass
Пример #2
0
def unpack_callback_protocol(t: Instance) -> Optional[Type]:
    assert t.type.is_protocol
    if t.type.protocol_members == ['__call__']:
        return find_member('__call__', t, t)
    return None
Пример #3
0
def unpack_callback_protocol(t: Instance) -> Optional[Type]:
    assert t.type.is_protocol
    if t.type.protocol_members == ['__call__']:
        return find_member('__call__', t, t)
    return None