Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit ef7a337

Browse files
authored
fix: format code snippets properly (#193)
* fix: format code snippets properly * test: update unit test * test: add unit test for testing with blocks of code snippet * test: parameterize unit test for indent_left * docs: add docstring to indent_code_left method
1 parent 8c32e97 commit ef7a337

2 files changed

Lines changed: 69 additions & 21 deletions

File tree

docfx_yaml/extension.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,17 @@ def extract_keyword(line):
386386
return line
387387

388388

389-
# Given lines of code, indent to left by 1 block, based on
390-
# amount of trailing white space of first line as 1 block.
391-
def indent_code_left(lines):
389+
def indent_code_left(lines, tab_space):
390+
"""Indents code lines left by tab_space.
391+
392+
Args:
393+
lines: String lines of code.
394+
tab_space: Number of spaces to indent to left by.
395+
396+
Returns:
397+
String lines of left-indented code.
398+
"""
392399
parts = lines.split("\n")
393-
# Count how much leading whitespaces there are based on first line.
394-
# lstrip(" ") removes all trailing whitespace from the string.
395-
tab_space = len(parts[0]) - len(parts[0].lstrip(" "))
396400
parts = [part[tab_space:] for part in parts]
397401
return "\n".join(parts)
398402

@@ -417,6 +421,9 @@ def _parse_docstring_summary(summary):
417421
if keyword and keyword in [CODE, CODEBLOCK]:
418422
# If we reach the end of keyword, close up the code block.
419423
if not part.startswith(" "*tab_space) or part.startswith(".."):
424+
if code_snippet:
425+
parts = [indent_code_left(part, tab_space) for part in code_snippet]
426+
summary_parts.append("\n\n".join(parts))
420427
summary_parts.append("```\n")
421428
keyword = ""
422429

@@ -428,9 +435,12 @@ def _parse_docstring_summary(summary):
428435
raise ValueError(f"Code in the code block should be indented. Please check the docstring: \n{summary}")
429436
if not part.startswith(" "*tab_space):
430437
# No longer looking at code-block, reset keyword.
438+
if code_snippet:
439+
parts = [indent_code_left(part, tab_space) for part in code_snippet]
440+
summary_parts.append("\n\n".join(parts))
431441
keyword = ""
432442
summary_parts.append("```\n")
433-
summary_parts.append(indent_code_left(part))
443+
code_snippet.append(part)
434444
continue
435445

436446
# Attributes come in 3 parts, parse the latter two here.
@@ -472,6 +482,7 @@ def _parse_docstring_summary(summary):
472482
language = part.split("::")[1].strip()
473483
summary_parts.append(f"```{language}")
474484

485+
code_snippet = []
475486
tab_space = -1
476487

477488
# Extract the name for attribute first.
@@ -490,6 +501,9 @@ def _parse_docstring_summary(summary):
490501
# Close up from the keyword if needed.
491502
if keyword and keyword in [CODE, CODEBLOCK]:
492503
# Check if it's already closed.
504+
if code_snippet:
505+
parts = [indent_code_left(part, tab_space) for part in code_snippet]
506+
summary_parts.append("\n\n".join(parts))
493507
if summary_parts[-1] != "```\n":
494508
summary_parts.append("```\n")
495509

tests/test_helpers.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,33 @@
1414
import tempfile
1515

1616
class TestGenerate(unittest.TestCase):
17-
def test_indent_code_left(self):
17+
code_testdata = [
1818
# Check that the code indents to left based on first line.
19-
code_want = \
20-
"""def foo():
21-
print('test function for indent')
22-
return ('left-indented-code')
23-
"""
24-
25-
code = \
19+
[
20+
\
2621
""" def foo():
2722
print('test function for indent')
2823
return ('left-indented-code')
24+
""",
25+
\
26+
"""def foo():
27+
print('test function for indent')
28+
return ('left-indented-code')
2929
"""
30-
code = indent_code_left(code)
31-
self.assertEqual(code, code_want)
32-
30+
],
3331
# Check that if there's no whitespace, it does not indent
34-
code_want = \
32+
[
33+
\
34+
"""
35+
print('test function for no impact indent')
36+
for i in range(10):
37+
print(i)
38+
if i%5 == 0:
39+
i += 1
40+
else:
41+
continue
42+
""",
43+
\
3544
"""
3645
print('test function for no impact indent')
3746
for i in range(10):
@@ -41,9 +50,34 @@ def test_indent_code_left(self):
4150
else:
4251
continue
4352
"""
53+
],
54+
]
55+
@parameterized.expand(code_testdata)
56+
def test_indent_code_left(self, code, code_want):
57+
parts = code.split("\n")
58+
tab_space = len(parts[0]) - len(parts[0].lstrip(" "))
59+
code_got = indent_code_left(code, tab_space)
60+
self.assertEqual(code_got, code_want)
61+
4462

45-
code_got = indent_code_left(code_want)
46-
# Confirm that nothing changes.
63+
def test_indent_code_blocks_left(self):
64+
# Check code blocks are indented properly.
65+
code_want = \
66+
"""def foo():
67+
68+
print('test function for indent')
69+
70+
return ('left-indented-blocks')
71+
"""
72+
73+
# Test with how blocks would appear in the code block
74+
code = [
75+
" def foo():",
76+
" print('test function for indent')",
77+
" return ('left-indented-blocks')\n"
78+
]
79+
tab_space = len(code[0]) - len(code[0].lstrip(" "))
80+
code_got = "\n\n".join([indent_code_left(part, tab_space) for part in code])
4781
self.assertEqual(code_got, code_want)
4882

4983

0 commit comments

Comments
 (0)