@@ -78,6 +78,18 @@ def test(fun, name):
7878 else:
7979 print(type(e))
8080
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+
8193 obj = Klass()
8294 test(lambda: bool(obj), "bool(obj)")
8395 test(lambda: len(obj), "len(obj)")
@@ -86,10 +98,23 @@ def test(fun, name):
8698 test(lambda: obj.foo, "obj.foo")
8799 test(lambda: obj.bar, "obj.bar")
88100
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+
89110 test(lambda: obj.__bool__(), "obj.__bool__()")
90111 test(lambda: obj.__len__(), "obj.__len__()")
91112 test(lambda: obj.__getattr__('bar'), "obj.__getattr__('bar')")
92113 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')")
93118
94119 class Dummy1:
95120 pass
@@ -143,6 +168,14 @@ def compile_ext(name):
143168 )
144169'''
145170
171+ # language=C
172+ C_SOURCE_HEADER = '''
173+ #include <Python.h>
174+
175+ PyObject *global_stash1;
176+ PyObject *global_stash2;
177+ '''
178+
146179
147180def write_all (filename , text ):
148181 with open (filename , 'w+' ) as f :
@@ -182,10 +215,38 @@ def tp_decl(self, name_prefix):
182215 Slot ('tp_as_number' , 'nb_bool' , 'int $name$(PyObject* self)' , ['1' , '0' , None ]),
183216 Slot ('tp_as_sequence' , 'sq_length' , 'Py_ssize_t $name$(PyObject* self)' , ['0' , '1' , '42' , None ]),
184217 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+ ''' ])
189250]
190251
191252
@@ -362,7 +423,7 @@ def choose_random(l):
362423 classes_count = max (3 , rand .randint (1 , 5 )) # Make it more likely that it's 3...
363424 classes = []
364425 test_module_name = f"test{ test_case_idx } "
365- c_source = '#include <Python.h> \n \n '
426+ c_source = C_SOURCE_HEADER
366427 py_source = SLOTS_TESTER
367428 native_classes = []
368429 for i in range (classes_count ):
0 commit comments