Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,47 @@ All notable changes to pytaskwarrior will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.2.0] - 2026-03-28

### Added

- **`Context in get_info`** — TaskWarrior.get_info() now includes `current_context` and `current_context_details` (name, read_filter, write_filter, active).

- **`TaskConfigurationError`** — new exception for environment and configuration errors:
binary not found in PATH, taskrc file missing or unreadable.
- **`TaskOperationError`** — new exception for write-operation failures on existing tasks
(delete, purge, done, start, stop, annotate).
- All six exceptions now **exported from the top-level package**:
`TaskWarriorError`, `TaskNotFound`, `TaskValidationError`, `TaskSyncError`,
`TaskConfigurationError`, `TaskOperationError`.
- **`TaskWarrior.synchronize()`** now runs `task sync` via the CLI.
Both local (`sync.local.server_dir`) and remote (`sync.server.origin`) sync backends are
supported through TaskWarrior's built-in sync command.
- `TaskWarrior.is_sync_configured()` returns `True` when any `sync.*` key is present in taskrc.

### Changed

- Exception hierarchy unified: 13 semantic fixes throughout the codebase ensure the right
exception is raised in the right context.
- `TaskValidationError` → `TaskConfigurationError` for binary not found / taskrc errors
- `TaskNotFound` → `TaskOperationError` for operation failures on existing tasks
- `OSError` / `subprocess.SubprocessError` → wrapped in `TaskWarriorError` to preserve exception contract
- All JSON parse errors now use `TaskWarriorError` instead of domain-specific exceptions
- `synchronize()` is **no longer a no-op**: the façade now calls `self.adapter.synchronize()`,
which in turn runs `task sync`. Raises `TaskSyncError` if sync is not configured or fails.
- `get_tasks()` now respects the active context's `read_filter` — when a context is applied,
its `read_filter` is combined with the user-provided filter using AND so listings are scoped
correctly (e.g. `project:work and (priority:H)`).
- Enhanced error coverage: all file I/O, JSON parsing, and subprocess operations now properly
protected with appropriate exception handling.

### Tests

- `uv run pytest -q` (164 passed, 0 failed)
- New `test_adapter_sync.py` validates sync behavior via `task sync` CLI.
- Updated sync tests to reflect new implementation (CLI-based, no external dependencies).
- `test_task_warrior_error_inheritance` extended to verify exception hierarchy.

## [1.1.1] - 2026‑03‑07
### Added
- Automated publishing to PyPI via GitHub Actions (trusted publishing with OIDC).
Expand Down
13 changes: 7 additions & 6 deletions PYPI_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@

A modern Python wrapper for [TaskWarrior](https://taskwarrior.org/), the command-line task management tool.

Production-ready with 132 tests (96% coverage), strict type checking, and professional-grade code quality. Zero linting errors, full async-safe subprocess handling, and PEP 561 type hints for IDE support.
Production-ready with 164 tests (96% coverage), strict type checking, and professional-grade code quality. Zero linting errors, full async-safe subprocess handling, PEP 561 type hints for IDE support, and a consistent exception hierarchy.

## Features

- ✅ Full CRUD operations for tasks
- ✅ Type-safe with Pydantic models
- ✅ Context management
- ✅ UDA (User Defined Attributes) support
- ✅ Recurring tasks and annotations
- Full CRUD operations for tasks
- Type-safe with Pydantic models
- Context management
- UDA (User Defined Attributes) support
- Recurring tasks and annotations
- Consistent exception hierarchy (`TaskNotFound`, `TaskValidationError`, `TaskOperationError`, `TaskConfigurationError`, …)

## Requirements

Expand Down
50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@

A modern Python wrapper for [TaskWarrior](https://taskwarrior.org/) v3.4, the command-line task management tool.

**v1.1.1**: Production-ready with 132 tests (96% coverage), strict type checking, and professional-grade code quality. Zero linting errors, full async-safe subprocess handling, and PEP 561 type hints for IDE support.
**v1.2.0**: Production-ready with 164 tests (96% coverage), strict type checking, and professional-grade code quality. Zero linting errors, full async-safe subprocess handling, PEP 561 type hints for IDE support, and a consistent exception hierarchy.

## Features

- **Full CRUD operations** - Create, read, update, delete tasks
- **Type-safe** - Pydantic models with full type hints
- **Context management** - Define, apply, and switch contexts
- **UDA support** - User Defined Attributes
- **Recurring tasks** - Full recurrence support
- **Annotations** - Add notes to tasks
- **Date calculations** - Use TaskWarrior's date expressions
- **Full CRUD operations** - Create, read, update, delete tasks
- **Type-safe** - Pydantic models with full type hints
- **Context management** - Define, apply, and switch contexts
- **UDA support** - User Defined Attributes
- **Recurring tasks** - Full recurrence support
- **Annotations** - Add notes to tasks
- **Date calculations** - Use TaskWarrior's date expressions

## Requirements

Expand All @@ -31,7 +31,7 @@ A modern Python wrapper for [TaskWarrior](https://taskwarrior.org/) v3.4, the co
## Installation

```bash
pip install pytaskwarrior==1.0.0
pip install pytaskwarrior==1.2.0
```

Or install from source:
Expand Down Expand Up @@ -140,6 +140,37 @@ tw = TaskWarrior(
| `delete_context(name)` | Remove a context |
| `has_context(name)` | Check if context exists |

#### Synchronization Operations

| Method | Description |
|--------|-------------|
| `is_sync_configured()` | Return `True` if any `sync.*` key is present in taskrc. |
| `synchronize()` | Run `task sync`; raises `TaskSyncError` if not configured or sync fails. |

### Exceptions

All exceptions inherit from `TaskWarriorError` and are importable from the top-level package:

```python
from taskwarrior import (
TaskWarriorError, # Base class — catch all library errors
TaskNotFound, # Task does not exist
TaskValidationError, # Invalid input data (empty description, etc.)
TaskOperationError, # Operation failed on an existing task
TaskConfigurationError, # Environment issue (binary not found, taskrc missing)
TaskSyncError, # Synchronization failure
)
```

| Exception | Raised when |
|-----------|-------------|
| `TaskWarriorError` | Base class; catch-all for any library error |
| `TaskNotFound` | The requested task does not exist |
| `TaskValidationError` | Input data is invalid (e.g., empty description) |
| `TaskOperationError` | A write operation failed on an existing task (delete, done, start…) |
| `TaskConfigurationError` | Environment error (binary not in PATH, taskrc missing/unreadable) |
| `TaskSyncError` | Sync backend not configured or synchronization failed |

### Data Models

#### TaskInputDTO
Expand Down Expand Up @@ -340,4 +371,3 @@ Contributions are welcome! Please feel free to submit a Pull Request.
- [TaskWarrior](https://taskwarrior.org/) - The underlying task management tool
- [GitHub Repository](https://github.com/sznicolas/pytaskwarrior/)
- [PyPI Package](https://pypi.org/project/pytaskwarrior/)

123 changes: 70 additions & 53 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,100 @@
# PyTaskWarrior 1.0.0 Release Notes
# PyTaskWarrior 1.2.0 Release Notes

## Overview

**PyTaskWarrior 1.0.0** is the first production-ready release featuring a complete API rewrite with professional-grade code quality.
**PyTaskWarrior 1.2.0** delivers a fully consistent exception hierarchy, new public exception
classes, and better error coverage throughout the library. Synchronization now works out of the box.

### Key Highlights

- **Production-ready**: 132 comprehensive tests (96% coverage), strict type checking (mypy), zero linting errors (ruff)
- **Type-safe API**: Pydantic v2 DTOs with full IDE/type-checker support (PEP 561)
- **Hardened subprocess handling**: 30s timeout, atomic operations, regex-based date validation
- **Clean architecture**: Adapters, services, and domain objects — no singletons, no hidden state
- **Full TaskWarrior feature parity**: Contexts, UDAs, recurring tasks, annotations, date calculations
- **Coherent exceptions**: two new exception classes, all six exceptions now publicly exported
- **No more stdlib exceptions leaking**: `OSError`/`SubprocessError` are now wrapped
- **Sync now works**: `TaskWarrior.synchronize()` runs `task sync` via the CLI
- **164 tests** passing, 0 failures

### Breaking Changes

⚠️ **Python 3.12+** and **TaskWarrior 3.4+** required.
⚠️ Complete API rewrite — see migration guide in [CHANGELOG.md](CHANGELOG.md).
---

### What's New
## What's New in 1.2.0

#### Core Features
- **Type-safe operations** via `TaskInputDTO` / `TaskOutputDTO` (Pydantic v2)
- **Context management** with active context tracking
- **UDA support** with registry and validation
- **Recurring tasks** enum + custom recurrence strings ("2weeks", "10days")
- **Task annotations** with ISO timestamps
- **Date utilities**: arithmetic and validation
### New Exceptions

#### Reliability & Safety
- Subprocess timeout (30s) prevents hangs
- Atomic `add_task()` — parses task ID from stdout (no race conditions)
- Atomic date validation via ISO regex (not exit code)
- Proper exception hierarchy with exception chaining
- Thread-safe `UdaRegistry` (no global state)
Two new exception classes complete the hierarchy:

#### Code Quality
- 132 unit tests (35 mocked, 97 integration)
- 96% code coverage (was 87%)
- `ruff` — zero linting errors (6 rules + SIM117 ignore for tests)
- `mypy` strict mode enabled
- GitHub Actions CI/CD (pytest matrix 3.12–3.13)
| Class | Inherits from | Use case |
|-------|--------------|----------|
| `TaskConfigurationError` | `TaskWarriorError` | Binary not found in PATH, taskrc missing or unreadable |
| `TaskOperationError` | `TaskWarriorError` | Write operation failure on an existing task (delete, done, start, stop, annotate, purge) |

### Migration from 0.3.0
All six exceptions are now importable from the top-level package:

```python
# Use Pydantic DTOs instead of dicts
from taskwarrior import TaskInputDTO, Priority
from taskwarrior import (
TaskWarriorError,
TaskNotFound,
TaskValidationError,
TaskOperationError,
TaskConfigurationError,
TaskSyncError,
)
```

task = TaskInputDTO(description="New task", priority=Priority.HIGH)
tw.add_task(task)
### Exception Semantic Fixes

# TaskOutputDTO replaces dict responses
for task in tw.get_tasks():
print(task.description, task.status)
```
13 fixes throughout the codebase ensure exceptions match their usage context:

| Before | After | Location |
|--------|-------|----------|
| `TaskValidationError` | `TaskConfigurationError` | Binary not found in PATH |
| `TaskValidationError` | `TaskWarriorError` | JSON parse errors on CLI responses |
| `TaskNotFound` | `TaskOperationError` | delete / purge / done / start / stop / annotate failures |
| `TaskNotFound` | `TaskWarriorError` | JSON errors in `get_recurring_instances` |
| `TaskWarriorError` | `TaskNotFound` | `get_task` with non-zero return code |
| `TaskValidationError` | `TaskWarriorError` | `modify_task` generic CLI failure |
| `TaskWarriorError` | `TaskValidationError` | Empty context name in `ContextService` |
| `TaskWarriorError` | `TaskConfigurationError` | Missing taskrc in `UdaRegistry` |
| `RuntimeError` | `TaskWarriorError` | `add_task` fallback path |

### Synchronization Now Works

- `TaskWarrior.synchronize()` calls `task sync` via the CLI (native TaskWarrior command)
- Both local (`sync.local.server_dir`) and remote (`sync.server.origin`) backends supported
- No external dependencies — works with any TaskWarrior 3.4+ installation
- `TaskWarrior.is_sync_configured()` returns `True` when any `sync.*` key exists in taskrc

Full migration guide in [CHANGELOG.md](CHANGELOG.md#migration-guide).
### Error Coverage Improvements

### Installation
- `OSError` / `SubprocessError` in `run_task_command` now wrapped in `TaskWarriorError`
- `get_recurring_task` now protects `json.loads` (was missing guard)
- `ConfigStore._extract_taskrc_config` now raises `TaskConfigurationError` on file I/O errors
- `parse_taskwarrior_date` fallback now raises `ValueError` with descriptive message

### Behavior Fixes

- `get_tasks()` now respects the active context's `read_filter`. When a context is applied,
its `read_filter` is combined with the user-provided filter using AND so task listings are
correctly scoped to the context (e.g. `project:work and (priority:H)`).

---

## Installation

```bash
pip install pytaskwarrior==1.0.0
pip install pytaskwarrior==1.2.0
```

### Documentation
## Links

- **[README.md](README.md)** – Quick start, examples, API reference
- **[CHANGELOG.md](CHANGELOG.md)** – Full release notes, breaking changes, migration guide
- **[GitHub Discussions](https://github.com/sznicolas/pytaskwarrior/discussions)** – Questions & feedback
- **[CHANGELOG.md](CHANGELOG.md)** – Full release history and migration guides
- **[README.md](README.md)** – Quick start, API reference, examples
- **[GitHub Issues](https://github.com/sznicolas/pytaskwarrior/issues)** – Bug reports

### Contributors
## Contributors

- Nicolas Schmeltz ([@sznicolas](https://github.com/sznicolas))
- GitHub Copilot (code review, quality audit, refactoring)
- GitHub Copilot (exception audit, refactoring, test updates)

### Support
---

Report issues: [GitHub Issues](https://github.com/sznicolas/pytaskwarrior/issues)
**v1.2.0** | March 28, 2026

---

**v1.0.0** | February 26, 2026
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pytaskwarrior"
version = "1.1.1"
version = "1.2.0"
description = "Taskwarrior wrapper python module"
readme = "PYPI_README.md"
requires-python = ">=3.12"
Expand Down
14 changes: 14 additions & 0 deletions src/taskwarrior/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
from .dto.task_dto import TaskInputDTO, TaskOutputDTO
from .dto.uda_dto import UdaConfig, UdaType
from .enums import Priority, RecurrencePeriod, TaskStatus
from .exceptions import (
TaskConfigurationError,
TaskNotFound,
TaskOperationError,
TaskSyncError,
TaskValidationError,
TaskWarriorError,
)
from .main import TaskWarrior
from .registry.uda_registry import UdaRegistry
from .utils.dto_converter import task_output_to_input
Expand All @@ -54,9 +62,15 @@
"Priority",
"RecurrencePeriod",
"TaskStatus",
"TaskConfigurationError",
"TaskInputDTO",
"TaskNotFound",
"TaskOperationError",
"TaskOutputDTO",
"TaskSyncError",
"TaskValidationError",
"TaskWarrior",
"TaskWarriorError",
"task_output_to_input",
"UdaConfig",
"UdaRegistry",
Expand Down
Loading
Loading