<commit_before>from django import forms
from django.forms.formsets import formset_factory, BaseFormSet
from django.forms.widgets import Select, Textarea
from django.utils.html import escape, conditional_escape
from django.utils.encoding import force_unicode

from itertools import chain

from gutter.web.registry import operators, arguments
from gutter.client.models import Switch, Condition

from functools import partial


class OperatorSelectWidget(Select):

    def __init__(self, arguments, *args, **kwargs):
        self.arguments = arguments
        super(OperatorSelectWidget, self).__init__(*args, **kwargs)

    def render_options(self, choices, selected_choices):
        def render_option(option_value, option_label):
            option_value = force_unicode(option_value)
            selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
            return u'<option data-arguments="%s" value="%s"%s>%s</option>' % (
                ','.join(self.arguments[option_value]),
                escape(option_value), selected_html,
                conditional_escape(force_unicode(option_label)))

        # Normalize to strings.
        selected_choices = set([force_unicode(v) for v in selected_choices])
        output = []

        for option_value, option_label in chain(self.choices, choices):
            if isinstance(option_label, (list, tuple)):
                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
                for option in option_label:
                    output.append(render_option(*option))
                output.append(u'</optgroup>')
            else:
                output.append(render_option(option_value, option_label))
        return u'\n'.join(output)


class SwitchForm(forms.Form):

    STATES = {1: 'Disabled', 2: 'Selective', 3: 'Global'}.items()

    name = forms.CharField(max_length=100)
    label = forms.CharField()
    description = forms.CharField(widget=Textarea())
    state = forms.IntegerField(widget=Select(choices=STATES))

    compounded = forms.BooleanField(required=False)
    concent = forms.BooleanField(required=False)

    @classmethod
    def from_object(cls, switch):
        data = dict(
            label=switch.label,
            name=switch.name,
            description=switch.description,
            state=switch.state,
            compounded=switch.compounded,
            concent=switch.concent
        )

        instance = cls(initial=data)

        condition_dicts = map(ConditionForm.to_dict, switch.conditions)
        instance.conditions = ConditionFormSet(initial=condition_dicts)

        return instance

    def field(self, key):
        return self.data.get(key, None) or self.initial[key]

    @property
    def to_object(self):
        switch = Switch(
            name=self.cleaned_data['name'],
            label=self.cleaned_data['label'],
            description=self.cleaned_data['description'],
            state=self.cleaned_data['state'],
            compounded=self.cleaned_data['compounded'],
            concent=self.cleaned_data['concent'],
        )

        return switch


class ConditionForm(forms.Form):

    NEGATIVE_CHOICES = ((0, 'Is'), (1, 'Is Not'))
    argument = forms.ChoiceField(choices=arguments.as_choices)
    negative = forms.ChoiceField(choices=NEGATIVE_CHOICES)
    operator = forms.ChoiceField(
        choices=operators.as_choices,
        widget=OperatorSelectWidget(operators.arguments)
    )

    @staticmethod
    def to_dict(condition):
        fields = dict(
            argument='.'.join((condition.argument.__name__, condition.attribute)),
            negative=condition.negative,
            operator=condition.operator.name
        )

        fields.update(condition.operator.variables)

        return fields


class BaseConditionFormSet(BaseFormSet):

    @property<commit_msg>Fix saving of conditions with negative select.<commit_after>from django import forms
from django.forms.formsets import formset_factory, BaseFormSet
from django.forms.widgets import Select, Textarea
from django.utils.html import escape, conditional_escape
from django.utils.encoding import force_unicode

from itertools import chain

from gutter.web.registry import operators, arguments
from gutter.client.models import Switch, Condition

from functools import partial


class OperatorSelectWidget(Select):

    def __init__(self, arguments, *args, **kwargs):
        self.arguments = arguments
        super(OperatorSelectWidget, self).__init__(*args, **kwargs)

    def render_options(self, choices, selected_choices):
        def render_option(option_value, option_label):
            option_value = force_unicode(option_value)
            selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
            return u'<option data-arguments="%s" value="%s"%s>%s</option>' % (
                ','.join(self.arguments[option_value]),
                escape(option_value), selected_html,
                conditional_escape(force_unicode(option_label)))

        # Normalize to strings.
        selected_choices = set([force_unicode(v) for v in selected_choices])
        output = []

        for option_value, option_label in chain(self.choices, choices):
            if isinstance(option_label, (list, tuple)):
                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
                for option in option_label:
                    output.append(render_option(*option))
                output.append(u'</optgroup>')
            else:
                output.append(render_option(option_value, option_label))
        return u'\n'.join(output)


class SwitchForm(forms.Form):

    STATES = {1: 'Disabled', 2: 'Selective', 3: 'Global'}.items()

    name = forms.CharField(max_length=100)
    label = forms.CharField()
    description = forms.CharField(widget=Textarea())
    state = forms.IntegerField(widget=Select(choices=STATES))

    compounded = forms.BooleanField(required=False)
    concent = forms.BooleanField(required=False)

    @classmethod
    def from_object(cls, switch):
        data = dict(
            label=switch.label,
            name=switch.name,
            description=switch.description,
            state=switch.state,
            compounded=switch.compounded,
            concent=switch.concent
        )

        instance = cls(initial=data)

        condition_dicts = map(ConditionForm.to_dict, switch.conditions)
        instance.conditions = ConditionFormSet(initial=condition_dicts)

        return instance

    def field(self, key):
        return self.data.get(key, None) or self.initial[key]

    @property
    def to_object(self):
        switch = Switch(
            name=self.cleaned_data['name'],
            label=self.cleaned_data['label'],
            description=self.cleaned_data['description'],
            state=self.cleaned_data['state'],
            compounded=self.cleaned_data['compounded'],
            concent=self.cleaned_data['concent'],
        )

        return switch


class ConditionForm(forms.Form):

    negative_widget = Select(choices=((False, 'Is'), (True, 'Is Not')))

    argument = forms.ChoiceField(choices=arguments.as_choices)
    negative = forms.BooleanField(widget=negative_widget, required=False)
    operator = forms.ChoiceField(
        choices=operators.as_choices,
        widget=OperatorSelectWidget(operators.arguments)
    )

    @staticmethod
    def to_dict(condition):
        fields = dict(
            argument='.'.join((condition.argument.__name__, condition.attribute)),
            negative=condition.negative,
            operator=condition.operator.name
        )

        fields.update(condition.operator.variables)

        return fields


class BaseConditionFormSet(BaseFormSet):

    @property
{'fraction_non_alphanumeric': 0.10445664666070745, 'fraction_numerical': 0.0017877665687651642, 'mean_word_length': 2.935678391959799, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4290316', 'n_tokens_mistral': 2183, 'n_tokens_neox': 2097, 'n_words': 418}