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

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

52 statements  

1# pool/events.py 

2# Copyright (C) 2005-2026 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 When using an :class:`.Engine` object created via :func:`_sa.create_engine` 

35 (or indirectly via :func:`.create_async_engine`), :class:`.PoolEvents` 

36 listeners are expected to be registered in terms of the :class:`.Engine`, 

37 which will direct the listeners to the :class:`.Pool` contained within:: 

38 

39 from sqlalchemy import create_engine 

40 from sqlalchemy import event 

41 

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

43 

44 

45 @event.listens_for(engine, "checkout") 

46 def my_on_checkout(dbapi_conn, connection_rec, connection_proxy): 

47 "handle an on checkout event" 

48 

49 :class:`.PoolEvents` may also be registered with the :class:`_pool.Pool` 

50 class, with the :class:`.Engine` class, as well as with instances of 

51 :class:`_pool.Pool`. 

52 

53 .. tip:: 

54 

55 Registering :class:`.PoolEvents` with the :class:`.Engine`, if present, 

56 is recommended since the :meth:`.Engine.dispose` method will carry 

57 along event listeners from the old pool to the new pool. 

58 

59 """ # noqa: E501 

60 

61 _target_class_doc = "SomeEngineOrPool" 

62 _dispatch_target = Pool 

63 

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

65 @classmethod 

66 def _accept_with( 

67 cls, 

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

69 identifier: str, 

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

71 if not typing.TYPE_CHECKING: 

72 Engine = util.preloaded.engine.Engine 

73 

74 if isinstance(target, type): 

75 if issubclass(target, Engine): 

76 return Pool 

77 else: 

78 assert issubclass(target, Pool) 

79 return target 

80 elif isinstance(target, Engine): 

81 return target.pool 

82 elif isinstance(target, Pool): 

83 return target 

84 elif hasattr(target, "_no_async_engine_events"): 

85 target._no_async_engine_events() 

86 else: 

87 return None 

88 

89 @classmethod 

90 def _listen( 

91 cls, 

92 event_key: event._EventKey[Pool], 

93 **kw: Any, 

94 ) -> None: 

95 target = event_key.dispatch_target 

96 

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

98 

99 event_key.base_listen(**kw) 

100 

101 def connect( 

102 self, 

103 dbapi_connection: DBAPIConnection, 

104 connection_record: ConnectionPoolEntry, 

105 ) -> None: 

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

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

108 

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

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

111 to produce a new DBAPI connection. 

112 

113 :param dbapi_connection: a DBAPI connection. 

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

115 

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

117 the DBAPI connection. 

118 

119 """ 

120 

121 def first_connect( 

122 self, 

123 dbapi_connection: DBAPIConnection, 

124 connection_record: ConnectionPoolEntry, 

125 ) -> None: 

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

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

128 

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

130 is to determine 

131 information about a particular series of database connections based 

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

133 :class:`_pool.Pool` 

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

135 of a :class:`_engine.Engine` 

136 refers to the URL and connection options used), 

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

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

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

140 encoding settings, collation settings, and many others. 

141 

142 :param dbapi_connection: a DBAPI connection. 

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

144 

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

146 the DBAPI connection. 

147 

148 """ 

149 

150 def checkout( 

151 self, 

152 dbapi_connection: DBAPIConnection, 

153 connection_record: ConnectionPoolEntry, 

154 connection_proxy: PoolProxiedConnection, 

155 ) -> None: 

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

157 

158 :param dbapi_connection: a DBAPI connection. 

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

160 

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

162 the DBAPI connection. 

163 

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

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

166 lifespan of the checkout. 

167 

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

169 connection will be disposed and a fresh connection retrieved. 

170 Processing of all checkout listeners will abort and restart 

171 using the new connection. 

172 

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

174 - a similar event 

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

176 

177 """ 

178 

179 def checkin( 

180 self, 

181 dbapi_connection: Optional[DBAPIConnection], 

182 connection_record: ConnectionPoolEntry, 

183 ) -> None: 

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

185 

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

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

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

189 

190 :param dbapi_connection: a DBAPI connection. 

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

192 

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

194 the DBAPI connection. 

195 

196 """ 

197 

198 @event._legacy_signature( 

199 "2.0", 

200 ["dbapi_connection", "connection_record"], 

201 lambda dbapi_connection, connection_record, reset_state: ( 

202 dbapi_connection, 

203 connection_record, 

204 ), 

205 ) 

206 def reset( 

207 self, 

208 dbapi_connection: DBAPIConnection, 

209 connection_record: ConnectionPoolEntry, 

210 reset_state: PoolResetState, 

211 ) -> None: 

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

213 

214 This event represents 

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

216 before it is returned to the pool or discarded. 

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

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

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

220 

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

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

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

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

225 connections that were detached using the 

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

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

228 connections before the connection was checked in. 

229 

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

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

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

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

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

235 

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

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

238 cases where the connection is discarded immediately after reset. 

239 

240 :param dbapi_connection: a DBAPI connection. 

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

242 

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

244 the DBAPI connection. 

245 

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

247 information about the circumstances under which the connection 

248 is being reset. 

249 

250 .. versionadded:: 2.0 

251 

252 .. seealso:: 

253 

254 :ref:`pool_reset_on_return` 

255 

256 :meth:`_events.ConnectionEvents.rollback` 

257 

258 :meth:`_events.ConnectionEvents.commit` 

259 

260 """ 

261 

262 def invalidate( 

263 self, 

264 dbapi_connection: DBAPIConnection, 

265 connection_record: ConnectionPoolEntry, 

266 exception: Optional[BaseException], 

267 ) -> None: 

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

269 

270 This event is called any time the 

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

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

273 

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

275 connection occurs. 

276 

277 :param dbapi_connection: a DBAPI connection. 

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

279 

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

281 the DBAPI connection. 

282 

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

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

285 

286 .. seealso:: 

287 

288 :ref:`pool_connection_invalidation` 

289 

290 """ 

291 

292 def soft_invalidate( 

293 self, 

294 dbapi_connection: DBAPIConnection, 

295 connection_record: ConnectionPoolEntry, 

296 exception: Optional[BaseException], 

297 ) -> None: 

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

299 

300 This event is called any time the 

301 :meth:`.ConnectionPoolEntry.invalidate` 

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

303 

304 Soft invalidation refers to when the connection record that tracks 

305 this connection will force a reconnect after the current connection 

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

307 at the point at which it is called. 

308 

309 :param dbapi_connection: a DBAPI connection. 

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

311 

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

313 the DBAPI connection. 

314 

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

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

317 

318 """ 

319 

320 def close( 

321 self, 

322 dbapi_connection: DBAPIConnection, 

323 connection_record: ConnectionPoolEntry, 

324 ) -> None: 

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

326 

327 The event is emitted before the close occurs. 

328 

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

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

331 the connection is discarded. 

332 

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

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

335 connections use :meth:`.close_detached`. 

336 

337 :param dbapi_connection: a DBAPI connection. 

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

339 

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

341 the DBAPI connection. 

342 

343 """ 

344 

345 def detach( 

346 self, 

347 dbapi_connection: DBAPIConnection, 

348 connection_record: ConnectionPoolEntry, 

349 ) -> None: 

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

351 

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

353 is no longer associated with the given connection record. 

354 

355 :param dbapi_connection: a DBAPI connection. 

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

357 

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

359 the DBAPI connection. 

360 

361 """ 

362 

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

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

365 

366 The event is emitted before the close occurs. 

367 

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

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

370 the connection is discarded. 

371 

372 :param dbapi_connection: a DBAPI connection. 

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

374 

375 """