Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 148 additions & 21 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import os
import csv
from mock_storage import MockCSVStorage

#IMPORT
def import_from_file(filename="students.csv"):
students = []
try:
with open(filename, 'r', newline='') as file: #'r' read file, newline='' to manage newline characters correctly in CSV files
for line in file:
reader = csv.DictReader(file)
lines = file.readlines() #read all the rows at once

for line in lines[1:]: #skip the 1st row (headlines)
cut_parts = line.strip().split(',') #delete whitespaces and create a seperator as ,
#in the file: first name, last name
if len(cut_parts) == 2: #no attendance provided
Expand All @@ -23,13 +27,18 @@ def import_from_file(filename="students.csv"):
})
else: print('Something went wrong when importing the file.')
return students

except FileNotFoundError:
print(f"The file '{filename}' was not found.") #added if filenotfound exception

#EXPORT

def export_attendance(students, filename="students.csv"):
fieldnames = ["first_name", "last_name", "present"]

with open(filename, 'w', newline='') as file: #'w' write file
writer = csv.DictWriter(file, fieldnames)
writer.writeheader()
for student in students:
present = 'yes' if student['present'] else 'no'
file.write(f"{student['first_name']},{student['last_name']},{present}\n")
Expand All @@ -38,39 +47,67 @@ def export_attendance(students, filename="students.csv"):
#ADDING NEW STUDENTS AND UPDATING DATABASE

# function that adds new student to the list and saves it to the file
def add_student(first_name, last_name, filename="students.csv"):
file_exists = os.path.isfile(filename)
def add_student(first_name, last_name, storage):
if isinstance(storage, str): #if storage is a path to file
file_exists = os.path.isfile(storage)

with open(filename, 'a', newline='') as file:
with open(storage, 'a', newline='') as file:
writer = csv.writer(file)

if not file_exists:
writer.writerow(["first_name", "last_name", "present"])
writer.writerow(["first_name", "last_name", "present"])

writer.writerow(["first_name", "last_name", "no"]) #present is "no" by default

elif isinstance(storage, MockCSVStorage): #if storage is mockcsvstorage
students = storage.read()

if any(student["first_name"] == first_name and student["last_name"] == last_name for student in students):
raise Exception("Student already exists in the database")

# "present" is false by default
writer.writerow([first_name, last_name, False])
print(f"Student {first_name} {last_name} was added to {filename}.")
storage.append({"first_name": first_name, "last_name": last_name, "present": "no"})
print(f"Student {first_name} {last_name} was added to {storage}.")


# function that edits student list
def edit_student(old_first_name, old_last_name, new_first_name, new_last_name, filename="students.csv"):
students = []
def edit_student(old_first_name, old_last_name, new_first_name, new_last_name, storage):
updated = False

with open(filename, 'r') as file:
reader = csv.DictReader(file)
for row in reader:
if isinstance(storage, str): #if storage is a path to file
students = []
with open(storage, 'r') as file:
reader = csv.DictReader(file)
for row in reader:
if row["first_name"] == old_first_name and row["last_name"] == old_last_name:
row["first_name"] = new_first_name
row["last_name"] = new_last_name
updated = True
row["first_name"] = new_first_name
row["last_name"] = new_last_name
updated = True
students.append(row)

with open(filename, 'w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=["first_name", "last_name", "present"])
writer.writeheader()
writer.writerows(students)

with open(storage, 'w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=["first_name", "last_name", "present"])
writer.writeheader()
writer.writerows(students)

elif isinstance(storage, MockCSVStorage): #if storage is mockcsvstorage
students = storage.read()
print(f"Before edit: {students}")
student_found = False

for student in students:
if student["first_name"] == old_first_name and student["last_name"] == old_last_name:
student["first_name"] = new_first_name
student["last_name"] = new_last_name
student_found = True
updated = True
break #found + updated so no need to continue

if not student_found:
raise Exception("Student does not exist in the database")

storage.write(students)
print(f"After edit: {students}")

if updated:
print(f"Student: {old_first_name} {old_last_name} has been updated to {new_first_name} {new_last_name}.")
else:
Expand Down Expand Up @@ -107,3 +144,93 @@ def mark_attenfance(students):
student['present'] = False # Mark as absent
else:
print("Invalid input, please enter 'yes' or 'no'.")

#MANAGING STUDENT'S DATA:
def student_data():
student_firstName = input('Enter students first name: ')
student_lastName = input('Enter students last name: ')
return f"{student_firstName} {student_lastName}"

def presence_function():
presence = input("Was the student present? (yes/no): ")
if (presence.lower() == 'yes'):
return 'PRESENT'
elif (presence.lower() == 'no'):
return 'ABSENT'
else:
print("Invalid output. Please try again. ")
return presence_function()

# CREATING 'ATTENDANCE_DICTIONARY' AND CREATING 'STUDENTS' LIST - a list where every element is a dictionary
def manage_attendance():
attendance_dictionary = {}
student_id = 1
while True:
student = student_data()
attendance_status = presence_function()
attendance_dictionary[student_id] = [student, attendance_status]
student_id += 1

add_student = input("Want to add another student? (yes/no):")
print()
if add_student.lower() != 'yes':
break

#EXPORT to .csv file (integration with export_attendance())
students = [
{
"first_name": s.split(' ')[0],
"last_name": s.split(' ')[1],
"present": a == "PRESENT"
}
for s_id, (s, a) in attendance_dictionary.items()
]

export_attendance(students)

#printing students' list:
print("ATTENDANCE LIST:")
for s_id, (student, status) in attendance_dictionary.items():
print(f"STUDENT ID: {s_id}, NAME: {student}, ATTENDANCE STATUS: {status}")
print()
return attendance_dictionary

# EDITING STUDENT'S ATTENDANCE STATUS
def edit_attendance(attendance_dictionary, student_id):
if student_id in attendance_dictionary:
new_attendance_status = presence_function()
attendance_dictionary[student_id][1] = new_attendance_status
else:
print("Student not found")
return attendance_dictionary

#MENU
if __name__ == "__main__":
attendance = {}
students = []
while True:
print("MENU:")
print("1. Manage attendance")
print("2. Edit attendance")
print("3. Import students")
print("4. Export attendance")
print("5. Exit")
choice = input("Choose your option: ")


if choice == "1":
attendance = manage_attendance()
elif choice == "2":
student_id = int(input("Enter student ID: "))
edit_attendance(attendance, student_id)
print("Updated attendance: ", attendance)
elif choice == "3":
students = import_from_file()
print("Imported students: ", students)
elif choice == "4":
export_attendance(students)
elif choice == "5":
print("Exiting the program.")
break
else:
print("Invalid choice. Please try again.")
17 changes: 17 additions & 0 deletions mock_storage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import List, Dict

class MockCSVStorage:
def __init__(self):
self.data = []

def write(self, rows: List[Dict[str, str]]):
self.data = rows

def read(self) -> List[Dict[str, str]]:
return self.data

def append(self, row: Dict[str, str]):
self.data.append(row)

#added cause i cant import sth from main.py to test_main.py
#and then from test_main.py to main.py 'cause they're mutually dependent
131 changes: 131 additions & 0 deletions test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
import pytest
import csv
from typing import List, Dict
from mock_storage import MockCSVStorage
from main import import_from_file, export_attendance, add_student, edit_student, manage_attendance

@pytest.fixture
def csv_file():
file = "students_test.csv"
open(file, 'w').close()
yield file
os.remove(file)


class TestAttendanceSystem:
#test: saving to file
def test_save_to_file(self, csv_file):
#Given
students = [
{"first_name": "John", "last_name": "Doe", "present": True},
{"first_name": "Jane", "last_name": "Smith", "present": False},
]

#When
export_attendance(students, csv_file)

#Then
expected_data = [
{"first_name": "John", "last_name": "Doe", "present": "yes"},
{"first_name": "Jane", "last_name": "Smith", "present": "no"},
]

with open(csv_file, 'r') as file:
reader = csv.DictReader(file)
actual_data = [row for row in reader]

assert actual_data == expected_data

#test: loading from file
def test_load_from_file(self, csv_file):
#Given
students = [
{"first_name": "John", "last_name": "Doe", "present": "yes"},
{"first_name": "Jane", "last_name": "Smith", "present": "no"},
]

with open(csv_file, 'w', newline='') as file:
fieldnames = ["first_name", "last_name", "present"]
writer = csv.DictWriter(file, fieldnames)
writer.writeheader()
writer.writerows(students)

#When
students_from_file = import_from_file(csv_file)

#Then
expected_students = [
{"first_name": "John", "last_name": "Doe", "present": True},
{"first_name": "Jane", "last_name": "Smith", "present": False},
]

assert students_from_file == expected_students

#test: adding students
def test_add_students(self):
#Given
mock_storage = MockCSVStorage()
mock_storage.write([
{"first_name": "John", "last_name": "Doe", "present": "yes"},
])

#When
add_student("Jane", "Smith", mock_storage)

#Then
expected_data = [
{"first_name": "John", "last_name": "Doe", "present": "yes"},
{"first_name": "Jane", "last_name": "Smith", "present": "no"},
]
assert mock_storage.data == expected_data

#test: editing students' data
def test_edit_student(self):
#Given
mock_storage = MockCSVStorage()
mock_storage.write([
{"first_name": "John", "last_name": "Doe", "present": "yes"},
{"first_name": "Jane", "last_name": "Smith", "present": "no"},
])

#When
edit_student("Jane", "Smith", "Janet", "Smith", mock_storage)

#Then
expected_data = [
{"first_name": "John", "last_name": "Doe", "present": "yes"},
{"first_name": "Janet", "last_name": "Smith", "present": "no"},

]
assert mock_storage.data == expected_data

#test: attendance
def test_attendance_management(self):
# Given
mock_storage = MockCSVStorage()
mock_storage.write([
{"first_name": "John", "last_name": "Doe", "present": "no"},
])

#replacement function to simulate user input
def mock_input(p):
if "Is John Doe present" in p:
return "yes"
return "no"

#When
students = mock_storage.read()
for student in students:
if mock_input(f"Is {student['first_name']} {student['last_name']} present? (yes/no): ").lower() == "yes":
student["present"] = "yes"
else:
student["present"] = "no"

mock_storage.write(students)

#Then
expected_data = [
{"first_name": "John", "last_name": "Doe", "present": "yes"},
]
assert mock_storage.read() == expected_data