taskcheck 1.6.1__tar.gz → 1.6.2__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 (34) hide show
  1. {taskcheck-1.6.1/taskcheck.egg-info → taskcheck-1.6.2}/PKG-INFO +6 -2
  2. {taskcheck-1.6.1 → taskcheck-1.6.2}/README.md +4 -0
  3. {taskcheck-1.6.1 → taskcheck-1.6.2}/pyproject.toml +2 -2
  4. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/parallel.py +6 -2
  5. {taskcheck-1.6.1 → taskcheck-1.6.2/taskcheck.egg-info}/PKG-INFO +6 -2
  6. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_parallel.py +19 -0
  7. {taskcheck-1.6.1 → taskcheck-1.6.2}/LICENSE +0 -0
  8. {taskcheck-1.6.1 → taskcheck-1.6.2}/setup.cfg +0 -0
  9. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/__main__.py +0 -0
  10. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/agent_blocks.py +0 -0
  11. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/common.py +0 -0
  12. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/dry_run.py +0 -0
  13. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/google_calendar.py +0 -0
  14. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/ical.py +0 -0
  15. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/install.py +0 -0
  16. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/report.py +0 -0
  17. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/theme.py +0 -0
  18. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/timeline.py +0 -0
  19. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck/undo.py +0 -0
  20. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck.egg-info/SOURCES.txt +0 -0
  21. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck.egg-info/dependency_links.txt +0 -0
  22. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck.egg-info/entry_points.txt +0 -0
  23. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck.egg-info/requires.txt +0 -0
  24. {taskcheck-1.6.1 → taskcheck-1.6.2}/taskcheck.egg-info/top_level.txt +0 -0
  25. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_agent_blocks.py +0 -0
  26. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_agent_scheduler_integration.py +0 -0
  27. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_common.py +0 -0
  28. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_google_calendar.py +0 -0
  29. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_ical.py +0 -0
  30. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_install.py +0 -0
  31. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_main.py +0 -0
  32. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_report.py +0 -0
  33. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_timeline.py +0 -0
  34. {taskcheck-1.6.1 → taskcheck-1.6.2}/tests/test_undo.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcheck
3
- Version: 1.6.1
3
+ Version: 1.6.2
4
4
  Summary: Automatic scheduler for taskwarrior
5
- Requires-Python: >=3.11
5
+ Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: appdirs>=1.4.4
8
8
  Requires-Dist: google-api-python-client>=2.198.0
@@ -148,6 +148,10 @@ Before writing a schedule, taskcheck backs up the affected tasks' `scheduled`, `
148
148
 
149
149
  If a task would finish after its due date, taskcheck retries with a total-urgency override. Each retry moves the task immediately above the task with the smallest greater urgency by adding `urgency_epsilon` (default: `0.1`). At rank 1, it adds epsilon for up to `max_top_urgency_rounds` retries (default: `10`), then tries once at urgency `1000`. If the task is still late, taskcheck stops raising it and optimizes the other overdue tasks.
150
150
 
151
+ Each task gets at most `N - 1 + max_top_urgency_rounds` priority increases before the final retry at urgency `1000`.
152
+ Here, `N` is the number of tasks in the schedule.
153
+ This limit stops repeated retries when tasks with competing deadlines keep overtaking each other.
154
+
151
155
  ## Tips and Tricks
152
156
 
153
157
  - You can exclude a task from being scheduled by removing the `time_map` or `estimated` attributes.
@@ -133,6 +133,10 @@ Before writing a schedule, taskcheck backs up the affected tasks' `scheduled`, `
133
133
 
134
134
  If a task would finish after its due date, taskcheck retries with a total-urgency override. Each retry moves the task immediately above the task with the smallest greater urgency by adding `urgency_epsilon` (default: `0.1`). At rank 1, it adds epsilon for up to `max_top_urgency_rounds` retries (default: `10`), then tries once at urgency `1000`. If the task is still late, taskcheck stops raising it and optimizes the other overdue tasks.
135
135
 
136
+ Each task gets at most `N - 1 + max_top_urgency_rounds` priority increases before the final retry at urgency `1000`.
137
+ Here, `N` is the number of tasks in the schedule.
138
+ This limit stops repeated retries when tasks with competing deadlines keep overtaking each other.
139
+
136
140
  ## Tips and Tricks
137
141
 
138
142
  - You can exclude a task from being scheduled by removing the `time_map` or `estimated` attributes.
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "taskcheck"
3
- version = "1.6.1"
3
+ version = "1.6.2"
4
4
  description = "Automatic scheduler for taskwarrior"
5
5
  readme = "README.md"
6
- requires-python = ">=3.11"
6
+ requires-python = ">=3.12"
7
7
  dependencies = [
8
8
  "appdirs>=1.4.4",
9
9
  "google-api-python-client>=2.198.0",
@@ -58,7 +58,7 @@ def advance_urgency_override(
58
58
  for task_uuid in overdue_uuids:
59
59
  state = adjustment_states.setdefault(
60
60
  task_uuid,
61
- {"top_rounds": 0, "fallback_used": False, "exhausted": False},
61
+ {"top_rounds": 0, "rounds": 0, "fallback_used": False, "exhausted": False},
62
62
  )
63
63
  if state["exhausted"]:
64
64
  continue
@@ -72,7 +72,10 @@ def advance_urgency_override(
72
72
  for uuid in task_info
73
73
  if uuid != task_uuid and effective_urgency(uuid) > current_urgency
74
74
  ]
75
- if greater_urgencies:
75
+ if state["rounds"] >= len(task_info) - 1 + max_top_rounds:
76
+ urgency_overrides[task_uuid] = 1000.0
77
+ state["fallback_used"] = True
78
+ elif greater_urgencies:
76
79
  urgency_overrides[task_uuid] = min(greater_urgencies) + epsilon
77
80
  elif state["top_rounds"] < max_top_rounds:
78
81
  urgency_overrides[task_uuid] = current_urgency + epsilon
@@ -80,6 +83,7 @@ def advance_urgency_override(
80
83
  else:
81
84
  urgency_overrides[task_uuid] = 1000.0
82
85
  state["fallback_used"] = True
86
+ state["rounds"] += 1
83
87
  return task_uuid
84
88
  return None
85
89
 
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcheck
3
- Version: 1.6.1
3
+ Version: 1.6.2
4
4
  Summary: Automatic scheduler for taskwarrior
5
- Requires-Python: >=3.11
5
+ Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: appdirs>=1.4.4
8
8
  Requires-Dist: google-api-python-client>=2.198.0
@@ -148,6 +148,10 @@ Before writing a schedule, taskcheck backs up the affected tasks' `scheduled`, `
148
148
 
149
149
  If a task would finish after its due date, taskcheck retries with a total-urgency override. Each retry moves the task immediately above the task with the smallest greater urgency by adding `urgency_epsilon` (default: `0.1`). At rank 1, it adds epsilon for up to `max_top_urgency_rounds` retries (default: `10`), then tries once at urgency `1000`. If the task is still late, taskcheck stops raising it and optimizes the other overdue tasks.
150
150
 
151
+ Each task gets at most `N - 1 + max_top_urgency_rounds` priority increases before the final retry at urgency `1000`.
152
+ Here, `N` is the number of tasks in the schedule.
153
+ This limit stops repeated retries when tasks with competing deadlines keep overtaking each other.
154
+
151
155
  ## Tips and Tricks
152
156
 
153
157
  - You can exclude a task from being scheduled by removing the `time_map` or `estimated` attributes.
@@ -388,6 +388,25 @@ class TestMainSchedulingFunction:
388
388
 
389
389
 
390
390
  class TestAutoAdjustUrgency:
391
+ def test_competing_overdue_tasks_exhaust_retries(self):
392
+ task_info = {
393
+ uuid: {"task": {"uuid": uuid, "urgency": urgency}, "urgency": urgency}
394
+ for uuid, urgency in (("a", 1.0), ("b", 2.0))
395
+ }
396
+ overrides = {}
397
+ states = {}
398
+ # Resolving one deadline can make the other task late on the next pass.
399
+ for index in range(12):
400
+ overdue = [task_info["a" if index % 2 == 0 else "b"]["task"]]
401
+ advance_urgency_override(
402
+ overdue, task_info, overrides, states, epsilon=0.1, max_top_rounds=2
403
+ )
404
+ assert advance_urgency_override(
405
+ [info["task"] for info in task_info.values()],
406
+ task_info, overrides, states, epsilon=0.1, max_top_rounds=2,
407
+ ) is None
408
+ assert overrides == {"a": 1000.0, "b": 1000.0}
409
+
391
410
  def test_urgency_override_moves_up_one_rank_then_uses_bounded_top_rounds(self):
392
411
  task_info = {
393
412
  "t1": {"task": {"uuid": "t1"}, "urgency": 1.0},
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