From b25b251a5e56a7c88e10b2d37baea06ba30fbffc Mon Sep 17 00:00:00 2001 From: Golixco Date: Thu, 2 Oct 2025 02:11:24 +0530 Subject: [PATCH 1/2] feat(cli): add simple CLI todo app (add/list/remove) --- intermediate/simple_todo.py | 139 ++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 intermediate/simple_todo.py diff --git a/intermediate/simple_todo.py b/intermediate/simple_todo.py new file mode 100644 index 0000000..e61a2e7 --- /dev/null +++ b/intermediate/simple_todo.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +""" +Simple CLI Todo app for Hacktoberfest contribution. +Stores tasks in a JSON file with features: add, list, done, remove, clear. +""" +import json +import argparse +from pathlib import Path +from datetime import datetime + +DATA_FILE = Path("tasks.json") + + +def load_tasks() -> list: + """ + Load and return the list of tasks from the JSON file. + Returns an empty list if the file does not exist or is invalid. + """ + if not DATA_FILE.exists(): + return [] + try: + return json.loads(DATA_FILE.read_text()) + except json.JSONDecodeError: + # Warn the user and reset tasks if JSON is invalid. + print("Warning: tasks.json is corrupted or not valid JSON. Resetting tasks list.") + return [] + + +def save_tasks(tasks: list) -> None: + """ + Save the list of tasks to the JSON file with pretty formatting. + """ + DATA_FILE.write_text(json.dumps(tasks, indent=2, sort_keys=False)) + + +def add_task(text: str) -> None: + """ + Add a new task with the given text to the list. + """ + tasks = load_tasks() + tasks.append({ + "id": int(datetime.now().timestamp()), + "text": text, + "done": False, + "created": datetime.now().isoformat() + }) + save_tasks(tasks) + print("Added:", text) + + +def list_tasks() -> None: + """ + List all tasks with their status. Uncompleted tasks show [ ] and done tasks show [✓]. + """ + tasks = load_tasks() + if not tasks: + print('No tasks. Add one using: todo.py add "Buy milk"') + return + for i, t in enumerate(tasks, 1): + status = "✓" if t.get("done") else " " + print(f"{i}. [{status}] {t.get('text')} (id:{t.get('id')})") + + +def mark_done(index: int) -> None: + """ + Mark the task at the given 1-based index as done. + """ + tasks = load_tasks() + if index < 1 or index > len(tasks): + print("Invalid task number.") + return + tasks[index - 1]["done"] = True + save_tasks(tasks) + print("Marked done:", tasks[index - 1]["text"]) + + +def remove_task(index: int) -> None: + """ + Remove the task at the given 1-based index. + """ + tasks = load_tasks() + if index < 1 or index > len(tasks): + print("Invalid task number.") + return + removed = tasks.pop(index - 1) + save_tasks(tasks) + print("Removed:", removed["text"]) + + +def clear_tasks() -> None: + """ + Clear all tasks. + """ + save_tasks([]) + print("All tasks cleared.") + + +def parse_args() -> argparse.Namespace: + """ + Parse command-line arguments and return the parsed namespace. + """ + parser = argparse.ArgumentParser(prog="todo.py", description="Simple CLI todo app") + subparsers = parser.add_subparsers(dest="cmd") + + # Add command + sp_add = subparsers.add_parser("add", help="Add a new task") + sp_add.add_argument("text", nargs="+", help="Task text") + # List command + sp_list = subparsers.add_parser("list", help="List all tasks") + # Done command + sp_done = subparsers.add_parser("done", help="Mark a task as done") + sp_done.add_argument("number", type=int, help="Task index to mark as done (from list)") + # Remove command + sp_rm = subparsers.add_parser("remove", help="Remove a task") + sp_rm.add_argument("number", type=int, help="Task index to remove (from list)") + # Clear command + sp_clear = subparsers.add_parser("clear", help="Remove all tasks") + + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if args.cmd == "add": + add_task(" ".join(args.text)) + elif args.cmd == "list" or args.cmd is None: + list_tasks() + elif args.cmd == "done": + mark_done(args.number) + elif args.cmd == "remove": + remove_task(args.number) + elif args.cmd == "clear": + clear_tasks() + else: + print("Unknown command. Use add/list/done/remove/clear") + + +if __name__ == "__main__": + main() From 37b0aa16c8f5ef14088f24b7fe6da7b94a67bd04 Mon Sep 17 00:00:00 2001 From: Golixco Date: Fri, 3 Oct 2025 18:02:02 +0530 Subject: [PATCH 2/2] feat: add NumPy array operations tutorial --- advanced/numpy_tutorial.py | 87 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 advanced/numpy_tutorial.py diff --git a/advanced/numpy_tutorial.py b/advanced/numpy_tutorial.py new file mode 100644 index 0000000..51eacdb --- /dev/null +++ b/advanced/numpy_tutorial.py @@ -0,0 +1,87 @@ +import numpy as np + +# create one-dimensional array with five elements +a = np.array([1, 2, 3, 4, 5]) +print("Array a:", a) + +# create 2D array (matrix) of shape 3x3 +b = np.array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) +print("Matrix b:\n", b) + +# array attributes +print("Shape of b:", b.shape) +print("Number of dimensions of b:", b.ndim) +print("Data type of b elements:", b.dtype) +# convert to float type +b = b.astype(float) +print("Converted matrix b to float, new dtype:", b.dtype) + +# indexing and slicing +print("b[0, 0]:", b[0, 0]) +print("First row of b:", b[0, :]) +print("Second column of b:", b[:, 1]) +# slicing with step +print("Elements of a with step 2:", a[::2]) + +# basic array operations +sum_array = a + np.array([5, 5, 5, 5, 5]) # adding two arrays +print("a + [5,5,5,5,5]:", sum_array) + +scaled = a * 2 # element-wise multiplication by scalar +print("a * 2:", scaled) + +# matrix multiplication (dot product) +c = np.dot(b, b) +print("Dot product b * b:\n", c) + +# sum of elements +print("Sum of elements in a:", a.sum()) +print("Sum of each column in b:", b.sum(axis=0)) +# example of an invalid axis in sum (to show an error) +try: + print("Sum with invalid axis 2:", b.sum(axis=2)) +except Exception as e: + print("Error summing along axis 2 (invalid):", e) + +# use of universal functions (ufuncs) +d = np.array([0, np.pi/2, np.pi]) +print("Angles d:", d) +print("sin(d):", np.sin(d)) +print("log of d (with -inf for zero):", np.log(d)) + +# broadcasting example +e = np.arange(1, 4) +f = np.array([[1], [2], [3]]) +print("e:", e) +print("f:", f) +print("Broadcasted sum e+f:\n", e + f) + +# reshape example +g = np.arange(8) +g = g.reshape((2,4)) +print("Reshaped g to 2x4:\n", g) + +# simple statistics +print("Mean of a:", a.mean()) +print("Standard deviation of g:", g.std()) + +# find unique elements +h = np.array([1, 2, 2, 3, 3, 3]) +print("Unique elements in h:", np.unique(h)) + +# sort elements of an array in descending order +print("Sorted a in descending:", np.sort(a)[::-1]) + +# random array example +np.random.seed(0) +rand_arr = np.random.rand(3, 3) +print("Random array:", rand_arr) + +# element-wise comparison +print("Elements of rand_arr > 0.5:\n", rand_arr > 0.5) + +# creating arrays using linspace +lin = np.linspace(0, 1, 5) +print("Linearly spaced array:", lin)