pytaskwarrior 2.0.2__tar.gz → 2.0.4__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.2 → pytaskwarrior-2.0.4}/PKG-INFO +10 -1
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/PYPI_README.md +9 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/README.md +8 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/pyproject.toml +1 -1
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/pytaskwarrior.egg-info/PKG-INFO +10 -1
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/adapters/taskwarrior_adapter.py +54 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/main.py +60 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/services/uda_service.py +35 -2
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/LICENSE +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/setup.cfg +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/pytaskwarrior.egg-info/SOURCES.txt +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/pytaskwarrior.egg-info/dependency_links.txt +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/pytaskwarrior.egg-info/requires.txt +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/pytaskwarrior.egg-info/top_level.txt +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/adapters/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/config/config_store.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/config/uda_parser.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/dto/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/dto/annotation_dto.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/dto/context_dto.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/dto/task_dto.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/dto/uda_dto.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/enums.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/exceptions.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/py.typed +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/registry/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/registry/uda_registry.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/services/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/services/context_service.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/utils/__init__.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/utils/conversions.py +0 -0
- {pytaskwarrior-2.0.2 → pytaskwarrior-2.0.4}/src/taskwarrior/utils/dto_converter.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytaskwarrior
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Taskwarrior wrapper python module
|
|
5
5
|
Author-email: sznicolas <sznicolas@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -42,6 +42,7 @@ Production-ready with 164 tests (96% coverage), strict type checking, and profes
|
|
|
42
42
|
- Type-safe with Pydantic models
|
|
43
43
|
- Context management
|
|
44
44
|
- UDA (User Defined Attributes) support
|
|
45
|
+
- Tag discovery and `@` context tags
|
|
45
46
|
- Recurring tasks and annotations
|
|
46
47
|
- Consistent exception hierarchy (`TaskNotFound`, `TaskValidationError`, `TaskOperationError`, `TaskConfigurationError`, …)
|
|
47
48
|
|
|
@@ -80,6 +81,14 @@ for t in tw.get_tasks():
|
|
|
80
81
|
tw.done_task(added.uuid)
|
|
81
82
|
```
|
|
82
83
|
|
|
84
|
+
## Tags
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
tags = tw.get_tags() # virtual tags excluded
|
|
88
|
+
all_tags = tw.get_tags(include_virtual_tags=True)
|
|
89
|
+
context_tags = tw.get_context_tags() # tags starting with "@"
|
|
90
|
+
```
|
|
91
|
+
|
|
83
92
|
## Documentation
|
|
84
93
|
|
|
85
94
|
Full documentation: [GitHub Repository](https://github.com/sznicolas/pytaskwarrior/)
|
|
@@ -17,6 +17,7 @@ Production-ready with 164 tests (96% coverage), strict type checking, and profes
|
|
|
17
17
|
- Type-safe with Pydantic models
|
|
18
18
|
- Context management
|
|
19
19
|
- UDA (User Defined Attributes) support
|
|
20
|
+
- Tag discovery and `@` context tags
|
|
20
21
|
- Recurring tasks and annotations
|
|
21
22
|
- Consistent exception hierarchy (`TaskNotFound`, `TaskValidationError`, `TaskOperationError`, `TaskConfigurationError`, …)
|
|
22
23
|
|
|
@@ -55,6 +56,14 @@ for t in tw.get_tasks():
|
|
|
55
56
|
tw.done_task(added.uuid)
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
## Tags
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
tags = tw.get_tags() # virtual tags excluded
|
|
63
|
+
all_tags = tw.get_tags(include_virtual_tags=True)
|
|
64
|
+
context_tags = tw.get_context_tags() # tags starting with "@"
|
|
65
|
+
```
|
|
66
|
+
|
|
58
67
|
## Documentation
|
|
59
68
|
|
|
60
69
|
Full documentation: [GitHub Repository](https://github.com/sznicolas/pytaskwarrior/)
|
|
@@ -17,6 +17,7 @@ A modern Python wrapper for [TaskWarrior](https://taskwarrior.org/) v3.4, the co
|
|
|
17
17
|
- **Type-safe** - Pydantic models with full type hints
|
|
18
18
|
- **Context management** - Define, apply, and switch contexts
|
|
19
19
|
- **UDA support** - User Defined Attributes
|
|
20
|
+
- **Tag discovery** - List real tags, virtual tags, and `@` context tags
|
|
20
21
|
- **Recurring tasks** - Full recurrence support
|
|
21
22
|
- **Annotations** - Add notes to tasks
|
|
22
23
|
- **Date calculations** - Use TaskWarrior's date expressions
|
|
@@ -128,6 +129,13 @@ tw = TaskWarrior(
|
|
|
128
129
|
| `stop_task(uuid)` | Stop working on task |
|
|
129
130
|
| `annotate_task(uuid, annotation)` | Add annotation to task |
|
|
130
131
|
|
|
132
|
+
#### Tags Operations
|
|
133
|
+
|
|
134
|
+
| Method | Description |
|
|
135
|
+
|--------|-------------|
|
|
136
|
+
| `get_tags(include_virtual_tags=False)` | List tags, excluding virtual tags by default |
|
|
137
|
+
| `get_context_tags()` | List tags that start with `@` |
|
|
138
|
+
|
|
131
139
|
#### Context Operations
|
|
132
140
|
|
|
133
141
|
| Method | Description |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytaskwarrior
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Taskwarrior wrapper python module
|
|
5
5
|
Author-email: sznicolas <sznicolas@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -42,6 +42,7 @@ Production-ready with 164 tests (96% coverage), strict type checking, and profes
|
|
|
42
42
|
- Type-safe with Pydantic models
|
|
43
43
|
- Context management
|
|
44
44
|
- UDA (User Defined Attributes) support
|
|
45
|
+
- Tag discovery and `@` context tags
|
|
45
46
|
- Recurring tasks and annotations
|
|
46
47
|
- Consistent exception hierarchy (`TaskNotFound`, `TaskValidationError`, `TaskOperationError`, `TaskConfigurationError`, …)
|
|
47
48
|
|
|
@@ -80,6 +81,14 @@ for t in tw.get_tasks():
|
|
|
80
81
|
tw.done_task(added.uuid)
|
|
81
82
|
```
|
|
82
83
|
|
|
84
|
+
## Tags
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
tags = tw.get_tags() # virtual tags excluded
|
|
88
|
+
all_tags = tw.get_tags(include_virtual_tags=True)
|
|
89
|
+
context_tags = tw.get_context_tags() # tags starting with "@"
|
|
90
|
+
```
|
|
91
|
+
|
|
83
92
|
## Documentation
|
|
84
93
|
|
|
85
94
|
Full documentation: [GitHub Repository](https://github.com/sznicolas/pytaskwarrior/)
|
|
@@ -26,6 +26,40 @@ from ..exceptions import (
|
|
|
26
26
|
|
|
27
27
|
logger = logging.getLogger(__name__)
|
|
28
28
|
|
|
29
|
+
TASKWARRIOR_VIRTUAL_TAGS: tuple[str, ...] = (
|
|
30
|
+
"BLOCKED",
|
|
31
|
+
"UNBLOCKED",
|
|
32
|
+
"BLOCKING",
|
|
33
|
+
"DUE",
|
|
34
|
+
"DUETODAY",
|
|
35
|
+
"TODAY",
|
|
36
|
+
"OVERDUE",
|
|
37
|
+
"WEEK",
|
|
38
|
+
"MONTH",
|
|
39
|
+
"QUARTER",
|
|
40
|
+
"YEAR",
|
|
41
|
+
"ACTIVE",
|
|
42
|
+
"SCHEDULED",
|
|
43
|
+
"PARENT",
|
|
44
|
+
"CHILD",
|
|
45
|
+
"UNTIL",
|
|
46
|
+
"WAITING",
|
|
47
|
+
"ANNOTATED",
|
|
48
|
+
"READY",
|
|
49
|
+
"YESTERDAY",
|
|
50
|
+
"TOMORROW",
|
|
51
|
+
"TAGGED",
|
|
52
|
+
"PENDING",
|
|
53
|
+
"COMPLETED",
|
|
54
|
+
"DELETED",
|
|
55
|
+
"UDA",
|
|
56
|
+
"ORPHAN",
|
|
57
|
+
"PRIORITY",
|
|
58
|
+
"PROJECT",
|
|
59
|
+
"LATEST",
|
|
60
|
+
)
|
|
61
|
+
TASKWARRIOR_VIRTUAL_TAG_SET = frozenset(TASKWARRIOR_VIRTUAL_TAGS)
|
|
62
|
+
|
|
29
63
|
|
|
30
64
|
class TaskWarriorAdapter:
|
|
31
65
|
"""Low-level adapter for TaskWarrior CLI commands.
|
|
@@ -515,3 +549,23 @@ class TaskWarriorAdapter:
|
|
|
515
549
|
|
|
516
550
|
projects = [line.strip() for line in result.stdout.split("\n") if line.strip()]
|
|
517
551
|
return projects
|
|
552
|
+
|
|
553
|
+
def get_tags(self, include_virtual_tags: bool = False) -> list[str]:
|
|
554
|
+
"""Get all tags defined in TaskWarrior.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
include_virtual_tags: If ``True``, include TaskWarrior virtual tags
|
|
558
|
+
such as ``TODAY`` and ``READY``.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
List of tag names.
|
|
562
|
+
"""
|
|
563
|
+
result = self.run_task_command(["_tags"])
|
|
564
|
+
|
|
565
|
+
if result.returncode != 0:
|
|
566
|
+
raise TaskWarriorError(f"Failed to get tags: {result.stderr}")
|
|
567
|
+
|
|
568
|
+
tags = [line.strip() for line in result.stdout.splitlines() if line.strip()]
|
|
569
|
+
if include_virtual_tags:
|
|
570
|
+
return list(dict.fromkeys(tags + list(TASKWARRIOR_VIRTUAL_TAGS)))
|
|
571
|
+
return [tag for tag in tags if tag not in TASKWARRIOR_VIRTUAL_TAG_SET]
|
|
@@ -554,6 +554,47 @@ class TaskWarrior:
|
|
|
554
554
|
"""
|
|
555
555
|
return self.uda_service.registry.get_uda(name)
|
|
556
556
|
|
|
557
|
+
def define_uda(self, uda: UdaConfig) -> None:
|
|
558
|
+
"""Define a new UDA via the TaskWarrior facade.
|
|
559
|
+
|
|
560
|
+
Delegates to UdaService.define_uda which performs the necessary
|
|
561
|
+
TaskWarrior config writes and registers the UDA in the local registry.
|
|
562
|
+
|
|
563
|
+
Args:
|
|
564
|
+
uda: The UdaConfig describing the UDA to create.
|
|
565
|
+
|
|
566
|
+
Raises:
|
|
567
|
+
TaskOperationError: If creating the UDA via the underlying adapter fails.
|
|
568
|
+
"""
|
|
569
|
+
self.uda_service.define_uda(uda)
|
|
570
|
+
|
|
571
|
+
def update_uda(self, uda: UdaConfig) -> None:
|
|
572
|
+
"""Update an existing UDA via the TaskWarrior facade.
|
|
573
|
+
|
|
574
|
+
Delegates to UdaService.update_uda.
|
|
575
|
+
|
|
576
|
+
Args:
|
|
577
|
+
uda: The UdaConfig with updated fields.
|
|
578
|
+
|
|
579
|
+
Raises:
|
|
580
|
+
TaskOperationError: If applying the update fails.
|
|
581
|
+
"""
|
|
582
|
+
self.uda_service.update_uda(uda)
|
|
583
|
+
|
|
584
|
+
def delete_uda(self, uda: UdaConfig) -> None:
|
|
585
|
+
"""Delete a UDA via the TaskWarrior facade.
|
|
586
|
+
|
|
587
|
+
Delegates to UdaService.delete_uda which removes TaskWarrior config
|
|
588
|
+
keys and the UDA from the local registry.
|
|
589
|
+
|
|
590
|
+
Args:
|
|
591
|
+
uda: The UdaConfig identifying the UDA to remove.
|
|
592
|
+
|
|
593
|
+
Raises:
|
|
594
|
+
TaskOperationError: If deletion fails for reasons other than missing keys.
|
|
595
|
+
"""
|
|
596
|
+
self.uda_service.delete_uda(uda)
|
|
597
|
+
|
|
557
598
|
def get_projects(self) -> list[str]:
|
|
558
599
|
"""Get all projects defined in TaskWarrior.
|
|
559
600
|
|
|
@@ -566,3 +607,22 @@ class TaskWarrior:
|
|
|
566
607
|
['dmc.fil.aretordre', 'dmc.fil.adérouler', 'perso', 'perso.orl', 'pro']
|
|
567
608
|
"""
|
|
568
609
|
return self.adapter.get_projects()
|
|
610
|
+
|
|
611
|
+
def get_tags(self, include_virtual_tags: bool = False) -> list[str]:
|
|
612
|
+
"""Get all tags defined in TaskWarrior.
|
|
613
|
+
|
|
614
|
+
Args:
|
|
615
|
+
include_virtual_tags: If ``True``, include TaskWarrior virtual tags
|
|
616
|
+
such as ``TODAY`` and ``READY``.
|
|
617
|
+
|
|
618
|
+
Returns:
|
|
619
|
+
List of tag names.
|
|
620
|
+
"""
|
|
621
|
+
return self.adapter.get_tags(include_virtual_tags=include_virtual_tags)
|
|
622
|
+
|
|
623
|
+
def get_context_tags(self) -> list[str]:
|
|
624
|
+
"""Return tags that follow the ``@`` context convention.
|
|
625
|
+
|
|
626
|
+
This is a convenience filter for user-defined tags such as ``@work``.
|
|
627
|
+
"""
|
|
628
|
+
return [tag for tag in self.get_tags() if tag.startswith("@")]
|
|
@@ -59,6 +59,16 @@ class UdaService:
|
|
|
59
59
|
|
|
60
60
|
The service executes the required `task config` commands via the adapter
|
|
61
61
|
and only updates the registry if all commands succeed.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
uda: The UdaConfig describing the UDA to create.
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
TaskOperationError: If any underlying TaskWarrior config command fails.
|
|
68
|
+
|
|
69
|
+
Example:
|
|
70
|
+
>>> uda = UdaConfig(name="sev", uda_type=UdaType.STRING, label="Severity")
|
|
71
|
+
>>> service.define_uda(uda)
|
|
62
72
|
"""
|
|
63
73
|
# Build commands to define the UDA
|
|
64
74
|
field_names = uda.__class__.model_fields.keys() - {"name"}
|
|
@@ -86,6 +96,12 @@ class UdaService:
|
|
|
86
96
|
"""Update an existing UDA in TaskWarrior and in the registry.
|
|
87
97
|
|
|
88
98
|
Executes commands via adapter and updates the registry on success.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
uda: The UdaConfig with updated settings to apply.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
TaskOperationError: If applying the updated configuration fails.
|
|
89
105
|
"""
|
|
90
106
|
# For now, same as define_uda
|
|
91
107
|
self.define_uda(uda)
|
|
@@ -94,9 +110,26 @@ class UdaService:
|
|
|
94
110
|
"""Delete a UDA from TaskWarrior and remove it from the registry.
|
|
95
111
|
|
|
96
112
|
Executes `task config <key>` without a value to remove each UDA key.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
uda: The UdaConfig identifying the UDA to remove.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
TaskOperationError: If an unexpected TaskWarrior error occurs while
|
|
119
|
+
attempting to remove configuration keys (missing keys are tolerated).
|
|
97
120
|
"""
|
|
98
|
-
|
|
99
|
-
|
|
121
|
+
# Mirror define_uda: skip 'name' and map internal 'uda_type' -> TaskWarrior 'type'
|
|
122
|
+
field_names = set(uda.__class__.model_fields.keys()) - {"name"}
|
|
123
|
+
keys_to_delete: list[str] = []
|
|
124
|
+
|
|
125
|
+
if "uda_type" in field_names:
|
|
126
|
+
keys_to_delete.append("type")
|
|
127
|
+
field_names.remove("uda_type")
|
|
128
|
+
|
|
129
|
+
# delete remaining fields deterministically
|
|
130
|
+
keys_to_delete.extend(sorted(field_names))
|
|
131
|
+
|
|
132
|
+
for key in keys_to_delete:
|
|
100
133
|
cmd = ["config", f"uda.{uda.name}.{key}"]
|
|
101
134
|
result = self.adapter.run_task_command(cmd)
|
|
102
135
|
if getattr(result, "returncode", 0) != 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
|
|
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
|