text: """Introspective functions for Python objects"""
  
  def docstrings():
    if py_version < '1.5.2': return
    """
    containers.__doc__   = "A tuple of built-in types that contain parts"
    simpletypes.__doc__  = "A tuple of built-in types that have no parts"
    datatypes.__doc__    = "A tuple of all the built-in types that hold data"
    immutabletypes.__doc__="A tuple of built-in types that are immutable"
    """
    isContainer.__doc__  = "this and that"
  
  import sys, string
  # this is used throughout Gnosis to enable
  # version-specific features/hacks
  py_version = string.split(sys.version)[0]
  
  from types import *
  from operator import add
  from gnosis.util.combinators import or_, not_, and_, lazy_any
  
  containers = (ListType, TupleType, DictType)
  simpletypes = (IntType, LongType, FloatType, ComplexType, StringType)
  if py_version >= '2.0':
      simpletypes = simpletypes + (UnicodeType,)
  datatypes = simpletypes+containers
  immutabletypes = simpletypes+(TupleType,)
  
  class undef: pass
  
  def isinstance_any(o, types):
      "A varargs form of isinstance()"
      for t in types:
          if isinstance(o, t): return t
  
  isContainer  = lambda o: isinstance_any(o, containers)
  isSimpleType = lambda o: isinstance_any(o, simpletypes)
  isInstance   = lambda o: type(o) is InstanceType
  isImmutable  = lambda o: isinstance_any(o, immutabletypes)
  
  if py_version >= '2.2':
      isNewStyleInstance = lambda o: issubclass(o.__class__,object) and \
                                  not type(o) in datatypes
  else:
      isNewStyleInstance = lambda o: 0
  isOldStyleInstance = lambda o: isinstance(o, ClassType)
  isClass         = or_(isOldStyleInstance, isNewStyleInstance)
  
  def isNewStyleClass(o):
      try:
          return issubclass(o,object)
      except TypeError:
          return 0
  
  hasSlots     = lambda o: hasattr(o,'__slots__')
  hasInit      = lambda o: hasattr(o,'__init__')
  hasDictAttrs = lambda o: (hasattr(o,'__dict__') and o.__dict__)
  
  isInstanceLike = lazy_any(isInstance, hasDictAttrs, hasSlots)
  hasCompoundShape = and_(isInstanceLike, not_(isInstance))
  
  true_container = lambda o: type(o) in containers
  true_simpletype = lambda o: type(o) in simpletypes
  true_datatype = or_(true_container, true_simpletype)
  child_container = and_(not_(true_container), isContainer)
  child_simpletype = and_(not_(true_simpletype), isSimpleType)
  child_datatype = or_(child_container, child_simpletype)
  
  def hasCoreData(o):
      """Is 'o' an object subclassed from a builtin type?
  
      (i.e. does it contain data other than attributes)
      We only want subclasses, not the class itself (otherwise we'd
      catch ALL lists, integers, etc.)
      """
      return child_datatype(o)
  
  # semantic convenience - maybe it'll do something else later?
  wantsCoreData = hasCoreData
  
  def attr_dict(o, fillslots=0):
      if hasattr(o,'__dict__'):
          return o.__dict__
      elif hasattr(o,'__slots__'):
          dct = {}
          for attr in o.__slots__:
              if fillslots and not hasattr(o, attr):
                  setattr(o, attr, undef())
                  dct[attr] = getattr(o,attr)
              elif hasattr(o, attr):
                  dct[attr] = getattr(o,attr)
          return dct
      else:
          raise TypeError, "Object has neither __dict__ nor __slots__"
  
  attr_keys = lambda o: attr_dict(o).keys()
  attr_vals = lambda o: attr_dict(o).values()
  
  def attr_update(o,new):
      for k,v in new.items():
          setattr(o,k,v)
  
  def data2attr(o):
      "COPY (not move) data to __coredata__ 'magic' attribute"
      o.__coredata__ = getCoreData(o)
      return o
  
  def attr2data(o):
      "Move 'magic' attribute back to 'core' data"
      if hasattr(o,'__coredata__'):
          o = setCoreData(o, o.__coredata__)
          del o.__coredata__
      return o
  
  def setCoreData(o, data, force=0):
      "Set core data of obj subclassed from a builtin type, return obj"
      #-- Only newobjects unless force'd
      if not force and not wantsCoreData(o): pass
      #-- Tuple and simpletypes are immutable (need new copy)!
      elif isImmutable(o):
          # Python appears to guarantee that all classes subclassed
          # from immutables must take one and only one argument
          # to __init__ [calling __init__() is not usually allowed
          # when unpickling] ... lucky us :-)
          new = o.__class__(data)
          attr_update(new, attr_dict(o))  # __slots__ safe attr_dict()
          o = new
      elif isinstance(o, DictType):
          o.clear()
          o.update(data)
      elif isinstance(o, ListType):
          o[:] = data
      return o
  
  def getCoreData(o):
      "Return the core data of object subclassed from builtin type"
      if hasCoreData(o):
          return isinstance_any(o, datatypes)(o)
      else:
          raise TypeError, "Unhandled type in getCoreData for: ", o
  
  def instance_noinit(C):
      """Create an instance of class C without calling __init__
  
      [Note: This function was greatly simplified in gnosis-1.0.7,
      but I'll leave these notes here for future reference.]
  
      We go to some lengths here to avoid calling __init__.  It
      gets complicated because we cannot always do the same thing;
      it depends on whether there are __slots__, and even whether
      __init__ is defined in a class or in its parent.  Even still,
      there are ways to construct *highly artificial* cases where
      the wrong thing happens.
  
      If you change this, make sure ALL test cases still work ...
      easy to break things
      """
      if isOldStyleInstance(C):
          import new
          # 2nd arg is required for Python 2.0 (optional for 2.1+)
          return new.instance(C,{})
      elif isNewStyleInstance(C):
          return C.__new__(C)
      else:
          raise TypeError, "You must specify a class to create instance of."
  
  if __name__ == '__main__':
      "We could use some could self-tests (see test/ subdir though)"
  else:
      docstrings()
  
  