From 1f885df2a580360c5de69cc41191f3c6bfaaeb35 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 14 Sep 2023 09:12:17 +0300 Subject: gh-107782: Use _testcapi to test non-representable signatures (GH-109325) Builtin functions and methods that have non-representable signatures today will have representable signatures yesterday, and they will become unusable for testing this feature. So we need to add special functions and methods to the _testcapi module that always have non-representable signatures. --- Lib/test/test_pydoc.py | 39 ++++++++++++++++++++++++++++++-- Modules/_testcapi/docstring.c | 44 ++++++++++++++++++++++++++++++++++++ Tools/c-analyzer/cpython/ignored.tsv | 1 + 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 499eeb9..70c5ebd 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -24,6 +24,7 @@ import textwrap from io import StringIO from collections import namedtuple from urllib.request import urlopen, urlcleanup +from test import support from test.support import import_helper from test.support import os_helper from test.support.script_helper import (assert_python_ok, @@ -1236,22 +1237,56 @@ class TestDescriptions(unittest.TestCase): self.assertEqual(self._get_summary_line(dict.__class_getitem__), "__class_getitem__(object, /) method of builtins.type instance") + @support.cpython_only def test_module_level_callable_unrepresentable_default(self): - self.assertEqual(self._get_summary_line(getattr), - "getattr(...)") + import _testcapi + builtin = _testcapi.func_with_unrepresentable_signature + self.assertEqual(self._get_summary_line(builtin), + "func_with_unrepresentable_signature(a, b=)") + @support.cpython_only def test_builtin_staticmethod_unrepresentable_default(self): self.assertEqual(self._get_summary_line(str.maketrans), "maketrans(x, y=, z=, /)") + import _testcapi + cls = _testcapi.DocStringUnrepresentableSignatureTest + self.assertEqual(self._get_summary_line(cls.staticmeth), + "staticmeth(a, b=)") + @support.cpython_only def test_unbound_builtin_method_unrepresentable_default(self): self.assertEqual(self._get_summary_line(dict.pop), "pop(self, key, default=, /)") + import _testcapi + cls = _testcapi.DocStringUnrepresentableSignatureTest + self.assertEqual(self._get_summary_line(cls.meth), + "meth(self, /, a, b=)") + @support.cpython_only def test_bound_builtin_method_unrepresentable_default(self): self.assertEqual(self._get_summary_line({}.pop), "pop(key, default=, /) " "method of builtins.dict instance") + import _testcapi + obj = _testcapi.DocStringUnrepresentableSignatureTest() + self.assertEqual(self._get_summary_line(obj.meth), + "meth(a, b=) " + "method of _testcapi.DocStringUnrepresentableSignatureTest instance") + + @support.cpython_only + def test_unbound_builtin_classmethod_unrepresentable_default(self): + import _testcapi + cls = _testcapi.DocStringUnrepresentableSignatureTest + descr = cls.__dict__['classmeth'] + self.assertEqual(self._get_summary_line(descr), + "classmeth(type, /, a, b=)") + + @support.cpython_only + def test_bound_builtin_classmethod_unrepresentable_default(self): + import _testcapi + cls = _testcapi.DocStringUnrepresentableSignatureTest + self.assertEqual(self._get_summary_line(cls.classmeth), + "classmeth(a, b=) method of builtins.type instance") def test_overridden_text_signature(self): class C: diff --git a/Modules/_testcapi/docstring.c b/Modules/_testcapi/docstring.c index b680171..d99fbdd 100644 --- a/Modules/_testcapi/docstring.c +++ b/Modules/_testcapi/docstring.c @@ -100,6 +100,13 @@ static PyMethodDef test_methods[] = { {"test_with_docstring", test_with_docstring, METH_VARARGS, PyDoc_STR("This is a pretty normal docstring.")}, + {"func_with_unrepresentable_signature", + (PyCFunction)test_with_docstring, METH_VARARGS, + PyDoc_STR( + "func_with_unrepresentable_signature($module, /, a, b=)\n" + "--\n\n" + "This docstring has a signature with unrepresentable default." + )}, {NULL}, }; @@ -140,6 +147,40 @@ static PyTypeObject DocStringNoSignatureTest = { .tp_new = PyType_GenericNew, }; +static PyMethodDef DocStringUnrepresentableSignatureTest_methods[] = { + {"meth", + (PyCFunction)test_with_docstring, METH_VARARGS, + PyDoc_STR( + "meth($self, /, a, b=)\n" + "--\n\n" + "This docstring has a signature with unrepresentable default." + )}, + {"classmeth", + (PyCFunction)test_with_docstring, METH_VARARGS|METH_CLASS, + PyDoc_STR( + "classmeth($type, /, a, b=)\n" + "--\n\n" + "This docstring has a signature with unrepresentable default." + )}, + {"staticmeth", + (PyCFunction)test_with_docstring, METH_VARARGS|METH_STATIC, + PyDoc_STR( + "staticmeth(a, b=)\n" + "--\n\n" + "This docstring has a signature with unrepresentable default." + )}, + {NULL}, +}; + +static PyTypeObject DocStringUnrepresentableSignatureTest = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_testcapi.DocStringUnrepresentableSignatureTest", + .tp_basicsize = sizeof(PyObject), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = DocStringUnrepresentableSignatureTest_methods, + .tp_new = PyType_GenericNew, +}; + int _PyTestCapi_Init_Docstring(PyObject *mod) { @@ -149,5 +190,8 @@ _PyTestCapi_Init_Docstring(PyObject *mod) if (PyModule_AddType(mod, &DocStringNoSignatureTest) < 0) { return -1; } + if (PyModule_AddType(mod, &DocStringUnrepresentableSignatureTest) < 0) { + return -1; + } return 0; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index d1ac041..8c2be44 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -420,6 +420,7 @@ Modules/_testcapi/buffer.c - testBufType - Modules/_testcapi/code.c get_code_extra_index key - Modules/_testcapi/datetime.c - test_run_counter - Modules/_testcapi/docstring.c - DocStringNoSignatureTest - +Modules/_testcapi/docstring.c - DocStringUnrepresentableSignatureTest - Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type - Modules/_testcapi/heaptype.c - _testcapimodule - Modules/_testcapi/mem.c - FmData - -- cgit v0.12