Mike Bayer avatar Mike Bayer committed cf6360f

- 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]

Comments (0)

Files changed (2)

     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]

lib/sqlalchemy/sql/expression.py

     _annotations = {}
     supports_execution = False
     _from_objects = []
-    _bind = None
+    bind = None
 
     def _clone(self):
         """Create a shallow copy of this ClauseElement.
         """
         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.')
         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.')
                 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
 
     supports_execution = True
     _execution_options = util.immutabledict()
+    _bind = None
 
     @_generative
     def execution_options(self, **kw):
             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.
 
         """
         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)
 
         """
         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
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.