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

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

25 statements  

1# sql/events.py 

2# Copyright (C) 2005-2025 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 

7 

8from __future__ import annotations 

9 

10from typing import Any 

11from typing import TYPE_CHECKING 

12 

13from .base import SchemaEventTarget 

14from .. import event 

15 

16if TYPE_CHECKING: 

17 from .schema import Column 

18 from .schema import Constraint 

19 from .schema import SchemaItem 

20 from .schema import Table 

21 from ..engine.base import Connection 

22 from ..engine.interfaces import ReflectedColumn 

23 from ..engine.reflection import Inspector 

24 

25 

26class DDLEvents(event.Events[SchemaEventTarget]): 

27 """ 

28 Define event listeners for schema objects, 

29 that is, :class:`.SchemaItem` and other :class:`.SchemaEventTarget` 

30 subclasses, including :class:`_schema.MetaData`, :class:`_schema.Table`, 

31 :class:`_schema.Column`, etc. 

32 

33 **Create / Drop Events** 

34 

35 Events emitted when CREATE and DROP commands are emitted to the database. 

36 The event hooks in this category include :meth:`.DDLEvents.before_create`, 

37 :meth:`.DDLEvents.after_create`, :meth:`.DDLEvents.before_drop`, and 

38 :meth:`.DDLEvents.after_drop`. 

39 

40 These events are emitted when using schema-level methods such as 

41 :meth:`.MetaData.create_all` and :meth:`.MetaData.drop_all`. Per-object 

42 create/drop methods such as :meth:`.Table.create`, :meth:`.Table.drop`, 

43 :meth:`.Index.create` are also included, as well as dialect-specific 

44 methods such as :meth:`_postgresql.ENUM.create`. 

45 

46 .. versionadded:: 2.0 :class:`.DDLEvents` event hooks now take place 

47 for non-table objects including constraints, indexes, and 

48 dialect-specific schema types. 

49 

50 Event hooks may be attached directly to a :class:`_schema.Table` object or 

51 to a :class:`_schema.MetaData` collection, as well as to any 

52 :class:`.SchemaItem` class or object that can be individually created and 

53 dropped using a distinct SQL command. Such classes include :class:`.Index`, 

54 :class:`.Sequence`, and dialect-specific classes such as 

55 :class:`_postgresql.ENUM`. 

56 

57 Example using the :meth:`.DDLEvents.after_create` event, where a custom 

58 event hook will emit an ``ALTER TABLE`` command on the current connection, 

59 after ``CREATE TABLE`` is emitted:: 

60 

61 from sqlalchemy import create_engine 

62 from sqlalchemy import event 

63 from sqlalchemy import Table, Column, Metadata, Integer 

64 

65 m = MetaData() 

66 some_table = Table("some_table", m, Column("data", Integer)) 

67 

68 

69 @event.listens_for(some_table, "after_create") 

70 def after_create(target, connection, **kw): 

71 connection.execute( 

72 text("ALTER TABLE %s SET name=foo_%s" % (target.name, target.name)) 

73 ) 

74 

75 

76 some_engine = create_engine("postgresql://scott:tiger@host/test") 

77 

78 # will emit "CREATE TABLE some_table" as well as the above 

79 # "ALTER TABLE" statement afterwards 

80 m.create_all(some_engine) 

81 

82 Constraint objects such as :class:`.ForeignKeyConstraint`, 

83 :class:`.UniqueConstraint`, :class:`.CheckConstraint` may also be 

84 subscribed to these events, however they will **not** normally produce 

85 events as these objects are usually rendered inline within an 

86 enclosing ``CREATE TABLE`` statement and implicitly dropped from a 

87 ``DROP TABLE`` statement. 

88 

89 For the :class:`.Index` construct, the event hook will be emitted 

90 for ``CREATE INDEX``, however SQLAlchemy does not normally emit 

91 ``DROP INDEX`` when dropping tables as this is again implicit within the 

92 ``DROP TABLE`` statement. 

93 

94 .. versionadded:: 2.0 Support for :class:`.SchemaItem` objects 

95 for create/drop events was expanded from its previous support for 

96 :class:`.MetaData` and :class:`.Table` to also include 

97 :class:`.Constraint` and all subclasses, :class:`.Index`, 

98 :class:`.Sequence` and some type-related constructs such as 

99 :class:`_postgresql.ENUM`. 

100 

101 .. note:: These event hooks are only emitted within the scope of 

102 SQLAlchemy's create/drop methods; they are not necessarily supported 

103 by tools such as `alembic <https://alembic.sqlalchemy.org>`_. 

104 

105 

106 **Attachment Events** 

107 

108 Attachment events are provided to customize 

109 behavior whenever a child schema element is associated 

110 with a parent, such as when a :class:`_schema.Column` is associated 

111 with its :class:`_schema.Table`, when a 

112 :class:`_schema.ForeignKeyConstraint` 

113 is associated with a :class:`_schema.Table`, etc. These events include 

114 :meth:`.DDLEvents.before_parent_attach` and 

115 :meth:`.DDLEvents.after_parent_attach`. 

116 

117 **Reflection Events** 

118 

119 The :meth:`.DDLEvents.column_reflect` event is used to intercept 

120 and modify the in-Python definition of database columns when 

121 :term:`reflection` of database tables proceeds. 

122 

123 **Use with Generic DDL** 

124 

125 DDL events integrate closely with the 

126 :class:`.DDL` class and the :class:`.ExecutableDDLElement` hierarchy 

127 of DDL clause constructs, which are themselves appropriate 

128 as listener callables:: 

129 

130 from sqlalchemy import DDL 

131 

132 event.listen( 

133 some_table, 

134 "after_create", 

135 DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"), 

136 ) 

137 

138 **Event Propagation to MetaData Copies** 

139 

140 For all :class:`.DDLEvent` events, the ``propagate=True`` keyword argument 

141 will ensure that a given event handler is propagated to copies of the 

142 object, which are made when using the :meth:`_schema.Table.to_metadata` 

143 method:: 

144 

145 from sqlalchemy import DDL 

146 

147 metadata = MetaData() 

148 some_table = Table("some_table", metadata, Column("data", Integer)) 

149 

150 event.listen( 

151 some_table, 

152 "after_create", 

153 DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"), 

154 propagate=True, 

155 ) 

156 

157 new_metadata = MetaData() 

158 new_table = some_table.to_metadata(new_metadata) 

159 

160 The above :class:`.DDL` object will be associated with the 

161 :meth:`.DDLEvents.after_create` event for both the ``some_table`` and 

162 the ``new_table`` :class:`.Table` objects. 

163 

164 .. seealso:: 

165 

166 :ref:`event_toplevel` 

167 

168 :class:`.ExecutableDDLElement` 

169 

170 :class:`.DDL` 

171 

172 :ref:`schema_ddl_sequences` 

173 

174 """ # noqa: E501 

175 

176 _target_class_doc = "SomeSchemaClassOrObject" 

177 _dispatch_target = SchemaEventTarget 

178 

179 def before_create( 

180 self, target: SchemaEventTarget, connection: Connection, **kw: Any 

181 ) -> None: 

182 r"""Called before CREATE statements are emitted. 

183 

184 :param target: the :class:`.SchemaObject`, such as a 

185 :class:`_schema.MetaData` or :class:`_schema.Table` 

186 but also including all create/drop objects such as 

187 :class:`.Index`, :class:`.Sequence`, etc., 

188 object which is the target of the event. 

189 

190 .. versionadded:: 2.0 Support for all :class:`.SchemaItem` objects 

191 was added. 

192 

193 :param connection: the :class:`_engine.Connection` where the 

194 CREATE statement or statements will be emitted. 

195 :param \**kw: additional keyword arguments relevant 

196 to the event. The contents of this dictionary 

197 may vary across releases, and include the 

198 list of tables being generated for a metadata-level 

199 event, the checkfirst flag, and other 

200 elements used by internal events. 

201 

202 :func:`.event.listen` accepts the ``propagate=True`` 

203 modifier for this event; when True, the listener function will 

204 be established for any copies made of the target object, 

205 i.e. those copies that are generated when 

206 :meth:`_schema.Table.to_metadata` is used. 

207 

208 :func:`.event.listen` accepts the ``insert=True`` 

209 modifier for this event; when True, the listener function will 

210 be prepended to the internal list of events upon discovery, and execute 

211 before registered listener functions that do not pass this argument. 

212 

213 """ 

214 

215 def after_create( 

216 self, target: SchemaEventTarget, connection: Connection, **kw: Any 

217 ) -> None: 

218 r"""Called after CREATE statements are emitted. 

219 

220 :param target: the :class:`.SchemaObject`, such as a 

221 :class:`_schema.MetaData` or :class:`_schema.Table` 

222 but also including all create/drop objects such as 

223 :class:`.Index`, :class:`.Sequence`, etc., 

224 object which is the target of the event. 

225 

226 .. versionadded:: 2.0 Support for all :class:`.SchemaItem` objects 

227 was added. 

228 

229 :param connection: the :class:`_engine.Connection` where the 

230 CREATE statement or statements have been emitted. 

231 :param \**kw: additional keyword arguments relevant 

232 to the event. The contents of this dictionary 

233 may vary across releases, and include the 

234 list of tables being generated for a metadata-level 

235 event, the checkfirst flag, and other 

236 elements used by internal events. 

237 

238 :func:`.event.listen` also accepts the ``propagate=True`` 

239 modifier for this event; when True, the listener function will 

240 be established for any copies made of the target object, 

241 i.e. those copies that are generated when 

242 :meth:`_schema.Table.to_metadata` is used. 

243 

244 """ 

245 

246 def before_drop( 

247 self, target: SchemaEventTarget, connection: Connection, **kw: Any 

248 ) -> None: 

249 r"""Called before DROP statements are emitted. 

250 

251 :param target: the :class:`.SchemaObject`, such as a 

252 :class:`_schema.MetaData` or :class:`_schema.Table` 

253 but also including all create/drop objects such as 

254 :class:`.Index`, :class:`.Sequence`, etc., 

255 object which is the target of the event. 

256 

257 .. versionadded:: 2.0 Support for all :class:`.SchemaItem` objects 

258 was added. 

259 

260 :param connection: the :class:`_engine.Connection` where the 

261 DROP statement or statements will be emitted. 

262 :param \**kw: additional keyword arguments relevant 

263 to the event. The contents of this dictionary 

264 may vary across releases, and include the 

265 list of tables being generated for a metadata-level 

266 event, the checkfirst flag, and other 

267 elements used by internal events. 

268 

269 :func:`.event.listen` also accepts the ``propagate=True`` 

270 modifier for this event; when True, the listener function will 

271 be established for any copies made of the target object, 

272 i.e. those copies that are generated when 

273 :meth:`_schema.Table.to_metadata` is used. 

274 

275 """ 

276 

277 def after_drop( 

278 self, target: SchemaEventTarget, connection: Connection, **kw: Any 

279 ) -> None: 

280 r"""Called after DROP statements are emitted. 

281 

282 :param target: the :class:`.SchemaObject`, such as a 

283 :class:`_schema.MetaData` or :class:`_schema.Table` 

284 but also including all create/drop objects such as 

285 :class:`.Index`, :class:`.Sequence`, etc., 

286 object which is the target of the event. 

287 

288 .. versionadded:: 2.0 Support for all :class:`.SchemaItem` objects 

289 was added. 

290 

291 :param connection: the :class:`_engine.Connection` where the 

292 DROP statement or statements have been emitted. 

293 :param \**kw: additional keyword arguments relevant 

294 to the event. The contents of this dictionary 

295 may vary across releases, and include the 

296 list of tables being generated for a metadata-level 

297 event, the checkfirst flag, and other 

298 elements used by internal events. 

299 

300 :func:`.event.listen` also accepts the ``propagate=True`` 

301 modifier for this event; when True, the listener function will 

302 be established for any copies made of the target object, 

303 i.e. those copies that are generated when 

304 :meth:`_schema.Table.to_metadata` is used. 

305 

306 """ 

307 

308 def before_parent_attach( 

309 self, target: SchemaEventTarget, parent: SchemaItem 

310 ) -> None: 

311 """Called before a :class:`.SchemaItem` is associated with 

312 a parent :class:`.SchemaItem`. 

313 

314 :param target: the target object 

315 :param parent: the parent to which the target is being attached. 

316 

317 :func:`.event.listen` also accepts the ``propagate=True`` 

318 modifier for this event; when True, the listener function will 

319 be established for any copies made of the target object, 

320 i.e. those copies that are generated when 

321 :meth:`_schema.Table.to_metadata` is used. 

322 

323 """ 

324 

325 def after_parent_attach( 

326 self, target: SchemaEventTarget, parent: SchemaItem 

327 ) -> None: 

328 """Called after a :class:`.SchemaItem` is associated with 

329 a parent :class:`.SchemaItem`. 

330 

331 :param target: the target object 

332 :param parent: the parent to which the target is being attached. 

333 

334 :func:`.event.listen` also accepts the ``propagate=True`` 

335 modifier for this event; when True, the listener function will 

336 be established for any copies made of the target object, 

337 i.e. those copies that are generated when 

338 :meth:`_schema.Table.to_metadata` is used. 

339 

340 """ 

341 

342 def _sa_event_column_added_to_pk_constraint( 

343 self, const: Constraint, col: Column[Any] 

344 ) -> None: 

345 """internal event hook used for primary key naming convention 

346 updates. 

347 

348 """ 

349 

350 def column_reflect( 

351 self, inspector: Inspector, table: Table, column_info: ReflectedColumn 

352 ) -> None: 

353 """Called for each unit of 'column info' retrieved when 

354 a :class:`_schema.Table` is being reflected. 

355 

356 This event is most easily used by applying it to a specific 

357 :class:`_schema.MetaData` instance, where it will take effect for 

358 all :class:`_schema.Table` objects within that 

359 :class:`_schema.MetaData` that undergo reflection:: 

360 

361 metadata = MetaData() 

362 

363 

364 @event.listens_for(metadata, "column_reflect") 

365 def receive_column_reflect(inspector, table, column_info): 

366 # receives for all Table objects that are reflected 

367 # under this MetaData 

368 ... 

369 

370 

371 # will use the above event hook 

372 my_table = Table("my_table", metadata, autoload_with=some_engine) 

373 

374 .. versionadded:: 1.4.0b2 The :meth:`_events.DDLEvents.column_reflect` 

375 hook may now be applied to a :class:`_schema.MetaData` object as 

376 well as the :class:`_schema.MetaData` class itself where it will 

377 take place for all :class:`_schema.Table` objects associated with 

378 the targeted :class:`_schema.MetaData`. 

379 

380 It may also be applied to the :class:`_schema.Table` class across 

381 the board:: 

382 

383 from sqlalchemy import Table 

384 

385 

386 @event.listens_for(Table, "column_reflect") 

387 def receive_column_reflect(inspector, table, column_info): 

388 # receives for all Table objects that are reflected 

389 ... 

390 

391 It can also be applied to a specific :class:`_schema.Table` at the 

392 point that one is being reflected using the 

393 :paramref:`_schema.Table.listeners` parameter:: 

394 

395 t1 = Table( 

396 "my_table", 

397 autoload_with=some_engine, 

398 listeners=[("column_reflect", receive_column_reflect)], 

399 ) 

400 

401 The dictionary of column information as returned by the 

402 dialect is passed, and can be modified. The dictionary 

403 is that returned in each element of the list returned 

404 by :meth:`.reflection.Inspector.get_columns`: 

405 

406 * ``name`` - the column's name, is applied to the 

407 :paramref:`_schema.Column.name` parameter 

408 

409 * ``type`` - the type of this column, which should be an instance 

410 of :class:`~sqlalchemy.types.TypeEngine`, is applied to the 

411 :paramref:`_schema.Column.type` parameter 

412 

413 * ``nullable`` - boolean flag if the column is NULL or NOT NULL, 

414 is applied to the :paramref:`_schema.Column.nullable` parameter 

415 

416 * ``default`` - the column's server default value. This is 

417 normally specified as a plain string SQL expression, however the 

418 event can pass a :class:`.FetchedValue`, :class:`.DefaultClause`, 

419 or :func:`_expression.text` object as well. Is applied to the 

420 :paramref:`_schema.Column.server_default` parameter 

421 

422 The event is called before any action is taken against 

423 this dictionary, and the contents can be modified; the following 

424 additional keys may be added to the dictionary to further modify 

425 how the :class:`_schema.Column` is constructed: 

426 

427 

428 * ``key`` - the string key that will be used to access this 

429 :class:`_schema.Column` in the ``.c`` collection; will be applied 

430 to the :paramref:`_schema.Column.key` parameter. Is also used 

431 for ORM mapping. See the section 

432 :ref:`mapper_automated_reflection_schemes` for an example. 

433 

434 * ``quote`` - force or un-force quoting on the column name; 

435 is applied to the :paramref:`_schema.Column.quote` parameter. 

436 

437 * ``info`` - a dictionary of arbitrary data to follow along with 

438 the :class:`_schema.Column`, is applied to the 

439 :paramref:`_schema.Column.info` parameter. 

440 

441 :func:`.event.listen` also accepts the ``propagate=True`` 

442 modifier for this event; when True, the listener function will 

443 be established for any copies made of the target object, 

444 i.e. those copies that are generated when 

445 :meth:`_schema.Table.to_metadata` is used. 

446 

447 .. seealso:: 

448 

449 :ref:`mapper_automated_reflection_schemes` - 

450 in the ORM mapping documentation 

451 

452 :ref:`automap_intercepting_columns` - 

453 in the :ref:`automap_toplevel` documentation 

454 

455 :ref:`metadata_reflection_dbagnostic_types` - in 

456 the :ref:`metadata_reflection_toplevel` documentation 

457 

458 """