diff --git a/Include/object.h b/Include/object.h index 68ca7b446aa..7584d4cdde1 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 7a2739f8042..017a7e85b5e 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 + clean_signature, self_parameter, last_positional_only = \ + _signature_strip_non_python_syntax(s) - first_parameter_is_self = s.startswith("($") - if first_parameter_is_self: - s = '(' + s[2:] - - 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 10e8c4e216a..ba7c38db27c 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 862ef8252f6..3f204191bf7 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 9ed7e7313dc..20cf65610c0 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 7531c2fc991..da44ef34eea 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 80fa4976311..fce6bbf3fa5 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 abeb799f091..93ea4161a7f 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 712e6eb54b4..fee388f5967 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 4dcaec1c31f..d4d1d9d0eb3 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 260e53d637f..9e817878453 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 6451dba2245..da589314ea5 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 98f9a1b88d7..8a201a08de0 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 184889185cf..c1ad8824af7 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 9ef469dc400..a20a61e6f58 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 92d13b091df..40ef5e2dc4d 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 e4ef36c9600..5247180a413 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 f810fcf81b3..f54a8053770 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 0646043f7fc..1428220cf61 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 c6c4ba2c71d..3253db21f1b 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 181cc51f0f9..2df5ac5f731 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 2673817b561..1ccea6ef2aa 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 ead7443cba7..f2616d4ef0e 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 23015b2c804..b9df44cace8 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; + } + return NULL; } static const char * -skip_eols(const char *trace) +_PyType_DocWithoutSignature(const char *name, const char *internal_doc) { - while (*trace == '\n') - trace++; - return trace; -} + const char *doc = find_signature(name, internal_doc); -static const char * -_PyType_DocWithoutSignature(const char *internal_doc) -{ - const char *signature = find_signature(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 7a1aa161fbe..eae4bc5bff6 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 5e5355d4852..001d745783f 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 e7e45c58462..68a14361fd2 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('*,') + + p_add, p_output = text_accumulator() + p_add(fix_right_bracket_count(p.right_bracket_count)) + + if isinstance(p.converter, self_converter): + # 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) - 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) 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 67b0eb9db40..cd21000c050 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