Integer fields should not accept booleans as defaults and vice versa
In Python, True
and False
are both integers and booleans:
>>> isinstance(0, bool), isinstance(0, int)
(False, True)
>>> isinstance(1, bool), isinstance(1, int)
(False, True)
>>> isinstance(False, bool), isinstance(False, int)
(True, True)
>>> isinstance(True, bool), isinstance(True, int)
(True, True)
Interestingly, DRF does the exact opposite:
>>> from rest_framework.serializers import BooleanField, IntegerField
>>> BooleanField().to_internal_value(0)
False
>>> BooleanField().to_internal_value(1)
True
>>> IntegerField().to_internal_value(True)
ValidationError: [ErrorDetail(string='A valid integer is required.', code='invalid')]
>>> IntegerField().to_internal_value(False)
ValidationError: [ErrorDetail(string='A valid integer is required.', code='invalid')]
That is because DRF first does str(True)
before using int('True', 10)
, and while True
is an integer, 'True'
isn't.
I randomly found a worker where a int
field had a default value of false
: YAML — Sample process
JavaScript is not happy about this, because false !== 0
and true !== 1
, and there are no unit tests on the backend side for either case. This can lead to confusion for worker developers because many are not aware that an integer can be a boolean in Python.
There should be some unit tests (or maybe some self.subTest
to test a lot of cases at once) to ensure that an int
with default: false
, an int
with default: true
, a boolean
with default: 0
and a boolean
with default: 1
are all invalid.