From be1d6cd0c223a9024f553f1ebe345615568dcb9b Mon Sep 17 00:00:00 2001 From: Neville88 <145358896+Neville88@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:58:23 +0300 Subject: [PATCH 1/2] Improve error handling and add meaningful logging --- app.py | 88 +++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/app.py b/app.py index 4b6ccca..f49f921 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,17 @@ from flask import Flask, render_template, request, redirect, url_for from flask_sqlalchemy import SQLAlchemy +from sqlalchemy.exc import SQLAlchemyError +import logging app = Flask(__name__) +# Configure logging +logging.basicConfig( + filename="app.log", + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" +) + # /// = relative path, //// = absolute path app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False @@ -11,40 +20,81 @@ class Todo(db.Model): id = db.Column(db.Integer, primary_key=True) - title = db.Column(db.String(100)) - complete = db.Column(db.Boolean) + title = db.Column(db.String(100), nullable=False) + complete = db.Column(db.Boolean, default=False) @app.route("/") def home(): - todo_list = Todo.query.all() - return render_template("base.html", todo_list=todo_list) + try: + todo_list = Todo.query.all() + logging.info("Loaded %d todo items", len(todo_list)) + return render_template("base.html", todo_list=todo_list) + except SQLAlchemyError as e: + logging.error("Database error while loading todo list: %s", e) + return "An error occurred while loading tasks.", 500 @app.route("/add", methods=["POST"]) def add(): - title = request.form.get("title") - new_todo = Todo(title=title, complete=False) - db.session.add(new_todo) - db.session.commit() - return redirect(url_for("home")) + title = request.form.get("title", "").strip() + + if not title: + logging.warning("User attempted to add an empty todo title") + return "Todo title cannot be empty.", 400 + + try: + new_todo = Todo(title=title, complete=False) + db.session.add(new_todo) + db.session.commit() + logging.info("Added new todo: '%s'", title) + return redirect(url_for("home")) + except SQLAlchemyError as e: + db.session.rollback() + logging.error("Database error while adding todo '%s': %s", title, e) + return "An error occurred while adding the task.", 500 @app.route("/update/") def update(todo_id): - todo = Todo.query.filter_by(id=todo_id).first() - todo.complete = not todo.complete - db.session.commit() - return redirect(url_for("home")) + try: + todo = Todo.query.filter_by(id=todo_id).first() + + if todo is None: + logging.warning("Update failed: todo with id=%d not found", todo_id) + return "Task not found.", 404 + + todo.complete = not todo.complete + db.session.commit() + logging.info("Updated todo id=%d, complete=%s", todo_id, todo.complete) + return redirect(url_for("home")) + except SQLAlchemyError as e: + db.session.rollback() + logging.error("Database error while updating todo id=%d: %s", todo_id, e) + return "An error occurred while updating the task.", 500 @app.route("/delete/") def delete(todo_id): - todo = Todo.query.filter_by(id=todo_id).first() - db.session.delete(todo) - db.session.commit() - return redirect(url_for("home")) + try: + todo = Todo.query.filter_by(id=todo_id).first() + + if todo is None: + logging.warning("Delete failed: todo with id=%d not found", todo_id) + return "Task not found.", 404 + + db.session.delete(todo) + db.session.commit() + logging.info("Deleted todo id=%d", todo_id) + return redirect(url_for("home")) + except SQLAlchemyError as e: + db.session.rollback() + logging.error("Database error while deleting todo id=%d: %s", todo_id, e) + return "An error occurred while deleting the task.", 500 + if __name__ == "__main__": - db.create_all() - app.run(debug=True) + with app.app_context(): + db.create_all() + logging.info("Database initialized successfully") + app.run(debug=True) \ No newline at end of file From d908615e273989196a25efaa6362162e77c445bf Mon Sep 17 00:00:00 2001 From: Neville88 <145358896+Neville88@users.noreply.github.com> Date: Wed, 11 Mar 2026 12:14:54 +0300 Subject: [PATCH 2/2] Add assignment documentation explaining error handling and logging improvements --- README.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/README.md b/README.md index e2a98cb..9d3e82e 100644 --- a/README.md +++ b/README.md @@ -43,3 +43,116 @@ Run the app ```console $ flask run ``` +--- + +## Assignment: Error Handling and Logging Improvements + +This repository was forked from the original project: +https://github.com/patrickloeber/flask-todo + +The purpose of this fork was to analyze weaknesses in the project's error handling and logging strategy, and implement improvements as part of a software engineering practical assignment. + +### Problems Identified in the Original Code + +The original implementation had several issues related to robustness and debugging: + +1. **No input validation** + - The `/add` route accepted empty todo titles. + +2. **Missing exception handling** + - Database operations (`add`, `update`, `delete`) were executed without `try/except` blocks. + +3. **No rollback mechanism** + - If a database operation failed, the transaction could leave the database in an inconsistent state. + +4. **Unsafe update/delete operations** + - The `update()` and `delete()` routes assumed that a todo item always exists. + - If an invalid ID was used, the application could crash. + +5. **No logging** + - The application did not record important events such as errors, updates, or deletions. + +--- + +### Improvements Implemented + +The following improvements were added to make the application more robust and easier to debug: + +#### 1. Input Validation +The `/add` route now checks that the todo title is not empty before saving it to the database. + +#### 2. Exception Handling +All database operations are wrapped in `try/except` blocks to prevent application crashes. + +#### 3. Transaction Rollback +`db.session.rollback()` is now used whenever a database error occurs to maintain database integrity. + +#### 4. Safe Record Handling +The application now verifies that a todo item exists before performing update or delete operations. + +#### 5. Meaningful Logging +Logging has been added using Python’s `logging` module. The application now records: + +- INFO logs for successful operations +- WARNING logs for suspicious user actions +- ERROR logs for database failures + +Example log messages: + +``` +INFO - Added new todo: 'Finish assignment' +WARNING - Update failed: todo with id=9999 not found +ERROR - Database error while deleting todo +``` + +Logs are written to the file: + +``` +app.log +``` +--- + +### AI-Generated Logging vs Human Reasoning + +AI-generated logging suggestions are often generic, such as: + +``` +logging.error("An error occurred") +``` + +Human reasoning improves logging by adding **context and useful debugging information**, for example: + +``` +logging.error("Database error while deleting todo id=%d: %s", todo_id, e) +``` + +This approach makes it much easier for developers to diagnose issues in production systems. + +--- + +### Outcome + +These improvements increase the **reliability**, **maintainability**, and **debuggability** of the application by introducing proper exception handling and meaningful logging. + + +--- + +### Running the Improved Version + +After installing the required dependencies, the application can be started with: + +```bash +python app.py +``` + +Then open the browser and navigate to: + +``` +http://127.0.0.1:5000 +``` + +The application will now run with improved exception handling and logging enabled. Log entries will be written to: + +``` +app.log +``` \ No newline at end of file