Skip to content
Open
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""add_task.py updated"""
"""complete_task.py updated"""
"""view_tasks.py updated"""
11/18/2025

"""added export_data.py and what changed"""
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""
#During Sprint 2, the add_task file was expanded to include an optional validated due_date, and every new task is created with a completion_date.
#This fixed the fact that Sprint 1 had an inconsistent JSON structure for add_tasks. view_tasks.py was improved to sort tasks by priority, show or hide completed tasks with a --show-completed flag, and display the new due-date and completion-date fields. complete_task.py was updated so finishing a task now records a timestamp and supports
# undoing completion. export_tasks.py was added, providing CSV/TXT export and filters for completed or pending tasks.
96 changes: 33 additions & 63 deletions add_task.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,35 @@
import json
import os

DATA_FILE = "data.json"

def load_data():
"""Load task data from data.json or create default structure."""
if os.path.exists(DATA_FILE):
with open(DATA_FILE, "r") as f:
return json.load(f)
return {
"tasks": [],
"settings": {
"app_name": "Task Manager",
"version": "1.0.0",
"max_tasks": 100
}
}

def save_data(data):
"""Save task data back to data.json."""
with open(DATA_FILE, "w") as f:
json.dump(data, f, indent=4)

def get_next_id(tasks):
"""Return the next task ID."""
if not tasks:
return 1
highest = 0
for t in tasks:
if int(t.get("id", 0)) > highest:
highest = int(t["id"])
return highest + 1

def add_task(description, priority):
"""Add a new task with description and priority."""
data = load_data()
tasks = data["tasks"]

max_tasks = data.get("settings", {}).get("max_tasks", 100)
if len(tasks) >= max_tasks:
print("You have reached the maximum number of tasks.")
return

new_task = {
"id": get_next_id(tasks),
"description": description,
"priority": priority,
"completed": False
}

tasks.append(new_task)
save_data(data)
print(" Task added:", description, "(Priority:", priority + ")")

if __name__ == "__main__":
print("Enter task description:")
desc = input().strip()
print("Enter priority (high, medium, low):")
prio = input().strip().lower()
if prio not in ["high", "medium", "low"]:
print("Priority must be: high, medium, or low.")
else:
add_task(desc, prio)
import re
DATA_FILE="data.json"

def is_valid_date(d):
"""Validate YYYY--MM--DD format"""
return re.match(r"^\d{4}-\d{2}-\d{2}$",d) is not None

def add_task():
description=input("Enter task description: ").strip()
priority=input("Enter priority (high/medium/low): ").strip().lower()
due_date=input("Enter due date (YYYY-MM-DD) or press Enter to skip: ")
if due_date=="":
due_date=None
elif not is_valid_date(due_date):
print("Invalid date format. Must be YYYY-MM-DD.")
return
with open(DATA_FILE,"r") as f:
data=json.load(f)
task_id=len(data["tasks"])+1
new_task={
"id":task_id,
"description":description,
"priority": priority,
"completed": False,
"due_date":due_date,
"completion_date":None
}
data["tasks"].append(new_task)
with open(DATA_FILE,"w") as f:
json.dump(data,f,indent=4)
print(f"Task #{task_id} added successfully!")
if __name__=="__main__":
add_task()

61 changes: 30 additions & 31 deletions complete_task.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,37 @@
import json
from datetime import datetime

DATA_FILE="data.json"
def load_tasks():
if not os.path.exists(DATA_FILE):
print("Error: data.json file not found.")
return {"tasks":[]}

def complete_task():
task_id=input("Enter task ID to complete: ").strip()
if not task_id.isdigit():
print("Invalid ID format.")
return
task_id=int(task_id)
with open(DATA_FILE,"r") as f:
data=json.load(f)
return data
def save_tasks(data):
with open(DATA_FILE,"w") as f:
json.dump(data,f,indent=4)

def complete_task(task_id):
data=load_tasks()
tasks=data["tasks"]
found=False
for task in tasks:
if task["id"]==task_id:
found=True
if task["completed"]:
print("Task",task_id,"is already completed.")
else:
task["completed"]=True
save_tasks(data)
print("Task",task_id,"marked as completed.")
found=None
for t in data["tasks"]:
if t["id"] == task_id:
found=t
break
if not found:
print("Task with ID",task_id,"not found.")
if __name__=="__main__":
import os
print("Enter the task to complete:")
task_id_input=input().strip()
if task_id_input.isdigit():
task_id=int(task_id_input)
complete_task(task_id)
print("Task not found.")
return
if found["completed"]:
undo=input("Task is already completed. Undo completion? (yes/no): ")
if undo=="yes":
found["completed"]=False
found["completion_date"]=None
print("Completion undone.")
else:
print("No changes made.")
else:
print("Please enter a valid task ID number.")
found["completed"]=True
found["completion_date"]=datetime.now().strftime("%Y-%m-%d")
print("Task marked completed!")
with open(DATA_FILE,"w") as f:
json.dump(data,f,indent=4)
if __name__=="__main__":
complete_task()
17 changes: 11 additions & 6 deletions data.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"tasks":[],
"settings":{
"app_name":"Task Manager",
"version":"1.0.0",
"max_tasks":100
}
"tasks": [
{
"id": 1,
"description": "Do something",
"priority": "high",
"completed": false,
"due_date": null,
"completion_date": null
}
]
}

1 change: 1 addition & 0 deletions delete_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions deleted.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[2025-11-19 05:17:13] Deleted Task ID=1 | "Finish homework"
87 changes: 87 additions & 0 deletions export_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import json
import os
import sys
from datetime import datetime

DATA_FILE = "data.json"

PRIORITY_ORDER = {
"high": 1,
"medium": 2,
"low": 3
}


def load_data():
"""Load tasks from JSON file."""
if os.path.exists(DATA_FILE):
with open(DATA_FILE, "r") as f:
return json.load(f)
return {"tasks": []}


def export_to_csv(tasks, filename="tasks_export.csv"):
"""Write tasks to a CSV file."""
with open(filename, "w") as f:
f.write("id,description,priority,completed,due_date,completion_date\n")
for t in tasks:
f.write(f"{t['id']},"
f"\"{t['description']}\","
f"{t['priority']},"
f"{t['completed']},"
f"{t.get('due_date','')},"
f"{t.get('completion_date','')}\n")
print(f"Export complete! File saved as {filename}")


def export_to_txt(tasks, filename="tasks_export.txt"):
"""Write tasks to a TXT file."""
with open(filename, "w") as f:
for t in tasks:
f.write(f"ID: {t['id']}\n")
f.write(f"Description: {t['description']}\n")
f.write(f"Priority: {t['priority']}\n")
f.write(f"Completed: {t['completed']}\n")
f.write(f"Due Date: {t.get('due_date','None')}\n")
f.write(f"Completion Date: {t.get('completion_date','None')}\n")
f.write("-" * 40 + "\n")
print(f"Export complete! File saved as {filename}")


def export_tasks():
args = sys.argv[1:]

data = load_data()
tasks = data.get("tasks", [])

# Filter flags
completed_only = "--completed-only" in args
pending_only = "--pending-only" in args
export_txt = "--txt" in args

if completed_only and pending_only:
print("Error: Cannot use --completed-only and --pending-only together.")
return

if completed_only:
tasks = [t for t in tasks if t.get("completed")]
elif pending_only:
tasks = [t for t in tasks if not t.get("completed")]

# Sort tasks by priority for consistent output
tasks.sort(key=lambda t: PRIORITY_ORDER.get(t["priority"], 99))

if not tasks:
print("No tasks match the selected filters.")
return

# Choose file format
if export_txt:
export_to_txt(tasks)
else:
export_to_csv(tasks)


if __name__ == "__main__":
export_tasks()

2 changes: 2 additions & 0 deletions tasks_export.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,description,priority,completed,due_date,completion_date
1,"Do something",high,False,None,None
58 changes: 28 additions & 30 deletions view_tasks.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
import json
import os
import sys
DATA_FILE="data.json"

DATA_FILE = "data.json"

def load_data():
"""Load tasks from JSON file or return empty list wrapper."""
if os.path.exists(DATA_FILE):
with open(DATA_FILE, "r") as f:
return json.load(f)
return {"tasks": []}
PRIORITY_ORDER={
"high":1,
"medium":2,
"low":3
}

def view_tasks():
"""Display all tasks neatly with ID, status, priority, description."""
data = load_data()
tasks = data.get("tasks", [])

if not tasks:
print("No tasks available.")
return

print("\n Task List")
print("-" * 50)
for task in tasks:
status = " Completed" if task.get("completed") else " Not Completed"
print("ID:", task.get("id"))
print("Description:", task.get("description"))
print("Priority:", task.get("priority"))
print("Status:", status)
print("-" * 50)

if __name__ == "__main__":
view_tasks()

show_completed="--show-completed" in sys.argv
with open(DATA_FILE,"r") as f:
data=json.load(f)
tasks=data["tasks"]
if not show_completed:
tasks=[t for t in tasks if not t["completed"]]
tasks.sort(key=lambda t: PRIORITY_ORDER.get(t["priority"],99))
if not tasks:
print("No tasks to display.")
return
for t in tasks:
status="Completed" if t["completed"] else "Pending"
due=t["due_date"] if t["due_date"] else "None"
print(f"[{t['id']}] {t['description']} ({t['priority']})")
print(f" Due: {due}")
print(f" Status: {status}")
if t["completion_date"]:
print(f" Completed on: {t['completion_date']}")
print()
if __name__=="__main__":
view_tasks()