Description
PR incoming.
Actual Behavior
WTForm's Length
validator incorrectly approves a missing string (aka field.data
is None
) when min=0
, whereas it should fail validation.
I interpret min=-1
to mean 'no minimum length, permit None
and the empty string ''
'
I interpret min=0
to mean 'minimum length 0, do not permit None
, aka a missing field, but do permit the empty string ''
'
Serving the following app with $ gunicorn min-len-fail:app
on the default localhost:8000
from flask import Flask, request, jsonify
from wtforms import Form, StringField
from wtforms.validators import Length
app = Flask(__name__)
class TestForm(Form):
title = StringField("Title", validators = [Length(min=0)])
@app.route("/", methods = ["POST"])
def index():
form = TestForm(request.form)
if form.validate():
return jsonify({"msg": "Success!", "title": form.title.data})
else:
return jsonify(form.errors), 400
Test POSTing title
both as missing, and as the empty string, with curl
$ curl -sSL -d 'titl=' localhost:8000
{"msg":"Success!","title":null}
$ curl -sSL -d 'title=' localhost:8000
{"msg":"Success!","title":""}
The Length validator reports success for both cases, whereas it should fail the first.
Expected Behavior
With the PR incoming
$ curl -sSL -d 'titl=' localhost:8000
{"title":["Field must be at least 0 characters long."]}
$ curl -sSL -d 'title=' localhost:8000
{"msg":"Success!","title":""}
Environment
- Python version: 3.12.7, Arch Linux
- wtforms version: main branch (3.2.1)
Cause
class Length:
...
def __call__(self, form, field):
length = field.data and len(field.data) or 0
...
The default length of 0
is incorrect; it should be -1
. And no we can't just change the 0
to a -1
in that awful x and y or z
mess otherwise the empty string would incorrectly set length
to -1
.
I've added three tests for the Length
validator to stress-test the difference between the None
missing string and the ''
empty string.