Skip to content

Commit 7eb0416

Browse files
committed
Add step to zen command slicing
1 parent 46cbc19 commit 7eb0416

File tree

2 files changed

+50
-27
lines changed

2 files changed

+50
-27
lines changed

bot/exts/utils/utils.py

+40-21
Original file line numberDiff line numberDiff line change
@@ -111,31 +111,50 @@ 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(r"(?P<index>-?\d++(?!:))|(?P<start>(?:-\d+)|\d*):(?:(?P<end>(?:-\d+)|\d*)(?::(?P<step>(?:-\d+)|\d*))?)?", search_value.split(" ")[0])
115115
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]
116+
if match.group("index"):
117+
index = int(match.group("index"))
118+
if not (-19 <= index <= 18):
119+
raise BadArgument(f"Please provide an index between {-19} and {18}.")
120+
embed.title += f" (line {index % 19}):"
121+
embed.description = zen_lines[index]
126122
await ctx.send(embed=embed)
127123
return
128124

129-
end_index= int(match.group(3)) if match.group(3) else len(zen_lines)
130-
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.")
135-
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)
125+
start_index = int(match.group("start")) if match.group("start") else None
126+
end_index = int(match.group("end")) if match.group("end") else None
127+
step_size = int(match.group("step")) if match.group("step") else 1
128+
129+
if step_size == 0:
130+
raise BadArgument(f"Step size must not be 0.")
131+
132+
lines = zen_lines[start_index:end_index:step_size]
133+
if not lines:
134+
raise BadArgument(f"Slice returned 0 lines.")
135+
elif len(lines) == 1:
136+
embed.title += f" (line {zen_lines.index(lines[0])}):"
137+
embed.description = lines[0]
138+
await ctx.send(embed=embed)
139+
elif lines == zen_lines:
140+
embed.title += ", by Tim Peters"
141+
await ctx.send(embed=embed)
142+
elif len(lines) == 19:
143+
embed.title += f" (step size {step_size}):"
144+
embed.description = "\n".join(lines)
145+
await ctx.send(embed=embed)
146+
else:
147+
if step_size != 1:
148+
step_message = f", step size {step_size}"
149+
else:
150+
step_message = ""
151+
first_position = zen_lines.index(lines[0])
152+
second_position = zen_lines.index(lines[-1])
153+
if first_position > second_position:
154+
(first_position, second_position) = (second_position, first_position)
155+
embed.title += f" (lines {first_position}-{second_position}{step_message}):"
156+
embed.description = "\n".join(lines)
157+
await ctx.send(embed=embed)
139158
return
140159

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

tests/bot/exts/utils/test_utils.py

+10-6
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,8 +87,8 @@ 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):
90-
await self.cog.zen.callback(self.cog, self.ctx, search_value=input_slice)
94+
await self.cog.zen.callback(self.cog, self.ctx, search_value=input_slice)

0 commit comments

Comments
 (0)