0%

Put a Python Boundary Around the Database · practice

Configure Every Connection Once

Two settings should be true before catalog work begins:

foreign_keys: 1
selected row type: Row

Right now, list_available_items remembers the second setting, while every other query or command would have to remember it again. enforcement has the same per-connection rule. One opening can make both promises once.

Open catalog_db.py. Add the two settings inside the supplied open_database(database_path) function, between sqlite3.connect(database_path) and return connection:

def open_database(database_path):
    connection = sqlite3.connect(database_path)
    connection.execute("PRAGMA foreign_keys = ON")
    connection.row_factory = sqlite3.Row
    return connection

Then remove this line from list_available_items:

connection.row_factory = sqlite3.Row

Keep its query, result, fetchall(), and temporary (result, rows) return. The row type does not change: Run will now pass in a connection that open_database already configured. Moving the setting matters because the query function can focus on its query instead of quietly changing a caller’s connection.

open_database has a narrow job. It opens the path provided by its caller, enables foreign-key checks immediately, chooses named rows, and returns the live connection. It does not create tables, load sample data, commit, roll back, or close. Those actions belong to callers with more context.

The order also avoids two SQLite surprises. A query executed before the row-factory would still produce positional , and foreign-key enforcement turned on after a begins may not affect that transaction. Configure first; use the connection second.

Press Run. The existing call now uses open_database(database_path). A second visible block makes that function’s result concrete:

open_database(database_path)
foreign_keys: 1
selected row type: Row
selected item: IT-100 | Cordless drill
connection still open: yes

Submit opens two different temporary paths with your function. It checks both settings before doing database work, creates tables, verifies that a missing reference is refused, reads a column by name, and uses each connection again. It also checks that list_available_items no longer assigns a row factory. Return the connection; its caller will close it.

Task

Complete open_database(database_path) so every new connection enables checks and uses sqlite3.Row, then returns that live connection.

Remove connection.row_factory = sqlite3.Row from list_available_items; connection setup now belongs only in open_database. Do not create tables, commit, or close in either .