def getMoverTableRows(self,tablerow=None,movercode=None,**kwargs): pkeys = tablerow['pkeys'].keys() table = tablerow['table'] objtype = tablerow['objtype'] tblobj = self.db.table(table) columns,mask = tblobj.rowcaptionDecode(tblobj.rowcaption) if columns: columns = ','.join(columns) f = tblobj.query(where='$pkey IN :pkeys',pkeys=tablerow['pkeys'].keys(),columns=columns).fetch() result = Bag() for r in f: result.setItem(r['pkey'],None,_pkey=r['pkey'],db_caption=tblobj.recordCaption(record=r),_customClasses='mover_db') indexpath = self.page.site.getStaticPath('user:temp','mover','index.xml') if os.path.isfile(indexpath): indexbag = Bag(indexpath) moverrows = indexbag.getItem('records.%s' %movercode) if not moverrows: return result for pkey in pkeys: rownode = moverrows.getNode(pkey) if rownode: xml_caption=rownode.attr['caption'] if not pkey in result: result.setItem(pkey,None,_pkey=pkey,xml_caption=xml_caption,_customClasses='mover_xml',objtype=objtype,table=tablerow['reftable']) else: result.getNode(pkey).attr.update(xml_caption=xml_caption,_customClasses='mover_both',objtype=objtype,table=tablerow['reftable']) return result
class TestAdvancedBag(unittest.TestCase): def setUp(self): self.bag = Bag() self.bag.setBackRef() self.bag["a.b.c.d"] = 4 self.bag["a.b.e"] = 5 def testparent(self): self.assertEqual(self.bag["a.b.c"].parent, self.bag["a.b"]) c = self.bag["a.b.c"] self.assertEqual(c["../e"], 5) self.bag["a.b"].delParentRef() self.assertFalse(self.bag["a.b"].backref) def testformula(self): self.bag["product"] = self.bag.formula("$x*$y", x="a.b.c.d", y="a.b.e") self.assertEqual(self.bag["product"], self.bag["a.b.c.d"] * self.bag["a.b.e"]) self.bag.defineFormula(calculate_perimeter="2*($base + $height)") self.bag.defineSymbol(base="a.b.c.d", height="a.b.e") self.bag["perimeter"] = self.bag.formula("calculate_perimeter") self.assertEqual(self.bag["perimeter"], 18) def testcallbackitem(self): def hello(): return "Hello!" self.bag.setCallBackItem("say_hello", hello) self.assertEqual(self.bag["say_hello"], hello()) def testnodetrigger(self): self.lastupdates = [] def mycallback(node, info=None, evt=None): self.lastupdates.append((node.getLabel(), info, node.getValue())) self.bag.getNode("a.b.c.d").subscribe("lastupdates", mycallback) self.bag["a.b.c.d"] = 20 self.assertEqual(self.lastupdates[-1], ("d", 4, 20)) def testbagtriggers(self): self.log = [] def log_upd(node, pathlist, oldvalue, evt): self.log.append((".".join(pathlist), node.getValue(), oldvalue, evt)) def log_ins(node, pathlist, ind, evt): self.log.append((".".join(pathlist), node.getValue(), ind, evt)) def log_del(node, pathlist, ind, evt): self.log.append((".".join(pathlist), node.getValue(), ind, evt)) self.bag.subscribe("log", update=log_upd, insert=log_ins, delete=log_del) self.bag["a.b.t"] = 45 self.assertEqual(self.log[-1], ("a.b", 45, 2, "ins")) self.bag["a.b.t"] = 56 self.assertEqual(self.log[-1], ("a.b.t", 56, 45, "upd_value")) self.bag.delItem("a.b.t") self.assertEqual(self.log[-1], ("a.b", 56, 2, "del"))
def onDroppedMover(self,file_path=None): import tarfile f = tarfile.open(file_path) f.extractall(self.page.site.getStaticPath('user:temp')) os.remove(file_path) indexpath = self.page.site.getStaticPath('user:temp','mover','index.xml') indexbag = Bag(indexpath) indexbag.getNode('movers').attr.update(imported=True) indexbag.toXml(indexpath)
def onDroppedMover(self, file_path=None): import tarfile f = tarfile.open(file_path) f.extractall(self.page.site.getStaticPath('user:temp')) os.remove(file_path) indexpath = self.page.site.getStaticPath('user:temp', 'mover', 'index.xml') indexbag = Bag(indexpath) indexbag.getNode('movers').attr.update(imported=True) indexbag.toXml(indexpath)
def cleanUserBatches(self,user): if self.page.isGuest: return if not os.path.exists(self.page.userDocument('_batch_result')): return batch_results = [x for x in os.listdir(self.page.userDocument('_batch_result')) if not x.startswith('.')] batch_to_remove = [] with self.page.userStore(user) as store: already_registered_batch = [dc.path.split('.')[2] for dc in store.datachanges if dc.path.startswith('gnr.batch')] for res_doc_name in batch_results: result_doc = Bag(self.page.userDocument('_batch_result', res_doc_name)) resultNode = result_doc.getNode('result') batch_id = result_doc['batch_id'] if not resultNode or not 'url' in resultNode.attr: batch_to_remove.append(batch_id) continue if batch_id not in already_registered_batch: batch_path = 'gnr.batch.%s' % batch_id newbatch = Bag( dict(title=result_doc['title'], start_ts=result_doc['start_ts'], note=result_doc['note'], owner_page_id=result_doc['owner_page_id'])) store.set_datachange(batch_path, newbatch, reason='btc_create') reason = 'btc_result_doc' if result_doc['result'] else 'btc_error_doc' store.set_datachange(batch_path, result_doc, reason=reason) if batch_to_remove: self.remove_batch(batch_id=batch_to_remove)
def th_slotbar_sections(self,parent,sections=None,condition=None,condition_kwargs=None,all_begin=None,all_end=None,**kwargs): inattr = parent.getInheritedAttributes() th_root = inattr['th_root'] pane = parent.div(datapath='.sections.%s' %sections) tblobj = self.db.table(inattr['table']) if sections in tblobj.model.columns and tblobj.column(sections).relatedTable() is not None: sectionslist = self._th_section_from_fkey(tblobj,sections,condition=condition,condition_kwargs=condition_kwargs,all_begin=all_begin,all_end=all_end) dflt = None multivalue = True variable_struct = False isMain = False mandatory = None depending_condition = False depending_condition_kwargs = dict() else: m = self._th_hook('sections_%s' %sections,mangler=th_root) sectionslist = m() dflt = getattr(m,'default',None) multivalue=getattr(m,'multivalue',False) isMain = getattr(m,'isMain',False) variable_struct = getattr(m,'variable_struct',False) mandatory=getattr(m,'mandatory',True) depending_condition = getattr(m,'_if',False) depending_condition_kwargs = dictExtract(dict(m.__dict__),'_if_') if not sectionslist: return sectionsBag = Bag() for i,kw in enumerate(sectionslist): sectionsBag.setItem(kw.get('code') or 'r_%i' %i,None,**kw) pane.data('.data',sectionsBag) if not dflt: dflt = sectionsBag.getNode('#0').label pane.data('.current',dflt) pane.data('.variable_struct',variable_struct) if multivalue and variable_struct: raise Exception('multivalue cannot be set with variable_struct') mb = pane.multiButton(items='^.data',value='^.current',multivalue=multivalue,mandatory=mandatory, disabled='^.#parent.parent.grid.loadingData',**kwargs) parent.dataController("""var enabled = depending_condition?funcApply('return '+depending_condition,_kwargs):true; genro.dom.toggleVisible(__mb,enabled) SET .%s.enabled = enabled; FIRE .#parent.#parent.sections_changed; """ %sections, __mb=mb,ss=sections,datapath='.sections', depending_condition=depending_condition,_onBuilt=True, **depending_condition_kwargs) pane.dataController(""" genro.assert(currentSection,'missing current section for sections %s') var sectionNode = sectionbag.getNode(currentSection); if(isMain){ FIRE .#parent.#parent.clearStore; SET .#parent.#parent.excludeDraft = !sectionNode.attr.includeDraft; } FIRE .#parent.#parent.sections_changed; """ %sections ,isMain=isMain,mb=mb,_onBuilt=True, currentSection='^.current',sectionbag='=.data', th_root=th_root)
def getMoverTableRows(self, tablerow=None, movercode=None, **kwargs): pkeys = tablerow['pkeys'].keys() table = tablerow['table'] objtype = tablerow['objtype'] tblobj = self.db.table(table) columns, mask = tblobj.rowcaptionDecode(tblobj.rowcaption) if columns: columns = ','.join(columns) f = tblobj.query(where='$pkey IN :pkeys', pkeys=tablerow['pkeys'].keys(), columns=columns).fetch() result = Bag() for r in f: result.setItem(r['pkey'], None, _pkey=r['pkey'], db_caption=tblobj.recordCaption(record=r), _customClasses='mover_db') indexpath = self.page.site.getStaticPath('user:temp', 'mover', 'index.xml') if os.path.isfile(indexpath): indexbag = Bag(indexpath) moverrows = indexbag.getItem('records.%s' % movercode) if not moverrows: return result for pkey in pkeys: rownode = moverrows.getNode(pkey) if rownode: xml_caption = rownode.attr['caption'] if not pkey in result: result.setItem(pkey, None, _pkey=pkey, xml_caption=xml_caption, _customClasses='mover_xml', objtype=objtype, table=tablerow['reftable']) else: result.getNode(pkey).attr.update( xml_caption=xml_caption, _customClasses='mover_both', objtype=objtype, table=tablerow['reftable']) return result
def getMoverTableRows(self, tablerow=None, movercode=None, **kwargs): pkeys = tablerow["pkeys"].keys() table = tablerow["table"] objtype = tablerow["objtype"] tblobj = self.db.table(table) columns, mask = tblobj.rowcaptionDecode(tblobj.rowcaption) if columns: columns = ",".join(columns) f = tblobj.query(where="$pkey IN :pkeys", pkeys=tablerow["pkeys"].keys(), columns=columns).fetch() result = Bag() for r in f: result.setItem( r["pkey"], None, _pkey=r["pkey"], db_caption=tblobj.recordCaption(record=r), _customClasses="mover_db" ) indexpath = self.page.site.getStaticPath("user:temp", "mover", "index.xml") if os.path.isfile(indexpath): indexbag = Bag(indexpath) moverrows = indexbag.getItem("records.%s" % movercode) if not moverrows: return result for pkey in pkeys: rownode = moverrows.getNode(pkey) if rownode: xml_caption = rownode.attr["caption"] if not pkey in result: result.setItem( pkey, None, _pkey=pkey, xml_caption=xml_caption, _customClasses="mover_xml", objtype=objtype, table=tablerow["reftable"], ) else: result.getNode(pkey).attr.update( xml_caption=xml_caption, _customClasses="mover_both", objtype=objtype, table=tablerow["reftable"], ) return result
def extdb_getDbStructure(self,connection_params=None,project=None,package=None): externaldb = self.extdb_getSourceDb(connection_params) existing_tables = [] if project and package: p = PathResolver() project_path = p.project_name_to_path(project) modelpath = os.path.join(project_path,'packages',package,'model') if os.path.isdir(modelpath): existing_tables = map(lambda r: os.path.splitext(r)[0], filter(lambda r: r.endswith('.py'), os.listdir(modelpath))) src = externaldb.model.src result = Bag() for pkg in src['packages'].keys(): pkgval = Bag() result.setItem(pkg, pkgval,name=pkg,checked=False) tables = src['packages'][pkg]['tables'] if not tables: continue tables.sort('#k') for table,tblattr,tblval in tables.digest('#k,#a,#v'): tblattr = dict(tblattr) tblattr['checked'] = 'disabled:on' if table.lower() in existing_tables else False tblattr['name'] = table tableval = Bag() pkgval.setItem(table,tableval,**tblattr) for column,colattr,colval in tblval['columns'].digest('#k,#a,#v'): cv = dict(colattr) for t,v in tblattr.items(): cv['table_%s' %t] = v #cv['checked'] = False cv['name'] = column if colval: relnode = colval.getNode('relation') cv['relate_to'] = relnode.attr['related_column'] tableval.setItem(column,None,**cv) if tblval['indexes']: for column,unique in tblval['indexes'].digest('#a.columns,#a.unique'): n = tableval.getNode(column) if n: n.attr['is_pkey'] = column == tblattr.get('pkey') n.attr['indexed'] = True n.attr['unique'] = boolean(unique) return result
def cleanUserBatches(self, user): if self.page.isGuest: return if not os.path.exists(self.page.userDocument('_batch_result')): return batch_results = [ x for x in os.listdir(self.page.userDocument('_batch_result')) if not x.startswith('.') ] batch_to_remove = [] with self.page.userStore(user) as store: already_registered_batch = [ dc.path.split('.')[2] for dc in store.datachanges if dc.path.startswith('gnr.batch') ] for res_doc_name in batch_results: result_doc = Bag( self.page.userDocument('_batch_result', res_doc_name)) resultNode = result_doc.getNode('result') batch_id = result_doc['batch_id'] if not resultNode or not 'url' in resultNode.attr: batch_to_remove.append(batch_id) continue if batch_id not in already_registered_batch: batch_path = 'gnr.batch.%s' % batch_id newbatch = Bag( dict(title=result_doc['title'], start_ts=result_doc['start_ts'], note=result_doc['note'], owner_page_id=result_doc['owner_page_id'])) store.set_datachange(batch_path, newbatch, reason='btc_create') reason = 'btc_result_doc' if result_doc[ 'result'] else 'btc_error_doc' store.set_datachange(batch_path, result_doc, reason=reason) if batch_to_remove: self.remove_batch(batch_id=batch_to_remove)
def makeNewPackage(self,package_name=None,name_long=None,is_main_package=None,project_name=None): path_resolver = PathResolver() project_path = path_resolver.project_name_to_path(project_name) packagespath = os.path.join(project_path,'packages') instances = os.path.join(project_path,'instances') sites = os.path.join(project_path,'sites') package_maker = PackageMaker(package_name,base_path=packagespath,helloworld=True,name_long=name_long) package_maker.do() if os.path.exists(instances): for d in os.listdir(instances): configpath = os.path.join(instances,d,'instanceconfig.xml') if os.path.isfile(configpath): b = Bag(configpath) b.setItem('packages.%s' %package_name,'') b.toXml(configpath,typevalue=False,pretty=True) if os.path.exists(sites): for d in os.listdir(sites): configpath = os.path.join(sites,d,'siteconfig.xml') if os.path.isfile(configpath): b = Bag(configpath) n = b.getNode('wsgi') n.attr['mainpackage'] = package_name b.toXml(configpath,typevalue=False,pretty=True) return package_name
class TestAttributeBag(unittest.TestCase): def setUp(self): self.fullbag = Bag( { "office": Bag({"John": Bag(), "Frank": Bag(), "Alexandra": Bag()}), "friends": Bag({"Henry": Bag(), "Fred": Bag()}), "relatives": Bag({"Karla": Bag(), "Albert": Bag()}), } ) self.fullbag["office"].setItem("Xavier", Bag(), fromdate="9-15-2005", role="researcher") self.fullbag["office"].setAttr("Frank", fromdate="3-5-1998", role="developer") self.fullbag["office"].setAttr("John", fromdate="2-1-1990", role="boss", age=55) def testattributes(self): self.assertEqual(self.fullbag["office"].getAttr("Xavier", "role"), "researcher") self.assertEqual(self.fullbag["office.Frank?a:role"], "developer") l = [("Frank", "developer"), ("John", "boss"), ("Alexandra", None), ("Xavier", "researcher")] self.failUnless(self.fullbag["office"].digest("#k,#a.role") == self.fullbag["office.?d:#k,#a.role"] == l) self.failUnless( self.fullbag["office.Xavier"] == self.fullbag["office.#3"] == self.fullbag["office.#role=researcher"] ) def testBagNodes(self): self.fullbag.delAttr("office.John", "age") n = self.fullbag.getNode("office.John") self.assertTrue(n.hasAttr("role")) self.assertFalse(n.hasAttr("age")) self.assertEqual(n, self.fullbag.getNodeByAttr("role", "boss")) def testgetNodeByAttr(self): researcher = self.fullbag.getNodeByAttr("role", "researcher") self.assertEqual(researcher, self.fullbag.getNode("office.Xavier")) def testfromToXml(self): self.fullbag["relatives.Karla.birthday"] = datetime.date(1952, 12, 10) self.fullbag["relatives.Karla.pierciengs"] = 0 self.fullbag["relatives.Karla.dogname"] = "" self.fullbag.setAttr("relatives.Karla", age=54) self.fullbag.toXml("mybag.xml") x = self.fullbag["relatives"].toXml() b = Bag(x) self.assertEqual(b.asString(), self.fullbag["relatives"].asString()) def testsfromSource(self): current = os.getcwd() fromlocal_std = Bag("%s/test_files/standardxml.xml" % current) self.assertTrue(isinstance(fromlocal_std, Bag)) # non riesce a printarla per carattere non encodabile fromlocal_bag = Bag("%s/test_files/mybag.xml" % current) self.assertTrue(isinstance(fromlocal_bag, Bag)) # uncomment the following test if you are online # fromurl=Bag('http://www.plone.org') # self.assertTrue(isinstance(fromurl, Bag)) stringxml = '<?xml version="1.02" encoding="UTF-8"?><a><b name="fuffy"><d>dog</d></b><c/></a>' fromstringxml = Bag(stringxml) self.assertTrue(isinstance(fromstringxml, Bag)) fromdirectory = Bag("%s/test_files" % current) self.assertTrue(isinstance(fromdirectory, Bag)) def testmerge(self): newbag = Bag() newbag.setItem("Henry", self.fullbag["friends.Henry"], role="documentation and tests") newbag.setItem("Xavier", "Mr Xavier", role="documentation manager", age=26) allflagstrue = self.fullbag["office"].merge(newbag) # all flags true allflagsfalse = self.fullbag["office"].merge( newbag, upd_values=False, add_values=False, upd_attr=False, add_attr=False ) self.assertEqual(allflagsfalse.asString(), self.fullbag["office"].asString()) notupdatevalues = self.fullbag["office"].merge(newbag, upd_values=False) self.assertTrue(isinstance(self.fullbag["office.Xavier"], Bag)) notaddvalues = self.fullbag["office"].merge(newbag, add_values=False) self.assertEqual(len(self.fullbag["office"].items()), len(notaddvalues.items())) notupdateattrs = self.fullbag["office"].merge(newbag, upd_attr=False) self.assertEqual(self.fullbag["office.Xavier?a:role"], notupdateattrs["Xavier?a:role"]) notaddattrs = self.fullbag["office"].merge(newbag, add_attr=False) self.assertFalse(notaddattrs.getAttr("Xavier", "age", default=False)) def testsum(self): numbers = Bag() numbers.setItem("first", 20, height=22) numbers.setItem("second", 30, height=342) self.assertEqual(numbers.sum("#v,#a.height"), [50, 364])
class TestAdvancedBag(unittest.TestCase): def setUp(self): self.bag = Bag() self.bag.setBackRef() self.bag['a.b.c.d'] = 4 self.bag['a.b.e'] = 5 def testparent(self): self.assertEqual(self.bag['a.b.c'].parent, self.bag['a.b']) c = self.bag['a.b.c'] self.assertEqual(c['../e'], 5) self.bag['a.b'].delParentRef() self.assertFalse(self.bag['a.b'].backref) def testformula(self): self.bag['product'] = self.bag.formula('$x*$y', x='a.b.c.d', y='a.b.e') self.assertEqual(self.bag['product'], self.bag['a.b.c.d'] * self.bag['a.b.e']) self.bag.defineFormula(calculate_perimeter='2*($base + $height)') self.bag.defineSymbol(base='a.b.c.d', height='a.b.e') self.bag['perimeter'] = self.bag.formula('calculate_perimeter') self.assertEqual(self.bag['perimeter'], 18) def testcallbackitem(self): def hello(): return 'Hello!' self.bag.setCallBackItem('say_hello', hello) self.assertEqual(self.bag['say_hello'], hello()) def testnodetrigger(self): self.lastupdates = [] def mycallback(node, info=None, evt=None): self.lastupdates.append((node.getLabel(), info, node.getValue())) self.bag.getNode('a.b.c.d').subscribe('lastupdates', mycallback) self.bag['a.b.c.d'] = 20 self.assertEqual(self.lastupdates[-1], ('d', 4, 20)) def testbagtriggers(self): self.log = [] def log_upd(node, pathlist, oldvalue, evt): self.log.append( ('.'.join(pathlist), node.getValue(), oldvalue, evt)) def log_ins(node, pathlist, ind, evt): self.log.append(('.'.join(pathlist), node.getValue(), ind, evt)) def log_del(node, pathlist, ind, evt): self.log.append(('.'.join(pathlist), node.getValue(), ind, evt)) self.bag.subscribe('log', update=log_upd, insert=log_ins, delete=log_del) self.bag['a.b.t'] = 45 self.assertEqual(self.log[-1], ('a.b', 45, 2, 'ins')) self.bag['a.b.t'] = 56 self.assertEqual(self.log[-1], ('a.b.t', 56, 45, 'upd_value')) self.bag.delItem('a.b.t') self.assertEqual(self.log[-1], ('a.b', 56, 2, 'del'))
class TestAttributeBag(unittest.TestCase): def setUp(self): self.fullbag = Bag({ 'office': Bag({ 'John': Bag(), 'Frank': Bag(), 'Alexandra': Bag() }), 'friends': Bag({ 'Henry': Bag(), 'Fred': Bag() }), 'relatives': Bag({ 'Karla': Bag(), 'Albert': Bag() }) }) self.fullbag['office'].setItem('Xavier', Bag(), fromdate='9-15-2005', role='researcher') self.fullbag['office'].setAttr('Frank', fromdate='3-5-1998', role='developer') self.fullbag['office'].setAttr('John', fromdate='2-1-1990', role='boss', age=55) def testattributes(self): self.assertEqual(self.fullbag['office'].getAttr('Xavier', 'role'), 'researcher') self.assertEqual(self.fullbag['office.Frank?a:role'], 'developer') l = [('Frank', 'developer'), ('John', 'boss'), ('Alexandra', None), ('Xavier', 'researcher')] self.failUnless(self.fullbag['office'].digest('#k,#a.role') == self.fullbag['office.?d:#k,#a.role'] == l) self.failUnless( self.fullbag['office.Xavier'] == self.fullbag['office.#3'] == self.fullbag['office.#role=researcher']) def testBagNodes(self): self.fullbag.delAttr('office.John', 'age') n = self.fullbag.getNode('office.John') self.assertTrue(n.hasAttr('role')) self.assertFalse(n.hasAttr('age')) self.assertEqual(n, self.fullbag.getNodeByAttr('role', 'boss')) def testgetNodeByAttr(self): researcher = self.fullbag.getNodeByAttr('role', 'researcher') self.assertEqual(researcher, self.fullbag.getNode('office.Xavier')) def testfromToXml(self): self.fullbag['relatives.Karla.birthday'] = datetime.date(1952, 12, 10) self.fullbag['relatives.Karla.pierciengs'] = 0 self.fullbag['relatives.Karla.dogname'] = '' self.fullbag.setAttr('relatives.Karla', age=54) self.fullbag.toXml('mybag.xml') x = self.fullbag['relatives'].toXml() b = Bag(x) self.assertEqual(b.asString(), self.fullbag['relatives'].asString()) def testsfromSource(self): current = os.getcwd() fromlocal_std = Bag('%s/test_files/standardxml.xml' % current) self.assertTrue(isinstance(fromlocal_std, Bag)) #non riesce a printarla per carattere non encodabile fromlocal_bag = Bag('%s/test_files/mybag.xml' % current) self.assertTrue(isinstance(fromlocal_bag, Bag)) #uncomment the following test if you are online #fromurl=Bag('http://www.plone.org') #self.assertTrue(isinstance(fromurl, Bag)) stringxml = '<?xml version="1.02" encoding="UTF-8"?><a><b name="fuffy"><d>dog</d></b><c/></a>' fromstringxml = Bag(stringxml) self.assertTrue(isinstance(fromstringxml, Bag)) fromdirectory = Bag('%s/test_files' % current) self.assertTrue(isinstance(fromdirectory, Bag)) def testmerge(self): newbag = Bag() newbag.setItem('Henry', self.fullbag['friends.Henry'], role='documentation and tests') newbag.setItem('Xavier', 'Mr Xavier', role='documentation manager', age=26) allflagstrue = self.fullbag['office'].merge(newbag) #all flags true allflagsfalse = self.fullbag['office'].merge(newbag, upd_values=False, add_values=False, upd_attr=False, add_attr=False) self.assertEqual(allflagsfalse.asString(), self.fullbag['office'].asString()) notupdatevalues = self.fullbag['office'].merge(newbag, upd_values=False) self.assertTrue(isinstance(self.fullbag['office.Xavier'], Bag)) notaddvalues = self.fullbag['office'].merge(newbag, add_values=False) self.assertEqual(len(self.fullbag['office'].items()), len(notaddvalues.items())) notupdateattrs = self.fullbag['office'].merge(newbag, upd_attr=False) self.assertEqual(self.fullbag['office.Xavier?a:role'], notupdateattrs['Xavier?a:role']) notaddattrs = self.fullbag['office'].merge(newbag, add_attr=False) self.assertFalse(notaddattrs.getAttr('Xavier', 'age', default=False)) def testsum(self): numbers = Bag() numbers.setItem('first', 20, height=22) numbers.setItem('second', 30, height=342) self.assertEqual(numbers.sum('#v,#a.height'), [50, 364])