diff --git a/commands/add.py b/commands/add.py index 1b1a943..a8716d0 100644 --- a/commands/add.py +++ b/commands/add.py @@ -1,22 +1,7 @@ """Add task command.""" import json -from pathlib import Path - - -def get_tasks_file(): - """Get path to tasks file.""" - return Path.home() / ".local" / "share" / "task-cli" / "tasks.json" - - -def validate_description(description): - """Validate task description.""" - # NOTE: Validation logic scattered here - should be in utils (refactor bounty) - if not description: - raise ValueError("Description cannot be empty") - if len(description) > 200: - raise ValueError("Description too long (max 200 chars)") - return description.strip() +from utils import get_tasks_file, validate_description def add_task(description): diff --git a/commands/done.py b/commands/done.py index c9dfd42..3e76370 100644 --- a/commands/done.py +++ b/commands/done.py @@ -1,20 +1,7 @@ """Mark task done command.""" import json -from pathlib import Path - - -def get_tasks_file(): - """Get path to tasks file.""" - return Path.home() / ".local" / "share" / "task-cli" / "tasks.json" - - -def validate_task_id(tasks, task_id): - """Validate task ID exists.""" - # NOTE: Validation logic scattered here - should be in utils (refactor bounty) - if task_id < 1 or task_id > len(tasks): - raise ValueError(f"Invalid task ID: {task_id}") - return task_id +from utils import get_tasks_file, validate_task_id def mark_done(task_id): diff --git a/commands/list.py b/commands/list.py index 714315d..03dd938 100644 --- a/commands/list.py +++ b/commands/list.py @@ -1,21 +1,7 @@ """List tasks command.""" import json -from pathlib import Path - - -def get_tasks_file(): - """Get path to tasks file.""" - return Path.home() / ".local" / "share" / "task-cli" / "tasks.json" - - -def validate_task_file(): - """Validate tasks file exists.""" - # NOTE: Validation logic scattered here - should be in utils (refactor bounty) - tasks_file = get_tasks_file() - if not tasks_file.exists(): - return [] - return tasks_file +from utils import get_tasks_file, validate_task_file def list_tasks(): diff --git a/task.py b/task.py index 53cc8ed..1437674 100644 --- a/task.py +++ b/task.py @@ -10,10 +10,39 @@ from commands.done import mark_done +DEFAULT_CONFIG = """# Default configuration for task CLI +# Auto-generated on first run + +# Task storage settings +storage: + format: json + max_tasks: 1000 + +# Display settings +display: + color: true + unicode: true +""" + + +def ensure_config_exists(): + """Ensure config file exists, create default if missing.""" + config_dir = Path.home() / ".config" / "task-cli" + config_path = config_dir / "config.yaml" + + if not config_path.exists(): + # Create config directory if it doesn't exist + config_dir.mkdir(parents=True, exist_ok=True) + # Create default config file + config_path.write_text(DEFAULT_CONFIG) + print(f"Created default config at {config_path}") + + return config_path + + def load_config(): """Load configuration from file.""" - config_path = Path.home() / ".config" / "task-cli" / "config.yaml" - # NOTE: This will crash if config doesn't exist - known bug for bounty testing + config_path = ensure_config_exists() with open(config_path) as f: return f.read() diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..524cb1f --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,15 @@ +"""Utility modules for task-cli.""" + +from .validation import ( + validate_description, + validate_task_file, + validate_task_id, +) +from .paths import get_tasks_file + +__all__ = [ + "validate_description", + "validate_task_file", + "validate_task_id", + "get_tasks_file", +] diff --git a/utils/paths.py b/utils/paths.py new file mode 100644 index 0000000..7bd71a3 --- /dev/null +++ b/utils/paths.py @@ -0,0 +1,12 @@ +"""Path utilities for task-cli.""" + +from pathlib import Path + + +def get_tasks_file(): + """Get path to tasks file. + + Returns: + Path to the tasks.json file in user's local data directory. + """ + return Path.home() / ".local" / "share" / "task-cli" / "tasks.json" diff --git a/utils/validation.py b/utils/validation.py new file mode 100644 index 0000000..30c080c --- /dev/null +++ b/utils/validation.py @@ -0,0 +1,52 @@ +"""Validation utilities for task-cli.""" + +from .paths import get_tasks_file + + +def validate_description(description): + """Validate task description. + + Args: + description: The task description to validate. + + Returns: + Stripped description if valid. + + Raises: + ValueError: If description is empty or too long. + """ + if not description: + raise ValueError("Description cannot be empty") + if len(description) > 200: + raise ValueError("Description too long (max 200 chars)") + return description.strip() + + +def validate_task_file(): + """Validate tasks file exists. + + Returns: + Path to tasks file if exists, empty list otherwise. + """ + tasks_file = get_tasks_file() + if not tasks_file.exists(): + return [] + return tasks_file + + +def validate_task_id(tasks, task_id): + """Validate task ID exists. + + Args: + tasks: List of tasks. + task_id: Task ID to validate. + + Returns: + Task ID if valid. + + Raises: + ValueError: If task ID is invalid. + """ + if task_id < 1 or task_id > len(tasks): + raise ValueError(f"Invalid task ID: {task_id}") + return task_id