Skip to content

Commit bb2a9d6

Browse files
committed
Add test for member kind precedence
1 parent 2607224 commit bb2a9d6

File tree

4 files changed

+98
-25
lines changed

4 files changed

+98
-25
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@
4949
GRAALPYTHON = sys.implementation.name == "graalpy"
5050

5151

52+
def assert_raises(err, fn, *args, **kwargs):
53+
raised = False
54+
try:
55+
fn(*args, **kwargs)
56+
except err:
57+
raised = True
58+
assert raised
59+
60+
5261
def unhandled_error_compare(x, y):
5362
if (isinstance(x, BaseException) and isinstance(y, BaseException)):
5463
return type(x) == type(y)
@@ -552,6 +561,11 @@ def CPyExtType(name, code, **kwargs):
552561
{{NULL, NULL, 0, NULL}}
553562
}};
554563
564+
static struct PyGetSetDef {name}_getset[] = {{
565+
""" + ("""{tp_getset},""" if "tp_getset" in kwargs else "") + """
566+
{{NULL, NULL, NULL, NULL, NULL}}
567+
}};
568+
555569
static struct PyMemberDef {name}_members[] = {{
556570
""" + ("""{tp_members},""" if "tp_members" in kwargs else "") + """
557571
{{NULL, 0, 0, 0, NULL}}
@@ -587,7 +601,7 @@ def CPyExtType(name, code, **kwargs):
587601
{tp_iternext}, /* tp_iternext */
588602
{name}_methods, /* tp_methods */
589603
{name}_members, /* tp_members */
590-
{tp_getset}, /* tp_getset */
604+
{name}_getset, /* tp_getset */
591605
{tp_base}, /* tp_base */
592606
{tp_dict}, /* tp_dict */
593607
{tp_descr_get}, /* tp_descr_get */

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

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -37,21 +37,11 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
import sys
41-
from . import CPyExtType
40+
from . import CPyExtType, assert_raises
4241

4342
__dir__ = __file__.rpartition("/")[0]
4443

4544

46-
def assert_raises(err, fn, *args, **kwargs):
47-
raised = False
48-
try:
49-
fn(*args, **kwargs)
50-
except err:
51-
raised = True
52-
assert raised
53-
54-
5545
def _reference_classmethod(args):
5646
if isinstance(args[0], type(list.append)):
5747
return classmethod(args[0])()
@@ -279,4 +269,4 @@ def test_member(self):
279269
assert_raises(TypeError, setattr, obj, "member_char", "xyz")
280270
assert obj.member_char == "x"
281271

282-
warnings.resetwarnings()
272+
warnings.resetwarnings()

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,11 @@
3838
# SOFTWARE.
3939
import types
4040

41-
from . import CPyExtType, CPyExtTestCase, unhandled_error_compare, CPyExtFunction
41+
from . import CPyExtType, CPyExtTestCase, unhandled_error_compare, CPyExtFunction, assert_raises
4242

4343
__dir__ = __file__.rpartition("/")[0]
4444

4545

46-
def assert_raises(err, fn, *args, **kwargs):
47-
raised = False
48-
try:
49-
fn(*args, **kwargs)
50-
except err:
51-
raised = True
52-
assert raised
53-
54-
5546
def _reference_classmethod(args):
5647
if isinstance(args[0], type(list.append)):
5748
return classmethod(args[0])()

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

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
import sys
4141

42-
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, GRAALPYTHON, unhandled_error_compare
42+
from . import CPyExtType, CPyExtTestCase, CPyExtFunction, GRAALPYTHON, unhandled_error_compare, assert_raises
4343

4444
__dir__ = __file__.rpartition("/")[0]
4545

@@ -744,6 +744,84 @@ class X(_A, B):
744744
x = X()
745745
assert x.foo == "foo"
746746

747+
def test_getset(self):
748+
TestGetter = CPyExtType(
749+
"TestGetter",
750+
"""
751+
static PyObject* foo_getter(PyObject* self, void* unused) {
752+
return PyUnicode_FromString("getter");
753+
}
754+
""",
755+
tp_getset='{"foo", foo_getter, (setter)NULL, NULL, NULL}',
756+
)
757+
obj = TestGetter()
758+
assert obj.foo == 'getter'
759+
760+
def call_set():
761+
obj.foo = 'set'
762+
763+
assert_raises(AttributeError, call_set)
764+
765+
TestSetter = CPyExtType(
766+
"TestSetter",
767+
"""
768+
static int state;
769+
770+
static PyObject* foo_getter(PyObject* self, void* unused) {
771+
if (state == 0)
772+
return PyUnicode_FromString("unset");
773+
else
774+
return PyUnicode_FromString("set");
775+
}
776+
777+
static int foo_setter(PyObject* self, PyObject* val, void* unused) {
778+
state = val != NULL;
779+
return 0;
780+
}
781+
""",
782+
tp_getset='{"foo", foo_getter, (setter)foo_setter, NULL, NULL}',
783+
)
784+
obj = TestSetter()
785+
assert obj.foo == 'unset'
786+
obj.foo = 'asdf'
787+
assert obj.foo == 'set'
788+
del obj.foo
789+
assert obj.foo == 'unset'
790+
791+
def test_member_kind_precedence(self):
792+
TestWithConflictingMember1 = CPyExtType(
793+
"TestWithConflictingMember1",
794+
"""
795+
static PyObject* foo_method(PyObject* self, PyObject* unused) {
796+
return PyUnicode_FromString("method");
797+
}
798+
799+
static PyObject* foo_getter(PyObject* self, void* unused) {
800+
return PyUnicode_FromString("getter");
801+
}
802+
""",
803+
cmembers="PyObject* foo_member;",
804+
tp_members='{"foo", T_OBJECT, offsetof(TestWithConflictingMember1Object, foo_member), 0, NULL}',
805+
tp_methods='{"foo", foo_method, METH_NOARGS, ""}',
806+
tp_getset='{"foo", foo_getter, (setter)NULL, NULL, NULL}',
807+
)
808+
obj = TestWithConflictingMember1()
809+
assert obj.foo() == 'method'
810+
811+
TestWithConflictingMember2 = CPyExtType(
812+
"TestWithConflictingMember2",
813+
"""
814+
static PyObject* foo_getter(PyObject* self, void* unused) {
815+
return PyUnicode_FromString("getter");
816+
}
817+
""",
818+
cmembers="PyObject* foo_member;",
819+
tp_members='{"foo", T_OBJECT, offsetof(TestWithConflictingMember2Object, foo_member), 0, NULL}',
820+
tp_getset='{"foo", foo_getter, (setter)NULL, NULL, NULL}',
821+
)
822+
obj = TestWithConflictingMember2()
823+
assert obj.foo is None # The member takes precedence
824+
747825
def test_slot_precedence(self):
748826
MapAndSeq = CPyExtType("MapAndSeq",
749827
'''

0 commit comments

Comments
 (0)