backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 17 Jun 2011 18:53:33 +0200
changeset 7536 29961a416faa
parent 7534 d58a9d96aad8 (current diff)
parent 7535 d5725a89dac9 (diff)
child 7539 7cd9fc2adcac
backport stable
devtools/__init__.py
hooks/syncsources.py
server/__init__.py
server/session.py
server/sources/native.py
server/sources/pyrorql.py
server/test/unittest_querier.py
server/test/unittest_undo.py
web/component.py
web/request.py
web/views/basecontrollers.py
web/views/cwsources.py
--- a/devtools/__init__.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/devtools/__init__.py	Fri Jun 17 18:53:33 2011 +0200
@@ -528,11 +528,19 @@
         return get_db_helper('postgres')
 
     @property
-    @cached
     def dbcnx(self):
-        from cubicweb.server.serverctl import _db_sys_cnx
-        return  _db_sys_cnx(self.system_source, 'CREATE DATABASE and / or USER',
-                            interactive=False)
+        try:
+            return self._cnx
+        except AttributeError:
+            from cubicweb.server.serverctl import _db_sys_cnx
+            try:
+                self._cnx = _db_sys_cnx(
+                    self.system_source, 'CREATE DATABASE and / or USER',
+                    interactive=False)
+                return self._cnx
+            except Exception:
+                self._cnx = None
+                raise
 
     @property
     @cached
@@ -570,17 +578,19 @@
                 cnx.close()
             init_repository(self.config, interactive=False)
         except:
-            self.dbcnx.rollback()
+            if self.dbcnx is not None:
+                self.dbcnx.rollback()
             print >> sys.stderr, 'building', self.dbname, 'failed'
             #self._drop(self.dbname)
             raise
 
     def helper_clear_cache(self):
-        self.dbcnx.commit()
-        self.dbcnx.close()
-        clear_cache(self, 'dbcnx')
+        if self.dbcnx is not None:
+            self.dbcnx.commit()
+            self.dbcnx.close()
+            del self._cnx
+            clear_cache(self, 'cursor')
         clear_cache(self, 'helper')
-        clear_cache(self, 'cursor')
 
     def __del__(self):
         self.helper_clear_cache()
--- a/doc/book/en/admin/config.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/admin/config.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -209,6 +209,8 @@
 Pyro configuration
 ------------------
 
+Pyro name server
+~~~~~~~~~~~~~~~~
 If you want to use Pyro to access your instance remotely, or to have multi-source
 or distributed configuration, it is required to have a Pyro name server running
 on your network. By default it is detected by a broadcast request, but you can
@@ -216,9 +218,13 @@
 
 To do so, you need to :
 
+* be sure to have installed it (see :ref:`InstallDependencies`)
+
 * launch the pyro name server with `pyro-nsd start` before starting cubicweb
 
 * under debian, edit the file :file:`/etc/default/pyro-nsd` so that the name
   server pyro will be launched automatically when the machine fire up
 
+Note that you can use the pyro server without a running pyro nameserver.
+Refer to `pyro-ns-host` server configuration option for details.
 
--- a/doc/book/en/admin/index.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/admin/index.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -14,6 +14,8 @@
    :numbered:
 
    setup
+   setup-windows
+   config
    cubicweb-ctl
    create-instance
    instance-config
--- a/doc/book/en/annexes/faq.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/annexes/faq.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -185,12 +185,6 @@
 recommended also for other attribute types). By default it expects to generate
 HTML, so it deals with rich text formating, xml escaping...
 
-How do I translate an msg id defined (and translated) in another cube ?
------------------------------------------------------------------------
-
-You should put these translations in the `i18n/static-messages.pot`
-file of your own cube.
-
 How to update a database after a schema modification ?
 ------------------------------------------------------
 
--- a/doc/book/en/annexes/rql/debugging.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/annexes/rql/debugging.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -8,26 +8,15 @@
 Available levels
 ~~~~~~~~~~~~~~~~
 
-:DBG_NONE:
-    no debug information (current mode)
-
-:DBG_RQL:
-    rql execution information
-
-:DBG_SQL:
-    executed sql
+Server debugging flags. They may be combined using binary operators.
 
-:DBG_REPO:
-    repository events
-
-:DBG_MS:
-    multi-sources
-
-:DBG_MORE:
-    more verbosity
-
-:DBG_ALL:
-    all level enabled
+.. autodata:: cubicweb.server.DBG_NONE
+.. autodata:: cubicweb.server.DBG_RQL
+.. autodata:: cubicweb.server.DBG_SQL
+.. autodata:: cubicweb.server.DBG_REPO
+.. autodata:: cubicweb.server.DBG_MS
+.. autodata:: cubicweb.server.DBG_MORE
+.. autodata:: cubicweb.server.DBG_ALL
 
 
 Enable verbose output
@@ -40,6 +29,8 @@
     from cubicweb import server
     server.set_debug(server.DBG_RQL|server.DBG_SQL|server.DBG_ALL)
 
+.. autofunction:: cubicweb.server.set_debug
+
 
 Detect largest RQL queries
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -50,7 +41,5 @@
 API
 ~~~
 
-.. autofunction:: cubicweb.server.set_debug
-
 .. autoclass:: cubicweb.server.debugged
 
--- a/doc/book/en/annexes/rql/intro.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/annexes/rql/intro.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -159,3 +159,4 @@
 .. _Datalog: http://en.wikipedia.org/wiki/Datalog
 .. _intensional: http://en.wikipedia.org/wiki/Intensional_definition
 .. _extensional: http://en.wikipedia.org/wiki/Extension_(predicate_logic)
+
--- a/doc/book/en/annexes/rql/language.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/annexes/rql/language.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -152,6 +152,10 @@
 
 - Aggregate Functions: COUNT, MIN, MAX, AVG, SUM, GROUP_CONCAT
 
+.. note::
+   Aggregate functions will return None if there is no result row.
+
+
 Having
 ```````
 
--- a/doc/book/en/devrepo/vreg.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devrepo/vreg.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -79,7 +79,7 @@
 .. autoclass:: cubicweb.selectors.has_add_permission
 .. autoclass:: cubicweb.selectors.has_mimetype
 .. autoclass:: cubicweb.selectors.is_in_state
-.. autoclass:: cubicweb.selectors.on_fire_transition
+.. autofunction:: cubicweb.selectors.on_fire_transition
 .. autoclass:: cubicweb.selectors.implements
 
 
--- a/doc/book/en/devweb/controllers.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/controllers.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -16,11 +16,11 @@
 `Browsing`:
 
 * the View controller is associated with most browsing actions within a
-  CubicWeb application: it always instantiates a :ref:`the_main_template` and
-  lets the ResultSet/Views dispatch system build up the whole content; it
-  handles :exc:`ObjectNotFound` and :exc:`NoSelectableObject` errors that may
-  bubble up to its entry point, in an end-user-friendly way (but other
-  programming errors will slip through)
+  CubicWeb application: it always instantiates a
+  :ref:`the_main_template_layout` and lets the ResultSet/Views dispatch system
+  build up the whole content; it handles :exc:`ObjectNotFound` and
+  :exc:`NoSelectableObject` errors that may bubble up to its entry point, in an
+  end-user-friendly way (but other programming errors will slip through)
 
 * the JSon controller (same module) provides services for Ajax calls,
   typically using JSON as a serialization format for input, and
--- a/doc/book/en/devweb/httpcaching.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/httpcaching.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -1,3 +1,21 @@
 HTTP cache management
----------------------
-XXX feedme
\ No newline at end of file
+=====================
+
+.. automodule:: cubicweb.web.httpcache
+
+Cache policies
+--------------
+.. autoclass:: cubicweb.web.httpcache.NoHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.MaxAgeHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.EtagHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.EntityHTTPCacheManager
+
+Exception
+---------
+.. autoexception:: cubicweb.web.httpcache.NoEtag
+
+Helper functions
+----------------
+.. autofunction:: cubicweb.web.httpcache.set_http_cache_headers
+
+.. NOT YET AVAILABLE IN STABLE autofunction:: cubicweb.web.httpcache.lastmodified
--- a/doc/book/en/devweb/index.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/index.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -17,5 +17,6 @@
    edition/index
    facets
    internationalization
-..   property
+   property
    httpcaching
+   resource
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/resource.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -0,0 +1,16 @@
+Locate resources
+----------------
+
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_resource
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_doc_file
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_all_files
+
+Static files handling
+---------------------
+
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_directory
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_exists
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_open
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_add
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_del
+
--- a/doc/book/en/devweb/views/idownloadable.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/views/idownloadable.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -1,5 +1,23 @@
-The 'download' view
--------------------
+The 'download' views
+====================
+
+.. automodule:: cubicweb.web.views.idownloadable
+
+Components
+----------
+
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadBox
 
-(:mod:`cubicweb.web.views.idownloadable`)
+Download views
+--------------
 
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadView
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadLinkView
+.. autoclass:: cubicweb.web.views.idownloadable.IDownloadablePrimaryView
+.. autoclass:: cubicweb.web.views.idownloadable.IDownloadableLineView
+
+Embedded views
+--------------
+
+.. autoclass:: cubicweb.web.views.idownloadable.ImageView
+.. autoclass:: cubicweb.web.views.idownloadable.EHTMLView
--- a/doc/book/en/devweb/views/index.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/views/index.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -25,7 +25,7 @@
 
    urlpublish
    breadcrumbs
-..   wdoc
+   idownloadable
+   wdoc
 ..   embedding
-..   idownloadable
 
--- a/doc/book/en/devweb/views/wdoc.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/devweb/views/wdoc.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -1,9 +1,17 @@
 .. -*- coding: utf-8 -*-
 
 Online documentation system
----------------------------
+===========================
+
+.. automodule:: cubicweb.web.views.wdoc
 
-(:mod:`cubicweb.web.views.wdoc`)
+Help views
+----------
+.. autoclass:: cubicweb.web.views.wdoc.InlineHelpView
+.. autoclass:: cubicweb.web.views.wdoc.ChangeLogView
 
-XXX  describe the on-line documentation system
-
+Actions
+-------
+.. autoclass:: cubicweb.web.views.wdoc.HelpAction
+.. autoclass:: cubicweb.web.views.wdoc.ChangeLogAction
+.. autoclass:: cubicweb.web.views.wdoc.AboutAction
--- a/doc/book/en/tutorials/advanced/part05_ui-advanced.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/tutorials/advanced/part05_ui-advanced.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -3,6 +3,8 @@
 
 We'll now see how to benefit from features introduced in 3.9 and 3.10 releases of CubicWeb
 
+.. _uiprops:
+
 Step 1: tired of the default look?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
--- a/doc/book/en/tutorials/tools/windmill.rst	Fri Jun 17 18:50:13 2011 +0200
+++ b/doc/book/en/tutorials/tools/windmill.rst	Fri Jun 17 18:53:33 2011 +0200
@@ -23,23 +23,21 @@
 environment, take a look to the `virtualenv
 <http://pypi.python.org/pypi/virtualenv>`_ project as well)::
 
-    pip install windmill
-    curl -O http://github.com/windmill/windmill/tarball/master
+    $ pip install windmill
+    $ curl -O http://github.com/windmill/windmill/tarball/master
 
 However, the Windmill project doesn't release frequently. Our recommandation is
-to used the last snapshot of the Git repository:
-
-.. sourcecode:: bash
+to used the last snapshot of the Git repository::
 
-    git clone git://github.com/windmill/windmill.git HEAD
-    cd windmill
-    python setup.py develop
+    $ git clone git://github.com/windmill/windmill.git HEAD
+    $ cd windmill
+    $ python setup.py develop
 
 Install instructions are `available <http://wiki.github.com/windmill/windmill/installing>`_.
 
 Be sure to have the windmill module in your PYTHONPATH afterwards::
 
-    python -c "import windmill"
+    $ python -c "import windmill"
 
 X dummy
 -------
@@ -60,9 +58,9 @@
 
     *From: http://www.x.org/wiki/XorgTesting*
 
-Then, you can run the X server with the following command :
+Then, you can run the X server with the following command ::
 
-    /usr/bin/X11/Xvfb :1 -ac -screen 0 1280x1024x8 -fbdir /tmp
+    $ /usr/bin/X11/Xvfb :1 -ac -screen 0 1280x1024x8 -fbdir /tmp
 
 
 Windmill usage
@@ -82,13 +80,15 @@
 
 If you are using firefox as client, consider the "firebug" option.
 
-If you have a running instance, you can refine the test by the *loadtest* windmill option:
+If you have a running instance, you can refine the test by the *loadtest* windmill option::
 
-    windmill -m firebug loadtest=<test_file.py> <instance url>
+    $ windmill -m firebug loadtest=<test_file.py> <instance url>
 
-Or use the internal windmill shell to explore available commands:
+Or use the internal windmill shell to explore available commands::
 
-    windmill -m firebug shell <instance url>
+    $ windmill -m firebug shell <instance url>
+
+And enter python commands:
 
 .. sourcecode:: python
 
@@ -125,7 +125,7 @@
 
 To run your test series::
 
-    % pytest test/test_windmill.py
+    $ pytest test/test_windmill.py
 
 By default, CubicWeb will use **firefox** as the default browser and will try
 to run test instance server on localhost. In the general case, You've no need
@@ -144,6 +144,8 @@
 
 Examples:
 
+.. sourcecode:: python
+
     browser = 'firefox'
     test_dir = osp.join(__file__, 'windmill')
     edit_test = False
@@ -162,7 +164,7 @@
 
 For instance, CubicWeb framework windmill tests can be manually run by::
 
-    % pytest web/test/test_windmill.py
+    $ pytest web/test/test_windmill.py
 
 Edit your tests
 ---------------
@@ -172,7 +174,7 @@
 But if you are using `pytest` as test runner, use the `-i` option directly.
 The test series will be loaded and you can run assertions step-by-step::
 
-    % pytest -i test/test_windmill.py
+    $ pytest -i test/test_windmill.py
 
 In this case, the `firebug` extension will be loaded automatically for you.
 
--- a/hooks/syncsources.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/hooks/syncsources.py	Fri Jun 17 18:53:33 2011 +0200
@@ -136,7 +136,7 @@
                 if not session.deleted_in_transaction(schemacfg.eid):
                     source.add_schema_config(schemacfg, checkonly=checkonly)
             elif session.deleted_in_transaction(schemacfg.eid):
-                source.delete_schema_config(schemacfg, checkonly=checkonly)
+                source.del_schema_config(schemacfg, checkonly=checkonly)
             else:
                 source.update_schema_config(schemacfg, checkonly=checkonly)
 
@@ -164,5 +164,4 @@
     def __call__(self):
         SourceMappingChangedOp.get_instance(self._cw).add_data(
             (self._cw.entity_from_eid(self.eidfrom),
-             self._cw.entity_from_eid(self.eidto)) )
-
+             self._cw.entity_from_eid(self.eidto).repo_source) )
--- a/rqlrewrite.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/rqlrewrite.py	Fri Jun 17 18:53:33 2011 +0200
@@ -20,12 +20,16 @@
 
 This is used for instance for read security checking in the repository.
 """
+from __future__ import with_statement
 
 __docformat__ = "restructuredtext en"
 
 from rql import nodes as n, stmts, TypeResolverException
 from rql.utils import common_parent
+
 from yams import BadSchemaDefinition
+
+from logilab.common import tempattr
 from logilab.common.graph import has_path
 
 from cubicweb import Unauthorized, typed_eid
@@ -156,7 +160,6 @@
         self.exists_snippet = {}
         self.pending_keys = []
         self.existingvars = existingvars
-        self._insert_scope = None
         # we have to annotate the rqlst before inserting snippets, even though
         # we'll have to redo it latter
         self.annotate(select)
@@ -193,6 +196,7 @@
         self.varmap = varmap
         self.revvarmap = {}
         self.varinfos = []
+        self._insert_scope = None
         for i, (selectvar, snippetvar) in enumerate(varmap):
             assert snippetvar in 'SOX'
             self.revvarmap[snippetvar] = (selectvar, i)
@@ -229,7 +233,7 @@
                 except Unsupported:
                     continue
                 inserted = True
-                if new is not None:
+                if new is not None and self._insert_scope is None:
                     self.exists_snippet[rqlexpr] = new
                 parent = parent or new
             else:
@@ -263,11 +267,12 @@
                         insert_scope = common_parent(scope, insert_scope)
             else:
                 insert_scope = self._insert_scope
-            if any(vi.get('stinfo', {}).get('optrelations') for vi in self.varinfos):
+            if self._insert_scope is None and any(vi.get('stinfo', {}).get('optrelations')
+                                                  for vi in self.varinfos):
                 assert parent is None
                 self._insert_scope = self.snippet_subquery(varmap, new)
                 self.insert_pending()
-                self._insert_scope = None
+                #self._insert_scope = None
                 return
             if not isinstance(new, (n.Exists, n.Not)):
                 new = n.Exists(new)
@@ -283,15 +288,14 @@
                 except Unsupported:
                     # some solutions have been lost, can't apply this rql expr
                     if parent is None:
-                        self.select.remove_node(new, undefine=True)
+                        self.current_statement().remove_node(new, undefine=True)
                     else:
                         parent.parent.replace(or_, or_.children[0])
                         self._cleanup_inserted(new)
                     raise
                 else:
-                    self._insert_scope = new
-                    self.insert_pending()
-                    self._insert_scope = None
+                    with tempattr(self, '_insert_scope', new):
+                        self.insert_pending()
             return new
         self.insert_pending()
 
@@ -303,6 +307,7 @@
         recomputed, we have to insert snippet defined for <action> of entity
         types taken by X
         """
+        stmt = self.current_statement()
         while self.pending_keys:
             key, action = self.pending_keys.pop()
             try:
@@ -313,12 +318,12 @@
                 except KeyError:
                     # variable isn't used anywhere else, we can't insert security
                     raise Unauthorized()
-            ptypes = self.select.defined_vars[varname].stinfo['possibletypes']
+            ptypes = stmt.defined_vars[varname].stinfo['possibletypes']
             if len(ptypes) > 1:
                 # XXX dunno how to handle this
                 self.session.error(
                     'cant check security of %s, ambigous type for %s in %s',
-                    self.select, varname, key[0]) # key[0] == the rql expression
+                    stmt, varname, key[0]) # key[0] == the rql expression
                 raise Unauthorized()
             etype = iter(ptypes).next()
             eschema = self.schema.eschema(etype)
@@ -499,17 +504,18 @@
         self.rewritten[key] = term.name
 
     def _get_varname_or_term(self, vname):
+        stmt = self.current_statement()
         if vname == 'U':
+            stmt = self.select
             if self.u_varname is None:
-                select = self.select
-                self.u_varname = select.allocate_varname()
+                self.u_varname = stmt.allocate_varname()
                 # generate an identifier for the substitution
-                argname = select.allocate_varname()
+                argname = stmt.allocate_varname()
                 while argname in self.kwargs:
-                    argname = select.allocate_varname()
+                    argname = stmt.allocate_varname()
                 # insert "U eid %(u)s"
-                select.add_constant_restriction(
-                    select.get_variable(self.u_varname),
+                stmt.add_constant_restriction(
+                    stmt.get_variable(self.u_varname),
                     'eid', unicode(argname), 'Substitute')
                 self.kwargs[argname] = self.session.user.eid
             return self.u_varname
@@ -517,7 +523,7 @@
         try:
             return self.rewritten[key]
         except KeyError:
-            self.rewritten[key] = newvname = self.select.allocate_varname()
+            self.rewritten[key] = newvname = stmt.allocate_varname()
             return newvname
 
     # visitor methods ##########################################################
@@ -625,14 +631,20 @@
 
     def visit_variableref(self, node):
         """get the sql name for a variable reference"""
+        stmt = self.current_statement()
         if node.name in self.revvarmap:
             selectvar, index = self.revvarmap[node.name]
             vi = self.varinfos[index]
             if vi.get('const') is not None:
                 return n.Constant(vi['const'], 'Int') # XXX gae
-            return n.VariableRef(self.select.get_variable(selectvar))
+            return n.VariableRef(stmt.get_variable(selectvar))
         vname_or_term = self._get_varname_or_term(node.name)
         if isinstance(vname_or_term, basestring):
-            return n.VariableRef(self.select.get_variable(vname_or_term))
+            return n.VariableRef(stmt.get_variable(vname_or_term))
         # shared term
-        return vname_or_term.copy(self.select)
+        return vname_or_term.copy(stmt)
+
+    def current_statement(self):
+        if self._insert_scope is None:
+            return self.select
+        return self._insert_scope.stmt
--- a/selectors.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/selectors.py	Fri Jun 17 18:53:33 2011 +0200
@@ -1252,15 +1252,18 @@
 
 def on_fire_transition(etype, tr_name, from_state_name=None):
     """Return 1 when entity of the type `etype` is going through transition of
-    the name `tr_name`. If `from_state_name` is specified, this selector will
-    also check the incoming state.
+    the name `tr_name`.
+    
+    If `from_state_name` is specified, this selector will also check the
+    incoming state.
 
     You should use this selector on 'after_add_entity' hook, since it's actually
     looking for addition of `TrInfo` entities. Hence in the hook, `self.entity`
     will reference the matching `TrInfo` entity, allowing to get all the
     transition details (including the entity to which is applied the transition
-    but also its original state, transition, destination state, user...).  See
-    :class:`cubicweb.entities.wfobjs.TrInfo` for more information.
+    but also its original state, transition, destination state, user...).
+    
+    See :class:`cubicweb.entities.wfobjs.TrInfo` for more information.
     """
     def match_etype_and_transition(trinfo):
         # take care trinfo.transition is None when calling change_state
--- a/server/__init__.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/__init__.py	Fri Jun 17 18:53:33 2011 +0200
@@ -18,7 +18,7 @@
 """Server subcube of cubicweb : defines objects used only on the server
 (repository) side
 
-This module contains functions to initialize a new repository.
+The server module contains functions to initialize a new repository.
 """
 
 from __future__ import with_statement
@@ -39,14 +39,23 @@
 # server-side debugging #########################################################
 
 # server debugging flags. They may be combined using binary operators.
-DBG_NONE = 0  # no debug information
-DBG_RQL = 1   # rql execution information
-DBG_SQL = 2   # executed sql
-DBG_REPO = 4  # repository events
-DBG_MS = 8    # multi-sources
-DBG_MORE = 16 # more verbosity
-DBG_ALL = 1 + 2 + 4 + 8 + 16
-# current debug mode
+
+#:no debug information
+DBG_NONE = 0  #: no debug information
+#: rql execution information
+DBG_RQL  = 1
+#: executed sql
+DBG_SQL  = 2
+#: repository events
+DBG_REPO = 4
+#: multi-sources
+DBG_MS   = 8
+#: more verbosity
+DBG_MORE = 16
+#: all level enabled
+DBG_ALL  = DBG_RQL + DBG_SQL + DBG_REPO + DBG_MS + DBG_MORE
+
+#: current debug mode
 DEBUG = 0
 
 def set_debug(debugmode):
--- a/server/mssteps.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/mssteps.py	Fri Jun 17 18:53:33 2011 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -22,6 +22,7 @@
 * each step has is own members (this is not necessarily bad, but a bit messy
   for now)
 """
+from __future__ import with_statement
 
 __docformat__ = "restructuredtext en"
 
@@ -32,25 +33,30 @@
 
 AGGR_TRANSFORMS = {'COUNT':'SUM', 'MIN':'MIN', 'MAX':'MAX', 'SUM': 'SUM'}
 
-def remove_clauses(union, keepgroup):
-    clauses = []
-    for select in union.children:
-        if keepgroup:
-            having, orderby = select.having, select.orderby
-            select.having, select.orderby = (), ()
-            clauses.append( (having, orderby) )
-        else:
-            groupby, having, orderby = select.groupby, select.having, select.orderby
-            select.groupby, select.having, select.orderby = (), (), ()
-            clauses.append( (groupby, having, orderby) )
-    return clauses
+class remove_and_restore_clauses(object):
+    def __init__(self, union, keepgroup):
+        self.union = union
+        self.keepgroup = keepgroup
+        self.clauses = None
 
-def restore_clauses(union, keepgroup, clauses):
-    for i, select in enumerate(union.children):
-        if keepgroup:
-            select.having, select.orderby = clauses[i]
-        else:
-            select.groupby, select.having, select.orderby = clauses[i]
+    def __enter__(self):
+        self.clauses = clauses = []
+        for select in self.union.children:
+            if self.keepgroup:
+                having, orderby = select.having, select.orderby
+                select.having, select.orderby = (), ()
+                clauses.append( (having, orderby) )
+            else:
+                groupby, having, orderby = select.groupby, select.having, select.orderby
+                select.groupby, select.having, select.orderby = (), (), ()
+                clauses.append( (groupby, having, orderby) )
+
+    def __exit__(self, exctype, exc, traceback):
+        for i, select in enumerate(self.union.children):
+            if self.keepgroup:
+                select.having, select.orderby = self.clauses[i]
+            else:
+                select.groupby, select.having, select.orderby = self.clauses[i]
 
 
 class FetchStep(OneFetchStep):
@@ -94,29 +100,24 @@
         plan = self.plan
         plan.create_temp_table(self.table)
         union = self.union
-        # XXX 2.5 use "with"
-        clauses = remove_clauses(union, self.keepgroup)
-        for source in self.sources:
-            source.flying_insert(self.table, plan.session, union, plan.args,
-                                 self.inputmap)
-        restore_clauses(union, self.keepgroup, clauses)
+        with remove_and_restore_clauses(union, self.keepgroup):
+            for source in self.sources:
+                source.flying_insert(self.table, plan.session, union, plan.args,
+                                     self.inputmap)
 
     def mytest_repr(self):
         """return a representation of this step suitable for test"""
-        clauses = remove_clauses(self.union, self.keepgroup)
-        try:
-            inputmap = varmap_test_repr(self.inputmap, self.plan.tablesinorder)
-            outputmap = varmap_test_repr(self.outputmap, self.plan.tablesinorder)
-        except AttributeError:
-            inputmap = self.inputmap
-            outputmap = self.outputmap
-        try:
+        with remove_and_restore_clauses(self.union, self.keepgroup):
+            try:
+                inputmap = varmap_test_repr(self.inputmap, self.plan.tablesinorder)
+                outputmap = varmap_test_repr(self.outputmap, self.plan.tablesinorder)
+            except AttributeError:
+                inputmap = self.inputmap
+                outputmap = self.outputmap
             return (self.__class__.__name__,
-                sorted((r.as_string(kwargs=self.plan.args), r.solutions)
-                       for r in self.union.children),
-                sorted(self.sources), inputmap, outputmap)
-        finally:
-            restore_clauses(self.union, self.keepgroup, clauses)
+                    sorted((r.as_string(kwargs=self.plan.args), r.solutions)
+                           for r in self.union.children),
+                    sorted(self.sources), inputmap, outputmap)
 
 
 class AggrStep(LimitOffsetMixIn, Step):
--- a/server/rqlannotation.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/rqlannotation.py	Fri Jun 17 18:53:33 2011 +0200
@@ -271,9 +271,17 @@
         return has_text_query
 
     def is_ambiguous(self, var):
-        # ignore has_text relation
-        if len([rel for rel in var.stinfo['relations']
-                if rel.scope is var.scope and rel.r_type == 'has_text']) == 1:
+        # ignore has_text relation when we know it will be used as principal.
+        # This is expected by the rql2sql generator which will use the `entities`
+        # table to filter out by type if necessary, This optimisation is very
+        # interesting in multi-sources cases, as it may avoid a costly query
+        # on sources to get all entities of a given type to achieve this, while
+        # we have all the necessary information.
+        root = var.stmt.root # Union node
+        # rel.scope -> Select or Exists node, so add .parent to get Union from
+        # Select node
+        rels = [rel for rel in var.stinfo['relations'] if rel.scope.parent is root]
+        if len(rels) == 1 and rels[0].r_type == 'has_text':
             return False
         try:
             data = var.stmt._deamb_data
--- a/server/sources/native.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/sources/native.py	Fri Jun 17 18:53:33 2011 +0200
@@ -165,6 +165,15 @@
 class UndoException(Exception):
     """something went wrong during undoing"""
 
+    def __unicode__(self):
+        """Called by the unicode builtin; should return a Unicode object
+
+        Type of UndoException message must be `unicode` by design in CubicWeb.
+
+        .. warning::
+            This method is not available in python2.5"""
+        assert isinstance(self.message, unicode)
+        return self.message
 
 def _undo_check_relation_target(tentity, rdef, role):
     """check linked entity has not been redirected for this relation"""
--- a/server/sources/pyrorql.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/sources/pyrorql.py	Fri Jun 17 18:53:33 2011 +0200
@@ -234,6 +234,7 @@
         etype, dexturi, dextid = cnx.describe(extid)
         if dexturi == 'system' or not (
             dexturi in self.repo.sources_by_uri or self._skip_externals):
+            assert etype in self.support_entities, etype
             eid = self.repo.extid2eid(self, str(extid), etype, session)
             if eid > 0:
                 return eid, True
--- a/server/test/unittest_querier.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/test/unittest_querier.py	Fri Jun 17 18:53:33 2011 +0200
@@ -1460,5 +1460,14 @@
         rset = self.execute('Any X,Y WHERE X nom XD, Y nom XD, X eid Z, Y eid > Z')
         self.assertEqual(rset.rows, [[peid1, peid2]])
 
+    def test_nonregr_has_text_ambiguity_1(self):
+        peid = self.execute("INSERT CWUser X: X login 'bidule', X upassword 'bidule', X in_group G WHERE G name 'users'")[0][0]
+        aeid = self.execute("INSERT Affaire X: X ref 'bidule'")[0][0]
+        self.commit()
+        rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule"')
+        self.assertEqual(rset.rows, [[peid]])
+        rset = self.execute('Any X WHERE X is CWUser, X has_text "bidule", X in_state S, S name SN')
+        self.assertEqual(rset.rows, [[peid]])
+
 if __name__ == '__main__':
     unittest_main()
--- a/server/test/unittest_rqlannotation.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/test/unittest_rqlannotation.py	Fri Jun 17 18:53:33 2011 +0200
@@ -18,13 +18,16 @@
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
 """unit tests for modules cubicweb.server.rqlannotation"""
 
-from cubicweb.devtools import init_test_database
+from cubicweb.devtools import TestServerConfiguration, get_test_db_handler
 from cubicweb.devtools.repotest import BaseQuerierTC
 
 
 def setUpModule(*args):
+    handler = get_test_db_handler(TestServerConfiguration(
+        'data2', apphome=SQLGenAnnotatorTC.datadir))
+    handler.build_db_cache()
     global repo, cnx
-    repo, cnx = init_test_database(apphome=SQLGenAnnotatorTC.datadir)
+    repo, cnx = handler.get_repo_and_cnx()
 
 def tearDownModule(*args):
     global repo, cnx
@@ -330,6 +333,13 @@
         self.assertEqual(rqlst.defined_vars['N']._q_invariant, False)
         self.assertEqual(rqlst.defined_vars['F']._q_invariant, True)
 
+    def test_nonregr_ambiguity_2(self):
+        rqlst = self._prepare('Any S,SN WHERE X has_text "tot", X in_state S, S name SN, X is CWUser')
+        # X use has_text but should not be invariant as ambiguous, and has_text
+        # may not be its principal
+        self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
+        self.assertEqual(rqlst.defined_vars['S']._q_invariant, False)
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/server/test/unittest_undo.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/server/test/unittest_undo.py	Fri Jun 17 18:53:33 2011 +0200
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
@@ -21,9 +22,11 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.transaction import *
 
+from cubicweb.server.sources.native import UndoException
+
+
 class UndoableTransactionTC(CubicWebTC):
 
-        
     def setup_database(self):
         req = self.request()
         self.session.undo_actions = set('CUDAR')
@@ -285,6 +288,15 @@
 
     # test implicit 'replacement' of an inlined relation
 
+
+class UndoExceptionInUnicode(CubicWebTC):
+
+    # problem occurs in string manipulation for python < 2.6
+    def test___unicode__method(self):
+        u = UndoException(u"voilĂ ")
+        self.assertIsInstance(unicode(u), unicode)
+
+
 if __name__ == '__main__':
     from logilab.common.testlib import unittest_main
     unittest_main()
--- a/test/unittest_rqlrewrite.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/test/unittest_rqlrewrite.py	Fri Jun 17 18:53:33 2011 +0200
@@ -82,8 +82,9 @@
     for vref in node.iget_nodes(nodes.VariableRef):
         vrefmap.setdefault(vref.name, set()).add(vref)
     for var in node.defined_vars.itervalues():
-        assert not (var.stinfo['references'] ^ vrefmap[var.name])
-        assert (var.stinfo['references'])
+        assert var.stinfo['references']
+        assert not (var.stinfo['references'] ^ vrefmap[var.name]), (node.as_string(), var.stinfo['references'], vrefmap[var.name])
+
 
 class RQLRewriteTC(TestCase):
     """a faire:
@@ -95,10 +96,10 @@
     """
 
     def test_base_var(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+        constraint = ('X in_state S, U in_group G, P require_state S,'
                            'P name "read", P require_group G')
         rqlst = parse('Card C')
-        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
         self.failUnlessEqual(rqlst.as_string(),
                              u"Any C WHERE C is Card, B eid %(D)s, "
                              "EXISTS(C in_state A, B in_group E, F require_state A, "
@@ -130,27 +131,31 @@
                              "E in_state D, D name 'subscribed'), D is State, E is CWUser)")
 
     def test_simplified_rqlst(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+        constraint = ('X in_state S, U in_group G, P require_state S,'
                            'P name "read", P require_group G')
         rqlst = parse('Any 2') # this is the simplified rql st for Any X WHERE X eid 12
-        rewrite(rqlst, {('2', 'X'): (card_constraint,)}, {})
+        rewrite(rqlst, {('2', 'X'): (constraint,)}, {})
         self.failUnlessEqual(rqlst.as_string(),
                              u"Any 2 WHERE B eid %(C)s, "
                              "EXISTS(2 in_state A, B in_group D, E require_state A, "
                              "E name 'read', E require_group D, A is State, D is CWGroup, E is CWPermission)")
 
-    def test_optional_var_base(self):
-        card_constraint = ('X in_state S, U in_group G, P require_state S,'
+    def test_optional_var_base_1(self):
+        constraint = ('X in_state S, U in_group G, P require_state S,'
                            'P name "read", P require_group G')
         rqlst = parse('Any A,C WHERE A documented_by C?')
-        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
         self.failUnlessEqual(rqlst.as_string(),
                              "Any A,C WHERE A documented_by C?, A is Affaire "
                              "WITH C BEING "
                              "(Any C WHERE EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', "
                              "G require_group F), D eid %(A)s, C is Card)")
+
+    def test_optional_var_base_2(self):
+        constraint = ('X in_state S, U in_group G, P require_state S,'
+                           'P name "read", P require_group G')
         rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
-        rewrite(rqlst, {('C', 'X'): (card_constraint,)}, {})
+        rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
         self.failUnlessEqual(rqlst.as_string(),
                              "Any A,C,T WHERE A documented_by C?, A is Affaire "
                              "WITH C,T BEING "
@@ -158,6 +163,19 @@
                              "G require_state B, G name 'read', G require_group F), "
                              "D eid %(A)s, C is Card)")
 
+    def test_optional_var_base_3(self):
+        constraint1 = ('X in_state S, U in_group G, P require_state S,'
+                       'P name "read", P require_group G')
+        constraint2 = 'X in_state S, S name "public"'
+        rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
+        rewrite(rqlst, {('C', 'X'): (constraint1, constraint2)}, {})
+        self.failUnlessEqual(rqlst.as_string(),
+                             "Any A,C,T WHERE A documented_by C?, A is Affaire "
+                             "WITH C,T BEING (Any C,T WHERE C title T, "
+                             "EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', G require_group F), "
+                             "D eid %(A)s, C is Card, "
+                             "EXISTS(C in_state E, E name 'public'))")
+
     def test_optional_var_inlined(self):
         c1 = ('X require_permission P')
         c2 = ('X inlined_card O, O require_permission P')
--- a/web/component.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/component.py	Fri Jun 17 18:53:33 2011 +0200
@@ -440,7 +440,6 @@
         params.pop('view', None)
         params.pop('entity', None)
         form = params.pop('formparams', {})
-        form['pageid'] = self._cw.pageid
         if entity.has_eid():
             eid = entity.eid
         else:
--- a/web/data/cubicweb.calendar.js	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/data/cubicweb.calendar.js	Fri Jun 17 18:53:33 2011 +0200
@@ -15,9 +15,9 @@
 /**
  * .. class:: Calendar
  *
- * Calendar (graphical) widget
+ *   Calendar (graphical) widget
  *
- * public methods are :
+ *   public methods are :
  *
  *   __init__ :
  *    :attr:`containerId`: the DOM node's ID where the calendar will be displayed
@@ -74,7 +74,7 @@
     /**
      * .. function:: Calendar._uppercaseFirst(s)
      *
-     * utility function (the only use for now is inside the calendar)
+     *    utility function (the only use for now is inside the calendar)
      */
     this._uppercaseFirst = function(s) {
         return s.charAt(0).toUpperCase();
@@ -83,7 +83,7 @@
     /**
      * .. function:: Calendar._domForRows(rows)
      *
-     * accepts the cells data and builds the corresponding TR nodes
+     *    accepts the cells data and builds the corresponding TR nodes
      *
      * * `rows`, a list of list of couples (daynum, cssprops)
      */
@@ -98,7 +98,7 @@
     /**
      * .. function:: Calendar._headdisplay(row)
      *
-     * builds the calendar headers
+     *    builds the calendar headers
      */
     this._headdisplay = function(row) {
         if (_CAL_HEADER) {
@@ -224,13 +224,17 @@
     this.hide); // connect(inputId, 'onfocus', this, 'hide');
 };
 
-// keep track of each calendar created
+/**
+ * .. data:: Calendar.REGISTRY
+ *
+ *     keep track of each calendar created
+ */
 Calendar.REGISTRY = {};
 
 /**
  * .. function:: toggleCalendar(containerId, inputId, year, month)
  *
- * popup / hide calendar associated to `containerId`
+ *    popup / hide calendar associated to `containerId`
  */
 function toggleCalendar(containerId, inputId, year, month) {
     var cal = Calendar.REGISTRY[containerId];
@@ -251,7 +255,7 @@
 /**
  * .. function:: toggleNextMonth(containerId)
  *
- * ask for next month to calendar displayed in `containerId`
+ *    ask for next month to calendar displayed in `containerId`
  */
 function toggleNextMonth(containerId) {
     var cal = Calendar.REGISTRY[containerId];
@@ -261,7 +265,7 @@
 /**
  * .. function:: togglePreviousMonth(containerId)
  *
- * ask for previous month to calendar displayed in `containerId`
+ *    ask for previous month to calendar displayed in `containerId`
  */
 function togglePreviousMonth(containerId) {
     var cal = Calendar.REGISTRY[containerId];
@@ -271,7 +275,7 @@
 /**
  * .. function:: dateSelected(cell, containerId)
  *
- * Callback called when the user clicked on a cell in the popup calendar
+ *    callback called when the user clicked on a cell in the popup calendar
  */
 function dateSelected(cell, containerId) {
     var cal = Calendar.REGISTRY[containerId];
--- a/web/data/cubicweb.edition.js	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/data/cubicweb.edition.js	Fri Jun 17 18:53:33 2011 +0200
@@ -583,6 +583,7 @@
  * around the corresponding input fields.
  */
 function validateForm(formid, action, onsuccess, onfailure) {
+    freezeFormButtons(formid);
     try {
         var zipped = cw.utils.formContents(formid);
         var args = ajaxFuncArgs('validate_form', null, action, zipped[0], zipped[1]);
--- a/web/data/cubicweb.timeline-bundle.js	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/data/cubicweb.timeline-bundle.js	Fri Jun 17 18:53:33 2011 +0200
@@ -1,10 +1,15 @@
+/**
+ *  This file contains timeline utilities
+ *  :organization: Logilab
+ */
+
 var SimileAjax_urlPrefix = baseuri() + 'data/';
 var Timeline_urlPrefix = baseuri() + 'data/';
 
 /*
  *  Simile Ajax API
  *
- *  Include this file in your HTML file as follows:
+ *  Include this file in your HTML file as follows::
  *
  *    <script src="http://simile.mit.edu/ajax/api/simile-ajax-api.js" type="text/javascript"></script>
  *
--- a/web/request.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/request.py	Fri Jun 17 18:53:33 2011 +0200
@@ -624,8 +624,10 @@
         extraparams.setdefault('fname', 'view')
         url = self.build_url('json', **extraparams)
         cbname = build_cb_uid(url[:50])
+        # think to propagate pageid. XXX see https://www.cubicweb.org/ticket/1753121
         jscode = 'function %s() { $("#%s").%s; }' % (
-            cbname, nodeid, js.loadxhtml(url, None, 'get', replacemode))
+            cbname, nodeid, js.loadxhtml(url, {'pageid': self.pageid},
+                                         'get', replacemode))
         self.html_headers.add_post_inline_script(jscode)
         return "javascript: %s()" % cbname
 
--- a/web/test/unittest_web.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/test/unittest_web.py	Fri Jun 17 18:53:33 2011 +0200
@@ -38,7 +38,7 @@
         self.failUnless(url.endswith('()'))
         cbname = url.split()[1][:-2]
         self.assertMultiLineEqual(
-            'function %s() { $("#foo").loadxhtml("http://testing.fr/cubicweb/json?%s",null,"get","replace"); }' % (cbname, qs),
+            'function %s() { $("#foo").loadxhtml("http://testing.fr/cubicweb/json?%s",{"pageid": "%s"},"get","replace"); }' % (cbname, qs, req.pageid),
             req.html_headers.post_inlined_scripts[0])
 
 if __name__ == '__main__':
--- a/web/views/basecontrollers.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/views/basecontrollers.py	Fri Jun 17 18:53:33 2011 +0200
@@ -604,7 +604,7 @@
         if not errors:
             self.redirect()
         return self._cw._('some errors occurred:') + self._cw.view(
-            'pyvalist', pyvalue=errors)
+            'pyvallist', pyvalue=errors)
 
     def redirect(self):
         req = self._cw
--- a/web/views/cwsources.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/views/cwsources.py	Fri Jun 17 18:53:33 2011 +0200
@@ -27,7 +27,7 @@
 from cubicweb.selectors import is_instance, score_entity, match_user_groups
 from cubicweb.view import EntityView, StartupView
 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
-from cubicweb.web import uicfg
+from cubicweb.web import uicfg, formwidgets as wdgs
 from cubicweb.web.views import tabs, actions
 
 
@@ -35,6 +35,12 @@
 _abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_schema', '*'), False)
 _abaa.tag_object_of(('CWSourceSchemaConfig', 'cw_for_source', '*'), False)
 
+_afs = uicfg.autoform_section
+_afs.tag_attribute(('CWSource', 'synchronizing'), 'main', 'hidden')
+_afs.tag_object_of(('*', 'cw_for_source', 'CWSource'), 'main', 'hidden')
+_affk = uicfg.autoform_field_kwargs
+_affk.tag_attribute(('CWSource', 'parser'), {'widget': wdgs.TextInput})
+
 # source primary views #########################################################
 
 _pvs = uicfg.primaryview_section
--- a/web/views/idownloadable.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/views/idownloadable.py	Fri Jun 17 18:53:33 2011 +0200
@@ -15,8 +15,10 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""Specific views for entities adapting to IDownloadable"""
-
+"""
+Specific views for entities adapting to IDownloadable
+=====================================================
+"""
 __docformat__ = "restructuredtext en"
 _ = unicode
 
@@ -50,6 +52,7 @@
 
 
 class DownloadBox(component.EntityCtxComponent):
+    """add download box"""
     __regid__ = 'download_box'    # no download box for images
     __select__ = (component.EntityCtxComponent.__select__ &
                   adaptable('IDownloadable') & ~has_mimetype('image/'))
@@ -71,7 +74,9 @@
 
 
 class DownloadView(EntityView):
-    """this view is replacing the deprecated 'download' controller and allow
+    """download view
+    
+    this view is replacing the deprecated 'download' controller and allow
     downloading of entities providing the necessary interface
     """
     __regid__ = 'download'
@@ -199,6 +204,7 @@
 
 
 class ImageView(AbstractEmbeddedView):
+    """image embedded view"""
     __regid__ = 'image'
     __select__ = has_mimetype('image/')
 
@@ -207,6 +213,7 @@
 
 
 class EHTMLView(AbstractEmbeddedView):
+    """html embedded view"""
     __regid__ = 'ehtml'
     __select__ = has_mimetype('text/html')
 
--- a/web/views/rdf.py	Fri Jun 17 18:50:13 2011 +0200
+++ b/web/views/rdf.py	Fri Jun 17 18:53:33 2011 +0200
@@ -59,6 +59,9 @@
                 self.entity2graph(graph, entity)
             self.w(graph.serialize().decode('utf-8'))
 
+        def entity_call(self, entity):
+            self.call()
+
         def entity2graph(self, graph, entity):
             cwuri = URIRef(entity.cwuri)
             add = graph.add