changeset: 95620:e75fd221a53e user: Zachary Ware date: Mon Apr 13 18:22:35 2015 -0500 files: Lib/test/test_capi.py Lib/test/test_inspect.py Misc/NEWS Modules/_testcapimodule.c Modules/cjkcodecs/clinic/multibytecodec.c.h Modules/clinic/pyexpat.c.h Objects/typeobject.c Tools/clinic/clinic.py description: Issue #20586: Argument Clinic now ensures signatures on functions without docstrings. diff -r 03ff92b26fa9 -r e75fd221a53e Lib/test/test_capi.py --- a/Lib/test/test_capi.py Mon Apr 13 17:48:40 2015 -0400 +++ b/Lib/test/test_capi.py Mon Apr 13 18:22:35 2015 -0500 @@ -123,7 +123,7 @@ self.assertEqual(_testcapi.no_docstring.__doc__, None) self.assertEqual(_testcapi.no_docstring.__text_signature__, None) - self.assertEqual(_testcapi.docstring_empty.__doc__, "") + self.assertEqual(_testcapi.docstring_empty.__doc__, None) self.assertEqual(_testcapi.docstring_empty.__text_signature__, None) self.assertEqual(_testcapi.docstring_no_signature.__doc__, @@ -150,6 +150,10 @@ "This docstring has a valid signature.") self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "($module, /, sig)") + self.assertEqual(_testcapi.docstring_with_signature_but_no_doc.__doc__, None) + self.assertEqual(_testcapi.docstring_with_signature_but_no_doc.__text_signature__, + "($module, /, sig)") + self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__doc__, "\nThis docstring has a valid signature and some extra newlines.") self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__, diff -r 03ff92b26fa9 -r e75fd221a53e Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Mon Apr 13 17:48:40 2015 -0400 +++ b/Lib/test/test_inspect.py Mon Apr 13 18:22:35 2015 -0500 @@ -1864,6 +1864,9 @@ test_unbound_method(dict.__delitem__) test_unbound_method(property.__delete__) + # Regression test for issue #20586 + test_callable(_testcapi.docstring_with_signature_but_no_doc) + @cpython_only @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") diff -r 03ff92b26fa9 -r e75fd221a53e Misc/NEWS --- a/Misc/NEWS Mon Apr 13 17:48:40 2015 -0400 +++ b/Misc/NEWS Mon Apr 13 18:22:35 2015 -0500 @@ -156,6 +156,9 @@ Tools/Demos ----------- +- Issue #20586: Argument Clinic now ensures that functions without docstrings + have signatures. + - Issue #23492: Argument Clinic now generates argument parsing code with PyArg_Parse instead of PyArg_ParseTuple if possible. diff -r 03ff92b26fa9 -r e75fd221a53e Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Mon Apr 13 17:48:40 2015 -0400 +++ b/Modules/_testcapimodule.c Mon Apr 13 18:22:35 2015 -0500 @@ -3083,6 +3083,12 @@ "This docstring has a valid signature." ); +PyDoc_STRVAR(docstring_with_signature_but_no_doc, +"docstring_with_signature_but_no_doc($module, /, sig)\n" +"--\n" +"\n" +); + PyDoc_STRVAR(docstring_with_signature_and_extra_newlines, "docstring_with_signature_and_extra_newlines($module, /, parameter)\n" "--\n" @@ -3635,6 +3641,9 @@ {"docstring_with_signature", (PyCFunction)test_with_docstring, METH_NOARGS, docstring_with_signature}, + {"docstring_with_signature_but_no_doc", + (PyCFunction)test_with_docstring, METH_NOARGS, + docstring_with_signature_but_no_doc}, {"docstring_with_signature_and_extra_newlines", (PyCFunction)test_with_docstring, METH_NOARGS, docstring_with_signature_and_extra_newlines}, diff -r 03ff92b26fa9 -r e75fd221a53e Modules/cjkcodecs/clinic/multibytecodec.c.h --- a/Modules/cjkcodecs/clinic/multibytecodec.c.h Mon Apr 13 17:48:40 2015 -0400 +++ b/Modules/cjkcodecs/clinic/multibytecodec.c.h Mon Apr 13 18:22:35 2015 -0500 @@ -78,7 +78,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalEncoder_encode__doc__, "encode($self, /, input, final=0)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTEINCREMENTALENCODER_ENCODE_METHODDEF \ {"encode", (PyCFunction)_multibytecodec_MultibyteIncrementalEncoder_encode, METH_VARARGS|METH_KEYWORDS, _multibytecodec_MultibyteIncrementalEncoder_encode__doc__}, @@ -106,7 +107,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalEncoder_reset__doc__, "reset($self, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTEINCREMENTALENCODER_RESET_METHODDEF \ {"reset", (PyCFunction)_multibytecodec_MultibyteIncrementalEncoder_reset, METH_NOARGS, _multibytecodec_MultibyteIncrementalEncoder_reset__doc__}, @@ -122,7 +124,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_decode__doc__, "decode($self, /, input, final=0)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTEINCREMENTALDECODER_DECODE_METHODDEF \ {"decode", (PyCFunction)_multibytecodec_MultibyteIncrementalDecoder_decode, METH_VARARGS|METH_KEYWORDS, _multibytecodec_MultibyteIncrementalDecoder_decode__doc__}, @@ -154,7 +157,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteIncrementalDecoder_reset__doc__, "reset($self, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTEINCREMENTALDECODER_RESET_METHODDEF \ {"reset", (PyCFunction)_multibytecodec_MultibyteIncrementalDecoder_reset, METH_NOARGS, _multibytecodec_MultibyteIncrementalDecoder_reset__doc__}, @@ -170,7 +174,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_read__doc__, "read($self, sizeobj=None, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMREADER_READ_METHODDEF \ {"read", (PyCFunction)_multibytecodec_MultibyteStreamReader_read, METH_VARARGS, _multibytecodec_MultibyteStreamReader_read__doc__}, @@ -196,7 +201,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_readline__doc__, "readline($self, sizeobj=None, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMREADER_READLINE_METHODDEF \ {"readline", (PyCFunction)_multibytecodec_MultibyteStreamReader_readline, METH_VARARGS, _multibytecodec_MultibyteStreamReader_readline__doc__}, @@ -222,7 +228,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_readlines__doc__, "readlines($self, sizehintobj=None, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMREADER_READLINES_METHODDEF \ {"readlines", (PyCFunction)_multibytecodec_MultibyteStreamReader_readlines, METH_VARARGS, _multibytecodec_MultibyteStreamReader_readlines__doc__}, @@ -248,7 +255,8 @@ PyDoc_STRVAR(_multibytecodec_MultibyteStreamReader_reset__doc__, "reset($self, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMREADER_RESET_METHODDEF \ {"reset", (PyCFunction)_multibytecodec_MultibyteStreamReader_reset, METH_NOARGS, _multibytecodec_MultibyteStreamReader_reset__doc__}, @@ -264,21 +272,24 @@ PyDoc_STRVAR(_multibytecodec_MultibyteStreamWriter_write__doc__, "write($self, strobj, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMWRITER_WRITE_METHODDEF \ {"write", (PyCFunction)_multibytecodec_MultibyteStreamWriter_write, METH_O, _multibytecodec_MultibyteStreamWriter_write__doc__}, PyDoc_STRVAR(_multibytecodec_MultibyteStreamWriter_writelines__doc__, "writelines($self, lines, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMWRITER_WRITELINES_METHODDEF \ {"writelines", (PyCFunction)_multibytecodec_MultibyteStreamWriter_writelines, METH_O, _multibytecodec_MultibyteStreamWriter_writelines__doc__}, PyDoc_STRVAR(_multibytecodec_MultibyteStreamWriter_reset__doc__, "reset($self, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC_MULTIBYTESTREAMWRITER_RESET_METHODDEF \ {"reset", (PyCFunction)_multibytecodec_MultibyteStreamWriter_reset, METH_NOARGS, _multibytecodec_MultibyteStreamWriter_reset__doc__}, @@ -294,8 +305,9 @@ PyDoc_STRVAR(_multibytecodec___create_codec__doc__, "__create_codec($module, arg, /)\n" -"--"); +"--\n" +"\n"); #define _MULTIBYTECODEC___CREATE_CODEC_METHODDEF \ {"__create_codec", (PyCFunction)_multibytecodec___create_codec, METH_O, _multibytecodec___create_codec__doc__}, -/*[clinic end generated code: output=dff1459dec464796 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0ea29cd57f7cbc1a input=a9049054013a1b77]*/ diff -r 03ff92b26fa9 -r e75fd221a53e Modules/clinic/pyexpat.c.h --- a/Modules/clinic/pyexpat.c.h Mon Apr 13 17:48:40 2015 -0400 +++ b/Modules/clinic/pyexpat.c.h Mon Apr 13 18:22:35 2015 -0500 @@ -209,7 +209,8 @@ PyDoc_STRVAR(pyexpat_xmlparser___dir____doc__, "__dir__($self, /)\n" -"--"); +"--\n" +"\n"); #define PYEXPAT_XMLPARSER___DIR___METHODDEF \ {"__dir__", (PyCFunction)pyexpat_xmlparser___dir__, METH_NOARGS, pyexpat_xmlparser___dir____doc__}, @@ -286,4 +287,4 @@ #ifndef PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF #define PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF #endif /* !defined(PYEXPAT_XMLPARSER_USEFOREIGNDTD_METHODDEF) */ -/*[clinic end generated code: output=9715b916f2d618fa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e5993de4e9dd2236 input=a9049054013a1b77]*/ diff -r 03ff92b26fa9 -r e75fd221a53e Objects/typeobject.c --- a/Objects/typeobject.c Mon Apr 13 17:48:40 2015 -0400 +++ b/Objects/typeobject.c Mon Apr 13 18:22:35 2015 -0500 @@ -137,7 +137,7 @@ { const char *doc = _PyType_DocWithoutSignature(name, internal_doc); - if (!doc) { + if (!doc || *doc == '\0') { Py_INCREF(Py_None); return Py_None; } diff -r 03ff92b26fa9 -r e75fd221a53e Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py Mon Apr 13 17:48:40 2015 -0400 +++ b/Tools/clinic/clinic.py Mon Apr 13 18:22:35 2015 -0500 @@ -66,6 +66,8 @@ unknown = Unknown() +sig_end_marker = '--' + _text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output") @@ -559,8 +561,13 @@ add(quoted_for_c_string(line)) add('\\n"\n') - text.pop() - add('"') + if text[-2] == sig_end_marker: + # If we only have a signature, add the blank line that the + # __text_signature__ getter expects to be there. + add('"\\n"') + else: + text.pop() + add('"') return ''.join(text) def output_templates(self, f): @@ -4015,7 +4022,7 @@ # add(f.return_converter.py_default) if not f.docstring_only: - add("\n--\n") + add("\n" + sig_end_marker + "\n") docstring_first_line = output()