# HG changeset patch # User Sylvain Thénault <sylvain.thenault@logilab.fr> # Date 1302685422 -7200 # Node ID 6053bf221fa90ba555640f62006248112c74de51 # Parent cacff15f847dc01ce4471bca679dbc29005caf49# Parent 2da7f3ec4e6f4d15163829c3d497c319bf0b1c82 backport stable diff -r cacff15f847d -r 6053bf221fa9 dataimport.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, diff -r cacff15f847d -r 6053bf221fa9 devtools/__init__.py --- 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: diff -r cacff15f847d -r 6053bf221fa9 entities/test/unittest_base.py --- 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): diff -r cacff15f847d -r 6053bf221fa9 entity.py --- 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), diff -r cacff15f847d -r 6053bf221fa9 web/views/schema.py --- 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',