diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2017-06-26 11:56:38 -0400 |
---|---|---|
committer | Gerrit Code Review <gerrit@awstats.zzzcomputing.com> | 2017-06-26 11:56:38 -0400 |
commit | e04594339c19c3cd8b8e0d96ce83e5ded961dbb7 (patch) | |
tree | 507edb6a721047f8aa81f760a5299bb18e6bbcb7 | |
parent | 9f1a375f10cb7af558a9549081a0e792546aca21 (diff) | |
parent | 1776597131ef96472b5188cebc72c31a387c90f4 (diff) | |
download | sqlalchemy-e04594339c19c3cd8b8e0d96ce83e5ded961dbb7.tar.gz |
Merge "Coerce float Python type to Float; ensure Python float coming back"
-rw-r--r-- | doc/build/changelog/changelog_12.rst | 14 | ||||
-rw-r--r-- | doc/build/changelog/migration_12.rst | 25 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/testing/suite/test_types.py | 18 | ||||
-rw-r--r-- | test/sql/test_types.py | 17 |
5 files changed, 75 insertions, 1 deletions
diff --git a/doc/build/changelog/changelog_12.rst b/doc/build/changelog/changelog_12.rst index a963b96f0..5dc83da2d 100644 --- a/doc/build/changelog/changelog_12.rst +++ b/doc/build/changelog/changelog_12.rst @@ -13,6 +13,20 @@ .. changelog:: :version: 1.2.0b1 + .. change:: 4017 + :tags: bug, sql + :tickets: 4017 + + Added some extra strictness to the handling of Python "float" values + passed to SQL statements. A "float" value will be associated with the + :class:`.Float` datatype and not the Decimal-coercing :class:`.Numeric` + datatype as was the case before, eliminating a confusing warning + emitted on SQLite as well as unecessary coercion to Decimal. + + .. seealso:: + + :ref:`change_floats_12` + .. change:: 3058 :tags: feature, orm :tickets: 3058 diff --git a/doc/build/changelog/migration_12.rst b/doc/build/changelog/migration_12.rst index f0857c531..add12a50c 100644 --- a/doc/build/changelog/migration_12.rst +++ b/doc/build/changelog/migration_12.rst @@ -764,6 +764,31 @@ Where the value of the parameter "x_1" is ``'total/%score'``. :ticket:`2694` +.. _change_floats_12: + +Stronger typing added to "float" datatypes +------------------------------------------ + +A series of changes allow for use of the :class:`.Float` datatype to more +strongly link itself to Python floating point values, instead of the more +generic :class:`.Numeric`. The changes are mostly related to ensuring +that Python floating point values are not erroneously coerced to +``Decimal()``, and are coerced to ``float`` if needed, on the result side, +if the application is working with plain floats. + +* A plain Python "float" value passed to a SQL expression will now be + pulled into a literal parameter with the type :class:`.Float`; previously, + the type was :class:`.Numeric`, with the default "asdecimal=True" flag, which + meant the result type would coerce to ``Decimal()``. In particular, + this would emit a confusing warning on SQLite:: + + float_value = connection.scalar( + select([literal(4.56)]) # the "BindParameter" will now be + # Float, not Numeric(asdecimal=True) + ) + +:ticket:`4017` + Key Behavioral Changes - ORM ============================ diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 7a3c50549..06b5e5c19 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -2604,7 +2604,7 @@ MATCHTYPE = MatchType() _type_map = { int: Integer(), - float: Numeric(), + float: Float(), bool: BOOLEANTYPE, decimal.Decimal: Numeric(), dt.date: Date(), diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py index ee757e1ca..de32e77a4 100644 --- a/lib/sqlalchemy/testing/suite/test_types.py +++ b/lib/sqlalchemy/testing/suite/test_types.py @@ -431,6 +431,24 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): filter_=lambda n: n is not None and round(n, 5) or None ) + @testing.fails_on("mysql", "until we do #4020") + def test_float_coerce_round_trip(self): + expr = 15.7563 + + val = testing.db.scalar( + select([literal(expr)]) + ) + eq_(val, expr) + + # TODO: this one still breaks on MySQL + # def test_decimal_coerce_round_trip(self): + # expr = decimal.Decimal("15.7563") + # + # val = testing.db.scalar( + # select([literal(expr)]) + # ) + # eq_(val, expr) + @testing.requires.precision_numerics_general def test_precision_decimal(self): numbers = set([ diff --git a/test/sql/test_types.py b/test/sql/test_types.py index f46ef21cd..9107adaca 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -2025,6 +2025,23 @@ class ExpressionTest( expr = column('foo', CHAR) == "asdf" eq_(expr.right.type.__class__, CHAR) + def test_actual_literal_adapters(self): + for data, expected in [ + (5, Integer), + (2.65, Float), + (True, Boolean), + (decimal.Decimal("2.65"), Numeric), + (datetime.date(2015, 7, 20), Date), + (datetime.time(10, 15, 20), Time), + (datetime.datetime(2015, 7, 20, 10, 15, 20), DateTime), + (datetime.timedelta(seconds=5), Interval), + (None, types.NullType) + ]: + is_( + literal(data).type.__class__, + expected + ) + def test_typedec_operator_adapt(self): expr = test_table.c.bvalue + "hi" |