pytaskwarrior 2.0.7__tar.gz → 3.0.0a1__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.
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/PKG-INFO +2 -1
- pytaskwarrior-3.0.0a1/README.md +123 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/pyproject.toml +19 -1
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/pytaskwarrior.egg-info/PKG-INFO +2 -1
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/pytaskwarrior.egg-info/SOURCES.txt +5 -0
- pytaskwarrior-3.0.0a1/src/pytaskwarrior.egg-info/requires.txt +2 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/__init__.py +3 -4
- pytaskwarrior-3.0.0a1/src/taskwarrior/adapters/__init__.py +79 -0
- pytaskwarrior-3.0.0a1/src/taskwarrior/adapters/taskchampion_adapter.py +466 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/adapters/taskwarrior_adapter.py +51 -91
- pytaskwarrior-3.0.0a1/src/taskwarrior/adapters/tc_converter.py +314 -0
- pytaskwarrior-3.0.0a1/src/taskwarrior/adapters/tc_filter.py +445 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/config/config_store.py +84 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/task_id.py +5 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/main.py +177 -69
- pytaskwarrior-3.0.0a1/src/taskwarrior/services/context_service.py +89 -0
- pytaskwarrior-3.0.0a1/src/taskwarrior/services/uda_service.py +111 -0
- pytaskwarrior-3.0.0a1/src/taskwarrior/utils/date_resolver.py +252 -0
- pytaskwarrior-3.0.0a1/src/taskwarrior/utils/virtual_tags.py +40 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/tests/test_main_get_udas.py +2 -2
- pytaskwarrior-2.0.7/README.md +0 -385
- pytaskwarrior-2.0.7/src/pytaskwarrior.egg-info/requires.txt +0 -1
- pytaskwarrior-2.0.7/src/taskwarrior/adapters/__init__.py +0 -1
- pytaskwarrior-2.0.7/src/taskwarrior/services/context_service.py +0 -174
- pytaskwarrior-2.0.7/src/taskwarrior/services/uda_service.py +0 -143
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/LICENSE +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/PYPI_README.md +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/setup.cfg +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/__init__.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/pytaskwarrior.egg-info/dependency_links.txt +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/pytaskwarrior.egg-info/top_level.txt +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/config/uda_parser.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/__init__.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/annotation_dto.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/context_dto.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/task_dto.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/dto/uda_dto.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/enums.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/exceptions.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/py.typed +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/registry/__init__.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/registry/uda_registry.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/services/__init__.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/utils/__init__.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/utils/conversions.py +0 -0
- {pytaskwarrior-2.0.7 → pytaskwarrior-3.0.0a1}/src/taskwarrior/utils/dto_converter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytaskwarrior
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0a1
|
|
4
4
|
Summary: Taskwarrior wrapper python module
|
|
5
5
|
Author-email: sznicolas <sznicolas@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,6 +21,7 @@ Requires-Python: >=3.12
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: pydantic>=2.11.7
|
|
24
|
+
Requires-Dist: taskchampion3-py-dev>=3.0.1.1a0
|
|
24
25
|
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
# pytaskwarrior
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# pytaskwarrior
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org/downloads/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/astral-sh/ruff)
|
|
6
|
+
[](https://github.com/sznicolas/pytaskwarrior/actions)
|
|
7
|
+
|
|
8
|
+
A modern Python library for [TaskWarrior](https://taskwarrior.org/) v3.x task management.
|
|
9
|
+
|
|
10
|
+
**No `task` binary required.** pytaskwarrior uses
|
|
11
|
+
[taskchampion-py](https://github.com/GothenburgBitFactory/taskchampion-py) — Rust bindings
|
|
12
|
+
to the taskchampion storage engine — for direct, high-performance SQLite access.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **No external binary** — reads/writes TaskWarrior's SQLite database directly
|
|
17
|
+
- **Full CRUD operations** — Create, read, update, delete tasks
|
|
18
|
+
- **Type-safe** — Pydantic models with full type hints
|
|
19
|
+
- **Context management** — Define, apply, and switch contexts (reads/writes `.taskrc`)
|
|
20
|
+
- **UDA support** — User Defined Attributes
|
|
21
|
+
- **Virtual tags** — `+OVERDUE`, `+DUE`, `+TODAY`, `+WEEK`, `+BLOCKED`, `+READY`, and 20+ more
|
|
22
|
+
- **Date expressions** — `due.before:tomorrow`, `due.after:eom`, compound expressions (`now + P3D`)
|
|
23
|
+
- **Recurring tasks** — Full recurrence support
|
|
24
|
+
- **Annotations** — Add notes to tasks
|
|
25
|
+
- **Optional CLI fallback** — Pass `task_cmd="task"` to use the classic CLI adapter
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- Python 3.12+
|
|
30
|
+
- `taskchampion-py` >= 3.0.1.1 (installed automatically)
|
|
31
|
+
|
|
32
|
+
The `task` binary is **not required** for the default adapter.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install pytaskwarrior
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or install from source:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/sznicolas/pytaskwarrior.git
|
|
44
|
+
cd pytaskwarrior
|
|
45
|
+
uv sync
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from taskwarrior import TaskWarrior, TaskInputDTO, Priority
|
|
52
|
+
|
|
53
|
+
# No binary needed — uses taskchampion SQLite backend directly
|
|
54
|
+
tw = TaskWarrior()
|
|
55
|
+
|
|
56
|
+
# Create a task
|
|
57
|
+
task = tw.add_task(TaskInputDTO(
|
|
58
|
+
description="Finish project report",
|
|
59
|
+
priority=Priority.HIGH,
|
|
60
|
+
project="work",
|
|
61
|
+
tags=["urgent"],
|
|
62
|
+
due="friday",
|
|
63
|
+
))
|
|
64
|
+
print(f"Created: {task.uuid}")
|
|
65
|
+
|
|
66
|
+
# Query tasks
|
|
67
|
+
for t in tw.get_tasks("project:work"):
|
|
68
|
+
print(f"[{t.priority or '-'}] {t.description}")
|
|
69
|
+
|
|
70
|
+
# Virtual tag filtering
|
|
71
|
+
overdue = tw.get_tasks("+OVERDUE")
|
|
72
|
+
due_soon = tw.get_tasks("due.before:eow")
|
|
73
|
+
|
|
74
|
+
# Complete a task
|
|
75
|
+
tw.done_task(task.uuid)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Using the CLI adapter (optional)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Explicit CLI mode — requires the task binary
|
|
82
|
+
tw = TaskWarrior(task_cmd="task")
|
|
83
|
+
|
|
84
|
+
# Custom paths
|
|
85
|
+
tw = TaskWarrior(
|
|
86
|
+
taskrc_file="/path/to/.taskrc",
|
|
87
|
+
data_location="/path/to/task/data",
|
|
88
|
+
)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Architecture
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
TaskWarrior (facade)
|
|
95
|
+
├── TaskChampionAdapter ← default: direct SQLite via taskchampion-py
|
|
96
|
+
│ ├── CRUD operations (add/get/modify/delete tasks)
|
|
97
|
+
│ ├── Filtering (tc_filter.py — Python reimplementation of TW filters)
|
|
98
|
+
│ └── Date resolution (date_resolver.py — Python reimplementation of TW dates)
|
|
99
|
+
├── ConfigStore ← reads/writes ~/.taskrc
|
|
100
|
+
│ ├── ContextService ← define/apply/delete contexts
|
|
101
|
+
│ └── UdaService ← define/delete UDAs
|
|
102
|
+
└── TaskWarriorAdapter ← optional CLI fallback (task_cmd="task")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Supported Filter Syntax
|
|
106
|
+
|
|
107
|
+
| Token | Example | Description |
|
|
108
|
+
|-------|---------|-------------|
|
|
109
|
+
| `+tag` / `-tag` | `+urgent -someday` | Include / exclude by tag |
|
|
110
|
+
| `+VIRTUAL` | `+OVERDUE`, `+DUE`, `+TODAY` | Virtual tags (computed) |
|
|
111
|
+
| `status:X` | `status:pending` | Status filter |
|
|
112
|
+
| `project:X` | `project:work` | Project (hierarchical) |
|
|
113
|
+
| `priority:X` | `priority:H` | Priority |
|
|
114
|
+
| `due.before:X` | `due.before:tomorrow` | Date range |
|
|
115
|
+
| `due.after:X` | `due.after:eom` | Date range |
|
|
116
|
+
| `due.by:X` | `due.by:friday` | Date range (inclusive) |
|
|
117
|
+
|
|
118
|
+
## Next Steps
|
|
119
|
+
|
|
120
|
+
- [Getting Started](docs/getting-started.md) — Installation and setup
|
|
121
|
+
- [TaskChampion Adapter](docs/taskchampion-adapter.md) — Technical details
|
|
122
|
+
- [API Reference](docs/api/taskwarrior.md) — Full API documentation
|
|
123
|
+
- [Examples](docs/examples/basic.md) — More usage examples
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pytaskwarrior"
|
|
3
|
-
version = "
|
|
3
|
+
version = "3.0.0a1"
|
|
4
4
|
description = "Taskwarrior wrapper python module"
|
|
5
5
|
readme = "PYPI_README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -21,6 +21,8 @@ classifiers = [
|
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
23
|
"pydantic>=2.11.7",
|
|
24
|
+
# "taskchampion-py-dev>=3.0.1.1a1"
|
|
25
|
+
"taskchampion3-py-dev>=3.0.1.1a0",
|
|
24
26
|
]
|
|
25
27
|
|
|
26
28
|
[dependency-groups]
|
|
@@ -94,3 +96,19 @@ strict_equality = true
|
|
|
94
96
|
[[tool.mypy.overrides]]
|
|
95
97
|
module = "tests.*"
|
|
96
98
|
disallow_untyped_defs = false
|
|
99
|
+
|
|
100
|
+
[tool.pytest.ini_options]
|
|
101
|
+
testpaths = ["tests"]
|
|
102
|
+
addopts = "--tb=short -q --ignore=tests/integration"
|
|
103
|
+
|
|
104
|
+
[tool.coverage.run]
|
|
105
|
+
source = ["src/taskwarrior"]
|
|
106
|
+
branch = true
|
|
107
|
+
|
|
108
|
+
[tool.coverage.report]
|
|
109
|
+
show_missing = true
|
|
110
|
+
exclude_lines = [
|
|
111
|
+
"pragma: no cover",
|
|
112
|
+
"if TYPE_CHECKING:",
|
|
113
|
+
"raise NotImplementedError",
|
|
114
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytaskwarrior
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0a1
|
|
4
4
|
Summary: Taskwarrior wrapper python module
|
|
5
5
|
Author-email: sznicolas <sznicolas@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,6 +21,7 @@ Requires-Python: >=3.12
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: pydantic>=2.11.7
|
|
24
|
+
Requires-Dist: taskchampion3-py-dev>=3.0.1.1a0
|
|
24
25
|
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
# pytaskwarrior
|
|
@@ -14,7 +14,10 @@ src/taskwarrior/exceptions.py
|
|
|
14
14
|
src/taskwarrior/main.py
|
|
15
15
|
src/taskwarrior/py.typed
|
|
16
16
|
src/taskwarrior/adapters/__init__.py
|
|
17
|
+
src/taskwarrior/adapters/taskchampion_adapter.py
|
|
17
18
|
src/taskwarrior/adapters/taskwarrior_adapter.py
|
|
19
|
+
src/taskwarrior/adapters/tc_converter.py
|
|
20
|
+
src/taskwarrior/adapters/tc_filter.py
|
|
18
21
|
src/taskwarrior/config/config_store.py
|
|
19
22
|
src/taskwarrior/config/uda_parser.py
|
|
20
23
|
src/taskwarrior/dto/__init__.py
|
|
@@ -30,5 +33,7 @@ src/taskwarrior/services/context_service.py
|
|
|
30
33
|
src/taskwarrior/services/uda_service.py
|
|
31
34
|
src/taskwarrior/utils/__init__.py
|
|
32
35
|
src/taskwarrior/utils/conversions.py
|
|
36
|
+
src/taskwarrior/utils/date_resolver.py
|
|
33
37
|
src/taskwarrior/utils/dto_converter.py
|
|
38
|
+
src/taskwarrior/utils/virtual_tags.py
|
|
34
39
|
tests/test_main_get_udas.py
|
|
@@ -29,7 +29,9 @@ Example:
|
|
|
29
29
|
|
|
30
30
|
Requirements:
|
|
31
31
|
- Python 3.12+
|
|
32
|
-
-
|
|
32
|
+
- The ``task`` binary is only required when passing ``task_cmd`` to
|
|
33
|
+
:class:`~taskwarrior.TaskWarrior`; the default backend (TaskChampion)
|
|
34
|
+
works without it.
|
|
33
35
|
"""
|
|
34
36
|
|
|
35
37
|
import importlib.metadata
|
|
@@ -53,13 +55,10 @@ from .registry.uda_registry import UdaRegistry
|
|
|
53
55
|
from .utils.dto_converter import task_output_to_input
|
|
54
56
|
|
|
55
57
|
__version__ = importlib.metadata.version("pytaskwarrior")
|
|
56
|
-
# Backwards-compatible alias
|
|
57
|
-
version = __version__
|
|
58
58
|
|
|
59
59
|
__all__ = [
|
|
60
60
|
"AnnotationDTO",
|
|
61
61
|
"ContextDTO",
|
|
62
|
-
"version",
|
|
63
62
|
"Priority",
|
|
64
63
|
"RecurrencePeriod",
|
|
65
64
|
"TaskID",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Adapter interfaces for pytaskwarrior.
|
|
2
|
+
|
|
3
|
+
This module exposes the :class:`AdapterProtocol` that any backend adapter
|
|
4
|
+
must satisfy, enabling dependency injection and testability.
|
|
5
|
+
|
|
6
|
+
It also re-exports :class:`~taskchampion.AccessMode` for convenience, so
|
|
7
|
+
callers do not need to import directly from ``taskchampion``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Protocol, runtime_checkable
|
|
13
|
+
|
|
14
|
+
from taskchampion import AccessMode
|
|
15
|
+
|
|
16
|
+
from ..dto.task_dto import TaskInputDTO, TaskOutputDTO
|
|
17
|
+
from ..dto.task_id import TaskRef
|
|
18
|
+
|
|
19
|
+
__all__ = ["AdapterProtocol", "AccessMode"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@runtime_checkable
|
|
23
|
+
class AdapterProtocol(Protocol):
|
|
24
|
+
"""Structural protocol satisfied by every pytaskwarrior adapter.
|
|
25
|
+
|
|
26
|
+
Both :class:`~taskwarrior.adapters.taskwarrior_adapter.TaskWarriorAdapter`
|
|
27
|
+
(subprocess-based) and
|
|
28
|
+
:class:`~taskwarrior.adapters.taskchampion_adapter.TaskChampionAdapter`
|
|
29
|
+
(direct SQLite via taskchampion-py) implement this protocol.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def add_task(self, task: TaskInputDTO) -> TaskOutputDTO: ...
|
|
33
|
+
|
|
34
|
+
def modify_task(self, task: TaskInputDTO, task_id: TaskRef) -> TaskOutputDTO: ...
|
|
35
|
+
|
|
36
|
+
def get_task(self, task_id: TaskRef) -> TaskOutputDTO: ...
|
|
37
|
+
|
|
38
|
+
def get_tasks(
|
|
39
|
+
self,
|
|
40
|
+
filter: str = "",
|
|
41
|
+
include_completed: bool = False,
|
|
42
|
+
include_deleted: bool = False,
|
|
43
|
+
) -> list[TaskOutputDTO]: ...
|
|
44
|
+
|
|
45
|
+
def get_recurring_task(self, task_id: TaskRef) -> TaskOutputDTO: ...
|
|
46
|
+
|
|
47
|
+
def get_recurring_instances(self, task_id: TaskRef) -> list[TaskOutputDTO]: ...
|
|
48
|
+
|
|
49
|
+
def delete_task(self, task_id: TaskRef) -> None: ...
|
|
50
|
+
|
|
51
|
+
def purge_task(self, task_id: TaskRef) -> None: ...
|
|
52
|
+
|
|
53
|
+
def done_task(self, task_id: TaskRef) -> None: ...
|
|
54
|
+
|
|
55
|
+
def start_task(self, task_id: TaskRef) -> None: ...
|
|
56
|
+
|
|
57
|
+
def stop_task(self, task_id: TaskRef) -> None: ...
|
|
58
|
+
|
|
59
|
+
def annotate_task(self, task_id: TaskRef, annotation: str) -> None: ...
|
|
60
|
+
|
|
61
|
+
def synchronize(self) -> None: ...
|
|
62
|
+
|
|
63
|
+
def is_sync_configured(self) -> bool: ...
|
|
64
|
+
|
|
65
|
+
def has_local_changes(self) -> bool: ...
|
|
66
|
+
|
|
67
|
+
def pending_local_ops_count(self) -> int: ...
|
|
68
|
+
|
|
69
|
+
def task_calc(self, date_str: str) -> str: ...
|
|
70
|
+
|
|
71
|
+
def task_date_validator(self, date_str: str) -> bool: ...
|
|
72
|
+
|
|
73
|
+
def get_data_location(self) -> str | None: ...
|
|
74
|
+
|
|
75
|
+
def get_version(self) -> str: ...
|
|
76
|
+
|
|
77
|
+
def get_projects(self) -> list[str]: ...
|
|
78
|
+
|
|
79
|
+
def get_tags(self, include_virtual_tags: bool = False) -> list[str]: ...
|