Issue #19674: inspect.signature() now produces a correct signature

for some builtins.
This commit is contained in:
Larry Hastings 2013-11-23 15:37:55 -08:00
parent 7fa6e1aeea
commit 44e2eaab54
18 changed files with 343 additions and 136 deletions

View File

@ -31,6 +31,7 @@ Here are some of the useful functions provided by this module:
__author__ = ('Ka-Ping Yee <ping@lfw.org>',
'Yury Selivanov <yselivanov@sprymix.com>')
import ast
import importlib.machinery
import itertools
import linecache
@ -1461,6 +1462,9 @@ def signature(obj):
if isinstance(obj, types.FunctionType):
return Signature.from_function(obj)
if isinstance(obj, types.BuiltinFunctionType):
return Signature.from_builtin(obj)
if isinstance(obj, functools.partial):
sig = signature(obj.func)
@ -1942,6 +1946,64 @@ class Signature:
return_annotation=annotations.get('return', _empty),
__validate_parameters__=False)
@classmethod
def from_builtin(cls, func):
s = getattr(func, "__text_signature__", None)
if not s:
return None
if s.endswith("/)"):
kind = Parameter.POSITIONAL_ONLY
s = s[:-2] + ')'
else:
kind = Parameter.POSITIONAL_OR_KEYWORD
s = "def foo" + s + ": pass"
try:
module = ast.parse(s)
except SyntaxError:
return None
if not isinstance(module, ast.Module):
return None
# ast.FunctionDef
f = module.body[0]
parameters = []
empty = Parameter.empty
def p(name_node, default_node, default=empty):
name = name_node.arg
if isinstance(default_node, ast.Num):
default = default.n
elif isinstance(default_node, ast.NameConstant):
default = default_node.value
parameters.append(Parameter(name, kind, default=default, annotation=empty))
# non-keyword-only parameters
for name, default in reversed(list(itertools.zip_longest(reversed(f.args.args), reversed(f.args.defaults), fillvalue=None))):
p(name, default)
# *args
if f.args.vararg:
kind = Parameter.VAR_POSITIONAL
p(f.args.vararg, empty)
# keyword-only arguments
kind = Parameter.KEYWORD_ONLY
for name, default in zip(f.args.kwonlyargs, f.args.kw_defaults):
p(name, default)
# **kwargs
if f.args.kwarg:
kind = Parameter.VAR_KEYWORD
p(f.args.kwarg, empty)
return cls(parameters, return_annotation=cls.empty)
@property
def parameters(self):
return self._parameters

View File

@ -916,20 +916,18 @@ class HTMLDoc(Doc):
reallink = realname
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
anchor, name, reallink)
if inspect.isfunction(object):
args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
inspect.getfullargspec(object)
argspec = inspect.formatargspec(
args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
formatvalue=self.formatvalue,
formatannotation=inspect.formatannotationrelativeto(object))
if realname == '<lambda>':
title = '<strong>%s</strong> <em>lambda</em> ' % name
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
else:
argspec = None
if inspect.isfunction(object) or inspect.isbuiltin(object):
signature = inspect.signature(object)
if signature:
argspec = str(signature)
if realname == '<lambda>':
title = '<strong>%s</strong> <em>lambda</em> ' % name
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
decl = title + argspec + (note and self.grey(
@ -1313,20 +1311,18 @@ location listed above.
cl.__dict__[realname] is object):
skipdocs = 1
title = self.bold(name) + ' = ' + realname
if inspect.isfunction(object):
args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
inspect.getfullargspec(object)
argspec = inspect.formatargspec(
args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
formatvalue=self.formatvalue,
formatannotation=inspect.formatannotationrelativeto(object))
if realname == '<lambda>':
title = self.bold(name) + ' lambda '
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
else:
argspec = None
if inspect.isfunction(object) or inspect.isbuiltin(object):
signature = inspect.signature(object)
if signature:
argspec = str(signature)
if realname == '<lambda>':
title = self.bold(name) + ' lambda '
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
decl = title + argspec + note

View File

@ -109,6 +109,35 @@ class CAPITest(unittest.TestCase):
self.assertRaises(TypeError, _posixsubprocess.fork_exec,
Z(),[b'1'],3,[1, 2],5,6,7,8,9,10,11,12,13,14,15,16,17)
def test_docstring_signature_parsing(self):
self.assertEqual(_testcapi.no_docstring.__doc__, None)
self.assertEqual(_testcapi.no_docstring.__text_signature__, None)
self.assertEqual(_testcapi.docstring_empty.__doc__, "")
self.assertEqual(_testcapi.docstring_empty.__text_signature__, None)
self.assertEqual(_testcapi.docstring_no_signature.__doc__,
"This docstring has no signature.")
self.assertEqual(_testcapi.docstring_no_signature.__text_signature__, None)
self.assertEqual(_testcapi.docstring_with_invalid_signature.__doc__,
"docstring_with_invalid_signature (boo)\n"
"\n"
"This docstring has an invalid signature."
)
self.assertEqual(_testcapi.docstring_with_invalid_signature.__text_signature__, None)
self.assertEqual(_testcapi.docstring_with_signature.__doc__,
"This docstring has a valid signature.")
self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "(sig)")
self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__doc__,
"This docstring has a valid signature and some extra newlines.")
self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__,
"(parameter)")
@unittest.skipUnless(threading, 'Threading required for this test.')
class TestPendingCalls(unittest.TestCase):

View File

@ -1588,10 +1588,9 @@ class TestSignatureObject(unittest.TestCase):
with self.assertRaisesRegex(ValueError, 'not supported by signature'):
# support for 'method-wrapper'
inspect.signature(min.__call__)
with self.assertRaisesRegex(ValueError,
'no signature found for builtin function'):
# support for 'method-wrapper'
inspect.signature(min)
self.assertEqual(inspect.signature(min), None)
signature = inspect.signature(os.stat)
self.assertTrue(isinstance(signature, inspect.Signature))
def test_signature_on_non_function(self):
with self.assertRaisesRegex(TypeError, 'is not a callable object'):

View File

@ -68,6 +68,9 @@ Core and Builtins
Library
-------
- Issue #19674: inspect.signature() now produces a correct signature
for some builtins.
- Issue #19722: Added opcode.stack_effect(), which
computes the stack effect of bytecode instructions.

View File

@ -134,6 +134,12 @@ typedef chtype attr_t; /* No attr_t type is available */
#define STRICT_SYSV_CURSES
#endif
/*[clinic]
module curses
class curses.window
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/* Definition of exception curses.error */
static PyObject *PyCursesError;
@ -550,8 +556,6 @@ PyCursesWindow_Dealloc(PyCursesWindowObject *wo)
/* Addch, Addstr, Addnstr */
/*[clinic]
module curses
class curses.window
curses.window.addch
@ -580,9 +584,9 @@ current settings for the window object.
[clinic]*/
PyDoc_STRVAR(curses_window_addch__doc__,
"addch([x, y,] ch, [attr])\n"
"Paint character ch at (y, x) with attributes attr.\n"
"\n"
"curses.window.addch([x, y,] ch, [attr])\n"
" x\n"
" X-coordinate.\n"
" y\n"
@ -646,7 +650,7 @@ curses_window_addch(PyObject *self, PyObject *args)
static PyObject *
curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr)
/*[clinic checksum: 094d012af1019387c0219a9c0bc76e90729c833f]*/
/*[clinic checksum: 44ed958b891cde91205e584c766e048f3999714f]*/
{
PyCursesWindowObject *cwself = (PyCursesWindowObject *)self;
int coordinates_group = group_left_1;

View File

@ -16,6 +16,12 @@
#include "datetime.h"
#undef Py_BUILD_CORE
/*[clinic]
module datetime
class datetime.datetime
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/* We require that C int be at least 32 bits, and use int virtually
* everywhere. In just a few cases we use a temp long, where a Python
* API returns a C long. In such cases, we have to ensure that the
@ -4140,8 +4146,6 @@ datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo)
}
/*[clinic]
module datetime
class datetime.datetime
@classmethod
datetime.datetime.now
@ -4155,9 +4159,9 @@ If no tz is specified, uses local timezone.
[clinic]*/
PyDoc_STRVAR(datetime_datetime_now__doc__,
"now(tz=None)\n"
"Returns new datetime object representing current time local to tz.\n"
"\n"
"datetime.datetime.now(tz=None)\n"
" tz\n"
" Timezone object.\n"
"\n"
@ -4188,7 +4192,7 @@ exit:
static PyObject *
datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz)
/*[clinic checksum: 5e61647d5d1feaf1ab096c5406ccea17bb7b061c]*/
/*[clinic checksum: ca3d26a423b3f633b260c7622e303f0915a96f7c]*/
{
PyObject *self;

View File

@ -28,6 +28,12 @@ static char *which_dbm = "Berkeley DB";
#error "No ndbm.h available!"
#endif
/*[clinic]
module dbm
class dbm.dbm
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
typedef struct {
PyObject_HEAD
int di_size; /* -1 means recompute */
@ -43,12 +49,6 @@ static PyTypeObject Dbmtype;
static PyObject *DbmError;
/*[clinic]
module dbm
class dbm.dbm
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/*[python]
class dbmobject_converter(self_converter):
type = "dbmobject *"
@ -278,9 +278,8 @@ Return the value for key if present, otherwise default.
[clinic]*/
PyDoc_STRVAR(dbm_dbm_get__doc__,
"Return the value for key if present, otherwise default.\n"
"\n"
"dbm.dbm.get(key, [default])");
"get(key, [default])\n"
"Return the value for key if present, otherwise default.");
#define DBM_DBM_GET_METHODDEF \
{"get", (PyCFunction)dbm_dbm_get, METH_VARARGS, dbm_dbm_get__doc__},
@ -318,7 +317,7 @@ dbm_dbm_get(PyObject *self, PyObject *args)
static PyObject *
dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value)
/*[clinic checksum: 5b4265e66568f163ef0fc7efec09410eaf793508]*/
/*[clinic checksum: 28cf8928811bde51e535d67ae98ea039d79df717]*/
{
datum dbm_key, val;
@ -461,9 +460,9 @@ Return a database object.
[clinic]*/
PyDoc_STRVAR(dbmopen__doc__,
"open(filename, flags=\'r\', mode=0o666)\n"
"Return a database object.\n"
"\n"
"dbm.open(filename, flags=\'r\', mode=0o666)\n"
" filename\n"
" The filename to open.\n"
" flags\n"
@ -498,7 +497,7 @@ exit:
static PyObject *
dbmopen_impl(PyModuleDef *module, const char *filename, const char *flags, int mode)
/*[clinic checksum: c1f2036017ec36a43ac6f59893732751e67c19d5]*/
/*[clinic checksum: fb265f75641553ccd963f84c143b35c11f9121fc]*/
{
int iflags;

View File

@ -1,11 +1,13 @@
#include "Python.h"
#include "opcode.h"
/*[clinic]
module _opcode
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/*[clinic]
module _opcode
_opcode.stack_effect -> int
opcode: int
@ -19,18 +21,17 @@ Compute the stack effect of the opcode.
[clinic]*/
PyDoc_STRVAR(_opcode_stack_effect__doc__,
"Compute the stack effect of the opcode.\n"
"\n"
"_opcode.stack_effect(opcode, [oparg])");
"stack_effect(opcode, [oparg])\n"
"Compute the stack effect of the opcode.");
#define _OPCODE_STACK_EFFECT_METHODDEF \
{"stack_effect", (PyCFunction)_opcode_stack_effect, METH_VARARGS, _opcode_stack_effect__doc__},
static int
_opcode_stack_effect_impl(PyObject *module, int opcode, int group_right_1, int oparg);
_opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg);
static PyObject *
_opcode_stack_effect(PyObject *module, PyObject *args)
_opcode_stack_effect(PyModuleDef *module, PyObject *args)
{
PyObject *return_value = NULL;
int opcode;
@ -62,8 +63,8 @@ exit:
}
static int
_opcode_stack_effect_impl(PyObject *module, int opcode, int group_right_1, int oparg)
/*[clinic checksum: 2312ded40abc9bcbce718942de21f53e61a2dfd3]*/
_opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg)
/*[clinic checksum: e880e62dc7b0de73403026eaf4f8074aa106358b]*/
{
int effect;
if (HAS_ARG(opcode)) {

View File

@ -2842,6 +2842,33 @@ test_pyobject_setallocators(PyObject *self)
return test_setallocators(PYMEM_DOMAIN_OBJ);
}
PyDoc_STRVAR(docstring_empty,
""
);
PyDoc_STRVAR(docstring_no_signature,
"This docstring has no signature."
);
PyDoc_STRVAR(docstring_with_invalid_signature,
"docstring_with_invalid_signature (boo)\n"
"\n"
"This docstring has an invalid signature."
);
PyDoc_STRVAR(docstring_with_signature,
"docstring_with_signature(sig)\n"
"This docstring has a valid signature."
);
PyDoc_STRVAR(docstring_with_signature_and_extra_newlines,
"docstring_with_signature_and_extra_newlines(parameter)\n"
"\n"
"\n"
"\n"
"This docstring has a valid signature and some extra newlines."
);
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
@ -2953,6 +2980,23 @@ static PyMethodDef TestMethods[] = {
(PyCFunction)test_pymem_setallocators, METH_NOARGS},
{"test_pyobject_setallocators",
(PyCFunction)test_pyobject_setallocators, METH_NOARGS},
{"no_docstring",
(PyCFunction)test_with_docstring, METH_NOARGS},
{"docstring_empty",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_empty},
{"docstring_no_signature",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_no_signature},
{"docstring_with_invalid_signature",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_with_invalid_signature},
{"docstring_with_signature",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_with_signature},
{"docstring_with_signature_and_extra_newlines",
(PyCFunction)test_with_docstring, METH_NOARGS,
docstring_with_signature_and_extra_newlines},
{NULL, NULL} /* sentinel */
};

View File

@ -5,8 +5,11 @@
((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
/*[clinic]
module _weakref
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/*[clinic]
_weakref.getweakrefcount -> Py_ssize_t
@ -17,9 +20,8 @@ Return the number of weak references to 'object'.
[clinic]*/
PyDoc_STRVAR(_weakref_getweakrefcount__doc__,
"Return the number of weak references to \'object\'.\n"
"\n"
"_weakref.getweakrefcount(object)");
"getweakrefcount(object)\n"
"Return the number of weak references to \'object\'.");
#define _WEAKREF_GETWEAKREFCOUNT_METHODDEF \
{"getweakrefcount", (PyCFunction)_weakref_getweakrefcount, METH_O, _weakref_getweakrefcount__doc__},
@ -43,7 +45,7 @@ exit:
static Py_ssize_t
_weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object)
/*[clinic checksum: 015113be0c9a0a8672d35df10c63e3642cc23da4]*/
/*[clinic checksum: 436e8fbe0297434375f039d8c2d9fc3a9bbe773c]*/
{
PyWeakReference **list;

View File

@ -190,7 +190,10 @@ corresponding Unix manual entries for more information on calls.");
#endif /* ! __WATCOMC__ || __QNX__ */
/*[clinic]
module os
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
#ifndef _MSC_VER
@ -2404,7 +2407,6 @@ class dir_fd_converter(CConverter):
/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/*[clinic]
module os
os.stat -> object(doc_default='stat_result')
@ -2435,9 +2437,9 @@ It's an error to use dir_fd or follow_symlinks when specifying path as
[clinic]*/
PyDoc_STRVAR(os_stat__doc__,
"stat(path, *, dir_fd=None, follow_symlinks=True)\n"
"Perform a stat system call on the given path.\n"
"\n"
"os.stat(path, *, dir_fd=None, follow_symlinks=True) -> stat_result\n"
" path\n"
" Path to be examined; can be string, bytes, or open-file-descriptor int.\n"
" dir_fd\n"
@ -2486,7 +2488,7 @@ exit:
static PyObject *
os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks)
/*[clinic checksum: b08112eff0ceab3ec2c72352da95ce73f245d104]*/
/*[clinic checksum: 85a71ad602e89f8e280118da976f70cd2f9abdf1]*/
{
return posix_do_stat("stat", path, dir_fd, follow_symlinks);
}
@ -2567,9 +2569,9 @@ Note that most operations will use the effective uid/gid, therefore this
[clinic]*/
PyDoc_STRVAR(os_access__doc__,
"access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n"
"Use the real uid/gid to test for access to a path.\n"
"\n"
"os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True) -> True if granted, False otherwise\n"
" path\n"
" Path to be tested; can be string, bytes, or open-file-descriptor int.\n"
" mode\n"
@ -2587,7 +2589,6 @@ PyDoc_STRVAR(os_access__doc__,
" access will examine the symbolic link itself instead of the file\n"
" the link points to.\n"
"\n"
"{parameters}\n"
"dir_fd, effective_ids, and follow_symlinks may not be implemented\n"
" on your platform. If they are unavailable, using them will raise a\n"
" NotImplementedError.\n"
@ -2628,7 +2629,7 @@ exit:
static PyObject *
os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks)
/*[clinic checksum: b9f8ececb061d31b64220c29526bfee642d1b602]*/
/*[clinic checksum: 636e835c36562a2fc11acab75314634127fdf769]*/
{
PyObject *return_value = NULL;
@ -2724,9 +2725,9 @@ Return the name of the terminal device connected to 'fd'.
[clinic]*/
PyDoc_STRVAR(os_ttyname__doc__,
"ttyname(fd)\n"
"Return the name of the terminal device connected to \'fd\'.\n"
"\n"
"os.ttyname(fd)\n"
" fd\n"
" Integer file descriptor handle.");
@ -2758,7 +2759,7 @@ exit:
static char *
os_ttyname_impl(PyModuleDef *module, int fd)
/*[clinic checksum: 61e4e525984cb293f949ccae6ae393c0011dfe8e]*/
/*[clinic checksum: 0f368134dc0a7f21f25185e2e6bacf7675fb473a]*/
{
char *ret;

View File

@ -17,6 +17,12 @@
#include "ucnhash.h"
#include "structmember.h"
/*[clinic]
module unicodedata
class unicodedata.UCD
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/* character properties */
typedef struct {
@ -108,8 +114,7 @@ static Py_UCS4 getuchar(PyUnicodeObject *obj)
/* --- Module API --------------------------------------------------------- */
/*[clinic]
module unicodedata
class unicodedata.UCD
unicodedata.UCD.decimal
unichr: object(type='str')
@ -124,10 +129,9 @@ not given, ValueError is raised.
[clinic]*/
PyDoc_STRVAR(unicodedata_UCD_decimal__doc__,
"decimal(unichr, default=None)\n"
"Converts a Unicode character into its equivalent decimal value.\n"
"\n"
"unicodedata.UCD.decimal(unichr, default=None)\n"
"\n"
"Returns the decimal value assigned to the Unicode character unichr\n"
"as integer. If no such value is defined, default is returned, or, if\n"
"not given, ValueError is raised.");
@ -157,7 +161,7 @@ exit:
static PyObject *
unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value)
/*[clinic checksum: a0980c387387287e2ac230c37d95b26f6903e0d2]*/
/*[clinic checksum: 9576fa55f4ea0be82968af39dc9d0283e634beeb]*/
{
PyUnicodeObject *v = (PyUnicodeObject *)unichr;
int have_old = 0;

View File

@ -165,6 +165,7 @@ PyZlib_Free(voidpf ctx, void *ptr)
}
/*[clinic]
zlib.compress
bytes: Py_buffer
Binary data to be compressed.
@ -179,9 +180,9 @@ Returns compressed string.
[clinic]*/
PyDoc_STRVAR(zlib_compress__doc__,
"compress(bytes, [level])\n"
"Returns compressed string.\n"
"\n"
"zlib.compress(bytes, [level])\n"
" bytes\n"
" Binary data to be compressed.\n"
" level\n"
@ -226,7 +227,7 @@ zlib_compress(PyModuleDef *module, PyObject *args)
static PyObject *
zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level)
/*[clinic checksum: 03e857836db25448d4d572da537eb7faf7695d71]*/
/*[clinic checksum: f490708eff84be652b5ebe7fe622ab73ac12c888]*/
{
PyObject *ReturnVal = NULL;
Byte *input, *output = NULL;
@ -742,6 +743,7 @@ save_unconsumed_input(compobject *self, int err)
}
/*[clinic]
zlib.Decompress.decompress
data: Py_buffer
@ -760,9 +762,9 @@ Call the flush() method to clear these buffers.
[clinic]*/
PyDoc_STRVAR(zlib_Decompress_decompress__doc__,
"decompress(data, max_length=0)\n"
"Return a string containing the decompressed version of the data.\n"
"\n"
"zlib.Decompress.decompress(data, max_length=0)\n"
" data\n"
" The binary data to decompress.\n"
" max_length\n"
@ -803,7 +805,7 @@ exit:
static PyObject *
zlib_Decompress_decompress_impl(PyObject *self, Py_buffer *data, unsigned int max_length)
/*[clinic checksum: f83e91728d327462d7ccbee95299514f26b92253]*/
/*[clinic checksum: 4683928665a1fa6987f5c57cada4a22807a78fbb]*/
{
compobject *zself = (compobject *)self;
int err;
@ -1029,16 +1031,15 @@ Return a copy of the compression object.
[clinic]*/
PyDoc_STRVAR(zlib_Compress_copy__doc__,
"Return a copy of the compression object.\n"
"\n"
"zlib.Compress.copy()");
"copy()\n"
"Return a copy of the compression object.");
#define ZLIB_COMPRESS_COPY_METHODDEF \
{"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__},
static PyObject *
zlib_Compress_copy(PyObject *self)
/*[clinic checksum: 2551952e72329f0f2beb48a1dde3780e485a220b]*/
/*[clinic checksum: 8d30351f05defbc2b335c2a78d18f07aa367bb1d]*/
{
compobject *zself = (compobject *)self;
compobject *retval = NULL;

View File

@ -69,6 +69,11 @@ to the combined-table form.
#include "Python.h"
#include "stringlib/eq.h"
/*[clinic]
class dict
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
typedef struct {
/* Cached hash code of me_key. */
Py_hash_t me_hash;
@ -2160,7 +2165,6 @@ dict_richcompare(PyObject *v, PyObject *w, int op)
}
/*[clinic]
class dict
@coexist
dict.__contains__
@ -2172,16 +2176,15 @@ True if D has a key k, else False"
[clinic]*/
PyDoc_STRVAR(dict___contains____doc__,
"True if D has a key k, else False\"\n"
"\n"
"dict.__contains__(key)");
"__contains__(key)\n"
"True if D has a key k, else False\"");
#define DICT___CONTAINS___METHODDEF \
{"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__},
static PyObject *
dict___contains__(PyObject *self, PyObject *key)
/*[clinic checksum: 61c5c802ea1d35699a1a754f1f3538ea9b259cf4]*/
/*[clinic checksum: 3bbac5ce898ae630d9668fa1c8b3afb645ff22e8]*/
{
register PyDictObject *mp = (PyDictObject *)self;
Py_hash_t hash;

View File

@ -159,15 +159,75 @@ meth_dealloc(PyCFunctionObject *m)
}
}
/*
* finds the docstring's introspection signature.
* if present, returns a pointer pointing to the first '('.
* otherwise returns NULL.
*/
static const char *find_signature(PyCFunctionObject *m)
{
const char *trace = m->m_ml->ml_doc;
const char *name = m->m_ml->ml_name;
size_t length;
if (!trace || !name)
return NULL;
length = strlen(name);
if (strncmp(trace, name, length))
return NULL;
trace += length;
if (*trace != '(')
return NULL;
return trace;
}
/*
* skips to the end of the docstring's instrospection signature.
*/
static const char *skip_signature(const char *trace)
{
while (*trace && *trace != '\n')
trace++;
return trace;
}
static const char *skip_eols(const char *trace)
{
while (*trace == '\n')
trace++;
return trace;
}
static PyObject *
meth_get__text_signature__(PyCFunctionObject *m, void *closure)
{
const char *start = find_signature(m);
const char *trace;
if (!start) {
Py_INCREF(Py_None);
return Py_None;
}
trace = skip_signature(start);
return PyUnicode_FromStringAndSize(start, trace - start);
}
static PyObject *
meth_get__doc__(PyCFunctionObject *m, void *closure)
{
const char *doc = m->m_ml->ml_doc;
const char *doc = find_signature(m);
if (doc != NULL)
return PyUnicode_FromString(doc);
Py_INCREF(Py_None);
return Py_None;
if (doc)
doc = skip_eols(skip_signature(doc));
else
doc = m->m_ml->ml_doc;
if (!doc) {
Py_INCREF(Py_None);
return Py_None;
}
return PyUnicode_FromString(doc);
}
static PyObject *
@ -236,6 +296,7 @@ static PyGetSetDef meth_getsets [] = {
{"__name__", (getter)meth_get__name__, NULL, NULL},
{"__qualname__", (getter)meth_get__qualname__, NULL, NULL},
{"__self__", (getter)meth_get__self__, NULL, NULL},
{"__text_signature__", (getter)meth_get__text_signature__, NULL, NULL},
{0}
};

View File

@ -47,6 +47,11 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <windows.h>
#endif
/*[clinic]
class str
[clinic]*/
/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
/* --- Globals ------------------------------------------------------------
NOTE: In the interpreter's initialization phase, some globals are currently
@ -12883,7 +12888,6 @@ unicode_swapcase(PyObject *self)
}
/*[clinic]
class str
@staticmethod
str.maketrans as unicode_maketrans
@ -12908,10 +12912,9 @@ must be a string, whose characters will be mapped to None in the result.
[clinic]*/
PyDoc_STRVAR(unicode_maketrans__doc__,
"maketrans(x, y=None, z=None)\n"
"Return a translation table usable for str.translate().\n"
"\n"
"str.maketrans(x, y=None, z=None)\n"
"\n"
"If there is only one argument, it must be a dictionary mapping Unicode\n"
"ordinals (integers) or characters to Unicode ordinals, strings or None.\n"
"Character keys will be then converted to ordinals.\n"
@ -12946,7 +12949,7 @@ exit:
static PyObject *
unicode_maketrans_impl(void *null, PyObject *x, PyObject *y, PyObject *z)
/*[clinic checksum: 6d522e3aea2f2e123da3c5d367132a99d803f9b9]*/
/*[clinic checksum: 7f76f414a0dfd0c614e0d4717872eeb520516da7]*/
{
PyObject *new = NULL, *key, *value;
Py_ssize_t i = 0;

View File

@ -24,17 +24,6 @@ import tempfile
import textwrap
# TODO:
# converters for
#
# es
# es#
# et
# et#
# s#
# u#
# y#
# z#
# Z#
#
# soon:
#
@ -44,12 +33,6 @@ import textwrap
# * max and min use positional only with an optional group
# and keyword-only
#
# * Generate forward slash for docstring first line
# (if I get positional-only syntax pep accepted)
#
# * Add "version" directive, so we can complain if the file
# is too new for us.
#
version = '1'
@ -2441,7 +2424,7 @@ class DSLParser:
## docstring first line
##
add(f.full_name)
add(f.name)
add('(')
# populate "right_bracket_count" field for every parameter
@ -2498,29 +2481,32 @@ class DSLParser:
add(fix_right_bracket_count(0))
add(')')
if f.return_converter.doc_default:
add(' -> ')
add(f.return_converter.doc_default)
# if f.return_converter.doc_default:
# add(' -> ')
# add(f.return_converter.doc_default)
docstring_first_line = output()
# now fix up the places where the brackets look wrong
docstring_first_line = docstring_first_line.replace(', ]', ',] ')
# okay. now we're officially building the
# "prototype" section.
add(docstring_first_line)
# okay. now we're officially building the "parameters" section.
# create substitution text for {parameters}
spacer_line = False
for p in parameters:
if not p.docstring.strip():
continue
add('\n')
if spacer_line:
add('\n')
else:
spacer_line = True
add(" ")
add(p.name)
add('\n')
add(textwrap.indent(rstrip_lines(p.docstring.rstrip()), " "))
prototype = output()
parameters = output()
if parameters:
parameters += '\n'
##
## docstring body
@ -2549,21 +2535,26 @@ class DSLParser:
elif len(lines) == 1:
# the docstring is only one line right now--the summary line.
# add an empty line after the summary line so we have space
# between it and the {prototype} we're about to add.
# between it and the {parameters} we're about to add.
lines.append('')
prototype_marker_count = len(docstring.split('{prototype}')) - 1
if prototype_marker_count:
fail('You may not specify {prototype} in a docstring!')
# insert *after* the summary line
lines.insert(2, '{prototype}\n')
parameters_marker_count = len(docstring.split('{parameters}')) - 1
if parameters_marker_count > 1:
fail('You may not specify {parameters} more than once in a docstring!')
if not parameters_marker_count:
# insert after summary line
lines.insert(2, '{parameters}')
# insert at front of docstring
lines.insert(0, docstring_first_line)
docstring = "\n".join(lines)
add(docstring)
docstring = output()
docstring = linear_format(docstring, prototype=prototype)
docstring = linear_format(docstring, parameters=parameters)
docstring = docstring.rstrip()
return docstring