Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/pool/events.py: 80%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

51 statements  

1# pool/events.py 

2# Copyright (C) 2005-2024 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: https://www.opensource.org/licenses/mit-license.php 

7from __future__ import annotations 

8 

9import typing 

10from typing import Any 

11from typing import Optional 

12from typing import Type 

13from typing import Union 

14 

15from .base import ConnectionPoolEntry 

16from .base import Pool 

17from .base import PoolProxiedConnection 

18from .base import PoolResetState 

19from .. import event 

20from .. import util 

21 

22if typing.TYPE_CHECKING: 

23 from ..engine import Engine 

24 from ..engine.interfaces import DBAPIConnection 

25 

26 

27class PoolEvents(event.Events[Pool]): 

28 """Available events for :class:`_pool.Pool`. 

29 

30 The methods here define the name of an event as well 

31 as the names of members that are passed to listener 

32 functions. 

33 

34 e.g.:: 

35 

36 from sqlalchemy import event 

37 

38 def my_on_checkout(dbapi_conn, connection_rec, connection_proxy): 

39 "handle an on checkout event" 

40 

41 event.listen(Pool, 'checkout', my_on_checkout) 

42 

43 In addition to accepting the :class:`_pool.Pool` class and 

44 :class:`_pool.Pool` instances, :class:`_events.PoolEvents` also accepts 

45 :class:`_engine.Engine` objects and the :class:`_engine.Engine` class as 

46 targets, which will be resolved to the ``.pool`` attribute of the 

47 given engine or the :class:`_pool.Pool` class:: 

48 

49 engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test") 

50 

51 # will associate with engine.pool 

52 event.listen(engine, 'checkout', my_on_checkout) 

53 

54 """ # noqa: E501 

55 

56 _target_class_doc = "SomeEngineOrPool" 

57 _dispatch_target = Pool 

58 

59 @util.preload_module("sqlalchemy.engine") 

60 @classmethod 

61 def _accept_with( 

62 cls, 

63 target: Union[Pool, Type[Pool], Engine, Type[Engine]], 

64 identifier: str, 

65 ) -> Optional[Union[Pool, Type[Pool]]]: 

66 if not typing.TYPE_CHECKING: 

67 Engine = util.preloaded.engine.Engine 

68 

69 if isinstance(target, type): 

70 if issubclass(target, Engine): 

71 return Pool 

72 else: 

73 assert issubclass(target, Pool) 

74 return target 

75 elif isinstance(target, Engine): 

76 return target.pool 

77 elif isinstance(target, Pool): 

78 return target 

79 elif hasattr(target, "_no_async_engine_events"): 

80 target._no_async_engine_events() 

81 else: 

82 return None 

83 

84 @classmethod 

85 def _listen( 

86 cls, 

87 event_key: event._EventKey[Pool], 

88 **kw: Any, 

89 ) -> None: 

90 target = event_key.dispatch_target 

91 

92 kw.setdefault("asyncio", target._is_asyncio) 

93 

94 event_key.base_listen(**kw) 

95 

96 def connect( 

97 self, 

98 dbapi_connection: DBAPIConnection, 

99 connection_record: ConnectionPoolEntry, 

100 ) -> None: 

101 """Called at the moment a particular DBAPI connection is first 

102 created for a given :class:`_pool.Pool`. 

103 

104 This event allows one to capture the point directly after which 

105 the DBAPI module-level ``.connect()`` method has been used in order 

106 to produce a new DBAPI connection. 

107 

108 :param dbapi_connection: a DBAPI connection. 

109 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

110 

111 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

112 the DBAPI connection. 

113 

114 """ 

115 

116 def first_connect( 

117 self, 

118 dbapi_connection: DBAPIConnection, 

119 connection_record: ConnectionPoolEntry, 

120 ) -> None: 

121 """Called exactly once for the first time a DBAPI connection is 

122 checked out from a particular :class:`_pool.Pool`. 

123 

124 The rationale for :meth:`_events.PoolEvents.first_connect` 

125 is to determine 

126 information about a particular series of database connections based 

127 on the settings used for all connections. Since a particular 

128 :class:`_pool.Pool` 

129 refers to a single "creator" function (which in terms 

130 of a :class:`_engine.Engine` 

131 refers to the URL and connection options used), 

132 it is typically valid to make observations about a single connection 

133 that can be safely assumed to be valid about all subsequent 

134 connections, such as the database version, the server and client 

135 encoding settings, collation settings, and many others. 

136 

137 :param dbapi_connection: a DBAPI connection. 

138 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

139 

140 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

141 the DBAPI connection. 

142 

143 """ 

144 

145 def checkout( 

146 self, 

147 dbapi_connection: DBAPIConnection, 

148 connection_record: ConnectionPoolEntry, 

149 connection_proxy: PoolProxiedConnection, 

150 ) -> None: 

151 """Called when a connection is retrieved from the Pool. 

152 

153 :param dbapi_connection: a DBAPI connection. 

154 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

155 

156 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

157 the DBAPI connection. 

158 

159 :param connection_proxy: the :class:`.PoolProxiedConnection` object 

160 which will proxy the public interface of the DBAPI connection for the 

161 lifespan of the checkout. 

162 

163 If you raise a :class:`~sqlalchemy.exc.DisconnectionError`, the current 

164 connection will be disposed and a fresh connection retrieved. 

165 Processing of all checkout listeners will abort and restart 

166 using the new connection. 

167 

168 .. seealso:: :meth:`_events.ConnectionEvents.engine_connect` 

169 - a similar event 

170 which occurs upon creation of a new :class:`_engine.Connection`. 

171 

172 """ 

173 

174 def checkin( 

175 self, 

176 dbapi_connection: Optional[DBAPIConnection], 

177 connection_record: ConnectionPoolEntry, 

178 ) -> None: 

179 """Called when a connection returns to the pool. 

180 

181 Note that the connection may be closed, and may be None if the 

182 connection has been invalidated. ``checkin`` will not be called 

183 for detached connections. (They do not return to the pool.) 

184 

185 :param dbapi_connection: a DBAPI connection. 

186 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

187 

188 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

189 the DBAPI connection. 

190 

191 """ 

192 

193 @event._legacy_signature( 

194 "2.0", 

195 ["dbapi_connection", "connection_record"], 

196 lambda dbapi_connection, connection_record, reset_state: ( 

197 dbapi_connection, 

198 connection_record, 

199 ), 

200 ) 

201 def reset( 

202 self, 

203 dbapi_connection: DBAPIConnection, 

204 connection_record: ConnectionPoolEntry, 

205 reset_state: PoolResetState, 

206 ) -> None: 

207 """Called before the "reset" action occurs for a pooled connection. 

208 

209 This event represents 

210 when the ``rollback()`` method is called on the DBAPI connection 

211 before it is returned to the pool or discarded. 

212 A custom "reset" strategy may be implemented using this event hook, 

213 which may also be combined with disabling the default "reset" 

214 behavior using the :paramref:`_pool.Pool.reset_on_return` parameter. 

215 

216 The primary difference between the :meth:`_events.PoolEvents.reset` and 

217 :meth:`_events.PoolEvents.checkin` events are that 

218 :meth:`_events.PoolEvents.reset` is called not just for pooled 

219 connections that are being returned to the pool, but also for 

220 connections that were detached using the 

221 :meth:`_engine.Connection.detach` method as well as asyncio connections 

222 that are being discarded due to garbage collection taking place on 

223 connections before the connection was checked in. 

224 

225 Note that the event **is not** invoked for connections that were 

226 invalidated using :meth:`_engine.Connection.invalidate`. These 

227 events may be intercepted using the :meth:`.PoolEvents.soft_invalidate` 

228 and :meth:`.PoolEvents.invalidate` event hooks, and all "connection 

229 close" events may be intercepted using :meth:`.PoolEvents.close`. 

230 

231 The :meth:`_events.PoolEvents.reset` event is usually followed by the 

232 :meth:`_events.PoolEvents.checkin` event, except in those 

233 cases where the connection is discarded immediately after reset. 

234 

235 :param dbapi_connection: a DBAPI connection. 

236 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

237 

238 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

239 the DBAPI connection. 

240 

241 :param reset_state: :class:`.PoolResetState` instance which provides 

242 information about the circumstances under which the connection 

243 is being reset. 

244 

245 .. versionadded:: 2.0 

246 

247 .. seealso:: 

248 

249 :ref:`pool_reset_on_return` 

250 

251 :meth:`_events.ConnectionEvents.rollback` 

252 

253 :meth:`_events.ConnectionEvents.commit` 

254 

255 """ 

256 

257 def invalidate( 

258 self, 

259 dbapi_connection: DBAPIConnection, 

260 connection_record: ConnectionPoolEntry, 

261 exception: Optional[BaseException], 

262 ) -> None: 

263 """Called when a DBAPI connection is to be "invalidated". 

264 

265 This event is called any time the 

266 :meth:`.ConnectionPoolEntry.invalidate` method is invoked, either from 

267 API usage or via "auto-invalidation", without the ``soft`` flag. 

268 

269 The event occurs before a final attempt to call ``.close()`` on the 

270 connection occurs. 

271 

272 :param dbapi_connection: a DBAPI connection. 

273 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

274 

275 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

276 the DBAPI connection. 

277 

278 :param exception: the exception object corresponding to the reason 

279 for this invalidation, if any. May be ``None``. 

280 

281 .. seealso:: 

282 

283 :ref:`pool_connection_invalidation` 

284 

285 """ 

286 

287 def soft_invalidate( 

288 self, 

289 dbapi_connection: DBAPIConnection, 

290 connection_record: ConnectionPoolEntry, 

291 exception: Optional[BaseException], 

292 ) -> None: 

293 """Called when a DBAPI connection is to be "soft invalidated". 

294 

295 This event is called any time the 

296 :meth:`.ConnectionPoolEntry.invalidate` 

297 method is invoked with the ``soft`` flag. 

298 

299 Soft invalidation refers to when the connection record that tracks 

300 this connection will force a reconnect after the current connection 

301 is checked in. It does not actively close the dbapi_connection 

302 at the point at which it is called. 

303 

304 :param dbapi_connection: a DBAPI connection. 

305 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

306 

307 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

308 the DBAPI connection. 

309 

310 :param exception: the exception object corresponding to the reason 

311 for this invalidation, if any. May be ``None``. 

312 

313 """ 

314 

315 def close( 

316 self, 

317 dbapi_connection: DBAPIConnection, 

318 connection_record: ConnectionPoolEntry, 

319 ) -> None: 

320 """Called when a DBAPI connection is closed. 

321 

322 The event is emitted before the close occurs. 

323 

324 The close of a connection can fail; typically this is because 

325 the connection is already closed. If the close operation fails, 

326 the connection is discarded. 

327 

328 The :meth:`.close` event corresponds to a connection that's still 

329 associated with the pool. To intercept close events for detached 

330 connections use :meth:`.close_detached`. 

331 

332 :param dbapi_connection: a DBAPI connection. 

333 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

334 

335 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

336 the DBAPI connection. 

337 

338 """ 

339 

340 def detach( 

341 self, 

342 dbapi_connection: DBAPIConnection, 

343 connection_record: ConnectionPoolEntry, 

344 ) -> None: 

345 """Called when a DBAPI connection is "detached" from a pool. 

346 

347 This event is emitted after the detach occurs. The connection 

348 is no longer associated with the given connection record. 

349 

350 :param dbapi_connection: a DBAPI connection. 

351 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

352 

353 :param connection_record: the :class:`.ConnectionPoolEntry` managing 

354 the DBAPI connection. 

355 

356 """ 

357 

358 def close_detached(self, dbapi_connection: DBAPIConnection) -> None: 

359 """Called when a detached DBAPI connection is closed. 

360 

361 The event is emitted before the close occurs. 

362 

363 The close of a connection can fail; typically this is because 

364 the connection is already closed. If the close operation fails, 

365 the connection is discarded. 

366 

367 :param dbapi_connection: a DBAPI connection. 

368 The :attr:`.ConnectionPoolEntry.dbapi_connection` attribute. 

369 

370 """