From: Mike Bayer Date: Fri, 11 Feb 2011 03:27:45 +0000 (-0500) Subject: - The concept of associating a ".bind" directly with a X-Git-Tag: rel_0_7b1~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=848257f7d2f325f67e2dab553d0ee9e5d89f03d6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - The concept of associating a ".bind" directly with a ClauseElement has been explicitly moved to Executable, i.e. the mixin that describes ClauseElements which represent engine-executable constructs. This change is an improvement to internal organization and is unlikely to affect any real-world usage. [ticket:2048] --- diff --git a/CHANGES b/CHANGES index 0371cc87dc..f1897c85cb 100644 --- a/CHANGES +++ b/CHANGES @@ -215,6 +215,13 @@ CHANGES executions which fail before the DBAPI becomes involved. [ticket:2015] + - The concept of associating a ".bind" directly with a + ClauseElement has been explicitly moved to Executable, + i.e. the mixin that describes ClauseElements which represent + engine-executable constructs. This change is an improvement + to internal organization and is unlikely to affect any + real-world usage. [ticket:2048] + -sqlite - SQLite dialect now uses `NullPool` for file-based databases [ticket:1921] diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 2a23d146b5..ec2a0e516a 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1277,7 +1277,7 @@ class ClauseElement(Visitable): _annotations = {} supports_execution = False _from_objects = [] - _bind = None + bind = None def _clone(self): """Create a shallow copy of this ClauseElement. @@ -1460,30 +1460,8 @@ class ClauseElement(Visitable): """ return self - # TODO: remove .bind as a method from the root ClauseElement. - # we should only be deriving binds from FromClause elements - # and certain SchemaItem subclasses. - # the "search_for_bind" functionality can still be used by - # execute(), however. - @property - def bind(self): - """Returns the Engine or Connection to which this ClauseElement is - bound, or None if none found. - - """ - if self._bind is not None: - return self._bind - - for f in _from_objects(self): - if f is self: - continue - engine = f.bind - if engine is not None: - return engine - else: - return None - @util.pending_deprecation('0.7', + @util.deprecated('0.7', 'Only SQL expressions which subclass ' ':class:`.Executable` may provide the ' ':func:`.execute` method.') @@ -1494,15 +1472,11 @@ class ClauseElement(Visitable): e = self.bind if e is None: label = getattr(self, 'description', self.__class__.__name__) - msg = ('This %s is not bound and does not support direct ' - 'execution. Supply this statement to a Connection or ' - 'Engine for execution. Or, assign a bind to the statement ' - 'or the Metadata of its underlying tables to enable ' - 'implicit execution via this method.' % label) + msg = ('This %s does not support direct execution.' % label) raise exc.UnboundExecutionError(msg) return e._execute_clauseelement(self, multiparams, params) - @util.pending_deprecation('0.7', + @util.deprecated('0.7', 'Only SQL expressions which subclass ' ':class:`.Executable` may provide the ' ':func:`.scalar` method.') @@ -1555,9 +1529,7 @@ class ClauseElement(Visitable): bind = self.bind else: dialect = default.DefaultDialect() - c= self._compiler(dialect, bind=bind, **kw) - #c.string = c.process(c.statement) - return c + return self._compiler(dialect, bind=bind, **kw) def _compiler(self, dialect, **kw): """Return a compiler appropriate for this ClauseElement, given a @@ -2656,6 +2628,7 @@ class Executable(_Generative): supports_execution = True _execution_options = util.immutabledict() + _bind = None @_generative def execution_options(self, **kw): @@ -2707,7 +2680,8 @@ class Executable(_Generative): includes a connection-only option to specify transaction isolation level. - :meth:`.Query.execution_options()` - applies options to the statement + :meth:`.Query.execution_options()` - applies options to + the statement generated by a :class:`.orm.Query` object. """ @@ -2727,11 +2701,9 @@ class Executable(_Generative): e = self.bind if e is None: label = getattr(self, 'description', self.__class__.__name__) - msg = ('This %s is not bound and does not support direct ' - 'execution. Supply this statement to a Connection or ' - 'Engine for execution. Or, assign a bind to the statement ' - 'or the Metadata of its underlying tables to enable ' - 'implicit execution via this method.' % label) + msg = ('This %s is not directly bound to a Connection or Engine.' + 'Use the .execute() method of a Connection or Engine ' + 'to execute this construct.' % label) raise exc.UnboundExecutionError(msg) return e._execute_clauseelement(self, multiparams, params) @@ -2742,6 +2714,29 @@ class Executable(_Generative): """ return self.execute(*multiparams, **params).scalar() + @property + def bind(self): + """Returns the :class:`.Engine` or :class:`.Connection` to + which this :class:`.Executable` is bound, or None if none found. + + This is a traversal which checks locally, then + checks among the "from" clauses of associated objects + until a bound engine or connection is found. + + """ + if self._bind is not None: + return self._bind + + for f in _from_objects(self): + if f is self: + continue + engine = f.bind + if engine is not None: + return engine + else: + return None + + # legacy, some outside users may be calling this _Executable = Executable