Skip to content

Commit 454c2eb

Browse files
committed
Changed and completed some features
1 parent 9b3db59 commit 454c2eb

2 files changed

Lines changed: 147 additions & 53 deletions

File tree

main.py

Lines changed: 139 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,64 @@
22

33
import json
44
import sys
5+
from typing import Dict
6+
7+
# fix bugs
58

69

710
def main():
8-
args = extract_args()
11+
args, do = extract_args()
12+
print(args) # debug
913

1014
# perform the task
11-
do_task(args)
15+
execute_command(args, do)
1216

1317

14-
def extract_args():
18+
def extract_args(): # Needs refactoring
1519
raw_args = sys.argv[1:]
16-
args = {}
20+
args: Dict = {}
1721
# Create a parser
1822
if raw_args[0] == "-h":
1923
print("""CLI task tracker""") # Add the help message
24+
2025
elif raw_args[0] == "add":
2126
args["command"] = "add"
2227
if "-h" not in raw_args[1:] or "--help" not in raw_args[1:]:
2328
if len(raw_args) != 2:
2429
report_error(f"Wrong number of arguments is provided {len(raw_args) - 1}."
2530
+ " Provide only 1 argument.", "Argument")
31+
return args, False
2632
else:
2733
task = raw_args[1]
2834
args["args"] = [task]
2935
else:
3036
if len(raw_args) != 2:
3137
report_error(f"Arbitrary arguments are provided with help option.", "Argument")
38+
return args, False
3239
else:
3340
print("Add a new task\n" + "Usage: add task\n "
3441
+ "Note if there is a space in the input task wrap it in a quotes")
42+
3543
elif raw_args[0] == "delete":
3644
args["command"] = "delete"
3745
if "-h" not in raw_args[1:] or "--help" not in raw_args[1:]:
3846
if len(raw_args) != 2:
3947
report_error(f"Wrong number of arguments is provided {len(raw_args) - 1}."
4048
+ " Provide only 1 argument.", "Argument")
49+
return args, False
4150
else:
4251
task_id_to_delete = raw_args[1]
4352
try:
4453
task_id_to_delete = int(task_id_to_delete)
4554
except ValueError:
4655
report_error("ID must be an integer", "Type")
56+
return args, False
4757
else:
4858
args["args"] = [task_id_to_delete]
4959
else:
5060
if len(raw_args) != 2:
5161
report_error(f"Arbitrary arguments are provided with help option.", "Argument")
62+
return args, False
5263
else:
5364
print("Delete an existing task by its ID\n" + "Usage: delete ID")
5465

@@ -58,13 +69,15 @@ def extract_args():
5869
if len(raw_args) != 3:
5970
report_error(f"Wrong number of arguments is provided {len(raw_args) - 1}."
6071
+ " Provide only 2 arguments.", "Argument")
72+
return args, False
6173
else:
6274
args["args"] = []
6375
task_id = raw_args[1]
6476
try:
6577
task_id = int(task_id)
6678
except ValueError:
6779
report_error("ID must be an integer", "Type")
80+
return args, False
6881
else:
6982
args["args"].append(task_id)
7083

@@ -73,67 +86,124 @@ def extract_args():
7386
else:
7487
if len(raw_args) != 2:
7588
report_error(f"Arbitrary arguments are provided with help option.", "Argument")
89+
return args, False
7690
else:
7791
print("Update an existing task by its id. The new task will replace the old one.\n"
7892
+ "Usage: update ID new-task")
93+
7994
elif raw_args[0] == "list":
80-
if len(raw_args) == 1:
81-
args["command"] = "list"
82-
elif len(raw_args) == 2:
83-
args["args"] = [raw_args[1]]
95+
args["command"] = "list"
96+
if "-h" not in raw_args[1:] or "--help" not in raw_args[1:]:
97+
if len(raw_args) == 1:
98+
args["args"] = ["all"] # default "all"
99+
elif len(raw_args) == 2:
100+
choices = ["all", "in-progress", "done", "todo"] # "to-do" == "undone"
101+
if raw_args[1] not in choices:
102+
report_error("Invalid status choose from: [all, in-progress, done, todo]",
103+
"InvalidChoice")
104+
return args, False
105+
else:
106+
args["args"] = [raw_args[1]] # Optional
107+
else:
108+
report_error(f"Wrong number of arguments is provided.", "Argument")
109+
return args, False
84110
else:
85-
pass # error
111+
if len(raw_args) != 2:
112+
report_error(f"Arbitrary arguments are provided with help option.", "Argument")
113+
return args, False
114+
else:
115+
print("List the tasks by the given status. If no status provided all tasks will be listed\n"
116+
+ "Usage: list [status]\n" + "Available status choices: in-progress, done, todo, all")
117+
86118
elif raw_args[0] == "mark":
87-
pass
88-
else:
89-
report_error("No such argument.\n" + "Choose from: [add, delete, update, list, or mark]", "Argument")
119+
args["command"] = "mark"
120+
if "-h" not in raw_args[1:] or "--help" not in raw_args[1:]:
121+
if len(raw_args) == 2:
122+
# ID argument
123+
task_id_to_mark = raw_args[1]
124+
try:
125+
task_id_to_mark = int(task_id_to_mark)
126+
except ValueError:
127+
report_error("ID must be an integer", "Type")
128+
return args, False
129+
else:
130+
args["args"] = [task_id_to_mark]
90131

91-
"""list_parser = subparsers.add_parser("list", help="Delete an existing task by its id", usage=SUPPRESS)
92-
list_parser.add_argument("options", type=str, choices=["in-progress", "done", "undone", "all"],
93-
help="Options: in-progress, done, undone, all", nargs="?" # to make it optional, or add -
94-
)
132+
# Status argument
133+
args["args"].append("done") # Optional, default "done"
95134

96-
mark_parser = subparsers.add_parser("mark", usage=SUPPRESS,
97-
help="Mark an existing item by its id as either in-progress or done")
98-
mark_parser.add_argument("task_id", type=int, help='task_id to be marked')
99-
mark_parser.add_argument("as", type=str, choices=["in-progress", "done"],
100-
help="Options: done, in-progress", nargs="?")
135+
elif len(raw_args) == 3:
136+
args["command"] = "mark"
101137

102-
# Parse arguments
103-
args = parser.parse_args()"""
138+
# ID argument
139+
task_id_to_mark = raw_args[1]
140+
try:
141+
task_id_to_mark = int(task_id_to_mark)
142+
except ValueError:
143+
report_error("ID must be an integer", "Type")
144+
return args, False
145+
else:
146+
args["args"] = [task_id_to_mark]
147+
148+
# Status argument
149+
choices = ["in-progress", "done", "todo"]
150+
# the last one to return the task to the basic state if it was marked by mistake
151+
if raw_args[2] not in choices:
152+
report_error("Invalid status choose from: [in-progress, done, todo]",
153+
"InvalidChoice")
154+
return args, False
155+
else:
156+
args["args"].append(raw_args[2]) # Optional
157+
else:
158+
report_error(f"Wrong number of arguments is provided.", "Argument")
159+
return args, False
160+
else:
161+
if len(raw_args) != 2:
162+
report_error(f"Arbitrary arguments are provided with help option.", "Argument")
163+
return args, False
164+
else:
165+
print("Mark the tasks as in-progress, done, or todo." +
166+
" If no choice provided the task will be marked as done\n"
167+
+ "Usage: mark [as]\n" + "Available choices: in-progress, done, or todo")
168+
else:
169+
report_error("No such argument.\n" + "Choose from: [add, delete, update, list, or mark]", "Argument")
104170

105-
return args
171+
return args, True
106172

107173

108-
def do_task(args):
174+
def execute_command(args, do):
109175
data = get_data()
110176
task_id = get_id(data)
111177
if args["command"] == "add":
112-
add_task(args["args"][0], task_id, data)
113-
elif args["command"] == "delete": # then (6) test delete when it is as done
114-
delete_task(args["args"][0], data)
115-
elif args["command"] == "update": # then (3) add this
116-
update_task(args["args"][0], args["args"][1], data)
178+
if do:
179+
add_task(args["args"][0], task_id, data)
180+
elif args["command"] == "delete":
181+
if do:
182+
delete_task(args["args"][0], data)
183+
elif args["command"] == "update":
184+
if do:
185+
update_task(args["args"][0], args["args"][1], data)
117186
elif args["command"] == "list":
118-
list_tasks(data)
119-
elif args["command"] == "mark": # then (5) add this -as done-, then (7) add - as in progress-
120-
item = data.pop(args.task_id)
121-
print(f"{item} is marked as... successfully")
187+
if do:
188+
list_tasks(data, args["args"][0])
189+
elif args["command"] == "mark":
190+
if do:
191+
mark_task(data, args["args"][0], args["args"][1])
122192
else:
123193
pass
194+
# No need to do anything, because extract_args reports error and ignore the invalid command
124195

125196
# then (8) add the rest of the features from roadmap like adding time ...
126197

127198

128-
def get_data(): # and test this
199+
def get_data():
129200
try:
130201
with open("tasks.json", "r") as file:
131202
data = json.load(file)
132203
return data
133204
except (FileNotFoundError, json.JSONDecodeError):
134-
with open("tasks.json", "w") as file:
135-
json.dump({}, file, indent=4)
136-
return {}
205+
write_to_json("tasks.json", {})
206+
return {}
137207

138208

139209
def get_id(data):
@@ -144,10 +214,14 @@ def get_id(data):
144214
return len(data) + 1 # If no missing values
145215

146216

147-
def add_task(item, task_id, data):
148-
data[f"t{task_id}"] = {"id": task_id, "task": item}
149-
with open("tasks.json", "w") as file:
217+
def write_to_json(file_name, data):
218+
with open(file_name, "w") as file:
150219
json.dump(data, file, indent=4)
220+
221+
222+
def add_task(item, task_id, data):
223+
data[f"t{task_id}"] = {"id": task_id, "task": item, "status": "todo"}
224+
write_to_json("tasks.json", data)
151225
print(f"Successfully added {item} (ID: {task_id})")
152226

153227

@@ -157,8 +231,7 @@ def delete_task(task_id, data):
157231
except KeyError:
158232
report_error(f"No task is associated with the ID {task_id}.", "ID") # error
159233
else:
160-
with open("tasks.json", "w") as file:
161-
json.dump(data, file, indent=4)
234+
write_to_json("tasks.json", data)
162235
print(f"Successfully deleted {item['task']}")
163236

164237

@@ -169,19 +242,37 @@ def update_task(task_id, new_task, data):
169242
except KeyError:
170243
report_error(f"No task is associated with the ID {task_id}.", "ID")
171244
else:
172-
with open("tasks.json", "w") as file:
173-
json.dump(data, file, indent=4)
245+
write_to_json("tasks.json", data)
174246
print(f"Successfully updated '{old}' to '{data[f't{task_id}']['task']}'!")
175247

176248

177249
def sort_dict_data(task_dict):
178250
return int(task_dict[0][1:])
179251

180252

181-
def list_tasks(data):
253+
def list_tasks(data, status):
182254
# noinspection PyTypeChecker
183-
for _, task_dict in sorted(data.items(), key=sort_dict_data):
184-
print(f"{task_dict["id"]}. {task_dict["task"]}")
255+
sorted_data = sorted(data.items(), key=sort_dict_data)
256+
if status == "all":
257+
for _, task_dict in sorted_data:
258+
print(f"{task_dict["id"]}. {task_dict["task"]} - {task_dict["status"]}")
259+
else:
260+
tasks = []
261+
for _, task_dict in sorted_data:
262+
if task_dict["status"] == status:
263+
tasks.append(task_dict)
264+
265+
if tasks:
266+
for task in tasks:
267+
print(f"{task["id"]}. {task["task"]}")
268+
else:
269+
print(f"No tasks marked as {status} to be listed.")
270+
271+
272+
def mark_task(data, task_id, new_status):
273+
data[f"t{task_id}"]["status"] = new_status
274+
write_to_json("tasks.json", data)
275+
print(f"Successfully marked {data[f"t{task_id}"]["task"]} as {new_status}!")
185276

186277

187278
def report_error(message, error_type=None):

main.pyi

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
from typing import Tuple, Dict, Any
1+
from typing import Tuple, Dict, Any, Literal
2+
23

34
def main() -> None: ...
4-
def make_parsers() -> Tuple[Namespace, ArgParser] : ...
5-
def do_task(args: Namespace) -> None: ...
5+
def extract_args() -> Tuple[Dict, bool]: ...
6+
def execute_command(args: Dict) -> None: ...
67
def get_data() -> Dict: ...
78
def get_id(data: Dict) -> int: ...
9+
def write_to_json(file_name: str, data: Dict) -> None: ...
810
def add_task(item: str, task_id: int, data: Dict) -> None: ...
911
def delete_task(task_id: int, data: Dict) -> None: ...
1012
def sort_dict_data(task_dict: Tuple[str, Dict[str, Any]]) -> None: ...
11-
def list_tasks(data: Dict) -> None: ...
12-
def report_error(message: str, error_type: str = None) -> None: ...
13+
def list_tasks(data: Dict, status: Literal["all", "in-progress", "done", "todo"]) -> None: ...
14+
def mark_task(data: Dict, task_id: int, new_status: Literal["in-progress", "done", "todo"]) -> None: ...
15+
def report_error(message: str, error_type: str | None = None) -> None: ...

0 commit comments

Comments
 (0)