backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 03 Nov 2011 15:28:30 +0100
changeset 8049 a48301a44b50
parent 8046 bdd555df7a91 (current diff)
parent 8048 10a0f73d834d (diff)
child 8050 0f3a54c37b05
backport stable
cwconfig.py
rset.py
server/migractions.py
test/unittest_rset.py
--- a/cwconfig.py	Thu Nov 03 11:18:37 2011 +0100
+++ b/cwconfig.py	Thu Nov 03 15:28:30 2011 +0100
@@ -22,6 +22,9 @@
 Resource mode
 -------------
 
+Standard resource mode
+```````````````````````````
+
 A resource *mode* is a predefined set of settings for various resources
 directories, such as cubes, instances, etc. to ease development with the
 framework. There are two running modes with *CubicWeb*:
@@ -30,7 +33,7 @@
   usually requiring root access):
 
   - instances are stored in :file:`<INSTALL_PREFIX>/etc/cubicweb.d`
-  - temporary files (such as pid file) in :file:`/var/run/cubicweb`
+  - temporary files (such as pid file) in :file:`<INSTALL_PREFIX>/var/run/cubicweb`
 
   where `<INSTALL_PREFIX>` is the detected installation prefix ('/usr/local' for
   instance).
@@ -42,6 +45,25 @@
 
 
 
+
+.. _CubicwebWithinVirtualEnv:
+
+Within virtual environment
+```````````````````````````
+
+If you are not administrator of you machine or if you need to play with some
+specific version of |cubicweb| you can use `virtualenv`_ a tool to create
+isolated Python environments.  Since version 3.9 |cubicweb| is **`virtualenv`
+friendly** and won't write any file outside the virtualenv directory.
+
+- instances are stored in :file:`<VIRTUAL_ENV>/etc/cubicweb.d`
+- temporary files (such as pid file) in :file:`<VIRTUAL_ENV>/var/run/cubicweb`
+
+.. _`virtualenv`: http://pypi.python.org/pypi/virtualenv
+
+Custom resource location
+````````````````````````````````
+
 Notice that each resource path may be explicitly set using an environment
 variable if the default doesn't suit your needs. Here are the default resource
 directories that are affected according to mode:
@@ -49,8 +71,8 @@
 * **system**: ::
 
         CW_INSTANCES_DIR = <INSTALL_PREFIX>/etc/cubicweb.d/
-        CW_INSTANCES_DATA_DIR = /var/lib/cubicweb/instances/
-        CW_RUNTIME_DIR = /var/run/cubicweb/
+        CW_INSTANCES_DATA_DIR = <INSTALL_PREFIX>/var/lib/cubicweb/instances/
+        CW_RUNTIME_DIR = <INSTALL_PREFIX>/var/run/cubicweb/
 
 * **user**: ::
 
@@ -60,10 +82,13 @@
 
 Cubes search path is also affected, see the :ref:`Cube` section.
 
-By default, the mode automatically set to `user` if a :file:`.hg` directory is found
-in the cubicweb package, else it's set to `system`. You can force this by setting
-the :envvar:`CW_MODE` environment variable to either `user` or `system` so you can
-easily:
+Setting Cubicweb Mode
+`````````````````````
+
+By default, the mode is set to 'system' for standard installation. The mode is
+set to 'user' if `cubicweb is used from a mercurial repository`_. You can force
+this by setting the :envvar:`CW_MODE` environment variable to either 'user' or
+'system' so you can easily:
 
 * use system wide installation but user specific instances and all, without root
   privileges on the system (`export CW_MODE=user`)
@@ -74,7 +99,15 @@
 If you've a doubt about the mode you're currently running, check the first line
 outputed by the :command:`cubicweb-ctl list` command.
 
-Also, if cubicweb is a mercurial checkout located in `<CW_SOFTWARE_ROOT>`:
+.. _`cubicweb is used from a mercurial repository`: CubicwebDevelopmentMod_
+
+.. _CubicwebDevelopmentMod:
+
+Development Mode
+`````````````````````
+If :file:`.hg` directory is found into the cubicweb package, there are specific resource rules.
+
+`<CW_SOFTWARE_ROOT>` is the mercurial checkout of cubicweb:
 
 * main cubes directory is `<CW_SOFTWARE_ROOT>/../cubes`. You can specify
   another one with :envvar:`CW_INSTANCES_DIR` environment variable or simply
--- a/rset.py	Thu Nov 03 11:18:37 2011 +0100
+++ b/rset.py	Thu Nov 03 15:28:30 2011 +0100
@@ -351,7 +351,8 @@
                     if offset <= entity.cw_row < stop:
                         entity.cw_row = entity.cw_row - offset
                     else:
-                        self.req.drop_entity_cache(entity.eid)
+                        entity.cw_rset = entity.as_rset()
+                        entity.cw_row = entity.cw_col = 0
         else:
             rset = self.copy(rows, descr)
             if not offset:
--- a/server/migractions.py	Thu Nov 03 11:18:37 2011 +0100
+++ b/server/migractions.py	Thu Nov 03 15:28:30 2011 +0100
@@ -392,7 +392,7 @@
         if cube is None:
             directory = osp.join(CW_SOFTWARE_ROOT, 'schemas')
         else:
-            directory = self.config.cube_dir(cube)
+            directory = osp.join(self.config.cube_dir(cube), 'schema')
         sql_scripts = glob(osp.join(directory, '*.%s.sql' % driver))
         for fpath in sql_scripts:
             print '-> installing', fpath
--- a/test/unittest_rset.py	Thu Nov 03 11:18:37 2011 +0100
+++ b/test/unittest_rset.py	Thu Nov 03 15:28:30 2011 +0100
@@ -107,7 +107,7 @@
         self.compare_urls(req.build_url('view', _restpath=''), baseurl)
 
 
-    def test_resultset_build(self):
+    def test_build(self):
         """test basic build of a ResultSet"""
         rs = ResultSet([1,2,3], 'CWGroup X', description=['CWGroup', 'CWGroup', 'CWGroup'])
         self.assertEqual(rs.rowcount, 3)
@@ -115,7 +115,7 @@
         self.assertEqual(rs.description, ['CWGroup', 'CWGroup', 'CWGroup'])
 
 
-    def test_resultset_limit(self):
+    def test_limit(self):
         rs = ResultSet([[12000, 'adim'], [13000, 'syt'], [14000, 'nico']],
                        'Any U,L where U is CWUser, U login L',
                        description=[['CWUser', 'String']] * 3)
@@ -128,8 +128,30 @@
         self.assertEqual(rs.limit(2, offset=2).rows, [[14000, 'nico']])
         self.assertEqual(rs.limit(2, offset=3).rows, [])
 
+    def test_limit_2(self):
+        req = self.request()
+        # drop user from cache for the sake of this test
+        req.drop_entity_cache(req.user.eid)
+        rs = req.execute('Any E,U WHERE E is CWEType, E created_by U')
+        # get entity on row 9. This will fill its created_by relation cache,
+        # with cwuser on row 9 as well
+        e1 = rs.get_entity(9, 0)
+        # get entity on row 10. This will fill its created_by relation cache,
+        # with cwuser built on row 9
+        e2 = rs.get_entity(10, 0)
+        # limit result set from row 10
+        rs.limit(1, 10, inplace=True)
+        # get back eid
+        e = rs.get_entity(0, 0)
+        self.assertTrue(e2 is e)
+        # rs.limit has properly removed cwuser for request cache, but it's
+        # still referenced by e/e2 relation cache
+        u = e.created_by[0]
+        # now ensure this doesn't trigger IndexError because cwuser.cw_row is 9
+        # while now rset has only one row
+        u.cw_rset[u.cw_row]
 
-    def test_resultset_filter(self):
+    def test_filter(self):
         rs = ResultSet([[12000, 'adim'], [13000, 'syt'], [14000, 'nico']],
                        'Any U,L where U is CWUser, U login L',
                        description=[['CWUser', 'String']] * 3)
@@ -142,7 +164,7 @@
         self.assertEqual(len(rs2), 2)
         self.assertEqual([login for _, login in rs2], ['adim', 'syt'])
 
-    def test_resultset_transform(self):
+    def test_transform(self):
         rs = ResultSet([[12, 'adim'], [13, 'syt'], [14, 'nico']],
                        'Any U,L where U is CWUser, U login L',
                        description=[['CWUser', 'String']] * 3)
@@ -154,7 +176,7 @@
         self.assertEqual(len(rs2), 3)
         self.assertEqual(list(rs2), [['adim'],['syt'],['nico']])
 
-    def test_resultset_sort(self):
+    def test_sort(self):
         rs = ResultSet([[12000, 'adim'], [13000, 'syt'], [14000, 'nico']],
                        'Any U,L where U is CWUser, U login L',
                        description=[['CWUser', 'String']] * 3)
@@ -179,7 +201,7 @@
         # make sure rs is unchanged
         self.assertEqual([login for _, login in rs], ['adim', 'syt', 'nico'])
 
-    def test_resultset_split(self):
+    def test_split(self):
         rs = ResultSet([[12000, 'adim', u'Adim chez les pinguins'],
                         [12000, 'adim', u'Jardiner facile'],
                         [13000, 'syt',  u'Le carrelage en 42 leçons'],
--- a/web/data/cubicweb.fckcwconfig-full.js	Thu Nov 03 11:18:37 2011 +0100
+++ b/web/data/cubicweb.fckcwconfig-full.js	Thu Nov 03 15:28:30 2011 +0100
@@ -29,6 +29,9 @@
 FCKConfig.ContextMenu = ['Generic','Link','Anchor','Image','BulletedList','NumberedList','Table'] ;
 
 FCKConfig.LinkUpload = false ;
+FCKConfig.LinkBrowser = false ;
 FCKConfig.ImageUpload = false ;
+FCKConfig.ImageBrowser = false ;
 FCKConfig.FlashUpload = false ;
+FCKConfig.FlashBrowser = false ;
 
--- a/web/data/cubicweb.fckcwconfig.js	Thu Nov 03 11:18:37 2011 +0100
+++ b/web/data/cubicweb.fckcwconfig.js	Thu Nov 03 15:28:30 2011 +0100
@@ -11,5 +11,8 @@
 FCKConfig.ContextMenu = ['Generic','Link','Anchor','Image','BulletedList','NumberedList','Table'] ;
 
 FCKConfig.LinkUpload = false ;
+FCKConfig.LinkBrowser = false ;
 FCKConfig.ImageUpload = false ;
+FCKConfig.ImageBrowser = false ;
 FCKConfig.FlashUpload = false ;
+FCKConfig.FlashBrowser = false ;
--- a/web/views/basecomponents.py	Thu Nov 03 11:18:37 2011 +0100
+++ b/web/views/basecomponents.py	Thu Nov 03 15:28:30 2011 +0100
@@ -50,25 +50,22 @@
     visible = False
 
     def call(self, view=None):
+        req = self._cw
         if hasattr(view, 'filter_box_context_info'):
             rset = view.filter_box_context_info()[0]
         else:
             rset = self.cw_rset
         # display multilines query as one line
-        rql = rset is not None and rset.printable_rql(encoded=False) or self._cw.form.get('rql', '')
+        rql = rset is not None and rset.printable_rql(encoded=False) or req.form.get('rql', '')
         rql = rql.replace(u"\n", u" ")
-        req = self._cw
-        self.w(u'''<div id="rqlinput" class="%s">
-          <form action="%s">
-<fieldset>
+        self.w(u'''<div id="rqlinput" class="%s"><form action="%s"><fieldset>
 <input type="text" id="rql" name="rql" value="%s"  title="%s" tabindex="%s" accesskey="q" class="searchField" />
-</fieldset>
 ''' % (not self.cw_propval('visible') and 'hidden' or '',
-       self._cw.build_url('view'), xml_escape(rql), req._('full text or RQL query'), req.next_tabindex()))
-        if self._cw.search_state[0] != 'normal':
+       req.build_url('view'), xml_escape(rql), req._('full text or RQL query'), req.next_tabindex()))
+        if req.search_state[0] != 'normal':
             self.w(u'<input type="hidden" name="__mode" value="%s"/>'
                    % ':'.join(req.search_state[1]))
-        self.w(u'</form></div>')
+        self.w(u'</fieldset></form></div>')