Commit c03afec7 authored by Matti Picus's avatar Matti Picus Committed by Stefan Behnel

ENH: add more tests and fixes for @property cdef decorator (GH-3115)

parent 43cdef76
...@@ -875,8 +875,6 @@ class ExprNode(Node): ...@@ -875,8 +875,6 @@ class ExprNode(Node):
# #
src = self src = self
src_type = self.type 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): if self.check_for_coercion_error(dst_type, env):
return self return self
...@@ -3637,10 +3635,7 @@ class IndexNode(_IndexingBaseNode): ...@@ -3637,10 +3635,7 @@ class IndexNode(_IndexingBaseNode):
self.nogil = env.nogil self.nogil = env.nogil
base_type = self.base.type base_type = self.base.type
if base_type.is_cfunction: if not base_type.is_cfunction:
if self.base.entry.is_cgetter:
base_type = base_type.return_type
else:
self.index = self.index.analyse_types(env) self.index = self.index.analyse_types(env)
self.original_index_type = self.index.type self.original_index_type = self.index.type
...@@ -3727,10 +3722,7 @@ class IndexNode(_IndexingBaseNode): ...@@ -3727,10 +3722,7 @@ class IndexNode(_IndexingBaseNode):
def analyse_as_c_array(self, env, is_slice): def analyse_as_c_array(self, env, is_slice):
base_type = self.base.type base_type = self.base.type
if hasattr(self.base, 'entry') and self.base.entry.is_cgetter: self.type = base_type.base_type
self.type = base_type.return_type.base_type
else:
self.type = base_type.base_type
if is_slice: if is_slice:
self.type = base_type self.type = base_type
elif self.index.type.is_pyobject: elif self.index.type.is_pyobject:
...@@ -6731,7 +6723,7 @@ class AttributeNode(ExprNode): ...@@ -6731,7 +6723,7 @@ class AttributeNode(ExprNode):
is_attribute = 1 is_attribute = 1
subexprs = ['obj'] subexprs = ['obj']
type = PyrexTypes.error_type _type = PyrexTypes.error_type
entry = None entry = None
is_called = 0 is_called = 0
needs_none_check = True needs_none_check = True
...@@ -6739,6 +6731,20 @@ class AttributeNode(ExprNode): ...@@ -6739,6 +6731,20 @@ class AttributeNode(ExprNode):
is_special_lookup = False is_special_lookup = False
is_py_attr = 0 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): def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and if (isinstance(self.obj, NameNode) and
self.obj.is_cython_module and not self.obj.is_cython_module and not
...@@ -7014,7 +7020,7 @@ class AttributeNode(ExprNode): ...@@ -7014,7 +7020,7 @@ class AttributeNode(ExprNode):
# (foo = pycfunction(foo_func_obj)) and need to go through # (foo = pycfunction(foo_func_obj)) and need to go through
# regular Python lookup as well # regular Python lookup as well
if (entry.is_variable and not entry.fused_cfunction) or entry.is_cmethod: 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 self.member = entry.cname
return return
else: else:
...@@ -7034,7 +7040,7 @@ class AttributeNode(ExprNode): ...@@ -7034,7 +7040,7 @@ class AttributeNode(ExprNode):
# mangle private '__*' Python attributes used inside of a class # mangle private '__*' Python attributes used inside of a class
self.attribute = env.mangle_class_private_name(self.attribute) self.attribute = env.mangle_class_private_name(self.attribute)
self.member = self.attribute self.member = self.attribute
self.type = py_object_type self._type = py_object_type
self.is_py_attr = 1 self.is_py_attr = 1
if not obj_type.is_pyobject and not obj_type.is_error: if not obj_type.is_pyobject and not obj_type.is_error:
...@@ -11210,10 +11216,6 @@ class NumBinopNode(BinopNode): ...@@ -11210,10 +11216,6 @@ class NumBinopNode(BinopNode):
self.operand2 = self.operand2.coerce_to(self.type, env) self.operand2 = self.operand2.coerce_to(self.type, env)
def compute_c_result_type(self, type1, type2): 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): if self.c_types_okay(type1, type2):
widest_type = PyrexTypes.widest_numeric_type(type1, type2) widest_type = PyrexTypes.widest_numeric_type(type1, type2)
if widest_type is PyrexTypes.c_bint_type: if widest_type is PyrexTypes.c_bint_type:
...@@ -12218,10 +12220,6 @@ class CmpNode(object): ...@@ -12218,10 +12220,6 @@ class CmpNode(object):
operand2 = self.operand2 operand2 = self.operand2
type1 = operand1.type type1 = operand1.type
type2 = operand2.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 new_common_type = None
......
...@@ -134,6 +134,10 @@ def sum(Foo f): ...@@ -134,6 +134,10 @@ def sum(Foo f):
# notices the alias and replaces the __getattr__ in c by f->f0 anyway # notices the alias and replaces the __getattr__ in c by f->f0 anyway
return f.field0 + f.field1 + f.field2 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 ######## ######## getter.pxd ########
# Access base Foo fields from C via getter functions # Access base Foo fields from C via getter functions
...@@ -175,7 +179,20 @@ def check_10(getter.Foo f): ...@@ -175,7 +179,20 @@ def check_10(getter.Foo f):
return f.fieldF1 != 10 return f.fieldF1 != 10
def vec0(getter.Foo f): 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 ######## ######## getter_fail0.pyx ########
...@@ -201,7 +218,7 @@ cdef extern from "foo.h": ...@@ -201,7 +218,7 @@ cdef extern from "foo.h":
######## runner.py ######## ######## runner.py ########
import warnings import warnings
import foo_extension, getter0, getter1 import foo_extension, getter0, getter1, getter2
def sum(f): def sum(f):
# pure python field access, but code is identical to cython cdef sum # pure python field access, but code is identical to cython cdef sum
...@@ -225,6 +242,12 @@ opaque_foo = foo_extension.OpaqueFoo(23, 123, 1023) ...@@ -225,6 +242,12 @@ opaque_foo = foo_extension.OpaqueFoo(23, 123, 1023)
opaque_ret = getter0.sum(opaque_foo) opaque_ret = getter0.sum(opaque_foo)
assert opaque_ret == ret assert opaque_ret == ret
val = getter2.check_pyobj(opaque_foo)
assert val is True
val = getter2.check_unary(opaque_foo)
assert val == -123
try: try:
f0 = opaque_ret.field0 f0 = opaque_ret.field0
assert False assert False
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment