Skip to content

Commit 581ee36

Browse files
committed
Issue #20326: Argument Clinic now uses a simple, unique signature to
annotate text signatures in docstrings, resulting in fewer false positives. "self" parameters are also explicitly marked, allowing inspect.Signature() to authoritatively detect (and skip) said parameters. Issue #20326: Argument Clinic now generates separate checksums for the input and output sections of the block, allowing external tools to verify that the input has not changed (and thus the output is not out-of-date).
1 parent eecbbad commit 581ee36

37 files changed

+497
-412
lines changed

Include/object.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,8 @@ PyAPI_FUNC(unsigned int) PyType_ClearCache(void);
493493
PyAPI_FUNC(void) PyType_Modified(PyTypeObject *);
494494

495495
#ifndef Py_LIMITED_API
496-
PyAPI_FUNC(PyObject *)
497-
_PyType_GetDocFromInternalDoc(const char *, const char *);
498-
PyAPI_FUNC(PyObject *)
499-
_PyType_GetTextSignatureFromInternalDoc(const char *, const char *);
496+
PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *);
497+
PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *);
500498
#endif
501499

502500
/* Generic operations on objects */

Lib/idlelib/idle_test/test_calltips.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ def gtest(obj, out):
5454

5555
gtest(List, List.__doc__)
5656
gtest(list.__new__,
57-
'T.__new__(S, ...) -> a new object with type S, a subtype of T')
57+
'Create and return a new object. See help(type) for accurate signature.')
5858
gtest(list.__init__,
59-
'x.__init__(...) initializes x; see help(type(x)) for signature')
59+
'Initialize self. See help(type(self)) for accurate signature.')
6060
append_doc = "L.append(object) -> None -- append object to end"
6161
gtest(list.append, append_doc)
6262
gtest([].append, append_doc)

Lib/inspect.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,10 @@ def from_builtin(cls, func):
19981998
else:
19991999
kind = Parameter.POSITIONAL_OR_KEYWORD
20002000

2001+
first_parameter_is_self = s.startswith("($")
2002+
if first_parameter_is_self:
2003+
s = '(' + s[2:]
2004+
20012005
s = "def foo" + s + ": pass"
20022006

20032007
try:
@@ -2102,18 +2106,11 @@ def p(name_node, default_node, default=empty):
21022106
kind = Parameter.VAR_KEYWORD
21032107
p(f.args.kwarg, empty)
21042108

2105-
if parameters and (hasattr(func, '__self__') or
2106-
isinstance(func, _WrapperDescriptor,) or
2107-
ismethoddescriptor(func)
2108-
):
2109-
name = parameters[0].name
2110-
if name not in ('self', 'module', 'type'):
2111-
pass
2112-
elif getattr(func, '__self__', None):
2113-
# strip off self (it's already been bound)
2114-
p = parameters.pop(0)
2115-
if not p.name in ('self', 'module', 'type'):
2116-
raise ValueError('Unexpected name ' + repr(p.name) + ', expected self/module/cls/type')
2109+
if first_parameter_is_self:
2110+
assert parameters
2111+
if getattr(func, '__self__', None):
2112+
# strip off self, it's already been bound
2113+
parameters.pop(0)
21172114
else:
21182115
# for builtins, self parameter is always positional-only!
21192116
p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY)

Lib/test/test_capi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def test_docstring_signature_parsing(self):
125125
self.assertEqual(_testcapi.docstring_no_signature.__text_signature__, None)
126126

127127
self.assertEqual(_testcapi.docstring_with_invalid_signature.__doc__,
128-
"docstring_with_invalid_signature (module, boo)\n"
128+
"sig= (module, boo)\n"
129129
"\n"
130130
"This docstring has an invalid signature."
131131
)

Lib/test/test_generators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,8 @@ def gen():
436436
>>> [s for s in dir(i) if not s.startswith('_')]
437437
['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw']
438438
>>> from test.support import HAVE_DOCSTRINGS
439-
>>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).')
440-
Implements next(self).
439+
>>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).')
440+
Implement next(self).
441441
>>> iter(i) is i
442442
True
443443
>>> import types

Lib/test/test_genexps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@
222222
True
223223
224224
>>> from test.support import HAVE_DOCSTRINGS
225-
>>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).')
226-
Implements next(self).
225+
>>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).')
226+
Implement next(self).
227227
>>> import types
228228
>>> isinstance(g, types.GeneratorType)
229229
True

Misc/NEWS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ Tests
203203
Tools/Demos
204204
-----------
205205

206+
- Issue #20326: Argument Clinic now uses a simple, unique signature to
207+
annotate text signatures in docstrings, resulting in fewer false
208+
positives. "self" parameters are also explicitly marked, allowing
209+
inspect.Signature() to authoritatively detect (and skip) said parameters.
210+
211+
- Issue #20326: Argument Clinic now generates separate checksums for the
212+
input and output sections of the block, allowing external tools to verify
213+
that the input has not changed (and thus the output is not out-of-date).
214+
206215
- Issue #20390: Argument Clinic's "file" output preset now defaults to
207216
"{dirname}/clinic/{basename}.h".
208217

Modules/_bz2module.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ module _bz2
204204
class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type"
205205
class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type"
206206
[clinic start generated code]*/
207-
/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
207+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e3b139924f5e18cc]*/
208208

209209
#include "clinic/_bz2module.c.h"
210210

@@ -224,7 +224,7 @@ flush() method to finish the compression process.
224224

225225
static PyObject *
226226
_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data)
227-
/*[clinic end generated code: checksum=59365426e941fbcc4c7a4d0eef85ca7e19196eaa]*/
227+
/*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/
228228
{
229229
PyObject *result = NULL;
230230

@@ -249,7 +249,7 @@ The compressor object may not be used after this method is called.
249249

250250
static PyObject *
251251
_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
252-
/*[clinic end generated code: checksum=3ef03fc1b092a701b382b97096c7fd50db87190b]*/
252+
/*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/
253253
{
254254
PyObject *result = NULL;
255255

@@ -304,7 +304,7 @@ For one-shot compression, use the compress() function instead.
304304

305305
static int
306306
_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
307-
/*[clinic end generated code: checksum=c4e6adfd02963827075a1cc9309dc6df184b1246]*/
307+
/*[clinic end generated code: output=c4e6adfd02963827 input=4e1ff7b8394b6e9a]*/
308308
{
309309
int bzerror;
310310

@@ -484,7 +484,7 @@ is ignored and saved in the unused_data attribute.
484484

485485
static PyObject *
486486
_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data)
487-
/*[clinic end generated code: checksum=086e4b99e60cb3f67c0481959591eae0735320bc]*/
487+
/*[clinic end generated code: output=086e4b99e60cb3f6 input=616c2a6db5269961]*/
488488
{
489489
PyObject *result = NULL;
490490

@@ -515,7 +515,7 @@ For one-shot decompression, use the decompress() function instead.
515515

516516
static int
517517
_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
518-
/*[clinic end generated code: checksum=e4d2b9bb866ab8f1f4a8bb786ddb5b614ce323c0]*/
518+
/*[clinic end generated code: output=e4d2b9bb866ab8f1 input=95f6500dcda60088]*/
519519
{
520520
int bzerror;
521521

Modules/_cryptmodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/*[clinic input]
1111
module crypt
1212
[clinic start generated code]*/
13-
/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
13+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c6252cf4f2f2ae81]*/
1414

1515

1616
/*[clinic input]
@@ -30,7 +30,7 @@ results for a given *word*.
3030
[clinic start generated code]*/
3131

3232
PyDoc_STRVAR(crypt_crypt__doc__,
33-
"crypt(module, word, salt)\n"
33+
"sig=($module, word, salt)\n"
3434
"Hash a *word* with the given *salt* and return the hashed password.\n"
3535
"\n"
3636
"*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n"
@@ -63,7 +63,7 @@ crypt_crypt(PyModuleDef *module, PyObject *args)
6363

6464
static PyObject *
6565
crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt)
66-
/*[clinic end generated code: checksum=dbfe26a21eb335abefe6a0bbd0a682ea22b9adc0]*/
66+
/*[clinic end generated code: output=c7443257e03fca92 input=4d93b6d0f41fbf58]*/
6767
{
6868
/* On some platforms (AtheOS) crypt returns NULL for an invalid
6969
salt. Return None in that case. XXX Maybe raise an exception? */

Modules/_cursesmodule.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ typedef chtype attr_t; /* No attr_t type is available */
138138
module curses
139139
class curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type"
140140
[clinic start generated code]*/
141-
/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
141+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=88c860abdbb50e0c]*/
142142

143143
/* Definition of exception curses.error */
144144

@@ -651,7 +651,7 @@ curses_window_addch(PyCursesWindowObject *self, PyObject *args)
651651

652652
static PyObject *
653653
curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr)
654-
/*[clinic end generated code: checksum=e1cdbd4f4e42fc6b36fd4755d7e4bd5b58751ea1]*/
654+
/*[clinic end generated code: output=e1cdbd4f4e42fc6b input=fe7e3711d5bbf1f6]*/
655655
{
656656
PyCursesWindowObject *cwself = (PyCursesWindowObject *)self;
657657
int coordinates_group = group_left_1;

0 commit comments

Comments
 (0)