Merge pull request #7561 from tk0miya/7143_typing.final

Support @final decorator
This commit is contained in:
Takeshi KOMIYA authored and GitHub committed 2020-04-28 22:57:56 +09:00
commit a8a2d59403
10 files changed
+255 -2

No files matched your search

@@ -0,0 +1,14 @@
import typing
from typing import final
@typing.final
class Class:
"""docstring"""
@final
def meth1(self):
"""docstring"""
def meth2(self):
"""docstring"""
+33
View File
@@ -1691,3 +1691,36 @@ def test_cython():
' Docstring.',
'',
]
@pytest.mark.skipif(sys.version_info < (3, 8),
reason='typing.final is available since python3.8')
@pytest.mark.usefixtures('setup_test')
def test_final():
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.final', options)
assert list(actual) == [
'',
'.. py:module:: target.final',
'',
'',
'.. py:class:: Class',
' :module: target.final',
' :final:',
'',
' docstring',
'',
'',
' .. py:method:: Class.meth1()',
' :module: target.final',
' :final:',
'',
' docstring',
'',
'',
' .. py:method:: Class.meth2()',
' :module: target.final',
'',
' docstring',
'',
]
+43 -1
View File
@@ -499,6 +499,34 @@ def test_pyfunction(app):
assert domain.objects['example.func2'] == ('index', 'example.func2', 'function')
def test_pyclass_options(app):
text = (".. py:class:: Class1\n"
".. py:class:: Class2\n"
" :final:\n")
domain = app.env.get_domain('py')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, (addnodes.index,
[desc, ([desc_signature, ([desc_annotation, "class "],
[desc_name, "Class1"])],
[desc_content, ()])],
addnodes.index,
[desc, ([desc_signature, ([desc_annotation, "final class "],
[desc_name, "Class2"])],
[desc_content, ()])]))
# class
assert_node(doctree[0], addnodes.index,
entries=[('single', 'Class1 (built-in class)', 'Class1', '', None)])
assert 'Class1' in domain.objects
assert domain.objects['Class1'] == ('index', 'Class1', 'class')
# :final:
assert_node(doctree[2], addnodes.index,
entries=[('single', 'Class2 (built-in class)', 'Class2', '', None)])
assert 'Class2' in domain.objects
assert domain.objects['Class2'] == ('index', 'Class2', 'class')
def test_pymethod_options(app):
text = (".. py:class:: Class\n"
"\n"
@@ -512,7 +540,9 @@ def test_pymethod_options(app):
" .. py:method:: meth5\n"
" :property:\n"
" .. py:method:: meth6\n"
" :abstractmethod:\n")
" :abstractmethod:\n"
" .. py:method:: meth7\n"
" :final:\n")
domain = app.env.get_domain('py')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, (addnodes.index,
@@ -529,6 +559,8 @@ def test_pymethod_options(app):
addnodes.index,
desc,
addnodes.index,
desc,
addnodes.index,
desc)])]))
# method
@@ -589,6 +621,16 @@ def test_pymethod_options(app):
assert 'Class.meth6' in domain.objects
assert domain.objects['Class.meth6'] == ('index', 'Class.meth6', 'method')
# :final:
assert_node(doctree[1][1][12], addnodes.index,
entries=[('single', 'meth7() (Class method)', 'Class.meth7', '', None)])
assert_node(doctree[1][1][13], ([desc_signature, ([desc_annotation, "final "],
[desc_name, "meth7"],
[desc_parameterlist, ()])],
[desc_content, ()]))
assert 'Class.meth7' in domain.objects
assert domain.objects['Class.meth7'] == ('index', 'Class.meth7', 'method')
def test_pyclassmethod(app):
text = (".. py:class:: Class\n"
+78
View File
@@ -374,3 +374,81 @@ def test_formfeed_char():
parser = Parser(source)
parser.parse()
assert parser.comments == {('Foo', 'attr'): 'comment'}
def test_typing_final():
source = ('import typing\n'
'\n'
'@typing.final\n'
'def func(): pass\n'
'\n'
'@typing.final\n'
'class Foo:\n'
' @typing.final\n'
' def meth(self):\n'
' pass\n')
parser = Parser(source)
parser.parse()
assert parser.finals == ['func', 'Foo', 'Foo.meth']
def test_typing_final_from_import():
source = ('from typing import final\n'
'\n'
'@final\n'
'def func(): pass\n'
'\n'
'@final\n'
'class Foo:\n'
' @final\n'
' def meth(self):\n'
' pass\n')
parser = Parser(source)
parser.parse()
assert parser.finals == ['func', 'Foo', 'Foo.meth']
def test_typing_final_import_as():
source = ('import typing as foo\n'
'\n'
'@foo.final\n'
'def func(): pass\n'
'\n'
'@foo.final\n'
'class Foo:\n'
' @typing.final\n'
' def meth(self):\n'
' pass\n')
parser = Parser(source)
parser.parse()
assert parser.finals == ['func', 'Foo']
def test_typing_final_from_import_as():
source = ('from typing import final as bar\n'
'\n'
'@bar\n'
'def func(): pass\n'
'\n'
'@bar\n'
'class Foo:\n'
' @final\n'
' def meth(self):\n'
' pass\n')
parser = Parser(source)
parser.parse()
assert parser.finals == ['func', 'Foo']
def test_typing_final_not_imported():
source = ('@typing.final\n'
'def func(): pass\n'
'\n'
'@typing.final\n'
'class Foo:\n'
' @final\n'
' def meth(self):\n'
' pass\n')
parser = Parser(source)
parser.parse()
assert parser.finals == []