Author: phd
Date: 2005-11-01 11:14:21 +0000 (Tue, 01 Nov 2005)
New Revision: 1181
Modified:
home/phd/SQLObject/paramstyles/docs/News.txt
home/phd/SQLObject/paramstyles/sqlobject/conftest.py
home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py
home/phd/SQLObject/paramstyles/sqlobject/events.py
Log:
Merged patches from the revisions 1175:1180 from the trunk
Modified: home/phd/SQLObject/paramstyles/docs/News.txt
===================================================================
--- home/phd/SQLObject/paramstyles/docs/News.txt 2005-10-31 23:50:28 UTC (rev 1180)
+++ home/phd/SQLObject/paramstyles/docs/News.txt 2005-11-01 11:14:21 UTC (rev 1181)
@@ -27,13 +27,22 @@
instead you must manually create it (e.g., with explicit SQLObject
classes for the joins).
-* Added ``createSQL`` as an option for sqlmeta. Here you can add related SQL
- you want executed by sqlobject-admin create after table creation. createSQL
- expects a string, list, or dictionary. If using a dictionary the key should
- be a dbName value (ex. 'postgres') and the value should be a string or list.
- Examples in sqlobject/tests/test_sqlobject_admin.py or at
+* Added ``createSQL`` as an option for sqlmeta. Here you can add
+ related SQL you want executed by sqlobject-admin create after table
+ creation. createSQL expects a string, list, or dictionary. If using
+ a dictionary the key should be a dbName value (ex. 'postgres') and
+ the value should be a string or list. Examples in
+ sqlobject/tests/test_sqlobject_admin.py or at
<http://sqlobject.org/sqlobject-admin.html#the-create-command>
+* Added method ``sqlhub.doInTransaction(callable, *args, **kwargs)``,
+ to be used like::
+
+ sqlhub.doInTransaction(process_request, os.environ)
+
+ This will run ``process_request(os.environ)``. The return
+ value will be preserved.
+
SQLObject 0.7.1
===============
Modified: home/phd/SQLObject/paramstyles/sqlobject/conftest.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/conftest.py 2005-10-31 23:50:28 UTC (rev 1180)
+++ home/phd/SQLObject/paramstyles/sqlobject/conftest.py 2005-11-01 11:14:21 UTC (rev 1181)
@@ -10,6 +10,8 @@
import py
import os
import sqlobject
+import pkg_resources
+pkg_resources.require('SQLObject')
connectionShortcuts = {
'mysql': 'mysql://test@localhost/test',
Modified: home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2005-10-31 23:50:28 UTC (rev 1180)
+++ home/phd/SQLObject/paramstyles/sqlobject/dbconnection.py 2005-11-01 11:14:21 UTC (rev 1181)
@@ -916,6 +916,34 @@
"No connection has been defined for this thread "
"or process")
+ def doInTransaction(self, func, *args, **kw):
+ """
+ This routine can be used to run a function in a transaction,
+ rolling the transaction back if any exception is raised from
+ that function, and committing otherwise. Use like::
+
+ sqlhub.doInTransaction(process_request, os.environ)
+
+ This will run ``process_request(os.environ)``. The return
+ value will be preserved.
+ """
+ # @@: In Python 2.5, something usable with with: should also
+ # be added.
+ old_conn = self.getConnection()
+ conn = old_conn.transaction()
+ self.threadConnection = conn
+ try:
+ try:
+ value = func(*args, **kw)
+ except:
+ conn.rollback()
+ raise
+ else:
+ conn.commit()
+ return value
+ finally:
+ self.threadConnection = old_conn
+
def _set_threadConnection(self, value):
self.threadingLocal.connection = value
Modified: home/phd/SQLObject/paramstyles/sqlobject/events.py
===================================================================
--- home/phd/SQLObject/paramstyles/sqlobject/events.py 2005-10-31 23:50:28 UTC (rev 1180)
+++ home/phd/SQLObject/paramstyles/sqlobject/events.py 2005-11-01 11:14:21 UTC (rev 1181)
@@ -1,4 +1,18 @@
-class Event(object):
+from dispatch import dispatcher
+from weakref import ref
+
+
+subclassClones = {}
+
+def listen(receiver, soClass, signal, alsoSubclasses=True):
+ dispatcher.connect(receiver, signal=signal, sender=soClass)
+ weakSOClass = ref(soClass)
+ weakReceiver = ref(receiver)
+ subclassClones.setdefault(weakSOClass, []).append((weakReceiver, signal))
+
+send = dispatcher.send
+
+class Signal(object):
"""
Base event for all SQLObject events.
@@ -6,9 +20,9 @@
instance.
"""
-class ClassCreateEvent(Event):
+class ClassCreateSignal(Signal):
"""
- Event raised before class creation. The sender is the superclass
+ Signal raised before class creation. The sender is the superclass
(in case of multiple superclasses, the first superclass). The
arguments are ``(new_class_name, bases, new_attrs, post_funcs)``.
``new_attrs`` is a dictionary and may be modified (but
@@ -21,30 +35,41 @@
``(new_class)``.
"""
+def _makeSubclassConnections(new_class_name, bases, new_attrs, post_funcs):
+ post_funcs.append(_makeSubclassConnectionsPost)
+
+def _makeSubclassConnectionsPost(new_class):
+ for cls in new_class.__bases__:
+ for weakReceiver, signal in subclassClones.get(cls, []):
+ receiver = weakReceiver()
+ if not receiver:
+ continue
+ dispatcher.connect(receiver, signal=signal, sender=new_class)
+
+dispatcher.connect(_makeSubclassConnections, signal=ClassCreateSignal)
+
# @@: Should there be a class reload event? This would allow modules
# to be reloaded, possibly. Or it could even be folded into
-# ClassCreateEvent, since anything that listens to that needs to pay
+# ClassCreateSignal, since anything that listens to that needs to pay
# attention to reloads (or else it is probably buggy).
-class InstanceCreateEvent(Event):
+class RowCreateSignal(Signal):
"""
Called before an instance is created, with the class as the
- sender. Called with the arguments ``(varargs, kwargs,
- post_funcs)``. Both ``kwargs`` and ``varargs`` may be usefully
- modified (``varargs`` is converted from a tuple to a list before
- calling). ``post_funcs`` is a list of callbacks, intended to have
+ sender. Called with the arguments ``(kwargs, post_funcs)``.
+ There may be a ``connection`` argument. ``kwargs``may be usefully
+ modified. ``post_funcs`` is a list of callbacks, intended to have
functions appended to it, and are called with the arguments
``(new_instance)``.
Note: this is not called when an instance is created from an
- existing database row. (@@: Show the name be RowCreateEvent, or
- RowInsertEvent?)
+ existing database row.
"""
# @@: An event for getting a row? But for each row, when doing a
# select? For .sync, .syncUpdate, .expire?
-class InstanceDestroyEvent(Event):
+class RowDestroySignal(Signal):
"""
Called before an instance is deleted. Sender is the instance's
class. Arguments are ``(instance)``. You cannot cancel the delete,
@@ -52,14 +77,13 @@
delete, but also cause an uncaught exception if not expected).
Note: this is not called when an instance is destroyed through
- garbage collection (@@: Should this be called RowDestroyEvent or
- RowDeleteEvent?)
+ garbage collection.
@@: Should this allow ``instance`` to be a primary key, so that a
row can be deleted without first fetching it?
"""
-class InstanceUpdateEvent(Event):
+class RowUpdateSignal(Signal):
"""
Called when an instance is updated through a call to ``.set()``.
The arguments are ``(instance, kwargs)``. ``kwargs`` can be
@@ -68,45 +92,57 @@
@@: Should this also catch single-column updates? Should this
only be run before updates go to the server? Should this be
- called RowUpdateEvent?
+ called RowUpdateSignal?
"""
-class AddColumnEvent(Event):
+class AddColumnSignal(Signal):
"""
Called when a column is added to a class, with arguments ``(cls,
- column_name, column_definition)``. This is called *after* the
- column has been added, and is called for each column after class
- creation.
+ connection, column_name, column_definition, changeSchema,
+ post_funcs)``. This is called *after* the column has been added,
+ and is called for each column after class creation.
+
+ post_funcs are called with ``(cls, so_column_obj)``
"""
-class DeleteColumnEvent(Event):
+class DeleteColumnSignal(Signal):
"""
Called when a column is removed from a class, with the arguments
- ``(cls, column_name, column_definition)``. Like
- ``AddColumnEvent`` this is called after the action has been
+ ``(cls, connection, column_name, so_column_obj, post_funcs)``.
+ Like ``AddColumnSignal`` this is called after the action has been
performed, and is called for subclassing (when a column is
implicitly removed by setting it to ``None``).
+
+ post_funcs are called with ``(cls, so_column_obj)``
"""
-# @@: Events for indexes and joins? These are mostly event consumers,
+# @@: Signals for indexes and joins? These are mostly event consumers,
# though.
-class CreateTableEvent(Event):
+class CreateTableSignal(Signal):
"""
Called when a table is created. If ``ifNotExists==True`` and the
table exists, this event is not called.
- Called with ``(cls, connection, post_funcs)``. ``post_funcs``
+ Called with ``(cls, connection, extra_sql, post_funcs)``.
+ ``extra_sql`` is a list (which can be appended to) of extra SQL
+ statements to be run after the table is created. ``post_funcs``
functions are called with ``(cls, connection)`` after the table
- has been created.
+ has been created. Those functions are *not* called simply when
+ constructing the SQL.
"""
-class DropTableEvent(Event):
+class DropTableSignal(Signal):
"""
Called when a table is dropped. If ``ifExists==True`` and the
table doesn't exist, this event is not called.
- Called with ``(cls, connection, post_funcs)``. ``post_funcs``
- functions are called with ``(cls, connection)`` after the table
- has been dropped.
+ Called with ``(cls, connection, extra_sql, post_funcs)``.
+ ``post_funcs`` functions are called with ``(cls, connection)``
+ after the table has been dropped.
"""
+
+__all__ = ['listen', 'send']
+for name, value in globals().items():
+ if isinstance(value, type) and issubclass(value, Signal):
+ __all__.append('value')
|