From a5d027ab665585f65581fdc6fd2bd00874d3c714 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 15 Dec 2017 10:56:18 -0500 Subject: [PATCH] Open up all cx_Oracle numeric tests, finish infinity support Added some additional rules to fully handle ``Decimal('Infinity')``, ``Decimal('-Infinity')`` values with cx_Oracle numerics when using ``asdecimal=True``. Allow remaining cx_Oracle numeric tests that were waiting for the refactor to be finished and forgot to get enabled. Change-Id: I1e2365176e34559c0230c84f800a7cfe0a034ed5 Fixes: #4064 --- doc/build/changelog/unreleased_12/4064.rst | 7 +++ lib/sqlalchemy/dialects/oracle/cx_oracle.py | 14 +++++- lib/sqlalchemy/testing/suite/test_types.py | 16 ------- test/dialect/oracle/test_types.py | 53 ++++++++++++++++++--- 4 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 doc/build/changelog/unreleased_12/4064.rst diff --git a/doc/build/changelog/unreleased_12/4064.rst b/doc/build/changelog/unreleased_12/4064.rst new file mode 100644 index 0000000000..70db0c1b8f --- /dev/null +++ b/doc/build/changelog/unreleased_12/4064.rst @@ -0,0 +1,7 @@ +.. change:: + :tags: bug, oracle + :tickets: 4064 + + Added some additional rules to fully handle ``Decimal('Infinity')``, + ``Decimal('-Infinity')`` values with cx_Oracle numerics when using + ``asdecimal=True``. diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index 68ecce5194..0288fe8981 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -223,6 +223,8 @@ class _OracleNumeric(sqltypes.Numeric): def process(value): if isinstance(value, (int, float)): return processor(value) + elif value is not None and value.is_infinite(): + return float(value) else: return value return process @@ -242,7 +244,12 @@ class _OracleNumeric(sqltypes.Numeric): outconverter = None if precision: if self.asdecimal: - if is_cx_oracle_6: + if default_type == cx_Oracle.NATIVE_FLOAT: + # receiving float and doing Decimal after the fact + # allows for float("inf") to be handled + type_ = default_type + outconverter = decimal.Decimal + elif is_cx_oracle_6: type_ = decimal.Decimal else: type_ = cx_Oracle.STRING @@ -258,7 +265,10 @@ class _OracleNumeric(sqltypes.Numeric): type_ = cx_Oracle.NATIVE_FLOAT else: if self.asdecimal: - if is_cx_oracle_6: + if default_type == cx_Oracle.NATIVE_FLOAT: + type_ = default_type + outconverter = decimal.Decimal + elif is_cx_oracle_6: type_ = decimal.Decimal else: type_ = cx_Oracle.STRING diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py index b9bb179aba..e419fb450b 100644 --- a/lib/sqlalchemy/testing/suite/test_types.py +++ b/lib/sqlalchemy/testing/suite/test_types.py @@ -380,8 +380,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): filter_=lambda n: n is not None and round(n, 5) or None ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") @testing.requires.precision_generic_float_type def test_float_custom_scale(self): self._do_test( @@ -391,8 +389,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): check_scale=True ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") def test_numeric_as_decimal(self): self._do_test( Numeric(precision=8, scale=4), @@ -400,8 +396,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): [decimal.Decimal("15.7563")], ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") def test_numeric_as_float(self): self._do_test( Numeric(precision=8, scale=4, asdecimal=False), @@ -409,8 +403,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): [15.7563], ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") @testing.requires.fetch_null_from_numeric def test_numeric_null_as_decimal(self): self._do_test( @@ -427,8 +419,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): [None], ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") @testing.requires.floats_to_four_decimals def test_float_as_decimal(self): self._do_test( @@ -437,8 +427,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): [decimal.Decimal("15.7563"), None], ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") def test_float_as_float(self): self._do_test( Float(precision=8), @@ -464,8 +452,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): # ) # eq_(val, expr) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") @testing.requires.precision_numerics_general def test_precision_decimal(self): numbers = set([ @@ -480,8 +466,6 @@ class NumericTest(_LiteralRoundTripFixture, fixtures.TestBase): numbers, ) - @testing.skip_if( - "oracle", "temporary skip until cx_oracle refactor is merged") @testing.requires.precision_numerics_enotation_large def test_enotation_decimal(self): """test exceedingly small decimals. diff --git a/test/dialect/oracle/test_types.py b/test/dialect/oracle/test_types.py index 3d08657d8a..394fc29a85 100644 --- a/test/dialect/oracle/test_types.py +++ b/test/dialect/oracle/test_types.py @@ -282,19 +282,58 @@ class TypesTest(fixtures.TestBase): Column("intcol", Integer), Column("numericcol", oracle.BINARY_DOUBLE(asdecimal=False))) t1.create() - t1.insert().execute( - intcol=1, - numericcol=float("inf"), + t1.insert().execute([ + dict( + intcol=1, + numericcol=float("inf") + ), + dict( + intcol=2, + numericcol=float("-inf") + ), + ]) + + eq_( + select([t1.c.numericcol]). + order_by(t1.c.intcol).execute().fetchall(), + [(float('inf'), ), (float('-inf'), )] + ) + + eq_( + testing.db.execute( + "select numericcol from t1 order by intcol").fetchall(), + [(float('inf'), ), (float('-inf'), )] ) + @testing.provide_metadata + def test_numeric_infinity_decimal(self): + m = self.metadata + t1 = Table('t1', m, + Column("intcol", Integer), + Column("numericcol", oracle.BINARY_DOUBLE(asdecimal=True))) + t1.create() + t1.insert().execute([ + dict( + intcol=1, + numericcol=decimal.Decimal("Infinity") + ), + dict( + intcol=2, + numericcol=decimal.Decimal("-Infinity") + ), + ]) + eq_( - select([t1.c.numericcol]).scalar(), - float("inf") + select([t1.c.numericcol]). + order_by(t1.c.intcol).execute().fetchall(), + [(decimal.Decimal("Infinity"), ), (decimal.Decimal("-Infinity"), )] ) eq_( - testing.db.scalar("select numericcol from t1"), - float("inf")) + testing.db.execute( + "select numericcol from t1 order by intcol").fetchall(), + [(decimal.Decimal("Infinity"), ), (decimal.Decimal("-Infinity"), )] + ) @testing.provide_metadata def test_numerics_broken_inspection(self): -- 2.47.3