@@ -78,6 +78,18 @@ def test(fun, name):
78
78
else:
79
79
print(type(e))
80
80
81
+ def test_dunder(obj, fun_name, *args):
82
+ # avoid going through tp_getattr/o, which may be overridden to something funky
83
+ args_str = ','.join([repr(x) for x in args])
84
+ test(lambda: Klass.__dict__[fun_name](obj, *args), f"{fun_name} via class dict")
85
+ test(lambda: getattr(obj, fun_name)(*args), f"{fun_name}")
86
+
87
+ def write_attr(obj, attr, value):
88
+ if attr == 'foo':
89
+ obj.foo = value
90
+ elif attr == 'bar':
91
+ obj.bar = value
92
+
81
93
obj = Klass()
82
94
test(lambda: bool(obj), "bool(obj)")
83
95
test(lambda: len(obj), "len(obj)")
@@ -86,10 +98,23 @@ def test(fun, name):
86
98
test(lambda: obj.foo, "obj.foo")
87
99
test(lambda: obj.bar, "obj.bar")
88
100
101
+ test(lambda: write_attr(obj, 'foo', 42), "obj.foo = 42")
102
+ test(lambda: obj.foo, "obj.foo")
103
+ test(lambda: write_attr(obj, 'foo', 'hello'), "obj.foo = 'hello'")
104
+ test(lambda: obj.foo, "obj.foo")
105
+
106
+ test(lambda: write_attr(obj, 'bar', 42), "obj.bar = 42")
107
+ test(lambda: obj.foo, "obj.foo")
108
+ test(lambda: obj.bar, "obj.bar")
109
+
89
110
test(lambda: obj.__bool__(), "obj.__bool__()")
90
111
test(lambda: obj.__len__(), "obj.__len__()")
91
112
test(lambda: obj.__getattr__('bar'), "obj.__getattr__('bar')")
92
113
test(lambda: obj.__getattribute__('bar'), "obj.__getattribute__('bar')")
114
+ test(lambda: obj.__setattr__('foo', 11), "obj.__setattr__('foo', 11)")
115
+ test(lambda: obj.__getattr__('foo'), "obj.__getattr__('foo')")
116
+ test(lambda: obj.__delattr__('foo'), "obj.__delattr__('foo')")
117
+ test(lambda: obj.__getattr__('foo'), "obj.__getattr__('foo')")
93
118
94
119
class Dummy1:
95
120
pass
@@ -143,6 +168,14 @@ def compile_ext(name):
143
168
)
144
169
'''
145
170
171
+ # language=C
172
+ C_SOURCE_HEADER = '''
173
+ #include <Python.h>
174
+
175
+ PyObject *global_stash1;
176
+ PyObject *global_stash2;
177
+ '''
178
+
146
179
147
180
def write_all (filename , text ):
148
181
with open (filename , 'w+' ) as f :
@@ -182,10 +215,38 @@ def tp_decl(self, name_prefix):
182
215
Slot ('tp_as_number' , 'nb_bool' , 'int $name$(PyObject* self)' , ['1' , '0' , None ]),
183
216
Slot ('tp_as_sequence' , 'sq_length' , 'Py_ssize_t $name$(PyObject* self)' , ['0' , '1' , '42' , None ]),
184
217
Slot ('tp_as_mapping' , 'mp_length' , 'Py_ssize_t $name$(PyObject* self)' , ['0' , '1' , '42' , None ]),
185
- Slot (NO_GROUP , 'tp_getattr' , 'PyObject* $name$(PyObject* self, char *name)' , ['Py_RETURN_NONE' , 'Py_RETURN_TRUE' , 'Py_NewRef(self)' , None ]),
186
- Slot (NO_GROUP , 'tp_getattro' , 'PyObject* $name$(PyObject* self, PyObject *name)' , ['Py_RETURN_NONE' , 'Py_RETURN_TRUE' , 'Py_NewRef(self)' , None ]),
187
- Slot (NO_GROUP , 'tp_descr_get' , 'PyObject* $name$(PyObject* self, PyObject* key, PyObject* type)' , ['Py_RETURN_NONE' , 'Py_NewRef(key)' , None ]),
188
- Slot (NO_GROUP , 'tp_descr_set' , 'int $name$(PyObject* self, PyObject* key, PyObject* value)' , ['0' , None ])
218
+ Slot (NO_GROUP , 'tp_getattr' , 'PyObject* $name$(PyObject* self, char *name)' , ['Py_RETURN_NONE' , 'Py_RETURN_TRUE' , 'Py_NewRef(self)' , None ,
219
+ '''
220
+ if (global_stash1 == NULL) Py_RETURN_NONE;
221
+ Py_IncRef(global_stash1);
222
+ return global_stash1;
223
+ ''' ]),
224
+ Slot (NO_GROUP , 'tp_getattro' , 'PyObject* $name$(PyObject* self, PyObject *name)' , ['Py_RETURN_NONE' , 'Py_RETURN_TRUE' , 'Py_NewRef(self)' , 'Py_NewRef(name)' , None ,
225
+ '''
226
+ if (global_stash1 == NULL) Py_RETURN_NONE;
227
+ Py_IncRef(global_stash1);
228
+ return global_stash1;
229
+ ''' ]),
230
+ Slot (NO_GROUP , 'tp_setattro' , 'PyObject* $name$(PyObject* self, PyObject *name, PyObject *value)' , ['0' , None ,
231
+ '''
232
+ Py_IncRef(value);
233
+ Py_XDECREF(global_stash1);
234
+ global_stash1 = value;
235
+ return 0;
236
+ ''' ]),
237
+ Slot (NO_GROUP , 'tp_descr_get' , 'PyObject* $name$(PyObject* self, PyObject* key, PyObject* type)' , ['Py_RETURN_NONE' , 'Py_NewRef(key)' , None ,
238
+ '''
239
+ if (global_stash2 == NULL) Py_RETURN_NONE;
240
+ Py_IncRef(global_stash2);
241
+ return global_stash2;
242
+ ''' ]),
243
+ Slot (NO_GROUP , 'tp_descr_set' , 'int $name$(PyObject* self, PyObject* key, PyObject* value)' , ['0' , None ,
244
+ '''
245
+ Py_IncRef(value);
246
+ Py_XDECREF(global_stash2);
247
+ global_stash2 = value;
248
+ return 0;
249
+ ''' ])
189
250
]
190
251
191
252
@@ -362,7 +423,7 @@ def choose_random(l):
362
423
classes_count = max (3 , rand .randint (1 , 5 )) # Make it more likely that it's 3...
363
424
classes = []
364
425
test_module_name = f"test{ test_case_idx } "
365
- c_source = '#include <Python.h> \n \n '
426
+ c_source = C_SOURCE_HEADER
366
427
py_source = SLOTS_TESTER
367
428
native_classes = []
368
429
for i in range (classes_count ):
0 commit comments