Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cython
Commits
2c7c22f5
Commit
2c7c22f5
authored
Jun 18, 2020
by
Ashwin Srinath
Committed by
GitHub
Jun 18, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for C++ scoped enums with "enum class" and "enum struct" (GH-3640)
Closes #1603.
parent
e87a5559
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
514 additions
and
37 deletions
+514
-37
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+2
-2
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+12
-10
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+41
-15
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+42
-7
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+69
-0
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+24
-3
Cython/Utility/CpdefEnums.pyx
Cython/Utility/CpdefEnums.pyx
+18
-0
docs/src/userguide/wrapping_CPlusPlus.rst
docs/src/userguide/wrapping_CPlusPlus.rst
+27
-0
tests/compile/cppenum.pyx
tests/compile/cppenum.pyx
+31
-0
tests/errors/cpp_enum_redeclare.pyx
tests/errors/cpp_enum_redeclare.pyx
+13
-0
tests/errors/e_cenum_with_type.pyx
tests/errors/e_cenum_with_type.pyx
+8
-0
tests/run/cpdef_scoped_enums.pyx
tests/run/cpdef_scoped_enums.pyx
+20
-0
tests/run/cpdef_scoped_enums_import.srctree
tests/run/cpdef_scoped_enums_import.srctree
+71
-0
tests/run/cpp_scoped_enums.pyx
tests/run/cpp_scoped_enums.pyx
+136
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
2c7c22f5
...
...
@@ -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
:
...
...
Cython/Compiler/ModuleNode.py
View file @
2c7c22f5
...
...
@@ -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
(
""
)
...
...
Cython/Compiler/Nodes.py
View file @
2c7c22f5
...
...
@@ -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
)
...
...
Cython/Compiler/Parsing.py
View file @
2c7c22f5
...
...
@@ -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
,
...
...
Cython/Compiler/PyrexTypes.py
View file @
2c7c22f5
...
...
@@ -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
):
...
...
Cython/Compiler/Symtab.py
View file @
2c7c22f5
...
...
@@ -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.
...
...
Cython/Utility/CpdefEnums.pyx
View file @
2c7c22f5
...
...
@@ -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
}}
docs/src/userguide/wrapping_CPlusPlus.rst
View file @
2c7c22f5
...
...
@@ -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
----------------
...
...
tests/compile/cppenum.pyx
0 → 100644
View file @
2c7c22f5
# 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
()
tests/errors/cpp_enum_redeclare.pyx
0 → 100644
View file @
2c7c22f5
# 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
"""
tests/errors/e_cenum_with_type.pyx
0 → 100644
View file @
2c7c22f5
# mode: error
cdef
enum
Spam
(
int
):
a
,
b
_ERRORS
=
u"""
3:14: Expected ':', found '('
"""
tests/run/cpdef_scoped_enums.pyx
0 → 100644
View file @
2c7c22f5
# 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
]
tests/run/cpdef_scoped_enums_import.srctree
0 → 100644
View file @
2c7c22f5
# 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
tests/run/cpp_scoped_enums.pyx
0 → 100644
View file @
2c7c22f5
# 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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment