Skip to content

Commit 72c627a

Browse files
committed
[GR-63367] Implement tp_init
PullRequest: graalpython/3735
2 parents 57156f0 + 956183d commit 72c627a

File tree

116 files changed

+1371
-1228
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+1371
-1228
lines changed

graalpython/com.oracle.graal.python.annotations/src/com/oracle/graal/python/annotations/Slot.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,26 @@
7676
*/
7777
@Retention(RetentionPolicy.RUNTIME)
7878
@interface SlotSignature {
79+
/**
80+
* Used to supply the function name for error messages from argument parsing.
81+
*/
82+
String name() default "";
83+
7984
int minNumOfPositionalArgs() default 0;
8085

86+
int maxNumOfPositionalArgs() default -1;
87+
8188
boolean takesVarArgs() default false;
8289

8390
boolean takesVarKeywordArgs() default false;
8491

8592
String[] parameterNames() default {};
8693

94+
String[] keywordOnlyNames() default {};
95+
8796
boolean needsFrame() default false;
8897

8998
boolean alwaysNeedsCallerFrame() default false;
90-
91-
String raiseErrorName() default "";
9299
}
93100

94101
/** See <a href="https://docs.python.org/3/c-api/typeobj.html">slot documentation</a> */
@@ -206,7 +213,8 @@ enum SlotKind {
206213
/** str(obj) */
207214
tp_str("__str__"),
208215
/** repr(obj) */
209-
tp_repr("__repr__");
216+
tp_repr("__repr__"),
217+
tp_init("__init__");
210218

211219
SlotKind(@SuppressWarnings("unused") String specialMethods) {
212220
}

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/ArgumentClinicProcessor.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -83,6 +83,7 @@
8383
public class ArgumentClinicProcessor extends AbstractProcessor {
8484
private static final boolean LOGGING = false;
8585
private static final String BuiltinAnnotationClass = "com.oracle.graal.python.builtins.Builtin";
86+
private static final String SlotSignatureAnnotationClass = "com.oracle.graal.python.annotations.Slot.SlotSignature";
8687
private static final String BuiltinsAnnotationClass = "com.oracle.graal.python.builtins.Builtins";
8788
private static final String BUILTINS_BASE_CLASSES_PACKAGE = "com.oracle.graal.python.nodes.function.builtins";
8889

@@ -360,6 +361,9 @@ private static BuiltinAnnotation getBuiltinAnnotation(TypeElement type) throws P
360361
int minNumOfPositionalArgs = -1;
361362
boolean takesVarArgs = false;
362363
AnnotationMirror annot = findAnnotationMirror(type, BuiltinAnnotationClass);
364+
if (annot == null) {
365+
annot = findAnnotationMirror(type, SlotSignatureAnnotationClass);
366+
}
363367
if (annot == null) {
364368
annot = findAnnotationMirror(type, BuiltinsAnnotationClass);
365369
if (annot != null) {

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsMapping.java

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static String getSlotBaseClass(Slot s) {
7979
case tp_setattro -> "TpSlotSetAttr.TpSlotSetAttrBuiltin";
8080
case tp_iternext -> "TpSlotIterNext.TpSlotIterNextBuiltin";
8181
case tp_hash -> "TpSlotHashFun.TpSlotHashBuiltin";
82+
case tp_init -> "TpSlotInit.TpSlotInitBuiltin";
8283
};
8384
}
8485

@@ -111,6 +112,7 @@ static String getSlotNodeBaseClass(Slot s) {
111112
case tp_descr_set -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrSet.DescrSetBuiltinNode";
112113
case tp_setattro -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotSetAttr.SetAttrBuiltinNode";
113114
case tp_hash -> "com.oracle.graal.python.builtins.objects.type.slots.TpSlotHashFun.HashBuiltinNode";
115+
case tp_init -> "com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode";
114116
};
115117
}
116118

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/ConversionNodeTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
import com.oracle.truffle.api.frame.VirtualFrame;
6363

6464
public class ConversionNodeTests {
65-
static final Signature SIGNATURE = new Signature(-1, false, -1, false, tsArray("arg"), null);
65+
static final Signature SIGNATURE = new Signature(-1, false, -1, tsArray("arg"), null);
6666

6767
protected static Object call(Object arg, ArgumentCastNode castNode) {
6868
final PythonContext pythonContext = PythonContext.get(castNode);

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tp_slots.py

+98-62
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,26 @@ def wrapper(*args):
980980
return wrapper
981981

982982

983+
native_slot_proxy_template = '''
984+
static PyObject* get_delegate(PyObject* self) {
985+
return ((ProxyObject*)self)->delegate;
986+
}
987+
static void set_delegate(PyObject* self, PyObject* delegate) {
988+
Py_XSETREF(((ProxyObject*)self)->delegate, delegate);
989+
}
990+
static PyObject* proxy_tp_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
991+
PyObject* delegate;
992+
if (!PyArg_UnpackTuple(args, "NativeSlotProxy", 0, 1, &delegate))
993+
return NULL;
994+
ProxyObject* obj = (ProxyObject*)type->tp_alloc(type, 0);
995+
if (!obj)
996+
return NULL;
997+
obj->delegate = Py_NewRef(delegate); // leaked
998+
return (PyObject*)obj;
999+
}
1000+
'''
1001+
1002+
9831003
def test_nb_slot_calls():
9841004
slots = [
9851005
('proxy_nb_binary_slot', 'nb_add'),
@@ -1023,22 +1043,7 @@ def test_nb_slot_calls():
10231043
cmembers='PyObject* delegate;',
10241044
code=r'''
10251045
typedef NativeNbSlotProxyObject ProxyObject;
1026-
static PyObject* get_delegate(PyObject* self) {
1027-
return ((ProxyObject*)self)->delegate;
1028-
}
1029-
static void set_delegate(PyObject* self, PyObject* delegate) {
1030-
Py_XSETREF(((ProxyObject*)self)->delegate, delegate);
1031-
}
1032-
static PyObject* proxy_tp_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
1033-
PyObject* delegate;
1034-
if (!PyArg_UnpackTuple(args, "NativeNbSlotProxy", 0, 1, &delegate))
1035-
return NULL;
1036-
ProxyObject* obj = (ProxyObject*)type->tp_alloc(type, 0);
1037-
if (!obj)
1038-
return NULL;
1039-
obj->delegate = Py_NewRef(delegate); // leaked
1040-
return (PyObject*)obj;
1041-
}
1046+
''' + native_slot_proxy_template + r'''
10421047
static PyTypeObject NativeNbSlotProxyType;
10431048
#define proxy_nb_unary_slot(slot) \
10441049
static PyObject* proxy_##slot(PyObject *a) { \
@@ -1249,22 +1254,7 @@ def test_sq_slot_calls():
12491254
cmembers='PyObject* delegate;',
12501255
code=r'''
12511256
typedef NativeSqSlotProxyObject ProxyObject;
1252-
static PyObject* get_delegate(PyObject* self) {
1253-
return ((ProxyObject*)self)->delegate;
1254-
}
1255-
static void set_delegate(PyObject* self, PyObject* delegate) {
1256-
Py_XSETREF(((ProxyObject*)self)->delegate, delegate);
1257-
}
1258-
static PyObject* proxy_tp_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
1259-
PyObject* delegate;
1260-
if (!PyArg_UnpackTuple(args, "NativeSqSlotProxy", 0, 1, &delegate))
1261-
return NULL;
1262-
ProxyObject* obj = (ProxyObject*)type->tp_alloc(type, 0);
1263-
if (!obj)
1264-
return NULL;
1265-
obj->delegate = Py_NewRef(delegate); // leaked
1266-
return (PyObject*)obj;
1267-
}
1257+
''' + native_slot_proxy_template + r'''
12681258
static Py_ssize_t proxy_sq_length(PyObject* self) {
12691259
PyObject* delegate = get_delegate(self);
12701260
return Py_TYPE(delegate)->tp_as_sequence->sq_length(delegate);
@@ -1388,19 +1378,7 @@ def test_mp_slot_calls():
13881378
cmembers='PyObject* delegate;',
13891379
code=r'''
13901380
typedef NativeMpSlotProxyObject ProxyObject;
1391-
static PyObject* get_delegate(PyObject* self) {
1392-
return ((ProxyObject*)self)->delegate;
1393-
}
1394-
static PyObject* proxy_tp_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
1395-
PyObject* delegate;
1396-
if (!PyArg_UnpackTuple(args, "NativeMpSlotProxy", 0, 1, &delegate))
1397-
return NULL;
1398-
ProxyObject* obj = (ProxyObject*)type->tp_alloc(type, 0);
1399-
if (!obj)
1400-
return NULL;
1401-
obj->delegate = Py_NewRef(delegate); // leaked
1402-
return (PyObject*)obj;
1403-
}
1381+
''' + native_slot_proxy_template + r'''
14041382
static Py_ssize_t proxy_mp_length(PyObject* self) {
14051383
PyObject* delegate = get_delegate(self);
14061384
return Py_TYPE(delegate)->tp_as_mapping->mp_length(delegate);
@@ -1447,25 +1425,13 @@ def __init__(self, delegate):
14471425
assert not bool(obj)
14481426

14491427

1450-
def test_tp_slot_calls():
1428+
def test_tp_iter_iternext_calls():
14511429
NativeSlotProxy = CPyExtType(
1452-
name='TpSlotProxy',
1430+
name='TpIterSlotProxy',
14531431
cmembers='PyObject* delegate;',
14541432
code=r'''
1455-
typedef TpSlotProxyObject ProxyObject;
1456-
static PyObject* get_delegate(PyObject* self) {
1457-
return ((ProxyObject*)self)->delegate;
1458-
}
1459-
static PyObject* proxy_tp_new(PyTypeObject* type, PyObject* args, PyObject* kwargs) {
1460-
PyObject* delegate;
1461-
if (!PyArg_UnpackTuple(args, "NativeTpSlotProxy", 0, 1, &delegate))
1462-
return NULL;
1463-
ProxyObject* obj = (ProxyObject*)type->tp_alloc(type, 0);
1464-
if (!obj)
1465-
return NULL;
1466-
obj->delegate = Py_NewRef(delegate); // leaked
1467-
return (PyObject*)obj;
1468-
}
1433+
typedef TpIterSlotProxyObject ProxyObject;
1434+
''' + native_slot_proxy_template + r'''
14691435
static PyObject* proxy_tp_iter(PyObject* self) {
14701436
PyObject* delegate = get_delegate(self);
14711437
return Py_TYPE(delegate)->tp_iter(delegate);
@@ -1570,6 +1536,76 @@ def __iter__(self):
15701536
assert str(e).endswith("is not an iterator")
15711537

15721538

1539+
def test_tp_str_repr_calls():
1540+
NativeSlotProxy = CPyExtType(
1541+
name='TpStrSlotProxy',
1542+
cmembers='PyObject* delegate;',
1543+
code=r'''
1544+
typedef TpStrSlotProxyObject ProxyObject;
1545+
''' + native_slot_proxy_template + r'''
1546+
static PyObject* proxy_tp_str(PyObject* self) {
1547+
PyObject* delegate = get_delegate(self);
1548+
return Py_TYPE(delegate)->tp_str(delegate);
1549+
}
1550+
static PyObject* proxy_tp_repr(PyObject* self) {
1551+
PyObject* delegate = get_delegate(self);
1552+
return Py_TYPE(delegate)->tp_repr(delegate);
1553+
}
1554+
''',
1555+
tp_new='proxy_tp_new',
1556+
tp_members='{"delegate", T_OBJECT, offsetof(ProxyObject, delegate), 0, NULL}',
1557+
tp_str='proxy_tp_str',
1558+
tp_repr='proxy_tp_repr',
1559+
)
1560+
1561+
class PureSlotProxy:
1562+
def __init__(self, delegate):
1563+
self.delegate = delegate
1564+
1565+
__str__ = DelegateSlot()
1566+
__repr__ = DelegateSlot()
1567+
1568+
for obj in [NativeSlotProxy("a\nb"), NativeSlotProxy(PureSlotProxy("a\nb"))]:
1569+
assert str(obj) == "a\nb"
1570+
assert repr(obj) == repr("a\nb")
1571+
1572+
1573+
def test_tp_init_calls():
1574+
NativeSlotProxy = CPyExtType(
1575+
name='TpInitSlotProxy',
1576+
cmembers='PyObject* delegate;',
1577+
code=r'''
1578+
typedef TpInitSlotProxyObject ProxyObject;
1579+
''' + native_slot_proxy_template + r'''
1580+
int proxy_tp_init(PyObject* self, PyObject* args, PyObject* kwargs) {
1581+
PyObject* delegate = get_delegate(self);
1582+
return Py_TYPE(delegate)->tp_init(delegate, args, kwargs);
1583+
}
1584+
''',
1585+
tp_new='proxy_tp_new',
1586+
tp_members='{"delegate", T_OBJECT, offsetof(ProxyObject, delegate), 0, NULL}',
1587+
tp_init='proxy_tp_init',
1588+
)
1589+
1590+
class PureSlotProxy:
1591+
def __new__(cls, delegate):
1592+
self = object.__new__(cls)
1593+
self.delegate = delegate
1594+
return self
1595+
1596+
def __init__(self, delegate, *args, **kwargs):
1597+
self.delegate.__init__(*args, **kwargs)
1598+
1599+
obj = NativeSlotProxy([1])
1600+
assert obj.delegate == []
1601+
assert obj.__init__({2}) is None
1602+
assert obj.delegate == [2]
1603+
assert_raises(TypeError, NativeSlotProxy, ([1],), {'a': 1})
1604+
1605+
obj = NativeSlotProxy(PureSlotProxy([1]))
1606+
assert obj.delegate.delegate == []
1607+
1608+
15731609
def test_richcmp():
15741610
MyNativeIntSubType = CPyExtType("MyNativeIntSubTypeForRichCmpTest",
15751611
ready_code = "MyNativeIntSubTypeForRichCmpTestType.tp_new = PyLong_Type.tp_new;",
@@ -1645,4 +1681,4 @@ def test_cmp(op_lambda, rop_lambda, op_name, rop_name):
16451681

16461682
assert create_mock(ne=1) == create_mock(eq=1)
16471683
assert create_mock(ne=1, eq=0) != create_mock(ne=0, eq=1)
1648-
assert not create_mock(ne=1, eq=0) == create_mock(ne=0, eq=1)
1684+
assert not create_mock(ne=1, eq=0) == create_mock(ne=0, eq=1)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Builtin.java

-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@
6363

6464
boolean takesVarArgs() default false;
6565

66-
boolean varArgsMarker() default false;
67-
6866
boolean takesVarKeywordArgs() default false;
6967

7068
String[] parameterNames() default {};

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
import com.oracle.graal.python.builtins.modules.JArrayModuleBuiltins;
8585
import com.oracle.graal.python.builtins.modules.JavaModuleBuiltins;
8686
import com.oracle.graal.python.builtins.modules.LocaleModuleBuiltins;
87-
import com.oracle.graal.python.builtins.modules.LsprofModuleBuiltins;
87+
import com.oracle.graal.python.builtins.modules.lsprof.LsprofModuleBuiltins;
8888
import com.oracle.graal.python.builtins.modules.MMapModuleBuiltins;
8989
import com.oracle.graal.python.builtins.modules.MarshalModuleBuiltins;
9090
import com.oracle.graal.python.builtins.modules.MathModuleBuiltins;
@@ -95,6 +95,7 @@
9595
import com.oracle.graal.python.builtins.modules.PosixModuleBuiltins;
9696
import com.oracle.graal.python.builtins.modules.PosixShMemModuleBuiltins;
9797
import com.oracle.graal.python.builtins.modules.PosixSubprocessModuleBuiltins;
98+
import com.oracle.graal.python.builtins.modules.lsprof.ProfilerBuiltins;
9899
import com.oracle.graal.python.builtins.modules.PwdModuleBuiltins;
99100
import com.oracle.graal.python.builtins.modules.QueueModuleBuiltins;
100101
import com.oracle.graal.python.builtins.modules.RandomModuleBuiltins;
@@ -790,7 +791,7 @@ private static PythonBuiltins[] initializeBuiltins(TruffleLanguage.Env env) {
790791
new TokenizerIterBuiltins()));
791792
if (hasProfilerTool) {
792793
builtins.add(new LsprofModuleBuiltins());
793-
builtins.add(LsprofModuleBuiltins.newProfilerBuiltins());
794+
builtins.add(new ProfilerBuiltins());
794795
}
795796
if (!PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES && (env.isNativeAccessAllowed() || env.isPreInitialization())) {
796797
builtins.add(new BZ2CompressorBuiltins());

0 commit comments

Comments
 (0)