Source code for questions.questions

from typing import Any
from typing import Dict
from typing import List
from typing import Union
from pydantic import BaseModel
from pydantic import Extra
from pydantic import HttpUrl

try:
    from typing import Literal
except ImportError:  # pragma: NO COVER
    from typing_extensions import Literal

from . import settings
from .utils import get_params_for_repr


class _Base(BaseModel):
    """Base class for questions classes. Main responsibility is renaming
    Python parameter names to Javascript's camelCase convention."""

    def __repr__(self):
        class_name = self.__class__.__name__
        params = get_params_for_repr(dict(self))
        return f"{class_name}({params}\n    )"

    class Config:
        fields = {
            "kind": "type",
            "all_rows_required": "isAllRowRequired",
            "expression_format": "format",
            "max_value": "max",
            "min_value": "min",
            "required": "isRequired",
        }

        @classmethod
        def fix_name(cls, name):
            words = name.split("_")
            name = ""
            for index, word in enumerate(words):
                if index == 0:
                    name += word
                else:
                    name += word.capitalize()
            return name

        extra = Extra.allow
        alias_generator = fix_name


[docs]class Validator(_Base): """Base class for all validators.""" kind: str message: str = "Invalid value"
[docs]class TextValidator(Validator): """Validator for text input.""" kind: str = "text" max_length: int = 0 min_length: int = 0 allow_digits: bool = True
[docs]class NumericValidator(Validator): """Validator for numeric input.""" kind: str = "numeric" max_value: int = 0 min_value: int = 0
[docs]class EmailValidator(Validator): """Checks if a value is a valid email address.""" kind: str = "email"
[docs]class RegexValidator(Validator): """Checks if a value matches a regular expression.""" kind: str = "regex" regex: str = ""
[docs]class ExpressionValidator(Validator): """Checks if a question's answer matches a set of conditions.""" kind: str = "regex" expression: str = ""
[docs]class Question(_Base): """ Base question class. All questions share these properties, and all can be set by passing them as parameters when instantiating the question. """ kind: str name: str = "" title: Union[str, Dict[str, str]] = "" description: Union[str, Dict[str, str]] = "" required: bool = False visible: bool = True default_value: str = "" correct_answer: str = "" visible_if: str = "" enable_if: str = "" start_with_new_line: bool = True value_name: str = "" required_if: str = "" required_error_text: str = "" hide_number: bool = True indent: int = 0 title_location: Literal[settings.TITLE_LOCATIONS] = "default" description_location: Literal[settings.DESCRIPTION_LOCATIONS] = "default" width: str = "" max_width: str = "initial" min_width: str = "300px" use_display_values_in_title: bool = True validators: List[Validator] = [] extra_js: List[HttpUrl] = [] extra_css: List[HttpUrl] = []
[docs]class TextQuestion(Question): """ A question that uses a text input box. It can handle all HTML5 text input types. """ kind: str = "text" place_holder: Union[str, Dict[str, str]] = "" input_type: Literal[settings.TEXT_INPUT_TYPES] = "text" max_length: int = -1 max_value: str = "" min_value: str = "" size: int = 0 step: str = "" text_update_mode: Literal[settings.TEXT_UPDATE_MODES] = "default" input_mask: str = "" input_format: str = "" prefix: str = "" auto_unmask: bool = True extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/inputmask@5.0.3/dist/inputmask.js", ]
[docs]class ChoicesQuestion(Question): """ Base class for questions that let the user select one or more options from a list of choices. The choices can either be set at question instantiation time, or come from a JSON web service at run time. """ kind: str = "" col_count: int = 4 choices: List[Union[str, Dict[str, Union[str, HttpUrl, Dict[str, str]]]]] = [] choices_by_url: Dict[Literal[settings.CHOICES_BY_URL_KEYS], str] = [] choices_order: Literal[settings.CHOICE_ORDER_VALUES] = "none" choices_enable_if: str = "" choices_visible_if: str = "" hide_if_choices_empty: bool = True has_other: bool = False other_text: Union[str, Dict[str, str]] = "Other" other_error_text: Union[str, Dict[str, str]] = "" other_place_holder: Union[str, Dict[str, str]] = ""
[docs]class RadioGroupQuestion(ChoicesQuestion): """ Select one option from a group of radio buttons. """ kind: str = "radiogroup" show_clear_button: bool = False
[docs]class CheckboxQuestion(ChoicesQuestion): """ Select one or more options from a group of check boxes. """ kind: str = "checkbox" has_none: bool = False has_select_all: bool = False none_text: Union[str, Dict[str, str]] = "None" select_all_text: Union[str, Dict[str, str]] = ""
[docs]class ImagePickerQuestion(ChoicesQuestion): """ Display a group of images and let the user pick one or more. """ kind: str = "imagepicker" content_mode: Literal[settings.IMAGE_CONTENT_MODE_VALUES] = "image" show_label: bool = False image_height: int = 200 image_width: int = 300 image_fit: Literal[settings.IMAGE_FIT_VALUES] = "none" multi_select: bool = False has_other: bool = False other_text: Union[str, Dict[str, str]] = "Other" other_error_text: Union[str, Dict[str, str]] = "" other_place_holder: Union[str, Dict[str, str]] = ""
[docs]class BooleanQuestion(Question): """ Get the answer for any two-possibility question. Usually true/false, yes/ no questions. """ kind: str = "boolean" label_true: Union[str, Dict[str, str]] = "" label_false: Union[str, Dict[str, str]] = "" show_title: bool = False value_true: Union[str, Dict[str, str]] = "true" value_false: Union[str, Dict[str, str]] = "false"
[docs]class SignaturePadQuestion(Question): """ Allow the user to "sign" something by drawing their signature. Can be used to capture user drawings for other types of questions. """ kind: str = "signaturepad" height: int = 200 width: int = 300 allow_clear: bool = True
[docs]class MultipleTextQuestion(Question): """ A text question with multiple related parts. Displays a text box for each part. """ kind: str = "multipletext" col_count: int = 2 items: List[Dict[str, str]] = [] item_size: int = 0
[docs]class CommentQuestion(Question): """ A question that uses a text area to get a multi-line text answer. """ kind: str = "comment" rows: int = 3 cols: int = 50 max_length: int = -1 place_holder: Union[str, Dict[str, str]] = "" text_update_mode: Literal[settings.TEXT_UPDATE_MODES] = "default"
[docs]class RatingQuestion(Question): """ A question that lets the user select a number on a fixed scale. """ kind: str = "rating" min_rate_description: Union[str, Dict[str, str]] = "" max_rate_description: Union[str, Dict[str, str]] = "" rate_max: int = 5 rate_min: int = 1 rate_step: int = 1 rate_values: List[Union[int, Dict[str, Union[int, str]]]] = []
[docs]class FileQuestion(Question): """ A question for uploading one or more files. """ kind: str = "file" show_preview: bool = True allow_multiple: bool = False store_data_as_text: bool = True image_height: int = 100 image_width: int = 150 max_size: int = 0 accepted_types: str = "" allow_images_preview: bool = True need_confirm_remove_file: bool = False wait_for_upload: bool = True
[docs]class MatrixQuestion(Question): """ A question that displays rows of radio buttons and allows the user to select a value from one of several columns for each row. """ kind: str = "matrix" columns: List[Any] rows: List[Any] = [] all_rows_required: bool = False cells: Dict[str, Dict[str, str]] = {} columns_visible_if: str = "" rows_order: Literal[settings.ROW_ORDER_VALUES] = "initial" rows_visible_if: str = "" show_header: bool = True
[docs]class MatrixDropdownQuestion(Question): """ A matrix question that can include other types of input controls, like dropdowns and text boxes. """ kind: str = "matrixdropdown" columns: List[Any] rows: List[Any] = [] all_rows_required: bool = False cells: Dict[str, Dict[str, Any]] = {} columns_visible_if: str = "" rows_order: Literal[settings.ROW_ORDER_VALUES] = "initial" rows_visible_if: str = "" show_header: bool = True cell_type: Literal[settings.MATRIX_CELL_TYPES] = "dropdown" choices: List[Any] = [] column_col_count: int = 1 column_layout: Literal[settings.MATRIX_COLUMN_LAYOUTS] = "horizontal" column_min_width: str = "" horizontal_scroll: bool = False options_caption: str = "" row_title_width: str = "" total_text: str = ""
[docs]class MatrixDynamicQuestion(Question): """ A matrix dropdown question that allows the user to add or remove new rows from their answer. """ kind: str = "matrixdynamic" columns: List[Any] rows: List[Any] = [] all_rows_required: bool = False cells: Dict[str, Dict[str, Any]] = {} columns_visible_if: str = "" rows_order: Literal[settings.ROW_ORDER_VALUES] = "initial" rows_visible_if: str = "" show_header: bool = True cell_type: Literal[settings.MATRIX_CELL_TYPES] = "dropdown" choices: List[Any] = [] column_col_count: int = 1 column_layout: Literal[settings.MATRIX_COLUMN_LAYOUTS] = "horizontal" column_min_width: str = "" horizontal_scroll: bool = False options_caption: str = "" add_row_location: Literal[settings.MATRIX_ROW_LOCATIONS] = "default" add_row_text: str = "" allow_add_rows: bool = True allow_remove_rows: bool = True confirm_delete: bool = False confirm_delete_text: str = "" default_row_value: Any = "" default_value_from_last_row: bool = False key_duplication_error: str = "" key_name: str = "" max_row_count: int = 100 min_row_count: int = 1 remove_row_text: str = "" row_count: int = 1
[docs]class TagBoxQuestion(DropdownQuestion): """ A question that uses the Select2 tag box widget. """ kind: str = "tagbox" select2_config: str = "" extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/js/select2.min.js", ] extra_css: List[HttpUrl] = [ "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/css/select2.min.css", ]
[docs]class JQueryUIDatePickerQuestion(TextQuestion): """ A question that uses the JQueryUI date picker. """ kind: str = "datepicker" date_format: str = "mm/dd/yy" config: str = "" max_date: str = "" min_date: str = "" extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://code.jquery.com/ui/1.11.4/jquery-ui.min.js", ] extra_css: List[HttpUrl] = [ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/smoothness/jquery-ui.css", ]
[docs]class BootstrapDatePickerQuestion(TextQuestion): """ A question that uses the bootstrap date picker. """ kind: str = "bootstrapdatepicker" date_format: str = "mm/dd/yy" start_date: str = "" end_date: str = "" today_highlight: bool = True week_start: int = 0 clear_button: bool = False auto_close: bool = True days_of_week_highlighted: str = "" disable_touch_keyboard: bool = True extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/moment@2.24.0/moment.js", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.js", ] extra_css: List[HttpUrl] = [ "https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css", ]
[docs]class Select2Question(DropdownQuestion): """ A question that uses the Select2 dropdown widget. """ render_as: str = "select2" select2_config: str = "" extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/js/select2.min.js", ] extra_css: List[HttpUrl] = [ "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/css/select2.min.css", ]
[docs]class BarRatingQuestion(DropdownQuestion): """ A question that uses the JQuery bar rating widget. """ kind: str = "barrating" rating_theme: Literal[settings.BAR_RATING_THEMES] = "fontawesome-stars" show_values: bool = False extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/jquery-bar-rating", ] extra_css: List[HttpUrl] = [ "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/bars-1to10.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/bars-movie.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/bars-pill.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/bars-reversed.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/bars-horizontal.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/fontawesome-stars.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/css-stars.css", "https://unpkg.com/jquery-bar-rating@1.2.2/dist/themes/fontawesome-stars-o.css", ]
[docs]class SortableJSQuestion(CheckboxQuestion): """ A question that uses the JQuery sortable widget. """ kind: str = "sortablelist" empty_text: str = "" max_answers_count: int = -1 extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/sortablejs@1.7.0/Sortable.js", ]
[docs]class NoUISliderQuestion(Question): """ A question that uses the NoUISlider JQuery widget. """ kind: str = "nouislider" step: int = 1 range_min: int = 0 range_max: int = 100 pips_mode: str = "positions" pips_values: List[int] = [0, 25, 50, 75, 100] pips_text: List[Union[int, str]] = [0, 25, 50, 75, 100] pips_density: int = 5 orientation: str = "horizontal" direction: str = "ltr" tooltips: bool = True extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/nouislider@9.2.0/distribute/nouislider.js", "https://unpkg.com/wnumb@1.1.0", ] extra_css: List[HttpUrl] = [ "https://unpkg.com/nouislider@9.2.0/distribute/nouislider.min.css", ]
[docs]class CKEditorQuestion(Question): """ A question that uses the CKEditor JQuery widget. """ kind: str = "editor" height: str = "300px" extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://cdn.ckeditor.com/4.14.1/standard/ckeditor.js", ]
[docs]class BootstrapSliderQuestion(Question): """ A question that uses the bootstrap slider widget. """ kind: str = "bootstrpslider" step: int = 1 range_min: int = 0 range_max: int = 100 extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.0.0/bootstrap-slider.js", ] extra_css: List[HttpUrl] = [ "https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.0.0/css/bootstrap-slider.css", ]
[docs]class EmotionsRatingQuestion(DropdownQuestion): """ A question that uses the emotion ratings JQuery widget. """ kind: str = "emotionsratings" emotions: List[str] = ["angry", "disappointed", "meh", "happy", "inLove"] emotion_size: int = 30 emotions_count: int = 5 bg_emotion: str = "happy" emotion_color: str = "FF0066" extra_js: List[HttpUrl] = [ "https://unpkg.com/jquery@3.5.1/dist/jquery.js", "https://unpkg.com/emotion-ratings@2.0.1/dist/emotion-ratings.js", ]
[docs]class MicrophoneQuestion(Question): """ A question that uses the RecordRTC sound recording widgets. """ kind: str = "microphone" extra_js: List[HttpUrl] = [ "https://www.WebRTC-Experiment.com/RecordRTC.js", ]
[docs]class HtmlBlock(Question): """ An HTML block that can be embedded in a form. """ kind: str = "html" html: Union[str, Dict[str, str]] = ""
[docs]class ImageBlock(Question): """ An block for inserting an image in a form. """ kind: str = "image" image_height: int = 200 image_width: int = 300 image_fit: Literal[settings.IMAGE_FIT_VALUES] = "none" image_link: HttpUrl content_mode: Literal[settings.IMAGE_CONTENT_MODE_VALUES] = "image"
[docs]class ExpressionBlock(Question): """ A block that inserts the result of an expression in a form. """ kind: str = "expression" expression: str currency: str = "USD" display_style: Literal[settings.EXPRESSION_DISPLAY_STYLES] = "none" expression_format: str = "" maximum_fraction_digits: int = -1 minimum_fraction_digits: int = -1 use_grouping: bool = True
[docs]class PanelBlock(Question): """ A form panel is a group of questions that go together. A form can contain any number of panels, even nested. """ kind: str = "panel" inner_indent: int = 1 elements: List[Question] = [] question_start_index: str = "" question_title_location: Literal[settings.TITLE_LOCATIONS] = "default" show_number: bool = False show_question_numbers: Literal[settings.SHOW_QUESTION_NUMBERS_VALUES] = "default" state: Literal[settings.PANEL_STATES] = "default"
[docs]class PanelDynamicBlock(Question): """ Dynamic blocks allow users to manually add or remove panels. A form can contain any number of dynamic panels, even nested. """ kind: str = "paneldynamic" inner_indent: int = 1 render_mode: Literal[settings.PANEL_RENDER_MODES] = "list" panel_count: int = 1 panel_add_text: Union[str, Dict[str, str]] = "" panel_remove_text: Union[str, Dict[str, str]] = "" template_title: Union[str, Dict[str, str]] = "" template_elements: List[Question] = [] allow_add_panel: bool = True allow_remove_panel: bool = True confirm_delete: bool = False confirm_delete_text: Union[str, Dict[str, str]] = "" default_value_from_last_panel: bool = False key_duplication_error: Union[str, Dict[str, str]] = "" key_name: str = "" max_panel_count: int = 100 min_panel_count: int = 1 panel_add_text: Union[str, Dict[str, str]] = "" panel_next_text: Union[str, Dict[str, str]] = "" panel_prev_text: Union[str, Dict[str, str]] = "" panel_remove_text: Union[str, Dict[str, str]] = "" panels_state: Literal[settings.PANEL_STATES] = "default" show_question_numbers: Literal[settings.SHOW_QUESTION_NUMBERS_VALUES] = "default" show_range_in_progress: bool = True template_description: Union[str, Dict[str, str]] = "" template_title_location: Literal[settings.TITLE_LOCATIONS] = "default"
[docs]class Page(_Base): """ A group of questions presented as an individual form page. A form can contain any number of pages. """ name: str = "" title: Union[str, Dict[str, str]] = "" questions: List[Question] = [] description: Union[str, Dict[str, str]] = "" max_time_to_finish: int = 0 navigation_buttons_visibility: Literal[settings.NAV_BUTTONS_VISIBILITY] = "inherit" question_title_location: Literal[settings.TITLE_LOCATIONS] = "default" questions_order: Literal[settings.QUESTION_ORDER_VALUES] = "default"
[docs]class Survey(_Base): """ The main SurveyJS form container. Questions forms generate a survey rendering the questions contained in a form. """ title: Union[str, Dict[str, str]] = "" pages: List[Page] = [] calculated_values: List[Any] = [] check_errors_mode: Literal[settings.CHECK_ERRORS_MODES] = "onNextPage" clear_invisible_values: Literal[settings.CLEAR_INVISIBLE_VALUES] = "onComplete" completed_before_html: Union[str, Dict[str, str]] = "" completed_html: Union[str, Dict[str, str]] = "" completed_html_on_condition: List[Dict[str, str]] = [] complete_text: Union[str, Dict[str, str]] = "" cookie_name: str = "" description: Union[str, Dict[str, str]] = "" edit_text: Union[str, Dict[str, str]] = "" first_page_is_started: bool = False focus_first_question_automatic: bool = True focus_on_first_error: bool = True go_next_page_automatic: bool = False loading_html: Union[str, Dict[str, str]] = "" locale: Literal[settings.LOCALES] = "" logo: HttpUrl = "" logo_fit: Literal[settings.IMAGE_FIT_VALUES] = "contain" logo_height: int = 200 logo_position: Literal[settings.LOGO_POSITIONS] = "left" logo_width: int = 300 max_others_length: int = 0 max_text_length: int = 0 max_time_to_finish: int = 0 mode: Literal[settings.SURVEY_MODES] = "edit" navigate_to_url: HttpUrl = "" navigate_to_url_on_condition: List[Dict[str, HttpUrl]] = [] page_next_text: Union[str, Dict[str, str]] = "" page_prev_text: Union[str, Dict[str, str]] = "" preview_text: Union[str, Dict[str, str]] = "" progress_bar_type: Literal[settings.PROGRESS_BAR_TYPES] = "pages" question_description_location: Literal[ settings.QUESTION_DESCRIPTION_LOCATIONS ] = "underTitle" question_error_location: Literal[settings.QUESTION_ERROR_LOCATIONS] = "top" questions_on_page_mode: Literal[settings.QUESTION_PAGE_MODES] = "standard" questions_order: Literal[settings.QUESTION_ORDER_VALUES] = "initial" question_start_index: str = "" question_title_location: Literal[settings.TITLE_LOCATIONS] = "top" question_title_pattern: str = "numTitleRequire" question_title_template: str = "" required_text: Union[str, Dict[str, str]] = "*" send_result_on_page_next: bool = False show_completed_page: bool = False show_navigation_buttons: Literal[settings.NAV_BUTTONS_POSITIONS] = "bottom" show_page_numbers: bool = True show_page_titles: bool = True show_prev_button: bool = True show_preview_before_complete: Literal[settings.SHOW_PREVIEW_VALUES] = "noPreview" show_progress_bar: Literal[settings.SHOW_PROGRESS_BAR_OPTIONS] = "off" show_question_numbers: Literal[settings.PAGE_SHOW_QUESTION_NUMBERS_VALUES] = "on" show_timer_panel: Literal[settings.SHOW_TIMER_VALUES] = "none" show_timer_panel_mode: Literal[settings.SHOW_TIMER_MODES] = "all" show_title: bool = True start_survey_text: Union[str, Dict[str, str]] = "" store_others_as_comment: bool = True survey_id: str = "" survey_post_id: str = "" survey_show_data_saving: bool = True text_update_mode: Literal[settings.TEXT_UPDATE_MODES] = "onBlur" triggers: List[Any] = []
QUESTION_TYPES = [ BarRatingQuestion, BooleanQuestion, BootstrapDatePickerQuestion, BootstrapSliderQuestion, CheckboxQuestion, CKEditorQuestion, CommentQuestion, DropdownQuestion, EmotionsRatingQuestion, FileQuestion, ImagePickerQuestion, JQueryUIDatePickerQuestion, MatrixDropdownQuestion, MatrixDynamicQuestion, MatrixQuestion, MicrophoneQuestion, MultipleTextQuestion, NoUISliderQuestion, RadioGroupQuestion, RatingQuestion, Select2Question, SignaturePadQuestion, SortableJSQuestion, TagBoxQuestion, TextQuestion, ] QUESTION_NAMES_TO_TYPES = { "barrating": BarRatingQuestion, "boolean": BooleanQuestion, "bootstrapdatepicker": BootstrapDatePickerQuestion, "bootstrapslider": BootstrapSliderQuestion, "checkbox": CheckboxQuestion, "editor": CKEditorQuestion, "comment": CommentQuestion, "dropdown": DropdownQuestion, "emotionsratings": EmotionsRatingQuestion, "expression": ExpressionBlock, "file": FileQuestion, "html": HtmlBlock, "image": ImageBlock, "imagepicker": ImagePickerQuestion, "datepicker": JQueryUIDatePickerQuestion, "matrixdropdown": MatrixDropdownQuestion, "matrixdynamic": MatrixDynamicQuestion, "matrix": MatrixQuestion, "microphone": MicrophoneQuestion, "multipletext": MultipleTextQuestion, "nouislider": NoUISliderQuestion, "radiogroup": RadioGroupQuestion, "rating": RatingQuestion, "select2": Select2Question, "signaturepad": SignaturePadQuestion, "sortablelist": SortableJSQuestion, "tagbox": TagBoxQuestion, "text": TextQuestion, }