updated to mysql-connector-python

This commit is contained in:
srikar committed 2026-09-27 10:36:18 -07:00
1 parent 65691a0aee
commit 4bc9b87317
6 files changed
+50 -38

No files matched your search

+5 -11
View File
@@ -6,7 +6,7 @@ Tables 9.3–9.5 (STUDENT, GUARDIAN, ATTENDANCE).
## What it does on startup ## What it does on startup
1. Connects to the MySQL server at `10.0.1.40:3306`. 1. Connects to the MySQL server at `10.10.0.160:3306`.
2. Verifies the `student_db` database exists — creates it if not. 2. Verifies the `student_db` database exists — creates it if not.
3. Verifies the `GUARDIAN`, `STUDENT`, and `ATTENDANCE` tables exist 3. Verifies the `GUARDIAN`, `STUDENT`, and `ATTENDANCE` tables exist
(in that order, since STUDENT references GUARDIAN and ATTENDANCE (in that order, since STUDENT references GUARDIAN and ATTENDANCE
@@ -31,7 +31,7 @@ Tables 9.3–9.5 (STUDENT, GUARDIAN, ATTENDANCE).
export DB_USER=root export DB_USER=root
export DB_PASSWORD=your_password_here export DB_PASSWORD=your_password_here
# optional overrides — these already default correctly: # optional overrides — these already default correctly:
# export DB_HOST=10.0.1.40 # export DB_HOST=10.10.0.160
# export DB_PORT=3306 # export DB_PORT=3306
# export DB_NAME=student_db # export DB_NAME=student_db
``` ```
@@ -72,12 +72,6 @@ cascades and removes their attendance records automatically.
## Notes ## Notes
- Uses [PyMySQL](https://pymysql.readthedocs.io/), a pure-Python MySQL - Uses [mysql-connector-python](https://dev.mysql.com/doc/connector-python/en/), Oracle's official pure-Python MySQL driver — no system libraries (like `libmysqlclient`) required.
client — no system libraries (like `libmysqlclient`) required. - All input is validated against the schema's constraints (max lengths, digit counts, date format, P/A status) before hitting the database, and database-level errors (duplicate keys, foreign key violations) are caught and shown as friendly messages rather than crashing.
- All input is validated against the schema's constraints (max lengths, - Tested end-to-end (connect → create DB/tables → full CRUD → constraint error handling → cascade delete) against a local MySQL/MariaDB instance before delivery.
digit counts, date format, P/A status) before hitting the database,
and database-level errors (duplicate keys, foreign key violations)
are caught and shown as friendly messages rather than crashing.
- Tested end-to-end (connect → create DB/tables → full CRUD → constraint
error handling → cascade delete) against a local MySQL/MariaDB
instance before delivery.
+7 -2
View File
@@ -5,12 +5,17 @@ Connection settings are read from environment variables first, falling back
to the defaults below (which match the assignment's requirements). This to the defaults below (which match the assignment's requirements). This
means you can run the app as-is, or override any value like: means you can run the app as-is, or override any value like:
DB_HOST=10.0.1.40 DB_USER=root DB_PASSWORD=secret python3 main.py DB_HOST=10.10.0.160 DB_USER=root DB_PASSWORD=secret python3 main.py
# on windows
$env:DB_USER="mysql_user"
$env:DB_PASSWORD="mysql_password"
python3 main.py
""" """
import os import os
DB_HOST = os.environ.get("DB_HOST", "10.0.1.40") DB_HOST = os.environ.get("DB_HOST", "10.10.0.160")
DB_PORT = int(os.environ.get("DB_PORT", "3306")) DB_PORT = int(os.environ.get("DB_PORT", "3306"))
DB_USER = os.environ.get("DB_USER", "root") DB_USER = os.environ.get("DB_USER", "root")
DB_PASSWORD = os.environ.get("DB_PASSWORD", "") DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
+12 -11
View File
@@ -1,12 +1,12 @@
""" """
CRUD operations for GUARDIAN, STUDENT and ATTENDANCE. CRUD operations for GUARDIAN, STUDENT and ATTENDANCE.
Every function takes an open pymysql connection as its first argument and Every function takes an open mysql-connector-python connection as its first
manages its own commit/rollback. All functions return plain data argument and manages its own commit/rollback. All functions return plain
(dicts/lists/bool) so this module has no dependency on the UI layer. data (dicts/lists/bool) so this module has no dependency on the UI layer.
""" """
import pymysql import mysql.connector
class CrudError(Exception): class CrudError(Exception):
@@ -20,8 +20,8 @@ def _run(conn, sql, params=None, fetch=None):
fetch: None (no fetch), 'one', or 'all' fetch: None (no fetch), 'one', or 'all'
Translates common MySQL errors into CrudError with a friendly message. Translates common MySQL errors into CrudError with a friendly message.
""" """
cur = conn.cursor(dictionary=True)
try: try:
with conn.cursor() as cur:
cur.execute(sql, params or ()) cur.execute(sql, params or ())
result = None result = None
if fetch == "one": if fetch == "one":
@@ -30,23 +30,24 @@ def _run(conn, sql, params=None, fetch=None):
result = cur.fetchall() result = cur.fetchall()
conn.commit() conn.commit()
return result if fetch else cur.rowcount return result if fetch else cur.rowcount
except pymysql.err.IntegrityError as e: except mysql.connector.errors.IntegrityError as e:
conn.rollback() conn.rollback()
code = e.args[0] if e.args else None if e.errno == 1062:
if code == 1062:
raise CrudError("A record with that primary/unique key already exists.") raise CrudError("A record with that primary/unique key already exists.")
if code in (1451, 1452): if e.errno in (1451, 1452):
raise CrudError( raise CrudError(
"That operation violates a foreign key constraint " "That operation violates a foreign key constraint "
"(referenced record missing, or still referenced by other rows)." "(referenced record missing, or still referenced by other rows)."
) )
raise CrudError(f"Database integrity error: {e}") raise CrudError(f"Database integrity error: {e}")
except pymysql.err.DataError as e: except mysql.connector.errors.DataError as e:
conn.rollback() conn.rollback()
raise CrudError(f"Invalid data for one or more fields: {e}") raise CrudError(f"Invalid data for one or more fields: {e}")
except pymysql.err.MySQLError as e: except mysql.connector.Error as e:
conn.rollback() conn.rollback()
raise CrudError(f"Database error: {e}") raise CrudError(f"Database error: {e}")
finally:
cur.close()
# ---------------------------------------------------------------- GUARDIAN -- # ---------------------------------------------------------------- GUARDIAN --
+22 -10
View File
@@ -13,8 +13,8 @@ Schema notes:
import sys import sys
import pymysql import mysql.connector
import pymysql.cursors from mysql.connector import errorcode
import config import config
@@ -61,18 +61,23 @@ TABLE_ORDER = ["GUARDIAN", "STUDENT", "ATTENDANCE"]
def connect_server(database=None): def connect_server(database=None):
"""Connect to the MySQL server (optionally selecting a database).""" """Connect to the MySQL server (optionally selecting a database)."""
try: try:
conn = pymysql.connect( conn = mysql.connector.connect(
host=config.DB_HOST, host=config.DB_HOST,
port=config.DB_PORT, port=config.DB_PORT,
user=config.DB_USER, user=config.DB_USER,
password=config.DB_PASSWORD, password=config.DB_PASSWORD,
database=database, database=database,
connect_timeout=config.DB_CONNECT_TIMEOUT, connection_timeout=config.DB_CONNECT_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor,
autocommit=False, autocommit=False,
) )
return conn return conn
except pymysql.err.OperationalError as e: except mysql.connector.Error as e:
if e.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print(f"\n[ERROR] Access denied for user '{config.DB_USER}' — check "
f"DB_USER/DB_PASSWORD.")
elif database and e.errno == errorcode.ER_BAD_DB_ERROR:
print(f"\n[ERROR] Database '{database}' does not exist.")
else:
print(f"\n[ERROR] Could not connect to MySQL server at " print(f"\n[ERROR] Could not connect to MySQL server at "
f"{config.DB_HOST}:{config.DB_PORT} as user '{config.DB_USER}'.") f"{config.DB_HOST}:{config.DB_PORT} as user '{config.DB_USER}'.")
print(f" Details: {e}") print(f" Details: {e}")
@@ -83,7 +88,8 @@ def ensure_database():
"""Verify the student_db database exists; create it if it does not.""" """Verify the student_db database exists; create it if it does not."""
conn = connect_server(database=None) conn = connect_server(database=None)
try: try:
with conn.cursor() as cur: cur = conn.cursor()
try:
cur.execute("SHOW DATABASES LIKE %s", (config.DB_NAME,)) cur.execute("SHOW DATABASES LIKE %s", (config.DB_NAME,))
exists = cur.fetchone() is not None exists = cur.fetchone() is not None
if exists: if exists:
@@ -96,23 +102,29 @@ def ensure_database():
) )
conn.commit() conn.commit()
print(f"[OK] Database '{config.DB_NAME}' created.") print(f"[OK] Database '{config.DB_NAME}' created.")
finally:
cur.close()
finally: finally:
conn.close() conn.close()
def ensure_tables(conn): def ensure_tables(conn):
"""Verify each required table exists; create any that are missing.""" """Verify each required table exists; create any that are missing."""
with conn.cursor() as cur: cur = conn.cursor()
cur.execute("SHOW TABLES") cur.execute("SHOW TABLES")
existing = {row[f"Tables_in_{config.DB_NAME}"] for row in cur.fetchall()} existing = {row[0] for row in cur.fetchall()}
cur.close()
for table in TABLE_ORDER: for table in TABLE_ORDER:
if table in existing: if table in existing:
print(f"[OK] Table '{table}' found.") print(f"[OK] Table '{table}' found.")
else: else:
print(f"[..] Table '{table}' not found. Creating it...") print(f"[..] Table '{table}' not found. Creating it...")
with conn.cursor() as cur: cur = conn.cursor()
try:
cur.execute(TABLE_DEFINITIONS[table]) cur.execute(TABLE_DEFINITIONS[table])
finally:
cur.close()
conn.commit() conn.commit()
print(f"[OK] Table '{table}' created.") print(f"[OK] Table '{table}' created.")
+3 -3
View File
@@ -3,7 +3,7 @@
Student Management System Student Management System
========================== ==========================
Terminal CRUD application for STUDENT / GUARDIAN / ATTENDANCE, backed by Terminal CRUD application for STUDENT / GUARDIAN / ATTENDANCE, backed by
MySQL on 10.0.1.40:3306 (student_db). MySQL on 10.10.0.160:3306 (student_db).
On startup this: On startup this:
1. Connects to the MySQL server. 1. Connects to the MySQL server.
@@ -17,7 +17,7 @@ Run:
import sys import sys
import pymysql import mysql.connector
import crud import crud
import db import db
@@ -326,7 +326,7 @@ def main():
main_menu(conn) main_menu(conn)
except KeyboardInterrupt: except KeyboardInterrupt:
print("\n\nInterrupted. Exiting.") print("\n\nInterrupted. Exiting.")
except pymysql.err.MySQLError as e: except mysql.connector.Error as e:
print(f"\n[ERROR] Lost database connection: {e}") print(f"\n[ERROR] Lost database connection: {e}")
sys.exit(1) sys.exit(1)
finally: finally:
+1 -1
View File
@@ -1 +1 @@
PyMySQL>=1.1.0 mysql-connector-python>=9.0.0