From: Mike Bayer Date: Thu, 12 Jan 2012 01:58:10 +0000 (-0500) Subject: - [bug] ensure pickleability of all ORM exceptions X-Git-Tag: rel_0_7_5~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e6c330673e28dfb6fa24022e66bb67d6f2f673a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - [bug] ensure pickleability of all ORM exceptions for multiprocessing compatibility. [ticket:2371] --- diff --git a/CHANGES b/CHANGES index fc72a7109c..beac4243cd 100644 --- a/CHANGES +++ b/CHANGES @@ -29,10 +29,14 @@ CHANGES emitted on a pending object, it would fail to load. + - [bug] ensure pickleability of all ORM exceptions + for multiprocessing compatibility. [ticket:2371] + - engine - [bug] Added __reduce__ to StatementError, - DBAPIError so that exceptions are pickleable, - as when using multiprocessing. However, not + DBAPIError, column errors so that exceptions + are pickleable, as when using multiprocessing. + However, not all DBAPIs support this yet, such as psycopg2. [ticket:2371] diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py index 1146284f95..2aaf1490b1 100644 --- a/lib/sqlalchemy/orm/exc.py +++ b/lib/sqlalchemy/orm/exc.py @@ -72,6 +72,8 @@ class UnmappedInstanceError(UnmappedError): 'required?' % _safe_cls_name(obj)) UnmappedError.__init__(self, msg) + def __reduce__(self): + return self.__class__, (None, self.args[0]) class UnmappedClassError(UnmappedError): """An mapping operation was requested for an unknown class.""" @@ -81,6 +83,8 @@ class UnmappedClassError(UnmappedError): msg = _default_unmapped(cls) UnmappedError.__init__(self, msg) + def __reduce__(self): + return self.__class__, (None, self.args[0]) class ObjectDeletedError(sa.exc.InvalidRequestError): """A refresh operation failed to retrieve the database @@ -101,12 +105,15 @@ class ObjectDeletedError(sa.exc.InvalidRequestError): object. """ - def __init__(self, state): - sa.exc.InvalidRequestError.__init__( - self, - "Instance '%s' has been deleted, or its " + def __init__(self, state, msg=None): + if not msg: + msg = "Instance '%s' has been deleted, or its "\ "row is otherwise not present." % orm_util.state_str(state) - ) + + sa.exc.InvalidRequestError.__init__(self, msg) + + def __reduce__(self): + return self.__class__, (None, self.args[0]) class UnmappedColumnError(sa.exc.InvalidRequestError): """Mapping operation was requested on an unknown column.""" diff --git a/test/orm/test_pickled.py b/test/orm/test_pickled.py index f63c4cfa2d..920159dc18 100644 --- a/test/orm/test_pickled.py +++ b/test/orm/test_pickled.py @@ -319,6 +319,21 @@ class PickleTest(fixtures.MappedTest): screen2 = Screen(Child2(), screen1) pickle.loads(pickle.dumps(screen2)) + def test_exceptions(self): + class Foo(object): + pass + users = self.tables.users + mapper(User, users) + + for sa_exc in ( + orm_exc.UnmappedInstanceError(Foo()), + orm_exc.UnmappedClassError(Foo), + orm_exc.ObjectDeletedError(attributes.instance_state(User())), + ): + for loads, dumps in picklers(): + repickled = loads(dumps(sa_exc)) + eq_(repickled.args[0], sa_exc.args[0]) + class PolymorphicDeferredTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata):