1 | # exc.py - ORM exceptions |
---|
2 | # Copyright (C) the SQLAlchemy authors and contributors |
---|
3 | # |
---|
4 | # This module is part of SQLAlchemy and is released under |
---|
5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php |
---|
6 | |
---|
7 | """SQLAlchemy ORM exceptions.""" |
---|
8 | |
---|
9 | import sqlalchemy as sa |
---|
10 | |
---|
11 | |
---|
12 | NO_STATE = (AttributeError, KeyError) |
---|
13 | """Exception types that may be raised by instrumentation implementations.""" |
---|
14 | |
---|
15 | class ConcurrentModificationError(sa.exc.SQLAlchemyError): |
---|
16 | """Rows have been modified outside of the unit of work.""" |
---|
17 | |
---|
18 | |
---|
19 | class FlushError(sa.exc.SQLAlchemyError): |
---|
20 | """A invalid condition was detected during flush().""" |
---|
21 | |
---|
22 | |
---|
23 | class UnmappedError(sa.exc.InvalidRequestError): |
---|
24 | """TODO""" |
---|
25 | |
---|
26 | |
---|
27 | class UnmappedInstanceError(UnmappedError): |
---|
28 | """An mapping operation was requested for an unknown instance.""" |
---|
29 | |
---|
30 | def __init__(self, obj, msg=None): |
---|
31 | if not msg: |
---|
32 | try: |
---|
33 | mapper = sa.orm.class_mapper(type(obj)) |
---|
34 | name = _safe_cls_name(type(obj)) |
---|
35 | msg = ("Class %r is mapped, but this instance lacks " |
---|
36 | "instrumentation. Possible causes: instance created " |
---|
37 | "before sqlalchemy.orm.mapper(%s) was called, or " |
---|
38 | "instance was pickled/depickled without instrumentation" |
---|
39 | "information." % (name, name)) |
---|
40 | except UnmappedClassError: |
---|
41 | msg = _default_unmapped(type(obj)) |
---|
42 | if isinstance(obj, type): |
---|
43 | msg += ( |
---|
44 | '; was a class (%s) supplied where an instance was ' |
---|
45 | 'required?' % _safe_cls_name(obj)) |
---|
46 | UnmappedError.__init__(self, msg) |
---|
47 | |
---|
48 | |
---|
49 | class UnmappedClassError(UnmappedError): |
---|
50 | """An mapping operation was requested for an unknown class.""" |
---|
51 | |
---|
52 | def __init__(self, cls, msg=None): |
---|
53 | if not msg: |
---|
54 | msg = _default_unmapped(cls) |
---|
55 | UnmappedError.__init__(self, msg) |
---|
56 | |
---|
57 | |
---|
58 | class ObjectDeletedError(sa.exc.InvalidRequestError): |
---|
59 | """An refresh() operation failed to re-retrieve an object's row.""" |
---|
60 | |
---|
61 | |
---|
62 | class UnmappedColumnError(sa.exc.InvalidRequestError): |
---|
63 | """Mapping operation was requested on an unknown column.""" |
---|
64 | |
---|
65 | |
---|
66 | class NoResultFound(sa.exc.InvalidRequestError): |
---|
67 | """A database result was required but none was found.""" |
---|
68 | |
---|
69 | |
---|
70 | class MultipleResultsFound(sa.exc.InvalidRequestError): |
---|
71 | """A single database result was required but more than one were found.""" |
---|
72 | |
---|
73 | |
---|
74 | # Legacy compat until 0.6. |
---|
75 | sa.exc.ConcurrentModificationError = ConcurrentModificationError |
---|
76 | sa.exc.FlushError = FlushError |
---|
77 | sa.exc.UnmappedColumnError |
---|
78 | |
---|
79 | def _safe_cls_name(cls): |
---|
80 | try: |
---|
81 | cls_name = '.'.join((cls.__module__, cls.__name__)) |
---|
82 | except AttributeError: |
---|
83 | cls_name = getattr(cls, '__name__', None) |
---|
84 | if cls_name is None: |
---|
85 | cls_name = repr(cls) |
---|
86 | return cls_name |
---|
87 | |
---|
88 | def _default_unmapped(cls): |
---|
89 | try: |
---|
90 | mappers = sa.orm.attributes.manager_of_class(cls).mappers |
---|
91 | except NO_STATE: |
---|
92 | mappers = {} |
---|
93 | except TypeError: |
---|
94 | mappers = {} |
---|
95 | name = _safe_cls_name(cls) |
---|
96 | |
---|
97 | if not mappers: |
---|
98 | return "Class '%s' is not mapped" % name |
---|