Skip to content

Commit 46993fc

Browse files
amuellermpharrigan
authored andcommitted
add (possibly slightly off) source lines to mangled docstrings. (numpy#61)
1 parent ef988a4 commit 46993fc

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

numpydoc/numpydoc.py

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
raise RuntimeError("Sphinx 1.0.1 or newer is required")
3030

3131
from .docscrape_sphinx import get_doc_object, SphinxDocString
32-
from sphinx.util.compat import Directive
3332

3433
if sys.version_info[0] >= 3:
3534
sixu = lambda s: s
@@ -133,7 +132,7 @@ def setup(app, get_doc_object_=get_doc_object):
133132
# Extra mangling domains
134133
app.add_domain(NumpyPythonDomain)
135134
app.add_domain(NumpyCDomain)
136-
135+
137136
metadata = {'parallel_read_safe': True}
138137
return metadata
139138

@@ -184,6 +183,62 @@ class NumpyCDomain(ManglingDomainBase, CDomain):
184183
}
185184

186185

186+
def match_items(lines, content_old):
187+
"""Create items for mangled lines.
188+
189+
This function tries to match the lines in ``lines`` with the items (source
190+
file references and line numbers) in ``content_old``. The
191+
``mangle_docstrings`` function changes the actual docstrings, but doesn't
192+
keep track of where each line came from. The manging does many operations
193+
on the original lines, which are hard to track afterwards.
194+
195+
Many of the line changes come from deleting or inserting blank lines. This
196+
function tries to match lines by ignoring blank lines. All other changes
197+
(such as inserting figures or changes in the references) are completely
198+
ignored, so the generated line numbers will be off if ``mangle_docstrings``
199+
does anything non-trivial.
200+
201+
This is a best-effort function and the real fix would be to make
202+
``mangle_docstrings`` actually keep track of the ``items`` together with
203+
the ``lines``.
204+
205+
Examples
206+
--------
207+
>>> lines = ['', 'A', '', 'B', ' ', '', 'C', 'D']
208+
>>> lines_old = ['a', '', '', 'b', '', 'c']
209+
>>> items_old = [('file1.py', 0), ('file1.py', 1), ('file1.py', 2),
210+
... ('file2.py', 0), ('file2.py', 1), ('file2.py', 2)]
211+
>>> content_old = ViewList(lines_old, items=items_old)
212+
>>> match_items(lines, content_old) # doctest: +NORMALIZE_WHITESPACE
213+
[('file1.py', 0), ('file1.py', 0), ('file2.py', 0), ('file2.py', 0),
214+
('file2.py', 2), ('file2.py', 2), ('file2.py', 2), ('file2.py', 2)]
215+
>>> # first 2 ``lines`` are matched to 'a', second 2 to 'b', rest to 'c'
216+
>>> # actual content is completely ignored.
217+
218+
Notes
219+
-----
220+
The algorithm tries to match any line in ``lines`` with one in
221+
``lines_old``. It skips over all empty lines in ``lines_old`` and assigns
222+
this line number to all lines in ``lines``, unless a non-empty line is
223+
found in ``lines`` in which case it goes to the next line in ``lines_old``.
224+
225+
"""
226+
items_new = []
227+
lines_old = content_old.data
228+
items_old = content_old.items
229+
j = 0
230+
for i, line in enumerate(lines):
231+
# go to next non-empty line in old:
232+
# line.strip() checks whether the string is all whitespace
233+
while j < len(lines_old) - 1 and not lines_old[j].strip():
234+
j += 1
235+
items_new.append(items_old[j])
236+
if line.strip() and j < len(lines_old) - 1:
237+
j += 1
238+
assert(len(items_new) == len(lines))
239+
return items_new
240+
241+
187242
def wrap_mangling_directive(base_directive, objtype):
188243
class directive(base_directive):
189244
def run(self):
@@ -199,7 +254,10 @@ def run(self):
199254

200255
lines = list(self.content)
201256
mangle_docstrings(env.app, objtype, name, None, None, lines)
202-
self.content = ViewList(lines, self.content.parent)
257+
if self.content:
258+
items = match_items(lines, self.content)
259+
self.content = ViewList(lines, items=items,
260+
parent=self.content.parent)
203261

204262
return base_directive.run(self)
205263

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
if sys.version_info[:2] < (2, 6) or (3, 0) <= sys.version_info[0:2] < (3, 3):
1010
raise RuntimeError("Python version 2.6, 2.7 or >= 3.3 required.")
1111

12-
version = "0.6.0"
12+
version = "0.6.1"
1313

1414
setup(
1515
name="numpydoc",

0 commit comments

Comments
 (0)