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.
Files changed (23) hide show
  1. {taskcheck-1.0.0/taskcheck.egg-info → taskcheck-1.0.0.post2}/PKG-INFO +33 -24
  2. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/README.md +32 -23
  3. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/pyproject.toml +1 -1
  4. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/__main__.py +13 -14
  5. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/parallel.py +23 -21
  6. {taskcheck-1.0.0 → taskcheck-1.0.0.post2/taskcheck.egg-info}/PKG-INFO +33 -24
  7. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_main.py +22 -3
  8. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_parallel.py +22 -8
  9. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/LICENSE +0 -0
  10. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/setup.cfg +0 -0
  11. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/common.py +0 -0
  12. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/ical.py +0 -0
  13. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/install.py +0 -0
  14. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck/report.py +0 -0
  15. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/SOURCES.txt +0 -0
  16. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/dependency_links.txt +0 -0
  17. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/entry_points.txt +0 -0
  18. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/requires.txt +0 -0
  19. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/taskcheck.egg-info/top_level.txt +0 -0
  20. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_common.py +0 -0
  21. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_ical.py +0 -0
  22. {taskcheck-1.0.0 → taskcheck-1.0.0.post2}/tests/test_install.py +0 -0
  23. {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
- 888888888888 88 ,ad8888ba, 88 88
17
- 88 88 d8"' `"8b 88 88
18
- 88 88 d8' 88 88
19
- 88 ,adPPYYba, ,adPPYba, 88 ,d8 88 88,dPPYba, ,adPPYba, ,adPPYba, 88 ,d8
20
- 88 "" `Y8 I8[ "" 88 ,a8" 88 88P' "8a a8P_____88 a8" "" 88 ,a8"
21
- 88 ,adPPPPP88 `"Y8ba, 8888[ Y8, 88 88 8PP""""""" 8b 8888[
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
- This is a taskwarrior extension that automatically schedule your tasks based on your working hours,
27
+ ![immagine](https://github.com/user-attachments/assets/27b83bb1-7a50-4923-a453-0a958fbe11ed)
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 mach due dates**
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, --verbose Increase output verbosity
191
- -i, --install Install taskcheck configuration
192
- -r, --report CONSTRAINT Show tasks planned until a certain time (e.g. 'today', '1w', 'eow')
193
- -s, --schedule Perform the scheduling algorithm and update tasks
194
- -f, --force-update Force update of all iCal calendars, ignoring cache expiration
195
- --taskrc PATH Set custom TASKRC directory (and TASKDATA) for debugging or alternate environments
196
- --urgency-weight FLOAT Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 0, only due urgency is considered.
197
- --dry-run Perform scheduling without modifying the Taskwarrior database (useful for testing)
198
- --no-auto-adjust-urgency Disable auto-adjustment of urgency weight (default: enabled)
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
- 888888888888 88 ,ad8888ba, 88 88
5
- 88 88 d8"' `"8b 88 88
6
- 88 88 d8' 88 88
7
- 88 ,adPPYYba, ,adPPYba, 88 ,d8 88 88,dPPYba, ,adPPYba, ,adPPYba, 88 ,d8
8
- 88 "" `Y8 I8[ "" 88 ,a8" 88 88P' "8a a8P_____88 a8" "" 88 ,a8"
9
- 88 ,adPPPPP88 `"Y8ba, 8888[ Y8, 88 88 8PP""""""" 8b 8888[
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
- This is a taskwarrior extension that automatically schedule your tasks based on your working hours,
15
+ ![immagine](https://github.com/user-attachments/assets/27b83bb1-7a50-4923-a453-0a958fbe11ed)
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 mach due dates**
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, --verbose Increase output verbosity
179
- -i, --install Install taskcheck configuration
180
- -r, --report CONSTRAINT Show tasks planned until a certain time (e.g. 'today', '1w', 'eow')
181
- -s, --schedule Perform the scheduling algorithm and update tasks
182
- -f, --force-update Force update of all iCal calendars, ignoring cache expiration
183
- --taskrc PATH Set custom TASKRC directory (and TASKDATA) for debugging or alternate environments
184
- --urgency-weight FLOAT Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 0, only due urgency is considered.
185
- --dry-run Perform scheduling without modifying the Taskwarrior database (useful for testing)
186
- --no-auto-adjust-urgency Disable auto-adjustment of urgency weight (default: enabled)
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskcheck"
3
- version = "1.0.0"
3
+ version = "1.0.0-2"
4
4
  description = "Automatic scheduler for taskwarrior"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -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="increase output verbosity."
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="install the UDAs, required settings, and default config file.",
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="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.",
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="perform the scheduling algorithm, giving a schedule and a scheduling UDA and alerting for not completable tasks",
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="force update of all ical calendars by ignoring cache expiration",
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="set custom TASKRC directory for debugging purposes",
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="weight for urgency in scheduling (0.0 to 1.0), overrides config value. Not aaplie to due urgency, i.e. when 0, only due urgency is considered.",
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="perform scheduling without modifying the Taskwarrior database, useful for testing",
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
- action="store_true",
53
- help="disable automatically reduction of urgency weight when tasks cannot be completed on time",
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
- if end_date_dt > due_dt:
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 (tasks_overdue and current_weight <= 0):
173
- # Print final weight message
174
- console.print(
175
- f"[green]Final urgency weight: {max(current_weight, 0.0):.1f}[/green]"
176
- )
177
- # Always print the warning if we still have overdue tasks
178
- console.print(
179
- "[red]Warning: cannot find a solution even with urgency weight 0.0[/red]"
180
- )
181
-
182
- # Do not print the final urgency weight message again here, as it is already printed above if needed.
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
- 888888888888 88 ,ad8888ba, 88 88
17
- 88 88 d8"' `"8b 88 88
18
- 88 88 d8' 88 88
19
- 88 ,adPPYYba, ,adPPYba, 88 ,d8 88 88,dPPYba, ,adPPYba, ,adPPYba, 88 ,d8
20
- 88 "" `Y8 I8[ "" 88 ,a8" 88 88P' "8a a8P_____88 a8" "" 88 ,a8"
21
- 88 ,adPPPPP88 `"Y8ba, 8888[ Y8, 88 88 8PP""""""" 8b 8888[
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
- This is a taskwarrior extension that automatically schedule your tasks based on your working hours,
27
+ ![immagine](https://github.com/user-attachments/assets/27b83bb1-7a50-4923-a453-0a958fbe11ed)
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 mach due dates**
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, --verbose Increase output verbosity
191
- -i, --install Install taskcheck configuration
192
- -r, --report CONSTRAINT Show tasks planned until a certain time (e.g. 'today', '1w', 'eow')
193
- -s, --schedule Perform the scheduling algorithm and update tasks
194
- -f, --force-update Force update of all iCal calendars, ignoring cache expiration
195
- --taskrc PATH Set custom TASKRC directory (and TASKDATA) for debugging or alternate environments
196
- --urgency-weight FLOAT Weight for urgency in scheduling (0.0 to 1.0), overrides config value. When 0, only due urgency is considered.
197
- --dry-run Perform scheduling without modifying the Taskwarrior database (useful for testing)
198
- --no-auto-adjust-urgency Disable auto-adjustment of urgency weight (default: enabled)
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 False
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(["--auto-adjust-urgency"])
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
- future_date = now + timedelta(days=5)
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", # 16 hours
485
+ "estimated": "P16H", # 2 working days, due in 7 days
485
486
  "time_map": "work",
486
487
  "urgency": 20.0,
487
- "due": future_date.strftime(
488
+ "due": future_date_far.strftime(
488
489
  "%Y%m%dT%H%M%SZ"
489
- ), # Due in 5 days - tight deadline
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 limited available time that will cause scheduling conflicts
501
- mock_long_range.return_value = ([2.0] * 7, 0.0) # Only 2 hours per day
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