class AppendedText(PrependedAppendedText):
    def __init__(self, field, text, *args, **kwargs):
        kwargs.pop("appended_text", None)
        kwargs.pop("prepended_text", None)
        self.text = text
        super().__init__(field, appended_text=text, **kwargs) class FieldWithButtons(Div):
    """
    A layout object for rendering a single field with any number of buttons.

    Args:
        fields : str or LayoutObject
            The first positional argument is the field. This can be either the
            name of the field as a string or an instance of `Field`. Following
            arguments will be rendered as buttons.
        input_size : str
            Additional CSS class to change the size of the input. e.g.
            "input-group-sm".
        kwargs
            Additional kwargs to be passed to the parent `Div` Layout Object.

    Example::

        FieldWithButtons(
            Field("password1", css_class="span4"),
            StrictButton("Go!", css_id="go-button"),
            input_size="input-group-sm",
        )
    """

    template = "%s/layout/field_with_buttons.html"
    field_template = "%s/field.html"

    def __init__(self, *fields, input_size=None, **kwargs):
        self.input_size = input_size
        super().__init__(*fields, **kwargs)

    def render(self, form, context, template_pack=TEMPLATE_PACK, extra_context=None, **kwargs):
        # We first render the buttons
        field_template = self.field_template % template_pack
        buttons = "".join(
            render_field(
                field,
                form,
                context,
                field_template,
                layout_object=self,
                template_pack=template_pack,
                **kwargs,
            )
            for field in self.fields[1:]
        )

        extra_context = {"div": self, "buttons": buttons}
        template = self.get_template_name(template_pack)

        if isinstance(self.fields[0], Field):
            # FieldWithButtons(Field('field_name'), StrictButton("go"))
            # We render the field passing its name and attributes
            return render_field(
                self.fields[0][0],
                form,
                context,
                template,
                attrs=self.fields[0].attrs,
                template_pack=template_pack,
                extra_context=extra_context,
                **kwargs,
            )
        else:
            return render_field(self.fields[0], form, context, template, extra_context=extra_context, **kwargs) class PrependedAppendedText(Field):
    template = "%s/layout/prepended_appended_text.html"

    def __init__(self, field, prepended_text=None, appended_text=None, input_size=None, *args, **kwargs):
        self.field = field
        self.appended_text = appended_text
        self.prepended_text = prepended_text
        if "active" in kwargs:
            self.active = kwargs.pop("active")

        self.input_size = input_size
        css_class = kwargs.get("css_class", "")

        # Bootstrap 3
        if "input-lg" in css_class:
            self.input_size = "input-lg"
        if "input-sm" in css_class:
            self.input_size = "input-sm"

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

    def render(self, form, context, template_pack=TEMPLATE_PACK, extra_context=None, **kwargs):
        extra_context = extra_context.copy() if extra_context is not None else {}
        extra_context.update(
            {
                "crispy_appended_text": self.appended_text,
                "crispy_prepended_text": self.prepended_text,
                "input_size": self.input_size,
                "active": getattr(self, "active", False),
                "wrapper_class": self.wrapper_class,
            }
        )
        template = self.get_template_name(template_pack)
        return render_field(
            self.field,
            form,
            context,
            template=template,
            attrs=self.attrs,
            template_pack=template_pack,
            extra_context=extra_context,
            **kwargs,
        ) class PrependedText(PrependedAppendedText):
    def __init__(self, field, text, *args, **kwargs):
        kwargs.pop("appended_text", None)
        kwargs.pop("prepended_text", None)
        self.text = text
        super().__init__(field, prepended_text=text, **kwargs) class StrictButton(TemplateNameMixin):
    """
    Layout object for rendering an HTML button in a ``<button>`` tag.

    Attributes
    ----------
    template: str
        The default template which this Layout Object will be rendered
        with.
    field_classes : str
        The CSS classes to be applied to the button. By defult "btn".

    Parameters
    ----------
    content : str
        The content of the button. This content is context aware, to bring
        this to life see the examples section.
    css_id : str, optional
        A custom DOM id for the layout object which will be added to the
        ``<button>`` if provided. By default None.
    css_class : str, optional
        Additional CSS classes to be applied to the ``<button>``. By default
        None.
    template : str, optional
        Overrides the default template, if provided. By default None.
    **kwargs : dict, optional
        Additional attributes are passed to `flatatt` and converted into
        key="value", pairs. These attributes are added to the ``<button>``.

    Examples
    --------

    In your ``Layout``::

        StrictButton("button content", css_class="extra")

    The content of the button is context aware, so you can do things like::

        StrictButton("Button for {{ user.username }}")
    """

    template = "%s/layout/button.html"
    field_classes = "btn"

    def __init__(self, content, css_id=None, css_class=None, template=None, **kwargs):
        self.content = content
        self.template = template or self.template

        kwargs.setdefault("type", "button")

        # We turn css_id and css_class into id and class
        if css_id:
            kwargs["id"] = css_id

        kwargs["class"] = self.field_classes
        if css_class:
            kwargs["class"] += f" {css_class}"

        self.flat_attrs = flatatt(kwargs)

    def render(self, form, context, template_pack=TEMPLATE_PACK, **kwargs):
        self.content = Template(str(self.content)).render(context)
        template = self.get_template_name(template_pack)
        context.update({"button": self})

        return render_to_string(template, context.flatten()) class DynamicLayoutHandler:
class FormHelper(DynamicLayoutHandler):
    def _check_layout(self):
    def _check_layout_and_form(self):
    def all(self):
    def filter(self, *LayoutClasses, **kwargs):
    def filter_by_widget(self, widget_type):
    def exclude_by_widget(self, widget_type):
    def __getitem__(self, key):
    def __setitem__(self, key, value):
    def __delitem__(self, key):
    def __len__(self):
    def __init__(self, form=None):
    def build_default_layout(self, form):
    def form_method(self):
    def form_method(self, method):
    def form_action(self):
    def form_action(self, action):
    def help_text_inline(self):
    def help_text_inline(self, flag):
    def error_text_inline(self):
    def error_text_inline(self, flag):
    def add_input(self, input_object):
    def add_layout(self, layout):
    def render_layout(self, form, context, template_pack=TEMPLATE_PACK):
    def get_attributes(self, template_pack=TEMPLATE_PACK):  # noqa: C901 class Button(BaseInput):
    """
    Used to create a button descriptor for the {% crispy %} template tag.

    Attributes
    ----------
    template: str
        The default template which this Layout Object will be rendered
        with.

    Parameters
    ----------
    name : str
        The name attribute of the button.
    value : str
        The value attribute of the button.
    css_id : str, optional
        A custom DOM id for the layout object. If not provided the name
        argument is slugified and turned into the id for the submit button.
        By default None.
    css_class : str, optional
        Additional CSS classes to be applied to the ``<input>``. By default
        None.
    template : str, optional
        Overrides the default template, if provided. By default None.
    **kwargs : dict, optional
        Additional attributes are passed to `flatatt` and converted into
        key="value", pairs. These attributes are added to the ``<input>``.

    Examples
    --------
    Note: ``form`` arg to ``render()`` is not required for ``BaseInput``
    inherited objects.

    >>> button = Button('Button 1', 'Press Me!')
    >>> button.render("", "", Context())
    '<input type="button" name="button-1" value="Press Me!" '
    'class="btn" id="button-id-button-1"/>'

    >>> button = Button('Button 1', 'Press Me!', css_id="custom-id",
                         css_class="custom class", my_attr=True, data="my-data")
    >>> button.render("", "", Context())
    '<input type="button" name="button-1" value="Press Me!" '
    'class="btn custom class" id="custom-id" data="my-data" my-attr/>'

    Usually you will not call the render method on the object directly. Instead
    add it to your ``Layout`` manually or use the `add_input` method::

        class ExampleForm(forms.Form):
        [...]
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.add_input(Button('Button 1', 'Press Me!'))
    """

    input_type = "button"

    def __init__(self, name, value, *, css_id=None, css_class=None, template=None, **kwargs):
        self.field_classes = "button" if get_template_pack() == "uni_form" else "btn"
        super().__init__(name=name, value=value, css_id=css_id, css_class=css_class, template=template, **kwargs) class Hidden(BaseInput):
    """
    Used to create a Hidden input descriptor for the {% crispy %} template tag.

    Attributes
    ----------
    template: str
        The default template which this Layout Object will be rendered
        with.

    Parameters
    ----------
    name : str
        The name attribute of the button.
    value : str
        The value attribute of the button.
    css_id : str, optional
        A custom DOM id for the layout object. If not provided the name
        argument is slugified and turned into the id for the submit button.
        By default None.
    css_class : str, optional
        Additional CSS classes to be applied to the ``<input>``. By default
        None.
    template : str, optional
        Overrides the default template, if provided. By default None.
    **kwargs : dict, optional
        Additional attributes are passed to `flatatt` and converted into
        key="value", pairs. These attributes are added to the ``<input>``.

    Examples
    --------
    Note: ``form`` arg to ``render()`` is not required for ``BaseInput``
    inherited objects.

    >>> hidden = Hidden("hidden", "hide-me")
    >>> hidden.render("", "", Context())
    '<input type="hidden" name="hidden" value="hide-me"/>'

    Usually you will not call the render method on the object directly. Instead
    add it to your ``Layout`` manually or use the `add_input` method::

        class ExampleForm(forms.Form):
        [...]
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.add_input(Hidden("hidden", "hide-me"))
    """

    input_type = "hidden"
    field_classes = "hidden" class Layout(LayoutObject):
    """
    Form Layout. It is conformed by Layout objects: `Fieldset`, `Row`, `Column`, `MultiField`,
    `HTML`, `ButtonHolder`, `Button`, `Hidden`, `Reset`, `Submit` and fields. Form fields
    have to be strings.
    Layout objects `Fieldset`, `Row`, `Column`, `MultiField` and `ButtonHolder` can hold other
    Layout objects within. Though `ButtonHolder` should only hold `HTML` and BaseInput
    inherited classes: `Button`, `Hidden`, `Reset` and `Submit`.

    Example::

        helper.layout = Layout(
            Fieldset('Company data',
                'is_company'
            ),
            Fieldset(_('Contact details'),
                'email',
                Row('password1', 'password2'),
                'first_name',
                'last_name',
                HTML('<img src="/media/somepicture.jpg"/>'),
                'company'
            ),
            ButtonHolder(
                Submit('Save', 'Save', css_class='button white'),
            ),
        )
    """

    def __init__(self, *fields):
        self.fields = list(fields)

    def render(self, form, context, template_pack=TEMPLATE_PACK, **kwargs):
        return self.get_rendered_fields(form, context, template_pack, **kwargs) class Reset(BaseInput):
    """
    Used to create a reset button descriptor for the {% crispy %} template tag.

    Attributes
    ----------
    template: str
        The default template which this Layout Object will be rendered
        with.

    Parameters
    ----------
    name : str
        The name attribute of the button.
    value : str
        The value attribute of the button.
    css_id : str, optional
        A custom DOM id for the layout object. If not provided the name
        argument is slugified and turned into the id for the submit button.
        By default None.
    css_class : str, optional
        Additional CSS classes to be applied to the ``<input>``. By default
        None.
    template : str, optional
        Overrides the default template, if provided. By default None.
    **kwargs : dict, optional
        Additional attributes are passed to `flatatt` and converted into
        key="value", pairs. These attributes are added to the ``<input>``.

    Examples
    --------
    Note: ``form`` arg to ``render()`` is not required for ``BaseInput``
    inherited objects.

    >>> reset = Reset('Reset This Form', 'Revert Me!')
    >>> reset.render("", "", Context())
    '<input type="reset" name="reset-this-form" value="Revert Me!" '
    'class="btn btn-inverse" id="reset-id-reset-this-form"/>'

    >>> reset = Reset('Reset This Form', 'Revert Me!', css_id="custom-id",
                         css_class="custom class", my_attr=True, data="my-data")
    >>> reset.render("", "", Context())
    '<input type="reset" name="reset-this-form" value="Revert Me!" '
    'class="btn btn-inverse custom class" id="custom-id" data="my-data" my-attr/>'

    Usually you will not call the render method on the object directly. Instead
    add it to your ``Layout`` manually manually or use the `add_input` method::

        class ExampleForm(forms.Form):
        [...]
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.add_input(Reset('Reset This Form', 'Revert Me!'))
    """

    input_type = "reset"

    def __init__(self, name, value, *, css_id=None, css_class=None, template=None, **kwargs):
        self.field_classes = "reset resetButton" if get_template_pack() == "uni_form" else "btn btn-inverse"
        super().__init__(name=name, value=value, css_id=css_id, css_class=css_class, template=template, **kwargs) class Submit(BaseInput):
    """
    Used to create a Submit button descriptor for the {% crispy %} template tag.

    Attributes
    ----------
    template: str
        The default template which this Layout Object will be rendered
        with.

    Parameters
    ----------
    name : str
        The name attribute of the button.
    value : str
        The value attribute of the button.
    css_id : str, optional
        A custom DOM id for the layout object. If not provided the name
        argument is slugified and turned into the id for the submit button.
        By default None.
    css_class : str, optional
        Additional CSS classes to be applied to the ``<input>``. By default
        None.
    template : str, optional
        Overrides the default template, if provided. By default None.
    **kwargs : dict, optional
        Additional attributes are passed to `flatatt` and converted into
        key="value", pairs. These attributes are added to the ``<input>``.

    Examples
    --------
    Note: ``form`` arg to ``render()`` is not required for ``BaseInput``
    inherited objects.

    >>> submit = Submit('Search the Site', 'search this site')
    >>> submit.render("", "", Context())
    '<input type="submit" name="search-the-site" value="search this site" '
    'class="btn btn-primary" id="submit-id-search-the-site"/>'

    >>> submit = Submit('Search the Site', 'search this site', css_id="custom-id",
                         css_class="custom class", my_attr=True, data="my-data")
    >>> submit.render("", "", Context())
    '<input type="submit" name="search-the-site" value="search this site" '
    'class="btn btn-primary custom class" id="custom-id" data="my-data" my-attr/>'

    Usually you will not call the render method on the object directly. Instead
    add it to your ``Layout`` manually or use the `add_input` method::

        class ExampleForm(forms.Form):
        [...]
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.helper = FormHelper()
            self.helper.add_input(Submit('submit', 'Submit'))
    """

    input_type = "submit"

    def __init__(self, name, value, *, css_id=None, css_class=None, template=None, **kwargs):
        self.field_classes = "submit submitButton" if get_template_pack() == "uni_form" else "btn btn-primary"
        super().__init__(name=name, value=value, css_id=css_id, css_class=css_class, template=template, **kwargs) class CrispyFormNode(BasicNode):
    def render(self, context):
        c = self.get_render(context).flatten()

        if self.actual_helper is not None and getattr(self.actual_helper, "template", False):
            template = get_template(self.actual_helper.template)
        else:
            if c["is_formset"]:
                template = whole_uni_formset_template(self.template_pack)
            else:
                template = whole_uni_form_template(self.template_pack)
        return template.render(c) def render_crispy_form(form, helper=None, context=None):
    """
    Renders a form and returns its HTML output.

    This function wraps the template logic in a function easy to use in a Django view.
    """
    from crispy_forms.templatetags.crispy_forms_tags import CrispyFormNode

    if helper is not None:
        node = CrispyFormNode("form", "helper")
    else:
        node = CrispyFormNode("form", None)

    node_context = Context(context)
    node_context.update({"form": form, "helper": helper})

    return node.render(node_context) def advanced_layout():
def template_packs(request, settings):
def check_template_pack(node, template_pack): class SampleForm(forms.Form):
    is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
    email = forms.EmailField(
        label="email", max_length=30, required=True, widget=forms.TextInput(), help_text="Insert your email"
    )
    password1 = forms.CharField(label="password", max_length=30, required=True, widget=forms.PasswordInput())
    password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())
    first_name = forms.CharField(label="first name", max_length=5, required=True, widget=forms.TextInput())
    last_name = forms.CharField(label="last name", max_length=5, required=True, widget=forms.TextInput())
    datetime_field = forms.SplitDateTimeField(label="date time", widget=forms.SplitDateTimeWidget())

    def clean(self):
        super().clean()
        password1 = self.cleaned_data.get("password1", None)
        password2 = self.cleaned_data.get("password2", None)
        if not password1 and not password2 or password1 != password2:
            raise forms.ValidationError("Passwords dont match")

        return self.cleaned_data class SampleForm7(forms.ModelForm):
    is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
    password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())

    class Meta:
        model = CrispyTestModel
        fields = ("email", "password", "password2") class SampleForm8(forms.ModelForm):
    is_company = forms.CharField(label="company", required=False, widget=forms.CheckboxInput())
    password2 = forms.CharField(label="re-enter password", max_length=30, required=True, widget=forms.PasswordInput())

    class Meta:
        model = CrispyTestModel
        fields = ("email", "password2", "password") class SampleFormWithMedia(forms.Form):
    class Media:
        css = {"all": ("test.css",)}
        js = ("test.js",) class SampleFormWithMultiValueField(forms.Form):
    multi = forms.SplitDateTimeField()
import re
import pytest
import django
from django import forms
from django.forms.models import formset_factory
from django.middleware.csrf import _get_new_csrf_string
from django.template import Context, Template, TemplateSyntaxError
from django.test.html import parse_html
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from crispy_forms.bootstrap import AppendedText, FieldWithButtons, PrependedAppendedText, PrependedText, StrictButton
from crispy_forms.helper import FormHelper, FormHelpersException
from crispy_forms.layout import Button, Hidden, Layout, Reset, Submit
from crispy_forms.templatetags.crispy_forms_tags import CrispyFormNode
from crispy_forms.utils import render_crispy_form
from .conftest import only_bootstrap3, only_bootstrap4
from .forms import SampleForm, SampleForm7, SampleForm8, SampleFormWithMedia, SampleFormWithMultiValueField
from .utils import parse_expected, parse_form
    from .utils import contains_partial
def test_render_unmentioned_fields_order():
    test_form = SampleForm7()
    test_form.helper = FormHelper()
    test_form.helper.layout = Layout("email")
    test_form.helper.render_unmentioned_fields = True

    html = render_crispy_form(test_form)
    assert html.count("<input") == 4
    assert (
        # From layout
        html.index('id="div_id_email"')
        # From form.Meta.fields
        < html.index('id="div_id_password"')
        < html.index('id="div_id_password2"')
        # From fields
        < html.index('id="div_id_is_company"')
    )

    test_form = SampleForm8()
    test_form.helper = FormHelper()
    test_form.helper.layout = Layout("email")
    test_form.helper.render_unmentioned_fields = True

    html = render_crispy_form(test_form)
    assert html.count("<input") == 4
    assert (
        # From layout
        html.index('id="div_id_email"')
        # From form.Meta.fields
        < html.index('id="div_id_password2"')
        < html.index('id="div_id_password"')
        # From fields
        < html.index('id="div_id_is_company"')
    )


def test_render_hidden_fields():

    test_form = SampleForm()
    test_form.helper = FormHelper()
    test_form.helper.layout = Layout("email")
    test_form.helper.render_hidden_fields = True

    html = render_crispy_form(test_form)
    assert html.count("<input") == 1

    # Now hide a couple of fields
    for field in ("password1", "password2"):
        test_form.fields[field].widget = forms.HiddenInput()

    html = render_crispy_form(test_form)
    assert html.count("<input") == 3
    assert html.count("hidden") == 2

    assert contains_partial(html, '<input name="password1" type="hidden"/>')
    assert contains_partial(html, '<input name="password2" type="hidden"/>')


def test_render_required_fields():
    test_form = SampleForm()
    test_form.helper = FormHelper()
    test_form.helper.layout = Layout("email")
    test_form.helper.render_required_fields = True

    html = render_crispy_form(test_form)
    assert html.count("<input") == 7


def test_helper_custom_template():
    form = SampleForm()
    form.helper = FormHelper()
    form.helper.template = "custom_form_template.html"

    html = render_crispy_form(form)
    assert "<h1>Special custom form</h1>" in html


def test_helper_custom_field_template():
    form = SampleForm()
    form.helper = FormHelper()
    form.helper.layout = Layout("password1", "password2")
    form.helper.field_template = "custom_field_template.html"

    html = render_crispy_form(form)
    assert html.count("<h1>Special custom field</h1>") == 2


def test_helper_custom_field_template_no_layout():
    form = SampleForm()
    form.helper = FormHelper()
    form.helper.field_template = "custom_field_template.html"

    html = render_crispy_form(form)
    for field in form.fields:
        assert html.count('id="div_id_%s"' % field) == 1
    assert html.count("<h1>Special custom field</h1>") == len(form.fields)


def test_helper_std_field_template_no_layout():
    form = SampleForm()
    form.helper = FormHelper()

    html = render_crispy_form(form)
    for field in form.fields:
        assert html.count('id="div_id_%s"' % field) == 1


@only_bootstrap3
def test_bootstrap_form_show_errors_bs3():
    form = SampleForm(
        {
            "email": "invalidemail",
            "first_name": "first_name_too_long",
            "last_name": "last_name_too_long",
            "password1": "yes",
            "password2": "yes",
        }
    )
    form.helper = FormHelper()
    form.helper.layout = Layout(

        AppendedText("email", "whatever"),