mirror of https://github.com/python/cpython.git
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*.
This commit is contained in:
parent
f137f75ab8
commit
2f93e28a19
|
@ -88,6 +88,38 @@ def testset3op(a, b, c, d, res, stmt="a[b:c]=d", meth="__setslice__"):
|
||||||
bm(b, c, d)
|
bm(b, c, d)
|
||||||
verify(dict['a'] == res)
|
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():
|
def lists():
|
||||||
if verbose: print "Testing list operations..."
|
if verbose: print "Testing list operations..."
|
||||||
testbinop([1], [2], [1,2], "a+b", "__add__")
|
testbinop([1], [2], [1,2], "a+b", "__add__")
|
||||||
|
@ -2168,7 +2200,7 @@ def __rpow__(self, other, mod=None):
|
||||||
return I(pow(int(other), int(self), mod))
|
return I(pow(int(other), int(self), mod))
|
||||||
else:
|
else:
|
||||||
return I(pow(int(other), int(self), int(mod)))
|
return I(pow(int(other), int(self), int(mod)))
|
||||||
|
|
||||||
vereq(`I(1) + I(2)`, "I(3)")
|
vereq(`I(1) + I(2)`, "I(3)")
|
||||||
vereq(`I(1) + 2`, "I(3)")
|
vereq(`I(1) + 2`, "I(3)")
|
||||||
vereq(`1 + I(2)`, "I(3)")
|
vereq(`1 + I(2)`, "I(3)")
|
||||||
|
@ -2182,6 +2214,7 @@ def __eq__(self, other):
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
|
class_docstrings()
|
||||||
lists()
|
lists()
|
||||||
dicts()
|
dicts()
|
||||||
dict_constructor()
|
dict_constructor()
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
import test_support
|
import test_support
|
||||||
|
|
||||||
# XXX The class docstring is skipped.
|
|
||||||
class C(object):
|
class C(object):
|
||||||
"""Class C.
|
"""Class C.
|
||||||
|
|
||||||
|
@ -29,7 +28,6 @@ def __str__(self):
|
||||||
"""
|
"""
|
||||||
return "42"
|
return "42"
|
||||||
|
|
||||||
# XXX The class docstring is skipped.
|
|
||||||
class D(object):
|
class D(object):
|
||||||
"""A nested D class.
|
"""A nested D class.
|
||||||
|
|
||||||
|
@ -96,9 +94,7 @@ def clsm(cls, val):
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
import test_doctest2
|
import test_doctest2
|
||||||
# XXX 2 class docstrings are skipped.
|
EXPECTED = 19
|
||||||
# EXPECTED = 19
|
|
||||||
EXPECTED = 17
|
|
||||||
f, t = test_support.run_doctest(test_doctest2)
|
f, t = test_support.run_doctest(test_doctest2)
|
||||||
if t != EXPECTED:
|
if t != EXPECTED:
|
||||||
raise test_support.TestFailed("expected %d tests to run, not %d" %
|
raise test_support.TestFailed("expected %d tests to run, not %d" %
|
||||||
|
|
|
@ -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,
|
/* Special-case __new__: if it's a plain function,
|
||||||
make it a static function */
|
make it a static function */
|
||||||
tmp = PyDict_GetItemString(dict, "__new__");
|
tmp = PyDict_GetItemString(dict, "__new__");
|
||||||
|
@ -1162,6 +1180,11 @@ type_clear(PyTypeObject *type)
|
||||||
CLEAR(type->tp_base);
|
CLEAR(type->tp_base);
|
||||||
CLEAR(et->slots);
|
CLEAR(et->slots);
|
||||||
|
|
||||||
|
if (type->tp_doc != NULL) {
|
||||||
|
PyObject_FREE(type->tp_doc);
|
||||||
|
type->tp_doc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#undef CLEAR
|
#undef CLEAR
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1350,7 +1373,7 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"__class__ assignment: "
|
"__class__ assignment: "
|
||||||
"'%s' object layout differs from '%s'",
|
"'%s' object layout differs from '%s'",
|
||||||
new->tp_name,
|
new->tp_name,
|
||||||
old->tp_name);
|
old->tp_name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue