School Commit Init

This commit is contained in:
2024-08-31 12:07:21 +03:00
commit 0b130ee18c
2801 changed files with 4720552 additions and 0 deletions
@@ -0,0 +1,130 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
.vscode/
@@ -0,0 +1,93 @@
# 💻 Assignment 08
## Requirements
- Provide a menu-driven console-based user interface. Implementation details are up to you
- Employ layered architecture and classes
- Have at least 20 procedurally generated items in your application at startup
- Provide specifications and **PyUnit test cases** for all non-UI classes and methods for the first functionality
- Implement and use your own exception classes.
- Deadline is **week 12**, with the exception of the undo-redo bonus.
## Bonus possibility (0.1p, deadline week 12)
- 95% unit test code coverage for all modules except the UI (use *PyCharm Professional*, the *[coverage](https://coverage.readthedocs.io/en/coverage-5.3/)* or other modules)
## Bonus possibility (0.2p, deadline week 12)
- Implement a graphical user interface, in addition to the required menu-driven UI
- The program can be started with either UI
## Bonus possibility (0.2p, deadline week 14)
- Unlimited undo/redo functionality. Each step will undo/redo the previous operation performed by the user. Undo/redo operations must cascade and have a memory-efficient implementation (no superfluous list copying) based on the [command design pattern](https://refactoring.guru/design-patterns/command)
## Problem Statements
### 1. Students Register Management
A faculty stores information about:
- **Student**: `student_id`, `name`
- **Discipline**: `discipline_id`, `name`
- **Grade**: `discipline_id`, `student_id`, `grade_value`
Create an application to:
1. Manage students and disciplines. The user can add, remove, update, and list both students and disciplines.
2. Grade students at a given discipline. Any student may receive one or several grades at any discipline. Deleting a student also removes their grades. Deleting a discipline deletes all grades at that discipline for all students.
3. Search for disciplines/students based on ID or name/title. The search must work using case-insensitive, partial string matching, and must return all matching disciplines/students.
4. Create statistics:
- All students failing at one or more disciplines (students having an average <5 for a discipline are failing it)
- Students with the best school situation, sorted in descending order of their aggregated average (the average between their average grades per discipline)
- All disciplines at which there is at least one grade, sorted in descending order of the average grade(s) received by all students
### 2. Student Lab Assignment
Write an application that manages student lab assignments for a discipline. The application will store:
- **Student**: `student_id`, `name`, `group`
- **Assignment**: `assignment_id`, `description`, `deadline`
- **Grade**: `assignment_id`, `student_id`, `grade_value`
Create an application that allows to:
1. Manage students and assignments. The user can add, remove, update, and list both students and assignments.
2. Give assignments to a student or a group of students. In case an assignment is given to a group of students, every student in the group will receive it. In case there are students who were previously given that assignment, it will not be assigned again.
3. Grade student for a given assignment. When grading, the program must allow the user to select the assignment that is graded, from the students list of ungraded assignments. A students grade for a given assignment cannot be changed. Deleting a student removes their assignments. Deleting an assignment also removes all grades at that assignment.
4. Create statistics:
- All students who received a given assignment, ordered descending by grade.
- All students who are late in handing in at least one assignment. These are all the students who have an ungraded assignment for which the deadline has passed.
- Students with the best school situation, sorted in descending order of the average grade received for all graded assignments.
### 3. Movie Rental
Write an application for movie rentals. The application will store:
- **Movie**: `movie_id`, `title`, `description`, `genre`
- **Client**: `client_id`, `name`
- **Rental**: `rental_id`, `movie_id`, `client_id`, `rented_date`, `due_date`, `returned_date`
Create an application which allows to:
1. Manage clients and movies. The user can add, remove, update, and list both clients and movies.
2. Rent or return a movie. A client can rent a movie until a given date, as long as they have no rented movies that passed their due date for return. A client can return a rented movie at any time.
3. Search for clients or movies using any one of their fields (e.g. movies can be searched for using id, title, description or genre). The search must work using case-insensitive, partial string matching, and must return all matching items.
4. Create statistics:
- Most rented movies. This will provide the list of movies, sorted in descending order of the number of days they were rented.
- Most active clients. This will provide the list of clients, sorted in descending order of the number of movie rental days they have (e.g. having 2 rented movies for 3 days each counts as 2 x 3 = 6 days).
- Late rentals. All the movies that are currently rented, for which the due date for return has passed, sorted in descending order of the number of days of delay.
### 4. Library
Write an application for a book library. The application will store:
- **Book**: `book_id`, `title`, `author`
- **Client**: `client_id`, `name`
- **Rental**: `rental_id`, `book_id`, `client_id`, `rented_date`, `returned_date`
Create an application to:
1. Manage clients and books. The user can add, remove, update, and list both clients and books.
2. Rent or return a book. A client can rent an available book. A client can return a rented book at any time. Only available books (those which are not currently rented) can be rented.
3. Search for clients or books using any one of their fields (e.g. books can be searched for using id, title or author). The search must work using case-insensitive, partial string matching, and must return all matching items.
4. Create statistics:
- Most rented books. This will provide the list of books, sorted in descending order of the number of times they were rented.
- Most active clients. This will provide the list of clients, sorted in descending order of the number of book rental days they have (e.g. having 2 rented books for 3 days each counts as 2 x 3 = 6 days).
- Most rented author. This provides the list of book authors, sorted in descending order of the number of rentals their books have.
### 5. Activity Planner
The following information is stored in a personal activity planner:
- **Person**: `person_id`, `name`, `phone_number`
- **Activity**: `activity_id`, `person_id` - list, `date`, `time`, `description`
Create an application to:
1. Manage persons and activities. The user can add, remove, update, and list both persons and activities.
2. Add/remove activities. Each activity can be performed together with one or several other persons, who are already in the users planner. Activities must not overlap (user cannot have more than one activity at a given time).
3. Search for persons or activities. Persons can be searched for using name or phone number. Activities can be searched for using date/time or description. The search must work using case-insensitive, partial string matching, and must return all matching items.
4. Create statistics:
- Activities for a given date. List the activities for a given date, in the order of their start time.
- Busiest days. This will provide the list of upcoming dates with activities, sorted in ascending order of the free time in that day (all intervals with no activities).
- Activities with a given person. List all upcoming activities to which a given person will participate.
@@ -0,0 +1,16 @@
from src.ui.ui import UI
from src.repository.students_repo import StudentsRepo
from src.repository.assignments_repo import AssignmentsRepo
from src.repository.grades_repo import GradesRepo
from src.services.services import Services
def main():
students_repo = StudentsRepo("src/data/students.json")
assignments_repo = AssignmentsRepo("src/data/assignments.json")
grades_repo = GradesRepo("src/data/grades.json")
services = Services(students_repo,assignments_repo,grades_repo)
ui = UI(services)
ui.start()
if __name__ == "__main__":
main()
@@ -0,0 +1,47 @@
[
{
"assignment_id": "1",
"description": "Science Assignment",
"deadline": {
"year": 2022,
"month": 12,
"day": 15
}
},
{
"assignment_id": "2",
"description": "Math Assignment",
"deadline": {
"year": 2023,
"month": 10,
"day": 10
}
},
{
"assignment_id": "3",
"description": "English Assignment",
"deadline": {
"year": 2023,
"month": 3,
"day": 12
}
},
{
"assignment_id": "4",
"description": "History Assignment",
"deadline": {
"year": 2022,
"month": 10,
"day": 5
}
},
{
"assignment_id": "5",
"description": "Art Assignment",
"deadline": {
"year": 2023,
"month": 2,
"day": 2
}
}
]
@@ -0,0 +1,32 @@
[
{
"assignment_id": "2",
"student_id": "A002",
"grade_value": 10.0
},
{
"assignment_id": "2",
"student_id": "A007",
"grade_value": 8.5
},
{
"assignment_id": "2",
"student_id": "A008",
"grade_value": 4.0
},
{
"assignment_id": "2",
"student_id": "A009",
"grade_value": null
},
{
"assignment_id": "4",
"student_id": "A003",
"grade_value": 7.5
},
{
"assignment_id": "4",
"student_id": "A010",
"grade_value": null
}
]
@@ -0,0 +1,52 @@
[
{
"student_id": "A001",
"name": "John Doe",
"group": "A1"
},
{
"student_id": "A002",
"name": "Jack Black",
"group": "C"
},
{
"student_id": "A003",
"name": "Justin Cole",
"group": "E"
},
{
"student_id": "A004",
"name": "Johnny Depp",
"group": "A1"
},
{
"student_id": "A005",
"name": "Mike Smith",
"group": "A1"
},
{
"student_id": "A006",
"name": "Dan Brown",
"group": "A1"
},
{
"student_id": "A007",
"name": "Walter White",
"group": "C"
},
{
"student_id": "A008",
"name": "Saul Goodman",
"group": "C"
},
{
"student_id": "A009",
"name": "Jesse Pinkman",
"group": "C"
},
{
"student_id": "A010",
"name": "Anna Henrietta",
"group": "E"
}
]
@@ -0,0 +1,40 @@
from datetime import date
class Assignment():
def __init__(self, assignment_id: str, description: str, deadline: date) -> None:
self.__assignment_id = assignment_id
self.__description = description
self.__deadline = deadline
def get_assignment_id(self) -> str:
return self.__assignment_id
def get_description(self) -> str:
return self.__description
def get_deadline(self) -> date:
return self.__deadline
def set_assignment_id(self, assignment_id: str) -> None:
self.__assignment_id = assignment_id
def set_description(self, description: str) -> None:
self.__description = description
def set_deadline(self, deadline: date) -> None:
self.__deadline = deadline
def __str__(self) -> str:
return f"Assignment ID: {self.__assignment_id} | Description: {self.__description} | Deadline: {self.__deadline.isoformat()}"
def toJson(self) -> dict:
return {
"assignment_id": self.__assignment_id,
"description": self.__description,
"deadline": {
"year": self.__deadline.year,
"month": self.__deadline.month,
"day": self.__deadline.day
}
}
@@ -0,0 +1,36 @@
from src.errors.errors import GradeValueAlreadySetError
class Grade():
def __init__(self, assignment_id: str, student_id: str, grade_value: float) -> None:
self.__assignment_id = assignment_id
self.__student_id = student_id
self.__grade_value = grade_value
def get_assignment_id(self) -> str:
return self.__assignment_id
def get_student_id(self) -> str:
return self.__student_id
def get_grade_value(self) -> float:
return self.__grade_value
def set_assignment_id(self, assignment_id: str) -> None:
self.__assignment_id = assignment_id
def set_student_id(self, student_id: str) -> None:
self.__student_id = student_id
def set_grade_value(self, grade_value: float) -> None:
self.__grade_value = grade_value
def __str__(self) -> str:
return f"Assignment id: {self.__assignment_id}, student id: {self.__student_id}, grade value: {self.__grade_value}"
def toJson(self) -> dict:
return {
"assignment_id": self.__assignment_id,
"student_id": self.__student_id,
"grade_value": self.__grade_value
}
@@ -0,0 +1,34 @@
class Student():
def __init__(self,student_id:str,name:str,group:str) -> None:
self.__student_id = student_id
self.__name = name
self.__group = group
def get_student_id(self) -> str:
return self.__student_id
def get_name(self) -> str:
return self.__name
def get_group(self) -> str:
return self.__group
def set_student_id(self,student_id:str) -> None:
self.__student_id = student_id
def set_name(self,name:str) -> None:
self.__name = name
def set_group(self,group:str) -> None:
self.__group = group
def __str__(self) -> str:
return f"Student ID: {self.__student_id} | Name: {self.__name} | Group: {self.__group}"
def toJson(self) -> dict:
return {
"student_id":self.__student_id,
"name":self.__name,
"group":self.__group
}
@@ -0,0 +1,26 @@
class DuplicatingError(Exception):
pass
class NonExistentError(Exception):
pass
class StudentNotFoundError(NonExistentError):
pass
class StudentAlreadyExistsError(DuplicatingError):
pass
class AssignmentNotFoundError(NonExistentError):
pass
class AssignmentAlreadyExistsError(DuplicatingError):
pass
class GradeNotFoundError(NonExistentError):
pass
class GradeAlreadyExistsError(DuplicatingError):
pass
class GradeValueAlreadySetError(DuplicatingError):
pass
@@ -0,0 +1,78 @@
import json
from datetime import date
from src.domain.assignment import Assignment
from src.errors.errors import *
class AssignmentsRepo:
"""
Class that manages the assignments
Reads and writes from a json file
Attributes:
__path: the path to the json file
assignments: a list of assignments
Methods:
__load_from_file: loads the assignments from the json file
__save_to_file: saves the assignments to the json file
add_assignment: adds an assignment to the repository
remove_assignment: removes an assignment from the repository
update_assignment: updates an assignment from the repository
list_assignments: returns a list of assignments
get_assignment: returns an assignment
is_an_assignment: returns True if the assignment is in the repository
"""
def __init__(self, path: str) -> None:
self.__path = path
self.assignments = []
self.__load_from_file()
def __load_from_file(self) -> None:
with open(self.__path, "r") as f:
assignments = json.load(f)
for assignment in assignments:
self.assignments.append(Assignment(assignment["assignment_id"], assignment["description"], date(assignment["deadline"]["year"], assignment["deadline"]["month"], assignment["deadline"]["day"])))
def __save_to_file(self) -> None:
assignments = []
for assignment in self.assignments:
assignments.append(assignment.toJson())
with open(self.__path, "w") as f:
json.dump(assignments, f, indent=4)
def add_assignment(self, assignment: Assignment) -> None:
if assignment.get_assignment_id() in [assignment.get_assignment_id() for assignment in self.assignments]:
raise AssignmentAlreadyExistsError("Assignment already exists")
self.assignments.append(assignment)
self.__save_to_file()
def remove_assignment(self, assignment_id: str) -> None:
for assignment in self.assignments:
if assignment.get_assignment_id() == assignment_id:
self.assignments.remove(assignment)
self.__save_to_file()
return
raise AssignmentNotFoundError("Assignment not found")
def update_assignment(self, assignment: Assignment) -> None:
for assignment_in_list in self.assignments:
if assignment_in_list.get_assignment_id() == assignment.get_assignment_id():
assignment_in_list.set_description(assignment.get_description())
assignment_in_list.set_deadline(assignment.get_deadline())
self.__save_to_file()
return
raise AssignmentNotFoundError("Assignment not found")
def list_assignments(self) -> list[Assignment]:
return self.assignments
def get_assignment(self, assignment_id: str) -> Assignment:
for assignment in self.assignments:
if assignment.get_assignment_id() == assignment_id:
return assignment
raise AssignmentNotFoundError("Assignment not found")
def is_an_assignment(self, assignment_id: str) -> bool:
for assignment in self.assignments:
if assignment.get_assignment_id() == assignment_id:
return True
return False
@@ -0,0 +1,57 @@
from src.domain.grade import Grade
from src.errors.errors import *
import json
class GradesRepo:
def __init__(self,path) -> None:
self.__path = path
self.grades = []
self.__load_from_file()
def __load_from_file(self) -> None:
with open(self.__path,"r") as f:
grades = json.load(f)
for grade in grades:
self.grades.append(Grade(grade["assignment_id"],grade["student_id"],grade["grade_value"]))
def __save_to_file(self) -> None:
grades = []
for grade in self.grades:
grades.append(grade.toJson())
with open(self.__path,"w") as f:
json.dump(grades,f,indent=4)
def add_grade(self, grade: Grade) -> None:
for grade_in_list in self.grades:
if grade_in_list.get_student_id() == grade.get_student_id() and grade_in_list.get_assignment_id() == grade.get_assignment_id():
raise GradeAlreadyExistsError("Grade already exists")
self.grades.append(grade)
self.__save_to_file()
def remove_grade(self, student_id: int, assignment_id: str) -> None:
for grade in self.grades:
if grade.get_student_id() == student_id and grade.get_assignment_id() == assignment_id:
self.grades.remove(grade)
self.__save_to_file()
return
raise GradeNotFoundError("Grade not found")
def update_grade(self, grade: Grade) -> None:
for grade_in_list in self.grades:
if grade_in_list.get_student_id() == grade.get_student_id() and grade_in_list.get_assignment_id() == grade.get_assignment_id():
if grade.get_grade_value() != None:
grade_in_list.set_grade_value(grade.get_grade_value())
self.__save_to_file()
return
else:
raise GradeValueAlreadySetError("Grade value already set")
raise GradeNotFoundError("Grade not found")
def list_grades(self) -> list[Grade]:
return self.grades
def is_a_grade(self, student_id: int, assignment_id: str) -> bool:
for grade in self.grades:
if grade.get_student_id() == student_id and grade.get_assignment_id() == assignment_id:
return True
return False
@@ -0,0 +1,74 @@
import json
from src.domain.student import Student
from src.errors.errors import *
class StudentsRepo():
"""
Class for the repository of students
Reads and writes from a json file
Attributes:
__path: the path to the json file
students: a list of students
Methods:
__load_from_file: loads the students from the json file
__save_to_file: saves the students to the json file
add_student: adds a student to the repository
remove_student: removes a student from the repository
update_student: updates a student from the repository
list_students: returns a list of students
is_a_student: returns True if the student is in the repository
"""
def __init__(self,path:str) -> None:
self.__path = path
self.students = []
self.__load_from_file()
def __load_from_file(self) -> None:
with open(self.__path,"r") as f:
students = json.load(f)
for student in students:
self.students.append(Student(student["student_id"],student["name"],student["group"]))
def __save_to_file(self) -> None:
students = []
for student in self.students:
students.append(student.toJson())
with open(self.__path,"w") as f:
json.dump(students,f,indent=4)
def add_student(self, student: Student) -> None:
if student.get_student_id() in [student.get_student_id() for student in self.students]:
raise StudentAlreadyExistsError("Student already exists")
self.students.append(student)
self.__save_to_file()
def remove_student(self, student_id: str) -> None:
for student in self.students:
if student.get_student_id() == student_id:
self.students.remove(student)
self.__save_to_file()
return
raise StudentNotFoundError("Student not found")
def update_student(self, student: Student) -> None:
for student_in_list in self.students:
if student_in_list.get_student_id() == student.get_student_id():
student_in_list.set_name(student.get_name())
student_in_list.set_group(student.get_group())
self.__save_to_file()
return
raise StudentNotFoundError("Student not found")
def list_students(self) -> list[Student]:
return self.students
def is_a_student(self,student_id:str) -> bool:
for student in self.students:
if student.get_student_id() == student_id:
return True
return False
@@ -0,0 +1,199 @@
from src.domain.student import Student
from src.domain.assignment import Assignment
from src.domain.grade import Grade
from src.errors.errors import *
from datetime import date
class Services:
def __init__(self, students_repo, assignments_repo, grades_repo) -> None:
self.__students_repo = students_repo
self.__assignments_repo = assignments_repo
self.__grades_repo = grades_repo
def add_student(self, student_id, name, group) -> None:
"""
Adds a student to the repository
:param student_id: the id of the student
:param name: the name of the student
:param group: the group of the student
:return: None
"""
student = Student(student_id, name, group)
self.__students_repo.add_student(student)
def remove_student(self, student_id) -> None:
"""
Removes a student from the repository
:param student_id: the id of the student
:return: None
"""
self.__students_repo.remove_student(student_id)
list_of_grades = self.__grades_repo.list_grades()
for grade in list_of_grades:
if grade.get_student_id() == student_id:
self.__grades_repo.remove_grade(grade.get_student_id(), grade.get_assignment_id())
def update_student(self, student_id, name, group) -> None:
"""
Updates a student from the repository
:param student_id: the id of the student
:param name: the name of the student
:param group: the group of the student
:return: None
"""
student = Student(student_id, name, group)
self.__students_repo.update_student(student)
def list_students(self) -> list[Student]:
"""
Returns a list of students
:return: a list of students
"""
return self.__students_repo.list_students()
def add_assignment(self, assignment_id, description, deadline) -> None:
"""
Adds an assignment to the repository
:param assignment_id: the id of the assignment
:param description: the description of the assignment
:param deadline: the deadline of the assignment
:return: None
"""
assignment = Assignment(assignment_id, description, deadline)
self.__assignments_repo.add_assignment(assignment)
def remove_assignment(self, assignment_id) -> None:
"""
Removes an assignment from the repository
:param assignment_id: the id of the assignment
:return: None
"""
self.__assignments_repo.remove_assignment(assignment_id)
list_of_grades = self.__grades_repo.list_grades()
for grade in list_of_grades:
if grade.get_assignment_id() == assignment_id:
self.__grades_repo.remove_grade(grade.get_student_id(), grade.get_assignment_id())
def update_assignment(self, assignment_id, description, deadline) -> None:
"""
Updates an assignment from the repository
:param assignment_id: the id of the assignment
:param description: the description of the assignment
:param deadline: the deadline of the assignment
:return: None
"""
assignment = Assignment(assignment_id, description, deadline)
self.__assignments_repo.update_assignment(assignment)
def list_assignments(self) -> list[Assignment]:
"""
Returns a list of assignments
:return: a list of assignments
"""
return self.__assignments_repo.list_assignments()
def give_assignment_to_student(self, student_id, assignment_id) -> None:
"""
Gives an assignment to a student
:param student_id: the id of the student
:param assignment_id: the id of the assignment
:return: None
"""
if not self.__students_repo.is_a_student(student_id):
raise StudentNotFoundError("Student not found")
if not self.__assignments_repo.is_an_assignment(assignment_id):
raise AssignmentNotFoundError("Assignment not found")
grade = Grade(assignment_id,student_id, None)
self.__grades_repo.add_grade(grade)
def give_assignment_to_group(self, group, assignment_id) -> None:
"""
Gives an assignment to all students in a group
:param group: the group of students
:param assignment_id: the id of the assignment
:return: None
"""
if not self.__assignments_repo.is_an_assignment(assignment_id):
raise AssignmentNotFoundError("Assignment not found")
students = self.__students_repo.list_students()
for student in students:
if student.get_group() == group:
grade = Grade(assignment_id,student.get_student_id(), None)
try:
self.__grades_repo.add_grade(grade)
except GradeAlreadyExistsError:
pass
def list_grades(self) -> list[Grade]:
return self.__grades_repo.list_grades()
def list_grades_for_student(self, student_id) -> list[Grade]:
grades = self.__grades_repo.list_grades()
grades_for_student = []
for grade in grades:
if grade.get_student_id() == student_id:
grades_for_student.append(grade)
return grades_for_student
def list_ungraded_assignments_for_student(self, student_id) -> list[Grade]:
if not self.__students_repo.is_a_student(student_id):
raise StudentNotFoundError("Student not found")
grades = self.__grades_repo.list_grades()
ungraded_assignments_for_student = []
ungraded_assignments_id_for_student=[]
for grade in grades:
if grade.get_student_id() == student_id and grade.get_grade_value() == None:
ungraded_assignments_id_for_student.append(grade.get_assignment_id())
assignments = self.__assignments_repo.list_assignments()
for assignment in assignments:
if assignment.get_assignment_id() in ungraded_assignments_id_for_student:
ungraded_assignments_for_student.append(assignment)
return ungraded_assignments_for_student
def add_grade(self, student_id, assignment_id, grade) -> None:
if not self.__students_repo.is_a_student(student_id):
raise StudentNotFoundError("Student not found")
if not self.__assignments_repo.is_an_assignment(assignment_id):
raise AssignmentNotFoundError("Assignment not found")
grade = Grade(assignment_id,student_id, grade)
self.__grades_repo.update_grade(grade)
def list_students_with_assignment(self,assignment_id) -> list[Student]:
students = self.__students_repo.list_students()
students_with_assignment = []
grades=sorted(self.__grades_repo.list_grades(), key=lambda grade: grade.get_grade_value() if grade.get_grade_value()!=None else 0 , reverse=True)
for grade in grades:
if grade.get_assignment_id() == assignment_id:
for student in students:
if student.get_student_id() == grade.get_student_id():
students_with_assignment.append(student)
return students_with_assignment
def list_students_late_on_assignment(self,assignment_id) -> list[Student]:
students = self.__students_repo.list_students()
students_late_on_assignment = []
grades= self.__grades_repo.list_grades()
for grade in grades:
if grade.get_assignment_id() == assignment_id and grade.get_grade_value() == None and self.__assignments_repo.get_assignment(assignment_id).get_deadline() < date.today():
for student in students:
if student.get_student_id() == grade.get_student_id() :
students_late_on_assignment.append(student)
return students_late_on_assignment
def list_students_best_school_situation(self) -> list[Student]:
students = self.__students_repo.list_students()
students_best_school_situation = []
grades=self.__grades_repo.list_grades()
for student in students:
sum_of_grades = 0
number_of_grades = 0
for grade in grades:
if grade.get_student_id() == student.get_student_id() and grade.get_grade_value() != None:
sum_of_grades += grade.get_grade_value()
number_of_grades += 1
if number_of_grades != 0:
average = sum_of_grades / number_of_grades
students_best_school_situation.append((student, average))
students_best_school_situation = [student for student, average in sorted(students_best_school_situation, key=lambda student: student[1], reverse=True)]
return students_best_school_situation
@@ -0,0 +1,262 @@
from src.errors.errors import *
from src.services.services import Services
from datetime import date
import re
class UI():
def __init__(self,service:Services) -> None:
self.__service = service
def __print_menu(self) -> None:
print("""
1.Manage students
2.Manage assignments
3.Manage grades
4.Statistics
0.Exit
""")
def __print_student_menu(self) -> None:
print("""
1.Add student
2.Remove student
3.Update student
4.List students
5.Back
""")
def __print_assignment_menu(self) -> None:
print("""
1.Add assignment
2.Remove assignment
3.Update assignment
4.List assignments
5.Give assignment to a student
6.Give assignment to a group of students
7.Back
""")
def __print_statistics_menu(self) -> None:
print("""
1.List students with a given assignment
2.List students late on an assignment
3.List students with the best school situation
4.Back
""")
def start(self) -> None:
while True:
self.__print_menu()
command = input("Enter command: ")
match command:
case "1":
self.__manage_students()
case "2":
self.__manage_assignments()
case "3":
self.__manage_grades()
case "4":
self.__statistics()
case "0":
break
case _:
print("Invalid command")
def __manage_students(self) -> None:
while True:
self.__print_student_menu()
command = input("Enter command: ")
match command:
case "1":
self.__add_student()
case "2":
self.__remove_student()
case "3":
self.__update_student()
case "4":
self.__list_students()
case "5":
break
case _:
print("Invalid command")
def __manage_assignments(self) -> None:
while True:
self.__print_assignment_menu()
command = input("Enter command: ")
match command:
case "1":
self.__add_assignment()
case "2":
self.__remove_assignment()
case "3":
self.__update_assignment()
case "4":
self.__list_assignments()
case "5":
self.__give_assignment_to_student()
case "6":
self.__give_assignment_to_group()
case "7":
break
case _:
print("Invalid command")
def __manage_grades(self) -> None:
try:
student_id = input("Enter student id: ")
ungraded_assignments = self.__service.list_ungraded_assignments_for_student(student_id)
if len(ungraded_assignments) == 0:
print("Student has no ungraded assignments")
return
for i,assignment in enumerate(ungraded_assignments):
print(f"{i+1}. {assignment}")
command = input("Enter assignment number: ")
if re.fullmatch("\d+",command) is None or int(command) < 1 or int(command) > len(ungraded_assignments):
print("Invalid command")
return
assignment = ungraded_assignments[int(command)-1]
grade = input("Enter grade: ")
if re.fullmatch("\d+(.\d)?+",grade) is None or float(grade) < 1 or float(grade) > 10:
print("Invalid grade")
return
self.__service.add_grade(student_id,assignment.get_assignment_id(),float(grade))
except StudentNotFoundError as e:
print(e)
def __statistics(self) -> None:
while True:
self.__print_statistics_menu()
command = input("Enter command: ")
match command:
case "1":
self.__list_students_with_assignment()
case "2":
self.__list_students_late_on_assignment()
case "3":
self.__list_students_best_school_situation()
case "4":
break
case _:
print("Invalid command")
def __add_student(self) -> None:
student_id = input("Enter student id: ")
name = input("Enter student name: ")
group = input("Enter student group: ")
if student_id == "" or name == "" or group == "":
print("Invalid student")
return
try:
self.__service.add_student(student_id, name, group)
except StudentAlreadyExistsError as e:
print(e)
def __remove_student(self) -> None:
student_id = input("Enter student id: ")
try:
self.__service.remove_student(student_id)
except StudentNotFoundError as e:
print(e)
def __update_student(self) -> None:
student_id = input("Enter student id: ")
name = input("Enter student name: ")
group = input("Enter student group: ")
if student_id == "" or name == "" or group == "":
print("Invalid student")
return
try:
self.__service.update_student(student_id, name, group)
except StudentNotFoundError as e:
print(e)
def __list_students(self) -> None:
students = self.__service.list_students()
for student in students:
print(student)
def __add_assignment(self) -> None:
assignment_id = input("Enter assignment id: ")
description = input("Enter assignment description: ")
day = input("Enter assignment deadline day: ")
month = input("Enter assignment deadline month: ")
year = input("Enter assignment deadline year: ")
if assignment_id == "" or description == "" or day == "" or month == "" or year == "":
print("Invalid assignment")
return
try:
deadline = date(int(year), int(month), int(day))
self.__service.add_assignment(assignment_id, description, deadline)
except AssignmentAlreadyExistsError as e:
print(e)
except ValueError as e:
print("Invalid date")
def __remove_assignment(self) -> None:
assignment_id = input("Enter assignment id: ")
try:
self.__service.remove_assignment(assignment_id)
except AssignmentNotFoundError as e:
print(e)
def __update_assignment(self) -> None:
assignment_id = input("Enter assignment id: ")
description = input("Enter assignment description: ")
day = input("Enter assignment deadline day: ")
month = input("Enter assignment deadline month: ")
year = input("Enter assignment deadline year: ")
if assignment_id == "" or description == "" or day == "" or month == "" or year == "":
print("Invalid assignment")
return
try:
deadline = date(int(year), int(month), int(day))
self.__service.update_assignment(assignment_id, description, deadline)
except AssignmentNotFoundError as e:
print(e)
except ValueError as e:
print("Invalid date")
def __list_assignments(self) -> None:
assignments = self.__service.list_assignments()
for assignment in assignments:
print(assignment)
def __give_assignment_to_student(self) -> None:
student_id = input("Enter student id: ")
assignment_id = input("Enter assignment id: ")
try:
self.__service.give_assignment_to_student(student_id, assignment_id)
except StudentNotFoundError as e:
print(e)
except AssignmentNotFoundError as e:
print(e)
except GradeAlreadyExistsError as e:
print(e)
def __give_assignment_to_group(self) -> None:
group = input("Enter group: ")
assignment_id = input("Enter assignment id: ")
try:
self.__service.give_assignment_to_group(group, assignment_id)
except AssignmentNotFoundError as e:
print(e)
def __list_students_with_assignment(self) -> None:
assignment_id = input("Enter assignment id: ")
students = self.__service.list_students_with_assignment(assignment_id)
for student in students:
print(student)
def __list_students_late_on_assignment(self) -> None:
assignment_id = input("Enter assignment id: ")
students = self.__service.list_students_late_on_assignment(assignment_id)
for student in students:
print(student)
def __list_students_best_school_situation(self) -> None:
students = self.__service.list_students_best_school_situation()
for student in students:
print(student)
@@ -0,0 +1,48 @@
import unittest
from datetime import date
from src.services.services import Services
from src.repository.students_repo import StudentsRepo
from src.repository.assignments_repo import AssignmentsRepo
from src.repository.grades_repo import GradesRepo
class Tester(unittest.TestCase):
def __init__(self, methodName: str = ...) -> None:
super().__init__(methodName)
def setUp(self) -> None:
self.service = Services(StudentsRepo("tests/test_students_file.json"), AssignmentsRepo("tests/test_assignments_file.json"), GradesRepo("tests/test_grades_file.json"))
def tearDown(self) -> None:
return super().tearDown()
def test_student_repo(self):
self.service.add_student("1","John", "911")
self.assertEqual(self.service.list_students()[0].get_name(), "John")
self.assertEqual(self.service.list_students()[0].get_student_id(), "1")
self.assertEqual(self.service.list_students()[0].get_group(), "911")
self.service.update_student("1", "Jack", "912")
self.assertEqual(self.service.list_students()[0].get_name(), "Jack")
self.assertEqual(self.service.list_students()[0].get_student_id(), "1")
self.assertEqual(self.service.list_students()[0].get_group(), "912")
self.service.remove_student("1")
self.assertEqual(len(self.service.list_students()), 0)
def test_assignment_repo(self):
self.service.add_assignment("1", "Assignment 1", date(2021, 2, 1))
self.assertEqual(self.service.list_assignments()[0].get_assignment_id(), "1")
self.assertEqual(self.service.list_assignments()[0].get_description(), "Assignment 1")
self.assertEqual(self.service.list_assignments()[0].get_deadline(), date(2021, 2, 1))
self.service.update_assignment("1", "Assignment 2", date(2021, 2, 2))
self.assertEqual(self.service.list_assignments()[0].get_assignment_id(), "1")
self.assertEqual(self.service.list_assignments()[0].get_description(), "Assignment 2")
self.assertEqual(self.service.list_assignments()[0].get_deadline(), date(2021, 2, 2))
self.service.remove_assignment("1")
self.assertEqual(len(self.service.list_assignments()), 0)
if __name__ == '__main__':
unittest.main()
#python -m unittest discover -v -s tests -p "*test*.py"