taskcheck 1.5.0__tar.gz → 1.5.1__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.1}/PKG-INFO +5 -3
- {taskcheck-1.5.0 → taskcheck-1.5.1}/README.md +4 -2
- {taskcheck-1.5.0 → taskcheck-1.5.1}/pyproject.toml +1 -1
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/__main__.py +7 -3
- taskcheck-1.5.1/taskcheck/dry_run.py +22 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1/taskcheck.egg-info}/PKG-INFO +5 -3
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck.egg-info/SOURCES.txt +1 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_main.py +44 -1
- {taskcheck-1.5.0 → taskcheck-1.5.1}/LICENSE +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/setup.cfg +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/common.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/google_calendar.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/ical.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/install.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/parallel.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/report.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/theme.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/timeline.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck/undo.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck.egg-info/dependency_links.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck.egg-info/entry_points.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck.egg-info/requires.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/taskcheck.egg-info/top_level.txt +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_common.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_google_calendar.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_ical.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_install.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_parallel.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_report.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/tests/test_timeline.py +0 -0
- {taskcheck-1.5.0 → taskcheck-1.5.1}/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.1
|
|
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')}")
|
|
@@ -151,6 +152,8 @@ def main():
|
|
|
151
152
|
config,
|
|
152
153
|
**check_tasks_kwargs,
|
|
153
154
|
)
|
|
155
|
+
if args.dry_run and result is not None:
|
|
156
|
+
save_dry_run_results(result, taskrc=args.taskrc)
|
|
154
157
|
print_help = False
|
|
155
158
|
|
|
156
159
|
if args.report:
|
|
@@ -158,9 +161,8 @@ def main():
|
|
|
158
161
|
|
|
159
162
|
config = load_config()
|
|
160
163
|
scheduling_results = None
|
|
161
|
-
if args.
|
|
162
|
-
|
|
163
|
-
scheduling_results = result
|
|
164
|
+
if args.dry_run:
|
|
165
|
+
scheduling_results = result if args.schedule else load_dry_run_results(args.taskrc)
|
|
164
166
|
generate_report(
|
|
165
167
|
config,
|
|
166
168
|
args.report,
|
|
@@ -176,6 +178,8 @@ def main():
|
|
|
176
178
|
from taskcheck.timeline import generate_timeline
|
|
177
179
|
|
|
178
180
|
scheduling_results = result if args.schedule and args.dry_run else None
|
|
181
|
+
if args.dry_run and scheduling_results is None:
|
|
182
|
+
scheduling_results = load_dry_run_results(args.taskrc)
|
|
179
183
|
zoom = getattr(args, "zoom", "day")
|
|
180
184
|
if zoom not in {"auto", "day", "week", "month"}:
|
|
181
185
|
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.1
|
|
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
|
|
|
@@ -413,10 +413,11 @@ class TestMainFunction:
|
|
|
413
413
|
auto_adjust_urgency=True,
|
|
414
414
|
)
|
|
415
415
|
|
|
416
|
+
@patch("taskcheck.__main__.save_dry_run_results")
|
|
416
417
|
@patch("taskcheck.__main__.load_config")
|
|
417
418
|
@patch("taskcheck.__main__.check_tasks_parallel")
|
|
418
419
|
def test_main_schedule_with_dry_run(
|
|
419
|
-
self, mock_check_tasks, mock_load_config, sample_config, test_taskrc
|
|
420
|
+
self, mock_check_tasks, mock_load_config, mock_save, sample_config, test_taskrc
|
|
420
421
|
):
|
|
421
422
|
"""Test that dry-run mode returns scheduling results without modifying tasks."""
|
|
422
423
|
mock_load_config.return_value = sample_config
|
|
@@ -437,6 +438,7 @@ class TestMainFunction:
|
|
|
437
438
|
}
|
|
438
439
|
]
|
|
439
440
|
mock_check_tasks.return_value = dry_run_results
|
|
441
|
+
mock_save.return_value = None
|
|
440
442
|
|
|
441
443
|
with patch(
|
|
442
444
|
"sys.argv",
|
|
@@ -469,6 +471,7 @@ class TestMainFunction:
|
|
|
469
471
|
)
|
|
470
472
|
mock_load_config.assert_called_once()
|
|
471
473
|
|
|
474
|
+
@patch("taskcheck.__main__.save_dry_run_results")
|
|
472
475
|
@patch("taskcheck.__main__.load_config")
|
|
473
476
|
@patch("taskcheck.__main__.check_tasks_parallel")
|
|
474
477
|
@patch("taskcheck.report.generate_report")
|
|
@@ -477,6 +480,7 @@ class TestMainFunction:
|
|
|
477
480
|
mock_generate_report,
|
|
478
481
|
mock_check_tasks,
|
|
479
482
|
mock_load_config,
|
|
483
|
+
mock_save,
|
|
480
484
|
sample_config,
|
|
481
485
|
test_taskrc,
|
|
482
486
|
):
|
|
@@ -499,6 +503,7 @@ class TestMainFunction:
|
|
|
499
503
|
}
|
|
500
504
|
]
|
|
501
505
|
mock_check_tasks.return_value = dry_run_results
|
|
506
|
+
mock_save.return_value = None
|
|
502
507
|
|
|
503
508
|
with patch(
|
|
504
509
|
"sys.argv",
|
|
@@ -536,6 +541,7 @@ class TestMainFunction:
|
|
|
536
541
|
taskrc=test_taskrc,
|
|
537
542
|
scheduling_results=dry_run_results,
|
|
538
543
|
)
|
|
544
|
+
mock_save.assert_called_once_with(dry_run_results, taskrc=test_taskrc)
|
|
539
545
|
|
|
540
546
|
# Verify that check_tasks_parallel was called with dry_run=True
|
|
541
547
|
mock_check_tasks.assert_called_once_with(
|
|
@@ -548,6 +554,43 @@ class TestMainFunction:
|
|
|
548
554
|
auto_adjust_urgency=True,
|
|
549
555
|
)
|
|
550
556
|
|
|
557
|
+
@patch("taskcheck.__main__.load_dry_run_results")
|
|
558
|
+
@patch("taskcheck.__main__.load_config")
|
|
559
|
+
@patch("taskcheck.report.generate_report")
|
|
560
|
+
def test_main_report_dry_run_loads_cached_results(
|
|
561
|
+
self, mock_generate_report, mock_load_config, mock_load_cache, sample_config, test_taskrc
|
|
562
|
+
):
|
|
563
|
+
mock_load_config.return_value = sample_config
|
|
564
|
+
cached = [{"id": "1", "scheduling": "2024-12-20 - PT2H"}]
|
|
565
|
+
mock_load_cache.return_value = cached
|
|
566
|
+
|
|
567
|
+
with patch("sys.argv", ["taskcheck", "--report", "today", "--dry-run", "--taskrc", test_taskrc]):
|
|
568
|
+
with patch("taskcheck.__main__.arg_parser.parse_args") as mock_parse:
|
|
569
|
+
mock_args = Mock()
|
|
570
|
+
mock_args.install = False
|
|
571
|
+
mock_args.schedule = False
|
|
572
|
+
mock_args.report = "today"
|
|
573
|
+
mock_args.timeline = None
|
|
574
|
+
mock_args.zoom = "auto"
|
|
575
|
+
mock_args.verbose = False
|
|
576
|
+
mock_args.force_update = False
|
|
577
|
+
mock_args.taskrc = test_taskrc
|
|
578
|
+
mock_args.urgency_weight = None
|
|
579
|
+
mock_args.dry_run = True
|
|
580
|
+
mock_args.auto_adjust_urgency = True
|
|
581
|
+
mock_parse.return_value = mock_args
|
|
582
|
+
main()
|
|
583
|
+
|
|
584
|
+
mock_load_cache.assert_called_once_with(test_taskrc)
|
|
585
|
+
mock_generate_report.assert_called_once_with(
|
|
586
|
+
sample_config,
|
|
587
|
+
"today",
|
|
588
|
+
False,
|
|
589
|
+
force_update=False,
|
|
590
|
+
taskrc=test_taskrc,
|
|
591
|
+
scheduling_results=cached,
|
|
592
|
+
)
|
|
593
|
+
|
|
551
594
|
@patch("taskcheck.__main__.load_config")
|
|
552
595
|
def test_main_config_loading_error(self, mock_load_config):
|
|
553
596
|
"""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
|