Skip to content

Commit f7ddc1f

Browse files
committed
cron: accept a step over a range (e.g. 1-5/2) and in list items
_validate_cron_component checked for /, - and , in a fixed order, so a stepped range like "1-5/2" (valid cron) was rejected, as was any comma-list whose items used ranges or steps. Split each field on "," first, then parse each item as an optional base ("*", a number or a range) followed by an optional step.
1 parent 70de324 commit f7ddc1f

2 files changed

Lines changed: 22 additions & 24 deletions

File tree

‎src/validators/cron.py‎

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,36 @@
44
from .utils import validator
55

66

7-
def _validate_cron_component(component: str, min_val: int, max_val: int):
8-
if component == "*":
9-
return True
10-
11-
if component.isdecimal():
12-
return min_val <= int(component) <= max_val
13-
14-
if "/" in component:
15-
parts = component.split("/")
16-
if len(parts) != 2 or not parts[1].isdecimal() or int(parts[1]) < 1:
7+
def _validate_cron_item(item: str, min_val: int, max_val: int):
8+
# An item may carry a step, e.g. "*/5", "1-30/2" or "5/10".
9+
if "/" in item:
10+
base, _, step = item.partition("/")
11+
if not step.isdecimal() or int(step) < 1:
1712
return False
18-
if parts[0] == "*":
19-
return True
20-
return parts[0].isdecimal() and min_val <= int(parts[0]) <= max_val
13+
else:
14+
base = item
15+
16+
if base == "*":
17+
return True
2118

22-
if "-" in component:
23-
parts = component.split("-")
19+
if "-" in base:
20+
parts = base.split("-")
2421
if len(parts) != 2 or not parts[0].isdecimal() or not parts[1].isdecimal():
2522
return False
2623
start, end = int(parts[0]), int(parts[1])
2724
return min_val <= start <= max_val and min_val <= end <= max_val and start <= end
2825

29-
if "," in component:
30-
for item in component.split(","):
31-
if not _validate_cron_component(item, min_val, max_val):
32-
return False
33-
return True
34-
# return all(
35-
# _validate_cron_component(item, min_val, max_val) for item in component.split(",")
36-
# ) # throws type error. why?
26+
if base.isdecimal():
27+
return min_val <= int(base) <= max_val
3728

3829
return False
3930

4031

32+
def _validate_cron_component(component: str, min_val: int, max_val: int):
33+
# A field is a comma-separated list of items, each optionally stepped.
34+
return all(_validate_cron_item(item, min_val, max_val) for item in component.split(","))
35+
36+
4137
@validator
4238
def cron(value: str, /):
4339
"""Return whether or not given value is a valid cron string.

‎tests/test_cron.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
"*/15 0,6,12,18 * * *",
2424
"0 12 * * 0",
2525
"*/61 * * * *",
26-
# "5-10/2 * * * *", # this is valid, but not supported yet
26+
"5-10/2 * * * *",
27+
"1-30/2 * * * *",
28+
"15,45 6-18/3 * * *",
2729
],
2830
)
2931
def test_returns_true_on_valid_cron(value: str):

0 commit comments

Comments
 (0)