From 521185b469246edb514ef66cf04a99cd9117553b Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Thu, 11 Mar 2010 17:21:13 -0300 Subject: [PATCH] remove dependency on structmember.h --- Cython/Compiler/ModuleNode.py | 34 +----- Cython/Compiler/Nodes.py | 16 +-- Cython/Compiler/ParseTreeTransforms.py | 35 +++++- Cython/Compiler/PyrexTypes.py | 145 +++++-------------------- Cython/Compiler/Symtab.py | 24 ++-- Cython/Compiler/TypeSlots.py | 5 +- tests/compile/extpymemberdef.pyx | 2 +- tests/errors/cdef_members_T517.pyx | 26 +++++ tests/errors/e_extweakref.pyx | 3 + tests/run/cdef_members_T517.pyx | 134 +++++++++++++++++++++++ tests/run/embedsignatures.pyx | 14 +++ tests/run/typedfieldbug_T303.pyx | 12 +- 12 files changed, 263 insertions(+), 187 deletions(-) create mode 100644 tests/errors/cdef_members_T517.pyx create mode 100644 tests/run/cdef_members_T517.pyx diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index ef7e2420..c0010d77 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -426,6 +426,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.globalstate["end"].putln("#endif /* Py_PYTHON_H */") code.put(""" +#include /* For offsetof */ +#ifndef offsetof +#define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif + #ifndef PY_LONG_LONG #define PY_LONG_LONG LONG_LONG #endif @@ -903,7 +908,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_descr_set_function(scope, code) self.generate_property_accessors(scope, code) self.generate_method_table(scope, code) - self.generate_member_table(scope, code) self.generate_getset_table(scope, code) self.generate_typeobj_definition(full_module_name, entry, code) @@ -1529,34 +1533,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln( "};") - def generate_member_table(self, env, code): - #print "ModuleNode.generate_member_table: scope =", env ### - if env.public_attr_entries: - code.putln("") - code.putln( - "static struct PyMemberDef %s[] = {" % - env.member_table_cname) - type = env.parent_type - if type.typedef_flag: - objstruct = type.objstruct_cname - else: - objstruct = "struct %s" % type.objstruct_cname - for entry in env.public_attr_entries: - type_code = entry.type.pymemberdef_typecode - if entry.visibility == 'readonly': - flags = "READONLY" - else: - flags = "0" - code.putln('{(char *)"%s", %s, %s, %s, 0},' % ( - entry.name, - type_code, - "offsetof(%s, %s)" % (objstruct, entry.cname), - flags)) - code.putln( - "{0, 0, 0, 0, 0}") - code.putln( - "};") - def generate_getset_table(self, env, code): if env.property_entries: code.putln("") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index f5da2453..76418599 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -891,13 +891,13 @@ class CVarDefNode(StatNode): # declarators [CDeclaratorNode] # in_pxd boolean # api boolean - # need_properties [entry] + # properties [entry] # decorators [cython.locals(...)] or None # directive_locals { string : NameNode } locals defined by cython.locals(...) child_attrs = ["base_type", "declarators"] - need_properties = () + properties = () decorators = None directive_locals = {} @@ -912,15 +912,12 @@ class CVarDefNode(StatNode): # so do conversion ourself rather than rely on the CPython mechanism (through # a property; made in AnalyseDeclarationsTransform). if (dest_scope.is_c_class_scope - and self.visibility == 'public' - and base_type.is_pyobject - and (base_type.is_builtin_type or base_type.is_extension_type)): - self.need_properties = [] + and self.visibility in ('public', 'readonly')): + self.properties = [] need_property = True - visibility = 'private' else: need_property = False - visibility = self.visibility + visibility = self.visibility for declarator in self.declarators: name_declarator, type = declarator.analyse(base_type, env) @@ -951,8 +948,7 @@ class CVarDefNode(StatNode): entry = dest_scope.declare_var(name, type, declarator.pos, cname = cname, visibility = visibility, is_cdef = 1) if need_property: - self.need_properties.append(entry) - entry.needs_property = 1 + self.properties.append(entry) class CStructOrUnionDefNode(StatNode): diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 678260ca..d6cbd5c5 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -952,6 +952,11 @@ property NAME: def __set__(self, value): ATTR = value """, level='c_class') + basic_property_ro = TreeFragment(u""" +property NAME: + def __get__(self): + return ATTR + """, level='c_class') def __call__(self, root): self.env_stack = [root.scope] @@ -1037,12 +1042,9 @@ property NAME: # to ensure all CNameDeclaratorNodes are visited. self.visitchildren(node) - if node.need_properties: - # cdef public attributes may need type testing on - # assignment, so we create a property accesss - # mechanism for them. + if node.properties: stats = [] - for entry in node.need_properties: + for entry in node.properties: property = self.create_Property(entry) property.analyse_declarations(node.dest_scope) self.visit(property) @@ -1052,13 +1054,34 @@ property NAME: return None def create_Property(self, entry): - template = self.basic_property + if entry.visibility == 'public': + template = self.basic_property + elif entry.visibility == 'readonly': + template = self.basic_property_ro property = template.substitute({ u"ATTR": AttributeNode(pos=entry.pos, obj=NameNode(pos=entry.pos, name="self"), attribute=entry.name), }, pos=entry.pos).stats[0] property.name = entry.name + # --------------------------------------- + # XXX This should go to AutoDocTransforms + # --------------------------------------- + if self.current_directives['embedsignature']: + attr_name = entry.name + type_name = entry.type.declaration_code("", for_display=1) + default_value = '' + if not entry.type.is_pyobject: + type_name = "'%s'" % type_name + elif entry.type.is_extension_type: + type_name = entry.type.module_name + '.' + type_name + if entry.init is not None: + default_value = ' = ' + entry.init + elif entry.init_to_none: + default_value = ' = ' + repr(None) + docstring = attr_name + ': ' + type_name + default_value + property.doc = EncodedString(docstring) + # --------------------------------------- return property class AnalyseExpressionsTransform(CythonTransform): diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 3d6a011f..8e1f7f99 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -56,7 +56,6 @@ class PyrexType(BaseType): # is_buffer boolean Is buffer access type # has_attributes boolean Has C dot-selectable attributes # default_value string Initial value - # pymemberdef_typecode string Type code for PyMemberDef struct # # declaration_code(entity_code, # for_display = 0, dll_linkage = None, pyrex = 0) @@ -109,7 +108,6 @@ class PyrexType(BaseType): is_buffer = 0 has_attributes = 0 default_value = "" - pymemberdef_typecode = None def resolve(self): # If a typedef, returns the base type. @@ -198,18 +196,6 @@ class CTypedefType(BaseType): self.typedef_cname = cname self.typedef_base_type = base_type self.typedef_is_external = is_external - # Make typecodes in external typedefs use typesize-neutral macros - if is_external: - typecode = None - if base_type.is_int: - if base_type.signed == 0: - typecode = "__Pyx_T_UNSIGNED_INT" - else: - typecode = "__Pyx_T_SIGNED_INT" - elif base_type.is_float and not rank_to_type_name[base_type.rank] == "long double": - typecode = "__Pyx_T_FLOATING" - if typecode: - self.pymemberdef_typecode = "%s(%s)" % (typecode, cname) def resolve(self): return self.typedef_base_type.resolve() @@ -349,7 +335,6 @@ class PyObjectType(PyrexType): name = "object" is_pyobject = 1 default_value = "0" - pymemberdef_typecode = "T_OBJECT" buffer_defaults = None is_extern = False is_subclassed = False @@ -618,10 +603,9 @@ class CNumericType(CType): sign_words = ("unsigned ", "", "signed ") - def __init__(self, rank, signed = 1, pymemberdef_typecode = None): + def __init__(self, rank, signed = 1): self.rank = rank self.signed = signed - self.pymemberdef_typecode = pymemberdef_typecode def sign_and_name(self): s = self.sign_words[self.signed] @@ -787,8 +771,8 @@ class CIntType(CNumericType): from_py_function = "__Pyx_PyInt_AsInt" exception_value = -1 - def __init__(self, rank, signed, pymemberdef_typecode = None, is_returncode = 0): - CNumericType.__init__(self, rank, signed, pymemberdef_typecode) + def __init__(self, rank, signed, is_returncode = 0): + CNumericType.__init__(self, rank, signed) self.is_returncode = is_returncode if self.from_py_function == "__Pyx_PyInt_AsInt": self.from_py_function = self.get_type_conversion() @@ -887,8 +871,8 @@ class CFloatType(CNumericType): exception_value = -1 - def __init__(self, rank, pymemberdef_typecode = None, math_h_modifier = ''): - CNumericType.__init__(self, rank, 1, pymemberdef_typecode) + def __init__(self, rank, math_h_modifier = ''): + CNumericType.__init__(self, rank, 1) self.math_h_modifier = math_h_modifier def assignable_from_resolved_type(self, src_type): @@ -1988,7 +1972,6 @@ class CStringType(object): class CUTF8CharArrayType(CStringType, CArrayType): # C 'char []' type. - pymemberdef_typecode = "T_STRING_INPLACE" is_unicode = 1 to_py_function = "PyUnicode_DecodeUTF8" @@ -2000,8 +1983,6 @@ class CUTF8CharArrayType(CStringType, CArrayType): class CCharArrayType(CStringType, CArrayType): # C 'char []' type. - pymemberdef_typecode = "T_STRING_INPLACE" - def __init__(self, size): CArrayType.__init__(self, c_char_type, size) @@ -2009,8 +1990,6 @@ class CCharArrayType(CStringType, CArrayType): class CCharPtrType(CStringType, CPtrType): # C 'char *' type. - pymemberdef_typecode = "T_STRING" - def __init__(self): CPtrType.__init__(self, c_char_type) @@ -2018,8 +1997,6 @@ class CCharPtrType(CStringType, CPtrType): class CUCharPtrType(CStringType, CPtrType): # C 'unsigned char *' type. - pymemberdef_typecode = "T_STRING" - to_py_function = "__Pyx_PyBytes_FromUString" from_py_function = "__Pyx_PyBytes_AsUString" @@ -2085,30 +2062,30 @@ c_void_type = CVoidType() c_void_ptr_type = CPtrType(c_void_type) c_void_ptr_ptr_type = CPtrType(c_void_ptr_type) -c_uchar_type = CIntType(0, 0, "T_UBYTE") -c_ushort_type = CIntType(1, 0, "T_USHORT") -c_uint_type = CUIntType(2, 0, "T_UINT") -c_ulong_type = CULongType(3, 0, "T_ULONG") -c_ulonglong_type = CULongLongType(6, 0, "T_ULONGLONG") - -c_char_type = CIntType(0, 1, "T_CHAR") -c_short_type = CIntType(1, 1, "T_SHORT") -c_int_type = CIntType(2, 1, "T_INT") -c_long_type = CLongType(3, 1, "T_LONG") -c_longlong_type = CLongLongType(6, 1, "T_LONGLONG") -c_bint_type = CBIntType(2, 1, "T_INT") - -c_schar_type = CIntType(0, 2, "T_CHAR") -c_sshort_type = CIntType(1, 2, "T_SHORT") -c_sint_type = CIntType(2, 2, "T_INT") -c_slong_type = CLongType(3, 2, "T_LONG") -c_slonglong_type = CLongLongType(6, 2, "T_LONGLONG") - -c_py_ssize_t_type = CPySSizeTType(4, 2, "T_PYSSIZET") -c_size_t_type = CSizeTType(5, 0, "T_SIZET") - -c_float_type = CFloatType(7, "T_FLOAT", math_h_modifier='f') -c_double_type = CFloatType(8, "T_DOUBLE") +c_uchar_type = CIntType(0, 0) +c_ushort_type = CIntType(1, 0) +c_uint_type = CUIntType(2, 0) +c_ulong_type = CULongType(3, 0) +c_ulonglong_type = CULongLongType(6, 0) + +c_char_type = CIntType(0, 1) +c_short_type = CIntType(1, 1) +c_int_type = CIntType(2, 1) +c_long_type = CLongType(3, 1) +c_longlong_type = CLongLongType(6, 1) +c_bint_type = CBIntType(2, 1) + +c_schar_type = CIntType(0, 2) +c_sshort_type = CIntType(1, 2) +c_sint_type = CIntType(2, 2) +c_slong_type = CLongType(3, 2) +c_slonglong_type = CLongLongType(6, 2) + +c_py_ssize_t_type = CPySSizeTType(4, 2) +c_size_t_type = CSizeTType(5, 0) + +c_float_type = CFloatType(7, math_h_modifier='f') +c_double_type = CFloatType(8) c_longdouble_type = CFloatType(9, math_h_modifier='l') c_double_complex_type = CComplexType(c_double_type) @@ -2123,7 +2100,7 @@ c_int_ptr_type = CPtrType(c_int_type) c_py_ssize_t_ptr_type = CPtrType(c_py_ssize_t_type) c_size_t_ptr_type = CPtrType(c_size_t_type) -c_returncode_type = CIntType(2, 1, "T_INT", is_returncode = 1) +c_returncode_type = CIntType(2, 1, is_returncode = 1) c_anon_enum_type = CAnonEnumType(-1, 1) @@ -2492,68 +2469,6 @@ type_conversion_predeclarations = """ static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); -#if !defined(T_PYSSIZET) -#if PY_VERSION_HEX < 0x02050000 -#define T_PYSSIZET T_INT -#elif !defined(T_LONGLONG) -#define T_PYSSIZET \\ - ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \\ - ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : -1)) -#else -#define T_PYSSIZET \\ - ((sizeof(Py_ssize_t) == sizeof(int)) ? T_INT : \\ - ((sizeof(Py_ssize_t) == sizeof(long)) ? T_LONG : \\ - ((sizeof(Py_ssize_t) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))) -#endif -#endif - - -#if !defined(T_ULONGLONG) -#define __Pyx_T_UNSIGNED_INT(x) \\ - ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \\ - ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \\ - ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \\ - ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : -1)))) -#else -#define __Pyx_T_UNSIGNED_INT(x) \\ - ((sizeof(x) == sizeof(unsigned char)) ? T_UBYTE : \\ - ((sizeof(x) == sizeof(unsigned short)) ? T_USHORT : \\ - ((sizeof(x) == sizeof(unsigned int)) ? T_UINT : \\ - ((sizeof(x) == sizeof(unsigned long)) ? T_ULONG : \\ - ((sizeof(x) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))))) -#endif -#if !defined(T_LONGLONG) -#define __Pyx_T_SIGNED_INT(x) \\ - ((sizeof(x) == sizeof(char)) ? T_BYTE : \\ - ((sizeof(x) == sizeof(short)) ? T_SHORT : \\ - ((sizeof(x) == sizeof(int)) ? T_INT : \\ - ((sizeof(x) == sizeof(long)) ? T_LONG : -1)))) -#else -#define __Pyx_T_SIGNED_INT(x) \\ - ((sizeof(x) == sizeof(char)) ? T_BYTE : \\ - ((sizeof(x) == sizeof(short)) ? T_SHORT : \\ - ((sizeof(x) == sizeof(int)) ? T_INT : \\ - ((sizeof(x) == sizeof(long)) ? T_LONG : \\ - ((sizeof(x) == sizeof(PY_LONG_LONG)) ? T_LONGLONG : -1))))) -#endif - -#define __Pyx_T_FLOATING(x) \\ - ((sizeof(x) == sizeof(float)) ? T_FLOAT : \\ - ((sizeof(x) == sizeof(double)) ? T_DOUBLE : -1)) - -#if !defined(T_SIZET) -#if !defined(T_ULONGLONG) -#define T_SIZET \\ - ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \\ - ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : -1)) -#else -#define T_SIZET \\ - ((sizeof(size_t) == sizeof(unsigned int)) ? T_UINT : \\ - ((sizeof(size_t) == sizeof(unsigned long)) ? T_ULONG : \\ - ((sizeof(size_t) == sizeof(unsigned PY_LONG_LONG)) ? T_ULONGLONG : -1))) -#endif -#endif - static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); static CYTHON_INLINE size_t __Pyx_PyInt_AsSize_t(PyObject*); diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 02f825d1..834a20db 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -791,7 +791,7 @@ class ModuleScope(Scope): self.doc_cname = Naming.moddoc_cname self.utility_code_list = [] self.module_entries = {} - self.python_include_files = ["Python.h", "structmember.h"] + self.python_include_files = ["Python.h"] self.include_files = [] self.type_names = dict(outer_scope.type_names) self.pxd_file_loaded = 0 @@ -1321,10 +1321,8 @@ class CClassScope(ClassScope): # #typeobj_cname string or None # #objstruct_cname string # method_table_cname string - # member_table_cname string # getset_table_cname string # has_pyobject_attrs boolean Any PyObject attributes? - # public_attr_entries boolean public/readonly attrs # property_entries [Entry] # defined boolean Defined in .pxd file # implemented boolean Defined in .pyx file @@ -1336,10 +1334,8 @@ class CClassScope(ClassScope): ClassScope.__init__(self, name, outer_scope) if visibility != 'extern': self.method_table_cname = outer_scope.mangle(Naming.methtab_prefix, name) - self.member_table_cname = outer_scope.mangle(Naming.memtab_prefix, name) self.getset_table_cname = outer_scope.mangle(Naming.gstab_prefix, name) self.has_pyobject_attrs = 0 - self.public_attr_entries = [] self.property_entries = [] self.inherited_var_entries = [] self.defined = 0 @@ -1380,16 +1376,14 @@ class CClassScope(ClassScope): error(pos, "Attribute of extension type cannot be declared %s" % visibility) if visibility in ('public', 'readonly'): - if type.pymemberdef_typecode: - self.public_attr_entries.append(entry) - if name == "__weakref__": - error(pos, "Special attribute __weakref__ cannot be exposed to Python") - else: - error(pos, - "C attribute of type '%s' cannot be accessed from Python" % type) - if visibility == 'public' and type.is_extension_type: - error(pos, - "Non-generic Python attribute cannot be exposed for writing from Python") + if name == "__weakref__": + error(pos, "Special attribute __weakref__ cannot be exposed to Python") + if not type.is_pyobject: + if (not type.create_to_py_utility_code(self) or + (visibility=='public' and not + type.create_from_py_utility_code(self))): + error(pos, + "C attribute of type '%s' cannot be accessed from Python" % type) return entry else: if type is unspecified_type: diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index 1399fcf3..232c51d2 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -370,10 +370,7 @@ class MemberTableSlot(SlotDescriptor): # Slot descriptor for the table of Python-accessible attributes. def slot_code(self, scope): - if scope.public_attr_entries: - return scope.member_table_cname - else: - return "0" + return "0" class GetSetSlot(SlotDescriptor): diff --git a/tests/compile/extpymemberdef.pyx b/tests/compile/extpymemberdef.pyx index 58a62a38..61bf6d1b 100644 --- a/tests/compile/extpymemberdef.pyx +++ b/tests/compile/extpymemberdef.pyx @@ -8,7 +8,7 @@ cdef class Spam: cdef public float f cdef public double d cdef public char *s - cdef public char a[42] + cdef readonly char a[42] cdef public object o cdef readonly int r cdef readonly Spam e diff --git a/tests/errors/cdef_members_T517.pyx b/tests/errors/cdef_members_T517.pyx new file mode 100644 index 00000000..ee95a408 --- /dev/null +++ b/tests/errors/cdef_members_T517.pyx @@ -0,0 +1,26 @@ +ctypedef void* VoidP + +cdef class Spam: + cdef VoidP vp0 + cdef readonly VoidP vp2 + cdef public VoidP vp1 + +ctypedef struct Foo: + int i + +cdef class Bar: + cdef Foo foo0 + cdef readonly Foo foo2 + cdef public Foo foo1 + pass + +_ERRORS = u""" +5:24: C attribute of type 'VoidP' cannot be accessed from Python +5:24: Cannot convert 'VoidP' to Python object +6:24: C attribute of type 'VoidP' cannot be accessed from Python +6:24: Cannot convert 'VoidP' to Python object +6:24: Cannot convert Python object to 'VoidP' +14:22: C attribute of type 'Foo' cannot be accessed from Python +14:22: Cannot convert Python object to 'Foo' +""" + diff --git a/tests/errors/e_extweakref.pyx b/tests/errors/e_extweakref.pyx index 6ce4cf3c..8354dcb5 100644 --- a/tests/errors/e_extweakref.pyx +++ b/tests/errors/e_extweakref.pyx @@ -13,7 +13,10 @@ cdef void f(): x = c.__weakref__ c.__weakref__ = x _ERRORS = u""" +5:20: Illegal use of special attribute __weakref__ +5:20: Illegal use of special attribute __weakref__ 5:20: Special attribute __weakref__ cannot be exposed to Python +8:22: Illegal use of special attribute __weakref__ 8:22: Special attribute __weakref__ cannot be exposed to Python 13:6: Illegal use of special attribute __weakref__ 14:2: Illegal use of special attribute __weakref__ diff --git a/tests/run/cdef_members_T517.pyx b/tests/run/cdef_members_T517.pyx new file mode 100644 index 00000000..22996817 --- /dev/null +++ b/tests/run/cdef_members_T517.pyx @@ -0,0 +1,134 @@ +#cython: embedsignature=True +__doc__ = u""" +>>> a = A() +>>> a.h = 7 +>>> a.i = 127 +>>> a.l = 255 +>>> a.q = 255 +>>> a.f = 1.0/2.0 +>>> a.d = 1/2.0 + 1/4.0 +>>> a.g = 1/2.0 + 1/4.0 + 1/8.0 +>>> a.Zf = 1+2j +>>> a.Zd = 3+4j +>>> a.Zg = 5+6j + +>>> a.h, a.i, a.l +(7, 127, 255) +>>> a.ro_h, a.ro_i, a.ro_l +(7, 127, 255) +>>> a.f, a.d, a.g +(0.5, 0.75, 0.875) +>>> a.ro_f, a.ro_d, a.ro_g +(0.5, 0.75, 0.875) +>>> a.Zf, a.Zd, a.Zg +((1+2j), (3+4j), (5+6j)) +>>> a.ro_Zf, a.ro_Zd, a.ro_Zg +((1+2j), (3+4j), (5+6j)) + +>>> b = B() +>>> b.a0 #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... +>>> b.b0 #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... +>>> b.c0 #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... + +>>> isinstance(b.a1, type(None)) +True +>>> isinstance(b.a2, type(None)) +True +>>> isinstance(b.b1, list) +True +>>> isinstance(b.b2, list) +True +>>> isinstance(b.c1, A) +True +>>> isinstance(b.c2, A) +True + +>>> b.a1 = a +>>> b.a1 is not b.a2 +True + +>>> b.b1 = 1 #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +TypeError: ... +>>> b.c1 = 1 #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +TypeError: ... +>>> b.a2 = None #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... +>>> b.b2 = [] #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... +>>> b.c2 = A() #doctest: +ELLIPSIS +Traceback (most recent call last): + ... +AttributeError: ... +""" + +cdef class A: + + cdef public short h + cdef public int i + cdef public long l + cdef public long long q + cdef public float f + cdef public double d + cdef public long double g + cdef public float complex Zf + cdef public double complex Zd + cdef public long double complex Zg + + cdef readonly short ro_h + cdef readonly int ro_i + cdef readonly long ro_l + cdef readonly long long ro_q + cdef readonly float ro_f + cdef readonly double ro_d + cdef readonly long double ro_g + cdef readonly float complex ro_Zf + cdef readonly double complex ro_Zd + cdef readonly long double complex ro_Zg + + def __cinit__(self): + self.ro_h = 7 + self.ro_i = 127 + self.ro_l = 255 + self.ro_q = 255 + self.ro_f = 1.0/2.0 + self.ro_d = 1/2.0 + 1/4.0 + self.ro_g = 1/2.0 + 1/4.0 + 1/8.0 + self.ro_Zf = 1+2j + self.ro_Zd = 3+4j + self.ro_Zg = 5+6j + + +cdef class B: + + cdef object a0 + cdef public object a1 + cdef readonly object a2 + + cdef list b0 + cdef public list b1 + cdef readonly list b2 + + cdef A c0 + cdef public A c1 + cdef readonly A c2 + + def __cinit__(self): + self.b0 = self.b1 = self.b2 = [] + self.c0 = self.c1 = self.c2 = A() diff --git a/tests/run/embedsignatures.pyx b/tests/run/embedsignatures.pyx index 3fafdbed..0bfcdcad 100644 --- a/tests/run/embedsignatures.pyx +++ b/tests/run/embedsignatures.pyx @@ -5,6 +5,15 @@ __doc__ = ur""" >>> print (Ext.__doc__) Ext(a, b, c=None) + >>> print (Ext.attr0.__doc__) + attr0: 'int' + >>> print (Ext.attr1.__doc__) + attr1: object + >>> print (Ext.attr2.__doc__) + attr2: list + >>> print (Ext.attr3.__doc__) + attr3: embedsignatures.Ext + >>> print (Ext.a.__doc__) Ext.a(self) @@ -145,6 +154,11 @@ __doc__ = ur""" cdef class Ext: + cdef public int attr0 + cdef public attr1 + cdef public list attr2 + cdef public Ext attr3 + def __init__(self, a, b, c=None): pass diff --git a/tests/run/typedfieldbug_T303.pyx b/tests/run/typedfieldbug_T303.pyx index 82094d4b..653fa513 100644 --- a/tests/run/typedfieldbug_T303.pyx +++ b/tests/run/typedfieldbug_T303.pyx @@ -1,12 +1,12 @@ __doc__ = """ ->>> readonly() +>>> readonly() #doctest: +ELLIPSIS Traceback (most recent call last): -... -TypeError: readonly attribute + ... +TypeError: ... """ import sys -if sys.version_info[0] >= 3: +if sys.version_info[0:2] >= (2,4): __doc__ = __doc__.replace(u'TypeError:', u'AttributeError:') @@ -51,9 +51,7 @@ def f(): def longdouble_access(): """ >>> longdouble_access() - Traceback (most recent call last): - ... - SystemError: bad memberdescr type + 42.0 """ cdef object c = MyClass() print c.float_isreally_longdouble -- 2.26.2