diff --git a/Lib/interfaceChecker.py b/Lib/interfaceChecker.py new file mode 100644 index 000000000..f2a447648 --- /dev/null +++ b/Lib/interfaceChecker.py @@ -0,0 +1,89 @@ +import sys, types + +try: + import describeFunction +except ImportError: + print "(Can't check interfaces, describeFunction could not be imported)" + describeFunction = None + + +def collectMethodNames(theClass, names=None): + if names is None: + names = {} + names.update(theClass.__dict__) + for baseClass in theClass.__bases__: + collectMethodNames(baseClass, names) + names = names.keys() + names.sort() + return names + + +def checkClass(moduleName, theClass): + className = theClass.__name__ + if theClass.__module__ <> moduleName: + return + if not hasattr(theClass, "__implements__"): + print "Interfaceless class: %s (%s)" % (className, theClass.__module__) + return + interfaces = theClass.__implements__ + if interfaces is None: + return + if isinstance(interfaces, types.ClassType): + interfaces = (interfaces,) + gotOne = 0 + for interface in interfaces: + methodNames = collectMethodNames(interface) + methodNames.sort() + for methodName in methodNames: + method = getattr(interface, methodName) + if not isinstance(method, types.UnboundMethodType): + continue + method = method.im_func + if not hasattr(theClass, methodName): + if not gotOne: + print "\nWarnings for module %s\n" % moduleName + gotOne = 1 + print "class %s misses required method:\n %s" % (className, describeFunction.describe(method)) + continue + method2 = getattr(theClass, methodName).im_func + argList = describeFunction._describe(method) + argList2 = describeFunction._describe(method2) + if len(argList2) < len(argList): + if not gotOne: + print "\nWarnings for module %s\n" % moduleName + gotOne = 1 + print "Method has not enough arguments:" + print " interface: %s.%s" % (className, describeFunction.describe(method)) + print " implementation: %s.%s" % (className, describeFunction.describe(method2)) + continue + for i in range(len(argList)): + if argList[i] <> argList2[i]: + if not gotOne: + print "\nWarnings for module %s\n" % moduleName + gotOne = 1 + print "Method has different arguments:" + print " interface: %s.%s" % (className, describeFunction.describe(method)) + print " implementation: %s.%s" % (className, describeFunction.describe(method2)) + break + for arg in argList2[len(argList):]: + if type(arg) == types.StringType: + if not gotOne: + print "\nWarnings for module %s\n" % moduleName + gotOne = 1 + print "Additional argument(s) should have default value(s):" + print " interface: %s.%s" % (className, describeFunction.describe(method)) + print " implementation: %s.%s" % (className, describeFunction.describe(method2)) + break + + + +def checkInterface(moduleName): + if describeFunction is None: + return + items = sys.modules[moduleName].__dict__.items() + items.sort() + for name, value in items: + if not isinstance(value, types.ClassType): + continue + checkClass(moduleName, value) +