taskcheck 1.0.0__tar.gz → 1.0.0.post2__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.
- {taskcheck-1.0.0/taskcheck.egg-info → taskcheck-1.0.0.post2}/PKG-INFO +33 -24
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/README.md +32 -23
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/pyproject.toml +1 -1
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/__main__.py +13 -14
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/parallel.py +23 -21
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2/taskcheck.egg-info}/PKG-INFO +33 -24
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_main.py +22 -3
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_parallel.py +22 -8
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/LICENSE +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/setup.cfg +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/common.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/ical.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/install.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/report.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/SOURCES.txt +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/dependency_links.txt +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/entry_points.txt +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/requires.txt +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/top_level.txt +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_common.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_ical.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_install.py +0 -0
- {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_report.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskcheck
|
|
3
|
-
Version: 1.0.0
|
|
3
|
+
Version: 1.0.0.post2
|
|
4
4
|
Summary: Automatic scheduler for taskwarrior
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -10,24 +10,25 @@ Requires-Dist: random-unicode-emoji>=2.8
|
|
|
10
10
|
Requires-Dist: requests>=2.32.3
|
|
11
11
|
Requires-Dist: rich>=13.9.4
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
<div align="center">
|
|
14
|
+
|
|
14
15
|
```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
88 88, ,88 aa ]8I 88`"Yba, Y8a. .a8P 88 88 "8b, ,aa "8a, ,aa 88`"Yba,
|
|
23
|
-
88 `"8bbdP"Y8 `"YbbdP"' 88 `Y8a `"Y8888Y"' 88 88 `"Ybbd8"' `"Ybbd8"' 88 `Y8a
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
######## ### ###### ## ## ###### ## ## ######## ###### ## ##
|
|
17
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
18
|
+
## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
19
|
+
## ## ## ###### ##### ## ######### ###### ## #####
|
|
20
|
+
## ######### ## ## ## ## ## ## ## ## ## ##
|
|
21
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
22
|
+
## ## ## ###### ## ## ###### ## ## ######## ###### ## ##
|
|
26
23
|
```
|
|
27
24
|
|
|
28
25
|
> _A non-AI automatic scheduler for taskwarrior (i.e. alternative to skedpal / timehero / flowsavvy / reclaim / trevor / motion)_
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
This is a taskwarrior extension that automatically schedules your tasks based on your working hours,
|
|
31
32
|
estimated time, and calendar events, finding an optimal time to work on each task and match all your
|
|
32
33
|
deadlines.
|
|
33
34
|
|
|
@@ -38,7 +39,7 @@ deadlines.
|
|
|
38
39
|
- [x] **Parallel scheduling algorithm for multiple tasks, considering urgency and dependencies**
|
|
39
40
|
- [x] Dry-run mode: preview scheduling without modifying your Taskwarrior database
|
|
40
41
|
- [x] Custom urgency weighting for scheduling (via CLI or config)
|
|
41
|
-
- [x] **Auto-fix scheduling to
|
|
42
|
+
- [x] **Auto-fix scheduling to match due dates**
|
|
42
43
|
- [x] Force update of iCal calendars, bypassing cache
|
|
43
44
|
- [x] Simple, customizable reports for planned and unplanned tasks
|
|
44
45
|
- [x] Emoji and attribute customization in reports
|
|
@@ -187,15 +188,23 @@ are scheduled before their due dates or the `weight_urgency` factor reaches 0.
|
|
|
187
188
|
## CLI Options
|
|
188
189
|
|
|
189
190
|
```
|
|
190
|
-
-v
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
191
|
+
usage: __main__.py [-h] [-v] [-i] [-r REPORT] [-s] [-f] [--taskrc TASKRC] [--urgency-weight URGENCY_WEIGHT] [--dry-run] [--no-auto-adjust-urgency]
|
|
192
|
+
|
|
193
|
+
options:
|
|
194
|
+
-h, --help show this help message and exit
|
|
195
|
+
-v, --verbose Increase output verbosity.
|
|
196
|
+
-i, --install Install the UDAs, required settings, and default config file.
|
|
197
|
+
-r REPORT, --report REPORT
|
|
198
|
+
Generate a report of the tasks based on the scheduling; can be any Taskwarrior datetime specification (e.g. today, tomorrow, eom, som, 1st, 2nd, etc.). It is considered as `by`, meaning that the report will be
|
|
199
|
+
generated for all the days until the specified date and including it.
|
|
200
|
+
-s, --schedule Perform the scheduling algorithm, giving a schedule and a scheduling UDA and alerting for not completable tasks
|
|
201
|
+
-f, --force-update Force update of all ical calendars by ignoring cache expiration
|
|
202
|
+
--taskrc TASKRC Set custom TASKRC directory for debugging purposes
|
|
203
|
+
--urgency-weight URGENCY_WEIGHT
|
|
204
|
+
Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 1.0, the whole Taskwarrior urgency is used for scheduling. When 0.0, the Taskwarrior urgency is reduced to only due urgency.
|
|
205
|
+
--dry-run Perform scheduling without modifying the Taskwarrior database, useful for testing
|
|
206
|
+
--no-auto-adjust-urgency
|
|
207
|
+
Disable automatic reduction of urgency weight … (default: enabled)
|
|
199
208
|
```
|
|
200
209
|
|
|
201
210
|
### Examples
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
2
3
|
```
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
88 88, ,88 aa ]8I 88`"Yba, Y8a. .a8P 88 88 "8b, ,aa "8a, ,aa 88`"Yba,
|
|
11
|
-
88 `"8bbdP"Y8 `"YbbdP"' 88 `Y8a `"Y8888Y"' 88 88 `"Ybbd8"' `"Ybbd8"' 88 `Y8a
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
######## ### ###### ## ## ###### ## ## ######## ###### ## ##
|
|
5
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
6
|
+
## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
7
|
+
## ## ## ###### ##### ## ######### ###### ## #####
|
|
8
|
+
## ######### ## ## ## ## ## ## ## ## ## ##
|
|
9
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
10
|
+
## ## ## ###### ## ## ###### ## ## ######## ###### ## ##
|
|
14
11
|
```
|
|
15
12
|
|
|
16
13
|
> _A non-AI automatic scheduler for taskwarrior (i.e. alternative to skedpal / timehero / flowsavvy / reclaim / trevor / motion)_
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
This is a taskwarrior extension that automatically schedules your tasks based on your working hours,
|
|
19
20
|
estimated time, and calendar events, finding an optimal time to work on each task and match all your
|
|
20
21
|
deadlines.
|
|
21
22
|
|
|
@@ -26,7 +27,7 @@ deadlines.
|
|
|
26
27
|
- [x] **Parallel scheduling algorithm for multiple tasks, considering urgency and dependencies**
|
|
27
28
|
- [x] Dry-run mode: preview scheduling without modifying your Taskwarrior database
|
|
28
29
|
- [x] Custom urgency weighting for scheduling (via CLI or config)
|
|
29
|
-
- [x] **Auto-fix scheduling to
|
|
30
|
+
- [x] **Auto-fix scheduling to match due dates**
|
|
30
31
|
- [x] Force update of iCal calendars, bypassing cache
|
|
31
32
|
- [x] Simple, customizable reports for planned and unplanned tasks
|
|
32
33
|
- [x] Emoji and attribute customization in reports
|
|
@@ -175,15 +176,23 @@ are scheduled before their due dates or the `weight_urgency` factor reaches 0.
|
|
|
175
176
|
## CLI Options
|
|
176
177
|
|
|
177
178
|
```
|
|
178
|
-
-v
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
179
|
+
usage: __main__.py [-h] [-v] [-i] [-r REPORT] [-s] [-f] [--taskrc TASKRC] [--urgency-weight URGENCY_WEIGHT] [--dry-run] [--no-auto-adjust-urgency]
|
|
180
|
+
|
|
181
|
+
options:
|
|
182
|
+
-h, --help show this help message and exit
|
|
183
|
+
-v, --verbose Increase output verbosity.
|
|
184
|
+
-i, --install Install the UDAs, required settings, and default config file.
|
|
185
|
+
-r REPORT, --report REPORT
|
|
186
|
+
Generate a report of the tasks based on the scheduling; can be any Taskwarrior datetime specification (e.g. today, tomorrow, eom, som, 1st, 2nd, etc.). It is considered as `by`, meaning that the report will be
|
|
187
|
+
generated for all the days until the specified date and including it.
|
|
188
|
+
-s, --schedule Perform the scheduling algorithm, giving a schedule and a scheduling UDA and alerting for not completable tasks
|
|
189
|
+
-f, --force-update Force update of all ical calendars by ignoring cache expiration
|
|
190
|
+
--taskrc TASKRC Set custom TASKRC directory for debugging purposes
|
|
191
|
+
--urgency-weight URGENCY_WEIGHT
|
|
192
|
+
Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 1.0, the whole Taskwarrior urgency is used for scheduling. When 0.0, the Taskwarrior urgency is reduced to only due urgency.
|
|
193
|
+
--dry-run Perform scheduling without modifying the Taskwarrior database, useful for testing
|
|
194
|
+
--no-auto-adjust-urgency
|
|
195
|
+
Disable automatic reduction of urgency weight … (default: enabled)
|
|
187
196
|
```
|
|
188
197
|
|
|
189
198
|
### Examples
|
|
@@ -6,51 +6,53 @@ from taskcheck.common import config_dir
|
|
|
6
6
|
|
|
7
7
|
arg_parser = argparse.ArgumentParser()
|
|
8
8
|
arg_parser.add_argument(
|
|
9
|
-
"-v", "--verbose", action="store_true", help="
|
|
9
|
+
"-v", "--verbose", action="store_true", help="Increase output verbosity."
|
|
10
10
|
)
|
|
11
11
|
arg_parser.add_argument(
|
|
12
12
|
"-i",
|
|
13
13
|
"--install",
|
|
14
14
|
action="store_true",
|
|
15
|
-
help="
|
|
15
|
+
help="Install the UDAs, required settings, and default config file.",
|
|
16
16
|
)
|
|
17
17
|
arg_parser.add_argument(
|
|
18
18
|
"-r",
|
|
19
19
|
"--report",
|
|
20
20
|
action="store",
|
|
21
|
-
help="
|
|
21
|
+
help="Generate a report of the tasks based on the scheduling; can be any Taskwarrior datetime specification (e.g. today, tomorrow, eom, som, 1st, 2nd, etc.). It is considered as `by`, meaning that the report will be generated for all the days until the specified date and including it.",
|
|
22
22
|
)
|
|
23
23
|
arg_parser.add_argument(
|
|
24
24
|
"-s",
|
|
25
25
|
"--schedule",
|
|
26
26
|
action="store_true",
|
|
27
|
-
help="
|
|
27
|
+
help="Perform the scheduling algorithm, giving a schedule and a scheduling UDA and alerting for not completable tasks",
|
|
28
28
|
)
|
|
29
29
|
arg_parser.add_argument(
|
|
30
30
|
"-f",
|
|
31
31
|
"--force-update",
|
|
32
32
|
action="store_true",
|
|
33
|
-
help="
|
|
33
|
+
help="Force update of all ical calendars by ignoring cache expiration",
|
|
34
34
|
)
|
|
35
35
|
arg_parser.add_argument(
|
|
36
36
|
"--taskrc",
|
|
37
37
|
action="store",
|
|
38
|
-
help="
|
|
38
|
+
help="Set custom TASKRC directory for debugging purposes",
|
|
39
39
|
)
|
|
40
40
|
arg_parser.add_argument(
|
|
41
41
|
"--urgency-weight",
|
|
42
42
|
type=float,
|
|
43
|
-
help="
|
|
43
|
+
help="Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 1.0, the whole Taskwarrior urgency is used for scheduling. When 0.0, the Taskwarrior urgency is reduced to only due urgency.",
|
|
44
44
|
)
|
|
45
45
|
arg_parser.add_argument(
|
|
46
46
|
"--dry-run",
|
|
47
47
|
action="store_true",
|
|
48
|
-
help="
|
|
48
|
+
help="Perform scheduling without modifying the Taskwarrior database, useful for testing",
|
|
49
49
|
)
|
|
50
50
|
arg_parser.add_argument(
|
|
51
51
|
"--no-auto-adjust-urgency",
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
dest="auto_adjust_urgency",
|
|
53
|
+
action="store_false",
|
|
54
|
+
default=True,
|
|
55
|
+
help="Disable automatic reduction of urgency weight … (default: enabled)",
|
|
54
56
|
)
|
|
55
57
|
|
|
56
58
|
|
|
@@ -106,12 +108,9 @@ def main():
|
|
|
106
108
|
taskrc=args.taskrc,
|
|
107
109
|
urgency_weight_override=args.urgency_weight,
|
|
108
110
|
dry_run=args.dry_run,
|
|
111
|
+
auto_adjust_urgency=args.auto_adjust_urgency,
|
|
109
112
|
)
|
|
110
113
|
# Only add auto_adjust_urgency if it is present and a real bool (not a mock)
|
|
111
|
-
if hasattr(args, "no_auto_adjust_urgency") and isinstance(
|
|
112
|
-
args.no_auto_adjust_urgency, bool
|
|
113
|
-
):
|
|
114
|
-
check_tasks_kwargs["auto_adjust_urgency"] = not args.auto_adjust_urgency
|
|
115
114
|
result = check_tasks_parallel(
|
|
116
115
|
config,
|
|
117
116
|
**check_tasks_kwargs,
|
|
@@ -138,20 +138,22 @@ def check_tasks_parallel(
|
|
|
138
138
|
tasks_overdue = []
|
|
139
139
|
for info in task_info.values():
|
|
140
140
|
task = info["task"]
|
|
141
|
-
if not info["scheduling"]:
|
|
142
|
-
continue
|
|
143
|
-
|
|
144
|
-
scheduled_dates = sorted(info["scheduling"].keys())
|
|
145
|
-
if not scheduled_dates:
|
|
146
|
-
continue
|
|
147
|
-
end_date = scheduled_dates[-1]
|
|
148
|
-
|
|
149
141
|
due = task.get("due")
|
|
142
|
+
|
|
150
143
|
if due is not None:
|
|
151
|
-
end_date_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
|
152
144
|
due_dt = datetime.strptime(due, "%Y%m%dT%H%M%SZ")
|
|
153
|
-
|
|
145
|
+
|
|
146
|
+
# Case 1: Task has no scheduling at all and has remaining hours
|
|
147
|
+
if not info["scheduling"] and info["remaining_hours"] > 0:
|
|
154
148
|
tasks_overdue.append(task)
|
|
149
|
+
# Case 2: Task is scheduled but completion date is after due date
|
|
150
|
+
elif info["scheduling"]:
|
|
151
|
+
scheduled_dates = sorted(info["scheduling"].keys())
|
|
152
|
+
if scheduled_dates:
|
|
153
|
+
end_date = scheduled_dates[-1]
|
|
154
|
+
end_date_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
|
155
|
+
if end_date_dt > due_dt:
|
|
156
|
+
tasks_overdue.append(task)
|
|
155
157
|
|
|
156
158
|
# If no tasks are overdue or auto-adjust is disabled, break the loop
|
|
157
159
|
if not tasks_overdue or not auto_adjust_urgency:
|
|
@@ -169,17 +171,17 @@ def check_tasks_parallel(
|
|
|
169
171
|
break
|
|
170
172
|
|
|
171
173
|
# After loop completes, check if we still have overdue tasks
|
|
172
|
-
if auto_adjust_urgency and
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
if auto_adjust_urgency and current_weight < initial_weight_urgency:
|
|
175
|
+
if tasks_overdue:
|
|
176
|
+
# We tried to adjust but still have overdue tasks
|
|
177
|
+
console.print(
|
|
178
|
+
"[red]Warning: cannot find a solution even with urgency weight 0.0[/red]"
|
|
179
|
+
)
|
|
180
|
+
else:
|
|
181
|
+
# We successfully resolved overdue tasks by adjusting weight
|
|
182
|
+
console.print(
|
|
183
|
+
f"[green]Final urgency weight: {max(current_weight, 0.0):.1f}[/green]"
|
|
184
|
+
)
|
|
183
185
|
|
|
184
186
|
if dry_run:
|
|
185
187
|
# Generate JSON output instead of updating tasks
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskcheck
|
|
3
|
-
Version: 1.0.0
|
|
3
|
+
Version: 1.0.0.post2
|
|
4
4
|
Summary: Automatic scheduler for taskwarrior
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -10,24 +10,25 @@ Requires-Dist: random-unicode-emoji>=2.8
|
|
|
10
10
|
Requires-Dist: requests>=2.32.3
|
|
11
11
|
Requires-Dist: rich>=13.9.4
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
<div align="center">
|
|
14
|
+
|
|
14
15
|
```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
88 88, ,88 aa ]8I 88`"Yba, Y8a. .a8P 88 88 "8b, ,aa "8a, ,aa 88`"Yba,
|
|
23
|
-
88 `"8bbdP"Y8 `"YbbdP"' 88 `Y8a `"Y8888Y"' 88 88 `"Ybbd8"' `"Ybbd8"' 88 `Y8a
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
######## ### ###### ## ## ###### ## ## ######## ###### ## ##
|
|
17
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
18
|
+
## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
19
|
+
## ## ## ###### ##### ## ######### ###### ## #####
|
|
20
|
+
## ######### ## ## ## ## ## ## ## ## ## ##
|
|
21
|
+
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
|
|
22
|
+
## ## ## ###### ## ## ###### ## ## ######## ###### ## ##
|
|
26
23
|
```
|
|
27
24
|
|
|
28
25
|
> _A non-AI automatic scheduler for taskwarrior (i.e. alternative to skedpal / timehero / flowsavvy / reclaim / trevor / motion)_
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
This is a taskwarrior extension that automatically schedules your tasks based on your working hours,
|
|
31
32
|
estimated time, and calendar events, finding an optimal time to work on each task and match all your
|
|
32
33
|
deadlines.
|
|
33
34
|
|
|
@@ -38,7 +39,7 @@ deadlines.
|
|
|
38
39
|
- [x] **Parallel scheduling algorithm for multiple tasks, considering urgency and dependencies**
|
|
39
40
|
- [x] Dry-run mode: preview scheduling without modifying your Taskwarrior database
|
|
40
41
|
- [x] Custom urgency weighting for scheduling (via CLI or config)
|
|
41
|
-
- [x] **Auto-fix scheduling to
|
|
42
|
+
- [x] **Auto-fix scheduling to match due dates**
|
|
42
43
|
- [x] Force update of iCal calendars, bypassing cache
|
|
43
44
|
- [x] Simple, customizable reports for planned and unplanned tasks
|
|
44
45
|
- [x] Emoji and attribute customization in reports
|
|
@@ -187,15 +188,23 @@ are scheduled before their due dates or the `weight_urgency` factor reaches 0.
|
|
|
187
188
|
## CLI Options
|
|
188
189
|
|
|
189
190
|
```
|
|
190
|
-
-v
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
191
|
+
usage: __main__.py [-h] [-v] [-i] [-r REPORT] [-s] [-f] [--taskrc TASKRC] [--urgency-weight URGENCY_WEIGHT] [--dry-run] [--no-auto-adjust-urgency]
|
|
192
|
+
|
|
193
|
+
options:
|
|
194
|
+
-h, --help show this help message and exit
|
|
195
|
+
-v, --verbose Increase output verbosity.
|
|
196
|
+
-i, --install Install the UDAs, required settings, and default config file.
|
|
197
|
+
-r REPORT, --report REPORT
|
|
198
|
+
Generate a report of the tasks based on the scheduling; can be any Taskwarrior datetime specification (e.g. today, tomorrow, eom, som, 1st, 2nd, etc.). It is considered as `by`, meaning that the report will be
|
|
199
|
+
generated for all the days until the specified date and including it.
|
|
200
|
+
-s, --schedule Perform the scheduling algorithm, giving a schedule and a scheduling UDA and alerting for not completable tasks
|
|
201
|
+
-f, --force-update Force update of all ical calendars by ignoring cache expiration
|
|
202
|
+
--taskrc TASKRC Set custom TASKRC directory for debugging purposes
|
|
203
|
+
--urgency-weight URGENCY_WEIGHT
|
|
204
|
+
Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 1.0, the whole Taskwarrior urgency is used for scheduling. When 0.0, the Taskwarrior urgency is reduced to only due urgency.
|
|
205
|
+
--dry-run Perform scheduling without modifying the Taskwarrior database, useful for testing
|
|
206
|
+
--no-auto-adjust-urgency
|
|
207
|
+
Disable automatic reduction of urgency weight … (default: enabled)
|
|
199
208
|
```
|
|
200
209
|
|
|
201
210
|
### Examples
|
|
@@ -17,7 +17,7 @@ class TestArgumentParsing:
|
|
|
17
17
|
assert args.taskrc is None
|
|
18
18
|
assert args.urgency_weight is None
|
|
19
19
|
assert args.dry_run is False
|
|
20
|
-
assert args.auto_adjust_urgency is
|
|
20
|
+
assert args.auto_adjust_urgency is True
|
|
21
21
|
|
|
22
22
|
def test_arg_parser_all_flags(self):
|
|
23
23
|
"""Test all command line flags."""
|
|
@@ -93,10 +93,10 @@ class TestArgumentParsing:
|
|
|
93
93
|
|
|
94
94
|
def test_auto_adjust_urgency_argument(self):
|
|
95
95
|
"""Test auto-adjust-urgency argument parsing."""
|
|
96
|
-
args = arg_parser.parse_args([
|
|
96
|
+
args = arg_parser.parse_args([])
|
|
97
97
|
assert args.auto_adjust_urgency is True
|
|
98
98
|
|
|
99
|
-
args = arg_parser.parse_args([])
|
|
99
|
+
args = arg_parser.parse_args(["--no-auto-adjust-urgency"])
|
|
100
100
|
assert args.auto_adjust_urgency is False
|
|
101
101
|
|
|
102
102
|
|
|
@@ -144,6 +144,7 @@ class TestMainFunction:
|
|
|
144
144
|
mock_args.install = False
|
|
145
145
|
mock_args.schedule = False
|
|
146
146
|
mock_args.report = None
|
|
147
|
+
mock_args.auto_adjust_urgency = True
|
|
147
148
|
mock_parse.return_value = mock_args
|
|
148
149
|
|
|
149
150
|
with patch.object(arg_parser, "print_help") as mock_help:
|
|
@@ -159,6 +160,7 @@ class TestMainFunction:
|
|
|
159
160
|
mock_args.install = True
|
|
160
161
|
mock_args.schedule = False
|
|
161
162
|
mock_args.report = None
|
|
163
|
+
mock_args.auto_adjust_urgency = True
|
|
162
164
|
mock_parse.return_value = mock_args
|
|
163
165
|
|
|
164
166
|
main()
|
|
@@ -189,6 +191,7 @@ class TestMainFunction:
|
|
|
189
191
|
mock_args.taskrc = test_taskrc
|
|
190
192
|
mock_args.urgency_weight = None
|
|
191
193
|
mock_args.dry_run = False
|
|
194
|
+
mock_args.auto_adjust_urgency = True
|
|
192
195
|
mock_parse.return_value = mock_args
|
|
193
196
|
|
|
194
197
|
main()
|
|
@@ -201,6 +204,7 @@ class TestMainFunction:
|
|
|
201
204
|
taskrc=test_taskrc,
|
|
202
205
|
urgency_weight_override=None,
|
|
203
206
|
dry_run=False,
|
|
207
|
+
auto_adjust_urgency=True,
|
|
204
208
|
)
|
|
205
209
|
|
|
206
210
|
@patch("taskcheck.__main__.load_config")
|
|
@@ -223,6 +227,7 @@ class TestMainFunction:
|
|
|
223
227
|
mock_args.force_update = True
|
|
224
228
|
mock_args.taskrc = test_taskrc
|
|
225
229
|
mock_args.dry_run = False
|
|
230
|
+
mock_args.auto_adjust_urgency = True
|
|
226
231
|
mock_parse.return_value = mock_args
|
|
227
232
|
|
|
228
233
|
main()
|
|
@@ -266,6 +271,7 @@ class TestMainFunction:
|
|
|
266
271
|
mock_args.taskrc = test_taskrc
|
|
267
272
|
mock_args.urgency_weight = None
|
|
268
273
|
mock_args.dry_run = False
|
|
274
|
+
mock_args.auto_adjust_urgency = True
|
|
269
275
|
mock_parse.return_value = mock_args
|
|
270
276
|
|
|
271
277
|
main()
|
|
@@ -309,6 +315,7 @@ class TestMainFunction:
|
|
|
309
315
|
mock_args.taskrc = test_taskrc
|
|
310
316
|
mock_args.urgency_weight = None
|
|
311
317
|
mock_args.dry_run = False
|
|
318
|
+
mock_args.auto_adjust_urgency = True
|
|
312
319
|
mock_parse.return_value = mock_args
|
|
313
320
|
|
|
314
321
|
main()
|
|
@@ -320,6 +327,7 @@ class TestMainFunction:
|
|
|
320
327
|
taskrc=test_taskrc,
|
|
321
328
|
urgency_weight_override=None,
|
|
322
329
|
dry_run=False,
|
|
330
|
+
auto_adjust_urgency=True,
|
|
323
331
|
)
|
|
324
332
|
|
|
325
333
|
@patch("taskcheck.__main__.load_config")
|
|
@@ -356,6 +364,7 @@ class TestMainFunction:
|
|
|
356
364
|
mock_args.taskrc = test_taskrc
|
|
357
365
|
mock_args.urgency_weight = 0.3
|
|
358
366
|
mock_args.dry_run = False
|
|
367
|
+
mock_args.auto_adjust_urgency = True
|
|
359
368
|
mock_parse.return_value = mock_args
|
|
360
369
|
|
|
361
370
|
main()
|
|
@@ -367,6 +376,7 @@ class TestMainFunction:
|
|
|
367
376
|
taskrc=test_taskrc,
|
|
368
377
|
urgency_weight_override=0.3,
|
|
369
378
|
dry_run=False,
|
|
379
|
+
auto_adjust_urgency=True,
|
|
370
380
|
)
|
|
371
381
|
|
|
372
382
|
@patch("taskcheck.__main__.load_config")
|
|
@@ -408,6 +418,7 @@ class TestMainFunction:
|
|
|
408
418
|
mock_args.taskrc = test_taskrc
|
|
409
419
|
mock_args.urgency_weight = None
|
|
410
420
|
mock_args.dry_run = True
|
|
421
|
+
mock_args.auto_adjust_urgency = True
|
|
411
422
|
mock_parse.return_value = mock_args
|
|
412
423
|
|
|
413
424
|
main()
|
|
@@ -420,6 +431,7 @@ class TestMainFunction:
|
|
|
420
431
|
taskrc=test_taskrc,
|
|
421
432
|
urgency_weight_override=None,
|
|
422
433
|
dry_run=True,
|
|
434
|
+
auto_adjust_urgency=True,
|
|
423
435
|
)
|
|
424
436
|
mock_load_config.assert_called_once()
|
|
425
437
|
|
|
@@ -476,6 +488,7 @@ class TestMainFunction:
|
|
|
476
488
|
mock_args.taskrc = test_taskrc
|
|
477
489
|
mock_args.urgency_weight = None
|
|
478
490
|
mock_args.dry_run = True
|
|
491
|
+
mock_args.auto_adjust_urgency = True
|
|
479
492
|
mock_parse.return_value = mock_args
|
|
480
493
|
|
|
481
494
|
main()
|
|
@@ -498,6 +511,7 @@ class TestMainFunction:
|
|
|
498
511
|
taskrc=test_taskrc,
|
|
499
512
|
urgency_weight_override=None,
|
|
500
513
|
dry_run=True,
|
|
514
|
+
auto_adjust_urgency=True,
|
|
501
515
|
)
|
|
502
516
|
|
|
503
517
|
@patch("taskcheck.__main__.load_config")
|
|
@@ -511,6 +525,7 @@ class TestMainFunction:
|
|
|
511
525
|
mock_args.install = False
|
|
512
526
|
mock_args.schedule = True
|
|
513
527
|
mock_args.report = None
|
|
528
|
+
mock_args.auto_adjust_urgency = True
|
|
514
529
|
mock_parse.return_value = mock_args
|
|
515
530
|
|
|
516
531
|
with pytest.raises(FileNotFoundError):
|
|
@@ -524,6 +539,7 @@ class TestMainFunction:
|
|
|
524
539
|
mock_args.install = False
|
|
525
540
|
mock_args.schedule = False
|
|
526
541
|
mock_args.report = None
|
|
542
|
+
mock_args.auto_adjust_urgency = True
|
|
527
543
|
mock_parse.return_value = mock_args
|
|
528
544
|
|
|
529
545
|
with patch.object(arg_parser, "print_help") as mock_help:
|
|
@@ -539,6 +555,7 @@ class TestMainFunction:
|
|
|
539
555
|
mock_args.install = True
|
|
540
556
|
mock_args.schedule = True
|
|
541
557
|
mock_args.report = None
|
|
558
|
+
mock_args.auto_adjust_urgency = True
|
|
542
559
|
mock_parse.return_value = mock_args
|
|
543
560
|
|
|
544
561
|
with patch("taskcheck.__main__.load_config") as mock_load:
|
|
@@ -558,6 +575,7 @@ class TestImportErrorHandling:
|
|
|
558
575
|
mock_args.install = True
|
|
559
576
|
mock_args.schedule = False
|
|
560
577
|
mock_args.report = None
|
|
578
|
+
mock_args.auto_adjust_urgency = True
|
|
561
579
|
mock_parse.return_value = mock_args
|
|
562
580
|
|
|
563
581
|
with patch(
|
|
@@ -575,6 +593,7 @@ class TestImportErrorHandling:
|
|
|
575
593
|
mock_args.install = False
|
|
576
594
|
mock_args.schedule = False
|
|
577
595
|
mock_args.report = "today"
|
|
596
|
+
mock_args.auto_adjust_urgency = True
|
|
578
597
|
mock_parse.return_value = mock_args
|
|
579
598
|
|
|
580
599
|
with patch("taskcheck.__main__.load_config", return_value={}):
|
|
@@ -473,7 +473,8 @@ class TestAutoAdjustUrgency:
|
|
|
473
473
|
from datetime import datetime, timedelta
|
|
474
474
|
|
|
475
475
|
now = datetime.now()
|
|
476
|
-
|
|
476
|
+
future_date_near = now + timedelta(days=3)
|
|
477
|
+
future_date_far = now + timedelta(days=7)
|
|
477
478
|
|
|
478
479
|
# Create tasks that will require at least one reduction in urgency weight
|
|
479
480
|
overdue_tasks = [
|
|
@@ -481,24 +482,37 @@ class TestAutoAdjustUrgency:
|
|
|
481
482
|
"id": 1,
|
|
482
483
|
"uuid": "task-1",
|
|
483
484
|
"description": "Tight deadline",
|
|
484
|
-
"estimated": "P16H", #
|
|
485
|
+
"estimated": "P16H", # 2 working days, due in 7 days
|
|
485
486
|
"time_map": "work",
|
|
486
487
|
"urgency": 20.0,
|
|
487
|
-
"due":
|
|
488
|
+
"due": future_date_far.strftime(
|
|
488
489
|
"%Y%m%dT%H%M%SZ"
|
|
489
|
-
), # Due in
|
|
490
|
+
), # Due in 7 days - tight deadline
|
|
490
491
|
"status": "pending",
|
|
491
492
|
"entry": now.strftime("%Y%m%dT%H%M%SZ"), # Created today
|
|
492
|
-
}
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"id": 2,
|
|
496
|
+
"uuid": "task-2",
|
|
497
|
+
"description": "Competing task",
|
|
498
|
+
"estimated": "P16H", # 2 working days, due in 3 days
|
|
499
|
+
"time_map": "work",
|
|
500
|
+
"urgency": 15.0,
|
|
501
|
+
"due": future_date_near.strftime(
|
|
502
|
+
"%Y%m%dT%H%M%SZ"
|
|
503
|
+
), # Same deadline to create conflict
|
|
504
|
+
"status": "pending",
|
|
505
|
+
"entry": now.strftime("%Y%m%dT%H%M%SZ"), # Created today
|
|
506
|
+
},
|
|
493
507
|
]
|
|
494
508
|
|
|
495
509
|
mock_tasks.return_value = overdue_tasks
|
|
496
510
|
mock_coeffs.return_value = UrgencyCoefficients(
|
|
497
|
-
{"P16H": 10.0}, False, 4.0, 365, 12, 2
|
|
511
|
+
{"P16H": 10.0, "P8H": 8.0}, False, 4.0, 365, 12, 2
|
|
498
512
|
)
|
|
499
513
|
mock_calendars.return_value = []
|
|
500
|
-
# Mock
|
|
501
|
-
mock_long_range.return_value = ([
|
|
514
|
+
# Mock enough available time that the task CAN be completed with weight reduction
|
|
515
|
+
mock_long_range.return_value = ([4.0] * 7, 0.0) # 28 total hours available
|
|
502
516
|
|
|
503
517
|
with patch("taskcheck.parallel.console.print") as mock_console_print:
|
|
504
518
|
check_tasks_parallel(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|