summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2019-12-23 09:06:37 +0200
committerStefan Behnel <stefan_ml@behnel.de>2019-12-23 08:06:37 +0100
commitc03afec7a7a2e44f26a1c74b9d57b65557f184e5 (patch)
tree8a7af0413c3681cf5df5c07f231bc691fa8cc09d
parent43cdef76c81637f52c53139f0ff15f7e40cfd3e7 (diff)
downloadcython-c03afec7a7a2e44f26a1c74b9d57b65557f184e5.tar.gz
ENH: add more tests and fixes for @property cdef decorator (GH-3115)
-rw-r--r--Cython/Compiler/ExprNodes.py40
-rw-r--r--tests/run/ext_attr_getter.srctree27
2 files changed, 44 insertions, 23 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index 81b8786b8..0bc099ca3 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -875,8 +875,6 @@ class ExprNode(Node):
#
src = self
src_type = self.type
- if src_type.is_cfunction and src_type.entry.is_cgetter:
- src_type = src_type.return_type
if self.check_for_coercion_error(dst_type, env):
return self
@@ -3637,10 +3635,7 @@ class IndexNode(_IndexingBaseNode):
self.nogil = env.nogil
base_type = self.base.type
- if base_type.is_cfunction:
- if self.base.entry.is_cgetter:
- base_type = base_type.return_type
- else:
+ if not base_type.is_cfunction:
self.index = self.index.analyse_types(env)
self.original_index_type = self.index.type
@@ -3727,10 +3722,7 @@ class IndexNode(_IndexingBaseNode):
def analyse_as_c_array(self, env, is_slice):
base_type = self.base.type
- if hasattr(self.base, 'entry') and self.base.entry.is_cgetter:
- self.type = base_type.return_type.base_type
- else:
- self.type = base_type.base_type
+ self.type = base_type.base_type
if is_slice:
self.type = base_type
elif self.index.type.is_pyobject:
@@ -6731,7 +6723,7 @@ class AttributeNode(ExprNode):
is_attribute = 1
subexprs = ['obj']
- type = PyrexTypes.error_type
+ _type = PyrexTypes.error_type
entry = None
is_called = 0
needs_none_check = True
@@ -6739,6 +6731,20 @@ class AttributeNode(ExprNode):
is_special_lookup = False
is_py_attr = 0
+ @property
+ def type(self):
+ if self._type.is_cfunction and hasattr(self._type, 'entry') and self._type.entry.is_cgetter:
+ return self._type.return_type
+ return self._type
+
+ @type.setter
+ def type(self, value):
+ # XXX review where the attribute is set
+ # make sure it is not already a cgetter
+ if self._type.is_cfunction and hasattr(self._type, 'entry') and self._type.entry.is_cgetter:
+ error(self.pos, "%s.type already set" % self.__name__)
+ self._type = value
+
def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and
self.obj.is_cython_module and not
@@ -7014,7 +7020,7 @@ class AttributeNode(ExprNode):
# (foo = pycfunction(foo_func_obj)) and need to go through
# regular Python lookup as well
if (entry.is_variable and not entry.fused_cfunction) or entry.is_cmethod:
- self.type = entry.type
+ self._type = entry.type
self.member = entry.cname
return
else:
@@ -7034,7 +7040,7 @@ class AttributeNode(ExprNode):
# mangle private '__*' Python attributes used inside of a class
self.attribute = env.mangle_class_private_name(self.attribute)
self.member = self.attribute
- self.type = py_object_type
+ self._type = py_object_type
self.is_py_attr = 1
if not obj_type.is_pyobject and not obj_type.is_error:
@@ -11210,10 +11216,6 @@ class NumBinopNode(BinopNode):
self.operand2 = self.operand2.coerce_to(self.type, env)
def compute_c_result_type(self, type1, type2):
- if type1.is_cfunction and type1.entry.is_cgetter:
- type1 = type1.return_type
- if type2.is_cfunction and type2.entry.is_cgetter:
- type2 = type2.return_type
if self.c_types_okay(type1, type2):
widest_type = PyrexTypes.widest_numeric_type(type1, type2)
if widest_type is PyrexTypes.c_bint_type:
@@ -12218,10 +12220,6 @@ class CmpNode(object):
operand2 = self.operand2
type1 = operand1.type
type2 = operand2.type
- if type1.is_cfunction and type1.entry.is_cgetter:
- type1 = type1.return_type
- if type2.is_cfunction and type2.entry.is_cgetter:
- type2 = type2.return_type
new_common_type = None
diff --git a/tests/run/ext_attr_getter.srctree b/tests/run/ext_attr_getter.srctree
index c421b4236..682b47eaf 100644
--- a/tests/run/ext_attr_getter.srctree
+++ b/tests/run/ext_attr_getter.srctree
@@ -134,6 +134,10 @@ def sum(Foo f):
# notices the alias and replaces the __getattr__ in c by f->f0 anyway
return f.field0 + f.field1 + f.field2
+def check_pyobj(Foo f):
+ # compare the c code to the check_pyobj in getter2.pyx
+ return bool(f.field1)
+
######## getter.pxd ########
# Access base Foo fields from C via getter functions
@@ -175,7 +179,20 @@ def check_10(getter.Foo f):
return f.fieldF1 != 10
def vec0(getter.Foo f):
- return f.vector[0]
+ return f.vector[0]
+
+def check_binop(getter.Foo f):
+ return f.fieldF1 / 10
+
+######## getter2.pyx ########
+
+cimport getter
+
+def check_pyobj(getter.Foo f):
+ return bool(f.fieldF1)
+
+def check_unary(getter.Foo f):
+ return -f.fieldF1
######## getter_fail0.pyx ########
@@ -201,7 +218,7 @@ cdef extern from "foo.h":
######## runner.py ########
import warnings
-import foo_extension, getter0, getter1
+import foo_extension, getter0, getter1, getter2
def sum(f):
# pure python field access, but code is identical to cython cdef sum
@@ -225,6 +242,12 @@ opaque_foo = foo_extension.OpaqueFoo(23, 123, 1023)
opaque_ret = getter0.sum(opaque_foo)
assert opaque_ret == ret
+
+val = getter2.check_pyobj(opaque_foo)
+assert val is True
+val = getter2.check_unary(opaque_foo)
+assert val == -123
+
try:
f0 = opaque_ret.field0
assert False