dargslan-cron-parser 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: dargslan-cron-parser
3
+ Version: 1.0.0
4
+ Summary: Crontab expression parser — next run calculation, natural language explanation, and schedule validation.
5
+ Author-email: Dargslan <info@dargslan.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://dargslan.com
8
+ Project-URL: Documentation, https://dargslan.com/blog
9
+ Project-URL: Repository, https://github.com/Dargslan
10
+ Project-URL: Free Cheat Sheets, https://dargslan.com/cheat-sheets
11
+ Project-URL: Linux & DevOps Books, https://dargslan.com/books
12
+ Keywords: linux,cron,crontab,scheduler,parser,sysadmin,devops
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: System :: Systems Administration
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+
22
+ # dargslan-cron-parser
23
+
24
+ Crontab expression parser — next run calculation, natural language explanation, and schedule validation.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install dargslan-cron-parser
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ dargslan-cron explain "*/5 * * * *" # Natural language
36
+ dargslan-cron next "0 2 * * *" # Next 5 runs
37
+ dargslan-cron validate "0 25 * * *" # Validate
38
+ dargslan-cron parse "0 */6 * * 1-5" # Parse fields
39
+ dargslan-cron json "0 0 1 * *" # JSON output
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - Natural language explanation of cron expressions
45
+ - Next N run calculations
46
+ - Expression validation with error messages
47
+ - Support for @yearly, @monthly, @daily, etc.
48
+ - Field expansion and range support
49
+ - Zero dependencies — pure Python
50
+
51
+ ## Part of dargslan-toolkit
52
+
53
+ Install all 54 Linux sysadmin tools: `pip install dargslan-toolkit`
54
+
55
+ ## Links
56
+
57
+ - [Free Linux Cheat Sheets](https://dargslan.com/cheat-sheets)
58
+ - [Linux & DevOps Books](https://dargslan.com/books)
59
+
60
+ ## License
61
+
62
+ MIT
@@ -0,0 +1,41 @@
1
+ # dargslan-cron-parser
2
+
3
+ Crontab expression parser — next run calculation, natural language explanation, and schedule validation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install dargslan-cron-parser
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ dargslan-cron explain "*/5 * * * *" # Natural language
15
+ dargslan-cron next "0 2 * * *" # Next 5 runs
16
+ dargslan-cron validate "0 25 * * *" # Validate
17
+ dargslan-cron parse "0 */6 * * 1-5" # Parse fields
18
+ dargslan-cron json "0 0 1 * *" # JSON output
19
+ ```
20
+
21
+ ## Features
22
+
23
+ - Natural language explanation of cron expressions
24
+ - Next N run calculations
25
+ - Expression validation with error messages
26
+ - Support for @yearly, @monthly, @daily, etc.
27
+ - Field expansion and range support
28
+ - Zero dependencies — pure Python
29
+
30
+ ## Part of dargslan-toolkit
31
+
32
+ Install all 54 Linux sysadmin tools: `pip install dargslan-toolkit`
33
+
34
+ ## Links
35
+
36
+ - [Free Linux Cheat Sheets](https://dargslan.com/cheat-sheets)
37
+ - [Linux & DevOps Books](https://dargslan.com/books)
38
+
39
+ ## License
40
+
41
+ MIT
@@ -0,0 +1,162 @@
1
+ """dargslan-cron-parser — Crontab expression parser and scheduler."""
2
+
3
+ __version__ = "1.0.0"
4
+
5
+ import re
6
+ import json
7
+ from datetime import datetime, timedelta
8
+ from calendar import monthrange
9
+
10
+ FIELD_NAMES = ["minute", "hour", "day_of_month", "month", "day_of_week"]
11
+ FIELD_RANGES = [(0, 59), (0, 23), (1, 31), (1, 12), (0, 7)]
12
+ MONTH_NAMES = {
13
+ "jan": 1, "feb": 2, "mar": 3, "apr": 4, "may": 5, "jun": 6,
14
+ "jul": 7, "aug": 8, "sep": 9, "oct": 10, "nov": 11, "dec": 12
15
+ }
16
+ DOW_NAMES = {
17
+ "sun": 0, "mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6
18
+ }
19
+ SPECIAL_EXPRESSIONS = {
20
+ "@yearly": "0 0 1 1 *", "@annually": "0 0 1 1 *",
21
+ "@monthly": "0 0 1 * *", "@weekly": "0 0 * * 0",
22
+ "@daily": "0 0 * * *", "@midnight": "0 0 * * *",
23
+ "@hourly": "0 * * * *",
24
+ }
25
+
26
+
27
+ def expand_field(field, min_val, max_val):
28
+ if max_val == 7 and field == "7":
29
+ field = "0"
30
+ values = set()
31
+ for part in field.split(","):
32
+ step = 1
33
+ if "/" in part:
34
+ part, step_str = part.split("/", 1)
35
+ step = int(step_str)
36
+ if part == "*":
37
+ values.update(range(min_val, max_val + 1, step))
38
+ elif "-" in part:
39
+ start, end = part.split("-", 1)
40
+ start, end = int(start), int(end)
41
+ values.update(range(start, end + 1, step))
42
+ else:
43
+ part_lower = part.lower()
44
+ if part_lower in MONTH_NAMES:
45
+ values.add(MONTH_NAMES[part_lower])
46
+ elif part_lower in DOW_NAMES:
47
+ values.add(DOW_NAMES[part_lower])
48
+ else:
49
+ values.add(int(part))
50
+ return sorted(v for v in values if min_val <= v <= max_val)
51
+
52
+
53
+ def parse_expression(expr):
54
+ expr = expr.strip()
55
+ if expr.startswith("@"):
56
+ expr = SPECIAL_EXPRESSIONS.get(expr.lower(), expr)
57
+ parts = expr.split()
58
+ if len(parts) != 5:
59
+ return None
60
+ fields = {}
61
+ for i, (part, name) in enumerate(zip(parts, FIELD_NAMES)):
62
+ fields[name] = expand_field(part, FIELD_RANGES[i][0], FIELD_RANGES[i][1])
63
+ return fields
64
+
65
+
66
+ def explain(expr):
67
+ expr_orig = expr.strip()
68
+ if expr_orig.startswith("@"):
69
+ mapped = SPECIAL_EXPRESSIONS.get(expr_orig.lower())
70
+ if mapped:
71
+ labels = {
72
+ "@yearly": "Once a year at midnight on January 1st",
73
+ "@annually": "Once a year at midnight on January 1st",
74
+ "@monthly": "Once a month at midnight on the 1st",
75
+ "@weekly": "Once a week at midnight on Sunday",
76
+ "@daily": "Once a day at midnight",
77
+ "@midnight": "Once a day at midnight",
78
+ "@hourly": "Once an hour at the beginning of the hour",
79
+ }
80
+ return labels.get(expr_orig.lower(), f"Equivalent to: {mapped}")
81
+ fields = parse_expression(expr)
82
+ if not fields:
83
+ return "Invalid cron expression"
84
+ parts = []
85
+ mins = fields["minute"]
86
+ hrs = fields["hour"]
87
+ doms = fields["day_of_month"]
88
+ mons = fields["month"]
89
+ dows = fields["day_of_week"]
90
+ dow_names_rev = {0: "Sunday", 1: "Monday", 2: "Tuesday", 3: "Wednesday", 4: "Thursday", 5: "Friday", 6: "Saturday"}
91
+ month_names_rev = {1: "January", 2: "February", 3: "March", 4: "April", 5: "May", 6: "June", 7: "July", 8: "August", 9: "September", 10: "October", 11: "November", 12: "December"}
92
+ if len(mins) == 1:
93
+ parts.append(f"At minute {mins[0]}")
94
+ elif len(mins) == 60:
95
+ parts.append("Every minute")
96
+ else:
97
+ parts.append(f"At minutes {', '.join(str(m) for m in mins)}")
98
+ if len(hrs) == 1:
99
+ parts.append(f"past hour {hrs[0]}")
100
+ elif len(hrs) < 24:
101
+ parts.append(f"past hours {', '.join(str(h) for h in hrs)}")
102
+ if len(doms) < 31:
103
+ parts.append(f"on day(s) {', '.join(str(d) for d in doms)}")
104
+ if len(mons) < 12:
105
+ parts.append(f"in {', '.join(month_names_rev.get(m, str(m)) for m in mons)}")
106
+ if len(dows) < 7:
107
+ parts.append(f"on {', '.join(dow_names_rev.get(d, str(d)) for d in dows)}")
108
+ return " ".join(parts)
109
+
110
+
111
+ def next_run(expr, after=None, count=5):
112
+ fields = parse_expression(expr)
113
+ if not fields:
114
+ return []
115
+ if after is None:
116
+ after = datetime.now()
117
+ current = after.replace(second=0, microsecond=0) + timedelta(minutes=1)
118
+ results = []
119
+ max_iter = 525600
120
+ for _ in range(max_iter):
121
+ if (current.minute in fields["minute"] and
122
+ current.hour in fields["hour"] and
123
+ current.day in fields["day_of_month"] and
124
+ current.month in fields["month"] and
125
+ (current.weekday() + 1) % 7 in fields["day_of_week"]):
126
+ results.append(current.isoformat())
127
+ if len(results) >= count:
128
+ break
129
+ current += timedelta(minutes=1)
130
+ return results
131
+
132
+
133
+ def validate(expr):
134
+ issues = []
135
+ expr = expr.strip()
136
+ if expr.startswith("@"):
137
+ if expr.lower() not in SPECIAL_EXPRESSIONS:
138
+ issues.append(f"Unknown special expression: {expr}")
139
+ return issues
140
+ parts = expr.split()
141
+ if len(parts) != 5:
142
+ issues.append(f"Expected 5 fields, got {len(parts)}")
143
+ return issues
144
+ for i, (part, name) in enumerate(zip(parts, FIELD_NAMES)):
145
+ try:
146
+ vals = expand_field(part, FIELD_RANGES[i][0], FIELD_RANGES[i][1])
147
+ if not vals:
148
+ issues.append(f"Field '{name}' ({part}) expands to empty set")
149
+ except (ValueError, IndexError):
150
+ issues.append(f"Invalid field '{name}': {part}")
151
+ return issues
152
+
153
+
154
+ def generate_report(expr):
155
+ return {
156
+ "expression": expr,
157
+ "explanation": explain(expr),
158
+ "validation": validate(expr),
159
+ "is_valid": len(validate(expr)) == 0,
160
+ "next_runs": next_run(expr),
161
+ "parsed_fields": parse_expression(expr),
162
+ }
@@ -0,0 +1,86 @@
1
+ """CLI for dargslan-cron-parser."""
2
+
3
+ import sys
4
+ import json
5
+ from . import explain, next_run, validate, parse_expression, generate_report, __version__
6
+
7
+
8
+ def main():
9
+ args = sys.argv[1:]
10
+ if not args or args[0] in ("-h", "--help"):
11
+ print(f"dargslan-cron-parser v{__version__}")
12
+ print(f"Crontab expression parser and scheduler")
13
+ print(f"\nUsage: dargslan-cron <command> <expression>")
14
+ print(f"\nCommands:")
15
+ print(f" explain \"*/5 * * * *\" Natural language explanation")
16
+ print(f" next \"0 2 * * *\" Next 5 scheduled runs")
17
+ print(f" validate \"0 25 * * *\" Validate expression")
18
+ print(f" parse \"0 */6 * * 1-5\" Parse into field values")
19
+ print(f" report \"0 0 1 * *\" Full analysis report")
20
+ print(f" json \"* * * * *\" Full report as JSON")
21
+ print(f" version Show version")
22
+ print(f"\nhttps://dargslan.com — Linux & DevOps Books")
23
+ return
24
+
25
+ cmd = args[0]
26
+ if cmd == "version":
27
+ print(f"dargslan-cron-parser v{__version__}")
28
+ return
29
+
30
+ if len(args) < 2:
31
+ print("Error: Please provide a cron expression.")
32
+ print("Example: dargslan-cron explain \"*/5 * * * *\"")
33
+ sys.exit(1)
34
+
35
+ expr = args[1]
36
+ if cmd == "explain":
37
+ print(explain(expr))
38
+ elif cmd == "next":
39
+ count = 5
40
+ if "-n" in args:
41
+ idx = args.index("-n")
42
+ if idx + 1 < len(args):
43
+ count = int(args[idx + 1])
44
+ runs = next_run(expr, count=count)
45
+ print(f"Next {len(runs)} runs for: {expr}")
46
+ print(f" {explain(expr)}")
47
+ for r in runs:
48
+ print(f" {r}")
49
+ elif cmd == "validate":
50
+ issues = validate(expr)
51
+ if not issues:
52
+ print(f"Valid: {expr}")
53
+ print(f" {explain(expr)}")
54
+ else:
55
+ print(f"Invalid: {expr}")
56
+ for i in issues:
57
+ print(f" [ERROR] {i}")
58
+ elif cmd == "parse":
59
+ fields = parse_expression(expr)
60
+ if fields:
61
+ for name, vals in fields.items():
62
+ print(f" {name}: {vals}")
63
+ else:
64
+ print("Invalid expression")
65
+ elif cmd == "report":
66
+ r = generate_report(expr)
67
+ print(f"Cron Expression: {r['expression']}")
68
+ print(f"Explanation: {r['explanation']}")
69
+ print(f"Valid: {r['is_valid']}")
70
+ if r['validation']:
71
+ print(f"Issues:")
72
+ for i in r['validation']:
73
+ print(f" {i}")
74
+ print(f"\nNext runs:")
75
+ for run in r['next_runs']:
76
+ print(f" {run}")
77
+ print(f"\nMore Linux tools: https://dargslan.com/cheat-sheets")
78
+ elif cmd == "json":
79
+ print(json.dumps(generate_report(expr), indent=2))
80
+ else:
81
+ print(f"Unknown command: {cmd}. Use --help for usage.")
82
+ sys.exit(1)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ main()
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: dargslan-cron-parser
3
+ Version: 1.0.0
4
+ Summary: Crontab expression parser — next run calculation, natural language explanation, and schedule validation.
5
+ Author-email: Dargslan <info@dargslan.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://dargslan.com
8
+ Project-URL: Documentation, https://dargslan.com/blog
9
+ Project-URL: Repository, https://github.com/Dargslan
10
+ Project-URL: Free Cheat Sheets, https://dargslan.com/cheat-sheets
11
+ Project-URL: Linux & DevOps Books, https://dargslan.com/books
12
+ Keywords: linux,cron,crontab,scheduler,parser,sysadmin,devops
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Topic :: System :: Systems Administration
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+
22
+ # dargslan-cron-parser
23
+
24
+ Crontab expression parser — next run calculation, natural language explanation, and schedule validation.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install dargslan-cron-parser
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ dargslan-cron explain "*/5 * * * *" # Natural language
36
+ dargslan-cron next "0 2 * * *" # Next 5 runs
37
+ dargslan-cron validate "0 25 * * *" # Validate
38
+ dargslan-cron parse "0 */6 * * 1-5" # Parse fields
39
+ dargslan-cron json "0 0 1 * *" # JSON output
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - Natural language explanation of cron expressions
45
+ - Next N run calculations
46
+ - Expression validation with error messages
47
+ - Support for @yearly, @monthly, @daily, etc.
48
+ - Field expansion and range support
49
+ - Zero dependencies — pure Python
50
+
51
+ ## Part of dargslan-toolkit
52
+
53
+ Install all 54 Linux sysadmin tools: `pip install dargslan-toolkit`
54
+
55
+ ## Links
56
+
57
+ - [Free Linux Cheat Sheets](https://dargslan.com/cheat-sheets)
58
+ - [Linux & DevOps Books](https://dargslan.com/books)
59
+
60
+ ## License
61
+
62
+ MIT
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ dargslan_cron_parser/__init__.py
4
+ dargslan_cron_parser/cli.py
5
+ dargslan_cron_parser.egg-info/PKG-INFO
6
+ dargslan_cron_parser.egg-info/SOURCES.txt
7
+ dargslan_cron_parser.egg-info/dependency_links.txt
8
+ dargslan_cron_parser.egg-info/entry_points.txt
9
+ dargslan_cron_parser.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ dargslan-cron = dargslan_cron_parser.cli:main
@@ -0,0 +1 @@
1
+ dargslan_cron_parser
@@ -0,0 +1,31 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dargslan-cron-parser"
7
+ version = "1.0.0"
8
+ description = "Crontab expression parser — next run calculation, natural language explanation, and schedule validation."
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.7"
12
+ authors = [{name = "Dargslan", email = "info@dargslan.com"}]
13
+ keywords = ["linux", "cron", "crontab", "scheduler", "parser", "sysadmin", "devops"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Intended Audience :: System Administrators",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: POSIX :: Linux",
19
+ "Programming Language :: Python :: 3",
20
+ "Topic :: System :: Systems Administration",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://dargslan.com"
25
+ Documentation = "https://dargslan.com/blog"
26
+ Repository = "https://github.com/Dargslan"
27
+ "Free Cheat Sheets" = "https://dargslan.com/cheat-sheets"
28
+ "Linux & DevOps Books" = "https://dargslan.com/books"
29
+
30
+ [project.scripts]
31
+ dargslan-cron = "dargslan_cron_parser.cli:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+