Skip to content

Commit a48e759

Browse files
committed
Fix: copy property object if accessor functions are changed.
1 parent 708db54 commit a48e759

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_property.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, 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
@@ -72,6 +72,22 @@ def prop_x(self):
7272
del self._x
7373

7474

75+
class X(object):
76+
@property
77+
def prop_x(self):
78+
return self._prop_x
79+
80+
@prop_x.setter
81+
def prop_x(self, new_val):
82+
self._prop_x = new_val
83+
return new_val
84+
85+
class Y(X):
86+
@X.prop_x.setter
87+
def prop_x(self, ax):
88+
X.prop_x.fset(self, ax)
89+
90+
7591
def test_properties():
7692
c = C(10)
7793
assert c.prop_x == 10
@@ -96,3 +112,5 @@ def test_properties():
96112
except AttributeError:
97113
not_found = True
98114
assert not_found
115+
116+
assert X.prop_x is not Y.prop_x

graalpython/lib-graalpython/property.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,13 @@ def __delete__(self, instance):
9696
return self.fdel(instance)
9797

9898
def setter(self, func):
99-
self.fset = func
100-
return self
99+
return self.__copy(fset=func)
101100

102101
def deleter(self, func):
103-
self.fdel = func
104-
return self
102+
return self.__copy(fdel=func)
105103

106104
def getter(self, func):
107-
self.fget = func
108-
return self
105+
return self.__copy(fget=func)
109106

110107
def __repr__(self):
111108
return "'".join([
@@ -115,3 +112,9 @@ def __repr__(self):
115112
getattr(self._owner, "__name__", str(self._owner)),
116113
" objects>"
117114
])
115+
116+
def __copy(self, fget=None, fset=None, fdel=None):
117+
_fget = fget if fget is not None else self.fget
118+
_fset = fset if fset is not None else self.fset
119+
_fdel = fdel if fdel is not None else self.fdel
120+
return type(self)(fget=_fget, fset=_fset, fdel=_fdel, doc=self.doc, name=self.name)

graalpython/lib-graalpython/python_cext.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -972,17 +972,18 @@ def AddMember(primary, tpDict, name, memberType, offset, canSet, doc):
972972
# the ReadMemberFunctions and WriteMemberFunctions don't have a wrapper to
973973
# convert arguments to Sulong, so we can avoid boxing the offsets into PInts
974974
pclass = to_java_type(primary)
975-
member = property()
976975
getter = ReadMemberFunctions[memberType]
977976
def member_getter(self):
978977
return to_java(getter(to_sulong(self), TrufflePInt_AsPrimitive(offset, 1, 8)))
979-
member.getter(member_getter)
978+
member_fget = member_getter
979+
member_fset = None
980980
if canSet:
981981
setter = WriteMemberFunctions[memberType]
982982
def member_setter(self, value):
983983
setter(to_sulong(self), TrufflePInt_AsPrimitive(offset, 1, 8), to_sulong(value))
984-
member.setter(member_setter)
985-
member.__doc__ = doc
984+
member_fset = member_setter
985+
# nb: do not use member.setter/getter because they create copies of the property
986+
member = property(fget=member_fget, fset=member_fset, doc=doc)
986987
type_dict = to_java(tpDict)
987988
type_dict[name] = member
988989

0 commit comments

Comments
 (0)