Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2f93e28

Browse files
committed
SF bug [#467331] ClassType.__doc__ always None.
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*.
1 parent f137f75 commit 2f93e28

3 files changed

Lines changed: 59 additions & 7 deletions

File tree

Lib/test/test_descr.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,38 @@ def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
8888
bm(b, c, d)
8989
verify(dict['a'] == res)
9090

91+
def class_docstrings():
92+
class Classic:
93+
"A classic docstring."
94+
verify(Classic.__doc__ == "A classic docstring.")
95+
verify(Classic.__dict__['__doc__'] == "A classic docstring.")
96+
97+
class Classic2:
98+
pass
99+
verify(Classic2.__doc__ is None)
100+
101+
class NewStatic:
102+
"Another docstring."
103+
__dynamic__ = 0
104+
verify(NewStatic.__doc__ == "Another docstring.")
105+
verify(NewStatic.__dict__['__doc__'] == "Another docstring.")
106+
107+
class NewStatic2:
108+
__dynamic__ = 0
109+
pass
110+
verify(NewStatic2.__doc__ is None)
111+
112+
class NewDynamic:
113+
"Another docstring."
114+
__dynamic__ = 1
115+
verify(NewDynamic.__doc__ == "Another docstring.")
116+
verify(NewDynamic.__dict__['__doc__'] == "Another docstring.")
117+
118+
class NewDynamic2:
119+
__dynamic__ = 1
120+
pass
121+
verify(NewDynamic2.__doc__ is None)
122+
91123
def lists():
92124
if verbose: print "Testing list operations..."
93125
testbinop([1], [2], [1,2], "a+b", "__add__")
@@ -2168,7 +2200,7 @@ def __rpow__(self, other, mod=None):
21682200
return I(pow(int(other), int(self), mod))
21692201
else:
21702202
return I(pow(int(other), int(self), int(mod)))
2171-
2203+
21722204
vereq(`I(1) + I(2)`, "I(3)")
21732205
vereq(`I(1) + 2`, "I(3)")
21742206
vereq(`1 + I(2)`, "I(3)")
@@ -2182,6 +2214,7 @@ def __eq__(self, other):
21822214

21832215

21842216
def test_main():
2217+
class_docstrings()
21852218
lists()
21862219
dicts()
21872220
dict_constructor()

Lib/test/test_doctest2.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import test_support
99

10-
# XXX The class docstring is skipped.
1110
class C(object):
1211
"""Class C.
1312
@@ -29,7 +28,6 @@ def __str__(self):
2928
"""
3029
return "42"
3130

32-
# XXX The class docstring is skipped.
3331
class D(object):
3432
"""A nested D class.
3533
@@ -96,9 +94,7 @@ def clsm(cls, val):
9694

9795
def test_main():
9896
import test_doctest2
99-
# XXX 2 class docstrings are skipped.
100-
# EXPECTED = 19
101-
EXPECTED = 17
97+
EXPECTED = 19
10298
f, t = test_support.run_doctest(test_doctest2)
10399
if t != EXPECTED:
104100
raise test_support.TestFailed("expected %d tests to run, not %d" %

Objects/typeobject.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,24 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
900900
}
901901
}
902902

903+
/* Set tp_doc to a copy of dict['__doc__'], if the latter is there
904+
and is a string (tp_doc is a char* -- can't copy a general object
905+
into it).
906+
XXX What if it's a Unicode string? Don't know -- this ignores it.
907+
*/
908+
{
909+
PyObject *doc = PyDict_GetItemString(dict, "__doc__");
910+
if (doc != NULL && PyString_Check(doc)) {
911+
const size_t n = (size_t)PyString_GET_SIZE(doc);
912+
type->tp_doc = PyObject_MALLOC(n+1);
913+
if (type->tp_doc == NULL) {
914+
Py_DECREF(type);
915+
return NULL;
916+
}
917+
memcpy(type->tp_doc, PyString_AS_STRING(doc), n+1);
918+
}
919+
}
920+
903921
/* Special-case __new__: if it's a plain function,
904922
make it a static function */
905923
tmp = PyDict_GetItemString(dict, "__new__");
@@ -1162,6 +1180,11 @@ type_clear(PyTypeObject *type)
11621180
CLEAR(type->tp_base);
11631181
CLEAR(et->slots);
11641182

1183+
if (type->tp_doc != NULL) {
1184+
PyObject_FREE(type->tp_doc);
1185+
type->tp_doc = NULL;
1186+
}
1187+
11651188
#undef CLEAR
11661189

11671190
return 0;
@@ -1350,7 +1373,7 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
13501373
PyErr_Format(PyExc_TypeError,
13511374
"__class__ assignment: "
13521375
"'%s' object layout differs from '%s'",
1353-
new->tp_name,
1376+
new->tp_name,
13541377
old->tp_name);
13551378
return -1;
13561379
}

0 commit comments

Comments
 (0)