summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-10-11 17:56:14 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2017-10-12 13:39:06 -0400
commitc63658973c95996b73251e0953cf4c598cdb262b (patch)
tree1d9aba0b27f2f096369b95cf0a6dbb95f87825ac /lib/sqlalchemy/sql
parent3306d4d34d0f78bdda6f85a0a3be81beb2850676 (diff)
downloadsqlalchemy-c63658973c95996b73251e0953cf4c598cdb262b.tar.gz
Disallow all ambiguous boolean values for Boolean
In release 1.1, the :class:`.Boolean` type was broken in that boolean coercion via ``bool()`` would occur for backends that did not feature "native boolean", but would not occur for native boolean backends, meaning the string ``"0"`` now behaved inconsistently. After a poll, a consensus was reached that non-boolean values should be raising an error, especially in the ambiguous case of string ``"0"``; so the :class:`.Boolean` datatype will now raise ``ValueError`` if an incoming value is not within the range ``None, True, False, 1, 0``. Change-Id: If70c4f79c266f0dd1a0306c0ffe7acb9c66c4cc3 Fixes: #4102
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py41
1 files changed, 37 insertions, 4 deletions
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index 061f8de96..2a30bf832 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -1581,9 +1581,22 @@ class Boolean(Emulated, TypeEngine, SchemaType):
"""A bool datatype.
- Boolean typically uses BOOLEAN or SMALLINT on the DDL side, and on
+ :class:`.Boolean` typically uses BOOLEAN or SMALLINT on the DDL side, and on
the Python side deals in ``True`` or ``False``.
+ The :class:`.Boolean` datatype currently has two levels of assertion
+ that the values persisted are simple true/false values. For all
+ backends, only the Python values ``None``, ``True``, ``False``, ``1``
+ or ``0`` are accepted as parameter values. For those backends that
+ don't support a "native boolean" datatype, a CHECK constraint is also
+ created on the target column. Production of the CHECK constraint
+ can be disabled by passing the :paramref:`.Boolean.create_constraint`
+ flag set to ``False``.
+
+ .. versionchanged:: 1.2 the :class:`.Boolean` datatype now asserts that
+ incoming Python values are already in pure boolean form.
+
+
"""
__visit_name__ = 'boolean'
@@ -1631,20 +1644,40 @@ class Boolean(Emulated, TypeEngine, SchemaType):
def python_type(self):
return bool
+ _strict_bools = frozenset([None, True, False])
+
+ def _strict_as_bool(self, value):
+ if value not in self._strict_bools:
+ if not isinstance(value, int):
+ raise TypeError(
+ "Not a boolean value: %r" % value)
+ else:
+ raise ValueError(
+ "Value %r is not None, True, or False" % value)
+ return value
+
def literal_processor(self, dialect):
compiler = dialect.statement_compiler(dialect, None)
true = compiler.visit_true(None)
false = compiler.visit_false(None)
def process(value):
- return true if value else false
+ return true if self._strict_as_bool(value) else false
return process
def bind_processor(self, dialect):
+ _strict_as_bool = self._strict_as_bool
if dialect.supports_native_boolean:
- return None
+ _coerce = bool
else:
- return processors.boolean_to_int
+ _coerce = int
+
+ def process(value):
+ value = _strict_as_bool(value)
+ if value is not None:
+ value = _coerce(value)
+ return value
+ return process
def result_processor(self, dialect, coltype):
if dialect.supports_native_boolean: