Why does the Flask bool query parameter always evaluate to true?
Question:
I have an odd behavior for one of my endpoints in my Flask application which accepts boolean query parameters. No matter what I pass to it, such as asfsdfd
or true
or false
, it is considered true. Only by leaving it empty does it become false.
full_info = request.args.get("fullInfo", default=False, type=bool)
if full_info:
# do stuff
It seems to be that either any input is considered to be true. Is there any way to make this work with the Flask intended way of defining the type, or do I need to accept a string and compare it?
Answers:
This is expected as query string is an actual string, hence when you get a string no matter what it is, if it’s not empty, it will be true.
As in:
>>>bool('False')
True
You will have to do string comparison if you want to get a boolean.
A "trick" is to use json.loads
as type
. It will act as a "factory" that will build a bool True
/False
from the strings 'true'
/'false'
The type
parameter of request.args.get
is a bit misleading, as it’s not for specifying the value’s type, but for specifying a callable:
- type – A callable that is used to cast the value in the MultiDict. If a ValueError is raised by this callable the default value is returned.
It accepts a callable (ex. a function), applies that callable to the query parameter value, and returns the result. So the code
request.args.get("fullInfo", default=False, type=bool)
calls bool(value)
where value
is the query parameter value. In Flask, the query parameter values are always stored as strings. And unfortunately, calling bool()
on a non-empty string will always be True
:
In [10]: bool('true')
Out[10]: True
In [11]: bool('false')
Out[11]: True
In [12]: bool('any non-empty will be true')
Out[12]: True
In [13]: bool('')
Out[13]: False
Instead of bool
, you can pass a function that explicitly checks if the string is equal to the literal string true
(or whichever value your API rules consider as true-ish):
full_info = request.args.get('fullInfo', default=False, type=lambda v: v.lower() == 'true')
return jsonify({'full_info': full_info})
$ curl -XGET http://localhost:5000/test?fullInfo=false
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=adasdasd
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=11431423
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=true
{"full_info":true}
$ curl -XGET http://localhost:5000/test?fullInfo=TRUE
{"full_info":true}
$ curl -XGET http://localhost:5000/test
{"full_info":false}
It would work properly if you use flask_restplus.inputs.boolean type instead of bool.
It’s explained here. https://github.com/noirbizarre/flask-restplus/issues/199#issuecomment-276645303
I have an odd behavior for one of my endpoints in my Flask application which accepts boolean query parameters. No matter what I pass to it, such as asfsdfd
or true
or false
, it is considered true. Only by leaving it empty does it become false.
full_info = request.args.get("fullInfo", default=False, type=bool)
if full_info:
# do stuff
It seems to be that either any input is considered to be true. Is there any way to make this work with the Flask intended way of defining the type, or do I need to accept a string and compare it?
This is expected as query string is an actual string, hence when you get a string no matter what it is, if it’s not empty, it will be true.
As in:
>>>bool('False')
True
You will have to do string comparison if you want to get a boolean.
A "trick" is to use json.loads
as type
. It will act as a "factory" that will build a bool True
/False
from the strings 'true'
/'false'
The type
parameter of request.args.get
is a bit misleading, as it’s not for specifying the value’s type, but for specifying a callable:
- type – A callable that is used to cast the value in the MultiDict. If a ValueError is raised by this callable the default value is returned.
It accepts a callable (ex. a function), applies that callable to the query parameter value, and returns the result. So the code
request.args.get("fullInfo", default=False, type=bool)
calls bool(value)
where value
is the query parameter value. In Flask, the query parameter values are always stored as strings. And unfortunately, calling bool()
on a non-empty string will always be True
:
In [10]: bool('true')
Out[10]: True
In [11]: bool('false')
Out[11]: True
In [12]: bool('any non-empty will be true')
Out[12]: True
In [13]: bool('')
Out[13]: False
Instead of bool
, you can pass a function that explicitly checks if the string is equal to the literal string true
(or whichever value your API rules consider as true-ish):
full_info = request.args.get('fullInfo', default=False, type=lambda v: v.lower() == 'true')
return jsonify({'full_info': full_info})
$ curl -XGET http://localhost:5000/test?fullInfo=false
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=adasdasd
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=11431423
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=
{"full_info":false}
$ curl -XGET http://localhost:5000/test?fullInfo=true
{"full_info":true}
$ curl -XGET http://localhost:5000/test?fullInfo=TRUE
{"full_info":true}
$ curl -XGET http://localhost:5000/test
{"full_info":false}
It would work properly if you use flask_restplus.inputs.boolean type instead of bool.
It’s explained here. https://github.com/noirbizarre/flask-restplus/issues/199#issuecomment-276645303