A Python-based classroom scheduling system using SQLite to automate timetable management for educational institutions. Prevents scheduling conflicts, enforces capacity limits, respects projector requirements, and optimizes room assignments.
- Conflict Detection: Prevents room double-booking, teacher overlaps, and course time conflicts
- Capacity Management: Validates room capacity against enrolled student counts
- Resource Planning: Ensures rooms with projectors are assigned to courses requiring them
- Auto-Assignment: Intelligent room recommendation using best-fit algorithm
- Schedule Management: Create, read, update, and delete schedule entries
- Reporting: Room utilization metrics and teacher workload analysis
- Transaction Safety: Foreign key constraints and data integrity enforcement
classroom_scheduling_system_de/
├── db.py # Database setup and connection management
├── crud.py # Create/Read/Update/Delete operations for all entities
├── scheduler.py # Conflict detection and auto-assignment logic
├── demo.py # Sample data and demonstration of all features
├── test_scheduler.py # Comprehensive test suite
├── README.md # This file
└── scheduling.db # SQLite database (created on first run)
- Python 3.9+
- pip or conda
- Clone or download the repository:
cd classroom_scheduling_system_de- Install dependencies (if using a virtual environment):
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt # or just pytest for testing- Initialize the database:
python db.pyfrom db import init_db
from crud import add_room, add_teacher, add_course, add_timeslot
from scheduler import schedule_class
# Initialize database
init_db()
# Add resources
room = add_room("Lecture Hall 101", capacity=50, building="Main", has_projector=True)
teacher = add_teacher("Dr. Smith", "smith@university.edu", dept="Computer Science")
course = add_course("CS101", "Intro to Programming", enrolled=35, requires_projector=True)
timeslot = add_timeslot("Mon", "09:00", "10:00")
# Schedule a class
result = schedule_class(course, teacher, room, timeslot)
if result.success:
print(f"Schedule created: #{result.schedule_id}")
print(result.message)
else:
print(f"Scheduling failed: {result.message}")python demo.pyThis will:
- Initialize the database
- Add sample rooms, teachers, courses, and timeslots
- Demonstrate manual scheduling with conflict detection
- Show auto-assignment in action
- Display room utilization and teacher workload reports
init_db(): Initialize SQLite database with all required tablesget_connection(): Get a database connection with proper settings
add_room(name, capacity, building="", has_projector=False) -> int
get_rooms() -> list[Row]
update_room(room_id, **kwargs)
delete_room(room_id)add_teacher(name, email, dept="") -> int
get_teachers() -> list[Row]
update_teacher(teacher_id, **kwargs)
delete_teacher(teacher_id)add_course(code, title, enrolled=0, requires_projector=False) -> int
get_courses() -> list[Row]
update_course(course_id, **kwargs)
delete_course(course_id)add_timeslot(day, start_time, end_time) -> int
get_timeslots() -> list[Row]
delete_timeslot(timeslot_id)get_schedules() -> list[Row]
delete_schedule(schedule_id)check_conflicts(course_id, teacher_id, room_id, timeslot_id,
exclude_schedule_id=None) -> ConflictReportReturns a ConflictReport with:
has_conflict: bool- Whether any conflicts existreasons: list[str]- Detailed conflict messages
Checks:
- Room double-booking in same timeslot
- Teacher double-booking in same timeslot
- Course already scheduled in this slot
- Room capacity vs enrolled students
- Projector requirement satisfaction
schedule_class(course_id, teacher_id, room_id, timeslot_id) -> ScheduleResultSchedules a class after full conflict checking.
Returns:
success: bool- Whether scheduling succeededschedule_id: int- ID of created schedule (if successful)message: str- Status message
update_schedule(schedule_id, course_id, teacher_id, room_id,
timeslot_id) -> ScheduleResultUpdates an existing schedule entry with conflict checking.
auto_assign(course_id, teacher_id, preferred_days=None) -> ScheduleResultAutomatically assigns a course to a free timeslot and suitable room.
Algorithm:
- Finds free timeslots for the teacher (optionally filtered by preferred days)
- Selects the smallest room that fits (best-fit algorithm)
- Respects projector requirements
- Returns first valid assignment or failure
room_utilisation() -> list[dict]Returns room utilization statistics:
[
{
'room': str, # Room name
'booked': int, # Number of booked slots
'total_slots': int, # Total available slots
'utilisation_pct': float # Percentage booked
},
...
]teacher_load() -> list[Row]Returns number of classes per teacher.
CREATE TABLE rooms (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
capacity INTEGER NOT NULL CHECK(capacity > 0),
building TEXT,
has_projector INTEGER NOT NULL DEFAULT 0
);CREATE TABLE teachers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
dept TEXT
);CREATE TABLE courses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
enrolled INTEGER NOT NULL DEFAULT 0,
requires_projector INTEGER NOT NULL DEFAULT 0
);CREATE TABLE timeslots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
day TEXT NOT NULL CHECK(day IN ('Mon','Tue','Wed','Thu','Fri','Sat')),
start_time TEXT NOT NULL,
end_time TEXT NOT NULL,
UNIQUE(day, start_time, end_time)
);CREATE TABLE schedules (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_id INTEGER NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
teacher_id INTEGER NOT NULL REFERENCES teachers(id) ON DELETE CASCADE,
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
timeslot_id INTEGER NOT NULL REFERENCES timeslots(id) ON DELETE CASCADE,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
UNIQUE(room_id, timeslot_id),
UNIQUE(teacher_id, timeslot_id),
UNIQUE(course_id, timeslot_id)
);Constraints:
- A room cannot be booked twice in the same timeslot
- A teacher cannot teach two classes simultaneously
- A course cannot be scheduled twice in the same slot
- Foreign keys enforce referential integrity with cascading deletes
Run the test suite using pytest:
pytest test_scheduler.py -vTests validate:
- ✓ Successful schedule creation
- ✓ Room double-booking prevention
- ✓ Teacher conflict detection
- ✓ Course duplicate scheduling prevention
- ✓ Room capacity validation
- ✓ Projector requirement enforcement
- ✓ Auto-assignment with various constraints
- ✓ Conflict reporting accuracy
All 13 tests should pass:
test_scheduler.py::TestManualScheduling::test_successful_schedule PASSED
test_scheduler.py::TestManualScheduling::test_room_double_booking PASSED
test_scheduler.py::TestManualScheduling::test_teacher_double_booking PASSED
test_scheduler.py::TestManualScheduling::test_course_double_slot PASSED
test_scheduler.py::TestManualScheduling::test_capacity_violation PASSED
test_scheduler.py::TestManualScheduling::test_projector_violation PASSED
test_scheduler.py::TestManualScheduling::test_no_conflict_different_slots PASSED
test_scheduler.py::TestAutoAssign::test_auto_assign_success PASSED
test_scheduler.py::TestAutoAssign::test_auto_assign_respects_projector PASSED
test_scheduler.py::TestAutoAssign::test_auto_assign_no_room_available PASSED
test_scheduler.py::TestAutoAssign::test_auto_assign_teacher_busy PASSED
test_scheduler.py::TestConflictReport::test_no_conflicts_report PASSED
test_scheduler.py::TestConflictReport::test_multiple_conflicts_reported PASSED
from db import init_db
from crud import add_room, add_teacher, add_course, add_timeslot
from scheduler import schedule_class, check_conflicts
init_db()
# Create entities
room_id = add_room("Lab-A", capacity=25, has_projector=False)
teacher_id = add_teacher("Dr. Johnson", "johnson@uni.edu", dept="Physics")
course_id = add_course("PHY201", "Physics II", enrolled=20)
timeslot_id = add_timeslot("Tue", "14:00", "15:00")
# Check for conflicts before scheduling
conflicts = check_conflicts(course_id, teacher_id, room_id, timeslot_id)
if conflicts.has_conflict:
print(f"Cannot schedule: {conflicts}")
else:
result = schedule_class(course_id, teacher_id, room_id, timeslot_id)
print(result.message)from scheduler import auto_assign
# Let the system find the best slot on Mon/Wed/Fri
result = auto_assign(
course_id=course_id,
teacher_id=teacher_id,
preferred_days=["Mon", "Wed", "Fri"]
)
if result.success:
print(f"Successfully auto-assigned: {result.message}")
else:
print(f"Could not find suitable slot: {result.message}")from scheduler import room_utilisation
for stat in room_utilisation():
utilization = stat['utilisation_pct']
booked = stat['booked']
total = stat['total_slots']
print(f"{stat['room']:20s} {booked:2d}/{total} ({utilization:5.1f}%)")from scheduler import update_schedule
# Move a class to different room/time
result = update_schedule(
schedule_id=42,
course_id=course_id,
teacher_id=teacher_id,
room_id=new_room_id,
timeslot_id=new_timeslot_id
)
print(result.message)This project is provided as-is for educational purposes.
- Ahan Mondal