Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BooleanField Default Value Not Honored #738

Closed
SoundsSerious opened this issue Apr 24, 2022 · 5 comments
Closed

BooleanField Default Value Not Honored #738

SoundsSerious opened this issue Apr 24, 2022 · 5 comments

Comments

@SoundsSerious
Copy link

SoundsSerious commented Apr 24, 2022

Using Python 3.8 with WTForms == 3.0.1

It seems pretty clear the default input for BooleanField is broken

Doesn't matter what the default is, not having input for the field will result in False

From Field.process():

        if formdata is not None:
            if self.name in formdata:
                self.raw_data = formdata.getlist(self.name)
            else:
                self.raw_data = []
                
            try:
                self.process_formdata(self.raw_data)  #< With no input this wil be []

In Boolean Field

    def process_formdata(self, valuelist):
        if not valuelist or valuelist[0] in self.false_values:
            self.data = False #NO INPUT ENDS UP HERE!
        else:
            self.data = True

Looking at the tests these seem broken too:

def test_defaults(): #SHOWN FOR REFERENCE
    # Test with no post data to make sure defaults work
    form = BoringForm()
    assert form.bool1.raw_data is None
    assert form.bool1.data is False
    assert form.bool2.data is True

def test_with_postdata():
    form = BoringForm(DummyPostData(bool1=["a"]))
    assert form.bool1.raw_data == ["a"]
    assert form.bool1.data is True #Why! a isn't boolean
    form = BoringForm(DummyPostData(bool1=["false"], bool2=["false"]))
    assert form.bool1.data is False 
    assert form.bool2.data is True #WTF

Its clear to see that whenever the value isn't input it will be false.

The simplest change could be:

def process_formdata(self, valuelist):
        if len(valuelist)==0:
            self.data = self.default_value
        elif valuelist[0] in self.false_values:
            self.data = False
        else:
            self.data = True

But to prevent any ambiguity in form parsing this is how BooleanField should work:

Input:

BooleanField( <normal args>, default:bool = False, true_values=None, false_values=None)

Parsing:

def process_formdata(self, valuelist):
        if len(valuelist)==0:
            self.data = self.default_value
        elif valuelist[0] in self.false_values:
            self.data = False
       elif valuelist[0] in self.true_values:
            self.data = True
       else:
             #Print warning!
             self.data = self.default_value
@davidism
Copy link
Member

Duplicate of #402

@SoundsSerious
Copy link
Author

@davidism this seems to be a completely separate issue? Did you even read the code exceprts?

@SoundsSerious
Copy link
Author

@davidism Its completely clear that the code will not work as intended, why don't you leave the issue open so people can comment

@SoundsSerious
Copy link
Author

No Input = False, whats the point of having a default?

@SoundsSerious
Copy link
Author

@davidism

Here is a non broken implementation of boolean

class BooleanField(Field):
    """
    REPLACE ISSUES WITH wtform.BooleanField
    Represents an ``<input type="checkbox">``. Set the ``checked``-status by using the
    ``default``-option. Any value for ``default``, e.g. ``default="checked"`` puts
    ``checked`` into the html-element and sets the ``data`` to ``True``

    :param false_values:
        If provided, a sequence of strings each of which is an exact match
        string of what is considered a "false" value. Defaults to the tuple
        ``(False, 'false', '',)``
    """
    widget = widgets.CheckboxInput()
    false_values = (False, 'false', 'no','n')
    true_values = (True,'true','yes','y')

    def __init__(self, label=None, validators=None, false_values=None, true_values=None, **kwargs):
        if 'default' in kwargs:
            default = kwargs['default']
            assert isinstance(default,bool)
            self.default=default
            
        super(BooleanField, self).__init__(label, validators, **kwargs)
        if false_values is not None:
            self.false_values = false_values

        if true_values is not None:
            self.true_values = true_values

    def process_data(self, value):
        self.data = bool(value)

    def process_formdata(self, valuelist):
        if len(valuelist)==0:
            self.data = self.default 
        elif valuelist[0] in self.false_values:
            self.data = False
        elif valuelist[0] in self.true_values:
                self.data = True
        else:
            #Print warning!
            self.data = self.default

    def _value(self):
        if self.raw_data:
            return str(self.raw_data[0])
        else:
            return 'y'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants