diff --git a/src/scwidgets/exercise/_widget_code_exercise.py b/src/scwidgets/exercise/_widget_code_exercise.py index 74d8f4f..c7b5383 100644 --- a/src/scwidgets/exercise/_widget_code_exercise.py +++ b/src/scwidgets/exercise/_widget_code_exercise.py @@ -40,7 +40,14 @@ class CodeExercise(VBox, CheckableWidget, ExerciseWidget): A function or CodeInput that is the input of code :param check_registry: - a check registry that is used to register checks + A check registry that is used to register checks + + :param exercise_registry: + A exercise registry that is used to register the answers to save them + later. If specified the save and load panel will appear. + + :param key: + The key that is used to store the exercise in the json file. :param parameters: Input parameters for the :py:class:`ParametersPanel` class or an initialized @@ -58,6 +65,12 @@ class CodeExercise(VBox, CheckableWidget, ExerciseWidget): A function that is run during the update process. The function takes as argument the CodeExercise, so it can update all cue_ouputs + :param description: + A string describing the exercises that will be put into an HTML widget + above the exercise. + + :param title: + A title for the exercise. If not given the key is used. """ def __init__( @@ -65,7 +78,7 @@ def __init__( code: Union[None, WidgetCodeInput, types.FunctionType] = None, check_registry: Optional[CheckRegistry] = None, exercise_registry: Optional[ExerciseRegistry] = None, - exercise_key: Optional[str] = None, + key: Optional[str] = None, parameters: Optional[ Union[Dict[str, Union[Check.FunInParamT, Widget]], ParametersPanel] ] = None, @@ -77,8 +90,8 @@ def __init__( Callable[[], Union[Any, Check.FunOutParamsT]], ] ] = None, - exercise_description: Optional[str] = None, - exercise_title: Optional[str] = None, + description: Optional[str] = None, + title: Optional[str] = None, *args, **kwargs, ): @@ -117,26 +130,26 @@ def __init__( else: self._update_func_nb_nondefault_args = None - self._exercise_description = exercise_description - if exercise_description is None: - self._exercise_description_html = None + self._description = description + if description is None: + self._description_html = None else: - self._exercise_description_html = HTMLMath(self._exercise_description) - if exercise_title is None: - if exercise_key is None: - self._exercise_title = None - self._exercise_title_html = None + self._description_html = HTMLMath(self._description) + if title is None: + if key is None: + self._title = None + self._title_html = None else: - self._exercise_title = exercise_key - self._exercise_title_html = HTML(f"{exercise_key}") + self._title = key + self._title_html = HTML(f"{key}") else: - self._exercise_title = exercise_title - self._exercise_title_html = HTML(f"{exercise_title}") + self._title = title + self._title_html = HTML(f"{title}") - if self._exercise_description_html is not None: - self._exercise_description_html.add_class("exercise-description") - if self._exercise_title_html is not None: - self._exercise_title_html.add_class("exercise-title") + if self._description_html is not None: + self._description_html.add_class("exercise-description") + if self._title_html is not None: + self._title_html.add_class("exercise-title") # verify if input argument `parameter` is valid if parameters is not None: @@ -176,10 +189,10 @@ def __init__( "code and parameters do no match: " + compatibility_result ) - name = kwargs.get("name", exercise_key) + name = kwargs.get("name", key) CheckableWidget.__init__(self, check_registry, name) if exercise_registry is not None: - ExerciseWidget.__init__(self, exercise_registry, exercise_key) + ExerciseWidget.__init__(self, exercise_registry, key) else: # otherwise ExerciseWidget constructor will raise an error ExerciseWidget.__init__(self, None, None) @@ -464,10 +477,10 @@ def __init__( ) demo_children = [CssStyle()] - if self._exercise_title_html is not None: - demo_children.append(self._exercise_title_html) - if self._exercise_description_html is not None: - demo_children.append(self._exercise_description_html) + if self._title_html is not None: + demo_children.append(self._title_html) + if self._description_html is not None: + demo_children.append(self._description_html) if self._cue_code is not None: demo_children.append(self._cue_code) @@ -584,12 +597,12 @@ def parameters(self) -> Dict[str, Check.FunInParamT]: ) @property - def exercise_title(self) -> Union[str, None]: - return self._exercise_title + def title(self) -> Union[str, None]: + return self._title @property - def exercise_description(self) -> Union[str, None]: - return self._exercise_description + def description(self) -> Union[str, None]: + return self._description def _on_trait_parameters_changed(self, change: dict): self.run_update() diff --git a/src/scwidgets/exercise/_widget_text_exercise.py b/src/scwidgets/exercise/_widget_text_exercise.py index ddac8c5..e2a9aea 100644 --- a/src/scwidgets/exercise/_widget_text_exercise.py +++ b/src/scwidgets/exercise/_widget_text_exercise.py @@ -14,39 +14,47 @@ class TextExercise(VBox, ExerciseWidget): a custom textarea with custom styling, if not specified the standard parameters are given. - the (keyword) arguments are passed to VBox + :param key: + The key that is used to store the exercise in the json file. + + :param description: + A string describing the exercises that will be put into an HTML widget + above the exercise. + + :param title: + A title for the exercise. If not given the key is used. """ def __init__( self, value: Optional[str] = None, - exercise_key: Optional[str] = None, + key: Optional[str] = None, exercise_registry: Optional[ExerciseRegistry] = None, - exercise_description: Optional[str] = None, - exercise_title: Optional[str] = None, + description: Optional[str] = None, + title: Optional[str] = None, *args, **kwargs, ): - self._exercise_description = exercise_description - if exercise_description is None: - self._exercise_description_html = None + self._description = description + if description is None: + self._description_html = None else: - self._exercise_description_html = HTMLMath(self._exercise_description) - if exercise_title is None: - if exercise_key is None: - self._exercise_title = None - self._exercise_title_html = None + self._description_html = HTMLMath(self._description) + if title is None: + if key is None: + self._title = None + self._title_html = None else: - self._exercise_title = exercise_key - self._exercise_title_html = HTML(f"{exercise_key}") + self._title = key + self._title_html = HTML(f"{key}") else: - self._exercise_title = exercise_title - self._exercise_title_html = HTML(f"{exercise_title}") + self._title = title + self._title_html = HTML(f"{title}") - if self._exercise_description_html is not None: - self._exercise_description_html.add_class("exercise-description") - if self._exercise_title_html is not None: - self._exercise_title_html.add_class("exercise-title") + if self._description_html is not None: + self._description_html.add_class("exercise-description") + if self._title_html is not None: + self._title_html.add_class("exercise-title") layout = kwargs.pop("layout", Layout(width="auto", height="150px")) self._textarea = Textarea(value, *args, layout=layout, **kwargs) @@ -98,13 +106,13 @@ def __init__( layout=Layout(justify_content="flex-end"), ) - ExerciseWidget.__init__(self, exercise_registry, exercise_key) + ExerciseWidget.__init__(self, exercise_registry, key) widget_children = [CssStyle()] - if self._exercise_title_html is not None: - widget_children.append(self._exercise_title_html) - if self._exercise_description_html is not None: - widget_children.append(self._exercise_description_html) + if self._title_html is not None: + widget_children.append(self._title_html) + if self._description_html is not None: + widget_children.append(self._description_html) widget_children.append(self._cue_textarea) if self._button_panel: widget_children.append(self._button_panel) @@ -117,12 +125,12 @@ def __init__( ) @property - def exercise_title(self) -> Union[str, None]: - return self._exercise_title + def title(self) -> Union[str, None]: + return self._title @property - def exercise_description(self) -> Union[str, None]: - return self._exercise_description + def description(self) -> Union[str, None]: + return self._description @property def answer(self) -> dict: diff --git a/tests/notebooks/widget_answers.py b/tests/notebooks/widget_answers.py index e49cf34..d9cae12 100644 --- a/tests/notebooks/widget_answers.py +++ b/tests/notebooks/widget_answers.py @@ -36,9 +36,7 @@ # ------- # Test if TextExercise shows correct output -text_exercise = TextExercise( - exercise_registry=exercise_registry, exercise_key="exercise_1" -) +text_exercise = TextExercise(exercise_registry=exercise_registry, key="exercise_1") text_exercise # Test 3: @@ -56,7 +54,7 @@ def foo(x): parameters={"x": (0, 2, 1)}, update_mode="manual", exercise_registry=exercise_registry, - exercise_key="exercise_2", + key="exercise_2", ) code_ex # - diff --git a/tests/test_code.py b/tests/test_code.py index 433115f..601c3f2 100644 --- a/tests/test_code.py +++ b/tests/test_code.py @@ -359,7 +359,7 @@ def print_success(code_ex: CodeExercise | None): code=function, parameters={"parameter": fixed(5)}, exercise_registry=exercise_registry, - exercise_key="test_save_registry_ex", + key="test_save_registry_ex", outputs=[cue_output], update=print_success, ) @@ -431,15 +431,15 @@ def test_consrtuction_with_registries(self): `CheckRegistry` we need to ensure the `CodeExercise` can be run with each individual one and both""" CodeExercise( - exercise_key="some_key", + key="some_key", check_registry=CheckRegistry(), ) CodeExercise( - exercise_key="some_key", + key="some_key", exercise_registry=ExerciseRegistry(), ) CodeExercise( - exercise_key="some_key", + key="some_key", check_registry=CheckRegistry(), exercise_registry=ExerciseRegistry(), )