SF bug [#467336] doctest failures w/ new-style classes.
Taught doctest about static methods, class methods, and property docstrings
in new-style classes.  As for inspect.py/pydoc.py before it, the new stuff
needed didn't really fit into the old architecture (but was less of a
strain to force-fit here).
New-style class docstrings still aren't found, but that's the subject
of a different bug and I want to fix that right instead of hacking around
it in doctest.
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 184699a..91c51cb 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -258,7 +258,7 @@
    8 tests in doctest
    6 tests in doctest.Tester
   10 tests in doctest.Tester.merge
-   7 tests in doctest.Tester.rundict
+  14 tests in doctest.Tester.rundict
    3 tests in doctest.Tester.rundoc
    3 tests in doctest.Tester.runstring
    2 tests in doctest.__test__._TestClass
@@ -267,8 +267,8 @@
    1 tests in doctest.__test__._TestClass.square
    2 tests in doctest.__test__.string
    7 tests in doctest.is_private
-53 tests in 17 items.
-53 passed and 0 failed.
+60 tests in 17 items.
+60 passed and 0 failed.
 Test passed.
 """
 
@@ -295,6 +295,7 @@
 from inspect import isclass    as _isclass
 from inspect import isfunction as _isfunction
 from inspect import ismodule   as _ismodule
+from inspect import classify_class_attrs as _classify_class_attrs
 
 # Extract interactive examples from a string.  Return a list of triples,
 # (source, outcome, lineno).  "source" is the source code, and ends
@@ -747,9 +748,51 @@
             print f, "of", t, "examples failed in", name + ".__doc__"
         self.__record_outcome(name, f, t)
         if _isclass(object):
-            f2, t2 = self.rundict(object.__dict__, name)
-            f = f + f2
-            t = t + t2
+            # In 2.2, class and static methods complicate life.  Build
+            # a dict "that works", by hook or by crook.
+            d = {}
+            for tag, kind, homecls, value in _classify_class_attrs(object):
+
+                if homecls is not object:
+                    # Only look at names defined immediately by the class.
+                    continue
+
+                elif self.isprivate(name, tag):
+                    continue
+
+                elif kind == "method":
+                    # value is already a function
+                    d[tag] = value
+
+                elif kind == "static method":
+                    # value isn't a function, but getattr reveals one
+                    d[tag] = getattr(object, tag)
+
+                elif kind == "class method":
+                    # Hmm.  A classmethod object doesn't seem to reveal
+                    # enough.  But getattr turns it into a bound method,
+                    # and from there .im_func retrieves the underlying
+                    # function.
+                    d[tag] = getattr(object, tag).im_func
+
+                elif kind == "property":
+                    # The methods implementing the property have their
+                    # own docstrings -- but the property may have one too.
+                    if value.__doc__ is not None:
+                        d[tag] = str(value.__doc__)
+
+                elif kind == "data":
+                    # Grab nested classes.
+                    if _isclass(value):
+                        d[tag] = value
+
+                else:
+                    raise ValueError("teach doctest about %r" % kind)
+
+            f2, t2 = self.run__test__(d, name)
+            f += f2
+            t += t2
+
         return f, t
 
     def rundict(self, d, name, module=None):
diff --git a/Lib/test/test_doctest2.py b/Lib/test/test_doctest2.py
new file mode 100644
index 0000000..0cbe3d4
--- /dev/null
+++ b/Lib/test/test_doctest2.py
@@ -0,0 +1,112 @@
+"""A module to test whether doctest recognizes some 2.2 features,
+like static and class methods.
+
+>>> print 'yup'  # 1
+yup
+"""
+
+import test_support
+
+# XXX The class docstring is skipped.
+class C(object):
+    """Class C.
+
+    >>> print C()  # 2
+    42
+    """
+
+    def __init__(self):
+        """C.__init__.
+
+        >>> print C() # 3
+        42
+        """
+
+    def __str__(self):
+        """
+        >>> print C() # 4
+        42
+        """
+        return "42"
+
+    # XXX The class docstring is skipped.
+    class D(object):
+        """A nested D class.
+
+        >>> print "In D!"   # 5
+        In D!
+        """
+
+        def nested(self):
+            """
+            >>> print 3 # 6
+            3
+            """
+
+    def getx(self):
+        """
+        >>> c = C()    # 7
+        >>> c.x = 12   # 8
+        >>> print c.x  # 9
+        -12
+        """
+        return -self._x
+
+    def setx(self, value):
+        """
+        >>> c = C()     # 10
+        >>> c.x = 12    # 11
+        >>> print c.x   # 12
+        -12
+        """
+        self._x = value
+
+    x = property(getx, setx, doc="""\
+        >>> c = C()    # 13
+        >>> c.x = 12   # 14
+        >>> print c.x  # 15
+        -12
+        """)
+
+    def statm():
+        """
+        A static method.
+
+        >>> print C.statm()    # 16
+        666
+        >>> print C().statm()  # 17
+        666
+        """
+        return 666
+
+    statm = staticmethod(statm)
+
+    def clsm(cls, val):
+        """
+        A class method.
+
+        >>> print C.clsm(22)    # 18
+        22
+        >>> print C().clsm(22)  # 19
+        22
+        """
+        return 22
+
+    clsm = classmethod(clsm)
+
+def test_main():
+    import test_doctest2
+    # XXX 2 class docstrings are skipped.
+    # EXPECTED = 19
+    EXPECTED = 17
+    f, t = test_support.run_doctest(test_doctest2)
+    if t != EXPECTED:
+        raise test_support.TestFailed("expected %d tests to run, not %d" %
+                                      (EXPECTED, t))
+
+# Pollute the namespace with a bunch of imported functions and classes,
+# to make sure they don't get tested.
+from doctest import *
+
+if __name__ == '__main__':
+    test_main()
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index fdb3ddf..1a241cf 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -101,7 +101,10 @@
     def test_easy(self):
         self.checkModule('pyclbr')
         self.checkModule('doctest',
-                         ignore=['_isclass', '_isfunction', '_ismodule'])
+                         ignore=['_isclass',
+                                 '_isfunction',
+                                 '_ismodule',
+                                 '_classify_class_attrs'])
         self.checkModule('rfc822')
         self.checkModule('xmllib')
         self.checkModule('difflib')
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 04a778b..e1923a6 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -176,7 +176,7 @@
 # doctest driver.
 
 def run_doctest(module, verbosity=None):
-    """Run doctest on the given module.
+    """Run doctest on the given module.  Return (#failures, #tests).
 
     If optional argument verbosity is not specified (or is None), pass
     test_support's belief about verbosity on to doctest.  Else doctest's
@@ -198,5 +198,6 @@
         f, t = doctest.testmod(module, verbose=verbosity)
         if f:
             raise TestFailed("%d of %d doctests failed" % (f, t))
+        return f, t
     finally:
         sys.stdout = save_stdout