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
+80 -68

No files matched your search

+24 -30
View File
@@ -6,41 +6,41 @@ Tables 9.3–9.5 (STUDENT, GUARDIAN, ATTENDANCE).
## 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.
3. Verifies the `GUARDIAN`, `STUDENT`, and `ATTENDANCE` tables exist
(in that order, since STUDENT references GUARDIAN and ATTENDANCE
references STUDENT) — creates any that are missing, with the exact
data types and constraints from the schema (primary keys, foreign
keys, `NOT NULL`, `UNIQUE` on `GPhone`, and the composite primary key
`(AttendanceDate, RollNumber)` on ATTENDANCE).
(in that order, since STUDENT references GUARDIAN and ATTENDANCE
references STUDENT) — creates any that are missing, with the exact
data types and constraints from the schema (primary keys, foreign
keys, `NOT NULL`, `UNIQUE` on `GPhone`, and the composite primary key
`(AttendanceDate, RollNumber)` on ATTENDANCE).
4. Launches an interactive menu for Create / Read / Update / Delete.
## Setup
1. Install the one dependency:
```bash
pip install -r requirements.txt
```
```bash
pip install -r requirements.txt
```
2. Set your MySQL credentials as environment variables (the host/port/
database default to the assignment's values already):
database default to the assignment's values already):
```bash
export DB_USER=root
export DB_PASSWORD=your_password_here
# optional overrides — these already default correctly:
# export DB_HOST=10.0.1.40
# export DB_PORT=3306
# export DB_NAME=student_db
```
```bash
export DB_USER=root
export DB_PASSWORD=your_password_here
# optional overrides — these already default correctly:
# export DB_HOST=10.10.0.160
# export DB_PORT=3306
# export DB_NAME=student_db
```
3. Run it:
```bash
python3 main.py
```
```bash
python3 main.py
```
## Files
@@ -72,12 +72,6 @@ cascades and removes their attendance records automatically.
## Notes
- Uses [PyMySQL](https://pymysql.readthedocs.io/), a pure-Python MySQL
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.
- Tested end-to-end (connect → create DB/tables → full CRUD → constraint
error handling → cascade delete) against a local MySQL/MariaDB
instance before delivery.
- 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.
- 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.
- 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
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
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_USER = os.environ.get("DB_USER", "root")
DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
+20 -19
View File
@@ -1,12 +1,12 @@
"""
CRUD operations for GUARDIAN, STUDENT and ATTENDANCE.
Every function takes an open pymysql connection as its first argument and
manages its own commit/rollback. All functions return plain data
(dicts/lists/bool) so this module has no dependency on the UI layer.
Every function takes an open mysql-connector-python connection as its first
argument and manages its own commit/rollback. All functions return plain
data (dicts/lists/bool) so this module has no dependency on the UI layer.
"""
import pymysql
import mysql.connector
class CrudError(Exception):
@@ -20,33 +20,34 @@ def _run(conn, sql, params=None, fetch=None):
fetch: None (no fetch), 'one', or 'all'
Translates common MySQL errors into CrudError with a friendly message.
"""
cur = conn.cursor(dictionary=True)
try:
with conn.cursor() as cur:
cur.execute(sql, params or ())
result = None
if fetch == "one":
result = cur.fetchone()
elif fetch == "all":
result = cur.fetchall()
conn.commit()
return result if fetch else cur.rowcount
except pymysql.err.IntegrityError as e:
cur.execute(sql, params or ())
result = None
if fetch == "one":
result = cur.fetchone()
elif fetch == "all":
result = cur.fetchall()
conn.commit()
return result if fetch else cur.rowcount
except mysql.connector.errors.IntegrityError as e:
conn.rollback()
code = e.args[0] if e.args else None
if code == 1062:
if e.errno == 1062:
raise CrudError("A record with that primary/unique key already exists.")
if code in (1451, 1452):
if e.errno in (1451, 1452):
raise CrudError(
"That operation violates a foreign key constraint "
"(referenced record missing, or still referenced by other rows)."
)
raise CrudError(f"Database integrity error: {e}")
except pymysql.err.DataError as e:
except mysql.connector.errors.DataError as e:
conn.rollback()
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()
raise CrudError(f"Database error: {e}")
finally:
cur.close()
# ---------------------------------------------------------------- GUARDIAN --
+25 -13
View File
@@ -13,8 +13,8 @@ Schema notes:
import sys
import pymysql
import pymysql.cursors
import mysql.connector
from mysql.connector import errorcode
import config
@@ -61,20 +61,25 @@ TABLE_ORDER = ["GUARDIAN", "STUDENT", "ATTENDANCE"]
def connect_server(database=None):
"""Connect to the MySQL server (optionally selecting a database)."""
try:
conn = pymysql.connect(
conn = mysql.connector.connect(
host=config.DB_HOST,
port=config.DB_PORT,
user=config.DB_USER,
password=config.DB_PASSWORD,
database=database,
connect_timeout=config.DB_CONNECT_TIMEOUT,
cursorclass=pymysql.cursors.DictCursor,
connection_timeout=config.DB_CONNECT_TIMEOUT,
autocommit=False,
)
return conn
except pymysql.err.OperationalError as e:
print(f"\n[ERROR] Could not connect to MySQL server at "
f"{config.DB_HOST}:{config.DB_PORT} as user '{config.DB_USER}'.")
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 "
f"{config.DB_HOST}:{config.DB_PORT} as user '{config.DB_USER}'.")
print(f" Details: {e}")
sys.exit(1)
@@ -83,7 +88,8 @@ def ensure_database():
"""Verify the student_db database exists; create it if it does not."""
conn = connect_server(database=None)
try:
with conn.cursor() as cur:
cur = conn.cursor()
try:
cur.execute("SHOW DATABASES LIKE %s", (config.DB_NAME,))
exists = cur.fetchone() is not None
if exists:
@@ -96,23 +102,29 @@ def ensure_database():
)
conn.commit()
print(f"[OK] Database '{config.DB_NAME}' created.")
finally:
cur.close()
finally:
conn.close()
def ensure_tables(conn):
"""Verify each required table exists; create any that are missing."""
with conn.cursor() as cur:
cur.execute("SHOW TABLES")
existing = {row[f"Tables_in_{config.DB_NAME}"] for row in cur.fetchall()}
cur = conn.cursor()
cur.execute("SHOW TABLES")
existing = {row[0] for row in cur.fetchall()}
cur.close()
for table in TABLE_ORDER:
if table in existing:
print(f"[OK] Table '{table}' found.")
else:
print(f"[..] Table '{table}' not found. Creating it...")
with conn.cursor() as cur:
cur = conn.cursor()
try:
cur.execute(TABLE_DEFINITIONS[table])
finally:
cur.close()
conn.commit()
print(f"[OK] Table '{table}' created.")
+3 -3
View File
@@ -3,7 +3,7 @@
Student Management System
==========================
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:
1. Connects to the MySQL server.
@@ -17,7 +17,7 @@ Run:
import sys
import pymysql
import mysql.connector
import crud
import db
@@ -326,7 +326,7 @@ def main():
main_menu(conn)
except KeyboardInterrupt:
print("\n\nInterrupted. Exiting.")
except pymysql.err.MySQLError as e:
except mysql.connector.Error as e:
print(f"\n[ERROR] Lost database connection: {e}")
sys.exit(1)
finally:
+1 -1
View File
@@ -1 +1 @@
PyMySQL>=1.1.0
mysql-connector-python>=9.0.0