diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-08-31 21:46:14 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-08-31 21:46:14 -0400 |
commit | 3a86cea34abbcf1ca852ca8925b9866be3cd86f8 (patch) | |
tree | e104cd2f398eac67957f696085c134941c5b00d9 /lib/sqlalchemy | |
parent | 1149197a36f01dae1f8da82b7cfb73a7777e7a4a (diff) | |
download | sqlalchemy-3a86cea34abbcf1ca852ca8925b9866be3cd86f8.tar.gz |
doh, forgot about ddl events. need some work with the pickling.
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r-- | lib/sqlalchemy/engine/ddl.py | 38 | ||||
-rw-r--r-- | lib/sqlalchemy/event.py | 8 | ||||
-rw-r--r-- | lib/sqlalchemy/schema.py | 127 |
3 files changed, 67 insertions, 106 deletions
diff --git a/lib/sqlalchemy/engine/ddl.py b/lib/sqlalchemy/engine/ddl.py index 74205dbb0..0e165b8f5 100644 --- a/lib/sqlalchemy/engine/ddl.py +++ b/lib/sqlalchemy/engine/ddl.py @@ -35,21 +35,20 @@ class SchemaGenerator(DDLBase): tables = metadata.tables.values() collection = [t for t in sql_util.sort_tables(tables) if self._can_create(t)] - for listener in metadata.ddl_listeners['before-create']: - listener('before-create', metadata, self.connection, tables=collection) - + metadata.dispatch.on_before_create(metadata, self.connection, + tables=collection) + for table in collection: self.traverse_single(table, create_ok=True) - - for listener in metadata.ddl_listeners['after-create']: - listener('after-create', metadata, self.connection, tables=collection) + + metadata.dispatch.on_after_create(metadata, self.connection, + tables=collection) def visit_table(self, table, create_ok=False): if not create_ok and not self._can_create(table): return - - for listener in table.ddl_listeners['before-create']: - listener('before-create', table, self.connection) + + table.dispatch.on_before_create(table, self.connection) for column in table.columns: if column.default is not None: @@ -61,8 +60,7 @@ class SchemaGenerator(DDLBase): for index in table.indexes: self.traverse_single(index) - for listener in table.ddl_listeners['after-create']: - listener('after-create', table, self.connection) + table.dispatch.on_after_create(table, self.connection) def visit_sequence(self, sequence): if self.dialect.supports_sequences: @@ -91,14 +89,14 @@ class SchemaDropper(DDLBase): tables = metadata.tables.values() collection = [t for t in reversed(sql_util.sort_tables(tables)) if self._can_drop(t)] - for listener in metadata.ddl_listeners['before-drop']: - listener('before-drop', metadata, self.connection, tables=collection) + metadata.dispatch.on_before_drop(metadata, self.connection, + tables=collection) for table in collection: self.traverse_single(table, drop_ok=True) - for listener in metadata.ddl_listeners['after-drop']: - listener('after-drop', metadata, self.connection, tables=collection) + metadata.dispatch.on_after_drop(metadata, self.connection, + tables=collection) def _can_drop(self, table): self.dialect.validate_identifier(table.name) @@ -112,18 +110,16 @@ class SchemaDropper(DDLBase): def visit_table(self, table, drop_ok=False): if not drop_ok and not self._can_drop(table): return - - for listener in table.ddl_listeners['before-drop']: - listener('before-drop', table, self.connection) + + table.dispatch.on_before_drop(table, self.connection) for column in table.columns: if column.default is not None: self.traverse_single(column.default) self.connection.execute(schema.DropTable(table)) - - for listener in table.ddl_listeners['after-drop']: - listener('after-drop', table, self.connection) + + table.dispatch.on_after_drop(table, self.connection) def visit_sequence(self, sequence): if self.dialect.supports_sequences: diff --git a/lib/sqlalchemy/event.py b/lib/sqlalchemy/event.py index 5448503b2..0e99eb374 100644 --- a/lib/sqlalchemy/event.py +++ b/lib/sqlalchemy/event.py @@ -5,7 +5,7 @@ and :mod:`sqlalchemy.orm` packages. """ -from sqlalchemy import util +from sqlalchemy import util, exc CANCEL = util.symbol('CANCEL') NO_RETVAL = util.symbol('NO_RETVAL') @@ -26,7 +26,9 @@ def listen(fn, identifier, target, *args, **kw): for evt_cls in _registrars[identifier]: for tgt in evt_cls.accept_with(target): tgt.dispatch.listen(fn, identifier, tgt, *args, **kw) - break + return + raise exc.InvalidRequestError("No such event %s for target %s" % + (identifier,target)) _registrars = util.defaultdict(list) @@ -178,7 +180,7 @@ class dispatcher(object): """ def __init__(self, events): self.dispatch_cls = events.dispatch - + self.events = events def __get__(self, obj, cls): if obj is None: diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 5b5983858..fdc961619 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -31,6 +31,7 @@ as components in SQL expressions. import re, inspect from sqlalchemy import exc, util, dialects from sqlalchemy.sql import expression, visitors +from sqlalchemy import event URL = None @@ -81,6 +82,20 @@ def _get_table_key(name, schema): else: return schema + "." + name +class DDLEvents(event.Events): + def on_before_create(self, target, connection, **kw): + pass + + def on_after_create(self, target, connection, **kw): + pass + + def on_before_drop(self, target, connection, **kw): + pass + + def on_after_drop(self, target, connection, **kw): + pass + + class Table(SchemaItem, expression.TableClause): """Represent a table in a database. @@ -174,8 +189,7 @@ class Table(SchemaItem, expression.TableClause): __visit_name__ = 'table' - ddl_events = ('before-create', 'after-create', - 'before-drop', 'after-drop') + dispatch = event.dispatcher(DDLEvents) def __new__(cls, *args, **kw): if not args: @@ -227,7 +241,6 @@ class Table(SchemaItem, expression.TableClause): self._set_primary_key(PrimaryKeyConstraint()) self._foreign_keys = util.OrderedSet() self._extra_dependencies = set() - self.ddl_listeners = util.defaultdict(list) self.kwargs = {} if self.schema is not None: self.fullname = "%s.%s" % (self.schema, self.name) @@ -371,37 +384,18 @@ class Table(SchemaItem, expression.TableClause): constraint._set_parent(self) - def append_ddl_listener(self, event, listener): + def append_ddl_listener(self, event_name, listener): """Append a DDL event listener to this ``Table``. - - The ``listener`` callable will be triggered when this ``Table`` is - created or dropped, either directly before or after the DDL is issued - to the database. The listener may modify the Table, but may not abort - the event itself. - :param event: - One of ``Table.ddl_events``; e.g. 'before-create', 'after-create', - 'before-drop' or 'after-drop'. - - :param listener: - A callable, invoked with three positional arguments: - - :event: - The event currently being handled - - :target: - The ``Table`` object being created or dropped - - :bind: - The ``Connection`` bueing used for DDL execution. - - Listeners are added to the Table's ``ddl_listeners`` attribute. + Deprecated. See :class:`.DDLEvents`. """ - - if event not in self.ddl_events: - raise LookupError(event) - self.ddl_listeners[event].append(listener) + + def adapt_listener(target, connection, **kw): + listener(event_name, target, connection, **kw) + + event.listen(adapt_listener, + "on_" + event_name.replace('-', '_'), self) def _set_parent(self, metadata): metadata.tables[_get_table_key(self.name, self.schema)] = self @@ -1835,8 +1829,7 @@ class MetaData(SchemaItem): __visit_name__ = 'metadata' - ddl_events = ('before-create', 'after-create', - 'before-drop', 'after-drop') + dispatch = event.dispatcher(DDLEvents) def __init__(self, bind=None, reflect=False): """Create a new MetaData object. @@ -1856,7 +1849,6 @@ class MetaData(SchemaItem): self.tables = {} self.bind = bind self.metadata = self - self.ddl_listeners = util.defaultdict(list) if reflect: if not bind: raise exc.ArgumentError( @@ -1993,44 +1985,17 @@ class MetaData(SchemaItem): for name in load: Table(name, self, **reflect_opts) - def append_ddl_listener(self, event, listener): + def append_ddl_listener(self, event_name, listener): """Append a DDL event listener to this ``MetaData``. - The ``listener`` callable will be triggered when this ``MetaData`` is - involved in DDL creates or drops, and will be invoked either before - all Table-related actions or after. - - :param event: - One of ``MetaData.ddl_events``; 'before-create', 'after-create', - 'before-drop' or 'after-drop'. - - :param listener: - A callable, invoked with three positional arguments: - - :event: - The event currently being handled - - :target: - The ``MetaData`` object being operated upon - - :bind: - The ``Connection`` bueing used for DDL execution. - - Listeners are added to the MetaData's ``ddl_listeners`` attribute. - - Note: MetaData listeners are invoked even when ``Tables`` are created - in isolation. This may change in a future release. I.e.:: - - # triggers all MetaData and Table listeners: - metadata.create_all() - - # triggers MetaData listeners too: - some.table.create() + Deprecated. See :class:`.DDLEvents`. """ - if event not in self.ddl_events: - raise LookupError(event) - self.ddl_listeners[event].append(listener) + def adapt_listener(target, connection, **kw): + listener(event, target, connection, **kw) + + event.listen(adapt_listener, + "on_" + event_name.replace('-', '_'), self) def create_all(self, bind=None, tables=None, checkfirst=True): """Create all tables stored in this metadata. @@ -2194,7 +2159,7 @@ class DDLElement(expression.Executable, expression.ClauseElement): bind.engine.logger.info( "DDL execution skipped, criteria not met.") - def execute_at(self, event, target): + def execute_at(self, event_name, target): """Link execution of this DDL to the DDL lifecycle of a SchemaItem. Links this ``DDLElement`` to a ``Table`` or ``MetaData`` instance, @@ -2203,9 +2168,10 @@ class DDLElement(expression.Executable, expression.ClauseElement): context as the Table create/drop itself. The ``.bind`` property of this statement is ignored. - :param event: - One of the events defined in the schema item's ``.ddl_events``; - e.g. 'before-create', 'after-create', 'before-drop' or 'after-drop' + :param event_name: + Name of an event from :class:`.DDLEvents`. e.g.: + 'on_before_create', 'on_after_create', 'on_before_drop', + 'on_after_drop'. :param target: The Table or MetaData instance for which this DDLElement will @@ -2220,16 +2186,12 @@ class DDLElement(expression.Executable, expression.ClauseElement): any DDL set to ``execute_at`` that Table's MetaData. This may change in a future release. """ - - if not hasattr(target, 'ddl_listeners'): - raise exc.ArgumentError( - "%s does not support DDL events" % type(target).__name__) - if event not in target.ddl_events: - raise exc.ArgumentError( - "Unknown event, expected one of (%s), got '%r'" % - (', '.join(target.ddl_events), event)) - target.ddl_listeners[event].append(self) - return self + + event_name = "on_" + event_name.replace('-', '_') + def call_event(target, connection, **kw): + self(event_name, target, connection, **kw) + + event.listen(call_event, event_name, target) @expression._generative def against(self, target): @@ -2346,7 +2308,8 @@ class DDL(DDLElement): :event: The name of the event that has triggered this DDL, such as - 'after-create' Will be None if the DDL is executed explicitly. + 'on_after_create' Will be None if the DDL is executed + explicitly. :target: The ``Table`` or ``MetaData`` object which is the target of |