]> granicus.if.org Git - python/commitdiff
SF bug [#467331] ClassType.__doc__ always None.
authorTim Peters <tim.peters@gmail.com>
Thu, 4 Oct 2001 05:27:00 +0000 (05:27 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 4 Oct 2001 05:27:00 +0000 (05:27 +0000)
For a dynamically constructed type object, fill in the tp_doc slot with
a copy of the argument dict's "__doc__" value, provided the latter exists
and is a string.
NOTE:  I don't know what to do if it's a Unicode string, so in that case
tp_doc is left NULL (which shows up as Py_None if you do Class.__doc__).
Note that tp_doc holds a char*, not a general PyObject*.

Lib/test/test_descr.py
Lib/test/test_doctest2.py
Objects/typeobject.c

index 4ed6853e19f0a34aa0f9ef03394b174e471e95ad..cd65c2c963fc1a3bdaf216e3b3f2b552ce5861fd 100644 (file)
@@ -88,6 +88,38 @@ def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
     bm(b, c, d)
     verify(dict['a'] == res)
 
+def class_docstrings():
+    class Classic:
+        "A classic docstring."
+    verify(Classic.__doc__ == "A classic docstring.")
+    verify(Classic.__dict__['__doc__'] == "A classic docstring.")
+
+    class Classic2:
+        pass
+    verify(Classic2.__doc__ is None)
+
+    class NewStatic:
+        "Another docstring."
+        __dynamic__ = 0
+    verify(NewStatic.__doc__ == "Another docstring.")
+    verify(NewStatic.__dict__['__doc__'] == "Another docstring.")
+
+    class NewStatic2:
+        __dynamic__ = 0
+        pass
+    verify(NewStatic2.__doc__ is None)
+
+    class NewDynamic:
+        "Another docstring."
+        __dynamic__ = 1
+    verify(NewDynamic.__doc__ == "Another docstring.")
+    verify(NewDynamic.__dict__['__doc__'] == "Another docstring.")
+
+    class NewDynamic2:
+        __dynamic__ = 1
+        pass
+    verify(NewDynamic2.__doc__ is None)
+
 def lists():
     if verbose: print "Testing list operations..."
     testbinop([1], [2], [1,2], "a+b", "__add__")
@@ -2168,7 +2200,7 @@ def binopoverride():
                 return I(pow(int(other), int(self), mod))
             else:
                 return I(pow(int(other), int(self), int(mod)))
-            
+
     vereq(`I(1) + I(2)`, "I(3)")
     vereq(`I(1) + 2`, "I(3)")
     vereq(`1 + I(2)`, "I(3)")
@@ -2182,6 +2214,7 @@ def binopoverride():
 
 
 def test_main():
+    class_docstrings()
     lists()
     dicts()
     dict_constructor()
index 9a0e57c9c4b8b9eaef78b3ecc458d471ab16db2b..00b6cc44828c0bd32edd230705581565765a3fb2 100644 (file)
@@ -7,7 +7,6 @@ yup
 
 import test_support
 
-# XXX The class docstring is skipped.
 class C(object):
     """Class C.
 
@@ -29,7 +28,6 @@ class C(object):
         """
         return "42"
 
-    # XXX The class docstring is skipped.
     class D(object):
         """A nested D class.
 
@@ -96,9 +94,7 @@ class C(object):
 
 def test_main():
     import test_doctest2
-    # XXX 2 class docstrings are skipped.
-    # EXPECTED = 19
-    EXPECTED = 17
+    EXPECTED = 19
     f, t = test_support.run_doctest(test_doctest2)
     if t != EXPECTED:
         raise test_support.TestFailed("expected %d tests to run, not %d" %
index c50b4465faabc1510e449514efaea1f834001406..e8f436c770fd80fd0783abb81d1f3bf2a19c13d7 100644 (file)
@@ -900,6 +900,24 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
                }
        }
 
+       /* Set tp_doc to a copy of dict['__doc__'], if the latter is there
+          and is a string (tp_doc is a char* -- can't copy a general object
+          into it).
+          XXX What if it's a Unicode string?  Don't know -- this ignores it.
+       */
+       {
+               PyObject *doc = PyDict_GetItemString(dict, "__doc__");
+               if (doc != NULL && PyString_Check(doc)) {
+                       const size_t n = (size_t)PyString_GET_SIZE(doc);
+                       type->tp_doc = PyObject_MALLOC(n+1);
+                       if (type->tp_doc == NULL) {
+                               Py_DECREF(type);
+                               return NULL;
+                       }
+                       memcpy(type->tp_doc, PyString_AS_STRING(doc), n+1);
+               }
+       }
+
        /* Special-case __new__: if it's a plain function,
           make it a static function */
        tmp = PyDict_GetItemString(dict, "__new__");
@@ -1162,6 +1180,11 @@ type_clear(PyTypeObject *type)
        CLEAR(type->tp_base);
        CLEAR(et->slots);
 
+       if (type->tp_doc != NULL) {
+               PyObject_FREE(type->tp_doc);
+               type->tp_doc = NULL;
+       }
+
 #undef CLEAR
 
        return 0;
@@ -1350,7 +1373,7 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
                PyErr_Format(PyExc_TypeError,
                             "__class__ assignment: "
                             "'%s' object layout differs from '%s'",
-                            new->tp_name, 
+                            new->tp_name,
                             old->tp_name);
                return -1;
        }