From e9c748a7bf1acb1423efa92ad797e9a0fbcf1cbb Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 25 Aug 2013 17:37:59 -0400 Subject: - ensure rowcount is returned for an UPDATE with no implicit returning - modernize test for that - use py3k compatible next() in test_returning/test_versioning --- test/engine/test_execute.py | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 1d2aebf97..9623c080a 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -17,9 +17,9 @@ from sqlalchemy.testing.engines import testing_engine import logging.handlers from sqlalchemy.dialects.oracle.zxjdbc import ReturningParam from sqlalchemy.engine import result as _result, default -from sqlalchemy.engine.base import Connection, Engine +from sqlalchemy.engine.base import Engine from sqlalchemy.testing import fixtures -from sqlalchemy.testing.mock import Mock, call +from sqlalchemy.testing.mock import Mock, call, patch users, metadata, users_autoinc = None, None, None @@ -29,11 +29,11 @@ class ExecuteTest(fixtures.TestBase): global users, users_autoinc, metadata metadata = MetaData(testing.db) users = Table('users', metadata, - Column('user_id', INT, primary_key = True, autoincrement=False), + Column('user_id', INT, primary_key=True, autoincrement=False), Column('user_name', VARCHAR(20)), ) users_autoinc = Table('users_autoinc', metadata, - Column('user_id', INT, primary_key = True, + Column('user_id', INT, primary_key=True, test_needs_autoincrement=True), Column('user_name', VARCHAR(20)), ) @@ -892,42 +892,42 @@ class ResultProxyTest(fixtures.TestBase): def test_no_rowcount_on_selects_inserts(self): """assert that rowcount is only called on deletes and updates. - This because cursor.rowcount can be expensive on some dialects - such as Firebird. + This because cursor.rowcount may can be expensive on some dialects + such as Firebird, however many dialects require it be called + before the cursor is closed. """ metadata = self.metadata engine = engines.testing_engine() - metadata.bind = engine t = Table('t1', metadata, Column('data', String(10)) ) - metadata.create_all() + metadata.create_all(engine) - class BreakRowcountMixin(object): - @property - def rowcount(self): - assert False + with patch.object(engine.dialect.execution_ctx_cls, "rowcount") as mock_rowcount: + mock_rowcount.__get__ = Mock() + engine.execute(t.insert(), + {'data': 'd1'}, + {'data': 'd2'}, + {'data': 'd3'}) - execution_ctx_cls = engine.dialect.execution_ctx_cls - engine.dialect.execution_ctx_cls = type("FakeCtx", - (BreakRowcountMixin, - execution_ctx_cls), - {}) + eq_(len(mock_rowcount.__get__.mock_calls), 0) - try: - r = t.insert().execute({'data': 'd1'}, {'data': 'd2'}, - {'data': 'd3'}) - eq_(t.select().execute().fetchall(), [('d1', ), ('d2', ), - ('d3', )]) - assert_raises(AssertionError, t.update().execute, {'data' - : 'd4'}) - assert_raises(AssertionError, t.delete().execute) - finally: - engine.dialect.execution_ctx_cls = execution_ctx_cls + eq_( + engine.execute(t.select()).fetchall(), + [('d1', ), ('d2', ), ('d3', )] + ) + eq_(len(mock_rowcount.__get__.mock_calls), 0) + + engine.execute(t.update(), {'data': 'd4'}) + + eq_(len(mock_rowcount.__get__.mock_calls), 1) + + engine.execute(t.delete()) + eq_(len(mock_rowcount.__get__.mock_calls), 2) @testing.requires.python26 -- cgit v1.2.1 From 08a6a8b51916ab1d084a0070bbb07001cabb1c38 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 22 Sep 2013 20:35:40 -0400 Subject: - Removed some now unneeded version checks [ticket:2829] courtesy alex gaynor --- test/engine/test_execute.py | 1 - 1 file changed, 1 deletion(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 9623c080a..b116e4d6b 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -930,7 +930,6 @@ class ResultProxyTest(fixtures.TestBase): eq_(len(mock_rowcount.__get__.mock_calls), 2) - @testing.requires.python26 def test_rowproxy_is_sequence(self): import collections from sqlalchemy.engine import RowProxy -- cgit v1.2.1 From 59ca4633acd42d90dc01aef9a40373ee98080481 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 17 Nov 2013 13:45:23 -0500 Subject: - remove informix dialect, moved out to https://bitbucket.org/zzzeek/sqlalchemy_informixdb - remove informix, maxdb, access symbols from tests etc. --- test/engine/test_execute.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index b116e4d6b..dbefc9f42 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -59,10 +59,9 @@ class ExecuteTest(fixtures.TestBase): scalar(stmt) eq_(result, '%') - @testing.fails_on_everything_except('firebird', 'maxdb', + @testing.fails_on_everything_except('firebird', 'sqlite', '+pyodbc', - '+mxodbc', '+zxjdbc', 'mysql+oursql', - 'informix+informixdb') + '+mxodbc', '+zxjdbc', 'mysql+oursql') def test_raw_qmark(self): def go(conn): conn.execute('insert into users (user_id, user_name) ' @@ -182,7 +181,7 @@ class ExecuteTest(fixtures.TestBase): finally: conn.close() - @testing.fails_on_everything_except('sqlite', 'oracle+cx_oracle', 'informix+informixdb') + @testing.fails_on_everything_except('sqlite', 'oracle+cx_oracle') def test_raw_named(self): def go(conn): conn.execute('insert into users (user_id, user_name) ' -- cgit v1.2.1 From f112dc1d533033f19186eb65227aba1660d03102 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 22 Nov 2013 18:35:36 -0500 Subject: - Fixed bug where SQL statement would be improperly ASCII-encoded when a pre-DBAPI :class:`.StatementError` were raised within :meth:`.Connection.execute`, causing encoding errors for non-ASCII statements. The stringification now remains within Python unicode thus avoiding encoding errors. [ticket:2871] --- test/engine/test_execute.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index dbefc9f42..8204eb529 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -1,4 +1,4 @@ - +# coding: utf-8 from sqlalchemy.testing import eq_, assert_raises, assert_raises_message, \ config, is_ @@ -226,7 +226,7 @@ class ExecuteTest(fixtures.TestBase): def _go(conn): assert_raises_message( tsa.exc.StatementError, - r"nope \(original cause: Exception: nope\) 'SELECT 1 ", + r"nope \(original cause: Exception: nope\) u?'SELECT 1 ", conn.execute, select([1]).\ where( @@ -240,6 +240,24 @@ class ExecuteTest(fixtures.TestBase): finally: conn.close() + def test_stmt_exception_non_ascii(self): + name = util.u('méil') + assert_raises_message( + tsa.exc.StatementError, + util.u( + "A value is required for bind parameter 'uname'" + r'.*SELECT users.user_name AS "m\\xe9il"') if util.py2k + else + util.u( + "A value is required for bind parameter 'uname'" + '.*SELECT users.user_name AS "méil"') + , + testing.db.execute, + select([users.c.user_name.label(name)]).where( + users.c.user_name == bindparam("uname")), + {'uname_incorrect': 'foo'} + ) + def test_stmt_exception_pickleable_no_dbapi(self): self._test_stmt_exception_pickleable(Exception("hello world")) -- cgit v1.2.1 From 54b8969be144a642311da60656a4d0410eff7030 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 23 Nov 2013 17:22:56 -0500 Subject: -be more agnostic of quotes here --- test/engine/test_execute.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 8204eb529..1f7bad31a 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -246,11 +246,11 @@ class ExecuteTest(fixtures.TestBase): tsa.exc.StatementError, util.u( "A value is required for bind parameter 'uname'" - r'.*SELECT users.user_name AS "m\\xe9il"') if util.py2k + r'.*SELECT users.user_name AS .m\\xe9il.') if util.py2k else util.u( "A value is required for bind parameter 'uname'" - '.*SELECT users.user_name AS "méil"') + '.*SELECT users.user_name AS .méil.') , testing.db.execute, select([users.c.user_name.label(name)]).where( -- cgit v1.2.1 From 6d5eae78a7dd79ad7bd0a0951bc6c95437d0fa8e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 7 Dec 2013 17:20:05 -0500 Subject: - A DBAPI that raises an error on ``connect()`` which is not a subclass of dbapi.Error (such as ``TypeError``, ``NotImplementedError``, etc.) will propagate the exception unchanged. Previously, the error handling specific to the ``connect()`` routine would both inappropriately run the exception through the dialect's :meth:`.Dialect.is_disconnect` routine as well as wrap it in a :class:`sqlalchemy.exc.DBAPIError`. It is now propagated unchanged in the same way as occurs within the execute process. [ticket:2881] - add tests for this in test_parseconnect, but also add tests in test_execute to ensure the execute() behavior as well --- test/engine/test_execute.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 1f7bad31a..7312bb041 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -203,19 +203,37 @@ class ExecuteTest(fixtures.TestBase): finally: conn.close() + @testing.engines.close_open_connections def test_exception_wrapping_dbapi(self): - def go(conn): + conn = testing.db.connect() + for _c in testing.db, conn: assert_raises_message( tsa.exc.DBAPIError, r"not_a_valid_statement", - conn.execute, 'not_a_valid_statement' + _c.execute, 'not_a_valid_statement' ) - go(testing.db) - conn = testing.db.connect() - try: - go(conn) - finally: - conn.close() + + @testing.requires.sqlite + def test_exception_wrapping_non_dbapi_error(self): + e = create_engine('sqlite://') + e.dialect.is_disconnect = is_disconnect = Mock() + + c = e.connect() + + c.connection.cursor = Mock( + return_value=Mock( + execute=Mock( + side_effect=TypeError("I'm not a DBAPI error") + )) + ) + + assert_raises_message( + TypeError, + "I'm not a DBAPI error", + c.execute, "select " + ) + eq_(is_disconnect.call_count, 0) + def test_exception_wrapping_non_dbapi_statement(self): class MyType(TypeDecorator): -- cgit v1.2.1 From fa5970c26547d03ba66f885ef9d7fdcd686648a1 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 5 Jan 2014 18:25:51 -0500 Subject: - these tests are really old but trying to make sure everything is closed out --- test/engine/test_execute.py | 80 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 7312bb041..c2479eff7 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -218,21 +218,20 @@ class ExecuteTest(fixtures.TestBase): e = create_engine('sqlite://') e.dialect.is_disconnect = is_disconnect = Mock() - c = e.connect() - - c.connection.cursor = Mock( - return_value=Mock( - execute=Mock( - side_effect=TypeError("I'm not a DBAPI error") - )) - ) + with e.connect() as c: + c.connection.cursor = Mock( + return_value=Mock( + execute=Mock( + side_effect=TypeError("I'm not a DBAPI error") + )) + ) - assert_raises_message( - TypeError, - "I'm not a DBAPI error", - c.execute, "select " - ) - eq_(is_disconnect.call_count, 0) + assert_raises_message( + TypeError, + "I'm not a DBAPI error", + c.execute, "select " + ) + eq_(is_disconnect.call_count, 0) def test_exception_wrapping_non_dbapi_statement(self): @@ -260,21 +259,22 @@ class ExecuteTest(fixtures.TestBase): def test_stmt_exception_non_ascii(self): name = util.u('méil') - assert_raises_message( - tsa.exc.StatementError, - util.u( - "A value is required for bind parameter 'uname'" - r'.*SELECT users.user_name AS .m\\xe9il.') if util.py2k - else + with testing.db.connect() as conn: + assert_raises_message( + tsa.exc.StatementError, util.u( "A value is required for bind parameter 'uname'" - '.*SELECT users.user_name AS .méil.') - , - testing.db.execute, - select([users.c.user_name.label(name)]).where( - users.c.user_name == bindparam("uname")), - {'uname_incorrect': 'foo'} - ) + r'.*SELECT users.user_name AS .m\\xe9il.') if util.py2k + else + util.u( + "A value is required for bind parameter 'uname'" + '.*SELECT users.user_name AS .méil.') + , + conn.execute, + select([users.c.user_name.label(name)]).where( + users.c.user_name == bindparam("uname")), + {'uname_incorrect': 'foo'} + ) def test_stmt_exception_pickleable_no_dbapi(self): self._test_stmt_exception_pickleable(Exception("hello world")) @@ -361,17 +361,17 @@ class ExecuteTest(fixtures.TestBase): def test_engine_level_options(self): eng = engines.testing_engine(options={'execution_options': {'foo': 'bar'}}) - conn = eng.contextual_connect() - eq_(conn._execution_options['foo'], 'bar') - eq_(conn.execution_options(bat='hoho')._execution_options['foo' - ], 'bar') - eq_(conn.execution_options(bat='hoho')._execution_options['bat' - ], 'hoho') - eq_(conn.execution_options(foo='hoho')._execution_options['foo' - ], 'hoho') - eng.update_execution_options(foo='hoho') - conn = eng.contextual_connect() - eq_(conn._execution_options['foo'], 'hoho') + with eng.contextual_connect() as conn: + eq_(conn._execution_options['foo'], 'bar') + eq_(conn.execution_options(bat='hoho')._execution_options['foo' + ], 'bar') + eq_(conn.execution_options(bat='hoho')._execution_options['bat' + ], 'hoho') + eq_(conn.execution_options(foo='hoho')._execution_options['foo' + ], 'hoho') + eng.update_execution_options(foo='hoho') + conn = eng.contextual_connect() + eq_(conn._execution_options['foo'], 'hoho') @testing.requires.ad_hoc_engines def test_generative_engine_execution_options(self): @@ -418,8 +418,8 @@ class ExecuteTest(fixtures.TestBase): event.listen(eng, "before_execute", l2) event.listen(eng1, "before_execute", l3) - eng.execute(select([1])) - eng1.execute(select([1])) + eng.execute(select([1])).close() + eng1.execute(select([1])).close() eq_(canary, ["l1", "l2", "l3", "l1", "l2"]) -- cgit v1.2.1 From 2775c95b1ee30831216cc558ceb88aa8f8353dbe Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 11 Jan 2014 13:12:40 -0500 Subject: new changelog --- test/engine/test_execute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index c2479eff7..d3bd3c2cd 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -1050,7 +1050,7 @@ class ResultProxyTest(fixtures.TestBase): class ExecutionOptionsTest(fixtures.TestBase): def test_dialect_conn_options(self): - engine = testing_engine("sqlite://") + engine = testing_engine("sqlite://", options=dict(_initialize=False)) engine.dialect = Mock() conn = engine.connect() c2 = conn.execution_options(foo="bar") -- cgit v1.2.1 From 232e3762b7cbf425dd911ae2421512382d6024af Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 13 Jan 2014 10:37:15 -0500 Subject: revert r2775c95b1ee30831216cc5 which was mostly an inadvertent commit, except for the changelog part --- test/engine/test_execute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index d3bd3c2cd..c2479eff7 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -1050,7 +1050,7 @@ class ResultProxyTest(fixtures.TestBase): class ExecutionOptionsTest(fixtures.TestBase): def test_dialect_conn_options(self): - engine = testing_engine("sqlite://", options=dict(_initialize=False)) + engine = testing_engine("sqlite://") engine.dialect = Mock() conn = engine.connect() c2 = conn.execution_options(foo="bar") -- cgit v1.2.1 From 1536bc4664a248faf81c62326fe1be3dbe18b8cd Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Mon, 13 Jan 2014 14:05:05 -0500 Subject: - The MySQL CAST compilation now takes into account aspects of a string type such as "charset" and "collation". While MySQL wants all character- based CAST calls to use the CHAR type, we now create a real CHAR object at CAST time and copy over all the parameters it has, so that an expression like ``cast(x, mysql.TEXT(charset='utf8'))`` will render ``CAST(t.col AS CHAR CHARACTER SET utf8)``. - Added new "unicode returns" detection to the MySQL dialect and to the default dialect system overall, such that any dialect can add extra "tests" to the on-first-connect "does this DBAPI return unicode directly?" detection. In this case, we are adding a check specifically against the "utf8" encoding with an explicit "utf8_bin" collation type (after checking that this collation is available) to test for some buggy unicode behavior observed with MySQLdb version 1.2.3. While MySQLdb has resolved this issue as of 1.2.4, the check here should guard against regressions. The change also allows the "unicode" checks to log in the engine logs, which was not previously the case. [ticket:2906] --- test/engine/test_execute.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/engine/test_execute.py') diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index c2479eff7..d3bd3c2cd 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -1050,7 +1050,7 @@ class ResultProxyTest(fixtures.TestBase): class ExecutionOptionsTest(fixtures.TestBase): def test_dialect_conn_options(self): - engine = testing_engine("sqlite://") + engine = testing_engine("sqlite://", options=dict(_initialize=False)) engine.dialect = Mock() conn = engine.connect() c2 = conn.execution_options(foo="bar") -- cgit v1.2.1