Skip to content

Blocks

hypha.apply.review.blocks

ScoreFieldBlock

Bases: OptionalFormFieldBlock

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

widget class-attribute instance-attribute

widget = None

required class-attribute instance-attribute

required = BooleanBlock(label=gettext_lazy('Required'), required=False)

field_class class-attribute instance-attribute

field_class = ScoredAnswerField

Meta

label class-attribute instance-attribute
label = gettext_lazy('Score')
icon class-attribute instance-attribute
icon = 'order'
template class-attribute instance-attribute
template = 'review/render_scored_answer_field.html'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/review/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["initial"] = ["", NA]
    return kwargs

render

render(value, context=None)
Source code in hypha/apply/review/blocks.py
def render(self, value, context=None):
    try:
        comment, score = context["data"]
    except ValueError:
        # TODO: Remove json load as data moved away from JSON
        comment, score = json.loads(context["data"])
    context.update(
        **{
            "comment": comment,
            "score": RATE_CHOICES_DICT.get(int(score), RATE_CHOICE_NA),
        }
    )

    return super().render(value, context)

ScoreFieldWithoutTextBlock

Bases: OptionalFormFieldBlock

There are two ways score could be accepted on reviews.

One is to use ScoreFieldBlock, where you need to put text answer along with giving score on the review.

Second is to use this block to just select a reasonable score with adding any text as answer.

This block modifies RATE_CHOICES to have empty string('') in place of NA for text value n/a - choose not to answer as it helps to render this value as default to the forms and also when this field is required it automatically handles validation on empty string.

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

required class-attribute instance-attribute

required = BooleanBlock(label=gettext_lazy('Required'), required=False)

name class-attribute instance-attribute

name = 'score without text'

field_class class-attribute instance-attribute

field_class = ChoiceField

widget class-attribute instance-attribute

widget = Select(attrs={'data-score-field': 'true'})

Meta

icon class-attribute instance-attribute
icon = 'order'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/review/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["choices"] = self.get_choices(RATE_CHOICES)
    return kwargs

render

render(value, context=None)
Source code in hypha/apply/review/blocks.py
def render(self, value, context=None):
    data = int(context["data"])
    choices = dict(self.get_choices(RATE_CHOICES))
    context["data"] = choices[data]

    return super().render(value, context)

get_choices

get_choices(choices)

Replace 'NA' option with an empty string choice.

Source code in hypha/apply/review/blocks.py
def get_choices(self, choices):
    """
    Replace 'NA' option with an empty string choice.
    """
    rate_choices = list(choices)
    rate_choices.pop(-1)
    rate_choices.append(("", "n/a - choose not to answer"))
    return tuple(rate_choices)

ReviewMustIncludeFieldBlock

ReviewMustIncludeFieldBlock(*args, **kwargs)

Bases: MustIncludeFieldBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

field_class class-attribute instance-attribute

field_class = CharField

widget class-attribute instance-attribute

widget = None

Meta

template class-attribute instance-attribute
template = 'stream_forms/render_field.html'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/utils/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["required"] = True
    return kwargs

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

RecommendationBlock

RecommendationBlock(*args, **kwargs)

Bases: ReviewMustIncludeFieldBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

widget class-attribute instance-attribute

widget = None

name class-attribute instance-attribute

name = 'recommendation'

description class-attribute instance-attribute

description = 'Overall recommendation'

field_class class-attribute instance-attribute

field_class = ChoiceField

Meta

icon class-attribute instance-attribute
icon = 'pick'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/review/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["choices"] = RECOMMENDATION_CHOICES
    return kwargs

render

render(value, context=None)
Source code in hypha/apply/review/blocks.py
def render(self, value, context=None):
    data = int(context["data"])
    choices = dict(RECOMMENDATION_CHOICES)
    context["data"] = choices[data]

    return super().render(value, context)

RecommendationCommentsBlock

RecommendationCommentsBlock(*args, **kwargs)

Bases: ReviewMustIncludeFieldBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

field_class class-attribute instance-attribute

field_class = CharField

name class-attribute instance-attribute

name = 'comments'

description class-attribute instance-attribute

description = 'Recommendation comments'

widget class-attribute instance-attribute

Meta

icon class-attribute instance-attribute
icon = 'openquote'
template class-attribute instance-attribute
template = 'stream_forms/render_unsafe_field.html'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/review/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super().get_field_kwargs(struct_value)
    kwargs["required"] = False
    return kwargs

VisibilityBlock

VisibilityBlock(*args, **kwargs)

Bases: ReviewMustIncludeFieldBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    info_name = (
        f"{self._meta_class.label} Field"
        if self._meta_class.label
        else f"{self.name.title()} Field"
    )
    child_blocks = [
        ("info", SingleIncludeStatic(label=info_name, description=self.description))
    ]
    super().__init__(child_blocks, *args, **kwargs)

field_label class-attribute instance-attribute

field_label = CharBlock(label=gettext_lazy('Label'))

help_text class-attribute instance-attribute

help_text = TextBlock(required=False, label=gettext_lazy('Help text'))
help_link = URLBlock(required=False, label=gettext_lazy('Help link'))

name class-attribute instance-attribute

name = 'visibility'

description class-attribute instance-attribute

description = 'Visibility'

field_class class-attribute instance-attribute

field_class = ChoiceField

widget class-attribute instance-attribute

widget = RadioSelect()

Meta

icon class-attribute instance-attribute
icon = 'radio-empty'

get_slug

get_slug(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_slug(self, struct_value):
    return force_str(slugify(anyascii(struct_value["field_label"])))

get_field_class

get_field_class(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field_class(self, struct_value):
    return self.field_class

get_widget

get_widget(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_widget(self, struct_value):
    return self.widget

get_field

get_field(struct_value)
Source code in hypha/apply/stream_forms/blocks.py
def get_field(self, struct_value):
    field_kwargs = self.get_field_kwargs(struct_value)
    return self.get_field_class(struct_value)(**field_kwargs)

decode

decode(value)

Convert JSON representation into actual python objects

Source code in hypha/apply/stream_forms/blocks.py
def decode(self, value):
    """Convert JSON representation into actual python objects"""
    return value

serialize

serialize(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize(self, value, context):
    field_kwargs = self.get_field_kwargs(value)
    return {
        "question": field_kwargs["label"],
        "answer": context.get("data"),
        "type": self.name,
    }

serialize_no_response

serialize_no_response(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def serialize_no_response(self, value, context):
    return {
        "question": value["field_label"],
        "answer": "-",
        "type": "no_response",
    }

prepare_data

prepare_data(value, data, serialize=False)
Source code in hypha/apply/stream_forms/blocks.py
def prepare_data(self, value, data, serialize=False):
    return nh3_value(str(data))

render

render(value, context)
Source code in hypha/apply/stream_forms/blocks.py
def render(self, value, context):
    data = context.get("data")
    data = self.prepare_data(value, data, context.get("serialize", False))

    context.update(data=data or self.no_response())

    if context.get("serialize"):
        if not data:
            return self.serialize_no_response(value, context)
        return self.serialize(value, context)

    return super().render(value, context)

get_searchable_content

get_searchable_content(value, data)
Source code in hypha/apply/stream_forms/blocks.py
def get_searchable_content(self, value, data):
    return str(data)

no_response

no_response()
Source code in hypha/apply/stream_forms/blocks.py
def no_response(self):
    return "-"

get_field_kwargs

get_field_kwargs(struct_value)
Source code in hypha/apply/review/blocks.py
def get_field_kwargs(self, struct_value):
    kwargs = super(VisibilityBlock, self).get_field_kwargs(struct_value)
    kwargs["choices"] = VISIBILITY.items()
    kwargs["initial"] = settings.REVIEW_VISIBILITY_DEFAULT
    kwargs["help_text"] = mark_safe(
        "<br>".join(
            [
                VISIBILITY[choice] + ": " + VISIBILILTY_HELP_TEXT[choice]
                for choice in VISIBILITY
            ]
        )
    )
    return kwargs

ReviewCustomFormFieldsBlock

ReviewCustomFormFieldsBlock(*args, **kwargs)

Bases: CustomFormFieldsBlock

Source code in hypha/apply/utils/blocks.py
def __init__(self, *args, **kwargs):
    # The space before " Required" is to make the group sort first. Ugly but easy, and it works.
    child_blocks = [
        (block.name, block(group=_(" Required"))) for block in self.required_blocks
    ]
    child_blocks += [
        (block.name, block(group=_("Custom"))) for block in self.single_blocks
    ]
    self.required_block_names = [block.name for block in self.required_blocks]
    self.single_block_names = [
        block.name for block in self.single_blocks
    ] + self.required_block_names

    super().__init__(child_blocks, *args, **kwargs)

rich_text class-attribute instance-attribute

rich_text = RichTextFieldBlock(group=gettext_lazy('Fields'))

markdown_text class-attribute instance-attribute

markdown_text = MarkdownTextFieldBlock(group=gettext_lazy('Fields'))

single_blocks class-attribute instance-attribute

single_blocks = []

required_block_names instance-attribute

required_block_names = [name for block in required_blocks]

single_block_names instance-attribute

single_block_names = [name for block in single_blocks] + required_block_names

char class-attribute instance-attribute

char = CharFieldBlock(group=gettext_lazy('Fields'))

text class-attribute instance-attribute

text = TextFieldBlock(group=gettext_lazy('Fields'))

text_markup class-attribute instance-attribute

text_markup = RichTextBlock(group=gettext_lazy('Fields'), label=gettext_lazy('Paragraph'))

score class-attribute instance-attribute

score = ScoreFieldBlock(group=gettext_lazy('Fields'))

score_without_text class-attribute instance-attribute

score_without_text = ScoreFieldWithoutTextBlock(group=gettext_lazy('Fields'))

checkbox class-attribute instance-attribute

checkbox = CheckboxFieldBlock(group=gettext_lazy('Fields'))

dropdown class-attribute instance-attribute

dropdown = DropdownFieldBlock(group=gettext_lazy('Fields'))

required_blocks class-attribute instance-attribute

required_blocks = __subclasses__()

clean

clean(value)
Source code in hypha/apply/utils/blocks.py
def clean(self, value):
    try:
        value = super().clean(value)
    except ValidationError as e:
        error_dict = e.params or {}
    else:
        error_dict = {}

    block_types = [block.block_type for block in value]
    missing = set(self.required_block_names) - set(block_types)

    duplicates = [
        name
        for name in find_duplicates(block_types)
        if name in self.single_block_names
    ]

    all_errors = []
    if missing:
        all_errors.append(
            "You are missing the following required fields: {}".format(
                ", ".join(prettify_names(missing))
            )
        )

    if duplicates:
        all_errors.append(
            "The following fields must be included only once: {}".format(
                ", ".join(prettify_names(duplicates))
            )
        )
        for i, block_name in enumerate(block_types):
            if block_name in duplicates:
                self.add_error_to_child(error_dict, i, "info", "Duplicate field")

    for block in value:
        if hasattr(block.block, "child_blocks"):
            for child_block_name, child_block in block.block.child_blocks.items():
                if child_block.required and not block.value[child_block_name]:
                    all_errors.append(
                        "{} cannot be empty for {}".format(
                            child_block.label, block.block.label
                        )
                    )
                if (
                    isinstance(child_block, ListBlock)
                    and child_block.child_block.required
                ):
                    for child_value in block.value[child_block_name]:
                        if not child_value:
                            all_errors.append(
                                "{} cannot be empty for {}".format(
                                    child_block.label, block.block.label
                                )
                            )

    if all_errors or error_dict:
        error_dict["__all__"] = all_errors
        raise ValidationError(all_errors, params=error_dict)

    return value

add_error_to_child

add_error_to_child(errors, child_number, field, message)
Source code in hypha/apply/utils/blocks.py
def add_error_to_child(self, errors, child_number, field, message):
    new_error = ErrorList([message])
    try:
        errors[child_number].data[0].params[field] = new_error
    except KeyError:
        errors[child_number] = ErrorList(
            [ValidationError("Error", params={field: new_error})]
        )

to_python

to_python(value)

This allows historic data to still be accessible even if a custom field type is removed from the code in the future.

Source code in hypha/apply/utils/blocks.py
def to_python(self, value):
    """
    This allows historic data to still be accessible even
    if a custom field type is removed from the code in the future.
    """
    # If the data type is missing, fallback to a CharField
    for child_data in value:
        if child_data["type"] not in self.child_blocks:
            child_data["type"] = "char"

    return StreamValue(self, value, is_lazy=True)