Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# orm/exc.py 

2# Copyright (C) 2005-2020 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: http://www.opensource.org/licenses/mit-license.php 

7 

8"""SQLAlchemy ORM exceptions.""" 

9from .. import exc as sa_exc 

10from .. import util 

11 

12 

13NO_STATE = (AttributeError, KeyError) 

14"""Exception types that may be raised by instrumentation implementations.""" 

15 

16 

17class StaleDataError(sa_exc.SQLAlchemyError): 

18 """An operation encountered database state that is unaccounted for. 

19 

20 Conditions which cause this to happen include: 

21 

22 * A flush may have attempted to update or delete rows 

23 and an unexpected number of rows were matched during 

24 the UPDATE or DELETE statement. Note that when 

25 version_id_col is used, rows in UPDATE or DELETE statements 

26 are also matched against the current known version 

27 identifier. 

28 

29 * A mapped object with version_id_col was refreshed, 

30 and the version number coming back from the database does 

31 not match that of the object itself. 

32 

33 * A object is detached from its parent object, however 

34 the object was previously attached to a different parent 

35 identity which was garbage collected, and a decision 

36 cannot be made if the new parent was really the most 

37 recent "parent". 

38 

39 """ 

40 

41 

42ConcurrentModificationError = StaleDataError 

43 

44 

45class FlushError(sa_exc.SQLAlchemyError): 

46 """A invalid condition was detected during flush().""" 

47 

48 

49class UnmappedError(sa_exc.InvalidRequestError): 

50 """Base for exceptions that involve expected mappings not present.""" 

51 

52 

53class ObjectDereferencedError(sa_exc.SQLAlchemyError): 

54 """An operation cannot complete due to an object being garbage 

55 collected. 

56 

57 """ 

58 

59 

60class DetachedInstanceError(sa_exc.SQLAlchemyError): 

61 """An attempt to access unloaded attributes on a 

62 mapped instance that is detached.""" 

63 

64 code = "bhk3" 

65 

66 

67class UnmappedInstanceError(UnmappedError): 

68 """An mapping operation was requested for an unknown instance.""" 

69 

70 @util.dependencies("sqlalchemy.orm.base") 

71 def __init__(self, base, obj, msg=None): 

72 if not msg: 

73 try: 

74 base.class_mapper(type(obj)) 

75 name = _safe_cls_name(type(obj)) 

76 msg = ( 

77 "Class %r is mapped, but this instance lacks " 

78 "instrumentation. This occurs when the instance " 

79 "is created before sqlalchemy.orm.mapper(%s) " 

80 "was called." % (name, name) 

81 ) 

82 except UnmappedClassError: 

83 msg = _default_unmapped(type(obj)) 

84 if isinstance(obj, type): 

85 msg += ( 

86 "; was a class (%s) supplied where an instance was " 

87 "required?" % _safe_cls_name(obj) 

88 ) 

89 UnmappedError.__init__(self, msg) 

90 

91 def __reduce__(self): 

92 return self.__class__, (None, self.args[0]) 

93 

94 

95class UnmappedClassError(UnmappedError): 

96 """An mapping operation was requested for an unknown class.""" 

97 

98 def __init__(self, cls, msg=None): 

99 if not msg: 

100 msg = _default_unmapped(cls) 

101 UnmappedError.__init__(self, msg) 

102 

103 def __reduce__(self): 

104 return self.__class__, (None, self.args[0]) 

105 

106 

107class ObjectDeletedError(sa_exc.InvalidRequestError): 

108 """A refresh operation failed to retrieve the database 

109 row corresponding to an object's known primary key identity. 

110 

111 A refresh operation proceeds when an expired attribute is 

112 accessed on an object, or when :meth:`_query.Query.get` is 

113 used to retrieve an object which is, upon retrieval, detected 

114 as expired. A SELECT is emitted for the target row 

115 based on primary key; if no row is returned, this 

116 exception is raised. 

117 

118 The true meaning of this exception is simply that 

119 no row exists for the primary key identifier associated 

120 with a persistent object. The row may have been 

121 deleted, or in some cases the primary key updated 

122 to a new value, outside of the ORM's management of the target 

123 object. 

124 

125 """ 

126 

127 @util.dependencies("sqlalchemy.orm.base") 

128 def __init__(self, base, state, msg=None): 

129 if not msg: 

130 msg = ( 

131 "Instance '%s' has been deleted, or its " 

132 "row is otherwise not present." % base.state_str(state) 

133 ) 

134 

135 sa_exc.InvalidRequestError.__init__(self, msg) 

136 

137 def __reduce__(self): 

138 return self.__class__, (None, self.args[0]) 

139 

140 

141class UnmappedColumnError(sa_exc.InvalidRequestError): 

142 """Mapping operation was requested on an unknown column.""" 

143 

144 

145class NoResultFound(sa_exc.InvalidRequestError): 

146 """A database result was required but none was found.""" 

147 

148 

149class MultipleResultsFound(sa_exc.InvalidRequestError): 

150 """A single database result was required but more than one were found.""" 

151 

152 

153class LoaderStrategyException(sa_exc.InvalidRequestError): 

154 """A loader strategy for an attribute does not exist.""" 

155 

156 def __init__( 

157 self, 

158 applied_to_property_type, 

159 requesting_property, 

160 applies_to, 

161 actual_strategy_type, 

162 strategy_key, 

163 ): 

164 if actual_strategy_type is None: 

165 sa_exc.InvalidRequestError.__init__( 

166 self, 

167 "Can't find strategy %s for %s" 

168 % (strategy_key, requesting_property), 

169 ) 

170 else: 

171 sa_exc.InvalidRequestError.__init__( 

172 self, 

173 'Can\'t apply "%s" strategy to property "%s", ' 

174 'which is a "%s"; this loader strategy is intended ' 

175 'to be used with a "%s".' 

176 % ( 

177 util.clsname_as_plain_name(actual_strategy_type), 

178 requesting_property, 

179 util.clsname_as_plain_name(applied_to_property_type), 

180 util.clsname_as_plain_name(applies_to), 

181 ), 

182 ) 

183 

184 

185def _safe_cls_name(cls): 

186 try: 

187 cls_name = ".".join((cls.__module__, cls.__name__)) 

188 except AttributeError: 

189 cls_name = getattr(cls, "__name__", None) 

190 if cls_name is None: 

191 cls_name = repr(cls) 

192 return cls_name 

193 

194 

195@util.dependencies("sqlalchemy.orm.base") 

196def _default_unmapped(base, cls): 

197 try: 

198 mappers = base.manager_of_class(cls).mappers 

199 except NO_STATE: 

200 mappers = {} 

201 except TypeError: 

202 mappers = {} 

203 name = _safe_cls_name(cls) 

204 

205 if not mappers: 

206 return "Class '%s' is not mapped" % name