"""$URL: svn+ssh://svn/repos/trunk/grouch/lib/util.py $ $Id: util.py 24750 2004-07-21 15:26:51Z dbinger $ """ import sys import __builtin__ from types import TypeType, ClassType, InstanceType def is_class_object (klass): """Return true if 'klass' is a class object (either a regular Python class or an ExtensionClass). """ # The first clause handles regular classes quickly; the second # is needed to accomodate ExtensionClasses return type(klass) is ClassType or hasattr(klass, '__bases__') def is_instance_object (object): """Return true if 'object' is an instance of some class (either a regular Python class or an ExtensionClass). """ return ((type(object) is InstanceType or (hasattr(object, '__class__') and not hasattr(object, '__bases__'))) and hasattr(object, '__dict__')) def get_class_object (name): lastdot = name.rfind(".") if lastdot == -1: # no dots -- look in main module module_name = '__main__' klass_name = name module = sys.modules[module_name] else: module_name = name[:lastdot] klass_name = name[lastdot+1:] try: __import__(module_name) except ImportError, exc: raise ValueError, \ "error finding class %s: %s" % (name, exc) module = sys.modules[module_name] if not hasattr(module, klass_name): raise ValueError, \ "no such class %s in module %s" % (`klass_name`, module_name) else: klass = getattr(module, klass_name) if is_class_object(klass): return klass else: raise ValueError, \ "%s in module %s: not a class" % (`klass_name`, module_name) def get_full_classname (klass): classname = klass.__name__ modname = klass.__module__ if modname == "__main__": return classname else: return "%s.%s" % (modname, classname) # Supposedly, these two won't be necessary with Python 2.1, since its # 'issubclass()' and 'isinstance()' will finally be able to deal with # extension classes completely in 2.1. (It's close in 1.6 and 2.0, but not # quite there yet.) I have not yet verified this! def issubclass (class1, class2): """A version of 'issubclass()' that works with extension classes as well as regular Python classes. """ # Both class objects are regular Python classes, so use the # built-in 'issubclass()'. if type(class1) is ClassType and type(class2) is ClassType: return __builtin__.issubclass(class1, class2) # Both so-called class objects have a '__bases__' attribute: ie., # they aren't regular Python classes, but they sure look like them. # Assume they are extension classes and reimplement what the builtin # 'issubclass()' does behind the scenes. elif hasattr(class1, '__bases__') and hasattr(class2, '__bases__'): # XXX it appears that "ec.__class__ is type(ec)" for an # extension class 'ec': could we/should we use this as an # additional check for extension classes? # Breadth-first traversal of class1's superclass tree. Order # doesn't matter because we're just looking for a "yes/no" # answer from the tree; if we were trying to resolve a name, # order would be important! stack = [class1] while stack: if stack[0] is class2: return 1 stack.extend(list(stack[0].__bases__)) del stack[0] else: return 0 # Not a regular class, not an extension class: blow up for consistency # with builtin 'issubclass()" else: raise TypeError, "arguments must be class or ExtensionClass objects" # issubclass () def isinstance (object, klass): """A version of 'isinstance()' that works with extension classes as well as regular Python classes.""" if type(klass) is TypeType: return __builtin__.isinstance(object, klass) elif hasattr(object, '__class__'): return issubclass(object.__class__, klass) else: return 0 import types # This is the list of types always defined in Python 2.0's types.py. # Some types (complex, unicode) are optional at build-time; others were # added in Python 2.2. Those are handled separately so Grouch will work # with the lowest-common-denominator Python 2.0. _type_name = { # everyday types types.DictType : 'dict', types.FileType : 'file', types.FloatType : 'float', types.IntType : 'int', types.ListType : 'list', types.LongType : 'long', types.NoneType : 'none', types.StringType : 'string', types.TupleType : 'tuple', # callable things types.BuiltinFunctionType : 'builtin function', types.FunctionType : 'function', types.MethodType : 'instance method', # not-quite-everyday types types.ClassType : 'class', types.InstanceType : 'instance', types.ModuleType : 'module', types.TypeType : 'type', # esoterica types.CodeType : 'code', types.FrameType : 'frame', types.TracebackType : 'traceback', types.BufferType : 'buffer', types.EllipsisType : 'ellipsis', types.SliceType : 'slice', types.XRangeType : 'xrange', } # These are optional in Python 2.0, or were added in 2.2. for (name, typename) in [("ComplexType", "complex"), ("UnicodeType", "unicode"), ("DictProxyType", "dict-proxy"), ("GeneratorType", "generator"), ("ObjectType", "object")]: if hasattr(types, name): _type_name[getattr(types, name)] = typename def get_type_name (type): global _type_name return _type_name.get(type, type.__name__)