# HG changeset patch # User Aurelien Campeas # Date 1293025235 -3600 # Node ID 2bbc1010494cb8197f34903e30bad48652911327 # Parent 7351806cd485e9e493ad5bd43588fc41aeb21a28 [doc/book] fix/update a bit the hooks chapter diff -r 7351806cd485 -r 2bbc1010494c doc/book/en/devrepo/repo/hooks.rst --- a/doc/book/en/devrepo/repo/hooks.rst Tue Dec 21 21:17:50 2010 +0100 +++ b/doc/book/en/devrepo/repo/hooks.rst Wed Dec 22 14:40:35 2010 +0100 @@ -131,7 +131,7 @@ In the above example, our hook will instantiate an operation each time the hook is called, i.e. each time the `subsidiary_of` relation is set. There is an alternative method to schedule an operation from a hook, using the -:func:`set_operation` function. +:func:`get_instance` class method. .. sourcecode:: python @@ -143,13 +143,12 @@ __select__ = Hook.__select__ & match_rtype('subsidiary_of') def __call__(self): - set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto, - CheckSubsidiaryCycleOp) + CheckSubsidiaryCycleOp.get_instance(self._cw).add_data(self.eidto) class CheckSubsidiaryCycleOp(Operation): def precommit_event(self): - for eid in self.session.transaction_data['subsidiary_cycle_detection']: + for eid in self.get_data(): check_cycle(self.session, eid, self.rtype) @@ -169,30 +168,31 @@ Reminder ~~~~~~~~ -Never, ever use the `entity.foo = 42` notation to update an entity. It will not -work.To updating an entity attribute or relation, uses :meth:`set_attributes` and +You should never use the `entity.foo = 42` notation to update an +entity. It will not do what you expect (updating the +database). Instead, use the :meth:`set_attributes` and :meth:`set_relations` methods. How to choose between a before and an after event ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -'before_*' hooks give you access to the old attribute (or relation) -values. You can also hi-jack actually edited stuff in the case of entity -modification. Needing one of this will definitly guide your choice. +`before_*` hooks give you access to the old attribute (or relation) +values. You can also intercept and update edited values in the case of +entity modification before they reach the database. Else the question is: should I need to do things before or after the actual -modification. If the answer is "it doesn't matter", use an 'after' event. +modification ? If the answer is "it doesn't matter", use an 'after' event. Validation Errors ~~~~~~~~~~~~~~~~~ -When a hook is responsible to maintain the consistency of the data model detect -an error, it must use a specific exception named +When a hook which is responsible to maintain the consistency of the +data model detects an error, it must use a specific exception named :exc:`~cubicweb.ValidationError`. Raising anything but a (subclass of) -:exc:`~cubicweb.ValidationError` is a programming error. Raising a it entails -aborting the current transaction. +:exc:`~cubicweb.ValidationError` is a programming error. Raising it +entails aborting the current transaction. This exception is used to convey enough information up to the user interface. Hence its constructor is different from the default Exception @@ -204,6 +204,11 @@ an end-user facing message (hence properly translated) relating the problem. +.. sourcecode:: python + + raise ValidationError(earth.eid, {'sea_level': self._cw._('too high'), + 'temperature': self._cw._('too hot')}) + Checking for object created/deleted in the current transaction ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -228,7 +233,8 @@ Relations which are defined in the schema as `inlined` (see :ref:`RelationType` for details) are inserted in the database at the same time as entity attributes. -This may have some side effect, for instance when creating entity and setting an -inlined relation in the same rql query, when 'before_add_relation' for that -relation will be run, the relation will already exist in the database (it's -usually not the case). + +This may have some side effect, for instance when creating an entity +and setting an inlined relation in the same rql query, then at +`before_add_relation` time, the relation will already exist in the +database (it is otherwise not the case). diff -r 7351806cd485 -r 2bbc1010494c server/hook.py --- a/server/hook.py Tue Dec 21 21:17:50 2010 +0100 +++ b/server/hook.py Wed Dec 22 14:40:35 2010 +0100 @@ -105,17 +105,17 @@ When called for one of these events, hook will have an `entity` attribute containing the entity instance. -* 'before_add_entity', 'before_update_entity': +* `before_add_entity`, `before_update_entity`: - on those events, you can check what attributes of the entity are modified in `entity.cw_edited` (by definition the database is not yet updated in a before event) - - you are allowed to further modify the entity before database operations, - using the dictionary notation. By doing this, you'll avoid the need for a - whole new rql query processing, the only difference is that the underlying - backend query (eg usually sql) will contains the additional data. For - example: + - you are allowed to further modify the entity before database + operations, using the dictionary notation on `cw_edited`. By doing + this, you'll avoid the need for a whole new rql query processing, + the only difference is that the underlying backend query (eg + usually sql) will contains the additional data. For example: .. sourcecode:: python @@ -136,17 +136,17 @@ Similarly, removing an attribute from `cw_edited` will cancel its modification. - - on 'before_update_entity' event, you can access to old and new values in + - on `before_update_entity` event, you can access to old and new values in this hook, by using `entity.cw_edited.oldnewvalue(attr)` -* 'after_add_entity', 'after_update_entity' +* `after_add_entity`, `after_update_entity` - on those events, you can still check what attributes of the entity are modified in `entity.cw_edited` but you can't get anymore the old value, nor modify it. -* 'before_delete_entity', 'after_delete_entity' +* `before_delete_entity`, `after_delete_entity` - on those events, the entity has no `cw_edited` set. @@ -158,11 +158,11 @@ attributes containing respectivly the eid of the subject entity, the relation type and the eid of the object entity. -* 'before_add_relation', 'before_delete_relation' +* `before_add_relation`, `before_delete_relation` - on those events, you can still get original relation by issuing a rql query -* 'after_add_relation', 'after_delete_relation' +* `after_add_relation`, `after_delete_relation` This is an occasion to remind us that relations support the add / delete operation, but no update. @@ -171,8 +171,8 @@ Non data events ~~~~~~~~~~~~~~~ -Hooks called on server start/maintenance/stop event (eg 'server_startup', -'server_maintenance', 'server_shutdown') have a `repo` attribute, but *their +Hooks called on server start/maintenance/stop event (eg `server_startup`, +`server_maintenance`, `server_shutdown`) have a `repo` attribute, but *their `_cw` attribute is None*. The `server_startup` is called on regular startup, while `server_maintenance` is called on cubicweb-ctl upgrade or shell commands. `server_shutdown` is called anyway. @@ -180,7 +180,7 @@ Hooks called on backup/restore event (eg 'server_backup', 'server_restore') have a `repo` and a `timestamp` attributes, but *their `_cw` attribute is None*. -Hooks called on session event (eg 'session_open', 'session_close') have no +Hooks called on session event (eg `session_open`, `session_close`) have no special attribute. @@ -400,7 +400,7 @@ .. Note:: - Do not forget to extend the base class selectors as in :: + Do not forget to extend the base class selectors as in: .. sourcecode:: python @@ -609,7 +609,7 @@ An operation is triggered on connections pool events related to commit / rollback transations. Possible events are: - * 'precommit': + * `precommit`: the transaction is being prepared for commit. You can freely do any heavy computation, raise an exception if the commit can't go. or even add some @@ -618,13 +618,13 @@ instance), you'll have to support the 'revertprecommit' event to revert things by yourself - * 'revertprecommit': + * `revertprecommit`: if an operation failed while being pre-commited, this event is triggered for all operations which had their 'precommit' event already fired to let them revert things (including the operation which made the commit fail) - * 'rollback': + * `rollback`: the transaction has been either rollbacked either: @@ -632,7 +632,7 @@ * a 'precommit' event failed, in which case all operations are rollbacked once 'revertprecommit'' has been called - * 'postcommit': + * `postcommit`: the transaction is over. All the ORM entities accessed by the earlier transaction are invalid. If you need to work on the database, you need to @@ -642,7 +642,7 @@ For an operation to support an event, one has to implement the `_event` method with no arguments. - Notice order of operations may be important, and is controlled according to + The order of operations may be important, and is controlled according to the insert_index's method output (whose implementation vary according to the base hook class used). """ @@ -736,6 +736,7 @@ `value`, since handling operations becomes costly on massive data import. Usage looks like: + .. sourcecode:: python class MyEntityHook(Hook):