From: Mike Bayer Date: Thu, 4 Oct 2012 22:26:55 +0000 (-0400) Subject: - add back __engine_options__ X-Git-Tag: rel_0_8_0b1~78 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=70be21311772c687105802850380050bfeb4bd82;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - add back __engine_options__ - break test_insert tests into explicitly get_lastrowid() vs. implicit_returning tests, fix up requirements to split them out --- diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 778ec6be61..21e02fcdc2 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -441,9 +441,9 @@ class DefaultExecutionContext(interfaces.ExecutionContext): self.isdelete = compiled.isdelete if self.isinsert or self.isupdate or self.isdelete: - self._is_explicit_returning = compiled.statement._returning - self._is_implicit_returning = compiled.returning and \ - not compiled.statement._returning + self._is_explicit_returning = bool(compiled.statement._returning) + self._is_implicit_returning = bool(compiled.returning and \ + not compiled.statement._returning) if not parameters: self.compiled_parameters = [compiled.construct_params()] diff --git a/lib/sqlalchemy/testing/engines.py b/lib/sqlalchemy/testing/engines.py index 74e22adf1e..9d15c50785 100644 --- a/lib/sqlalchemy/testing/engines.py +++ b/lib/sqlalchemy/testing/engines.py @@ -180,6 +180,7 @@ def reconnecting_engine(url=None, options=None): engine.dispose = dispose return engine + def testing_engine(url=None, options=None): """Produce an engine configured by --options with optional overrides.""" diff --git a/lib/sqlalchemy/testing/plugin/noseplugin.py b/lib/sqlalchemy/testing/plugin/noseplugin.py index 59a364be9a..0dcd45825f 100644 --- a/lib/sqlalchemy/testing/plugin/noseplugin.py +++ b/lib/sqlalchemy/testing/plugin/noseplugin.py @@ -28,6 +28,7 @@ warnings = None profiling = None assertions = None requirements = None +config = None util = None file_config = None @@ -38,6 +39,7 @@ db_label = None db_url = None db_opts = {} options = None +_existing_engine = None def _log(option, opt_str, value, parser): global logging @@ -297,9 +299,10 @@ class NoseSQLAlchemy(Plugin): # late imports, has to happen after config as well # as nose plugins like coverage global util, fixtures, engines, exclusions, \ - assertions, warnings, profiling + assertions, warnings, profiling,\ + config from sqlalchemy.testing import fixtures, engines, exclusions, \ - assertions, warnings, profiling + assertions, warnings, profiling, config from sqlalchemy import util def describeTest(self, test): @@ -335,11 +338,7 @@ class NoseSQLAlchemy(Plugin): test_suite.__name__ = cls.__name__ for requirement in cls.__requires__: check = getattr(config.requirements, requirement) - try: - check(test_suite)() - except TypeError: - import pdb - pdb.set_trace() + check(test_suite)() if cls.__unsupported_on__: spec = exclusions.db_spec(*cls.__unsupported_on__) @@ -378,11 +377,24 @@ class NoseSQLAlchemy(Plugin): engines.testing_reaper._after_test_ctx() warnings.resetwarnings() + def _setup_engine(self, ctx): + if getattr(ctx, '__engine_options__', None): + global _existing_engine + _existing_engine = config.db + config.db = engines.testing_engine(options=ctx.__engine_options__) + + def _restore_engine(self, ctx): + global _existing_engine + if _existing_engine is not None: + config.db = _existing_engine + _existing_engine = None + def startContext(self, ctx): if not isinstance(ctx, type) \ or not issubclass(ctx, fixtures.TestBase): return self._do_skips(ctx) + self._setup_engine(ctx) def stopContext(self, ctx): if not isinstance(ctx, type) \ @@ -391,3 +403,4 @@ class NoseSQLAlchemy(Plugin): engines.testing_reaper._stop_test_ctx() if not options.low_connections: assertions.global_cleanup_assertions() + self._restore_engine(ctx) diff --git a/lib/sqlalchemy/testing/requirements.py b/lib/sqlalchemy/testing/requirements.py index 8a5a82cdb9..560bc9c97a 100644 --- a/lib/sqlalchemy/testing/requirements.py +++ b/lib/sqlalchemy/testing/requirements.py @@ -86,6 +86,26 @@ class SuiteRequirements(Requirements): "Backend does not require denormalized names." ) + @property + def implements_get_lastrowid(self): + """"target dialect implements the executioncontext.get_lastrowid() + method without reliance on RETURNING. + + """ + return exclusions.open() + + @property + def emulated_lastrowid(self): + """"target dialect retrieves cursor.lastrowid, or fetches + from a database-side function after an insert() construct executes, + within the get_lastrowid() method. + + Only dialects that "pre-execute", or need RETURNING to get last + inserted id, would return closed/fail/skip for this. + + """ + return exclusions.closed() + @property def dbapi_lastrowid(self): """"target platform includes a 'lastrowid' accessor on the DBAPI diff --git a/lib/sqlalchemy/testing/suite/test_insert.py b/lib/sqlalchemy/testing/suite/test_insert.py index 61b11966bc..3cd7d39bca 100644 --- a/lib/sqlalchemy/testing/suite/test_insert.py +++ b/lib/sqlalchemy/testing/suite/test_insert.py @@ -8,9 +8,13 @@ from sqlalchemy import Integer, String, select, util from ..schema import Table, Column -class InsertSequencingTest(fixtures.TablesTest): +class LastrowidTest(fixtures.TablesTest): run_deletes = 'each' + __requires__ = 'implements_get_lastrowid', 'autoincrement_insert' + + __engine_options__ = {"implicit_returning": False} + @classmethod def define_tables(cls, metadata): Table('autoinc_pk', metadata, @@ -24,23 +28,21 @@ class InsertSequencingTest(fixtures.TablesTest): Column('data', String(50)) ) - def _assert_round_trip(self, table): - row = config.db.execute(table.select()).first() + def _assert_round_trip(self, table, conn): + row = conn.execute(table.select()).first() eq_( row, (1, "some data") ) - @requirements.autoincrement_insert def test_autoincrement_on_insert(self): config.db.execute( self.tables.autoinc_pk.insert(), data="some data" ) - self._assert_round_trip(self.tables.autoinc_pk) + self._assert_round_trip(self.tables.autoinc_pk, config.db) - @requirements.autoincrement_insert def test_last_inserted_id(self): r = config.db.execute( @@ -107,7 +109,16 @@ class InsertBehaviorTest(fixtures.TablesTest): class ReturningTest(fixtures.TablesTest): run_deletes = 'each' - __requires__ = 'returning', + __requires__ = 'returning', 'autoincrement_insert' + + __engine_options__ = {"implicit_returning": True} + + def _assert_round_trip(self, table, conn): + row = conn.execute(table.select()).first() + eq_( + row, + (1, "some data") + ) @classmethod def define_tables(cls, metadata): @@ -129,8 +140,27 @@ class ReturningTest(fixtures.TablesTest): fetched_pk = config.db.scalar(select([table.c.id])) eq_(fetched_pk, pk) + def test_autoincrement_on_insert_implcit_returning(self): + + config.db.execute( + self.tables.autoinc_pk.insert(), + data="some data" + ) + self._assert_round_trip(self.tables.autoinc_pk, config.db) + + def test_last_inserted_id_implicit_returning(self): + + r = config.db.execute( + self.tables.autoinc_pk.insert(), + data="some data" + ) + pk = config.db.scalar(select([self.tables.autoinc_pk.c.id])) + eq_( + r.inserted_primary_key, + [pk] + ) -__all__ = ('InsertSequencingTest', 'InsertBehaviorTest', 'ReturningTest') +__all__ = ('LastrowidTest', 'InsertBehaviorTest', 'ReturningTest')