Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8666e65

Browse files
committed
Issue #20228: Argument Clinic now has special support for class special
methods.
1 parent 0191be3 commit 8666e65

3 files changed

Lines changed: 119 additions & 17 deletions

File tree

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ Tests
7272
Tools/Demos
7373
-----------
7474

75+
- Issue #20228: Argument Clinic now has special support for class special
76+
methods.
77+
7578
- Issue #20214: Fixed a number of small issues and documentation errors in
7679
Argument Clinic (see issue for details).
7780

Modules/_pickle.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4068,9 +4068,6 @@ PyDoc_STRVAR(_pickle_Pickler___init____doc__,
40684068
"to map the new Python 3 names to the old module names used in Python\n"
40694069
"2, so that the pickle data stream is readable with Python 2.");
40704070

4071-
#define _PICKLE_PICKLER___INIT___METHODDEF \
4072-
{"__init__", (PyCFunction)_pickle_Pickler___init__, METH_VARARGS|METH_KEYWORDS, _pickle_Pickler___init____doc__},
4073-
40744071
static PyObject *
40754072
_pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports);
40764073

@@ -4095,7 +4092,7 @@ _pickle_Pickler___init__(PyObject *self, PyObject *args, PyObject *kwargs)
40954092

40964093
static PyObject *
40974094
_pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports)
4098-
/*[clinic end generated code: checksum=2b5ce6452544600478cf9f4b701ab9d9b5efbab9]*/
4095+
/*[clinic end generated code: checksum=defa3d9e9f8b51fb257d4fdfca99db503db0e6df]*/
40994096
{
41004097
_Py_IDENTIFIER(persistent_id);
41014098
_Py_IDENTIFIER(dispatch_table);
@@ -6637,9 +6634,6 @@ PyDoc_STRVAR(_pickle_Unpickler___init____doc__,
66376634
"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n"
66386635
"string instances as bytes objects.");
66396636

6640-
#define _PICKLE_UNPICKLER___INIT___METHODDEF \
6641-
{"__init__", (PyCFunction)_pickle_Unpickler___init__, METH_VARARGS|METH_KEYWORDS, _pickle_Unpickler___init____doc__},
6642-
66436637
static PyObject *
66446638
_pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors);
66456639

@@ -6665,7 +6659,7 @@ _pickle_Unpickler___init__(PyObject *self, PyObject *args, PyObject *kwargs)
66656659

66666660
static PyObject *
66676661
_pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors)
6668-
/*[clinic end generated code: checksum=9ce6783224e220573d42a94fe1bb7199d6f1c5a6]*/
6662+
/*[clinic end generated code: checksum=26c1d4a06841a8e51d29a0c244ba7f4607ff358a]*/
66696663
{
66706664
_Py_IDENTIFIER(persistent_load);
66716665

Tools/clinic/clinic.py

Lines changed: 114 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,16 @@ def quoted_for_c_string(s):
111111
def is_legal_py_identifier(s):
112112
return all(is_legal_c_identifier(field) for field in s.split('.'))
113113

114-
# added "module", "self", "cls", and "null" just to be safe
115-
# (clinic will generate variables with these names)
114+
# though it's called c_keywords, really it's a list of parameter names
115+
# that are okay in Python but aren't a good idea in C. so if they're used
116+
# Argument Clinic will add "_value" to the end of the name in C.
117+
# (We added "args", "type", "module", "self", "cls", and "null"
118+
# just to be safe, even though they're not C keywords.)
116119
c_keywords = set("""
117-
asm auto break case char cls const continue default do double
120+
args asm auto break case char cls const continue default do double
118121
else enum extern float for goto if inline int long module null
119122
register return self short signed sizeof static struct switch
120-
typedef typeof union unsigned void volatile while
123+
type typedef typeof union unsigned void volatile while
121124
""".strip().split())
122125

123126
def ensure_legal_c_identifier(s):
@@ -392,11 +395,17 @@ def docstring_for_c_string(self, f):
392395

393396
@staticmethod
394397
def template_base(*args):
395-
flags = '|'.join(f for f in args if f)
396-
return """
398+
# HACK suppress methoddef define for METHOD_NEW and METHOD_INIT
399+
base = """
397400
PyDoc_STRVAR({c_basename}__doc__,
398401
{docstring});
402+
"""
403+
404+
if args[-1] == None:
405+
return base
399406

407+
flags = '|'.join(f for f in args if f)
408+
return base + """
400409
#define {methoddef_name} \\
401410
{{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}},
402411
""".replace('{methoddef_flags}', flags)
@@ -650,7 +659,13 @@ def render_function(self, f):
650659
name = full_name.rpartition('.')[2]
651660
template_dict['name'] = name
652661

653-
c_basename = f.c_basename or full_name.replace(".", "_")
662+
if f.c_basename:
663+
c_basename = f.c_basename
664+
else:
665+
fields = full_name.split(".")
666+
if fields[-1] == '__new__':
667+
fields.pop()
668+
c_basename = "_".join(fields)
654669
template_dict['c_basename'] = c_basename
655670

656671
methoddef_name = "{}_METHODDEF".format(c_basename.upper())
@@ -1171,8 +1186,81 @@ def __init__(self, name, module=None, cls=None):
11711186
def __repr__(self):
11721187
return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">"
11731188

1189+
unsupported_special_methods = set("""
1190+
1191+
__abs__
1192+
__add__
1193+
__and__
1194+
__bytes__
1195+
__call__
1196+
__complex__
1197+
__delitem__
1198+
__divmod__
1199+
__eq__
1200+
__float__
1201+
__floordiv__
1202+
__ge__
1203+
__getattr__
1204+
__getattribute__
1205+
__getitem__
1206+
__gt__
1207+
__hash__
1208+
__iadd__
1209+
__iand__
1210+
__idivmod__
1211+
__ifloordiv__
1212+
__ilshift__
1213+
__imod__
1214+
__imul__
1215+
__index__
1216+
__int__
1217+
__invert__
1218+
__ior__
1219+
__ipow__
1220+
__irshift__
1221+
__isub__
1222+
__iter__
1223+
__itruediv__
1224+
__ixor__
1225+
__le__
1226+
__len__
1227+
__lshift__
1228+
__lt__
1229+
__mod__
1230+
__mul__
1231+
__neg__
1232+
__new__
1233+
__next__
1234+
__or__
1235+
__pos__
1236+
__pow__
1237+
__radd__
1238+
__rand__
1239+
__rdivmod__
1240+
__repr__
1241+
__rfloordiv__
1242+
__rlshift__
1243+
__rmod__
1244+
__rmul__
1245+
__ror__
1246+
__round__
1247+
__rpow__
1248+
__rrshift__
1249+
__rshift__
1250+
__rsub__
1251+
__rtruediv__
1252+
__rxor__
1253+
__setattr__
1254+
__setitem__
1255+
__str__
1256+
__sub__
1257+
__truediv__
1258+
__xor__
11741259
1175-
DATA, CALLABLE, METHOD, STATIC_METHOD, CLASS_METHOD = range(5)
1260+
""".strip().split())
1261+
1262+
1263+
INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6)
11761264

11771265
class Function:
11781266
"""
@@ -1207,6 +1295,8 @@ def __init__(self, parameters=None, *, name,
12071295

12081296
@property
12091297
def methoddef_flags(self):
1298+
if self.kind in (METHOD_INIT, METHOD_NEW):
1299+
return None
12101300
flags = []
12111301
if self.kind == CLASS_METHOD:
12121302
flags.append('METH_CLASS')
@@ -1846,7 +1936,7 @@ class self_converter(CConverter):
18461936
type = "PyObject *"
18471937
def converter_init(self, *, type=None):
18481938
f = self.function
1849-
if f.kind == CALLABLE:
1939+
if f.kind in (CALLABLE, METHOD_INIT):
18501940
if f.cls:
18511941
self.name = "self"
18521942
else:
@@ -1858,6 +1948,9 @@ def converter_init(self, *, type=None):
18581948
elif f.kind == CLASS_METHOD:
18591949
self.name = "cls"
18601950
self.type = "PyTypeObject *"
1951+
elif f.kind == METHOD_NEW:
1952+
self.name = "type"
1953+
self.type = "PyTypeObject *"
18611954

18621955
if type:
18631956
self.type = type
@@ -2258,6 +2351,18 @@ def state_modulename_name(self, line):
22582351
function_name = fields.pop()
22592352
module, cls = self.clinic._module_and_class(fields)
22602353

2354+
fields = full_name.split('.')
2355+
if fields[-1] == '__new__':
2356+
if (self.kind != CLASS_METHOD) or (not cls):
2357+
fail("__new__ must be a class method!")
2358+
self.kind = METHOD_NEW
2359+
elif fields[-1] == '__init__':
2360+
if (self.kind != CALLABLE) or (not cls):
2361+
fail("__init__ must be a normal method, not a class or static method!")
2362+
self.kind = METHOD_INIT
2363+
elif fields[-1] in unsupported_special_methods:
2364+
fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)")
2365+
22612366
if not module:
22622367
fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".")
22632368
self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename,

0 commit comments

Comments
 (0)