Skip to content

Commit

Permalink
Merge pull request #3540 from rayl/fix-3348
Browse files Browse the repository at this point in the history
Fix #3348: Show decorators in literalinclude and viewcode directives
  • Loading branch information
tk0miya authored Mar 12, 2017
2 parents ba0209c + 560c8ab commit 6fbc421
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Features added
* HTML buildre uses experimental HTML5 writer if ``html_experimental_html5_builder`` is True
and docutils 0.13 and newer is installed.
* LaTeX macros to customize space before and after tables in PDF output (refs #3504)
* #3348: Show decorators in literalinclude and viewcode directives

Bugs fixed
----------
Expand Down
7 changes: 6 additions & 1 deletion sphinx/pycode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ def find_tags(self):
namespace = [] # type: List[unicode]
stack = [] # type: List[Tuple[unicode, unicode, unicode, int]]
indent = 0
decopos = None
defline = False
expect_indent = False
emptylines = 0
Expand All @@ -319,8 +320,12 @@ def tokeniter(ignore = (token.COMMENT,)):
name = next(tokeniter)[1] # type: ignore
namespace.append(name)
fullname = '.'.join(namespace)
stack.append((tok, fullname, spos[0], indent))
stack.append((tok, fullname, decopos or spos[0], indent))
defline = True
decopos = None
elif type == token.OP and tok == '@':
if decopos is None:
decopos = spos[0]
elif type == token.INDENT:
expect_indent = False
indent += 1
Expand Down
16 changes: 16 additions & 0 deletions tests/roots/test-directive-code/py-decorators.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Literally included file using Python highlighting
# -*- coding: utf-8 -*-

@class_decorator
@other_decorator()
class TheClass(object):

@method_decorator
@other_decorator()
def the_method():
pass

@function_decorator
@other_decorator()
def the_function():
pass
17 changes: 17 additions & 0 deletions tests/roots/test-directive-code/py-decorators.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
py-decorators
=============

Various decorators
------------------

.. literalinclude:: py-decorators.inc
:name: literal_include_pydecorators_1
:pyobject: TheClass

.. literalinclude:: py-decorators.inc
:name: literal_include_pydecorators_2
:pyobject: TheClass.the_method

.. literalinclude:: py-decorators.inc
:name: literal_include_pydecorators_3
:pyobject: the_function
5 changes: 5 additions & 0 deletions tests/roots/test-ext-viewcode/spam/mod1.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
mod1
"""

def decorator(f):
return f

@decorator
def func1(a, b):
"""
this is func1
"""
return a, b


@decorator
class Class1(object):
"""
this is Class1
Expand Down
5 changes: 5 additions & 0 deletions tests/roots/test-ext-viewcode/spam/mod2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
mod2
"""

def decorator(f):
return f

@decorator
def func2(a, b):
"""
this is func2
"""
return a, b


@decorator
class Class2(object):
"""
this is Class2
Expand Down
42 changes: 42 additions & 0 deletions tests/test_directive_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,3 +454,45 @@ def test_literalinclude_classes(app, status, warning):
assert len(literalinclude) > 0
assert 'bar baz' == literalinclude[0].get('classes')
assert 'literal_include' == literalinclude[0].get('names')


@pytest.mark.sphinx('xml', testroot='directive-code')
def test_literalinclude_pydecorators(app, status, warning):
app.builder.build(['py-decorators'])
et = etree_parse(app.outdir / 'py-decorators.xml')
secs = et.findall('./section/section')

literal_include = secs[0].findall('literal_block')
assert len(literal_include) == 3

actual = literal_include[0].text
expect = (
'@class_decorator\n'
'@other_decorator()\n'
'class TheClass(object):\n'
'\n'
' @method_decorator\n'
' @other_decorator()\n'
' def the_method():\n'
' pass\n'
)
assert actual == expect

actual = literal_include[1].text
expect = (
' @method_decorator\n'
' @other_decorator()\n'
' def the_method():\n'
' pass\n'
)
assert actual == expect

actual = literal_include[2].text
expect = (
'@function_decorator\n'
'@other_decorator()\n'
'def the_function():\n'
' pass\n'
)
assert actual == expect

1 change: 1 addition & 0 deletions tests/test_ext_viewcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def test_viewcode(app, status, warning):
assert result.count('href="_modules/spam/mod2.html#func2"') == 2
assert result.count('href="_modules/spam/mod1.html#Class1"') == 2
assert result.count('href="_modules/spam/mod2.html#Class2"') == 2
assert result.count('@decorator') == 1


@pytest.mark.sphinx(testroot='ext-viewcode', tags=['test_linkcode'])
Expand Down

0 comments on commit 6fbc421

Please sign in to comment.