From 03a3b5ffd3027c79ce9b17b9388fd074e69b889d Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 30 Nov 2015 12:19:26 -0500 Subject: [PATCH] - A descriptive ValueError is now raised in the event that SQL server returns an invalid date or time format from a DATE or TIME column, rather than failing with a NoneType error. Pull request courtesy Ed Avis. pullreq github:206 --- doc/build/changelog/changelog_10.rst | 10 ++++++++ lib/sqlalchemy/dialects/mssql/base.py | 12 +++++++-- test/dialect/mssql/test_types.py | 36 ++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index be0654b849..537f750ca3 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,16 @@ .. changelog:: :version: 1.0.10 + .. change:: + :tags: bug, mssql + :versions: 1.1.0b1 + :pullreq: github:206 + + A descriptive ValueError is now raised in the event that SQL server + returns an invalid date or time format from a DATE or TIME + column, rather than failing with a NoneType error. Pull request + courtesy Ed Avis. + .. change:: :tags: bug, py3k :versions: 1.1.0b1 diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 487f21df93..1ee328e834 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -533,9 +533,13 @@ class _MSDate(sqltypes.Date): if isinstance(value, datetime.datetime): return value.date() elif isinstance(value, util.string_types): + m = self._reg.match(value) + if not m: + raise ValueError( + "could not parse %r as a date value" % (value, )) return datetime.date(*[ int(x or 0) - for x in self._reg.match(value).groups() + for x in m.groups() ]) else: return value @@ -567,9 +571,13 @@ class TIME(sqltypes.TIME): if isinstance(value, datetime.datetime): return value.time() elif isinstance(value, util.string_types): + m = self._reg.match(value) + if not m: + raise ValueError( + "could not parse %r as a time value" % (value, )) return datetime.time(*[ int(x or 0) - for x in self._reg.match(value).groups()]) + for x in m.groups()]) else: return value return process diff --git a/test/dialect/mssql/test_types.py b/test/dialect/mssql/test_types.py index 6c6ff6841b..dad86c60a7 100644 --- a/test/dialect/mssql/test_types.py +++ b/test/dialect/mssql/test_types.py @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -from sqlalchemy.testing import eq_, engines, pickleable +from sqlalchemy.testing import eq_, engines, pickleable, assert_raises_message import datetime import os from sqlalchemy import Table, Column, MetaData, Float, \ @@ -8,8 +8,8 @@ from sqlalchemy import Table, Column, MetaData, Float, \ UnicodeText, LargeBinary from sqlalchemy import types, schema from sqlalchemy.databases import mssql -from sqlalchemy.dialects.mssql.base import TIME, MS_2005_VERSION, \ - MS_2008_VERSION +from sqlalchemy.dialects.mssql.base import TIME, _MSDate +from sqlalchemy.dialects.mssql.base import MS_2005_VERSION, MS_2008_VERSION from sqlalchemy.testing import fixtures, \ AssertsExecutionResults, ComparesTables from sqlalchemy import testing @@ -34,6 +34,36 @@ class TimeTypeTest(fixtures.TestBase): result_processor = mssql_time_type.result_processor(None, None) eq_(expected, result_processor(value)) + def test_result_processor_invalid(self): + mssql_time_type = TIME() + result_processor = mssql_time_type.result_processor(None, None) + assert_raises_message( + ValueError, + "could not parse 'abc' as a time value", + result_processor, 'abc' + ) + + +class MSDateTypeTest(fixtures.TestBase): + + def test_result_processor(self): + expected = datetime.date(2000, 1, 2) + self._assert_result_processor(expected, '2000-01-02') + + def _assert_result_processor(self, expected, value): + mssql_date_type = _MSDate() + result_processor = mssql_date_type.result_processor(None, None) + eq_(expected, result_processor(value)) + + def test_result_processor_invalid(self): + mssql_date_type = _MSDate() + result_processor = mssql_date_type.result_processor(None, None) + assert_raises_message( + ValueError, + "could not parse 'abc' as a date value", + result_processor, 'abc' + ) + class TypeDDLTest(fixtures.TestBase): -- 2.47.2