Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add load specific answer from answer file using student name #100

Merged
merged 1 commit into from
Dec 18, 2024
Merged
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
66 changes: 51 additions & 15 deletions src/scwidgets/exercise/_widget_exercise_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def load(self) -> Union[str, Exception]:
raise ValueError(
"No exercise key given on initialization, save cannot be used"
)
return self._exercise_registry.load_answer(self._exercise_key)
return self._exercise_registry.load_answer_from_loaded_file(self._exercise_key)

@property
def exercise_registry(self):
Expand Down Expand Up @@ -341,26 +341,65 @@ def create_new_file_from_student_name(self, student_name: str):

self._loaded_file_name = answers_filename

def load_answer(self, exercise_key: Hashable) -> str:
def load_answer_from_student_name(
self, student_name: str, exercise_key: Union[Hashable, ExerciseWidget]
):
"""
Only works when file has been loaded
Loads the answer with key `exercise_key` from the file corresponding to
`student_name`.

:param exercise_key:
unique exercise key for widget to store, so it can be reloaded persistently
after a restart of the python kernel
:raises KeyError: Corresponding widget to exercise_key cannot be found
:raises KeyError: Corresponding key in file cannot be found
:raises FileNotFoundError: If the file cannot be found
:param student_name: The name of the student
:param exercise_key: Unique exercise key for widget to store, so it can
be reloaded persistently after a restart of the python kernel
"""
self.load_answer(self.get_answer_filename(student_name), exercise_key)

def load_answer_from_loaded_file(
self, exercise_key: Union[Hashable, ExerciseWidget]
) -> str:
"""
Loads the answer with key `exercise_key` from the currently loaded file.

:raises ValueError: No have has been loaded
:raises KeyError: Corresponding widget to exercise_key cannot be found
:raises KeyError: Corresponding key in file cannot be found
:raises FileNotFoundError: If the file cannot be found
:param exercise_key: Unique exercise key for widget to store, so it can
be reloaded persistently after a restart of the python kernel
"""
if self._loaded_file_name is None:
raise ValueError("No file has been loaded.")

self.load_answer(self._loaded_file_name, exercise_key)
return f"Exercise has been loaded from file {self._loaded_file_name!r}."

def load_answer(
self, answers_filename: str, exercise_key: Union[Hashable, ExerciseWidget]
):
"""
Loads the answer with key `exercise_key` from the `answer_filename`.

:raises KeyError: Corresponding widget to exercise_key cannot be found
:raises KeyError: Corresponding key in file cannot be found
:raises FileNotFoundError: If the file cannot be found
:param answers_filename: The file with the answer
:param exercise_key: Unique exercise key for widget to store, so it can
be reloaded persistently after a restart of the python kernel
"""
if isinstance(exercise_key, ExerciseWidget):
exercise_key = exercise_key.exercise_key

if exercise_key not in self._widgets.keys():
raise KeyError(
f"There is no widget registered with exercise key {exercise_key!r}."
)
if self._loaded_file_name is None:
raise ValueError("No file has been selected in the dropdown list.")

answers_filename = self._loaded_file_name

if not (os.path.exists(answers_filename)):
raise FileNotFoundError(
"Selected file does not exist anymore. Maybe you have renamed "
f"The file {answers_filename!r} does not exist. Maybe you have renamed "
"or deleted it? Please choose another file or create a new one."
)

Expand All @@ -375,9 +414,6 @@ def load_answer(self, exercise_key: Hashable) -> str:
else:
self._widgets[exercise_key].answer = answers[exercise_key]
self._loaded_file_name = answers_filename
return f"Exercise has been loaded from file {answers_filename!r}."

self._answers_files_dropdown.value

def load_file_from_dropdown(self) -> str:
"""
Expand Down Expand Up @@ -410,7 +446,7 @@ def load_file(self, answers_filename: str):

if not (os.path.exists(answers_filename)):
raise FileNotFoundError(
"Selected file does not exist anymore. Maybe you have renamed "
f"The file {answers_filename!r} does not exist. Maybe you have renamed "
"or deleted it? Please choose another file or create a new one."
)

Expand Down
28 changes: 18 additions & 10 deletions tests/test_answer.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ def test_load_file_from_dropdown(self):
# Tests if error is raised on moved file
os.rename(f"{self.prefix}-{self.student_name}.json", "tmp.json")
with pytest.raises(
FileNotFoundError, match=r".*Selected file does not exist anymore.*"
FileNotFoundError,
match=r".*The file 'pytest-test-answer-registry.json' does not exist.*",
):
answer_registry.load_file_from_dropdown()
os.rename("tmp.json", f"{self.prefix}-{self.student_name}.json")
Expand All @@ -236,18 +237,26 @@ def test_load_file_from_dropdown(self):
assert answer_widget_1.answer == "update_1"
assert answer_widget_2.answer == "update_2"

def test_load_answer(self):
def test_load_answer_from_loaded_file(self):
answers = {"exercise_1": "answer_1", "exercise_2": "answer_2"}
with open(f"{self.prefix}-{self.student_name}.json", "w") as answer_file:
json.dump(answers, answer_file)

answer_registry = ExerciseRegistry(filename_prefix=self.prefix)
with pytest.raises(
ValueError,
match=r".*No file has been loaded*",
):
answer_registry.load_answer_from_loaded_file("notkey")

# To avoid the no loaded file error
answer_registry._loaded_file_name = "some"
with pytest.raises(
KeyError,
match=r".*There is no widget registered with exercise key 'notkey'.*",
):
answer_registry.load_answer("notkey")
answer_registry.load_answer_from_loaded_file("notkey")
answer_registry._loaded_file_name = None

exercise_key_1 = "exercise_1"
answer_widget_1 = mock_answer_widget(answer_registry, exercise_key_1)
Expand All @@ -259,10 +268,8 @@ def test_load_answer(self):
answer_registry._answers_files_dropdown.value = (
answer_registry._create_new_file_dropdown_option()
)
with pytest.raises(
ValueError, match=r".*No file has been selected in the dropdown list.*"
):
answer_registry.load_answer(exercise_key_1)
with pytest.raises(ValueError, match=r".*No file has been loaded.*"):
answer_registry.load_answer_from_loaded_file(exercise_key_1)
# select back file to load
answer_registry._answers_files_dropdown.value = (
f"{self.prefix}-{self.student_name}.json"
Expand All @@ -272,15 +279,16 @@ def test_load_answer(self):
# Tests if error is raised on moved file
os.rename(f"{self.prefix}-{self.student_name}.json", "tmp.json")
with pytest.raises(
FileNotFoundError, match=r".*Selected file does not exist anymore.*"
FileNotFoundError,
match=r".*The file 'pytest-test-answer-registry.json' does not exist.*",
):
answer_registry.load_answer(exercise_key_1)
answer_registry.load_answer_from_loaded_file(exercise_key_1)
os.rename("tmp.json", f"{self.prefix}-{self.student_name}.json")

# Test that file is contains only the updated answer
answer_widget_1.answer = "update_1"
answer_widget_2.answer = "update_2"
result = answer_registry.load_answer(exercise_key_1)
result = answer_registry.load_answer_from_loaded_file(exercise_key_1)
assert (
result == "Exercise has been loaded from file "
"'pytest-test-answer-registry.json'."
Expand Down
Loading