diff options
author | Matti Picus <matti.picus@gmail.com> | 2019-12-23 09:06:37 +0200 |
---|---|---|
committer | Stefan Behnel <stefan_ml@behnel.de> | 2019-12-23 08:06:37 +0100 |
commit | c03afec7a7a2e44f26a1c74b9d57b65557f184e5 (patch) | |
tree | 8a7af0413c3681cf5df5c07f231bc691fa8cc09d | |
parent | 43cdef76c81637f52c53139f0ff15f7e40cfd3e7 (diff) | |
download | cython-c03afec7a7a2e44f26a1c74b9d57b65557f184e5.tar.gz |
ENH: add more tests and fixes for @property cdef decorator (GH-3115)
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 40 | ||||
-rw-r--r-- | tests/run/ext_attr_getter.srctree | 27 |
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 |