From a1d2e4d4915544b0257d294f4a92fb904fbf1a6b Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 28 Dec 2013 17:50:19 -0500 Subject: [PATCH] - apply a similar fix for floats to mssql+pyodbc as we did to firebird - wrangle through osx+pyodbc+freetds to get at least test_suite to pass again with mssql+pyodbc. invovled adding some silly requirements --- doc/build/changelog/changelog_08.rst | 6 +++--- lib/sqlalchemy/dialects/mssql/pyodbc.py | 12 ++++++++--- lib/sqlalchemy/testing/requirements.py | 10 +++++++++ lib/sqlalchemy/testing/suite/test_types.py | 24 ++++++++++++++++++---- test/requirements.py | 12 ++++++++++- 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 96e855ed68..497bf76439 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -28,12 +28,12 @@ in order of RDB$FIELD_POSITION. .. change:: - :tags: bug, firebird + :tags: bug, mssql, firebird :versions: 0.9.0b2 The "asdecimal" flag used with the :class:`.Float` type will now - work with Firebird dialects; previously the decimal conversion was - not occurring. + work with Firebird as well as the mssql+pyodbc dialects; previously the + decimal conversion was not occurring. .. change:: :tags: bug, mssql, pymssql diff --git a/lib/sqlalchemy/dialects/mssql/pyodbc.py b/lib/sqlalchemy/dialects/mssql/pyodbc.py index beb6066f54..a0c0bd2ae6 100644 --- a/lib/sqlalchemy/dialects/mssql/pyodbc.py +++ b/lib/sqlalchemy/dialects/mssql/pyodbc.py @@ -116,8 +116,8 @@ from ...connectors.pyodbc import PyODBCConnector from ... import types as sqltypes, util import decimal +class _ms_numeric_pyodbc(object): -class _MSNumeric_pyodbc(sqltypes.Numeric): """Turns Decimals with adjusted() < 0 or > 7 into strings. The routines here are needed for older pyodbc versions @@ -127,7 +127,7 @@ class _MSNumeric_pyodbc(sqltypes.Numeric): def bind_processor(self, dialect): - super_process = super(_MSNumeric_pyodbc, self).\ + super_process = super(_ms_numeric_pyodbc, self).\ bind_processor(dialect) if not dialect._need_decimal_fix: @@ -180,6 +180,11 @@ class _MSNumeric_pyodbc(sqltypes.Numeric): [str(s) for s in _int][0:value.adjusted() + 1])) return result +class _MSNumeric_pyodbc(_ms_numeric_pyodbc, sqltypes.Numeric): + pass + +class _MSFloat_pyodbc(_ms_numeric_pyodbc, sqltypes.Float): + pass class MSExecutionContext_pyodbc(MSExecutionContext): _embedded_scope_identity = False @@ -238,7 +243,8 @@ class MSDialect_pyodbc(PyODBCConnector, MSDialect): colspecs = util.update_copy( MSDialect.colspecs, { - sqltypes.Numeric: _MSNumeric_pyodbc + sqltypes.Numeric: _MSNumeric_pyodbc, + sqltypes.Float: _MSFloat_pyodbc } ) diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py index 64bc300e0b..055b8ec708 100644 --- a/lib/sqlalchemy/testing/requirements.py +++ b/lib/sqlalchemy/testing/requirements.py @@ -401,6 +401,16 @@ class SuiteRequirements(Requirements): """ return exclusions.open() + @property + def fetch_null_from_numeric(self): + """target backend doesn't crash when you try to select a NUMERIC + value that has a value of NULL. + + Added to support Pyodbc bug #351. + """ + + return exclusions.open() + @property def text_type(self): """Target database must support an unbounded Text() " diff --git a/lib/sqlalchemy/testing/suite/test_types.py b/lib/sqlalchemy/testing/suite/test_types.py index 4733e66660..e6de6e06c8 100644 --- a/lib/sqlalchemy/testing/suite/test_types.py +++ b/lib/sqlalchemy/testing/suite/test_types.py @@ -271,15 +271,31 @@ class NumericTest(fixtures.TestBase): def test_numeric_as_decimal(self): self._do_test( Numeric(precision=8, scale=4), - [15.7563, decimal.Decimal("15.7563"), None], - [decimal.Decimal("15.7563"), None], + [15.7563, decimal.Decimal("15.7563")], + [decimal.Decimal("15.7563")], ) def test_numeric_as_float(self): self._do_test( Numeric(precision=8, scale=4, asdecimal=False), - [15.7563, decimal.Decimal("15.7563"), None], - [15.7563, None], + [15.7563, decimal.Decimal("15.7563")], + [15.7563], + ) + + @testing.requires.fetch_null_from_numeric + def test_numeric_null_as_decimal(self): + self._do_test( + Numeric(precision=8, scale=4), + [None], + [None], + ) + + @testing.requires.fetch_null_from_numeric + def test_numeric_null_as_float(self): + self._do_test( + Numeric(precision=8, scale=4, asdecimal=False), + [None], + [None], ) @testing.requires.floats_to_four_decimals diff --git a/test/requirements.py b/test/requirements.py index 7bf2c66414..21583ec22c 100644 --- a/test/requirements.py +++ b/test/requirements.py @@ -566,9 +566,19 @@ class DefaultRequirements(SuiteRequirements): ("mysql+oursql", None, None, "Floating point error"), ("firebird", None, None, "Firebird still has FP inaccuracy even " - "with only four decimal places") + "with only four decimal places"), + ('mssql+pyodbc', None, None, + 'mssql+pyodbc has FP inaccuracy even with ' + 'only four decimal places ' + ) ]) + @property + def fetch_null_from_numeric(self): + return skip_if( + ("mssql+pyodbc", None, None, "crashes due to bug #351"), + ) + @property def python2(self): return skip_if( -- 2.47.2