[cwproperties] refactor properties form to make it partly overrideable easily (closes #1936782)
also fix some pitfalls on the way:
* shouldn't capitalize labels, this has to be done in translation files as desired
* form_row in CWProperties form didn't return subform as its parent class
# 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.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.fromdatetimeimportdatetime,timedeltafromitertoolsimportrepeatfromcubicweb.devtoolsimportTestServerConfiguration,init_test_databasefromcubicweb.devtools.testlibimportCubicWebTC,Tagsfromcubicweb.devtools.repotestimportdo_monkey_patch,undo_monkey_patchfromcubicweb.devtoolsimportget_test_db_handlerclassExternalSource1Configuration(TestServerConfiguration):sourcefile='sources_extern'classExternalSource2Configuration(TestServerConfiguration):sourcefile='sources_multi'MTIME=datetime.now()-timedelta(0,10)EXTERN_SOURCE_CFG=u'''pyro-ns-id = externcubicweb-user = admincubicweb-password = gingkowbase-url=http://extern.org/'''# hi-jackingfromcubicweb.server.sources.pyrorqlimportPyroRQLSourcefromcubicweb.dbapiimportConnectionPyroRQLSource_get_connection=PyroRQLSource.get_connectionConnection_close=Connection.closedefadd_extern_mapping(source):source.init_mapping(zip(('Card','Affaire','State','in_state','documented_by','multisource_inlined_rel'),repeat(u'write')))defpre_setup_database_extern(session,config):session.execute('INSERT Card X: X title "C3: An external card", X wikiid "aaa"')session.execute('INSERT Card X: X title "C4: Ze external card", X wikiid "zzz"')session.execute('INSERT Affaire X: X ref "AFFREF"')session.commit()defpre_setup_database_multi(session,config):session.create_entity('CWSource',name=u'extern',type=u'pyrorql',config=EXTERN_SOURCE_CFG)session.commit()classTwoSourcesTC(CubicWebTC):"""Main repo -> extern-multi -> extern \-------------/ """test_db_id='cw-server-multisources'tags=CubicWebTC.tags|Tags(('multisources'))@classmethoddefsetUpClass(cls):cls._cfg2=ExternalSource1Configuration('data',apphome=TwoSourcesTC.datadir)cls._cfg3=ExternalSource2Configuration('data',apphome=TwoSourcesTC.datadir)TestServerConfiguration.no_sqlite_wrap=True# hi-jack PyroRQLSource.get_connection to access existing connection (no# pyro connection)PyroRQLSource.get_connection=lambdax:x.uri=='extern-multi'andcls.cnx3orcls.cnx2# also necessary since the repository is closing its initial connections# pool though we want to keep cnx2 validConnection.close=lambdax:None@classmethoddeftearDowncls(cls):PyroRQLSource.get_connection=PyroRQLSource_get_connectionConnection.close=Connection_closecls.cnx2.close()cls.cnx3.close()TestServerConfiguration.no_sqlite_wrap=False@classmethoddef_init_repo(cls):repo2_handler=get_test_db_handler(cls._cfg2)repo2_handler.build_db_cache('4cards-1affaire',pre_setup_func=pre_setup_database_extern)cls.repo2,cls.cnx2=repo2_handler.get_repo_and_cnx('4cards-1affaire')repo3_handler=get_test_db_handler(cls._cfg3)repo3_handler.build_db_cache('multisource',pre_setup_func=pre_setup_database_multi)cls.repo3,cls.cnx3=repo3_handler.get_repo_and_cnx('multisource')super(TwoSourcesTC,cls)._init_repo()defsetUp(self):CubicWebTC.setUp(self)self.addCleanup(self.cnx2.close)self.addCleanup(self.cnx3.close)do_monkey_patch()deftearDown(self):forsourceinself.repo.sources[1:]:self.repo.remove_source(source.uri)CubicWebTC.tearDown(self)self.cnx2.close()self.cnx3.close()undo_monkey_patch()@staticmethoddefpre_setup_database(session,config):foruri,src_configin[('extern',EXTERN_SOURCE_CFG),('extern-multi','''pyro-ns-id = extern-multicubicweb-user = admincubicweb-password = gingkow''')]:source=session.create_entity('CWSource',name=unicode(uri),type=u'pyrorql',config=unicode(src_config))session.commit()add_extern_mapping(source)session.commit()# trigger discoverysession.execute('Card X')session.execute('Affaire X')session.execute('State X')defsetup_database(self):cu2=self.cnx2.cursor()self.ec1=cu2.execute('Any X WHERE X is Card, X title "C3: An external card", X wikiid "aaa"')[0][0]self.aff1=cu2.execute('Any X WHERE X is Affaire, X ref "AFFREF"')[0][0]cu2.close()# add some entitiesself.ic1=self.sexecute('INSERT Card X: X title "C1: An internal card", X wikiid "aaai"')[0][0]self.ic2=self.sexecute('INSERT Card X: X title "C2: Ze internal card", X wikiid "zzzi"')[0][0]deftest_eid_comp(self):rset=self.sexecute('Card X WHERE X eid > 1')self.assertEqual(len(rset),4)rset=self.sexecute('Any X,T WHERE X title T, X eid > 1')self.assertEqual(len(rset),4)deftest_metainformation(self):rset=self.sexecute('Card X ORDERBY T WHERE X title T')# 2 added to the system source, 2 added to the external sourceself.assertEqual(len(rset),4)# since they are orderd by eid, we know the 3 first one is coming from the system source# and the others from external sourceself.assertEqual(rset.get_entity(0,0).cw_metainformation(),{'source':{'type':'native','uri':'system','use-cwuri-as-url':False},'type':u'Card','extid':None})externent=rset.get_entity(3,0)metainf=externent.cw_metainformation()self.assertEqual(metainf['source'],{'type':'pyrorql','base-url':'http://extern.org/','uri':'extern','use-cwuri-as-url':False})self.assertEqual(metainf['type'],'Card')self.assert_(metainf['extid'])etype=self.sexecute('Any ETN WHERE X is ET, ET name ETN, X eid %(x)s',{'x':externent.eid})[0][0]self.assertEqual(etype,'Card')deftest_order_limit_offset(self):rsetbase=self.sexecute('Any W,X ORDERBY W,X WHERE X wikiid W')self.assertEqual(len(rsetbase),4)self.assertEqual(sorted(rsetbase.rows),rsetbase.rows)rset=self.sexecute('Any W,X ORDERBY W,X LIMIT 2 OFFSET 2 WHERE X wikiid W')self.assertEqual(rset.rows,rsetbase.rows[2:4])deftest_has_text(self):self.repo.sources_by_uri['extern'].synchronize(MTIME)# in case fti_update has been run beforeself.assertTrue(self.sexecute('Any X WHERE X has_text "affref"'))self.assertTrue(self.sexecute('Affaire X WHERE X has_text "affref"'))self.assertTrue(self.sexecute('Any X ORDERBY FTIRANK(X) WHERE X has_text "affref"'))self.assertTrue(self.sexecute('Affaire X ORDERBY FTIRANK(X) WHERE X has_text "affref"'))deftest_anon_has_text(self):self.repo.sources_by_uri['extern'].synchronize(MTIME)# in case fti_update has been run beforeself.sexecute('INSERT Affaire X: X ref "no readable card"')[0][0]aff1=self.sexecute('INSERT Affaire X: X ref "card"')[0][0]# grant read accessself.sexecute('SET X owned_by U WHERE X eid %(x)s, U login "anon"',{'x':aff1})self.commit()cnx=self.login('anon')cu=cnx.cursor()rset=cu.execute('Any X WHERE X has_text "card"')# 5: 4 card + 1 readable affaireself.assertEqual(len(rset),5,zip(rset.rows,rset.description))rset=cu.execute('Any X ORDERBY FTIRANK(X) WHERE X has_text "card"')self.assertEqual(len(rset),5,zip(rset.rows,rset.description))Connection_close(cnx.cnx)# cnx is a TestCaseConnectionProxydeftest_synchronization(self):cu=self.cnx2.cursor()assertcu.execute('Any X WHERE X eid %(x)s',{'x':self.aff1})cu.execute('SET X ref "BLAH" WHERE X eid %(x)s',{'x':self.aff1})aff2=cu.execute('INSERT Affaire X: X ref "AFFREUX"')[0][0]self.cnx2.commit()try:# force syncself.repo.sources_by_uri['extern'].synchronize(MTIME)self.assertTrue(self.sexecute('Any X WHERE X has_text "blah"'))self.assertTrue(self.sexecute('Any X WHERE X has_text "affreux"'))cu.execute('DELETE Affaire X WHERE X eid %(x)s',{'x':aff2})self.cnx2.commit()self.repo.sources_by_uri['extern'].synchronize(MTIME)rset=self.sexecute('Any X WHERE X has_text "affreux"')self.assertFalse(rset)finally:# restore statecu.execute('SET X ref "AFFREF" WHERE X eid %(x)s',{'x':self.aff1})self.cnx2.commit()deftest_simplifiable_var(self):affeid=self.sexecute('Affaire X WHERE X ref "AFFREF"')[0][0]rset=self.sexecute('Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB',{'x':affeid})self.assertEqual(len(rset),1)self.assertEqual(rset[0][1],"pitetre")deftest_simplifiable_var_2(self):affeid=self.sexecute('Affaire X WHERE X ref "AFFREF"')[0][0]rset=self.sexecute('Any E WHERE E eid %(x)s, E in_state S, NOT S name "moved"',{'x':affeid,'u':self.session.user.eid})self.assertEqual(len(rset),1)deftest_sort_func(self):self.sexecute('Affaire X ORDERBY DUMB_SORT(RF) WHERE X ref RF')deftest_sort_func_ambigous(self):self.sexecute('Any X ORDERBY DUMB_SORT(RF) WHERE X title RF')deftest_in_eid(self):iec1=self.repo.extid2eid(self.repo.sources_by_uri['extern'],str(self.ec1),'Card',self.session)rset=self.sexecute('Any X WHERE X eid IN (%s, %s)'%(iec1,self.ic1))self.assertEqual(sorted(r[0]forrinrset.rows),sorted([iec1,self.ic1]))deftest_greater_eid(self):rset=self.sexecute('Any X WHERE X eid > %s'%(self.ic1-1))self.assertEqual(len(rset.rows),2)# self.ic1 and self.ic2cu=self.cnx2.cursor()ec2=cu.execute('INSERT Card X: X title "glup"')[0][0]self.cnx2.commit()# 'X eid > something' should not trigger discoveryrset=self.sexecute('Any X WHERE X eid > %s'%(self.ic1-1))self.assertEqual(len(rset.rows),2)# trigger discovery using another querycrset=self.sexecute('Card X WHERE X title "glup"')self.assertEqual(len(crset.rows),1)rset=self.sexecute('Any X WHERE X eid > %s'%(self.ic1-1))self.assertEqual(len(rset.rows),3)rset=self.sexecute('Any MAX(X)')self.assertEqual(len(rset.rows),1)self.assertEqual(rset.rows[0][0],crset[0][0])deftest_attr_unification_1(self):n1=self.sexecute('INSERT Note X: X type "AFFREF"')[0][0]n2=self.sexecute('INSERT Note X: X type "AFFREU"')[0][0]rset=self.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X type T, Y ref T')self.assertEqual(len(rset),1,rset.rows)deftest_attr_unification_2(self):cu=self.cnx2.cursor()ec2=cu.execute('INSERT Card X: X title "AFFREF"')[0][0]self.cnx2.commit()try:c1=self.sexecute('INSERT Card C: C title "AFFREF"')[0][0]rset=self.sexecute('Any X,Y WHERE X is Card, Y is Affaire, X title T, Y ref T')self.assertEqual(len(rset),2,rset.rows)finally:cu.execute('DELETE Card X WHERE X eid %(x)s',{'x':ec2})self.cnx2.commit()deftest_attr_unification_neq_1(self):# XXX completeself.sexecute('Any X,Y WHERE X is Note, Y is Affaire, X creation_date D, Y creation_date > D')deftest_attr_unification_neq_2(self):# XXX completeself.sexecute('Any X,Y WHERE X is Card, Y is Affaire, X creation_date D, Y creation_date > D')deftest_union(self):afeids=self.sexecute('Affaire X')ueids=self.sexecute('CWUser X')rset=self.sexecute('(Any X WHERE X is Affaire) UNION (Any X WHERE X is CWUser)')self.assertEqual(sorted(r[0]forrinrset.rows),sorted(r[0]forrinafeids+ueids))deftest_subquery1(self):rsetbase=self.sexecute('Any W,X WITH W,X BEING (Any W,X ORDERBY W,X WHERE X wikiid W)')self.assertEqual(len(rsetbase),4)self.assertEqual(sorted(rsetbase.rows),rsetbase.rows)rset=self.sexecute('Any W,X LIMIT 2 OFFSET 2 WITH W,X BEING (Any W,X ORDERBY W,X WHERE X wikiid W)')self.assertEqual(rset.rows,rsetbase.rows[2:4])rset=self.sexecute('Any W,X ORDERBY W,X LIMIT 2 OFFSET 2 WITH W,X BEING (Any W,X WHERE X wikiid W)')self.assertEqual(rset.rows,rsetbase.rows[2:4])rset=self.sexecute('Any W,X WITH W,X BEING (Any W,X ORDERBY W,X LIMIT 2 OFFSET 2 WHERE X wikiid W)')self.assertEqual(rset.rows,rsetbase.rows[2:4])deftest_subquery2(self):affeid=self.sexecute('Affaire X WHERE X ref "AFFREF"')[0][0]rset=self.sexecute('Any X,AA,AB WITH X,AA,AB BEING (Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB)',{'x':affeid})self.assertEqual(len(rset),1)self.assertEqual(rset[0][1],"pitetre")deftest_not_relation(self):states=set(tuple(x)forxinself.sexecute('Any S,SN WHERE S is State, S name SN'))userstate=self.session.user.in_state[0]states.remove((userstate.eid,userstate.name))notstates=set(tuple(x)forxinself.sexecute('Any S,SN WHERE S is State, S name SN, NOT X in_state S, X eid %(x)s',{'x':self.session.user.eid}))self.assertSetEqual(notstates,states)aff1=self.sexecute('Any X WHERE X is Affaire, X ref "AFFREF"')[0][0]aff1stateeid,aff1statename=self.sexecute('Any S,SN WHERE X eid %(x)s, X in_state S, S name SN',{'x':aff1})[0]self.assertEqual(aff1statename,'pitetre')states.add((userstate.eid,userstate.name))states.remove((aff1stateeid,aff1statename))notstates=set(tuple(x)forxinself.sexecute('Any S,SN WHERE S is State, S name SN, NOT X in_state S, X eid %(x)s',{'x':aff1}))self.assertSetEqual(notstates,states)deftest_absolute_url_base_url(self):cu=self.cnx2.cursor()ceid=cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]self.cnx2.commit()lc=self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0,0)self.assertEqual(lc.absolute_url(),'http://extern.org/card/eid/%s'%ceid)cu.execute('DELETE Card X WHERE X eid %(x)s',{'x':ceid})self.cnx2.commit()deftest_absolute_url_no_base_url(self):cu=self.cnx3.cursor()ceid=cu.execute('INSERT Card X: X title "without wikiid to get eid based url"')[0][0]self.cnx3.commit()lc=self.sexecute('Card X WHERE X title "without wikiid to get eid based url"').get_entity(0,0)self.assertEqual(lc.absolute_url(),'http://testing.fr/cubicweb/card/eid/%s'%lc.eid)cu.execute('DELETE Card X WHERE X eid %(x)s',{'x':ceid})self.cnx3.commit()deftest_crossed_relation_noeid_needattr(self):"""http://www.cubicweb.org/ticket/1382452"""aff1=self.sexecute('INSERT Affaire X: X ref "AFFREF"')[0][0]# link within extern sourceec1=self.sexecute('Card X WHERE X wikiid "zzz"')[0][0]self.sexecute('SET A documented_by C WHERE E eid %(a)s, C eid %(c)s',{'a':aff1,'c':ec1})# link from system to extern sourceself.sexecute('SET A documented_by C WHERE E eid %(a)s, C eid %(c)s',{'a':aff1,'c':self.ic2})rset=self.sexecute('DISTINCT Any DEP WHERE P ref "AFFREF", P documented_by DEP, DEP wikiid LIKE "z%"')self.assertEqual(sorted(rset.rows),[[ec1],[self.ic2]])deftest_nonregr1(self):ueid=self.session.user.eidaffaire=self.sexecute('Affaire X WHERE X ref "AFFREF"').get_entity(0,0)self.sexecute('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',{'x':affaire.eid,'u':ueid})deftest_nonregr2(self):iworkflowable=self.session.user.cw_adapt_to('IWorkflowable')iworkflowable.fire_transition('deactivate')treid=iworkflowable.latest_trinfo().eidrset=self.sexecute('Any X ORDERBY D DESC WHERE E eid %(x)s, E wf_info_for X, X modification_date D',{'x':treid})self.assertEqual(len(rset),1)self.assertEqual(rset.rows[0],[self.session.user.eid])deftest_nonregr3(self):self.sexecute('DELETE Card X WHERE X eid %(x)s, NOT X multisource_inlined_rel Y',{'x':self.ic1})deftest_nonregr4(self):self.sexecute('Any X,S,U WHERE X in_state S, X todo_by U')deftest_delete_source(self):req=self.request()req.execute('DELETE CWSource S WHERE S name "extern"')self.commit()cu=self.session.system_sql("SELECT * FROM entities WHERE source='extern'")self.assertFalse(cu.fetchall())if__name__=='__main__':fromlogilab.common.testlibimportunittest_mainunittest_main()