From: Mike Bayer Date: Sun, 9 Nov 2008 19:32:25 +0000 (+0000) Subject: - Removed the 'properties' attribute of the X-Git-Tag: rel_0_5rc4~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0cff22720b4c60c1c305b5ab858c2f453cc66e34;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Removed the 'properties' attribute of the Connection object, Connection.info should be used. - Method consoliation in Connection, ExecutionContext --- diff --git a/CHANGES b/CHANGES index c59eb826ae..d71fd226ea 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,10 @@ CHANGES - Query.get() returns a more informative error message when executed against multiple entities. [ticket:1220] + +- sql + - Removed the 'properties' attribute of the + Connection object, Connection.info should be used. - access - Added support for Currency type. diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index b810f5f67b..832903a735 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -324,7 +324,7 @@ class ExecutionContext(object): raise NotImplementedError() - def pre_execution(self): + def pre_exec(self): """Called before an execution of a compiled statement. If a compiled statement was passed to this ExecutionContext, @@ -334,7 +334,7 @@ class ExecutionContext(object): raise NotImplementedError() - def post_execution(self): + def post_exec(self): """Called after the execution of a compiled statement. If a compiled statement was passed to this ExecutionContext, @@ -352,11 +352,6 @@ class ExecutionContext(object): raise NotImplementedError() - def should_autocommit_compiled(self, compiled): - """return True if the given Compiled object refers to a "committable" statement.""" - - raise NotImplementedError() - def should_autocommit_text(self, statement): """Parse the given textual statement and return True if it refers to a "committable" statement""" @@ -425,6 +420,7 @@ class Compiled(object): bind Optional Engine or Connection to compile this statement against. + """ self.dialect = dialect self.statement = statement @@ -502,6 +498,7 @@ class Connection(Connectable): a begin method to return Transaction objects. The Connection object is **not** threadsafe. + """ def __init__(self, engine, connection=None, close_with_result=False, @@ -511,6 +508,7 @@ class Connection(Connectable): Connection objects are typically constructed by an [sqlalchemy.engine#Engine], see the ``connect()`` and ``contextual_connect()`` methods of Engine. + """ self.engine = engine @@ -528,6 +526,7 @@ class Connection(Connectable): This is used to execute "sub" statements within a single execution, usually an INSERT statement. + """ return self.engine.Connection(self.engine, self.__connection, _branch=True) @@ -568,8 +567,8 @@ class Connection(Connectable): def should_close_with_result(self): """Indicates if this Connection should be closed when a corresponding ResultProxy is closed; this is essentially an auto-release mode. + """ - return self.__close_with_result @property @@ -577,16 +576,14 @@ class Connection(Connectable): """A collection of per-DB-API connection instance properties.""" return self.connection.info - properties = property(info, doc="""An alias for the .info collection, will be removed in 0.5.""") - def connect(self): """Returns self. This ``Connectable`` interface method returns self, allowing Connections to be used interchangably with Engines in most situations that require a bind. - """ + """ return self def contextual_connect(self, **kwargs): @@ -595,8 +592,8 @@ class Connection(Connectable): This ``Connectable`` interface method returns self, allowing Connections to be used interchangably with Engines in most situations that require a bind. - """ + """ return self def invalidate(self, exception=None): @@ -636,8 +633,8 @@ class Connection(Connectable): [sqlalchemy.interfaces#PoolListener] for a mechanism to modify connection state when connections leave and return to their connection pool. - """ + """ self.__connection.detach() def begin(self): @@ -648,8 +645,8 @@ class Connection(Connectable): outermost transaction may ``commit``. Calls to ``commit`` on inner transactions are ignored. Any transaction in the hierarchy may ``rollback``, however. - """ + """ if self.__transaction is None: self.__transaction = RootTransaction(self) else: @@ -774,20 +771,6 @@ class Connection(Connectable): self.engine.dialect.do_commit_twophase(self, xid, is_prepared) self.__transaction = None - def _autocommit(self, context): - """Possibly issue a commit. - - When no Transaction is present, this is called after statement - execution to provide "autocommit" behavior. Dialects may - inspect the statement to determine if a commit is actually - required. - """ - - # TODO: have the dialect determine if autocommit can be set on - # the connection directly without this extra step - if not self.in_transaction() and context.should_autocommit: - self._commit_impl() - def _autorollback(self): if not self.in_transaction(): self._rollback_impl() @@ -824,16 +807,6 @@ class Connection(Connectable): else: raise exc.InvalidRequestError("Unexecutable object type: " + str(type(object))) - def _execute_default(self, default, multiparams=None, params=None): - return self.engine.dialect.defaultrunner(self.__create_execution_context()).traverse_single(default) - - def _execute_text(self, statement, multiparams, params): - parameters = self.__distill_params(multiparams, params) - context = self.__create_execution_context(statement=statement, parameters=parameters) - self.__execute_raw(context) - self._autocommit(context) - return context.get_result_proxy() - def __distill_params(self, multiparams, params): """given arguments from the calling form *multiparams, **params, return a list of bind parameter structures, usually a list of dictionaries. @@ -847,15 +820,16 @@ class Connection(Connectable): else: return [{}] elif len(multiparams) == 1: - if isinstance(multiparams[0], (list, tuple)): - if not multiparams[0] or isinstance(multiparams[0][0], (list, tuple, dict)): - return multiparams[0] + zero = multiparams[0] + if isinstance(zero, (list, tuple)): + if not zero or isinstance(zero[0], (list, tuple, dict)): + return zero else: - return [multiparams[0]] - elif isinstance(multiparams[0], dict): - return [multiparams[0]] + return [zero] + elif isinstance(zero, dict): + return [zero] else: - return [[multiparams[0]]] + return [[zero]] else: if isinstance(multiparams[0], (list, tuple, dict)): return multiparams @@ -865,35 +839,49 @@ class Connection(Connectable): def _execute_function(self, func, multiparams, params): return self.execute_clauseelement(func.select(), multiparams, params) + def _execute_default(self, default, multiparams=None, params=None): + return self.engine.dialect.defaultrunner(self.__create_execution_context()).traverse_single(default) + def execute_clauseelement(self, elem, multiparams=None, params=None): params = self.__distill_params(multiparams, params) if params: keys = params[0].keys() else: keys = None - return self._execute_compiled(elem.compile(dialect=self.dialect, column_keys=keys, inline=len(params) > 1), distilled_params=params) - def _execute_compiled(self, compiled, multiparams=None, params=None, distilled_params=None): - """Execute a sql.Compiled object.""" - if not compiled.can_execute: - raise exc.ArgumentError("Not an executable clause: %s" % (str(compiled))) + context = self.__create_execution_context( + compiled=elem.compile(dialect=self.dialect, column_keys=keys, inline=len(params) > 1), + parameters=params + ) + return self.__execute_context(context) - if distilled_params is None: - distilled_params = self.__distill_params(multiparams, params) - context = self.__create_execution_context(compiled=compiled, parameters=distilled_params) + def _execute_compiled(self, compiled, multiparams=None, params=None): + """Execute a sql.Compiled object.""" - context.pre_execution() - self.__execute_raw(context) - context.post_execution() - self._autocommit(context) - return context.get_result_proxy() + context = self.__create_execution_context( + compiled=compiled, + parameters=self.__distill_params(multiparams, params) + ) + return self.__execute_context(context) - def __execute_raw(self, context): + def _execute_text(self, statement, multiparams, params): + parameters = self.__distill_params(multiparams, params) + context = self.__create_execution_context(statement=statement, parameters=parameters) + return self.__execute_context(context) + + def __execute_context(self, context): + if context.compiled: + context.pre_exec() if context.executemany: self._cursor_executemany(context.cursor, context.statement, context.parameters, context=context) else: self._cursor_execute(context.cursor, context.statement, context.parameters[0], context=context) - + if context.compiled: + context.post_exec() + if context.should_autocommit and not self.in_transaction(): + self._commit_impl() + return context.get_result_proxy() + def _execute_ddl(self, ddl, params, multiparams): if params: schema_item, params = params[0], params[1:] diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index ec15313e42..251cf8b2c2 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -136,6 +136,9 @@ class DefaultExecutionContext(base.ExecutionContext): # compiled clauseelement. process bind params, process table defaults, # track collections used by ResultProxy to target and process results + if not compiled.can_execute: + raise exc.ArgumentError("Not an executable clause: %s" % compiled) + self.processors = dict( (key, value) for key, value in ( (compiled.bind_names[bindparam], @@ -152,10 +155,9 @@ class DefaultExecutionContext(base.ExecutionContext): self.isinsert = compiled.isinsert self.isupdate = compiled.isupdate + self.should_autocommit = compiled.statement._autocommit if isinstance(compiled.statement, expression._TextClause): - self.should_autocommit = compiled.statement._autocommit or self.should_autocommit_text(self.statement) - else: - self.should_autocommit = getattr(compiled.statement, '_autocommit', False) or self.should_autocommit_compiled(compiled) + self.should_autocommit = self.should_autocommit or self.should_autocommit_text(self.statement) if not parameters: self.compiled_parameters = [compiled.construct_params()] @@ -248,21 +250,12 @@ class DefaultExecutionContext(base.ExecutionContext): parameters.append(param) return parameters - def should_autocommit_compiled(self, compiled): - return isinstance(compiled.statement, expression._UpdateBase) - def should_autocommit_text(self, statement): return AUTOCOMMIT_REGEXP.match(statement) def create_cursor(self): return self._connection.connection.cursor() - def pre_execution(self): - self.pre_exec() - - def post_execution(self): - self.post_exec() - def pre_exec(self): pass diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 80a4d7f52a..b83c9ab209 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -134,6 +134,10 @@ class DefaultCompiler(engine.Compiled): operators = OPERATORS functions = FUNCTIONS + # if we are insert/update/delete. + # set to true when we visit an INSERT, UPDATE or DELETE + isdelete = isinsert = isupdate = False + def __init__(self, dialect, statement, column_keys=None, inline=False, **kwargs): """Construct a new ``DefaultCompiler`` object. @@ -148,10 +152,7 @@ class DefaultCompiler(engine.Compiled): statement. """ - super(DefaultCompiler, self).__init__(dialect, statement, column_keys, **kwargs) - - # if we are insert/update/delete. set to true when we visit an INSERT, UPDATE or DELETE - self.isdelete = self.isinsert = self.isupdate = False + engine.Compiled.__init__(self, dialect, statement, column_keys, **kwargs) # compile INSERT/UPDATE defaults/sequences inlined (no pre-execute) self.inline = inline or getattr(statement, 'inline', False) diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 2fa3fc36f9..9b847c78b4 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2551,6 +2551,8 @@ class Alias(FromClause): baseselectable = baseselectable.element self.original = baseselectable self.supports_execution = baseselectable.supports_execution + if self.supports_execution: + self._autocommit = baseselectable._autocommit self.element = selectable if alias is None: if self.original.named_with_column: @@ -3453,7 +3455,8 @@ class _UpdateBase(ClauseElement): """Form the base for ``INSERT``, ``UPDATE``, and ``DELETE`` statements.""" supports_execution = True - + _autocommit = True + def _generate(self): s = self.__class__.__new__(self.__class__) s.__dict__ = self.__dict__.copy() @@ -3606,6 +3609,7 @@ class Delete(_UpdateBase): class _IdentifiedClause(ClauseElement): supports_execution = True + _autocommit = False quote = None def __init__(self, ident): diff --git a/test/profiling/zoomark.py b/test/profiling/zoomark.py index a91539d5a0..79c954688f 100644 --- a/test/profiling/zoomark.py +++ b/test/profiling/zoomark.py @@ -340,7 +340,7 @@ class ZooMarkTest(TestBase): def test_profile_4_expressions(self): self.test_baseline_4_expressions() - @profiling.function_call_count(1442, {'2.4': 1001}) + @profiling.function_call_count(1347, {'2.4': 1001}) def test_profile_5_aggregates(self): self.test_baseline_5_aggregates() @@ -348,7 +348,7 @@ class ZooMarkTest(TestBase): def test_profile_6_editing(self): self.test_baseline_6_editing() - @profiling.function_call_count(3110, {'2.4': 1998}) + @profiling.function_call_count(2994, {'2.4': 1998}) def test_profile_7_multiview(self): self.test_baseline_7_multiview() diff --git a/test/profiling/zoomark_orm.py b/test/profiling/zoomark_orm.py index 7af72b2586..edf37ba040 100644 --- a/test/profiling/zoomark_orm.py +++ b/test/profiling/zoomark_orm.py @@ -306,7 +306,7 @@ class ZooMarkTest(TestBase): def test_profile_4_expressions(self): self.test_baseline_4_expressions() - @profiling.function_call_count(1426) + @profiling.function_call_count(1331) def test_profile_5_aggregates(self): self.test_baseline_5_aggregates() diff --git a/test/sql/constraints.py b/test/sql/constraints.py index b719ac93d3..b7208532c5 100644 --- a/test/sql/constraints.py +++ b/test/sql/constraints.py @@ -175,12 +175,12 @@ class ConstraintTest(TestBase, AssertsExecutionResults): capt = [] connection = testing.db.connect() # TODO: hacky, put a real connection proxy in - ex = connection._Connection__execute_raw + ex = connection._Connection__execute_context def proxy(context): capt.append(context.statement) capt.append(repr(context.parameters)) ex(context) - connection._Connection__execute_raw = proxy + connection._Connection__execute_context = proxy schemagen = testing.db.dialect.schemagenerator(testing.db.dialect, connection) schemagen.traverse(events) diff --git a/test/testlib/testing.py b/test/testlib/testing.py index cc77369379..b38968964f 100644 --- a/test/testlib/testing.py +++ b/test/testlib/testing.py @@ -486,7 +486,7 @@ class ExecutionContextWrapper(object): setattr(self.ctx, key, value) trailing_underscore_pattern = re.compile(r'(\W:[\w_#]+)_\b',re.MULTILINE) - def post_execution(self): + def post_exec(self): ctx = self.ctx statement = unicode(ctx.compiled) statement = re.sub(r'\n', '', ctx.statement) @@ -540,7 +540,7 @@ class ExecutionContextWrapper(object): testdata.unittest.assert_(equivalent, "Testing for query '%s' params %s, received '%s' with params %s" % (query, repr(params), statement, repr(parameters))) testdata.sql_count += 1 - self.ctx.post_execution() + self.ctx.post_exec() def convert_statement(self, query): paramstyle = self.ctx.dialect.paramstyle