Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
  • Loading branch information
itzzdev09 committed Sep 18, 2026
commit f7ddc1f69c8bff3a86b499e6fe82efc5db53b279
42 changes: 19 additions & 23 deletions src/validators/cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,36 @@
from .utils import validator


def _validate_cron_component(component: str, min_val: int, max_val: int):
if component == "*":
return True

if component.isdecimal():
return min_val <= int(component) <= max_val

if "/" in component:
parts = component.split("/")
if len(parts) != 2 or not parts[1].isdecimal() or int(parts[1]) < 1:
def _validate_cron_item(item: str, min_val: int, max_val: int):
# An item may carry a step, e.g. "*/5", "1-30/2" or "5/10".
if "/" in item:
base, _, step = item.partition("/")
if not step.isdecimal() or int(step) < 1:
return False
if parts[0] == "*":
return True
return parts[0].isdecimal() and min_val <= int(parts[0]) <= max_val
else:
base = item

if base == "*":
return True

if "-" in component:
parts = component.split("-")
if "-" in base:
parts = base.split("-")
if len(parts) != 2 or not parts[0].isdecimal() or not parts[1].isdecimal():
return False
start, end = int(parts[0]), int(parts[1])
return min_val <= start <= max_val and min_val <= end <= max_val and start <= end

if "," in component:
for item in component.split(","):
if not _validate_cron_component(item, min_val, max_val):
return False
return True
# return all(
# _validate_cron_component(item, min_val, max_val) for item in component.split(",")
# ) # throws type error. why?
if base.isdecimal():
return min_val <= int(base) <= max_val

return False


def _validate_cron_component(component: str, min_val: int, max_val: int):
# A field is a comma-separated list of items, each optionally stepped.
return all(_validate_cron_item(item, min_val, max_val) for item in component.split(","))


@validator
def cron(value: str, /):
"""Return whether or not given value is a valid cron string.
Expand Down
4 changes: 3 additions & 1 deletion tests/test_cron.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"*/15 0,6,12,18 * * *",
"0 12 * * 0",
"*/61 * * * *",
# "5-10/2 * * * *", # this is valid, but not supported yet
"5-10/2 * * * *",
"1-30/2 * * * *",
"15,45 6-18/3 * * *",
],
)
def test_returns_true_on_valid_cron(value: str):
Expand Down