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
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
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)