diff options
| author | Jason Kirtland <jek@discorporate.us> | 2008-05-21 03:39:06 +0000 |
|---|---|---|
| committer | Jason Kirtland <jek@discorporate.us> | 2008-05-21 03:39:06 +0000 |
| commit | 92c7a834d76462822376998aa647341eacbbbdfa (patch) | |
| tree | 8a6b3ca1d7b98020dee956154cc78e5dbcbea45d /lib/sqlalchemy/orm/exc.py | |
| parent | 6536af53fcbedb1af42dde824561252becbbd7e5 (diff) | |
| download | sqlalchemy-92c7a834d76462822376998aa647341eacbbbdfa.tar.gz | |
- Centralized 'x is not mapped' reporting into sa.orm.exc.
- Guards are now present on all public Session methods and passing in an
unmapped hoho anywhere yields helpful exception messages, going to some
effort to provide hints for debugging situations that would otherwise seem
hopeless, such as broken user instrumentation or half-pickles.
Diffstat (limited to 'lib/sqlalchemy/orm/exc.py')
| -rw-r--r-- | lib/sqlalchemy/orm/exc.py | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py index ea7efd3fb..d97a54621 100644 --- a/lib/sqlalchemy/orm/exc.py +++ b/lib/sqlalchemy/orm/exc.py @@ -6,31 +6,96 @@ """SQLAlchemy ORM exceptions.""" -import sqlalchemy.exceptions as sa_exc +import sqlalchemy as sa -class ConcurrentModificationError(sa_exc.SQLAlchemyError): +NO_STATE = (AttributeError, KeyError) +"""Exception types that may be raised by instrumentation implementations.""" + +class ConcurrentModificationError(sa.exc.SQLAlchemyError): """Rows have been modified outside of the unit of work.""" -class FlushError(sa_exc.SQLAlchemyError): +class FlushError(sa.exc.SQLAlchemyError): """A invalid condition was detected during flush().""" -class ObjectDeletedError(sa_exc.InvalidRequestError): +class UnmappedError(sa.exc.InvalidRequestError): + """TODO""" + + +class UnmappedInstanceError(UnmappedError): + """An mapping operation was requested for an unknown instance.""" + + def __init__(self, obj, entity_name=None, msg=None): + if not msg: + try: + mapper = sa.orm.class_mapper(type(obj), entity_name) + name = _safe_cls_name(type(obj)) + msg = ("Class %r is mapped, but this instance lacks " + "instrumentation. Possible causes: instance created " + "before sqlalchemy.orm.mapper(%s) was called, or " + "instance was pickled/depickled without instrumentation" + "information." % (name, name)) + except UnmappedClassError: + msg = _default_unmapped(type(obj), entity_name) + if isinstance(obj, type): + msg += ( + '; was a class (%s) supplied where an instance was ' + 'required?' % _safe_cls_name(obj)) + UnmappedError.__init__(self, msg) + + +class UnmappedClassError(UnmappedError): + """An mapping operation was requested for an unknown class.""" + + def __init__(self, cls, entity_name=None, msg=None): + if not msg: + msg = _default_unmapped(cls, entity_name) + UnmappedError.__init__(self, msg) + + +class ObjectDeletedError(sa.exc.InvalidRequestError): """An refresh() operation failed to re-retrieve an object's row.""" -class UnmappedColumnError(sa_exc.InvalidRequestError): +class UnmappedColumnError(sa.exc.InvalidRequestError): """Mapping operation was requested on an unknown column.""" -class NoResultFound(sa_exc.InvalidRequestError): + +class NoResultFound(sa.exc.InvalidRequestError): """A database result was required but none was found.""" -class MultipleResultsFound(sa_exc.InvalidRequestError): + +class MultipleResultsFound(sa.exc.InvalidRequestError): """A single database result was required but more than one were found.""" + # Legacy compat until 0.6. -sa_exc.ConcurrentModificationError = ConcurrentModificationError -sa_exc.FlushError = FlushError -sa_exc.UnmappedColumnError +sa.exc.ConcurrentModificationError = ConcurrentModificationError +sa.exc.FlushError = FlushError +sa.exc.UnmappedColumnError + +def _safe_cls_name(cls): + try: + cls_name = '.'.join((cls.__module__, cls.__name__)) + except AttributeError: + cls_name = getattr(cls, '__name__', None) + if cls_name is None: + cls_name = repr(cls) + return cls_name + +def _default_unmapped(cls, entity_name): + try: + mappers = sa.orm.attributes.manager_of_class(cls).mappers + except NO_STATE: + mappers = {} + except TypeError: + mappers = {} + name = _safe_cls_name(cls) + + if not mappers and entity_name is None: + return "Class '%s' is not mapped" % name + else: + return "Class '%s' is not mapped with entity_name %r" % ( + name, entity_name) |
