]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The concept of associating a ".bind" directly with a
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 11 Feb 2011 03:27:45 +0000 (22:27 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 11 Feb 2011 03:27:45 +0000 (22:27 -0500)
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]

CHANGES
lib/sqlalchemy/sql/expression.py

diff --git a/CHANGES b/CHANGES
index 0371cc87dca5d3297898eec69cbb65df4270f6c9..f1897c85cbad5e0230414a28a1ddec0c0c0c3f80 100644 (file)
--- 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]
index 2a23d146b515ca6ebb7f2847c78b1ece915b3f18..ec2a0e516a6936c8d89061c855f29823c1cfc62f 100644 (file)
@@ -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