Source code for scwidgets.exercise._widget_text_exercise

from typing import Optional, Union

from ipywidgets import HTML, HBox, HTMLMath, Layout, Output, Textarea, VBox

from .._utils import Formatter
from ..css_style import CssStyle
from ..cue import SaveCueBox, SaveResetCueButton
from ._widget_exercise_registry import ExerciseRegistry, ExerciseWidget


[docs] class TextExercise(VBox, ExerciseWidget): """ :param textarea: a custom textarea with custom styling, if not specified the standard parameters are given. :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, key: Optional[str] = None, exercise_registry: Optional[ExerciseRegistry] = None, description: Optional[str] = None, title: Optional[str] = None, *args, **kwargs, ): self._description = description if description is None: self._description_html = None else: self._description_html = HTMLMath(self._description) if title is None: if key is None: self._title = None self._title_html = None else: self._title = key self._title_html = HTML(f"<b>{key}</b>") else: self._title = title self._title_html = HTML(f"<b>{title}</b>") 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) self._cue_textarea = self._textarea self._output = Output() if exercise_registry is None: self._save_button = None self._load_button = None self._button_panel = None else: self._cue_textarea = SaveCueBox( self._textarea, "value", self._cue_textarea, cued=True ) self._save_button = SaveResetCueButton( self._cue_textarea, self._on_click_save_action, disable_on_successful_action=kwargs.pop( "disable_save_button_on_successful_action", False ), disable_during_action=kwargs.pop( "disable_save_button_during_action", True ), description="Save answer", button_tooltip="Saves answer to the loaded file", ) self._cue_code = SaveCueBox( self._textarea, "value", self._cue_textarea, cued=True ) self._load_button = SaveResetCueButton( self._cue_textarea, self._on_click_load_action, disable_on_successful_action=kwargs.pop( "disable_load_button_on_successful_action", False ), disable_during_action=kwargs.pop( "disable_load_button_during_action", True ), description="Load answer", button_tooltip="Loads answer from the loaded file", ) # click on load button resets cue of save buton and vise-versa self._save_button.set_cue_widgets([self._cue_textarea, self._load_button]) self._load_button.set_cue_widgets([self._cue_textarea, self._save_button]) self._button_panel = HBox( [self._save_button, self._load_button], layout=Layout(justify_content="flex-end"), ) ExerciseWidget.__init__(self, exercise_registry, key) widget_children = [CssStyle()] 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) widget_children.append(self._output) VBox.__init__( self, widget_children, ) @property def title(self) -> Union[str, None]: return self._title @property def description(self) -> Union[str, None]: return self._description @property def answer(self) -> dict: return {"textarea": self._textarea.value} @answer.setter def answer(self, answer: dict): # this function should only be used by the AnsweRegistry to set value # because we don't want to cue if a loading changes the the value we disable it if hasattr(self._cue_textarea, "unobserve_widgets"): self._cue_textarea.unobserve_widgets() if self._save_button is not None: self._save_button.unobserve_widgets() if self._load_button is not None: self._load_button.unobserve_widgets() self._textarea.value = answer["textarea"] if hasattr(self._cue_textarea, "unobserve_widgets"): self._cue_textarea.observe_widgets() if self._save_button is not None: self._save_button.observe_widgets() if self._load_button is not None: self._load_button.observe_widgets() def _on_click_save_action(self) -> bool: self._output.clear_output(wait=True) raised_error = False with self._output: try: result = self.save() if isinstance(result, str): print(Formatter.color_success_message(result)) elif isinstance(result, Exception): raise result else: print(result) except Exception as e: print(Formatter.color_error_message("Error raised while saving file:")) raised_error = True raise e return not (raised_error) def _on_click_load_action(self) -> bool: self._output.clear_output(wait=True) raised_error = False with self._output: try: result = self.load() if isinstance(result, str): print(Formatter.color_success_message(result)) elif isinstance(result, Exception): raise result else: print(result) return True except Exception as e: print(Formatter.color_error_message("Error raised while loading file:")) raised_error = True raise e return not (raised_error)
[docs] def handle_save_result(self, result: Union[str, Exception]) -> None: self._output.clear_output(wait=True) with self._output: if isinstance(result, Exception): print(Formatter.color_error_message("Error raised while saving file:")) raise result else: # answer changes, so we have to disable the automatic cueing if self._load_button is not None: self._load_button.cued = False if self._save_button is not None: self._save_button.cued = False if self._cue_textarea is not None: self._cue_textarea.cued = False print(Formatter.color_success_message(result))
[docs] def handle_load_result(self, result: Union[str, Exception]) -> None: self._output.clear_output(wait=True) with self._output: if isinstance(result, Exception): print(Formatter.color_error_message("Error raised while loading file:")) raise result else: if self._load_button is not None: self._load_button.cued = False if self._save_button is not None: self._save_button.cued = False if self._cue_textarea is not None: self._cue_textarea.cued = False print(Formatter.color_success_message(result))