taskcheck 1.5.0__tar.gz → 1.5.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 (31) hide show
  1. {taskcheck-1.5.0/taskcheck.egg-info → taskcheck-1.5.2}/PKG-INFO +5 -3
  2. {taskcheck-1.5.0 → taskcheck-1.5.2}/README.md +4 -2
  3. {taskcheck-1.5.0 → taskcheck-1.5.2}/pyproject.toml +1 -1
  4. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/__main__.py +8 -3
  5. taskcheck-1.5.2/taskcheck/dry_run.py +22 -0
  6. {taskcheck-1.5.0 → taskcheck-1.5.2/taskcheck.egg-info}/PKG-INFO +5 -3
  7. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/SOURCES.txt +1 -0
  8. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_main.py +47 -1
  9. {taskcheck-1.5.0 → taskcheck-1.5.2}/LICENSE +0 -0
  10. {taskcheck-1.5.0 → taskcheck-1.5.2}/setup.cfg +0 -0
  11. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/common.py +0 -0
  12. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/google_calendar.py +0 -0
  13. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/ical.py +0 -0
  14. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/install.py +0 -0
  15. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/parallel.py +0 -0
  16. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/report.py +0 -0
  17. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/theme.py +0 -0
  18. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/timeline.py +0 -0
  19. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/undo.py +0 -0
  20. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/dependency_links.txt +0 -0
  21. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/entry_points.txt +0 -0
  22. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/requires.txt +0 -0
  23. {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/top_level.txt +0 -0
  24. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_common.py +0 -0
  25. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_google_calendar.py +0 -0
  26. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_ical.py +0 -0
  27. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_install.py +0 -0
  28. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_parallel.py +0 -0
  29. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_report.py +0 -0
  30. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_timeline.py +0 -0
  31. {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_undo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcheck
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: Automatic scheduler for taskwarrior
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -32,7 +32,7 @@ Use it if you want to:
32
32
  - ✨ Auto-schedule tasks from working hours + calendar blocks
33
33
  - 🧭 Support complex working-hour maps
34
34
  - ⏱️ Consider urgency, due dates, and dependencies
35
- - 🧪 Dry-run mode to preview changes
35
+ - 🧪 Persisted dry-run previews for reports and timelines
36
36
  - ↩️ Undo the latest schedule update
37
37
  - 🧠 Auto-adjust urgency when deadlines cannot be met
38
38
  - 🔄 Force-refresh iCal calendars
@@ -84,7 +84,9 @@ tuesday = [[9, 12.30], [14, 17]]
84
84
  - `taskcheck --timeline 1w` → automatic day/week/month timeline for the next week
85
85
  - `taskcheck --timeline eom --zoom week` → weekly timeline through month end
86
86
 
87
- Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals when `COLORFGBG` is available.
87
+ Create a preview with `taskcheck --schedule --dry-run`. It does not update Taskwarrior; instead, it saves the generated schedule to the Taskwarrior data directory. Reuse it with `taskcheck --report today --dry-run` or `taskcheck --timeline 1w --dry-run`.
88
+
89
+ Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals through OSC 11, with config and environment fallbacks.
88
90
 
89
91
  ## Reference
90
92
 
@@ -17,7 +17,7 @@ Use it if you want to:
17
17
  - ✨ Auto-schedule tasks from working hours + calendar blocks
18
18
  - 🧭 Support complex working-hour maps
19
19
  - ⏱️ Consider urgency, due dates, and dependencies
20
- - 🧪 Dry-run mode to preview changes
20
+ - 🧪 Persisted dry-run previews for reports and timelines
21
21
  - ↩️ Undo the latest schedule update
22
22
  - 🧠 Auto-adjust urgency when deadlines cannot be met
23
23
  - 🔄 Force-refresh iCal calendars
@@ -69,7 +69,9 @@ tuesday = [[9, 12.30], [14, 17]]
69
69
  - `taskcheck --timeline 1w` → automatic day/week/month timeline for the next week
70
70
  - `taskcheck --timeline eom --zoom week` → weekly timeline through month end
71
71
 
72
- Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals when `COLORFGBG` is available.
72
+ Create a preview with `taskcheck --schedule --dry-run`. It does not update Taskwarrior; instead, it saves the generated schedule to the Taskwarrior data directory. Reuse it with `taskcheck --report today --dry-run` or `taskcheck --timeline 1w --dry-run`.
73
+
74
+ Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals through OSC 11, with config and environment fallbacks.
73
75
 
74
76
  ## Reference
75
77
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskcheck"
3
- version = "1.5.0"
3
+ version = "1.5.2"
4
4
  description = "Automatic scheduler for taskwarrior"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -4,6 +4,7 @@ from importlib.metadata import version
4
4
 
5
5
  from taskcheck.parallel import check_tasks_parallel
6
6
  from taskcheck.common import config_dir
7
+ from taskcheck.dry_run import load_dry_run_results, save_dry_run_results
7
8
 
8
9
  arg_parser = argparse.ArgumentParser()
9
10
  arg_parser.add_argument("--version", action="version", version=f"taskcheck {version('taskcheck')}")
@@ -62,6 +63,7 @@ arg_parser.add_argument(
62
63
  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.",
63
64
  )
64
65
  arg_parser.add_argument(
66
+ "-d",
65
67
  "--dry-run",
66
68
  action="store_true",
67
69
  help="Perform scheduling without modifying the Taskwarrior database, useful for testing.",
@@ -151,6 +153,8 @@ def main():
151
153
  config,
152
154
  **check_tasks_kwargs,
153
155
  )
156
+ if args.dry_run and result is not None:
157
+ save_dry_run_results(result, taskrc=args.taskrc)
154
158
  print_help = False
155
159
 
156
160
  if args.report:
@@ -158,9 +162,8 @@ def main():
158
162
 
159
163
  config = load_config()
160
164
  scheduling_results = None
161
- if args.schedule and args.dry_run:
162
- # If we just did a dry-run schedule, use those results
163
- scheduling_results = result
165
+ if args.dry_run:
166
+ scheduling_results = result if args.schedule else load_dry_run_results(args.taskrc)
164
167
  generate_report(
165
168
  config,
166
169
  args.report,
@@ -176,6 +179,8 @@ def main():
176
179
  from taskcheck.timeline import generate_timeline
177
180
 
178
181
  scheduling_results = result if args.schedule and args.dry_run else None
182
+ if args.dry_run and scheduling_results is None:
183
+ scheduling_results = load_dry_run_results(args.taskrc)
179
184
  zoom = getattr(args, "zoom", "day")
180
185
  if zoom not in {"auto", "day", "week", "month"}:
181
186
  zoom = "auto"
@@ -0,0 +1,22 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from taskcheck.undo import get_task_data_dir
5
+
6
+
7
+ def get_dry_run_path(taskrc=None):
8
+ return get_task_data_dir(taskrc) / "taskcheck" / "dry-run.json"
9
+
10
+
11
+ def save_dry_run_results(results, taskrc=None):
12
+ path = get_dry_run_path(taskrc)
13
+ path.parent.mkdir(parents=True, exist_ok=True)
14
+ path.write_text(json.dumps(results, indent=2, sort_keys=True))
15
+ return path
16
+
17
+
18
+ def load_dry_run_results(taskrc=None):
19
+ path = get_dry_run_path(taskrc)
20
+ if not path.exists():
21
+ return None
22
+ return json.loads(path.read_text())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskcheck
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: Automatic scheduler for taskwarrior
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -32,7 +32,7 @@ Use it if you want to:
32
32
  - ✨ Auto-schedule tasks from working hours + calendar blocks
33
33
  - 🧭 Support complex working-hour maps
34
34
  - ⏱️ Consider urgency, due dates, and dependencies
35
- - 🧪 Dry-run mode to preview changes
35
+ - 🧪 Persisted dry-run previews for reports and timelines
36
36
  - ↩️ Undo the latest schedule update
37
37
  - 🧠 Auto-adjust urgency when deadlines cannot be met
38
38
  - 🔄 Force-refresh iCal calendars
@@ -84,7 +84,9 @@ tuesday = [[9, 12.30], [14, 17]]
84
84
  - `taskcheck --timeline 1w` → automatic day/week/month timeline for the next week
85
85
  - `taskcheck --timeline eom --zoom week` → weekly timeline through month end
86
86
 
87
- Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals when `COLORFGBG` is available.
87
+ Create a preview with `taskcheck --schedule --dry-run`. It does not update Taskwarrior; instead, it saves the generated schedule to the Taskwarrior data directory. Reuse it with `taskcheck --report today --dry-run` or `taskcheck --timeline 1w --dry-run`.
88
+
89
+ Timeline rows follow dotted project levels such as `work.client`. Without `--zoom`, the most detailed view that fits the terminal width is selected: day, then week, then month. The track uses `▶` for a start, `━` for work, `◀` for an end, and `◆` for a deadline. Thin, heavy, and double rules separate days, weeks, and months. Project colors are deterministic and adapt to light or dark terminals through OSC 11, with config and environment fallbacks.
88
90
 
89
91
  ## Reference
90
92
 
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  taskcheck/__main__.py
5
5
  taskcheck/common.py
6
+ taskcheck/dry_run.py
6
7
  taskcheck/google_calendar.py
7
8
  taskcheck/ical.py
8
9
  taskcheck/install.py
@@ -101,6 +101,9 @@ class TestArgumentParsing:
101
101
  args = arg_parser.parse_args(["--dry-run"])
102
102
  assert args.dry_run is True
103
103
 
104
+ args = arg_parser.parse_args(["-d"])
105
+ assert args.dry_run is True
106
+
104
107
  args = arg_parser.parse_args([])
105
108
  assert args.dry_run is False
106
109
 
@@ -413,10 +416,11 @@ class TestMainFunction:
413
416
  auto_adjust_urgency=True,
414
417
  )
415
418
 
419
+ @patch("taskcheck.__main__.save_dry_run_results")
416
420
  @patch("taskcheck.__main__.load_config")
417
421
  @patch("taskcheck.__main__.check_tasks_parallel")
418
422
  def test_main_schedule_with_dry_run(
419
- self, mock_check_tasks, mock_load_config, sample_config, test_taskrc
423
+ self, mock_check_tasks, mock_load_config, mock_save, sample_config, test_taskrc
420
424
  ):
421
425
  """Test that dry-run mode returns scheduling results without modifying tasks."""
422
426
  mock_load_config.return_value = sample_config
@@ -437,6 +441,7 @@ class TestMainFunction:
437
441
  }
438
442
  ]
439
443
  mock_check_tasks.return_value = dry_run_results
444
+ mock_save.return_value = None
440
445
 
441
446
  with patch(
442
447
  "sys.argv",
@@ -469,6 +474,7 @@ class TestMainFunction:
469
474
  )
470
475
  mock_load_config.assert_called_once()
471
476
 
477
+ @patch("taskcheck.__main__.save_dry_run_results")
472
478
  @patch("taskcheck.__main__.load_config")
473
479
  @patch("taskcheck.__main__.check_tasks_parallel")
474
480
  @patch("taskcheck.report.generate_report")
@@ -477,6 +483,7 @@ class TestMainFunction:
477
483
  mock_generate_report,
478
484
  mock_check_tasks,
479
485
  mock_load_config,
486
+ mock_save,
480
487
  sample_config,
481
488
  test_taskrc,
482
489
  ):
@@ -499,6 +506,7 @@ class TestMainFunction:
499
506
  }
500
507
  ]
501
508
  mock_check_tasks.return_value = dry_run_results
509
+ mock_save.return_value = None
502
510
 
503
511
  with patch(
504
512
  "sys.argv",
@@ -536,6 +544,7 @@ class TestMainFunction:
536
544
  taskrc=test_taskrc,
537
545
  scheduling_results=dry_run_results,
538
546
  )
547
+ mock_save.assert_called_once_with(dry_run_results, taskrc=test_taskrc)
539
548
 
540
549
  # Verify that check_tasks_parallel was called with dry_run=True
541
550
  mock_check_tasks.assert_called_once_with(
@@ -548,6 +557,43 @@ class TestMainFunction:
548
557
  auto_adjust_urgency=True,
549
558
  )
550
559
 
560
+ @patch("taskcheck.__main__.load_dry_run_results")
561
+ @patch("taskcheck.__main__.load_config")
562
+ @patch("taskcheck.report.generate_report")
563
+ def test_main_report_dry_run_loads_cached_results(
564
+ self, mock_generate_report, mock_load_config, mock_load_cache, sample_config, test_taskrc
565
+ ):
566
+ mock_load_config.return_value = sample_config
567
+ cached = [{"id": "1", "scheduling": "2024-12-20 - PT2H"}]
568
+ mock_load_cache.return_value = cached
569
+
570
+ with patch("sys.argv", ["taskcheck", "--report", "today", "--dry-run", "--taskrc", test_taskrc]):
571
+ with patch("taskcheck.__main__.arg_parser.parse_args") as mock_parse:
572
+ mock_args = Mock()
573
+ mock_args.install = False
574
+ mock_args.schedule = False
575
+ mock_args.report = "today"
576
+ mock_args.timeline = None
577
+ mock_args.zoom = "auto"
578
+ mock_args.verbose = False
579
+ mock_args.force_update = False
580
+ mock_args.taskrc = test_taskrc
581
+ mock_args.urgency_weight = None
582
+ mock_args.dry_run = True
583
+ mock_args.auto_adjust_urgency = True
584
+ mock_parse.return_value = mock_args
585
+ main()
586
+
587
+ mock_load_cache.assert_called_once_with(test_taskrc)
588
+ mock_generate_report.assert_called_once_with(
589
+ sample_config,
590
+ "today",
591
+ False,
592
+ force_update=False,
593
+ taskrc=test_taskrc,
594
+ scheduling_results=cached,
595
+ )
596
+
551
597
  @patch("taskcheck.__main__.load_config")
552
598
  def test_main_config_loading_error(self, mock_load_config):
553
599
  """Test behavior when config loading fails."""
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