Skip to content

Commit a9b8efe

Browse files
committed
get_block_string_indentation: simplify implementation
Replicates graphql/graphql-js@d6be64c
1 parent 362b902 commit a9b8efe

File tree

3 files changed

+57
-45
lines changed

3 files changed

+57
-45
lines changed

src/graphql/language/block_string.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import List
2-
31
__all__ = [
42
"dedent_block_string_value",
53
"print_block_string",
@@ -21,48 +19,54 @@ def dedent_block_string_value(raw_string: str) -> str:
2119
lines = raw_string.splitlines()
2220

2321
# Remove common indentation from all lines but first.
24-
common_indent = get_block_string_indentation(lines)
22+
common_indent = get_block_string_indentation(raw_string)
2523

2624
if common_indent:
2725
lines[1:] = [line[common_indent:] for line in lines[1:]]
2826

2927
# Remove leading and trailing blank lines.
30-
while lines and not lines[0].strip():
31-
lines = lines[1:]
32-
33-
while lines and not lines[-1].strip():
34-
lines = lines[:-1]
28+
start_line = 0
29+
end_line = len(lines)
30+
while start_line < end_line and is_blank(lines[start_line]):
31+
start_line += 1
32+
while end_line > start_line and is_blank(lines[end_line - 1]):
33+
end_line -= 1
3534

3635
# Return a string of the lines joined with U+000A.
37-
return "\n".join(lines)
36+
return "\n".join(lines[start_line:end_line])
37+
38+
39+
def is_blank(s: str) -> bool:
40+
"""Check whether string contains only space or tab characters."""
41+
return all(c == " " or c == "\t" for c in s)
3842

3943

40-
def get_block_string_indentation(lines: List[str]) -> int:
44+
def get_block_string_indentation(value: str) -> int:
4145
"""Get the amount of indentation for the given block string.
4246
4347
For internal use only.
4448
"""
49+
is_first_line = is_empty_line = True
50+
indent = 0
4551
common_indent = None
4652

47-
for line in lines[1:]:
48-
indent = leading_whitespace(line)
49-
if indent == len(line):
50-
continue # skip empty lines
51-
52-
if common_indent is None or indent < common_indent:
53-
common_indent = indent
54-
if common_indent == 0:
55-
break
56-
57-
return 0 if common_indent is None else common_indent
58-
59-
60-
def leading_whitespace(s: str) -> int:
61-
i = 0
62-
n = len(s)
63-
while i < n and s[i] in " \t":
64-
i += 1
65-
return i
53+
for c in value:
54+
if c in "\r\n":
55+
is_first_line = False
56+
is_empty_line = True
57+
indent = 0
58+
elif c in "\t ":
59+
indent += 1
60+
else:
61+
if (
62+
is_empty_line
63+
and not is_first_line
64+
and (common_indent is None or indent < common_indent)
65+
):
66+
common_indent = indent
67+
is_empty_line = False
68+
69+
return common_indent or 0
6670

6771

6872
def print_block_string(

src/graphql/utilities/strip_ignored_characters.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ def dedent_block_string(block_str: str) -> str:
103103
raw_str = block_str[3:-3]
104104
body = dedent_block_string_value(raw_str)
105105

106-
lines = body.splitlines()
107-
if get_block_string_indentation(lines) > 0:
106+
if get_block_string_indentation(body) > 0:
108107
body = "\n" + body
109108

110109
last_char = body[-1:]

tests/language/test_block_string.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,28 +75,37 @@ def does_not_alter_trailing_spaces():
7575

7676
def describe_get_block_string_indentation():
7777
def returns_zero_for_an_empty_list():
78-
assert get_block_string_indentation([]) == 0
78+
assert get_block_string_indentation("") == 0
7979

8080
def do_not_take_first_line_into_account():
81-
assert get_block_string_indentation([" a"]) == 0
82-
assert get_block_string_indentation([" a", " b"]) == 2
81+
assert get_block_string_indentation(" a") == 0
82+
assert get_block_string_indentation(" a\n b") == 2
8383

8484
def returns_minimal_indentation_length():
85-
assert get_block_string_indentation(["", " a", " b"]) == 1
86-
assert get_block_string_indentation(["", " a", " b"]) == 1
87-
assert get_block_string_indentation(["", " a", " b", "c"]) == 0
85+
assert get_block_string_indentation("\n a\n b") == 1
86+
assert get_block_string_indentation("\n a\n b") == 1
87+
assert get_block_string_indentation("\n a\n b\nc") == 0
8888

8989
def count_both_tab_and_space_as_single_character():
90-
assert get_block_string_indentation(["", "\ta", " b"]) == 1
91-
assert get_block_string_indentation(["", "\t a", " b"]) == 2
92-
assert get_block_string_indentation(["", " \t a", " b"]) == 3
90+
assert get_block_string_indentation("\n\ta\n b") == 1
91+
assert get_block_string_indentation("\n\t a\n b") == 2
92+
assert get_block_string_indentation("\n \t a\n b") == 3
9393

9494
def do_not_take_empty_lines_into_account():
95-
assert get_block_string_indentation((["a", "\t"])) == 0
96-
assert get_block_string_indentation((["a", " "])) == 0
97-
assert get_block_string_indentation((["a", " ", " b"])) == 2
98-
assert get_block_string_indentation((["a", " ", " b"])) == 2
99-
assert get_block_string_indentation((["a", "", " b"])) == 1
95+
assert get_block_string_indentation("a\n ") == 0
96+
assert get_block_string_indentation("a\n\t") == 0
97+
assert get_block_string_indentation("a\n\n b") == 1
98+
assert get_block_string_indentation("a\n \n b") == 2
99+
100+
def treat_carriage_returns_like_newlines():
101+
assert get_block_string_indentation(" a\r b") == 2
102+
assert get_block_string_indentation(" a\r\n b") == 2
103+
assert get_block_string_indentation("\r a\r b") == 1
104+
assert get_block_string_indentation("\r\n a\r\n b") == 1
105+
assert get_block_string_indentation("\r \t a\r b") == 3
106+
assert get_block_string_indentation("\r\n \t a\r\n b") == 3
107+
assert get_block_string_indentation("a\r \r b") == 2
108+
assert get_block_string_indentation("a\r\n \r\n b") == 2
100109

101110

102111
def describe_print_block_string():

0 commit comments

Comments
 (0)