Skip to content

Commit 2d4f688

Browse files
authored
Merge pull request #3311 from MeGaGiGaGon/main
Add step to zen command slicing
2 parents 46cbc19 + 4c169a5 commit 2d4f688

File tree

2 files changed

+53
-26
lines changed

2 files changed

+53
-26
lines changed

bot/exts/utils/utils.py

+44-21
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
log = get_logger(__name__)
1818

19-
ZEN_OF_PYTHON = """\
19+
ZEN_OF_PYTHON = """
2020
Beautiful is better than ugly.
2121
Explicit is better than implicit.
2222
Simple is better than complex.
@@ -36,7 +36,7 @@
3636
If the implementation is hard to explain, it's a bad idea.
3737
If the implementation is easy to explain, it may be a good idea.
3838
Namespaces are one honking great idea -- let's do more of those!
39-
"""
39+
""".strip()
4040
LEADS_AND_COMMUNITY = (Roles.project_leads, Roles.domain_leads, Roles.partners, Roles.python_community)
4141

4242

@@ -111,31 +111,54 @@ async def zen(
111111
zen_lines = ZEN_OF_PYTHON.splitlines()
112112

113113
# Prioritize checking for an index or slice
114-
match = re.match(r"(-?\d+)(:(-?\d+)?)?", search_value.split(" ")[0])
114+
match = re.match(
115+
r"(?P<index>-?\d++(?!:))|(?P<start>(?:-\d+)|\d*):(?:(?P<end>(?:-\d+)|\d*)(?::(?P<step>(?:-\d+)|\d*))?)?",
116+
search_value.split(" ")[0],
117+
)
115118
if match:
116-
upper_bound = len(zen_lines) - 1
117-
lower_bound = -1 * len(zen_lines)
118-
119-
start_index = int(match.group(1))
120-
121-
if not match.group(2):
122-
if not (lower_bound <= start_index <= upper_bound):
123-
raise BadArgument(f"Please provide an index between {lower_bound} and {upper_bound}.")
124-
embed.title += f" (line {start_index % len(zen_lines)}):"
125-
embed.description = zen_lines[start_index]
119+
if match.group("index"):
120+
index = int(match.group("index"))
121+
if not (-19 <= index <= 18):
122+
raise BadArgument("Please provide an index between -19 and 18.")
123+
embed.title += f" (line {index % 19}):"
124+
embed.description = zen_lines[index]
126125
await ctx.send(embed=embed)
127126
return
128127

129-
end_index= int(match.group(3)) if match.group(3) else len(zen_lines)
128+
start_index = int(match.group("start")) if match.group("start") else None
129+
end_index = int(match.group("end")) if match.group("end") else None
130+
step_size = int(match.group("step")) if match.group("step") else 1
130131

131-
if not ((lower_bound <= start_index <= upper_bound) and (lower_bound <= end_index <= len(zen_lines))):
132-
raise BadArgument(f"Please provide valid indices between {lower_bound} and {upper_bound}.")
133-
if not (start_index % len(zen_lines) < end_index % (len(zen_lines) + 1)):
134-
raise BadArgument("The start index for the slice must be smaller than the end index.")
132+
if step_size == 0:
133+
raise BadArgument("Step size must not be 0.")
135134

136-
embed.title += f" (lines {start_index%len(zen_lines)}-{(end_index-1)%len(zen_lines)}):"
137-
embed.description = "\n".join(zen_lines[start_index:end_index])
138-
await ctx.send(embed=embed)
135+
lines = zen_lines[start_index:end_index:step_size]
136+
if not lines:
137+
raise BadArgument("Slice returned 0 lines.")
138+
139+
if len(lines) == 1:
140+
embed.title += f" (line {zen_lines.index(lines[0])}):"
141+
embed.description = lines[0]
142+
await ctx.send(embed=embed)
143+
elif lines == zen_lines:
144+
embed.title += ", by Tim Peters"
145+
await ctx.send(embed=embed)
146+
elif len(lines) == 19:
147+
embed.title += f" (step size {step_size}):"
148+
embed.description = "\n".join(lines)
149+
await ctx.send(embed=embed)
150+
else:
151+
if step_size != 1:
152+
step_message = f", step size {step_size}"
153+
else:
154+
step_message = ""
155+
first_position = zen_lines.index(lines[0])
156+
second_position = zen_lines.index(lines[-1])
157+
if first_position > second_position:
158+
(first_position, second_position) = (second_position, first_position)
159+
embed.title += f" (lines {first_position}-{second_position}{step_message}):"
160+
embed.description = "\n".join(lines)
161+
await ctx.send(embed=embed)
139162
return
140163

141164
# Try to handle first exact word due difflib.SequenceMatched may use some other similar word instead

tests/bot/exts/utils/test_utils.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,15 @@ async def test_zen_with_valid_slices(self):
6565
""" Tests if the `!zen` command reacts properly to valid slices for indexing as an argument. """
6666

6767
expected_results = {
68-
"0:19": ("The Zen of Python (lines 0-18):", "\n".join(self.zen_list[0:19])),
69-
"0:": ("The Zen of Python (lines 0-18):", "\n".join(self.zen_list[0:])),
70-
"-2:-1": ("The Zen of Python (lines 17-17):", self.zen_list[17]),
68+
"0:19": ("The Zen of Python, by Tim Peters", "\n".join(self.zen_list)),
69+
":": ("The Zen of Python, by Tim Peters", "\n".join(self.zen_list)),
70+
"::": ("The Zen of Python, by Tim Peters", "\n".join(self.zen_list)),
71+
"1:": ("The Zen of Python (lines 1-18):", "\n".join(self.zen_list[1:])),
72+
"-2:-1": ("The Zen of Python (line 17):", self.zen_list[17]),
7173
"0:-1": ("The Zen of Python (lines 0-17):", "\n".join(self.zen_list[0:-1])),
72-
"10:13": ("The Zen of Python (lines 10-12):", "\n".join(self.zen_list[10:13]))
74+
"10:13": ("The Zen of Python (lines 10-12):", "\n".join(self.zen_list[10:13])),
75+
"::-1": ("The Zen of Python (step size -1):", "\n".join(self.zen_list[::-1])),
76+
"10:5:-1": ("The Zen of Python (lines 6-10, step size -1):", "\n".join(self.zen_list[10:5:-1])),
7377
}
7478

7579
for input_slice, (title, description) in expected_results.items():
@@ -83,7 +87,7 @@ async def test_zen_with_valid_slices(self):
8387

8488
async def test_zen_with_invalid_slices(self):
8589
""" Tests if the `!zen` command reacts properly to invalid slices for indexing as an argument. """
86-
slices= ["19:", "10:9", "-1:-2", "0:20", "-100:", "0:-100"]
90+
slices= ["19:18", "10:9", "-1:-2", "0:-100", "::0", "1:2:-1", "-5:-4:-1"]
8791

8892
for input_slice in slices:
8993
with self.subTest(input_slice = input_slice), self.assertRaises(BadArgument):

0 commit comments

Comments
 (0)