From 2623c8c23cead505a78ec416072223552e94727e Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sat, 8 Feb 2014 22:15:29 -0800 Subject: Issue #20530: Argument Clinic's signature format has been revised again. The new syntax is highly human readable while still preventing false positives. The syntax also extends Python syntax to denote "self" and positional-only parameters, allowing inspect.Signature objects to be totally accurate for all supported builtins in Python 3.4. --- Include/object.h | 4 +- Lib/inspect.py | 115 ++++++++++++++++++++----- Lib/test/test_capi.py | 17 +++- Lib/test/test_inspect.py | 73 ++++++++++++++-- Misc/NEWS | 14 ++- Modules/_cryptmodule.c | 6 +- Modules/_datetimemodule.c | 6 +- Modules/_dbmmodule.c | 12 ++- Modules/_opcode.c | 6 +- Modules/_sre.c | 6 +- Modules/_testcapimodule.c | 27 ++++-- Modules/_weakref.c | 6 +- Modules/clinic/_bz2module.c.h | 22 +++-- Modules/clinic/_lzmamodule.c.h | 30 +++++-- Modules/clinic/_pickle.c.h | 68 +++++++++++---- Modules/clinic/audioop.c.h | 107 +++++++++++++++++------ Modules/clinic/binascii.c.h | 58 +++++++++---- Modules/clinic/zlibmodule.c.h | 52 +++++++++--- Modules/posixmodule.c | 19 +++-- Modules/unicodedata.c | 6 +- Objects/descrobject.c | 12 +-- Objects/dictobject.c | 12 ++- Objects/methodobject.c | 4 +- Objects/typeobject.c | 189 ++++++++++++++++++++++++----------------- Objects/unicodeobject.c | 6 +- Python/import.c | 72 ++++++++++------ Tools/clinic/clinic.py | 160 ++++++++++++++++++++++++---------- Tools/clinic/clinic_test.py | 43 +++++++--- 28 files changed, 825 insertions(+), 327 deletions(-) diff --git a/Include/object.h b/Include/object.h index 68ca7b4..7584d4c 100644 --- a/Include/object.h +++ b/Include/object.h @@ -496,8 +496,8 @@ PyAPI_FUNC(unsigned int) PyType_ClearCache(void); PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); #ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *); -PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *); +PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); +PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); #endif /* Generic operations on objects */ diff --git a/Lib/inspect.py b/Lib/inspect.py index 7a2739f..017a7e8 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -39,6 +39,7 @@ import os import re import sys import tokenize +import token import types import warnings import functools @@ -1648,25 +1649,88 @@ def _signature_get_bound_param(spec): return spec[2:pos] +def _signature_strip_non_python_syntax(signature): + """ + Takes a signature in Argument Clinic's extended signature format. + Returns a tuple of three things: + * that signature re-rendered in standard Python syntax, + * the index of the "self" parameter (generally 0), or None if + the function does not have a "self" parameter, and + * the index of the last "positional only" parameter, + or None if the signature has no positional-only parameters. + """ + + if not signature: + return signature, None, None + + self_parameter = None + last_positional_only = None + + lines = [l.encode('ascii') for l in signature.split('\n')] + generator = iter(lines).__next__ + token_stream = tokenize.tokenize(generator) + + delayed_comma = False + skip_next_comma = False + text = [] + add = text.append + + current_parameter = 0 + OP = token.OP + ERRORTOKEN = token.ERRORTOKEN + + # token stream always starts with ENCODING token, skip it + t = next(token_stream) + assert t.type == tokenize.ENCODING + + for t in token_stream: + type, string = t.type, t.string + + if type == OP: + if string == ',': + if skip_next_comma: + skip_next_comma = False + else: + assert not delayed_comma + delayed_comma = True + current_parameter += 1 + continue + + if string == '/': + assert not skip_next_comma + assert last_positional_only is None + skip_next_comma = True + last_positional_only = current_parameter - 1 + continue + + if (type == ERRORTOKEN) and (string == '$'): + assert self_parameter is None + self_parameter = current_parameter + continue + + if delayed_comma: + delayed_comma = False + if not ((type == OP) and (string == ')')): + add(', ') + add(string) + if (string == ','): + add(' ') + clean_signature = ''.join(text) + return clean_signature, self_parameter, last_positional_only + + def _signature_fromstr(cls, obj, s): # Internal helper to parse content of '__text_signature__' # and return a Signature based on it Parameter = cls._parameter_cls - if s.endswith("/)"): - kind = Parameter.POSITIONAL_ONLY - s = s[:-2] + ')' - else: - kind = Parameter.POSITIONAL_OR_KEYWORD - - first_parameter_is_self = s.startswith("($") - if first_parameter_is_self: - s = '(' + s[2:] + clean_signature, self_parameter, last_positional_only = \ + _signature_strip_non_python_syntax(s) - s = "def foo" + s + ": pass" + program = "def foo" + clean_signature + ": pass" try: - module = ast.parse(s) + module = ast.parse(program) except SyntaxError: module = None @@ -1750,8 +1814,14 @@ def _signature_fromstr(cls, obj, s): args = reversed(f.args.args) defaults = reversed(f.args.defaults) iter = itertools.zip_longest(args, defaults, fillvalue=None) - for name, default in reversed(list(iter)): + if last_positional_only is not None: + kind = Parameter.POSITIONAL_ONLY + else: + kind = Parameter.POSITIONAL_OR_KEYWORD + for i, (name, default) in enumerate(reversed(list(iter))): p(name, default) + if i == last_positional_only: + kind = Parameter.POSITIONAL_OR_KEYWORD # *args if f.args.vararg: @@ -1768,7 +1838,7 @@ def _signature_fromstr(cls, obj, s): kind = Parameter.VAR_KEYWORD p(f.args.kwarg, empty) - if first_parameter_is_self: + if self_parameter is not None: assert parameters if getattr(obj, '__self__', None): # strip off self, it's already been bound @@ -1861,12 +1931,13 @@ def signature(obj): # At this point we know, that `obj` is a class, with no user- # defined '__init__', '__new__', or class-level '__call__' - for base in obj.__mro__: + for base in obj.__mro__[:-1]: # Since '__text_signature__' is implemented as a # descriptor that extracts text signature from the # class docstring, if 'obj' is derived from a builtin # class, its own '__text_signature__' may be 'None'. - # Therefore, we go through the MRO to find the first + # Therefore, we go through the MRO (except the last + # class in there, which is 'object') to find the first # class with non-empty text signature. try: text_sig = base.__text_signature__ @@ -1881,13 +1952,7 @@ def signature(obj): # No '__text_signature__' was found for the 'obj' class. # Last option is to check if its '__init__' is # object.__init__ or type.__init__. - if type in obj.__mro__: - # 'obj' is a metaclass without user-defined __init__ - # or __new__. - if obj.__init__ is type.__init__: - # Return a signature of 'type' builtin. - return signature(type) - else: + if type not in obj.__mro__: # We have a class (not metaclass), but no user-defined # __init__ or __new__ for it if obj.__init__ is object.__init__: @@ -1901,7 +1966,11 @@ def signature(obj): # infinite recursion (and even potential segfault) call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: - sig = signature(call) + try: + sig = signature(call) + except ValueError as ex: + msg = 'no signature found for {!r}'.format(obj) + raise ValueError(msg) from ex if sig is not None: # For classes and objects we skip the first parameter of their diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 10e8c4e..ba7c38d 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -126,20 +126,29 @@ class CAPITest(unittest.TestCase): self.assertEqual(_testcapi.docstring_no_signature.__text_signature__, None) self.assertEqual(_testcapi.docstring_with_invalid_signature.__doc__, - "sig= (module, boo)\n" + "docstring_with_invalid_signature($module, /, boo)\n" "\n" "This docstring has an invalid signature." ) self.assertEqual(_testcapi.docstring_with_invalid_signature.__text_signature__, None) + self.assertEqual(_testcapi.docstring_with_invalid_signature2.__doc__, + "docstring_with_invalid_signature2($module, /, boo)\n" + "\n" + "--\n" + "\n" + "This docstring also has an invalid signature." + ) + self.assertEqual(_testcapi.docstring_with_invalid_signature2.__text_signature__, None) + self.assertEqual(_testcapi.docstring_with_signature.__doc__, "This docstring has a valid signature.") - self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "(module, sig)") + self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "($module, /, sig)") self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__doc__, - "This docstring has a valid signature and some extra newlines.") + "\nThis docstring has a valid signature and some extra newlines.") self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__, - "(module, parameter)") + "($module, /, parameter)") @unittest.skipUnless(threading, 'Threading required for this test.') diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 862ef82..3f20419 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1684,7 +1684,6 @@ class TestSignatureObject(unittest.TestCase): self.assertEqual(p('sys'), sys.maxsize) self.assertEqual(p('exp'), sys.maxsize - 1) - test_callable(type) test_callable(object) # normal method @@ -1710,9 +1709,12 @@ class TestSignatureObject(unittest.TestCase): # support for 'method-wrapper' test_callable(min.__call__) - class ThisWorksNow: - __call__ = type - test_callable(ThisWorksNow()) + # This doesn't work now. + # (We don't have a valid signature for "type" in 3.4) + with self.assertRaisesRegex(ValueError, "no signature found"): + class ThisWorksNow: + __call__ = type + test_callable(ThisWorksNow()) @cpython_only @unittest.skipIf(MISSING_C_DOCSTRINGS, @@ -2213,11 +2215,11 @@ class TestSignatureObject(unittest.TestCase): # Test meta-classes without user-defined __init__ or __new__ class C(type): pass - self.assertEqual(str(inspect.signature(C)), - '(object_or_name, bases, dict)') class D(C): pass - self.assertEqual(str(inspect.signature(D)), - '(object_or_name, bases, dict)') + with self.assertRaisesRegex(ValueError, "callable.*is not supported"): + self.assertEqual(inspect.signature(C), None) + with self.assertRaisesRegex(ValueError, "callable.*is not supported"): + self.assertEqual(inspect.signature(D), None) @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") @@ -2768,6 +2770,61 @@ class TestSignaturePrivateHelpers(unittest.TestCase): self.assertEqual(getter('($self, obj)'), 'self') self.assertEqual(getter('($cls, /, obj)'), 'cls') + def _strip_non_python_syntax(self, input, + clean_signature, self_parameter, last_positional_only): + computed_clean_signature, \ + computed_self_parameter, \ + computed_last_positional_only = \ + inspect._signature_strip_non_python_syntax(input) + self.assertEqual(computed_clean_signature, clean_signature) + self.assertEqual(computed_self_parameter, self_parameter) + self.assertEqual(computed_last_positional_only, last_positional_only) + + def test_signature_strip_non_python_syntax(self): + self._strip_non_python_syntax( + "($module, /, path, mode, *, dir_fd=None, " + + "effective_ids=False,\n follow_symlinks=True)", + "(module, path, mode, *, dir_fd=None, " + + "effective_ids=False, follow_symlinks=True)", + 0, + 0) + + self._strip_non_python_syntax( + "($module, word, salt, /)", + "(module, word, salt)", + 0, + 2) + + self._strip_non_python_syntax( + "(x, y=None, z=None, /)", + "(x, y=None, z=None)", + None, + 2) + + self._strip_non_python_syntax( + "(x, y=None, z=None)", + "(x, y=None, z=None)", + None, + None) + + self._strip_non_python_syntax( + "(x,\n y=None,\n z = None )", + "(x, y=None, z=None)", + None, + None) + + self._strip_non_python_syntax( + "", + "", + None, + None) + + self._strip_non_python_syntax( + None, + None, + None, + None) + class TestUnwrap(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS index 9ed7e73..20cf656 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -200,18 +200,24 @@ Tests Tools/Demos ----------- -- #Issue 20456: Argument Clinic now observes the C preprocessor conditional +- Issue #20530: Argument Clinic's signature format has been revised again. + The new syntax is highly human readable while still preventing false + positives. The syntax also extends Python syntax to denote "self" and + positional-only parameters, allowing inspect.Signature objects to be + totally accurate for all supported builtins in Python 3.4. + +- Issue #20456: Argument Clinic now observes the C preprocessor conditional compilation statements of the C files it parses. When a Clinic block is inside a conditional code, it adjusts its output to match, including automatically generating an empty methoddef macro. -- #Issue 20456: Cloned functions in Argument Clinic now use the correct +- Issue #20456: Cloned functions in Argument Clinic now use the correct name, not the name of the function they were cloned from, for text strings inside generated code. -- #Issue 20456: Fixed Argument Clinic's test suite and "--converters" feature. +- Issue #20456: Fixed Argument Clinic's test suite and "--converters" feature. -- #Issue 20456: Argument Clinic now allows specifying different names +- Issue #20456: Argument Clinic now allows specifying different names for a parameter in Python and C, using "as" on the parameter line. - Issue #20326: Argument Clinic now uses a simple, unique signature to diff --git a/Modules/_cryptmodule.c b/Modules/_cryptmodule.c index 7531c2f..da44ef3 100644 --- a/Modules/_cryptmodule.c +++ b/Modules/_cryptmodule.c @@ -30,7 +30,9 @@ results for a given *word*. [clinic start generated code]*/ PyDoc_STRVAR(crypt_crypt__doc__, -"sig=($module, word, salt)\n" +"crypt($module, word, salt, /)\n" +"--\n" +"\n" "Hash a *word* with the given *salt* and return the hashed password.\n" "\n" "*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n" @@ -63,7 +65,7 @@ exit: static PyObject * crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt) -/*[clinic end generated code: output=c7443257e03fca92 input=4d93b6d0f41fbf58]*/ +/*[clinic end generated code: output=3eaacdf994a6ff23 input=4d93b6d0f41fbf58]*/ { /* On some platforms (AtheOS) crypt returns NULL for an invalid salt. Return None in that case. XXX Maybe raise an exception? */ diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 80fa497..fce6bbf 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4159,7 +4159,9 @@ If no tz is specified, uses local timezone. [clinic start generated code]*/ PyDoc_STRVAR(datetime_datetime_now__doc__, -"sig=($type, tz=None)\n" +"now($type, /, tz=None)\n" +"--\n" +"\n" "Returns new datetime object representing current time local to tz.\n" "\n" " tz\n" @@ -4192,7 +4194,7 @@ exit: static PyObject * datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) -/*[clinic end generated code: output=c8a47308483e579a input=80d09869c5267d00]*/ +/*[clinic end generated code: output=583c5637e3c843fa input=80d09869c5267d00]*/ { PyObject *self; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index abeb799..93ea416 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -278,7 +278,9 @@ Return the value for key if present, otherwise default. [clinic start generated code]*/ PyDoc_STRVAR(dbm_dbm_get__doc__, -"sig=($self, key, default=None)\n" +"get($self, key, default=None, /)\n" +"--\n" +"\n" "Return the value for key if present, otherwise default."); #define DBM_DBM_GET_METHODDEF \ @@ -307,7 +309,7 @@ exit: static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, PyObject *default_value) -/*[clinic end generated code: output=2bbaf9a187f9b6bf input=aecf5efd2f2b1a3b]*/ +/*[clinic end generated code: output=452ea11394e7e92d input=aecf5efd2f2b1a3b]*/ { datum dbm_key, val; @@ -448,7 +450,9 @@ Return a database object. [clinic start generated code]*/ PyDoc_STRVAR(dbmopen__doc__, -"sig=($module, filename, flags=\'r\', mode=0o666)\n" +"open($module, filename, flags=\'r\', mode=0o666, /)\n" +"--\n" +"\n" "Return a database object.\n" "\n" " filename\n" @@ -485,7 +489,7 @@ exit: static PyObject * dbmopen_impl(PyModuleDef *module, const char *filename, const char *flags, int mode) -/*[clinic end generated code: output=a1da6a481d9d332b input=6499ab0fab1333ac]*/ +/*[clinic end generated code: output=9a7b725f9c4dcec2 input=6499ab0fab1333ac]*/ { int iflags; diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 712e6eb..fee388f 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -18,7 +18,9 @@ Compute the stack effect of the opcode. [clinic start generated code]*/ PyDoc_STRVAR(_opcode_stack_effect__doc__, -"sig=($module, opcode, oparg=None)\n" +"stack_effect($module, opcode, oparg=None, /)\n" +"--\n" +"\n" "Compute the stack effect of the opcode."); #define _OPCODE_STACK_EFFECT_METHODDEF \ @@ -50,7 +52,7 @@ exit: static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, PyObject *oparg) -/*[clinic end generated code: output=4fe636f5db87c0a9 input=2d0a9ee53c0418f5]*/ +/*[clinic end generated code: output=9e1133f8d587bc67 input=2d0a9ee53c0418f5]*/ { int effect; int oparg_int = 0; diff --git a/Modules/_sre.c b/Modules/_sre.c index 4dcaec1..d4d1d9d 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -540,7 +540,9 @@ Matches zero or more characters at the beginning of the string. [clinic start generated code]*/ PyDoc_STRVAR(pattern_match__doc__, -"sig=($self, pattern, pos=0, endpos=sys.maxsize)\n" +"match($self, /, pattern, pos=0, endpos=sys.maxsize)\n" +"--\n" +"\n" "Matches zero or more characters at the beginning of the string."); #define PATTERN_MATCH_METHODDEF \ @@ -570,7 +572,7 @@ exit: static PyObject * pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos) -/*[clinic end generated code: output=9f5b785661677848 input=26f9fd31befe46b9]*/ +/*[clinic end generated code: output=1528eafdb8b025ad input=26f9fd31befe46b9]*/ { SRE_STATE state; Py_ssize_t status; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 260e53d..9e81787 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2851,26 +2851,40 @@ PyDoc_STRVAR(docstring_no_signature, ); PyDoc_STRVAR(docstring_with_invalid_signature, -"sig= (module, boo)\n" +"docstring_with_invalid_signature($module, /, boo)\n" "\n" "This docstring has an invalid signature." ); +PyDoc_STRVAR(docstring_with_invalid_signature2, +"docstring_with_invalid_signature2($module, /, boo)\n" +"\n" +"--\n" +"\n" +"This docstring also has an invalid signature." +); + PyDoc_STRVAR(docstring_with_signature, -"sig=(module, sig)\n" +"docstring_with_signature($module, /, sig)\n" +"--\n" +"\n" "This docstring has a valid signature." ); PyDoc_STRVAR(docstring_with_signature_and_extra_newlines, -"sig=(module, parameter)\n" -"\n" +"docstring_with_signature_and_extra_newlines($module, /, parameter)\n" +"--\n" "\n" "\n" "This docstring has a valid signature and some extra newlines." ); PyDoc_STRVAR(docstring_with_signature_with_defaults, -"sig=(module, s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" +"docstring_with_signature_with_defaults(module, s='avocado',\n" +" b=b'bytes', d=3.14, i=35, n=None, t=True, f=False,\n" +" local=the_number_three, sys=sys.maxsize,\n" +" exp=sys.maxsize - 1)\n" +"--\n" "\n" "\n" "\n" @@ -3090,6 +3104,9 @@ static PyMethodDef TestMethods[] = { {"docstring_with_invalid_signature", (PyCFunction)test_with_docstring, METH_NOARGS, docstring_with_invalid_signature}, + {"docstring_with_invalid_signature2", + (PyCFunction)test_with_docstring, METH_NOARGS, + docstring_with_invalid_signature2}, {"docstring_with_signature", (PyCFunction)test_with_docstring, METH_NOARGS, docstring_with_signature}, diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 6451dba..da58931 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -20,7 +20,9 @@ Return the number of weak references to 'object'. [clinic start generated code]*/ PyDoc_STRVAR(_weakref_getweakrefcount__doc__, -"sig=($module, object)\n" +"getweakrefcount($module, object, /)\n" +"--\n" +"\n" "Return the number of weak references to \'object\'."); #define _WEAKREF_GETWEAKREFCOUNT_METHODDEF \ @@ -46,7 +48,7 @@ exit: static Py_ssize_t _weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object) -/*[clinic end generated code: output=ef51baac56180816 input=cedb69711b6a2507]*/ +/*[clinic end generated code: output=032eedbfd7d69e10 input=cedb69711b6a2507]*/ { PyWeakReference **list; diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h index 98f9a1b..8a201a0 100644 --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(_bz2_BZ2Compressor_compress__doc__, -"sig=($self, data)\n" +"compress($self, data, /)\n" +"--\n" +"\n" "Provide data to the compressor object.\n" "\n" "Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" @@ -38,7 +40,9 @@ exit: } PyDoc_STRVAR(_bz2_BZ2Compressor_flush__doc__, -"sig=($self)\n" +"flush($self, /)\n" +"--\n" +"\n" "Finish the compression process.\n" "\n" "Returns the compressed data left in internal buffers.\n" @@ -58,7 +62,9 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, -"sig=(compresslevel=9)\n" +"BZ2Compressor(compresslevel=9, /)\n" +"--\n" +"\n" "Create a compressor object for compressing data incrementally.\n" "\n" " compresslevel\n" @@ -89,7 +95,9 @@ exit: } PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, -"sig=($self, data)\n" +"decompress($self, data, /)\n" +"--\n" +"\n" "Provide data to the decompressor object.\n" "\n" "Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" @@ -125,7 +133,9 @@ exit: } PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, -"sig=()\n" +"BZ2Decompressor()\n" +"--\n" +"\n" "Create a decompressor object for decompressing data incrementally.\n" "\n" "For one-shot decompression, use the decompress() function instead."); @@ -149,4 +159,4 @@ _bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=aca4f6329c1c773a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=21ca4405519a0931 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h index 1848891..c1ad882 100644 --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/clinic/_lzmamodule.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(_lzma_LZMACompressor_compress__doc__, -"sig=($self, data)\n" +"compress($self, data, /)\n" +"--\n" +"\n" "Provide data to the compressor object.\n" "\n" "Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" @@ -38,7 +40,9 @@ exit: } PyDoc_STRVAR(_lzma_LZMACompressor_flush__doc__, -"sig=($self)\n" +"flush($self, /)\n" +"--\n" +"\n" "Finish the compression process.\n" "\n" "Returns the compressed data left in internal buffers.\n" @@ -58,7 +62,9 @@ _lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, -"sig=($self, data)\n" +"decompress($self, data, /)\n" +"--\n" +"\n" "Provide data to the decompressor object.\n" "\n" "Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" @@ -94,7 +100,9 @@ exit: } PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, -"sig=(format=FORMAT_AUTO, memlimit=None, filters=None)\n" +"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" +"--\n" +"\n" "Create a decompressor object for decompressing data incrementally.\n" "\n" " format\n" @@ -137,7 +145,9 @@ exit: } PyDoc_STRVAR(_lzma_is_check_supported__doc__, -"sig=($module, check_id)\n" +"is_check_supported($module, check_id, /)\n" +"--\n" +"\n" "Test whether the given integrity check is supported.\n" "\n" "Always returns True for CHECK_NONE and CHECK_CRC32."); @@ -165,7 +175,9 @@ exit: } PyDoc_STRVAR(_lzma__encode_filter_properties__doc__, -"sig=($module, filter)\n" +"_encode_filter_properties($module, filter, /)\n" +"--\n" +"\n" "Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" "\n" "The result does not include the filter ID itself, only the options."); @@ -197,7 +209,9 @@ exit: } PyDoc_STRVAR(_lzma__decode_filter_properties__doc__, -"sig=($module, filter_id, encoded_props)\n" +"_decode_filter_properties($module, filter_id, encoded_props, /)\n" +"--\n" +"\n" "Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" "\n" "The result does not include the filter ID itself, only the options."); @@ -228,4 +242,4 @@ exit: return return_value; } -/*[clinic end generated code: output=fe63bc798a5c5c55 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=808fec8216ac712b input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h index 9ef469d..a20a61e 100644 --- a/Modules/clinic/_pickle.c.h +++ b/Modules/clinic/_pickle.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, -"sig=($self)\n" +"clear_memo($self, /)\n" +"--\n" +"\n" "Clears the pickler\'s \"memo\".\n" "\n" "The memo is the data structure that remembers which objects the\n" @@ -24,14 +26,18 @@ _pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_pickle_Pickler_dump__doc__, -"sig=($self, obj)\n" +"dump($self, obj, /)\n" +"--\n" +"\n" "Write a pickled representation of the given object to the open file."); #define _PICKLE_PICKLER_DUMP_METHODDEF \ {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, PyDoc_STRVAR(_pickle_Pickler___init____doc__, -"sig=(file, protocol=None, fix_imports=True)\n" +"Pickler(file, protocol=None, fix_imports=True)\n" +"--\n" +"\n" "This takes a binary file for writing a pickle data stream.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -74,7 +80,9 @@ exit: } PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, -"sig=($self)\n" +"clear($self, /)\n" +"--\n" +"\n" "Remove all items from memo."); #define _PICKLE_PICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -90,7 +98,9 @@ _pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED } PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, -"sig=($self)\n" +"copy($self, /)\n" +"--\n" +"\n" "Copy the memo to a new object."); #define _PICKLE_PICKLERMEMOPROXY_COPY_METHODDEF \ @@ -106,7 +116,9 @@ _pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED( } PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, -"sig=($self)\n" +"__reduce__($self, /)\n" +"--\n" +"\n" "Implement pickle support."); #define _PICKLE_PICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -122,7 +134,9 @@ _pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_U } PyDoc_STRVAR(_pickle_Unpickler_load__doc__, -"sig=($self)\n" +"load($self, /)\n" +"--\n" +"\n" "Load a pickle.\n" "\n" "Read a pickled object representation from the open file object given\n" @@ -142,7 +156,9 @@ _pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, -"sig=($self, module_name, global_name)\n" +"find_class($self, module_name, global_name, /)\n" +"--\n" +"\n" "Return an object from a specified module.\n" "\n" "If necessary, the module will be imported. Subclasses may override\n" @@ -176,7 +192,9 @@ exit: } PyDoc_STRVAR(_pickle_Unpickler___init____doc__, -"sig=(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"Unpickler(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"--\n" +"\n" "This takes a binary file for reading a pickle data stream.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -222,7 +240,9 @@ exit: } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, -"sig=($self)\n" +"clear($self, /)\n" +"--\n" +"\n" "Remove all items from memo."); #define _PICKLE_UNPICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -238,7 +258,9 @@ _pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UN } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, -"sig=($self)\n" +"copy($self, /)\n" +"--\n" +"\n" "Copy the memo to a new object."); #define _PICKLE_UNPICKLERMEMOPROXY_COPY_METHODDEF \ @@ -254,7 +276,9 @@ _pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNU } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, -"sig=($self)\n" +"__reduce__($self, /)\n" +"--\n" +"\n" "Implement pickling support."); #define _PICKLE_UNPICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -270,7 +294,9 @@ _pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject * } PyDoc_STRVAR(_pickle_dump__doc__, -"sig=($module, obj, file, protocol=None, *, fix_imports=True)\n" +"dump($module, /, obj, file, protocol=None, *, fix_imports=True)\n" +"--\n" +"\n" "Write a pickled representation of obj to the open file object file.\n" "\n" "This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may\n" @@ -320,7 +346,9 @@ exit: } PyDoc_STRVAR(_pickle_dumps__doc__, -"sig=($module, obj, protocol=None, *, fix_imports=True)\n" +"dumps($module, /, obj, protocol=None, *, fix_imports=True)\n" +"--\n" +"\n" "Return the pickled representation of the object as a bytes object.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -361,7 +389,10 @@ exit: } PyDoc_STRVAR(_pickle_load__doc__, -"sig=($module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"load($module, /, file, *, fix_imports=True, encoding=\'ASCII\',\n" +" errors=\'strict\')\n" +"--\n" +"\n" "Read and return an object from the pickle data stored in a file.\n" "\n" "This is equivalent to ``Unpickler(file).load()``, but may be more\n" @@ -413,7 +444,10 @@ exit: } PyDoc_STRVAR(_pickle_loads__doc__, -"sig=($module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"loads($module, /, data, *, fix_imports=True, encoding=\'ASCII\',\n" +" errors=\'strict\')\n" +"--\n" +"\n" "Read and return an object from the given pickle data.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -454,4 +488,4 @@ _pickle_loads(PyModuleDef *module, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=c59d4dafc2646f11 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f965b6c7018c898d input=a9049054013a1b77]*/ diff --git a/Modules/clinic/audioop.c.h b/Modules/clinic/audioop.c.h index 92d13b0..40ef5e2 100644 --- a/Modules/clinic/audioop.c.h +++ b/Modules/clinic/audioop.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(audioop_getsample__doc__, -"sig=($module, fragment, width, index)\n" +"getsample($module, fragment, width, index, /)\n" +"--\n" +"\n" "Return the value of sample index from the fragment."); #define AUDIOOP_GETSAMPLE_METHODDEF \ @@ -35,7 +37,9 @@ exit: } PyDoc_STRVAR(audioop_max__doc__, -"sig=($module, fragment, width)\n" +"max($module, fragment, width, /)\n" +"--\n" +"\n" "Return the maximum of the absolute value of all samples in a fragment."); #define AUDIOOP_MAX_METHODDEF \ @@ -66,7 +70,9 @@ exit: } PyDoc_STRVAR(audioop_minmax__doc__, -"sig=($module, fragment, width)\n" +"minmax($module, fragment, width, /)\n" +"--\n" +"\n" "Return the minimum and maximum values of all samples in the sound fragment."); #define AUDIOOP_MINMAX_METHODDEF \ @@ -97,7 +103,9 @@ exit: } PyDoc_STRVAR(audioop_avg__doc__, -"sig=($module, fragment, width)\n" +"avg($module, fragment, width, /)\n" +"--\n" +"\n" "Return the average over all samples in the fragment."); #define AUDIOOP_AVG_METHODDEF \ @@ -128,7 +136,9 @@ exit: } PyDoc_STRVAR(audioop_rms__doc__, -"sig=($module, fragment, width)\n" +"rms($module, fragment, width, /)\n" +"--\n" +"\n" "Return the root-mean-square of the fragment, i.e. sqrt(sum(S_i^2)/n)."); #define AUDIOOP_RMS_METHODDEF \ @@ -159,7 +169,9 @@ exit: } PyDoc_STRVAR(audioop_findfit__doc__, -"sig=($module, fragment, reference)\n" +"findfit($module, fragment, reference, /)\n" +"--\n" +"\n" "Try to match reference as well as possible to a portion of fragment."); #define AUDIOOP_FINDFIT_METHODDEF \ @@ -193,7 +205,9 @@ exit: } PyDoc_STRVAR(audioop_findfactor__doc__, -"sig=($module, fragment, reference)\n" +"findfactor($module, fragment, reference, /)\n" +"--\n" +"\n" "Return a factor F such that rms(add(fragment, mul(reference, -F))) is minimal."); #define AUDIOOP_FINDFACTOR_METHODDEF \ @@ -227,7 +241,9 @@ exit: } PyDoc_STRVAR(audioop_findmax__doc__, -"sig=($module, fragment, length)\n" +"findmax($module, fragment, length, /)\n" +"--\n" +"\n" "Search fragment for a slice of specified number of samples with maximum energy."); #define AUDIOOP_FINDMAX_METHODDEF \ @@ -258,7 +274,9 @@ exit: } PyDoc_STRVAR(audioop_avgpp__doc__, -"sig=($module, fragment, width)\n" +"avgpp($module, fragment, width, /)\n" +"--\n" +"\n" "Return the average peak-peak value over all samples in the fragment."); #define AUDIOOP_AVGPP_METHODDEF \ @@ -289,7 +307,9 @@ exit: } PyDoc_STRVAR(audioop_maxpp__doc__, -"sig=($module, fragment, width)\n" +"maxpp($module, fragment, width, /)\n" +"--\n" +"\n" "Return the maximum peak-peak value in the sound fragment."); #define AUDIOOP_MAXPP_METHODDEF \ @@ -320,7 +340,9 @@ exit: } PyDoc_STRVAR(audioop_cross__doc__, -"sig=($module, fragment, width)\n" +"cross($module, fragment, width, /)\n" +"--\n" +"\n" "Return the number of zero crossings in the fragment passed as an argument."); #define AUDIOOP_CROSS_METHODDEF \ @@ -351,7 +373,9 @@ exit: } PyDoc_STRVAR(audioop_mul__doc__, -"sig=($module, fragment, width, factor)\n" +"mul($module, fragment, width, factor, /)\n" +"--\n" +"\n" "Return a fragment that has all samples in the original fragment multiplied by the floating-point value factor."); #define AUDIOOP_MUL_METHODDEF \ @@ -383,7 +407,9 @@ exit: } PyDoc_STRVAR(audioop_tomono__doc__, -"sig=($module, fragment, width, lfactor, rfactor)\n" +"tomono($module, fragment, width, lfactor, rfactor, /)\n" +"--\n" +"\n" "Convert a stereo fragment to a mono fragment."); #define AUDIOOP_TOMONO_METHODDEF \ @@ -416,7 +442,9 @@ exit: } PyDoc_STRVAR(audioop_tostereo__doc__, -"sig=($module, fragment, width, lfactor, rfactor)\n" +"tostereo($module, fragment, width, lfactor, rfactor, /)\n" +"--\n" +"\n" "Generate a stereo fragment from a mono fragment."); #define AUDIOOP_TOSTEREO_METHODDEF \ @@ -449,7 +477,9 @@ exit: } PyDoc_STRVAR(audioop_add__doc__, -"sig=($module, fragment1, fragment2, width)\n" +"add($module, fragment1, fragment2, width, /)\n" +"--\n" +"\n" "Return a fragment which is the addition of the two samples passed as parameters."); #define AUDIOOP_ADD_METHODDEF \ @@ -484,7 +514,9 @@ exit: } PyDoc_STRVAR(audioop_bias__doc__, -"sig=($module, fragment, width, bias)\n" +"bias($module, fragment, width, bias, /)\n" +"--\n" +"\n" "Return a fragment that is the original fragment with a bias added to each sample."); #define AUDIOOP_BIAS_METHODDEF \ @@ -516,7 +548,9 @@ exit: } PyDoc_STRVAR(audioop_reverse__doc__, -"sig=($module, fragment, width)\n" +"reverse($module, fragment, width, /)\n" +"--\n" +"\n" "Reverse the samples in a fragment and returns the modified fragment."); #define AUDIOOP_REVERSE_METHODDEF \ @@ -547,7 +581,9 @@ exit: } PyDoc_STRVAR(audioop_byteswap__doc__, -"sig=($module, fragment, width)\n" +"byteswap($module, fragment, width, /)\n" +"--\n" +"\n" "Convert big-endian samples to little-endian and vice versa."); #define AUDIOOP_BYTESWAP_METHODDEF \ @@ -578,7 +614,9 @@ exit: } PyDoc_STRVAR(audioop_lin2lin__doc__, -"sig=($module, fragment, width, newwidth)\n" +"lin2lin($module, fragment, width, newwidth, /)\n" +"--\n" +"\n" "Convert samples between 1-, 2-, 3- and 4-byte formats."); #define AUDIOOP_LIN2LIN_METHODDEF \ @@ -610,7 +648,10 @@ exit: } PyDoc_STRVAR(audioop_ratecv__doc__, -"sig=($module, fragment, width, nchannels, inrate, outrate, state, weightA=1, weightB=0)\n" +"ratecv($module, fragment, width, nchannels, inrate, outrate, state,\n" +" weightA=1, weightB=0, /)\n" +"--\n" +"\n" "Convert the frame rate of the input fragment."); #define AUDIOOP_RATECV_METHODDEF \ @@ -647,7 +688,9 @@ exit: } PyDoc_STRVAR(audioop_lin2ulaw__doc__, -"sig=($module, fragment, width)\n" +"lin2ulaw($module, fragment, width, /)\n" +"--\n" +"\n" "Convert samples in the audio fragment to u-LAW encoding."); #define AUDIOOP_LIN2ULAW_METHODDEF \ @@ -678,7 +721,9 @@ exit: } PyDoc_STRVAR(audioop_ulaw2lin__doc__, -"sig=($module, fragment, width)\n" +"ulaw2lin($module, fragment, width, /)\n" +"--\n" +"\n" "Convert sound fragments in u-LAW encoding to linearly encoded sound fragments."); #define AUDIOOP_ULAW2LIN_METHODDEF \ @@ -709,7 +754,9 @@ exit: } PyDoc_STRVAR(audioop_lin2alaw__doc__, -"sig=($module, fragment, width)\n" +"lin2alaw($module, fragment, width, /)\n" +"--\n" +"\n" "Convert samples in the audio fragment to a-LAW encoding."); #define AUDIOOP_LIN2ALAW_METHODDEF \ @@ -740,7 +787,9 @@ exit: } PyDoc_STRVAR(audioop_alaw2lin__doc__, -"sig=($module, fragment, width)\n" +"alaw2lin($module, fragment, width, /)\n" +"--\n" +"\n" "Convert sound fragments in a-LAW encoding to linearly encoded sound fragments."); #define AUDIOOP_ALAW2LIN_METHODDEF \ @@ -771,7 +820,9 @@ exit: } PyDoc_STRVAR(audioop_lin2adpcm__doc__, -"sig=($module, fragment, width, state)\n" +"lin2adpcm($module, fragment, width, state, /)\n" +"--\n" +"\n" "Convert samples to 4 bit Intel/DVI ADPCM encoding."); #define AUDIOOP_LIN2ADPCM_METHODDEF \ @@ -803,7 +854,9 @@ exit: } PyDoc_STRVAR(audioop_adpcm2lin__doc__, -"sig=($module, fragment, width, state)\n" +"adpcm2lin($module, fragment, width, state, /)\n" +"--\n" +"\n" "Decode an Intel/DVI ADPCM coded fragment to a linear fragment."); #define AUDIOOP_ADPCM2LIN_METHODDEF \ @@ -833,4 +886,4 @@ exit: return return_value; } -/*[clinic end generated code: output=ee7e58cfd3d0d5a6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=be840bba5d40c2ce input=a9049054013a1b77]*/ diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h index e4ef36c..5247180 100644 --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(binascii_a2b_uu__doc__, -"sig=($module, data)\n" +"a2b_uu($module, data, /)\n" +"--\n" +"\n" "Decode a line of uuencoded data."); #define BINASCII_A2B_UU_METHODDEF \ @@ -33,7 +35,9 @@ exit: } PyDoc_STRVAR(binascii_b2a_uu__doc__, -"sig=($module, data)\n" +"b2a_uu($module, data, /)\n" +"--\n" +"\n" "Uuencode line of data."); #define BINASCII_B2A_UU_METHODDEF \ @@ -63,7 +67,9 @@ exit: } PyDoc_STRVAR(binascii_a2b_base64__doc__, -"sig=($module, data)\n" +"a2b_base64($module, data, /)\n" +"--\n" +"\n" "Decode a line of base64 data."); #define BINASCII_A2B_BASE64_METHODDEF \ @@ -93,7 +99,9 @@ exit: } PyDoc_STRVAR(binascii_b2a_base64__doc__, -"sig=($module, data)\n" +"b2a_base64($module, data, /)\n" +"--\n" +"\n" "Base64-code line of data."); #define BINASCII_B2A_BASE64_METHODDEF \ @@ -123,7 +131,9 @@ exit: } PyDoc_STRVAR(binascii_a2b_hqx__doc__, -"sig=($module, data)\n" +"a2b_hqx($module, data, /)\n" +"--\n" +"\n" "Decode .hqx coding."); #define BINASCII_A2B_HQX_METHODDEF \ @@ -153,7 +163,9 @@ exit: } PyDoc_STRVAR(binascii_rlecode_hqx__doc__, -"sig=($module, data)\n" +"rlecode_hqx($module, data, /)\n" +"--\n" +"\n" "Binhex RLE-code binary data."); #define BINASCII_RLECODE_HQX_METHODDEF \ @@ -183,7 +195,9 @@ exit: } PyDoc_STRVAR(binascii_b2a_hqx__doc__, -"sig=($module, data)\n" +"b2a_hqx($module, data, /)\n" +"--\n" +"\n" "Encode .hqx data."); #define BINASCII_B2A_HQX_METHODDEF \ @@ -213,7 +227,9 @@ exit: } PyDoc_STRVAR(binascii_rledecode_hqx__doc__, -"sig=($module, data)\n" +"rledecode_hqx($module, data, /)\n" +"--\n" +"\n" "Decode hexbin RLE-coded string."); #define BINASCII_RLEDECODE_HQX_METHODDEF \ @@ -243,7 +259,9 @@ exit: } PyDoc_STRVAR(binascii_crc_hqx__doc__, -"sig=($module, data, crc)\n" +"crc_hqx($module, data, crc, /)\n" +"--\n" +"\n" "Compute hqx CRC incrementally."); #define BINASCII_CRC_HQX_METHODDEF \ @@ -278,7 +296,9 @@ exit: } PyDoc_STRVAR(binascii_crc32__doc__, -"sig=($module, data, crc=0)\n" +"crc32($module, data, crc=0, /)\n" +"--\n" +"\n" "Compute CRC-32 incrementally."); #define BINASCII_CRC32_METHODDEF \ @@ -313,7 +333,9 @@ exit: } PyDoc_STRVAR(binascii_b2a_hex__doc__, -"sig=($module, data)\n" +"b2a_hex($module, data, /)\n" +"--\n" +"\n" "Hexadecimal representation of binary data.\n" "\n" "The return value is a bytes object. This function is also\n" @@ -346,7 +368,9 @@ exit: } PyDoc_STRVAR(binascii_a2b_hex__doc__, -"sig=($module, hexstr)\n" +"a2b_hex($module, hexstr, /)\n" +"--\n" +"\n" "Binary data of hexadecimal representation.\n" "\n" "hexstr must contain an even number of hex digits (upper or lower case).\n" @@ -379,7 +403,9 @@ exit: } PyDoc_STRVAR(binascii_a2b_qp__doc__, -"sig=($module, data, header=False)\n" +"a2b_qp($module, /, data, header=False)\n" +"--\n" +"\n" "Decode a string of qp-encoded data."); #define BINASCII_A2B_QP_METHODDEF \ @@ -411,7 +437,9 @@ exit: } PyDoc_STRVAR(binascii_b2a_qp__doc__, -"sig=($module, data, quotetabs=False, istext=True, header=False)\n" +"b2a_qp($module, /, data, quotetabs=False, istext=True, header=False)\n" +"--\n" +"\n" "Encode a string using quoted-printable encoding.\n" "\n" "On encoding, when istext is set, newlines are not encoded, and white\n" @@ -447,4 +475,4 @@ exit: return return_value; } -/*[clinic end generated code: output=831a8ccc9f984001 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=68e2bcc6956b6213 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index f810fcf..f54a805 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -3,7 +3,9 @@ preserve [clinic start generated code]*/ PyDoc_STRVAR(zlib_compress__doc__, -"sig=($module, bytes, level=Z_DEFAULT_COMPRESSION)\n" +"compress($module, bytes, level=Z_DEFAULT_COMPRESSION, /)\n" +"--\n" +"\n" "Returns a bytes object containing compressed data.\n" "\n" " bytes\n" @@ -39,7 +41,9 @@ exit: } PyDoc_STRVAR(zlib_decompress__doc__, -"sig=($module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)\n" +"decompress($module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE, /)\n" +"--\n" +"\n" "Returns a bytes object containing the uncompressed data.\n" "\n" " data\n" @@ -78,7 +82,11 @@ exit: } PyDoc_STRVAR(zlib_compressobj__doc__, -"sig=($module, level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" +"compressobj($module, /, level=Z_DEFAULT_COMPRESSION, method=DEFLATED,\n" +" wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL,\n" +" strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" +"--\n" +"\n" "Return a compressor object.\n" "\n" " level\n" @@ -132,7 +140,9 @@ exit: } PyDoc_STRVAR(zlib_decompressobj__doc__, -"sig=($module, wbits=MAX_WBITS, zdict=b\'\')\n" +"decompressobj($module, /, wbits=MAX_WBITS, zdict=b\'\')\n" +"--\n" +"\n" "Return a decompressor object.\n" "\n" " wbits\n" @@ -166,7 +176,9 @@ exit: } PyDoc_STRVAR(zlib_Compress_compress__doc__, -"sig=($self, data)\n" +"compress($self, data, /)\n" +"--\n" +"\n" "Returns a bytes object containing compressed data.\n" "\n" " data\n" @@ -203,7 +215,9 @@ exit: } PyDoc_STRVAR(zlib_Decompress_decompress__doc__, -"sig=($self, data, max_length=0)\n" +"decompress($self, data, max_length=0, /)\n" +"--\n" +"\n" "Return a bytes object containing the decompressed version of the data.\n" "\n" " data\n" @@ -245,7 +259,9 @@ exit: } PyDoc_STRVAR(zlib_Compress_flush__doc__, -"sig=($self, mode=zlib.Z_FINISH)\n" +"flush($self, mode=zlib.Z_FINISH, /)\n" +"--\n" +"\n" "Return a bytes object containing any remaining compressed data.\n" "\n" " mode\n" @@ -279,7 +295,9 @@ exit: #if defined(HAVE_ZLIB_COPY) PyDoc_STRVAR(zlib_Compress_copy__doc__, -"sig=($self)\n" +"copy($self, /)\n" +"--\n" +"\n" "Return a copy of the compression object."); #define ZLIB_COMPRESS_COPY_METHODDEF \ @@ -303,7 +321,9 @@ zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) #if defined(HAVE_ZLIB_COPY) PyDoc_STRVAR(zlib_Decompress_copy__doc__, -"sig=($self)\n" +"copy($self, /)\n" +"--\n" +"\n" "Return a copy of the decompression object."); #define ZLIB_DECOMPRESS_COPY_METHODDEF \ @@ -325,7 +345,9 @@ zlib_Decompress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) #endif /* !defined(ZLIB_DECOMPRESS_COPY_METHODDEF) */ PyDoc_STRVAR(zlib_Decompress_flush__doc__, -"sig=($self, length=zlib.DEF_BUF_SIZE)\n" +"flush($self, length=zlib.DEF_BUF_SIZE, /)\n" +"--\n" +"\n" "Return a bytes object containing any remaining decompressed data.\n" "\n" " length\n" @@ -354,7 +376,9 @@ exit: } PyDoc_STRVAR(zlib_adler32__doc__, -"sig=($module, data, value=1)\n" +"adler32($module, data, value=1, /)\n" +"--\n" +"\n" "Compute an Adler-32 checksum of data.\n" "\n" " value\n" @@ -390,7 +414,9 @@ exit: } PyDoc_STRVAR(zlib_crc32__doc__, -"sig=($module, data, value=0)\n" +"crc32($module, data, value=0, /)\n" +"--\n" +"\n" "Compute a CRC-32 checksum of data.\n" "\n" " value\n" @@ -424,4 +450,4 @@ exit: return return_value; } -/*[clinic end generated code: output=67d3e81eafcfb982 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bc9473721ca7c962 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0646043f..1428220 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2435,7 +2435,9 @@ It's an error to use dir_fd or follow_symlinks when specifying path as [clinic start generated code]*/ PyDoc_STRVAR(os_stat__doc__, -"sig=($module, path, *, dir_fd=None, follow_symlinks=True)\n" +"stat($module, /, path, *, dir_fd=None, follow_symlinks=True)\n" +"--\n" +"\n" "Perform a stat system call on the given path.\n" "\n" " path\n" @@ -2486,7 +2488,7 @@ exit: static PyObject * os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) -/*[clinic end generated code: output=33b6ee92cd1b98de input=5ae155bd475fd20a]*/ +/*[clinic end generated code: output=f1dcaa5e24db9882 input=5ae155bd475fd20a]*/ { return posix_do_stat("stat", path, dir_fd, follow_symlinks); } @@ -2567,7 +2569,10 @@ Note that most operations will use the effective uid/gid, therefore this [clinic start generated code]*/ PyDoc_STRVAR(os_access__doc__, -"sig=($module, path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" +"access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n" +" follow_symlinks=True)\n" +"--\n" +"\n" "Use the real uid/gid to test for access to a path.\n" "\n" " path\n" @@ -2627,7 +2632,7 @@ exit: static PyObject * os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic end generated code: output=33b3fafc61e778e1 input=2e2e7594371f5b7e]*/ +/*[clinic end generated code: output=a6ed4f151be9df0f input=2e2e7594371f5b7e]*/ { PyObject *return_value = NULL; @@ -2723,7 +2728,9 @@ Return the name of the terminal device connected to 'fd'. [clinic start generated code]*/ PyDoc_STRVAR(os_ttyname__doc__, -"sig=($module, fd)\n" +"ttyname($module, fd, /)\n" +"--\n" +"\n" "Return the name of the terminal device connected to \'fd\'.\n" "\n" " fd\n" @@ -2757,7 +2764,7 @@ exit: static char * os_ttyname_impl(PyModuleDef *module, int fd) -/*[clinic end generated code: output=c3083e665d4d11b9 input=5f72ca83e76b3b45]*/ +/*[clinic end generated code: output=cee7bc4cffec01a2 input=5f72ca83e76b3b45]*/ { char *ret; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index c6c4ba2..3253db2 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -129,7 +129,9 @@ not given, ValueError is raised. [clinic start generated code]*/ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__, -"sig=($self, unichr, default=None)\n" +"decimal($self, unichr, default=None, /)\n" +"--\n" +"\n" "Converts a Unicode character into its equivalent decimal value.\n" "\n" "Returns the decimal value assigned to the Unicode character unichr\n" @@ -161,7 +163,7 @@ exit: static PyObject * unicodedata_UCD_decimal_impl(PreviousDBVersion *self, PyUnicodeObject *unichr, PyObject *default_value) -/*[clinic end generated code: output=a3ad5de9393acb2f input=c25c9d2b4de076b1]*/ +/*[clinic end generated code: output=8689669896d293df input=c25c9d2b4de076b1]*/ { int have_old = 0; long rc; diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 181cc51..2df5ac5 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -353,13 +353,13 @@ wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { - return _PyType_GetDocFromInternalDoc(descr->d_method->ml_doc); + return _PyType_GetDocFromInternalDoc(descr->d_method->ml_name, descr->d_method->ml_doc); } static PyObject * method_get_text_signature(PyMethodDescrObject *descr, void *closure) { - return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_doc); + return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_name, descr->d_method->ml_doc); } static PyObject * @@ -466,13 +466,13 @@ static PyGetSetDef getset_getset[] = { static PyObject * wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) { - return _PyType_GetDocFromInternalDoc(descr->d_base->doc); + return _PyType_GetDocFromInternalDoc(descr->d_base->name, descr->d_base->doc); } static PyObject * wrapperdescr_get_text_signature(PyWrapperDescrObject *descr, void *closure) { - return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->doc); + return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->name, descr->d_base->doc); } static PyGetSetDef wrapperdescr_getset[] = { @@ -1151,13 +1151,13 @@ wrapper_name(wrapperobject *wp) static PyObject * wrapper_doc(wrapperobject *wp, void *closure) { - return _PyType_GetDocFromInternalDoc(wp->descr->d_base->doc); + return _PyType_GetDocFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc); } static PyObject * wrapper_text_signature(wrapperobject *wp, void *closure) { - return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->doc); + return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc); } static PyObject * diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2673817..1ccea6e 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1702,7 +1702,9 @@ Returns a new dict with keys from iterable and values equal to value. [clinic start generated code]*/ PyDoc_STRVAR(dict_fromkeys__doc__, -"sig=($type, iterable, value=None)\n" +"fromkeys($type, iterable, value=None, /)\n" +"--\n" +"\n" "Returns a new dict with keys from iterable and values equal to value."); #define DICT_FROMKEYS_METHODDEF \ @@ -1730,7 +1732,7 @@ exit: static PyObject * dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value) -/*[clinic end generated code: output=aff6e583703dbeba input=b85a667f9bf4669d]*/ +/*[clinic end generated code: output=55f8dc0ffa87406f input=b85a667f9bf4669d]*/ { PyObject *it; /* iter(seq) */ PyObject *key; @@ -2209,7 +2211,9 @@ True if D has a key k, else False. [clinic start generated code]*/ PyDoc_STRVAR(dict___contains____doc__, -"sig=($self, key)\n" +"__contains__($self, key, /)\n" +"--\n" +"\n" "True if D has a key k, else False."); #define DICT___CONTAINS___METHODDEF \ @@ -2217,7 +2221,7 @@ PyDoc_STRVAR(dict___contains____doc__, static PyObject * dict___contains__(PyDictObject *self, PyObject *key) -/*[clinic end generated code: output=c654684a6d880281 input=b852b2a19b51ab24]*/ +/*[clinic end generated code: output=3cf3f8aaf2cc5cc3 input=b852b2a19b51ab24]*/ { register PyDictObject *mp = self; Py_hash_t hash; diff --git a/Objects/methodobject.c b/Objects/methodobject.c index ead7443..f2616d4 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -182,13 +182,13 @@ static PyMethodDef meth_methods[] = { static PyObject * meth_get__text_signature__(PyCFunctionObject *m, void *closure) { - return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_doc); + return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc); } static PyObject * meth_get__doc__(PyCFunctionObject *m, void *closure) { - return _PyType_GetDocFromInternalDoc(m->m_ml->ml_doc); + return _PyType_GetDocFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc); } static PyObject * diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 23015b2..b9df44c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -55,51 +55,75 @@ static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); /* - * finds the docstring's introspection signature. + * finds the beginning of the docstring's introspection signature. * if present, returns a pointer pointing to the first '('. * otherwise returns NULL. + * + * doesn't guarantee that the signature is valid, only that it + * has a valid prefix. (the signature must also pass skip_signature.) */ static const char * -find_signature(const char *doc) +find_signature(const char *name, const char *doc) { - if (doc && !strncmp(doc, "sig=(", 5)) - return doc + 4; - return NULL; + const char *dot; + size_t length; + + if (!doc) + return NULL; + + assert(name != NULL); + + /* for dotted names like classes, only use the last component */ + dot = strrchr(name, '.'); + if (dot) + name = dot + 1; + + length = strlen(name); + if (strncmp(doc, name, length)) + return NULL; + doc += length; + if (*doc != '(') + return NULL; + return doc; } +#define SIGNATURE_END_MARKER ")\n--\n\n" +#define SIGNATURE_END_MARKER_LENGTH 6 /* - * skips to the end of the docstring's instrospection signature. + * skips past the end of the docstring's instrospection signature. + * (assumes doc starts with a valid signature prefix.) */ static const char * skip_signature(const char *doc) { - while (*doc && *doc != '\n') + while (*doc) { + if ((*doc == *SIGNATURE_END_MARKER) && + !strncmp(doc, SIGNATURE_END_MARKER, SIGNATURE_END_MARKER_LENGTH)) + return doc + SIGNATURE_END_MARKER_LENGTH; + if ((*doc == '\n') && (doc[1] == '\n')) + return NULL; doc++; - return doc; -} - -static const char * -skip_eols(const char *trace) -{ - while (*trace == '\n') - trace++; - return trace; + } + return NULL; } static const char * -_PyType_DocWithoutSignature(const char *internal_doc) +_PyType_DocWithoutSignature(const char *name, const char *internal_doc) { - const char *signature = find_signature(internal_doc); + const char *doc = find_signature(name, internal_doc); - if (signature) - return skip_eols(skip_signature(signature)); + if (doc) { + doc = skip_signature(doc); + if (doc) + return doc; + } return internal_doc; } PyObject * -_PyType_GetDocFromInternalDoc(const char *internal_doc) +_PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc) { - const char *doc = _PyType_DocWithoutSignature(internal_doc); + const char *doc = _PyType_DocWithoutSignature(name, internal_doc); if (!doc) { Py_INCREF(Py_None); @@ -110,18 +134,26 @@ _PyType_GetDocFromInternalDoc(const char *internal_doc) } PyObject * -_PyType_GetTextSignatureFromInternalDoc(const char *internal_doc) +_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc) { - const char *signature = find_signature(internal_doc); - const char *doc; + const char *start = find_signature(name, internal_doc); + const char *end; - if (!signature) { + if (start) + end = skip_signature(start); + else + end = NULL; + if (!end) { Py_INCREF(Py_None); return Py_None; } - doc = skip_signature(signature); - return PyUnicode_FromStringAndSize(signature, doc - signature); + /* back "end" up until it points just past the final ')' */ + end -= SIGNATURE_END_MARKER_LENGTH - 1; + assert((end - start) >= 2); /* should be "()" at least */ + assert(end[-1] == ')'); + assert(end[0] == '\n'); + return PyUnicode_FromStringAndSize(start, end - start); } unsigned int @@ -699,7 +731,7 @@ type_get_doc(PyTypeObject *type, void *context) { PyObject *result; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) { - return _PyType_GetDocFromInternalDoc(type->tp_doc); + return _PyType_GetDocFromInternalDoc(type->tp_name, type->tp_doc); } result = _PyDict_GetItemId(type->tp_dict, &PyId___doc__); if (result == NULL) { @@ -719,7 +751,7 @@ type_get_doc(PyTypeObject *type, void *context) static PyObject * type_get_text_signature(PyTypeObject *type, void *context) { - return _PyType_GetTextSignatureFromInternalDoc(type->tp_doc); + return _PyType_GetTextSignatureFromInternalDoc(type->tp_name, type->tp_doc); } static int @@ -2597,7 +2629,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) /* need to make a copy of the docstring slot, which usually points to a static string literal */ if (slot->slot == Py_tp_doc) { - const char *old_doc = _PyType_DocWithoutSignature(slot->pfunc); + const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc); size_t len = strlen(old_doc)+1; char *tp_doc = PyObject_MALLOC(len); if (tp_doc == NULL) { @@ -3002,7 +3034,7 @@ static PyMethodDef type_methods[] = { PyDoc_STRVAR(type_doc, /* this text signature cannot be accurate yet. will fix. --larry */ -"sig=(object_or_name, bases, dict)\n" +"type(object_or_name, bases, dict)\n" "type(object) -> the object's type\n" "type(name, bases, dict) -> a new type"); @@ -4198,7 +4230,7 @@ PyTypeObject PyBaseObject_Type = { PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("sig=()\nThe most base type"), /* tp_doc */ + PyDoc_STR("object()\n--\n\nThe most base type"), /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ object_richcompare, /* tp_richcompare */ @@ -4665,7 +4697,8 @@ PyType_Ready(PyTypeObject *type) */ if (_PyDict_GetItemId(type->tp_dict, &PyId___doc__) == NULL) { if (type->tp_doc != NULL) { - const char *old_doc = _PyType_DocWithoutSignature(type->tp_doc); + const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, + type->tp_doc); PyObject *doc = PyUnicode_FromString(old_doc); if (doc == NULL) goto error; @@ -5327,7 +5360,7 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) static struct PyMethodDef tp_new_methoddef[] = { {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("sig=($type, *args, **kwargs)\n" + PyDoc_STR("__new__($type, *args, **kwargs)\n--\n\n" "Create and return a new object. " "See help(type) for accurate signature.")}, {0} @@ -6101,22 +6134,22 @@ typedef struct wrapperbase slotdef; ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) #define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "sig=($self)\n" DOC) + NAME "($self)\n--\n\n" DOC) #define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "sig=($self, value)\nReturn self" DOC "value.") + NAME "($self, value)\n--\n\nReturn self" DOC "value.") #define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "sig=($self, value)\nReturn self" DOC "value.") + NAME "($self, value)\n--\n\nReturn self" DOC "value.") #define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "sig=($self, value)\nReturn value" DOC "self.") + NAME "($self, value)\n--\n\nReturn value" DOC "self.") #define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "sig=($self, value)\n" DOC) + NAME "($self, value)\n--\n\n" DOC) #define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "sig=($self, value)\n" DOC) + NAME "($self, value)\n--\n\n" DOC) static slotdef slotdefs[] = { TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), @@ -6124,51 +6157,51 @@ static slotdef slotdefs[] = { TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, - "sig=($self)\nReturn repr(self)."), + "__repr__($self)\n--\n\nReturn repr(self)."), TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, - "sig=($self)\nReturn hash(self)."), + "__hash__($self)\n--\n\nReturn hash(self)."), FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, - "sig=($self, *args, **kwargs)\nCall self as a function.", + "__call__($self, *args, **kwargs)\n--\n\nCall self as a function.", PyWrapperFlag_KEYWORDS), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, - "sig=($self)\nReturn str(self)."), + "__str__($self)\n--\n\nReturn str(self)."), TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, wrap_binaryfunc, - "sig=($self, name)\nReturn getattr(self, name)."), + "__getattribute__($self, name)\n--\n\nReturn getattr(self, name)."), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, - "sig=($self, name, value)\nImplement setattr(self, name, value)."), + "__setattr__($self, name, value)\n--\n\nImplement setattr(self, name, value)."), TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, - "sig=($self, name)\nImplement delattr(self, name)."), + "__delattr__($self, name)\n--\n\nImplement delattr(self, name)."), TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, - "sig=($self, value)\nReturn selfvalue."), + "__gt__($self, value)\n--\n\nReturn self>value."), TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, - "sig=($self, value)\nReturn self>=value."), + "__ge__=($self, value)\n--\n\nReturn self>=value."), TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, - "sig=($self)\nImplement iter(self)."), + "__iter__($self)\n--\n\nImplement iter(self)."), TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next, - "sig=($self)\nImplement next(self)."), + "__next__($self)\n--\n\nImplement next(self)."), TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, - "sig=($self, instance, owner)\nReturn an attribute of instance, which is of type owner."), + "__get__($self, instance, owner)\n--\n\nReturn an attribute of instance, which is of type owner."), TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, - "sig=($self, instance, value)\nSet an attribute of instance to value."), + "__set__($self, instance, value)\n--\n\nSet an attribute of instance to value."), TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set, wrap_descr_delete, - "sig=(instance)\nDelete an attribute of instance."), + "__delete__(instance)\n--\n\nDelete an attribute of instance."), FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, - "sig=($self, *args, **kwargs)\n" + "__init__($self, *args, **kwargs)\n--\n\n" "Initialize self. See help(type(self)) for accurate signature.", PyWrapperFlag_KEYWORDS), TPSLOT("__new__", tp_new, slot_tp_new, NULL, - "sig=(type, *args, **kwargs)\n" + "__new__(type, *args, **kwargs)\n--\n\n" "Create and return new object. See help(type) for accurate signature."), TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), @@ -6193,9 +6226,9 @@ static slotdef slotdefs[] = { RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, "Return divmod(value, self)."), NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, - "sig=($self, value, mod=None)\nReturn pow(self, value, mod)."), + "__pow__($self, value, mod=None)\n--\n\nReturn pow(self, value, mod)."), NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, - "sig=($self, value, mod=None)\nReturn pow(value, self, mod)."), + "__rpow__($self, value, mod=None)\n--\n\nReturn pow(value, self, mod)."), UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-self"), UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+self"), UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, @@ -6246,48 +6279,48 @@ static slotdef slotdefs[] = { IBSLOT("__itruediv__", nb_inplace_true_divide, slot_nb_inplace_true_divide, wrap_binaryfunc, "/"), NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, - "sig=($self)\n" + "__index__($self)\n--\n\n" "Return self converted to an integer, if self is suitable" "for use as an index into a list."), MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, - "sig=($self)\nReturn len(self)."), + "__len__($self)\n--\n\nReturn len(self)."), MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_binaryfunc, - "sig=($self, key)\nReturn self[key]."), + "__getitem__($self, key)\n--\n\nReturn self[key]."), MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_objobjargproc, - "sig=($self, key, value)\nSet self[key] to value."), + "__setitem__($self, key, value)\n--\n\nSet self[key] to value."), MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_delitem, - "sig=(key)\nDelete self[key]."), + "__delitem__(key)\n--\n\nDelete self[key]."), SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, - "sig=($self)\nReturn len(self)."), + "__len__($self)\n--\n\nReturn len(self)."), /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. The logic in abstract.c always falls back to nb_add/nb_multiply in this case. Defining both the nb_* and the sq_* slots to call the user-defined methods has unexpected side-effects, as shown by test_descr.notimplemented() */ SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, - "sig=($self, value)\nReturn self+value."), + "__add__($self, value)\n--\n\nReturn self+value."), SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, - "sig=($self, value)\nReturn self*value.n"), + "__mul__($self, value)\n--\n\nReturn self*value.n"), SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, - "sig=($self, value)\nReturn self*value."), + "__rmul__($self, value)\n--\n\nReturn self*value."), SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, - "sig=($self, key)\nReturn self[key]."), + "__getitem__($self, key)\n--\n\nReturn self[key]."), SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, - "sig=($self, key, value)\nSet self[key] to value."), + "__setitem__($self, key, value)\n--\n\nSet self[key] to value."), SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, - "sig=($self, key)\nDelete self[key]."), + "__delitem__($self, key)\n--\n\nDelete self[key]."), SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, - "sig=($self, key)\nReturn key in self."), + "__contains__($self, key)\n--\n\nReturn key in self."), SQSLOT("__iadd__", sq_inplace_concat, NULL, wrap_binaryfunc, - "sig=($self, value)\nImplement self+=value."), + "__iadd__($self, value)\n--\n\nImplement self+=value."), SQSLOT("__imul__", sq_inplace_repeat, NULL, wrap_indexargfunc, - "sig=($self, value)\nImplement self*=value."), + "__imul__($self, value)\n--\n\nImplement self*=value."), {NULL} }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7a1aa16..eae4bc5 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12893,7 +12893,9 @@ must be a string, whose characters will be mapped to None in the result. [clinic start generated code]*/ PyDoc_STRVAR(unicode_maketrans__doc__, -"sig=(x, y=None, z=None)\n" +"maketrans(x, y=None, z=None, /)\n" +"--\n" +"\n" "Return a translation table usable for str.translate().\n" "\n" "If there is only one argument, it must be a dictionary mapping Unicode\n" @@ -12930,7 +12932,7 @@ exit: static PyObject * unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) -/*[clinic end generated code: output=ca001ac83ed32269 input=7bfbf529a293c6c5]*/ +/*[clinic end generated code: output=566edf630f77436a input=7bfbf529a293c6c5]*/ { PyObject *new = NULL, *key, *value; Py_ssize_t i = 0; diff --git a/Python/import.c b/Python/import.c index 5e5355d..001d745 100644 --- a/Python/import.c +++ b/Python/import.c @@ -232,7 +232,9 @@ On platforms without threads, return False. [clinic start generated code]*/ PyDoc_STRVAR(_imp_lock_held__doc__, -"sig=($module)\n" +"lock_held($module, /)\n" +"--\n" +"\n" "Return True if the import lock is currently held, else False.\n" "\n" "On platforms without threads, return False."); @@ -251,7 +253,7 @@ _imp_lock_held(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) static PyObject * _imp_lock_held_impl(PyModuleDef *module) -/*[clinic end generated code: output=5ce46d12a8e4c469 input=9b088f9b217d9bdf]*/ +/*[clinic end generated code: output=dae65674966baa65 input=9b088f9b217d9bdf]*/ { #ifdef WITH_THREAD return PyBool_FromLong(import_lock_thread != -1); @@ -270,7 +272,9 @@ modules. On platforms without threads, this function does nothing. [clinic start generated code]*/ PyDoc_STRVAR(_imp_acquire_lock__doc__, -"sig=($module)\n" +"acquire_lock($module, /)\n" +"--\n" +"\n" "Acquires the interpreter\'s import lock for the current thread.\n" "\n" "This lock should be used by import hooks to ensure thread-safety when importing\n" @@ -290,7 +294,7 @@ _imp_acquire_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) static PyObject * _imp_acquire_lock_impl(PyModuleDef *module) -/*[clinic end generated code: output=b0dd6a132ad25961 input=4a2d4381866d5fdc]*/ +/*[clinic end generated code: output=478f1fa089fdb9a4 input=4a2d4381866d5fdc]*/ { #ifdef WITH_THREAD _PyImport_AcquireLock(); @@ -308,7 +312,9 @@ On platforms without threads, this function does nothing. [clinic start generated code]*/ PyDoc_STRVAR(_imp_release_lock__doc__, -"sig=($module)\n" +"release_lock($module, /)\n" +"--\n" +"\n" "Release the interpreter\'s import lock.\n" "\n" "On platforms without threads, this function does nothing."); @@ -327,7 +333,7 @@ _imp_release_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) static PyObject * _imp_release_lock_impl(PyModuleDef *module) -/*[clinic end generated code: output=b1e6e9d723cf5f89 input=934fb11516dd778b]*/ +/*[clinic end generated code: output=36c77a6832fdafd4 input=934fb11516dd778b]*/ { #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { @@ -927,7 +933,9 @@ Changes code.co_filename to specify the passed-in file path. [clinic start generated code]*/ PyDoc_STRVAR(_imp__fix_co_filename__doc__, -"sig=($module, code, path)\n" +"_fix_co_filename($module, code, path, /)\n" +"--\n" +"\n" "Changes code.co_filename to specify the passed-in file path.\n" "\n" " code\n" @@ -960,7 +968,7 @@ exit: static PyObject * _imp__fix_co_filename_impl(PyModuleDef *module, PyCodeObject *code, PyObject *path) -/*[clinic end generated code: output=3fe5b5a1b0d497df input=895ba50e78b82f05]*/ +/*[clinic end generated code: output=6b4b1edeb0d55c5d input=895ba50e78b82f05]*/ { update_compiled_module(code, path); @@ -1823,7 +1831,9 @@ Returns the list of file suffixes used to identify extension modules. [clinic start generated code]*/ PyDoc_STRVAR(_imp_extension_suffixes__doc__, -"sig=($module)\n" +"extension_suffixes($module, /)\n" +"--\n" +"\n" "Returns the list of file suffixes used to identify extension modules."); #define _IMP_EXTENSION_SUFFIXES_METHODDEF \ @@ -1840,7 +1850,7 @@ _imp_extension_suffixes(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) static PyObject * _imp_extension_suffixes_impl(PyModuleDef *module) -/*[clinic end generated code: output=c1bcfbddabefa00a input=ecdeeecfcb6f839e]*/ +/*[clinic end generated code: output=bb30a2438167798c input=ecdeeecfcb6f839e]*/ { PyObject *list; const char *suffix; @@ -1878,7 +1888,9 @@ Initializes a built-in module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_builtin__doc__, -"sig=($module, name)\n" +"init_builtin($module, name, /)\n" +"--\n" +"\n" "Initializes a built-in module."); #define _IMP_INIT_BUILTIN_METHODDEF \ @@ -1905,7 +1917,7 @@ exit: static PyObject * _imp_init_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=02437efd4668f53e input=f934d2231ec52a2e]*/ +/*[clinic end generated code: output=a0244948a43f8e26 input=f934d2231ec52a2e]*/ { int ret; PyObject *m; @@ -1932,7 +1944,9 @@ Initializes a frozen module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_frozen__doc__, -"sig=($module, name)\n" +"init_frozen($module, name, /)\n" +"--\n" +"\n" "Initializes a frozen module."); #define _IMP_INIT_FROZEN_METHODDEF \ @@ -1959,7 +1973,7 @@ exit: static PyObject * _imp_init_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=20cea421af513afe input=13019adfc04f3fb3]*/ +/*[clinic end generated code: output=e4bc2bff296f8f22 input=13019adfc04f3fb3]*/ { int ret; PyObject *m; @@ -1986,7 +2000,9 @@ Create a code object for a frozen module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_get_frozen_object__doc__, -"sig=($module, name)\n" +"get_frozen_object($module, name, /)\n" +"--\n" +"\n" "Create a code object for a frozen module."); #define _IMP_GET_FROZEN_OBJECT_METHODDEF \ @@ -2013,7 +2029,7 @@ exit: static PyObject * _imp_get_frozen_object_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=f00d01ae30ec842f input=ed689bc05358fdbd]*/ +/*[clinic end generated code: output=4089ec702a9d70c5 input=ed689bc05358fdbd]*/ { return get_frozen_object(name); } @@ -2028,7 +2044,9 @@ Returns True if the module name is of a frozen package. [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen_package__doc__, -"sig=($module, name)\n" +"is_frozen_package($module, name, /)\n" +"--\n" +"\n" "Returns True if the module name is of a frozen package."); #define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ @@ -2055,7 +2073,7 @@ exit: static PyObject * _imp_is_frozen_package_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=35c78f2448c6fcff input=81b6cdecd080fbb8]*/ +/*[clinic end generated code: output=86aab14dcd4b959b input=81b6cdecd080fbb8]*/ { return is_frozen_package(name); } @@ -2070,7 +2088,9 @@ Returns True if the module name corresponds to a built-in module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_builtin__doc__, -"sig=($module, name)\n" +"is_builtin($module, name, /)\n" +"--\n" +"\n" "Returns True if the module name corresponds to a built-in module."); #define _IMP_IS_BUILTIN_METHODDEF \ @@ -2097,7 +2117,7 @@ exit: static PyObject * _imp_is_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=641689f833347f66 input=86befdac021dd1c7]*/ +/*[clinic end generated code: output=d5847f8cac50946e input=86befdac021dd1c7]*/ { return PyLong_FromLong(is_builtin(name)); } @@ -2112,7 +2132,9 @@ Returns True if the module name corresponds to a frozen module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen__doc__, -"sig=($module, name)\n" +"is_frozen($module, name, /)\n" +"--\n" +"\n" "Returns True if the module name corresponds to a frozen module."); #define _IMP_IS_FROZEN_METHODDEF \ @@ -2139,7 +2161,7 @@ exit: static PyObject * _imp_is_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: output=0f80c7a3f283a686 input=7301dbca1897d66b]*/ +/*[clinic end generated code: output=6691af884ba4987d input=7301dbca1897d66b]*/ { const struct _frozen *p; @@ -2161,7 +2183,9 @@ Loads an extension module. [clinic start generated code]*/ PyDoc_STRVAR(_imp_load_dynamic__doc__, -"sig=($module, name, path, file=None)\n" +"load_dynamic($module, name, path, file=None, /)\n" +"--\n" +"\n" "Loads an extension module."); #define _IMP_LOAD_DYNAMIC_METHODDEF \ @@ -2190,7 +2214,7 @@ exit: static PyObject * _imp_load_dynamic_impl(PyModuleDef *module, PyObject *name, PyObject *path, PyObject *file) -/*[clinic end generated code: output=8f33f48dc6252948 input=af64f06e4bad3526]*/ +/*[clinic end generated code: output=81d11a1fbd1ea0a8 input=af64f06e4bad3526]*/ { PyObject *mod; FILE *fp; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index e7e45c5..68a1436 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1123,10 +1123,12 @@ def OverrideStdioWith(stdout): sys.stdout = saved_stdout -def create_regex(before, after, word=True): +def create_regex(before, after, word=True, whole_line=True): """Create an re object for matching marker lines.""" group_re = "\w+" if word else ".+" - pattern = r'^{}({}){}$' + pattern = r'{}({}){}' + if whole_line: + pattern = '^' + pattern + '$' pattern = pattern.format(re.escape(before), group_re, re.escape(after)) return re.compile(pattern) @@ -1218,6 +1220,7 @@ class BlockParser: self.language = language before, _, after = language.start_line.partition('{dsl_name}') assert _ == '{dsl_name}' + self.find_start_re = create_regex(before, after, whole_line=False) self.start_re = create_regex(before, after) self.verify = verify self.last_checksum_re = None @@ -1735,11 +1738,15 @@ def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf except KeyError: fail("Can't identify file type for file " + repr(filename)) - clinic = Clinic(language, force=force, verify=verify, filename=filename) - with open(filename, 'r', encoding=encoding) as f: raw = f.read() + # exit quickly if there are no clinic markers in the file + find_start_re = BlockParser("", language).find_start_re + if not find_start_re.search(raw): + return + + clinic = Clinic(language, force=force, verify=verify, filename=filename) cooked = clinic.parse(raw) if (cooked == raw) and not force: return @@ -1897,7 +1904,7 @@ class Function: full_name=None, return_converter, return_annotation=_empty, docstring=None, kind=CALLABLE, coexist=False, - suppress_signature=False): + docstring_only=False): self.parameters = parameters or collections.OrderedDict() self.return_annotation = return_annotation self.name = name @@ -1911,7 +1918,11 @@ class Function: self.kind = kind self.coexist = coexist self.self_converter = None - self.suppress_signature = suppress_signature + # docstring_only means "don't generate a machine-readable + # signature, just a normal docstring". it's True for + # functions with optional groups because we can't represent + # those accurately with inspect.Signature in 3.4. + self.docstring_only = docstring_only self.rendered_parameters = None @@ -1951,7 +1962,7 @@ class Function: 'full_name': self.full_name, 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, - 'suppress_signature': self.suppress_signature, + 'docstring_only': self.docstring_only, } kwargs.update(overrides) f = Function(**kwargs) @@ -1987,6 +1998,9 @@ class Parameter: def is_keyword_only(self): return self.kind == inspect.Parameter.KEYWORD_ONLY + def is_positional_only(self): + return self.kind == inspect.Parameter.POSITIONAL_ONLY + def copy(self, **overrides): kwargs = { 'name': self.name, 'kind': self.kind, 'default':self.default, @@ -2929,7 +2943,7 @@ class IndentStack: Returns the length of the line's margin. """ if '\t' in line: - fail('Tab characters are illegal in the Clinic DSL.') + fail('Tab characters are illegal in the Argument Clinic DSL.') stripped = line.lstrip() if not len(stripped): # we can't tell anything from an empty line @@ -3694,7 +3708,7 @@ class DSLParser: else: fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") self.group += 1 - self.function.suppress_signature = True + self.function.docstring_only = True elif symbol == ']': if not self.group: fail("Function " + self.function.name + " has a ] without a matching [.") @@ -3783,21 +3797,20 @@ class DSLParser: # don't render a docstring at all, no signature, nothing. return f.docstring - add, output = text_accumulator() + text, add, output = _text_accumulator() parameters = f.render_parameters ## ## docstring first line ## - if not f.suppress_signature: - add('sig=') + if new_or_init: + # classes get *just* the name of the class + # not __new__, not __init__, and not module.classname + assert f.cls + add(f.cls.name) else: - if new_or_init: - assert f.cls - add(f.cls.name) - else: - add(f.name) + add(f.name) add('(') # populate "right_bracket_count" field for every parameter @@ -3834,53 +3847,105 @@ class DSLParser: right_bracket_count -= 1 return s + need_slash = False + added_slash = False + need_a_trailing_slash = False + + # we only need a trailing slash: + # * if this is not a "docstring_only" signature + # * and if the last *shown* parameter is + # positional only + if not f.docstring_only: + for p in reversed(parameters): + if not p.converter.show_in_signature: + continue + if p.is_positional_only(): + need_a_trailing_slash = True + break + + added_star = False - add_comma = False + + first_parameter = True + last_p = parameters[-1] + line_length = len(''.join(text)) + indent = " " * line_length + def add_parameter(text): + nonlocal line_length + nonlocal first_parameter + if first_parameter: + s = text + first_parameter = False + else: + s = ' ' + text + if line_length + len(s) >= 72: + add('\n') + add(indent) + line_length = len(indent) + s = text + line_length += len(s) + add(s) for p in parameters: if not p.converter.show_in_signature: continue - assert p.name + is_self = isinstance(p.converter, self_converter) + if is_self and f.docstring_only: + # this isn't a real machine-parsable signature, + # so let's not print the "self" parameter + continue + + if p.is_positional_only(): + need_slash = not f.docstring_only + elif need_slash and not (added_slash or p.is_positional_only()): + added_slash = True + add_parameter('/,') + if p.is_keyword_only() and not added_star: added_star = True - if add_comma: - add(', ') - add('*') - add_comma = True + add_parameter('*,') - name = p.converter.signature_name or p.name + p_add, p_output = text_accumulator() + p_add(fix_right_bracket_count(p.right_bracket_count)) - a = [] if isinstance(p.converter, self_converter): - if f.suppress_signature: - continue - else: - # annotate first parameter as being a "self". - # - # if inspect.Signature gets this function, and it's already bound, - # the self parameter will be stripped off. - # - # if it's not bound, it should be marked as positional-only. - a.append('$') - a.append(name) - else: - a.append(name) + # annotate first parameter as being a "self". + # + # if inspect.Signature gets this function, + # and it's already bound, the self parameter + # will be stripped off. + # + # if it's not bound, it should be marked + # as positional-only. + # + # note: we don't print "self" for __init__, + # because this isn't actually the signature + # for __init__. (it can't be, __init__ doesn't + # have a docstring.) if this is an __init__ + # (or __new__), then this signature is for + # calling the class to contruct a new instance. + p_add('$') + + name = p.converter.signature_name or p.name + p_add(name) + if p.converter.is_optional(): - a.append('=') + p_add('=') value = p.converter.py_default if not value: value = repr(p.converter.default) - a.append(value) - s = fix_right_bracket_count(p.right_bracket_count) - s += "".join(a) - if add_comma: - add(', ') - add(s) - add_comma = True + p_add(value) + + if (p != last_p) or need_a_trailing_slash: + p_add(',') + + add_parameter(p_output()) add(fix_right_bracket_count(0)) + if need_a_trailing_slash: + add_parameter('/') add(')') # PEP 8 says: @@ -3896,6 +3961,9 @@ class DSLParser: # add(' -> ') # add(f.return_converter.py_default) + if not f.docstring_only: + add("\n--\n") + docstring_first_line = output() # now fix up the places where the brackets look wrong diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py index 67b0eb9..cd21000 100644 --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -359,7 +359,9 @@ os.stat as os_stat_fn Perform a stat system call on the given path.""") self.assertEqual(""" -sig=($module, path) +stat($module, /, path) +-- + Perform a stat system call on the given path. path @@ -379,7 +381,9 @@ This is the documentation for foo. Okay, we're done here. """) self.assertEqual(""" -sig=($module, x, y) +bar($module, /, x, y) +-- + This is the documentation for foo. x @@ -395,7 +399,7 @@ os.stat path: str This/used to break Clinic! """) - self.assertEqual("sig=($module, path)\n\nThis/used to break Clinic!", function.docstring) + self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring) def test_c_name(self): function = self.parse_function("module os\nos.stat as os_stat_fn") @@ -504,7 +508,8 @@ curses.imaginary self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) self.assertEqual(function.docstring.strip(), """ -imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, attr6]]) +imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, + attr6]]) y1 @@ -624,9 +629,23 @@ foo.bar Docstring """) - self.assertEqual("sig=($module)\nDocstring", function.docstring) + self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring) self.assertEqual(1, len(function.parameters)) # self! + def test_init_with_no_parameters(self): + function = self.parse_function(""" +module foo +class foo.Bar "unused" "notneeded" +foo.Bar.__init__ + +Docstring + +""", signatures_in_block=3, function_index=2) + # self is not in the signature + self.assertEqual("Bar()\n--\n\nDocstring", function.docstring) + # but it *is* a parameter + self.assertEqual(1, len(function.parameters)) + def test_illegal_module_line(self): self.parse_function_should_fail(""" module foo @@ -719,7 +738,9 @@ foo.bar Not at column 0! """) self.assertEqual(""" -sig=($module, x, *, y) +bar($module, /, x, *, y) +-- + Not at column 0! x @@ -733,7 +754,7 @@ os.stat path: str This/used to break Clinic! """) - self.assertEqual("sig=($module, path)\nThis/used to break Clinic!", function.docstring) + self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring) def test_directive(self): c = FakeClinic() @@ -756,13 +777,13 @@ This/used to break Clinic! parser.parse(block) return block - def parse_function(self, text): + def parse_function(self, text, signatures_in_block=2, function_index=1): block = self.parse(text) s = block.signatures - self.assertEqual(len(s), 2) + self.assertEqual(len(s), signatures_in_block) assert isinstance(s[0], clinic.Module) - assert isinstance(s[1], clinic.Function) - return s[1] + assert isinstance(s[function_index], clinic.Function) + return s[function_index] def test_scaffolding(self): # test repr on special values -- cgit v0.12