]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Friendlier exception messages for unbound, implicit execution
authorJason Kirtland <jek@discorporate.us>
Thu, 31 Jan 2008 19:48:13 +0000 (19:48 +0000)
committerJason Kirtland <jek@discorporate.us>
Thu, 31 Jan 2008 19:48:13 +0000 (19:48 +0000)
- Implicit binding failures now raise UnboundExecutionError

lib/sqlalchemy/engine/base.py
lib/sqlalchemy/exceptions.py
lib/sqlalchemy/orm/dynamic.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/orm/strategies.py
lib/sqlalchemy/schema.py
lib/sqlalchemy/sql/expression.py
test/engine/bind.py

index 733d77a69635a505e02c2942f96dc5a0c4aa7614..2bbbf398d6a2f468f1aeae8bae8b9766399182b4 100644 (file)
@@ -484,7 +484,7 @@ class Compiled(object):
 
         e = self.bind
         if e is None:
-            raise exceptions.InvalidRequestError("This Compiled object is not bound to any Engine or Connection.")
+            raise exceptions.UnboundExecutionError("This Compiled object is not bound to any Engine or Connection.")
         return e._execute_compiled(self, multiparams, params)
 
     def scalar(self, *multiparams, **params):
index eda368d7cc396dc2a0e3a13dcfeb4f4e269c669a..7bac05c26ff2af9fa385f3833913ba82b88538a4 100644 (file)
@@ -55,6 +55,8 @@ class NoSuchTableError(InvalidRequestError):
     database, but the table doesn't exist.
     """
 
+class UnboundExecutionError(InvalidRequestError):
+    """SQL was attempted without a database connection to execute it on."""
 
 class AssertionError(SQLAlchemyError):
     """Corresponds to internal state being detected in an invalid state."""
index a5e1a84678de61af13df08eb98b91c9143eb88ae..98702ecb04dd05346e1ca2f0bf5b3dd963206668 100644 (file)
@@ -128,7 +128,7 @@ class AppenderQuery(Query):
                 try:
                     sess = object_mapper(instance).get_session()
                 except exceptions.InvalidRequestError:
-                    raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (mapperutil.instance_str(instance), self.attr.key))
+                    raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (mapperutil.instance_str(instance), self.attr.key))
 
         return sess.query(self.attr.target_mapper).with_parent(instance, self.attr.key)
 
index 1489ef65e16f0a33acfeb4044357c7f9a3171423..b99e736b3ed432cfb44f103751e51254befbb15e 100644 (file)
@@ -1555,7 +1555,7 @@ def _load_scalar_attributes(instance, attribute_names):
         try:
             session = mapper.get_session()
         except exceptions.InvalidRequestError:
-            raise exceptions.InvalidRequestError("Instance %s is not bound to a Session, and no contextual session is established; attribute refresh operation cannot proceed" % (instance.__class__))
+            raise exceptions.UnboundExecutionError("Instance %s is not bound to a Session, and no contextual session is established; attribute refresh operation cannot proceed" % (instance.__class__))
     
     state = instance._state
     if '_instance_key' in state.dict:
index b689b24411a1c8d3f155cf460a03d0a1986e5e60..c75b786644cdcb80796742c2f22305f7e10de0da 100644 (file)
@@ -695,7 +695,7 @@ class Session(object):
             if self.bind is not None:
                 return self.bind
             else:
-                raise exceptions.InvalidRequestError("This session is unbound to any Engine or Connection; specify a mapper to get_bind()")
+                raise exceptions.UnboundExecutionError("This session is unbound to any Engine or Connection; specify a mapper to get_bind()")
 
         elif len(self.__binds):
             if mapper is not None:
@@ -713,7 +713,7 @@ class Session(object):
         if self.bind is not None:
             return self.bind
         elif mapper is None:
-            raise exceptions.InvalidRequestError("Could not locate any mapper associated with SQL expression")
+            raise exceptions.UnboundExecutionError("Could not locate any mapper associated with SQL expression")
         else:
             if isinstance(mapper, type):
                 mapper = _class_mapper(mapper)
@@ -721,7 +721,7 @@ class Session(object):
                 mapper = mapper.compile()
             e = mapper.mapped_table.bind
             if e is None:
-                raise exceptions.InvalidRequestError("Could not locate any Engine or Connection bound to mapper '%s'" % str(mapper))
+                raise exceptions.UnboundExecutionError("Could not locate any Engine or Connection bound to mapper '%s'" % str(mapper))
             return e
 
     def query(self, mapper_or_class, *addtl_entities, **kwargs):
index 908c43feb15a1f619f47dbab1b917347c98fbde8..3b3c86d1a6796d5e986954bebd229ea52f97156d 100644 (file)
@@ -192,7 +192,7 @@ class LoadDeferredColumns(object):
 
         session = sessionlib.object_session(self.instance)
         if session is None:
-            raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key))
+            raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key))
 
         query = session.query(localparent)
         if not self.optimizing_statement:
@@ -438,7 +438,7 @@ class LoadLazyAttribute(object):
             try:
                 session = instance_mapper.get_session()
             except exceptions.InvalidRequestError:
-                raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))
+                raise exceptions.UnboundExecutionError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key))
 
         q = session.query(prop.mapper).autoflush(False)
         if self.path:
index 0d626397f3a1bb0f629ea5a15471a208aa380c91..44dcb575558fe71d6ad6f8f3c94f3239ba760ac8 100644 (file)
@@ -1336,5 +1336,21 @@ class SchemaVisitor(visitors.ClauseVisitor):
 def _bind_or_error(schemaitem):
     bind = schemaitem.bind
     if not bind:
-        raise exceptions.InvalidRequestError("This SchemaItem is not connected to any Engine or Connection.")
-    return bind
\ No newline at end of file
+        name = schemaitem.__class__.__name__
+        label = getattr(schemaitem, 'fullname',
+                        getattr(schemaitem, 'name', None))
+        if label:
+            item = '%s %r' % (name, label)
+        else:
+            item = name
+        if isinstance(schemaitem, MetaData):
+            bindable = "the %s's .bind" % name
+        else:
+            bindable = "this %s's .metadata.bind" % name
+
+        msg = ('The %s is not bound to an Engine or Connection.  '
+               'Execution can not proceed without a database to execute '
+               'against.  Either execute with an explicit connection or '
+               'assign %s to enable implicit execution.') % (item, bindable)
+        raise exceptions.UnboundExecutionError(msg)
+    return bind
index 2e5797b34632b0a90c64e73163e6e5c25a3146b2..ee867a2f9c63c9f4493cf442d40e5e7ed093c154 100644 (file)
@@ -1002,7 +1002,13 @@ class ClauseElement(object):
 
         e = self.bind
         if e is None:
-            raise exceptions.InvalidRequestError("This Compiled object is not bound to any Engine or Connection.")
+            label = getattr(self, 'description', self.__class__.__name__)
+            msg = ('This %s is not bound to an Engine or Connection.  '
+                   'Execution can not proceed without a database to execute '
+                   'against.  Either execute with an explicit connection or '
+                   'bind the MetaData of the underlying tables to enable '
+                   'implicit execution.') % label
+            raise exceptions.UnboundExecutionError(msg)
         return e.execute_clauseelement(self, multiparams, params)
 
     def scalar(self, *multiparams, **params):
index 7e716ba9d8e6f38313ff6d4e46cccbcd49af9e51..c273bdb05e940243b4ebfab1cc6c6a05f26c5b46 100644 (file)
@@ -34,7 +34,6 @@ class BindTest(PersistTest):
 
         for meth in [
             metadata.create_all,
-            table.exists,
             metadata.drop_all,
             table.create,
             table.drop,
@@ -42,8 +41,53 @@ class BindTest(PersistTest):
             try:
                 meth()
                 assert False
-            except exceptions.InvalidRequestError, e:
-                assert str(e)  == "This SchemaItem is not connected to any Engine or Connection."
+            except exceptions.UnboundExecutionError, e:
+                self.assertEquals(
+                    str(e),
+                    "The MetaData "
+                    "is not bound to an Engine or Connection.  "
+                    "Execution can not proceed without a database to execute "
+                    "against.  Either execute with an explicit connection or "
+                    "assign the MetaData's .bind to enable implicit execution.")
+
+        for meth in [
+            table.exists,
+            # future:
+            #table.create,
+            #table.drop,
+        ]:
+            try:
+                meth()
+                assert False
+            except exceptions.UnboundExecutionError, e:
+                self.assertEquals(
+                    str(e),
+                    "The Table 'test_table' "
+                    "is not bound to an Engine or Connection.  "
+                    "Execution can not proceed without a database to execute "
+                    "against.  Either execute with an explicit connection or "
+                    "assign this Table's .metadata.bind to enable implicit "
+                    "execution.")
+
+    @testing.future
+    def test_create_drop_err2(self):
+        for meth in [
+            table.exists,
+            table.create,
+            table.drop,
+        ]:
+            try:
+                meth()
+                assert False
+            except exceptions.UnboundExecutionError, e:
+                self.assertEquals(
+                    str(e),
+                    "The Table 'test_table' "
+                    "is not bound to an Engine or Connection.  "
+                    "Execution can not proceed without a database to execute "
+                    "against.  Either execute with an explicit connection or "
+                    "assign this Table's .metadata.bind to enable implicit "
+                    "execution.")
 
     @testing.uses_deprecated('//connect')
     def test_create_drop_bound(self):
@@ -157,8 +201,13 @@ class BindTest(PersistTest):
                     assert e.bind is None
                     e.execute()
                     assert False
-                except exceptions.InvalidRequestError, e:
-                    assert str(e) == "This Compiled object is not bound to any Engine or Connection."
+                except exceptions.UnboundExecutionError, e:
+                    assert str(e).endswith(
+                        'is not bound to an Engine or '
+                        'Connection.  Execution can not proceed without a '
+                        'database to execute against.  Either execute with '
+                        'an explicit connection or bind the MetaData of the '
+                        'underlying tables to enable implicit execution.')
 
         finally:
             if isinstance(bind, engine.Connection):