gitlab-ce/doc/user/gitlab_duo/tutorials/python_code_files.md

9.3 KiB

stage group description info title
none Tutorials Tutorial on how to fix errors in a shop application in Python with GitLab Duo. To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments GitLab Duo fix errors tutorial Python code files

Tutorial: Use GitLab Duo to fix errors in a Python shop application

For the Tutorial on using GitLab Duo to fix errors in a Python shop application, your Python web application is made up of the following files.

{{< tabs >}}

{{< tab title="app/models/article.py" >}}

class Article:
    """Article class for a bookstore inventory system."""

    def __init__(self, name, price, quantity, article_id=None):
        """
        Initialize an article.

        Args:
            name (str): The name/title of the book
            price (float): The price of the book
            quantity (int): The quantity in stock
            article_id (int, optional): The unique identifier for the article
        """
        self.id = article_id
        self.name = name  # Missing validation
        self.price = float(price)  # Missing proper validation
        self.quantity = int(quantity)  # Missing proper validation

    def to_dict(self):
        """
        Convert the article to a dictionary.

        Returns:
            dict: Dictionary representation of the article
        """
        return {
            "id": self.id,
            "name": self.name,
            "price": self.price,
            "quantity": self.quantity
        }

    @classmethod
    def from_dict(cls, data):
        """
        Create an article from a dictionary.

        Args:
            data (dict): Dictionary with article data

        Returns:
            Article: New article instance
        """
        article_id = data.get("id")
        # Missing data validation before creating object
        return cls(
            name=data["name"],
            price=data["price"],
            quantity=data["quantity"],
            article_id=article_id
        )

{{< /tab >}}

{{< tab title="app/database.py" >}}

import sqlite3
import os
from app.models.article import Article

# Hard coded database path instead of using environment variables
DATABASE_PATH = 'bookstore.db'

def get_db_connection():
    """
    Get a database connection.

    Returns:
        sqlite3.Connection: Database connection object
    """
    # Missing error handling
    # Missing connection management
    conn = sqlite3.connect(DATABASE_PATH)
    conn.row_factory = sqlite3.Row
    return conn

def initialize_database():
    """
    Initialize the database by creating the articles table if it doesn't exist.
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    # Create articles table
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS articles (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            price REAL NOT NULL,
            quantity INTEGER NOT NULL
        )
    ''')

    conn.commit()
    conn.close()

def add_article(article):
    """
    Add a new article to the database.

    Args:
        article (Article): Article object to add

    Returns:
        int: ID of the newly added article
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute(
        "INSERT INTO articles (name, price, quantity) VALUES (?, ?, ?)",
        (article.name, article.price, article.quantity)
    )

    # Get the ID of the newly inserted article
    article_id = cursor.lastrowid
    conn.commit()
    conn.close()
    return article_id

def get_article_by_id(article_id):
    """
    Get an article by its ID.

    Args:
        article_id (int): ID of the article to retrieve

    Returns:
        Article: Article object if found, None otherwise
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute("SELECT * FROM articles WHERE id = ?", (article_id,))
    row = cursor.fetchone()
    conn.close()

    if row:
        return Article(
            name=row['name'],
            price=row['price'],
            quantity=row['quantity'],
            article_id=row['id']
        )
    return None

def get_all_articles():
    """
    Get all articles from the database.

    Returns:
        list: List of Article objects
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute("SELECT * FROM articles")
    rows = cursor.fetchall()
    conn.close()

    articles = []
    for row in rows:
        article = Article(
            name=row['name'],
            price=row['price'],
            quantity=row['quantity'],
            article_id=row['id']
        )
        articles.append(article)

    return articles

def update_article(article):
    """
    Update an existing article in the database.

    Args:
        article (Article): Article object with updated values
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute(
        "UPDATE articles SET name = ?, price = ?, quantity = ? WHERE id = ?",
        (article.name, article.price, article.quantity, article.id)
    )

    conn.commit()
    conn.close()
    # Missing return value and error checking

def delete_article(article_id):
    """
    Delete an article from the database.

    Args:
        article_id (int): ID of the article to delete
    """
    conn = get_db_connection()
    cursor = conn.cursor()

    cursor.execute("DELETE FROM articles WHERE id = ?", (article_id,))

    conn.commit()
    conn.close()
    # Missing return value and error checking

{{< /tab >}}

{{< tab title="app/routes/shop.py" >}}

from flask import Blueprint, request, jsonify
from app.models.article import Article
from app import database

# Create a blueprint for the shop routes
shop_bp = Blueprint('shop', __name__, url_prefix='/books')

@shop_bp.route('', methods=['GET'])
def get_all_books():
    """Get all books from the inventory."""
    books = database.get_all_articles()
    return jsonify([book.to_dict() for book in books])  # Missing error handling

@shop_bp.route('/<int:book_id>', methods=['GET'])
def get_book(book_id):
    """Get a specific book by ID."""
    book = database.get_article_by_id(book_id)
    if book:
        return jsonify(book.to_dict())
    return jsonify({"message": "Book not found"}), 404  # Incorrect error format

@shop_bp.route('', methods=['POST'])
def add_book():
    """Add a new book to the inventory."""
    data = request.get_json()

    # Missing input validation
    # Directly using input without validation
    new_book = Article(
        name=data['name'],
        price=data['price'],
        quantity=data['quantity']
    )

    book_id = database.add_article(new_book)
    created_book = database.get_article_by_id(book_id)
    return jsonify(created_book.to_dict()), 201

@shop_bp.route('/<int:book_id>', methods=['PUT'])
def update_book(book_id):
    """Update an existing book."""
    data = request.get_json()

    # Check if book exists
    existing_book = database.get_article_by_id(book_id)
    if not existing_book:
        return jsonify({"message": "Book not found"}), 404

    # Update book properties without validation
    if 'name' in data:
        existing_book.name = data['name']
    if 'price' in data:
        existing_book.price = float(data['price'])
    if 'quantity' in data:
        existing_book.quantity = int(data['quantity'])

    # Save updated book
    database.update_article(existing_book)

    # Missing error handling for the update operation
    updated_book = database.get_article_by_id(book_id)
    return jsonify(updated_book.to_dict())

@shop_bp.route('/<int:book_id>', methods=['DELETE'])
def delete_book(book_id):
    """Delete a book from the inventory."""
    # Missing check if book exists before deletion
    database.delete_article(book_id)
    return jsonify({"message": "Book deleted"}), 200

{{< /tab >}}

{{< tab title="tests/test_shop.py" >}}

# Missing comprehensive test cases
import pytest

def test_dummy():
    """A dummy test that always passes."""
    assert True

{{< /tab >}}

{{< tab title="app/init.py" >}}

from flask import Flask

def create_app(test_config=None):
    """
    Application factory for creating the Flask app.

    Args:
        test_config (dict, optional): Test configuration to override default config

    Returns:
        Flask: Configured Flask application
    """
    # Create and configure the app
    app = Flask(__name__)

    # Set default configuration
    app.config.from_mapping(
        SECRET_KEY='dev',  # Hard coded secret key
    )

    # Missing configuration from environment variables
    # Missing test config handling

    # Initialize database
    from app import database
    database.initialize_database()

    # Register blueprints
    from app.routes.shop import shop_bp
    app.register_blueprint(shop_bp)

    # Add a simple index route
    @app.route('/')
    def index():
        return {
            "message": "Welcome to the Bookstore Inventory API"
        }

    return app

{{< /tab >}}

{{< tab title=".env" >}}

# Missing many important environment variables
FLASK_APP=app
FLASK_ENV=development

{{< /tab >}}

{{< /tabs >}}

You will use Chat and Code Suggestions to identify and fix issues in these files.