Commit 3fed4faf authored by matham's avatar matham Committed by GitHub

Add doc support for cpdef enum (GH-3813)

parent adb44bd0
...@@ -1546,17 +1546,23 @@ class CEnumDefNode(StatNode): ...@@ -1546,17 +1546,23 @@ class CEnumDefNode(StatNode):
# in_pxd boolean # in_pxd boolean
# create_wrapper boolean # create_wrapper boolean
# entry Entry # entry Entry
# doc EncodedString or None Doc string
child_attrs = ["items", "underlying_type"] child_attrs = ["items", "underlying_type"]
doc = None
def declare(self, env): def declare(self, env):
doc = None
if Options.docstrings:
doc = embed_position(self.pos, self.doc)
self.entry = env.declare_enum( self.entry = env.declare_enum(
self.name, self.pos, self.name, self.pos,
cname=self.cname, cname=self.cname,
scoped=self.scoped, scoped=self.scoped,
typedef_flag=self.typedef_flag, typedef_flag=self.typedef_flag,
visibility=self.visibility, api=self.api, visibility=self.visibility, api=self.api,
create_wrapper=self.create_wrapper) create_wrapper=self.create_wrapper, doc=doc)
def analyse_declarations(self, env): def analyse_declarations(self, env):
scope = None scope = None
......
...@@ -3171,11 +3171,13 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -3171,11 +3171,13 @@ def p_c_enum_definition(s, pos, ctx):
s.expect(':') s.expect(':')
items = [] items = []
doc = None
if s.sy != 'NEWLINE': if s.sy != 'NEWLINE':
p_c_enum_line(s, ctx, items) p_c_enum_line(s, ctx, items)
else: else:
s.next() # 'NEWLINE' s.next() # 'NEWLINE'
s.expect_indent() s.expect_indent()
doc = p_doc_string(s)
while s.sy not in ('DEDENT', 'EOF'): while s.sy not in ('DEDENT', 'EOF'):
p_c_enum_line(s, ctx, items) p_c_enum_line(s, ctx, items)
...@@ -3191,7 +3193,7 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -3191,7 +3193,7 @@ def p_c_enum_definition(s, pos, ctx):
underlying_type=underlying_type, underlying_type=underlying_type,
typedef_flag=ctx.typedef_flag, visibility=ctx.visibility, typedef_flag=ctx.typedef_flag, visibility=ctx.visibility,
create_wrapper=ctx.overridable, create_wrapper=ctx.overridable,
api=ctx.api, in_pxd=ctx.level == 'module_pxd') api=ctx.api, in_pxd=ctx.level == 'module_pxd', doc=doc)
def p_c_enum_line(s, ctx, items): def p_c_enum_line(s, ctx, items):
if s.sy != 'pass': if s.sy != 'pass':
......
...@@ -4028,12 +4028,14 @@ class CppClassType(CType): ...@@ -4028,12 +4028,14 @@ class CppClassType(CType):
class CppScopedEnumType(CType): class CppScopedEnumType(CType):
# name string # name string
# doc string or None
# cname string # cname string
is_cpp_enum = True is_cpp_enum = True
def __init__(self, name, cname, underlying_type, namespace=None): def __init__(self, name, cname, underlying_type, namespace=None, doc=None):
self.name = name self.name = name
self.doc = doc
self.cname = cname self.cname = cname
self.values = [] self.values = []
self.underlying_type = underlying_type self.underlying_type = underlying_type
...@@ -4088,6 +4090,7 @@ class CppScopedEnumType(CType): ...@@ -4088,6 +4090,7 @@ class CppScopedEnumType(CType):
"cname": self.cname.split("::")[-1], "cname": self.cname.split("::")[-1],
"items": tuple(self.values), "items": tuple(self.values),
"underlying_type": self.underlying_type.empty_declaration_code(), "underlying_type": self.underlying_type.empty_declaration_code(),
"enum_doc": self.doc,
}, },
outer_module_scope=env.global_scope()) outer_module_scope=env.global_scope())
...@@ -4143,6 +4146,7 @@ def is_optional_template_param(type): ...@@ -4143,6 +4146,7 @@ def is_optional_template_param(type):
class CEnumType(CIntLike, CType): class CEnumType(CIntLike, CType):
# name string # name string
# doc string or None
# cname string or None # cname string or None
# typedef_flag boolean # typedef_flag boolean
# values [string], populated during declaration analysis # values [string], populated during declaration analysis
...@@ -4151,8 +4155,9 @@ class CEnumType(CIntLike, CType): ...@@ -4151,8 +4155,9 @@ class CEnumType(CIntLike, CType):
signed = 1 signed = 1
rank = -1 # Ranks below any integer type rank = -1 # Ranks below any integer type
def __init__(self, name, cname, typedef_flag, namespace=None): def __init__(self, name, cname, typedef_flag, namespace=None, doc=None):
self.name = name self.name = name
self.doc = doc
self.cname = cname self.cname = cname
self.values = [] self.values = []
self.typedef_flag = typedef_flag self.typedef_flag = typedef_flag
...@@ -4194,7 +4199,9 @@ class CEnumType(CIntLike, CType): ...@@ -4194,7 +4199,9 @@ class CEnumType(CIntLike, CType):
env.use_utility_code(CythonUtilityCode.load( env.use_utility_code(CythonUtilityCode.load(
"EnumType", "CpdefEnums.pyx", "EnumType", "CpdefEnums.pyx",
context={"name": self.name, context={"name": self.name,
"items": tuple(self.values)}, "items": tuple(self.values),
"enum_doc": self.doc,
},
outer_module_scope=env.global_scope())) outer_module_scope=env.global_scope()))
......
...@@ -682,7 +682,7 @@ class Scope(object): ...@@ -682,7 +682,7 @@ class Scope(object):
entry.name, entry.visibility)) entry.name, entry.visibility))
def declare_enum(self, name, pos, cname, scoped, typedef_flag, def declare_enum(self, name, pos, cname, scoped, typedef_flag,
visibility='private', api=0, create_wrapper=0): visibility='private', api=0, create_wrapper=0, doc=None):
if name: if name:
if not cname: if not cname:
if (self.in_cinclude or visibility == 'public' if (self.in_cinclude or visibility == 'public'
...@@ -696,9 +696,9 @@ class Scope(object): ...@@ -696,9 +696,9 @@ class Scope(object):
namespace = None namespace = None
if scoped: if scoped:
type = PyrexTypes.CppScopedEnumType(name, cname, namespace) type = PyrexTypes.CppScopedEnumType(name, cname, namespace, doc=doc)
else: else:
type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace) type = PyrexTypes.CEnumType(name, cname, typedef_flag, namespace, doc=doc)
else: else:
type = PyrexTypes.c_anon_enum_type type = PyrexTypes.c_anon_enum_type
entry = self.declare_type(name, type, pos, cname = cname, entry = self.declare_type(name, type, pos, cname = cname,
......
...@@ -51,12 +51,16 @@ if PY_VERSION_HEX >= 0x03040000: ...@@ -51,12 +51,16 @@ if PY_VERSION_HEX >= 0x03040000:
('{{item}}', {{item}}), ('{{item}}', {{item}}),
{{endfor}} {{endfor}}
])) ]))
{{if enum_doc is not None}}
{{name}}.__doc__ = {{ repr(enum_doc) }}
{{endif}}
{{for item in items}} {{for item in items}}
__Pyx_globals['{{item}}'] = {{name}}.{{item}} __Pyx_globals['{{item}}'] = {{name}}.{{item}}
{{endfor}} {{endfor}}
else: else:
class {{name}}(__Pyx_EnumBase): class {{name}}(__Pyx_EnumBase):
pass {{ repr(enum_doc) if enum_doc is not None else 'pass' }}
{{for item in items}} {{for item in items}}
__Pyx_globals['{{item}}'] = {{name}}({{item}}, '{{item}}') __Pyx_globals['{{item}}'] = {{name}}({{item}}, '{{item}}')
{{endfor}} {{endfor}}
...@@ -78,3 +82,7 @@ else: ...@@ -78,3 +82,7 @@ else:
{{for item in items}} {{for item in items}}
__Pyx_globals["{{name}}"](<{{underlying_type}}>({{name}}.{{item}}), '{{item}}') __Pyx_globals["{{name}}"](<{{underlying_type}}>({{name}}.{{item}}), '{{item}}')
{{endfor}} {{endfor}}
{{if enum_doc is not None}}
__Pyx_globals["{{name}}"].__doc__ = {{ repr(enum_doc) }}
{{endif}}
...@@ -11,5 +11,19 @@ cpdef enum PxdEnum: ...@@ -11,5 +11,19 @@ cpdef enum PxdEnum:
RANK_1 = 37 RANK_1 = 37
RANK_2 = 389 RANK_2 = 389
cpdef enum cpdefPxdDocEnum:
"""Home is where...
"""
RANK_6 = 159
cpdef enum cpdefPxdDocLineEnum:
"""Home is where..."""
RANK_7 = 889
cdef enum PxdSecretEnum: cdef enum PxdSecretEnum:
RANK_3 = 5077 RANK_8 = 5077
cdef enum cdefPxdDocEnum:
"""the heart is.
"""
RANK_9 = 2458
...@@ -11,6 +11,8 @@ True ...@@ -11,6 +11,8 @@ True
True True
>>> FIVE == 5 or FIVE >>> FIVE == 5 or FIVE
True True
>>> ELEVEN == 11 or ELEVEN
True
>>> SEVEN # doctest: +ELLIPSIS >>> SEVEN # doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
NameError: ...name 'SEVEN' is not defined NameError: ...name 'SEVEN' is not defined
...@@ -29,6 +31,10 @@ True ...@@ -29,6 +31,10 @@ True
True True
>>> RANK_2 == 389 or RANK_2 >>> RANK_2 == 389 or RANK_2
True True
>>> RANK_6 == 159 or RANK_6
True
>>> RANK_7 == 889 or RANK_7
True
>>> RANK_3 # doctest: +ELLIPSIS >>> RANK_3 # doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
NameError: ...name 'RANK_3' is not defined NameError: ...name 'RANK_3' is not defined
...@@ -48,7 +54,6 @@ Traceback (most recent call last): ...@@ -48,7 +54,6 @@ Traceback (most recent call last):
NameError: ...name 'IntEnum' is not defined NameError: ...name 'IntEnum' is not defined
""" """
cdef extern from *: cdef extern from *:
cpdef enum: # ExternPyx cpdef enum: # ExternPyx
ONE "1" ONE "1"
...@@ -63,9 +68,24 @@ cpdef enum PyxEnum: ...@@ -63,9 +68,24 @@ cpdef enum PyxEnum:
THREE = 3 THREE = 3
FIVE = 5 FIVE = 5
cpdef enum cpdefPyxDocEnum:
"""Home is where...
"""
ELEVEN = 11
cpdef enum cpdefPyxDocLineEnum:
"""Home is where..."""
FOURTEEN = 14
cdef enum SecretPyxEnum: cdef enum SecretPyxEnum:
SEVEN = 7 SEVEN = 7
cdef enum cdefPyxDocEnum:
"""the heart is.
"""
FIVE_AND_SEVEN = 5077
def test_as_variable_from_cython(): def test_as_variable_from_cython():
""" """
>>> test_as_variable_from_cython() >>> test_as_variable_from_cython()
...@@ -89,3 +109,21 @@ def verify_resolution_GH1533(): ...@@ -89,3 +109,21 @@ def verify_resolution_GH1533():
""" """
THREE = 100 THREE = 100
return int(PyxEnum.THREE) return int(PyxEnum.THREE)
def check_docs():
"""
>>> PxdEnum.__doc__ not in ("Home is where...\\n ", "Home is where...")
True
>>> PyxEnum.__doc__ not in ("Home is where...\\n ", "Home is where...")
True
>>> cpdefPyxDocEnum.__doc__ == "Home is where...\\n "
True
>>> cpdefPxdDocEnum.__doc__ == "Home is where...\\n "
True
>>> cpdefPyxDocLineEnum.__doc__
'Home is where...'
>>> cpdefPxdDocLineEnum.__doc__
'Home is where...'
"""
pass
...@@ -7,14 +7,36 @@ cdef extern from *: ...@@ -7,14 +7,36 @@ cdef extern from *:
Item1 = 1, Item1 = 1,
Item2 = 2 Item2 = 2
}; };
enum class Enum2 {
Item4 = 4,
Item5 = 5
};
""" """
cpdef enum class Enum1: cpdef enum class Enum1:
Item1 Item1
Item2 Item2
cpdef enum class Enum2:
"""Apricots and other fruits.
"""
Item4
Item5
def test_enum_to_list(): def test_enum_to_list():
""" """
>>> test_enum_to_list() >>> test_enum_to_list()
""" """
assert list(Enum1) == [1, 2] assert list(Enum1) == [1, 2]
assert list(Enum2) == [4, 5]
def test_enum_doc():
"""
>>> Enum2.__doc__ == "Apricots and other fruits.\\n "
True
>>> Enum1.__doc__ != "Apricots and other fruits.\\n "
True
"""
pass
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