Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix docs build for numbered lists #1740

Merged
merged 13 commits into from
Sep 6, 2023
56 changes: 49 additions & 7 deletions gapic/utils/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,47 @@ def sort_lines(text: str, dedupe: bool = True) -> str:
return f'{leading}{answer}{trailing}'


def get_subsequent_line_indentation_level(list_item: str) -> int:
"""
Given a list item return the indentation level for subsequent lines.
For example, if it is a numbered list, the indentation level should be 3
as shown below.

Here subsequent lines should be indented by 2

- The quick brown fox jumps over the lazy dog. The quick brown fox jumps
over the lazy dog

Here subsequent lines should be indented by 2

+ The quick brown fox jumps over the lazy dog. The quick brown fox jumps
over the lazy dog

Here subsequent lines should be indented by 3

1. The quick brown fox jumps over the lazy dog. The quick brown fox jumps
over the lazy dog

"""
if len(list_item) >= 2 and list_item[0:2] in ['- ', '+ ']:
indentation_level = 2
elif len(list_item) >= 3 and list_item[0].isdigit() and list_item[1:3] == '. ':
parthea marked this conversation as resolved.
Show resolved Hide resolved
indentation_level = 3
else:
# Don't use any intentation level if the list item marker is not known
indentation_level = 0
return indentation_level


def is_list_item(list_item: str) -> bool:
"""
Given a string return a boolean indicating whether a list is identified.
"""
if len(list_item) < 3:
return False
return list_item.startswith('- ') or list_item.startswith('+ ') or (list_item[0].isdigit() and list_item[1:].startswith('. '))
parthea marked this conversation as resolved.
Show resolved Hide resolved


def wrap(text: str, width: int, *, offset: Optional[int] = None, indent: int = 0) -> str:
"""Wrap the given string to the given width.

Expand Down Expand Up @@ -93,11 +134,12 @@ def wrap(text: str, width: int, *, offset: Optional[int] = None, indent: int = 0
break_on_hyphens=False,
)
# Strip the first \n from the text so it is not misidentified as an
# intentionally short line below, except when the text contains `:`
# as the new line is required for lists.
# intentionally short line below, except when the text contains a list,
# as the new line is required for lists. Look for a list item marker in
# the remaining text which indicates that a list is present.
if '\n' in text:
initial_text = text.split('\n')[0]
if ":" not in initial_text:
remaining_text = "".join(text.split('\n')[1:])
if not is_list_item(remaining_text.strip()):
text = text.replace('\n', ' ', 1)

# Save the new `first` line.
Expand All @@ -121,9 +163,9 @@ def wrap(text: str, width: int, *, offset: Optional[int] = None, indent: int = 0
tokens = []
token = ''
for line in text.split('\n'):
# Ensure that lines that start with a hyphen are always on a new line
# Ensure that lines that start with a list item marker are always on a new line
# Ensure that blank lines are preserved
if (line.strip().startswith('-') or not len(line)) and token:
if (is_list_item(line.strip()) or not len(line)) and token:
tokens.append(token)
token = ''
token += line + '\n'
Expand All @@ -145,7 +187,7 @@ def wrap(text: str, width: int, *, offset: Optional[int] = None, indent: int = 0
initial_indent=' ' * indent,
# ensure that subsequent lines for lists are indented 2 spaces
subsequent_indent=' ' * indent + \
(' ' if token.strip().startswith('-') else ''),
' ' * get_subsequent_line_indentation_level(token.strip()),
text=token,
width=width,
break_on_hyphens=False,
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/utils/test_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,37 @@ def test_list_with_multiple_paragraphs():
erat. In nec est nisl. Quisque ut orci efficitur, vestibulum
ante non, vestibulum erat. Donec mollis ultricies nisl."""
assert lines.wrap(input, width=60) == expected


def test_list_with_numbered_list():
input = """Config for video classification human labeling task.
Currently two types of video classification are supported:
1. Assign labels on the entire video.
2. Split the video into multiple video clips based on camera shot, and
assign labels on each video clip."""
parthea marked this conversation as resolved.
Show resolved Hide resolved
expected = """Config for video classification human labeling task.
Currently two types of video classification are supported:

1. Assign labels on the entire video.
2. Split the video into multiple video clips based on camera
shot, and assign labels on each video clip."""
assert lines.wrap(input, width=60) == expected


def test_list_with_plus_list_item_marker():
input = """User-assigned name of the trigger. Must be unique within the project.
Trigger names must meet the following requirements:
+ They must contain only alphanumeric characters and dashes.
+ They can be 1-64 characters long.
+ They must begin and end with an alphanumeric character."""
expected = """User-assigned name of the trigger. Must
be unique within the project. Trigger
names must meet the following
requirements:

+ They must contain only alphanumeric
characters and dashes.
+ They can be 1-64 characters long.
+ They must begin and end with an
alphanumeric character."""
assert lines.wrap(input, width=40) == expected