diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2020-06-19 09:22:39 +0200 |
---|---|---|
committer | Stefan Behnel <stefan_ml@behnel.de> | 2020-06-19 09:22:39 +0200 |
commit | d6fa2b351666f1070200fc0e887ce383ad2fe346 (patch) | |
tree | da2e9d95f8e548e471d23583e6890678c0d1aaa7 | |
parent | 4d928725ab76216bf72a02931496f28627784ace (diff) | |
parent | 1e72c2c57efbe0aac96b961a1ba1a8dee9ada4b7 (diff) | |
download | cython-d6fa2b351666f1070200fc0e887ce383ad2fe346.tar.gz |
Merge branch 'master' of git+ssh://github.com/cython/cython
-rw-r--r-- | Cython/Compiler/ExprNodes.py | 4 | ||||
-rw-r--r-- | Cython/Compiler/ModuleNode.py | 22 | ||||
-rw-r--r-- | Cython/Compiler/Nodes.py | 56 | ||||
-rw-r--r-- | Cython/Compiler/Parsing.py | 49 | ||||
-rw-r--r-- | Cython/Compiler/PyrexTypes.py | 69 | ||||
-rw-r--r-- | Cython/Compiler/Symtab.py | 27 | ||||
-rw-r--r-- | Cython/Utility/CpdefEnums.pyx | 18 | ||||
-rw-r--r-- | docs/src/userguide/wrapping_CPlusPlus.rst | 27 | ||||
-rw-r--r-- | tests/compile/cppenum.pyx | 31 | ||||
-rw-r--r-- | tests/errors/cpp_enum_redeclare.pyx | 13 | ||||
-rw-r--r-- | tests/errors/e_cenum_with_type.pyx | 8 | ||||
-rw-r--r-- | tests/run/cpdef_scoped_enums.pyx | 20 | ||||
-rw-r--r-- | tests/run/cpdef_scoped_enums_import.srctree | 71 | ||||
-rw-r--r-- | tests/run/cpp_scoped_enums.pyx | 136 |
14 files changed, 514 insertions, 37 deletions
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index d4e5fe970..0806a2923 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -2146,7 +2146,7 @@ class NameNode(AtomicExprNode): entry = self.entry if entry.is_type and entry.type.is_extension_type: self.type_entry = entry - if entry.is_type and entry.type.is_enum: + if entry.is_type and (entry.type.is_enum or entry.type.is_cpp_enum): py_entry = Symtab.Entry(self.name, None, py_object_type) py_entry.is_pyglobal = True py_entry.scope = self.entry.scope @@ -6957,7 +6957,7 @@ class AttributeNode(ExprNode): ubcm_entry.is_unbound_cmethod = 1 ubcm_entry.scope = entry.scope return self.as_name_node(env, ubcm_entry, target=False) - elif type.is_enum: + elif type.is_enum or type.is_cpp_enum: if self.attribute in type.values: for entry in type.entry.enum_values: if entry.name == self.attribute: diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 1e1774d54..2a2bfced5 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -155,7 +155,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.create_import_star_conversion_utility_code(env) for name, entry in sorted(env.entries.items()): if (entry.create_wrapper and entry.scope is env - and entry.is_type and entry.type.is_enum): + and entry.is_type and (entry.type.is_enum or entry.type.is_cpp_enum)): entry.type.create_type_wrapper(env) def process_implementation(self, options, result): @@ -880,7 +880,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): type = entry.type if type.is_typedef: # Must test this first! self.generate_typedef(entry, code) - elif type.is_enum: + elif type.is_enum or type.is_cpp_enum: self.generate_enum_definition(entry, code) elif type.is_struct_or_union: self.generate_struct_union_definition(entry, code) @@ -957,8 +957,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln("#endif") code.putln(header) var_entries = scope.var_entries - if not var_entries: - error(entry.pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block") for attr in var_entries: code.putln( "%s;" % attr.type.declaration_code(attr.cname)) @@ -1079,7 +1077,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.mark_pos(entry.pos) type = entry.type name = entry.cname or entry.name or "" - header, footer = self.sue_header_footer(type, "enum", name) + + kind = "enum class" if entry.type.is_cpp_enum else "enum" + header, footer = self.sue_header_footer(type, kind, name) code.putln(header) enum_values = entry.enum_values if not enum_values: @@ -1093,18 +1093,20 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): for value_entry in enum_values: if value_entry.value_node is None: - value_code = value_entry.cname + value_code = value_entry.cname.split("::")[-1] else: value_code = ("%s = %s" % ( - value_entry.cname, + value_entry.cname.split("::")[-1], value_entry.value_node.result())) if value_entry is not last_entry: value_code += "," code.putln(value_code) code.putln(footer) - if entry.type.typedef_flag: - # Not pre-declared. - code.putln("typedef enum %s %s;" % (name, name)) + + if entry.type.is_enum: + if entry.type.typedef_flag: + # Not pre-declared. + code.putln("typedef enum %s %s;" % (name, name)) def generate_typeobj_predeclaration(self, entry, code): code.putln("") diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 6e9428a05..7f981b826 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -23,7 +23,7 @@ from . import TypeSlots from .PyrexTypes import py_object_type, error_type from .Symtab import (ModuleScope, LocalScope, ClosureScope, PropertyScope, StructOrUnionScope, PyClassScope, CppClassScope, TemplateScope, - punycodify_name) + CppScopedEnumScope, punycodify_name) from .Code import UtilityCode from .StringEncoding import EncodedString from . import Future @@ -1535,36 +1535,56 @@ class CppClassNode(CStructOrUnionDefNode, BlockNode): class CEnumDefNode(StatNode): - # name string or None - # cname string or None - # items [CEnumDefItemNode] - # typedef_flag boolean - # visibility "public" or "private" or "extern" - # api boolean - # in_pxd boolean - # create_wrapper boolean - # entry Entry - - child_attrs = ["items"] + # name string or None + # cname string or None + # scoped boolean Is a C++ scoped enum + # underlying_type CSimpleBaseTypeNode The underlying value type (int or C++ type) + # items [CEnumDefItemNode] + # typedef_flag boolean + # visibility "public" or "private" or "extern" + # api boolean + # in_pxd boolean + # create_wrapper boolean + # entry Entry + + child_attrs = ["items", "underlying_type"] def declare(self, env): self.entry = env.declare_enum( self.name, self.pos, - cname=self.cname, typedef_flag=self.typedef_flag, + cname=self.cname, + scoped=self.scoped, + typedef_flag=self.typedef_flag, visibility=self.visibility, api=self.api, create_wrapper=self.create_wrapper) def analyse_declarations(self, env): + scope = None + underlying_type = self.underlying_type.analyse(env) + + if not underlying_type.is_int: + error(self.underlying_type.pos, "underlying type is not an integral type") + + self.entry.type.underlying_type = underlying_type + + if self.scoped and self.items is not None: + scope = CppScopedEnumScope(self.name, env) + scope.type = self.entry.type + else: + scope = env + if self.items is not None: if self.in_pxd and not env.in_cinclude: self.entry.defined_in_pxd = 1 for item in self.items: - item.analyse_declarations(env, self.entry) + item.analyse_declarations(scope, self.entry) def analyse_expressions(self, env): return self def generate_execution_code(self, code): + if self.scoped: + return # nothing to do here for C++ enums if self.visibility == 'public' or self.api: code.mark_pos(self.pos) temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) @@ -1596,9 +1616,15 @@ class CEnumDefItemNode(StatNode): if not self.value.type.is_int: self.value = self.value.coerce_to(PyrexTypes.c_int_type, env) self.value = self.value.analyse_const_expression(env) + + if enum_entry.type.is_cpp_enum: + cname = "%s::%s" % (enum_entry.cname, self.name) + else: + cname = self.cname + entry = env.declare_const( self.name, enum_entry.type, - self.value, self.pos, cname=self.cname, + self.value, self.pos, cname=cname, visibility=enum_entry.visibility, api=enum_entry.api, create_wrapper=enum_entry.create_wrapper and enum_entry.name is None) enum_entry.enum_values.append(entry) diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index a5d8d57f9..4755f9ad1 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -3133,6 +3133,12 @@ def p_cdef_extern_block(s, pos, ctx): def p_c_enum_definition(s, pos, ctx): # s.sy == ident 'enum' s.next() + + scoped = False + if s.context.cpp and (s.sy == 'class' or (s.sy == 'IDENT' and s.systring == 'struct')): + scoped = True + s.next() + if s.sy == 'IDENT': name = s.systring s.next() @@ -3140,24 +3146,49 @@ def p_c_enum_definition(s, pos, ctx): if cname is None and ctx.namespace is not None: cname = ctx.namespace + "::" + name else: - name = None - cname = None - items = None + name = cname = None + if scoped: + s.error("Unnamed scoped enum not allowed") + + if scoped and s.sy == '(': + s.next() + underlying_type = p_c_base_type(s) + s.expect(')') + else: + underlying_type = Nodes.CSimpleBaseTypeNode( + pos, + name="int", + module_path = [], + is_basic_c_type = True, + signed = 1, + complex = 0, + longness = 0 + ) + s.expect(':') items = [] + if s.sy != 'NEWLINE': p_c_enum_line(s, ctx, items) else: s.next() # 'NEWLINE' s.expect_indent() + while s.sy not in ('DEDENT', 'EOF'): p_c_enum_line(s, ctx, items) + s.expect_dedent() + + if not items and ctx.visibility != "extern": + error(pos, "Empty enum definition not allowed outside a 'cdef extern from' block") + return Nodes.CEnumDefNode( - pos, name = name, cname = cname, items = items, - typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, - create_wrapper = ctx.overridable, - api = ctx.api, in_pxd = ctx.level == 'module_pxd') + pos, name=name, cname=cname, + scoped=scoped, items=items, + underlying_type=underlying_type, + typedef_flag=ctx.typedef_flag, visibility=ctx.visibility, + create_wrapper=ctx.overridable, + api=ctx.api, in_pxd=ctx.level == 'module_pxd') def p_c_enum_line(s, ctx, items): if s.sy != 'pass': @@ -3217,8 +3248,12 @@ def p_c_struct_or_union_definition(s, pos, ctx): s.next() s.expect_newline("Expected a newline") s.expect_dedent() + + if not attributes and ctx.visibility != "extern": + error(pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block") else: s.expect_newline("Syntax error in struct or union definition") + return Nodes.CStructOrUnionDefNode(pos, name = name, cname = cname, kind = kind, attributes = attributes, typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 984868faf..b943fbe1e 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -182,6 +182,7 @@ class PyrexType(BaseType): # is_struct_or_union boolean Is a C struct or union type # is_struct boolean Is a C struct type # is_enum boolean Is a C enum type + # is_cpp_enum boolean Is a C++ scoped enum type # is_typedef boolean Is a typedef type # is_string boolean Is a C char * type # is_pyunicode_ptr boolean Is a C PyUNICODE * type @@ -248,6 +249,7 @@ class PyrexType(BaseType): is_cpp_string = 0 is_struct = 0 is_enum = 0 + is_cpp_enum = False is_typedef = 0 is_string = 0 is_pyunicode_ptr = 0 @@ -4019,6 +4021,73 @@ class CppClassType(CType): if constructor is not None and best_match([], constructor.all_alternatives()) is None: error(pos, "C++ class must have a nullary constructor to be %s" % msg) +class CppScopedEnumType(CType): + # name string + # cname string + + is_cpp_enum = True + + def __init__(self, name, cname, underlying_type, namespace=None): + self.name = name + self.cname = cname + self.values = [] + self.underlying_type = underlying_type + self.namespace = namespace + + def __str__(self): + return self.name + + def declaration_code(self, entity_code, + for_display=0, dll_linkage=None, pyrex=0): + if pyrex or for_display: + type_name = self.name + else: + if self.namespace: + type_name = "%s::%s" % ( + self.namespace.empty_declaration_code(), + self.cname + ) + else: + type_name = "enum %s" % self.cname + type_name = public_decl(type_name, dll_linkage) + return self.base_declaration_code(type_name, entity_code) + + def create_from_py_utility_code(self, env): + if self.from_py_function: + return True + if self.underlying_type.create_from_py_utility_code(env): + self.from_py_function = '(%s)%s' % ( + self.cname, self.underlying_type.from_py_function + ) + return True + + def create_to_py_utility_code(self, env): + if self.to_py_function is not None: + return True + if self.underlying_type.create_to_py_utility_code(env): + # Using a C++11 lambda here, which is fine since + # scoped enums are a C++11 feature + self.to_py_function = '[](const %s& x){return %s((%s)x);}' % ( + self.cname, + self.underlying_type.to_py_function, + self.underlying_type.empty_declaration_code() + ) + return True + + def create_type_wrapper(self, env): + from .UtilityCode import CythonUtilityCode + rst = CythonUtilityCode.load( + "CppScopedEnumType", "CpdefEnums.pyx", + context={ + "name": self.name, + "cname": self.cname.split("::")[-1], + "items": tuple(self.values), + "underlying_type": self.underlying_type.empty_declaration_code(), + }, + outer_module_scope=env.global_scope()) + + env.use_utility_code(rst) + class TemplatePlaceholderType(CType): diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 081b4ec23..38d05e6cc 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -679,8 +679,8 @@ class Scope(object): error(pos, "'%s' previously declared as '%s'" % ( entry.name, entry.visibility)) - def declare_enum(self, name, pos, cname, typedef_flag, - visibility = 'private', api = 0, create_wrapper = 0): + def declare_enum(self, name, pos, cname, scoped, typedef_flag, + visibility='private', api=0, create_wrapper=0): if name: if not cname: if (self.in_cinclude or visibility == 'public' @@ -692,13 +692,18 @@ class Scope(object): namespace = self.outer_scope.lookup(self.name).type else: namespace = None - type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) + + if scoped: + type = PyrexTypes.CppScopedEnumType(name, cname, namespace) + else: + type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) else: type = PyrexTypes.c_anon_enum_type entry = self.declare_type(name, type, pos, cname = cname, visibility = visibility, api = api) entry.create_wrapper = create_wrapper entry.enum_values = [] + self.sue_entries.append(entry) return entry @@ -2628,6 +2633,22 @@ class CppClassScope(Scope): return scope +class CppScopedEnumScope(Scope): + # Namespace of a ScopedEnum + + def __init__(self, name, outer_scope): + Scope.__init__(self, name, outer_scope, None) + + def declare_var(self, name, type, pos, + cname=None, visibility='extern'): + # Add an entry for an attribute. + if not cname: + cname = name + entry = self.declare(name, cname, type, pos, visibility) + entry.is_variable = True + return entry + + class PropertyScope(Scope): # Scope holding the __get__, __set__ and __del__ methods for # a property of an extension type. diff --git a/Cython/Utility/CpdefEnums.pyx b/Cython/Utility/CpdefEnums.pyx index 940027314..59ffad2d9 100644 --- a/Cython/Utility/CpdefEnums.pyx +++ b/Cython/Utility/CpdefEnums.pyx @@ -60,3 +60,21 @@ else: {{for item in items}} __Pyx_globals['{{item}}'] = {{name}}({{item}}, '{{item}}') {{endfor}} + +#################### CppScopedEnumType #################### +#@requires: EnumBase +cdef dict __Pyx_globals = globals() + +if PY_VERSION_HEX >= 0x03040000: + # create new IntEnum() + __Pyx_globals["{{name}}"] = __Pyx_EnumBase('{{name}}', __Pyx_OrderedDict([ + {{for item in items}} + ('{{item}}', <{{underlying_type}}>({{name}}.{{item}})), + {{endfor}} + ])) + +else: + __Pyx_globals["{{name}}"] = type('{{name}}', (__Pyx_EnumBase,), {}) + {{for item in items}} + __Pyx_globals["{{name}}"](<{{underlying_type}}>({{name}}.{{item}}), '{{item}}') + {{endfor}} diff --git a/docs/src/userguide/wrapping_CPlusPlus.rst b/docs/src/userguide/wrapping_CPlusPlus.rst index fca022fbb..c0bb8f109 100644 --- a/docs/src/userguide/wrapping_CPlusPlus.rst +++ b/docs/src/userguide/wrapping_CPlusPlus.rst @@ -482,6 +482,33 @@ Note, however, that it is unnecessary to declare the arguments of extern functions as references (const or otherwise) as it has no impact on the caller's syntax. +Scoped Enumerations +------------------- + +Cython supports scoped enumerations (:keyword:`enum class`) in C++ mode:: + + cdef enum class Cheese: + cheddar = 1 + camembert = 2 + +As with "plain" enums, you may access the enumerators as attributes of the type. +Unlike plain enums however, the enumerators are not visible to the +enclosing scope:: + + cdef Cheese c1 = Cheese.cheddar # OK + cdef Cheese c2 = cheddar # ERROR! + +Optionally, you may specify the underlying type of a scoped enumeration. +This is especially important when declaring an external scoped enumeration +with an underlying type:: + + cdef extern from "Foo.h": + cdef enum class Spam(unsigned int): + x = 10 + y = 20 + ... + +Declaring an enum class as ``cpdef`` will create a :pep:`435`-style Python wrapper. ``auto`` Keyword ---------------- diff --git a/tests/compile/cppenum.pyx b/tests/compile/cppenum.pyx new file mode 100644 index 000000000..8431ac83b --- /dev/null +++ b/tests/compile/cppenum.pyx @@ -0,0 +1,31 @@ +# mode: compile +# tag: cpp,cpp11 + + +cpdef enum class Spam: + a, b + c + d + e + f = 42 + + +cpdef enum class Cheese(unsigned int): + x = 1 + y = 2 + + +cdef enum struct parrot_state: + alive = 1 + dead = 0 + + +cdef void eggs(): + cdef Spam s1 + s1 = Spam.a + s2 = Spam.b + + cdef Cheese c1 + c1 = Cheese.x + +eggs() diff --git a/tests/errors/cpp_enum_redeclare.pyx b/tests/errors/cpp_enum_redeclare.pyx new file mode 100644 index 000000000..3d2ae7763 --- /dev/null +++ b/tests/errors/cpp_enum_redeclare.pyx @@ -0,0 +1,13 @@ +# mode: error +# tag: cpp + +cdef enum class Spam: + a + +cdef enum class Spam: + b + +_ERRORS=""" +7:5: 'Spam' redeclared +4:5: Previous declaration is here +""" diff --git a/tests/errors/e_cenum_with_type.pyx b/tests/errors/e_cenum_with_type.pyx new file mode 100644 index 000000000..43c0e08fc --- /dev/null +++ b/tests/errors/e_cenum_with_type.pyx @@ -0,0 +1,8 @@ +# mode: error + +cdef enum Spam(int): + a, b + +_ERRORS = u""" +3:14: Expected ':', found '(' +""" diff --git a/tests/run/cpdef_scoped_enums.pyx b/tests/run/cpdef_scoped_enums.pyx new file mode 100644 index 000000000..796e0fd3c --- /dev/null +++ b/tests/run/cpdef_scoped_enums.pyx @@ -0,0 +1,20 @@ +# mode: run +# tag: cpp, cpp11 + +cdef extern from *: + """ + enum class Enum1 { + Item1 = 1, + Item2 = 2 + }; + """ + cpdef enum class Enum1: + Item1 + Item2 + + +def test_enum_to_list(): + """ + >>> test_enum_to_list() + """ + assert list(Enum1) == [1, 2] diff --git a/tests/run/cpdef_scoped_enums_import.srctree b/tests/run/cpdef_scoped_enums_import.srctree new file mode 100644 index 000000000..2d79fb05a --- /dev/null +++ b/tests/run/cpdef_scoped_enums_import.srctree @@ -0,0 +1,71 @@ +# mode: run +# tag: cpp, cpp11 + +""" +PYTHON setup.py build_ext --inplace +PYTHON -c "import runner" +""" + +######## setup.py ######## + +from Cython.Build.Dependencies import cythonize +from distutils.core import setup +setup(ext_modules=cythonize("*.pyx", language='c++')) + +setup( + ext_modules = cythonize([ + "cheese.pyx", + "import_scoped_enum_test.pyx", + "dotted_import_scoped_enum_test.pyx" + ]) +) + +######## cheese.pxd ######## +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + + +cdef extern from * namespace "Namespace": + """ + namespace Namespace { + enum class Cheese { + cheddar = 1, + camembert = 2 + }; + } + """ + cpdef enum class Cheese: + cheddar + camembert + +######## cheese.pyx ######## +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + +pass + +######## import_scoped_enum_test.pyx ######## +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + +from cheese import Cheese +from cheese cimport Cheese + +cdef Cheese c = Cheese.cheddar +assert list(Cheese) == [1, 2] + +######## dotted_import_scoped_enum_test.pyx ######## +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + + +cimport cheese + +cdef cheese.Cheese c = cheese.Cheese.cheddar +assert [cheese.Cheese.cheddar, cheese.Cheese.camembert] == [1, 2] +cdef cheese.Cheese d = int(1) + +######## runner.py ######## + +import import_scoped_enum_test +import dotted_import_scoped_enum_test diff --git a/tests/run/cpp_scoped_enums.pyx b/tests/run/cpp_scoped_enums.pyx new file mode 100644 index 000000000..7a2bc912f --- /dev/null +++ b/tests/run/cpp_scoped_enums.pyx @@ -0,0 +1,136 @@ +# mode: run +# tag: cpp, cpp11 + +from libcpp.limits cimport numeric_limits + +cdef extern from *: + """ + enum class Enum1 { + Item1, + Item2 + }; + """ + cdef enum class Enum1: + Item1 + Item2 + + +cdef extern from * namespace "Namespace1": + """ + namespace Namespace1 { + enum class Enum2 { + Item1, + Item2 + }; + } + """ + cdef enum class Enum2: + Item1 + Item2 + + +cdef enum class Enum3(int): + a = 1 + b = 2 + + +cdef extern from *: + """ + enum class sorted + { + a = 1, + b = 0 + }; + """ + cdef enum class Enum4 "sorted": + a + b + + +cdef extern from *: + """ + #include <limits> + + enum class LongIntEnum : long int { + val = std::numeric_limits<long int>::max(), + }; + """ + enum class LongIntEnum(long int): + val + + +def test_compare_enums(): + """ + >>> test_compare_enums() + (True, True, False, False) + """ + cdef Enum1 x, y + x = Enum1.Item1 + y = Enum1.Item2 + + return ( + x == Enum1.Item1, + y == Enum1.Item2, + x == Enum1.Item2, + y == Enum1.Item1 + ) + + +def test_compare_namespace_enums(): + """ + >>> test_compare_enums() + (True, True, False, False) + """ + cdef Enum2 z, w + + z = Enum2.Item1 + w = Enum2.Item2 + + return ( + z == Enum2.Item1, + w == Enum2.Item2, + z == Enum2.Item2, + w == Enum2.Item1 + ) + + +def test_coerce_to_from_py_value(object i): + """ + >>> test_coerce_to_from_py_value(1) + (True, False) + + >>> test_coerce_to_from_py_value(2) + (False, True) + + >>> test_coerce_to_from_py_value(3) + (False, False) + + >>> test_coerce_to_from_py_value(11111111111111111111111111111111111111111111) + Traceback (most recent call last): + OverflowError: Python int too large to convert to C long + """ + cdef Enum3 x = i + y = Enum3.b + + return ( + x == Enum3.a, + y == int(i) + ) + + +def test_reserved_cname(): + """ + >>> test_reserved_cname() + True + """ + cdef Enum4 x = Enum4.a + return Enum4.a == int(1) + + +def test_large_enum(): + """ + >>> test_large_enum() + True + """ + long_max = int(numeric_limits[long].max()) + return LongIntEnum.val == long_max |