def is_code_unique(plant, code): """ Return True/False if the code is a unique Plant code for accession. This method will also take range values for code that can be passed to utils.range_builder() """ # if the range builder only creates one number then we assume the # code is not a range and so we test against the string version of # code codes = map(utils.utf8, utils.range_builder(code)) # test if a range if len(codes) == 1: codes = [utils.utf8(code)] # reference accesssion.id instead of accession_id since # setting the accession on the model doesn't set the # accession_id until the session is flushed session = db.Session() count = ( session.query(Plant) .join("accession") .filter(and_(Accession.id == plant.accession.id, Plant.code.in_(codes))) .count() ) session.close() return count == 0
def test_bulk_plant_editor(self): """ Test creating multiple plants with the plant editor. """ try: import gtk except ImportError: raise SkipTest('could not import gtk') # use our own plant because PlantEditor.commit_changes() will # only work in bulk mode when the plant is in session.new p = Plant(accession=self.accession, location=self.location, code=u'2', quantity=52) self.editor = PlantEditor(model=p) #editor.start() update_gui() rng = '2,3,4-6' for code in utils.range_builder(rng): q = self.session.query(Plant).join('accession').\ filter(and_(Accession.id==self.plant.accession.id, Plant.code==utils.utf8(code))) self.assert_(not q.first(), 'code already exists') widgets = self.editor.presenter.view.widgets # make sure the entry gets a Problem added to it if an # existing plant code is used in bulk mode widgets.plant_code_entry.set_text('1,' + rng) widgets.plant_quantity_entry.set_text('2') update_gui() problem = (self.editor.presenter.PROBLEM_DUPLICATE_PLANT_CODE, self.editor.presenter.view.widgets.plant_code_entry) self.assert_(problem in self.editor.presenter.problems, 'no problem added for duplicate plant code') # create multiple plant codes widgets.plant_code_entry.set_text(rng) update_gui() self.editor.handle_response(gtk.RESPONSE_OK) for code in utils.range_builder(rng): q = self.session.query(Plant).join('accession').\ filter(and_(Accession.id==self.plant.accession.id, Plant.code==utils.utf8(code))) self.assert_(q.first(), 'plant %s.%s not created' % \ (self.accession, code))
def test_range_builder(self): """Test bauble.utils.range_builder """ assert utils.range_builder('1-3') == [1, 2, 3] assert utils.range_builder('1-3,5-7') == [1, 2, 3, 5, 6 ,7] assert utils.range_builder('1-3,5') == [1, 2, 3, 5] assert utils.range_builder('1-3,5,7-9')== [1, 2, 3, 5, 7, 8, 9] assert utils.range_builder('1,2,3,4') == [1, 2, 3, 4] assert utils.range_builder('11') == [11] # bad range strings assert utils.range_builder('-1') == [] assert utils.range_builder('a-b') == [] #self.assertRaises(ParseException, utils.range_builder, '-1') self.assertRaises(CheckConditionError, utils.range_builder, '2-1')
def test_range_builder(self): """Test bauble.utils.range_builder """ assert utils.range_builder('1-3') == [1, 2, 3] assert utils.range_builder('1-3,5-7') == [1, 2, 3, 5, 6, 7] assert utils.range_builder('1-3,5') == [1, 2, 3, 5] assert utils.range_builder('1-3,5,7-9') == [1, 2, 3, 5, 7, 8, 9] assert utils.range_builder('1,2,3,4') == [1, 2, 3, 4] assert utils.range_builder('11') == [11] # bad range strings assert utils.range_builder('-1') == [] assert utils.range_builder('a-b') == [] #self.assertRaises(ParseException, utils.range_builder, '-1') self.assertRaises(CheckConditionError, utils.range_builder, '2-1')
def commit_changes(self): """ """ codes = utils.range_builder(self.model.code) if len(codes) <= 1 or self.model not in self.session.new \ and not self.branched_plant: change = self.presenter.change if self.branched_plant: # branch mode self.branched_plant.quantity -= self.model.quantity change.parent_plant = self.branched_plant if not change.to_location: change.to_location = self.model.location elif change.quantity is None \ or (change.quantity == self.model.quantity and \ change.from_location == self.model.location and \ change.quantity==self.presenter._original_quantity): # if the quantity and location haven't changed then # don't save the change # UPDATE: # TODO: why save the change, what if we want to indicate # a change even if the quantity and location hasn't # changed? utils.delete_or_expunge(change) self.model.change = None else: if self.model.location != change.from_location: # transfer change.to_location = self.model.location elif self.model.quantity > self.presenter._original_quantity \ and not change.to_location: # additions should use to_location change.to_location = self.model.location change.from_location = None else: # removal change.quantity = -change.quantity super(PlantEditor, self).commit_changes() self._committed.append(self.model) return # this method will create new plants from self.model even if # the plant code is not a range....its a small price to pay plants = [] mapper = object_mapper(self.model) # TODO: precompute the _created and _last_updated attributes # incase we have to create lots of plants it won't be too slow # we have to set the properties on the new objects # individually since session.merge won't create a new object # since the object is already in the session import sqlalchemy.orm as orm for code in codes: new_plant = Plant() self.session.add(new_plant) # TODO: can't we user Plant.duplicate here ignore = ('changes', 'notes', 'propagations') for prop in mapper.iterate_properties: if prop.key not in ignore: setattr(new_plant, prop.key, getattr(self.model, prop.key)) new_plant.code = utils.utf8(code) new_plant.id = None new_plant._created = None new_plant._last_updated = None plants.append(new_plant) for note in self.model.notes: new_note = PlantNote() for prop in object_mapper(note).iterate_properties: setattr(new_note, prop.key, getattr(note, prop.key)) new_note.plant = new_plant try: map(self.session.expunge, self.model.notes) self.session.expunge(self.model) super(PlantEditor, self).commit_changes() except: self.session.add(self.model) raise self._committed.extend(plants)