def test__str__(self):
     from zope.interface.exceptions import BrokenMethodImplementation
     excs = [
         BrokenMethodImplementation('aMethod', 'I said so'),
         Exception("Regular exception")
     ]
     dni = self._makeOne(excs)
     self.assertEqual(
         str(dni), "The object 'target' has failed to implement interface "
         "zope.interface.tests.test_exceptions.IDummy:\n"
         "    The contract of 'aMethod' is violated because I said so\n"
         "    Regular exception")
 def test__repr__(self):
     from zope.interface.exceptions import BrokenMethodImplementation
     excs = [
         BrokenMethodImplementation('aMethod', 'I said so'),
         # Use multiple arguments to normalize repr; versions of Python
         # prior to 3.7 add a trailing comma if there's just one.
         Exception("Regular", "exception")
     ]
     dni = self._makeOne(excs)
     self.assertEqual(
         repr(dni),
         "MultipleInvalid(<InterfaceClass zope.interface.tests.test_exceptions.IDummy>,"
         " 'target',"
         " (BrokenMethodImplementation('aMethod', 'I said so'),"
         " Exception('Regular', 'exception')))")
def _verify(iface, candidate, tentative=0, vtype=None):
    """Verify that 'candidate' might correctly implements 'iface'.

    This involves:

      o Making sure the candidate defines all the necessary methods

      o Making sure the methods have the correct signature

      o Making sure the candidate asserts that it implements the interface

    Note that this isn't the same as verifying that the class does
    implement the interface.

    If optional tentative is true, suppress the "is implemented by" test.
    """

    if vtype == 'c':
        tester = iface.implementedBy
    else:
        tester = iface.providedBy

    violations = []
    def format(e):
        return "    " + str(e).strip() + "\n"

    if not tentative and not tester(candidate):
        violations.append(format(DoesNotImplement(iface)))

    # Here the `desc` is either an `Attribute` or `Method` instance
    for name, desc in iface.namesAndDescriptions(1):
        if not hasattr(candidate, name):
            if (not isinstance(desc, Method)) and vtype == 'c':
                # We can't verify non-methods on classes, since the
                # class may provide attrs in it's __init__.
                continue

            if isinstance(desc, Method):
                violations.append("    The %r method was not provided.\n" % (name,))
            else:
                violations.append("    The %r attribute was not provided.\n" % (name,))
            continue

        attr = getattr(candidate, name)
        if not isinstance(desc, Method):
            # If it's not a method, there's nothing else we can test
            continue

        if isinstance(attr, FunctionType):
            # should never get here, since classes should not provide functions
            meth = fromFunction(attr, iface, name=name)
        elif (isinstance(attr, MethodTypes)
              and type(attr.im_func) is FunctionType):
            meth = fromMethod(attr, iface, name)
        else:
            if not callable(attr):
                violations.append(format(BrokenMethodImplementation(name, "Not a method")))
            # sigh, it's callable, but we don't know how to intrspect it, so
            # we have to give it a pass.
            continue

        # Make sure that the required and implemented method signatures are
        # the same.
        desc = desc.getSignatureInfo()
        meth = meth.getSignatureInfo()

        mess = _incompat(desc, meth)
        if mess:
            violations.append(format(BrokenMethodImplementation(name, mess)))

    if violations:
        raise Exception("".join(violations))
    return True
Example #4
0
def _verify(iface, candidate, tentative=0, vtype=None):
    """Verify that 'candidate' might correctly implements 'iface'.

    This involves:

      o Making sure the candidate defines all the necessary methods

      o Making sure the methods have the correct signature

      o Making sure the candidate asserts that it implements the interface

    Note that this isn't the same as verifying that the class does
    implement the interface.

    If optional tentative is true, suppress the "is implemented by" test.
    """

    if vtype == 'c':
        tester = iface.implementedBy
    else:
        tester = iface.providedBy

    if not tentative and not tester(candidate):
        raise DoesNotImplement(iface)

    # Here the `desc` is either an `Attribute` or `Method` instance
    for name, desc in iface.namesAndDescriptions(1):
        try:
            attr = getattr(candidate, name)
        except AttributeError:
            if (not isinstance(desc, Method)) and vtype == 'c':
                # We can't verify non-methods on classes, since the
                # class may provide attrs in it's __init__.
                continue

            raise BrokenImplementation(iface, name)

        if not isinstance(desc, Method):
            # If it's not a method, there's nothing else we can test
            continue

        if isinstance(attr, FunctionType):
            if sys.version_info[0] >= 3 and isinstance(candidate, type) and vtype == 'c':
                # This is an "unbound method" in Python 3.
                # Only unwrap this if we're verifying implementedBy;
                # otherwise we can unwrap @staticmethod on classes that directly
                # provide an interface.
                meth = fromFunction(attr, iface, name=name,
                                    imlevel=1)
            else:
                # Nope, just a normal function
                meth = fromFunction(attr, iface, name=name)
        elif (isinstance(attr, MethodTypes)
              and type(attr.__func__) is FunctionType):
            meth = fromMethod(attr, iface, name)
        elif isinstance(attr, property) and vtype == 'c':
            # We without an instance we cannot be sure it's not a
            # callable.
            continue
        else:
            if not callable(attr):
                raise BrokenMethodImplementation(name, "Not a method")
            # sigh, it's callable, but we don't know how to introspect it, so
            # we have to give it a pass.
            continue

        # Make sure that the required and implemented method signatures are
        # the same.
        desc = desc.getSignatureInfo()
        meth = meth.getSignatureInfo()

        mess = _incompat(desc, meth)
        if mess:
            raise BrokenMethodImplementation(name, mess)

    return True
Example #5
0
def _verify_element(iface, name, desc, candidate, vtype):
    # Here the `desc` is either an `Attribute` or `Method` instance
    try:
        attr = getattr(candidate, name)
    except AttributeError:
        if (not isinstance(desc, Method)) and vtype == 'c':
            # We can't verify non-methods on classes, since the
            # class may provide attrs in it's __init__.
            return
        # TODO: On Python 3, this should use ``raise...from``
        raise BrokenImplementation(iface, desc, candidate)

    if not isinstance(desc, Method):
        # If it's not a method, there's nothing else we can test
        return

    if inspect.ismethoddescriptor(attr) or inspect.isbuiltin(attr):
        # The first case is what you get for things like ``dict.pop``
        # on CPython (e.g., ``verifyClass(IFullMapping, dict))``). The
        # second case is what you get for things like ``dict().pop`` on
        # CPython (e.g., ``verifyObject(IFullMapping, dict()))``.
        # In neither case can we get a signature, so there's nothing
        # to verify. Even the inspect module gives up and raises
        # ValueError: no signature found. The ``__text_signature__`` attribute
        # isn't typically populated either.
        #
        # Note that on PyPy 2 or 3 (up through 7.3 at least), these are
        # not true for things like ``dict.pop`` (but might be true for C extensions?)
        return

    if isinstance(attr, FunctionType):
        if sys.version_info[0] >= 3 and isinstance(candidate,
                                                   type) and vtype == 'c':
            # This is an "unbound method" in Python 3.
            # Only unwrap this if we're verifying implementedBy;
            # otherwise we can unwrap @staticmethod on classes that directly
            # provide an interface.
            meth = fromFunction(attr, iface, name=name, imlevel=1)
        else:
            # Nope, just a normal function
            meth = fromFunction(attr, iface, name=name)
    elif (isinstance(attr, MethodTypes)
          and type(attr.__func__) is FunctionType):
        meth = fromMethod(attr, iface, name)
    elif isinstance(attr, property) and vtype == 'c':
        # Without an instance we cannot be sure it's not a
        # callable.
        # TODO: This should probably check inspect.isdatadescriptor(),
        # a more general form than ``property``
        return

    else:
        if not callable(attr):
            raise BrokenMethodImplementation(desc,
                                             "implementation is not a method",
                                             attr, iface, candidate)
        # sigh, it's callable, but we don't know how to introspect it, so
        # we have to give it a pass.
        return

    # Make sure that the required and implemented method signatures are
    # the same.
    mess = _incompat(desc.getSignatureInfo(), meth.getSignatureInfo())
    if mess:
        if PYPY2 and _pypy2_false_positive(mess, candidate, vtype):
            return
        raise BrokenMethodImplementation(desc, mess, attr, iface, candidate)