backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 13 Apr 2011 11:03:42 +0200
changeset 7216 6053bf221fa9
parent 7211 cacff15f847d (current diff)
parent 7215 2da7f3ec4e6f (diff)
child 7218 78622865b6c1
backport stable
entity.py
--- a/dataimport.py	Tue Apr 12 14:09:39 2011 +0200
+++ b/dataimport.py	Wed Apr 13 11:03:42 2011 +0200
@@ -581,7 +581,7 @@
                     self.tell(pformat(sorted(error[1])))
 
     def _print_stats(self):
-        nberrors = sum(len(err[1]) for err in self.errors.values())
+        nberrors = sum(len(err) for err in self.errors.values())
         self.tell('\nImport statistics: %i entities, %i types, %i relations and %i errors'
                   % (self.store.nb_inserted_entities,
                      self.store.nb_inserted_types,
--- a/devtools/__init__.py	Tue Apr 12 14:09:39 2011 +0200
+++ b/devtools/__init__.py	Wed Apr 13 11:03:42 2011 +0200
@@ -232,6 +232,11 @@
 
 # XXX merge with BaseApptestConfiguration ?
 class ApptestConfiguration(BaseApptestConfiguration):
+    # `skip_db_create_and_restore` controls wether or not the test database
+    # should be created / backuped / restored. If set to True, those
+    # steps are completely skipped, the database is used as is and is
+    # considered initialized
+    skip_db_create_and_restore = False
 
     def __init__(self, appid, apphome=None,
                  log_threshold=logging.CRITICAL, sourcefile=None):
@@ -260,6 +265,7 @@
               self.view('foaf', rset)
 
     """
+    skip_db_create_and_restore = True
     read_instance_schema = True # read schema from database
 
 
@@ -477,13 +483,38 @@
             cnx.close()
         self.backup_database(test_db_id)
 
+
+class NoCreateDropDatabaseHandler(TestDataBaseHandler):
+    """This handler is used if config.skip_db_create_and_restore is True
+
+    This is typically the case with RealDBConfig. In that case,
+    we explicitely want to skip init / backup / restore phases.
+
+    This handler redefines the three corresponding methods and delegates
+    to original handler for any other method / attribute
+    """
+
+    def __init__(self, base_handler):
+        self.base_handler = base_handler
+
+    # override init / backup / restore methods
+    def init_test_database(self):
+        pass
+
+    def backup_database(self, db_id):
+        pass
+
+    def restore_database(self, db_id):
+        pass
+
+    # delegate to original handler in all other cases
+    def __getattr__(self, attrname):
+        return getattr(self.base_handler, attrname)
+
+
 ### postgres test database handling ############################################
 
 class PostgresTestDataBaseHandler(TestDataBaseHandler):
-
-    # XXX
-    # XXX PostgresTestDataBaseHandler Have not been tested at all.
-    # XXX
     DRIVER = 'postgres'
 
     @property
@@ -504,14 +535,19 @@
     def cursor(self):
         return self.dbcnx.cursor()
 
+    def process_cache_entry(self, directory, dbname, db_id, entry):
+        backup_name = self._backup_name(db_id)
+        if backup_name in self.helper.list_databases(self.cursor):
+            return backup_name
+        return None
+
     def init_test_database(self):
-        """initialize a fresh postgresql databse used for testing purpose"""
+        """initialize a fresh postgresql database used for testing purpose"""
         from cubicweb.server import init_repository
         from cubicweb.server.serverctl import system_source_cnx, createdb
         # connect on the dbms system base to create our base
         try:
             self._drop(self.dbname)
-
             createdb(self.helper, self.system_source, self.dbcnx, self.cursor)
             self.dbcnx.commit()
             cnx = system_source_cnx(self.system_source, special_privs='LANGUAGE C',
@@ -555,7 +591,6 @@
 
     def _drop(self, db_name):
         if db_name in self.helper.list_databases(self.cursor):
-            #print 'dropping overwritted database:', db_name
             self.cursor.execute('DROP DATABASE %s' % db_name)
             self.dbcnx.commit()
 
@@ -567,7 +602,6 @@
         orig_name = self.system_source['db-name']
         try:
             backup_name = self._backup_name(db_id)
-            #print 'storing postgres backup as', backup_name
             self._drop(backup_name)
             self.system_source['db-name'] = backup_name
             createdb(self.helper, self.system_source, self.dbcnx, self.cursor, template=orig_name)
@@ -581,7 +615,6 @@
         """Actual restore of the current database.
 
         Use the value tostored in db_cache as input """
-        #print 'restoring postgrest backup from', backup_coordinates
         self._drop(self.dbname)
         createdb(self.helper, self.system_source, self.dbcnx, self.cursor,
                  template=backup_coordinates)
@@ -647,7 +680,6 @@
         # remove database file if it exists ?
         dbfile = self.absolute_dbfile()
         self._cleanup_database(dbfile)
-        #print 'resto from', backup_coordinates
         shutil.copy(backup_coordinates, dbfile)
         repo = self.get_repo()
 
@@ -754,6 +786,8 @@
     handlerkls = HANDLERS.get(driver, None)
     if handlerkls is not None:
         handler = handlerkls(config)
+        if config.skip_db_create_and_restore:
+            handler = NoCreateDropDatabaseHandler(handler)
         HCACHE.set(config, handler)
         return handler
     else:
--- a/entities/test/unittest_base.py	Tue Apr 12 14:09:39 2011 +0200
+++ b/entities/test/unittest_base.py	Wed Apr 13 11:03:42 2011 +0200
@@ -111,6 +111,11 @@
                                'creation_date', 'modification_date', 'cwuri', 'eid'))
                           )
 
+    def test_cw_instantiate_object_relation(self):
+        """ a weird non regression test """
+        e = self.execute('CWUser U WHERE U login "member"').get_entity(0, 0)
+        self.request().create_entity('CWGroup', name=u'logilab', reverse_in_group=e)
+
 
 class InterfaceTC(CubicWebTC):
 
--- a/entity.py	Tue Apr 12 14:09:39 2011 +0200
+++ b/entity.py	Wed Apr 13 11:03:42 2011 +0200
@@ -254,10 +254,12 @@
 
         >>> companycls = vreg['etypes'].etype_class(('Company')
         >>> personcls = vreg['etypes'].etype_class(('Person')
-        >>> c = companycls.cw_instantiate(req.execute, name=u'Logilab')
-        >>> personcls.cw_instantiate(req.execute, firstname=u'John', lastname=u'Doe',
-        ...                          works_for=c)
+        >>> c = companycls.cw_instantiate(session.execute, name=u'Logilab')
+        >>> p = personcls.cw_instantiate(session.execute, firstname=u'John', lastname=u'Doe',
+        ...                              works_for=c)
 
+        You can also set relation where the entity has 'object' role by
+        prefixing the relation by 'reverse_'.
         """
         rql = 'INSERT %s X' % cls.__regid__
         relations = []
@@ -276,14 +278,14 @@
                 if len(value) == 1:
                     value = iter(value).next()
                 else:
+                    # prepare IN clause
                     del kwargs[attr]
                     pending_relations.append( (attr, value) )
                     continue
             if hasattr(value, 'eid'): # non final relation
                 rvar = attr.upper()
-                # XXX safer detection of object relation
-                if attr.startswith('reverse_'):
-                    relations.append('%s %s X' % (rvar, attr[len('reverse_'):]))
+                if role == 'object':
+                    relations.append('%s %s X' % (rvar, attr))
                 else:
                     relations.append('X %s %s' % (attr, rvar))
                 restriction = '%s eid %%(%s)s' % (rvar, attr)
@@ -941,9 +943,7 @@
         assert kwargs
         assert self.cw_is_saved(), "should not call set_attributes while entity "\
                "hasn't been saved yet"
-        relations = []
-        for key in kwargs:
-            relations.append('X %s %%(%s)s' % (key, key))
+        relations = ['X %s %%(%s)s' % (key, key) for key in kwargs]
         # and now update the database
         kwargs['x'] = self.eid
         self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations),
--- a/web/views/schema.py	Tue Apr 12 14:09:39 2011 +0200
+++ b/web/views/schema.py	Wed Apr 13 11:03:42 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.
@@ -543,8 +543,9 @@
     pass
 
 class CWSchemaDotPropsHandler(s2d.SchemaDotPropsHandler):
-    def __init__(self, visitor):
+    def __init__(self, visitor, cw):
         self.visitor = visitor
+        self.cw = cw
         self.nextcolor = cycle( ('#ff7700', '#000000',
                                  '#ebbc69', '#888888') ).next
         self.colors = {}
@@ -558,7 +559,7 @@
         label.append(r'\l}') # trailing \l ensure alignement of the last one
         return {'label' : ''.join(label), 'shape' : "record",
                 'fontname' : "Courier", 'style' : "filled",
-                'href': 'cwetype/%s' % eschema.type,
+                'href': self.cw.build_url('cwetype/%s' % eschema.type),
                 'fontsize': '10px'
                 }
 
@@ -569,11 +570,12 @@
             kwargs = {'label': rschema.type,
                       'color': '#887788', 'style': 'dashed',
                       'dir': 'both', 'arrowhead': 'normal', 'arrowtail': 'normal',
-                      'fontsize': '10px', 'href': 'cwrtype/%s' % rschema.type}
+                      'fontsize': '10px',
+                      'href': self.cw.build_url('cwrtype/%s' % rschema.type)}
         else:
             kwargs = {'label': rschema.type,
                       'color' : 'black',  'style' : 'filled', 'fontsize': '10px',
-                      'href': 'cwrtype/%s' % rschema.type}
+                      'href': self.cw.build_url('cwrtype/%s' % rschema.type)}
             rdef = rschema.rdef(subjnode, objnode)
             composite = rdef.composite
             if rdef.composite == 'subject':
@@ -625,7 +627,7 @@
             alt = self._cw._('graphical representation of %(appid)s data model')
         alt %= {'rtype': rtype, 'etype': etype,
                 'appid': self._cw.vreg.config.appid}
-        prophdlr = CWSchemaDotPropsHandler(visitor)
+        prophdlr = CWSchemaDotPropsHandler(visitor, self._cw)
         generator = GraphGenerator(DotBackend('schema', 'BT',
                                               ratio='compress',size=None,
                                               renderer='dot',