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.
- {taskcheck-1.5.0/taskcheck.egg-info → taskcheck-1.5.2}/PKG-INFO +5 -3
- {taskcheck-1.5.0 → taskcheck-1.5.2}/README.md +4 -2
- {taskcheck-1.5.0 → taskcheck-1.5.2}/pyproject.toml +1 -1
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/__main__.py +8 -3
- taskcheck-1.5.2/taskcheck/dry_run.py +22 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2/taskcheck.egg-info}/PKG-INFO +5 -3
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/SOURCES.txt +1 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_main.py +47 -1
- {taskcheck-1.5.0 → taskcheck-1.5.2}/LICENSE +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/setup.cfg +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/common.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/google_calendar.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/ical.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/install.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/parallel.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/report.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/theme.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/timeline.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck/undo.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/dependency_links.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/entry_points.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/requires.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/taskcheck.egg-info/top_level.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_common.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_google_calendar.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_ical.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_install.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_parallel.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_report.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.2}/tests/test_timeline.py +0 -0
- {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.
|
|
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
|
-
- 🧪
|
|
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
|
-
|
|
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
|
-
- 🧪
|
|
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
|
-
|
|
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
|
|
|
@@ -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.
|
|
162
|
-
|
|
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.
|
|
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
|
-
- 🧪
|
|
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
|
-
|
|
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
|
|
|
@@ -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
|
|
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
|