def test_listyness(self): old = range(10) new = ObservableList(old) assert old == new # Make them differ in first elem old[0] = 17 assert old != new assert old[3] == new[3] assert old[3:9:2] == new[3:9:2] with pytest.raises(IndexError): new[17] # Delete 1st elem, should be the same again del new[0] del old[0] assert old == new # Check len assert len(new) == 9 assert new.length == 9 new.insert(0, 'foo') old.insert(0, 'foo') assert old == new return
def test_listyness(self): old = range(10) new = ObservableList(old) assert old == new # Make them differ in first elem old[0] = 17 assert old != new assert old[3] == new[3] assert old[3:9:2] == new[3:9:2] with pytest.raises(IndexError): new[17] # Delete 1st elem, should be the same again del new[0] del old[0] assert old == new # Check len assert len(new) == 9 assert new.length == 9 new.insert(0, 'foo') old.insert(0, 'foo') assert old == new return
def test_copy(self): import copy old = ObservableList(range(3)) new = copy.copy(old) new.append('wibble') with pytest.raises(IndexError): old[3]
def test_observation(self): def ResetAll(obs): for obPair in obs: for ob in obPair: ob.Reset() return def CheckObservers(observers, pattern): for obPair, shouldChange in itertools.izip(observers, pattern): if shouldChange: for ob in obPair: assert ob.CallTime is not None assert obPair[0].CallTime < obPair[1].CallTime else: for ob in obPair: assert ob.CallTime is None return lst = ObservableList() observers = self.MakeListObservers(lst) # Add an elem lst.append(Circle(4)) CheckObservers(observers, (True, False, False, True)) # Replace one ResetAll(observers) lst[0] = 18 CheckObservers(observers, (False, False, True, False)) # Delete one ResetAll(observers) del lst[0] CheckObservers(observers, (False, True, False, True)) return
def test_observation(self): def ResetAll(obs): for obPair in obs: for ob in obPair: ob.Reset() return def CheckObservers(observers, pattern): for obPair, shouldChange in itertools.izip(observers, pattern): if shouldChange: for ob in obPair: assert ob.CallTime is not None assert obPair[0].CallTime < obPair[1].CallTime else: for ob in obPair: assert ob.CallTime is None return lst = ObservableList() observers = self.MakeListObservers(lst) # Add an elem lst.append(Circle(4)) CheckObservers(observers, (True, False, False, True)) # Replace one ResetAll(observers) lst[0] = 18 CheckObservers(observers, (False, False, True, False)) # Delete one ResetAll(observers) del lst[0] CheckObservers(observers, (False, True, False, True)) return
class Profile(Observable): """This class represents the parameters necessary to perform a setup for HemeLb and supplies the functionality to do it. The required parameters are below with defaults and all must be specified to actually create the setup files. """ # Required parameters and defaults. _CloneOrder = ['StlFileUnitId', 'StlFile', 'VoxelSize'] _Args = { 'StlFile': None, 'StlFileUnitId': 1, 'Iolets': ObservableList(), 'VoxelSize': 0., 'TimeStepSeconds': 1e-4, 'DurationSeconds': 5.0, 'SeedPoint': Vector(), 'OutputGeometryFile': None, 'OutputXmlFile': None } _UnitChoices = [metre, millimetre, micrometre] def __init__(self, **kwargs): """Required arguments may be set here through keyword arguments. """ # Set attributes on this instance according to the keyword # args given here or the default dict if they aren't present. for a, default in Profile._Args.iteritems(): setattr(self, a, kwargs.pop(a, copy(default))) continue # Raise an error on a kwarg we don't understand for k in kwargs: raise TypeError( "__init__() got an unexpected keyword argument '%'" % k) # We need a reader to get the polydata self.StlReader = vtkSTLReader() # And a way to estimate the voxel size self.SideLengthCalculator = AverageSideLengthCalculator() self.SideLengthCalculator.SetInputConnection( self.StlReader.GetOutputPort()) # Dependencies for properties self.AddDependency('HaveValidStlFile', 'StlFile') self.AddDependency('HaveValidOutputXmlFile', 'OutputXmlFile') self.AddDependency('HaveValidOutputGeometryFile', 'OutputGeometryFile') self.AddDependency('HaveValidSeedPoint', 'SeedPoint.x') self.AddDependency('HaveValidSeedPoint', 'SeedPoint.y') self.AddDependency('HaveValidSeedPoint', 'SeedPoint.z') self.AddDependency('IsReadyToGenerate', 'HaveValidStlFile') self.AddDependency('IsReadyToGenerate', 'HaveValidOutputXmlFile') self.AddDependency('IsReadyToGenerate', 'HaveValidOutputGeometryFile') self.AddDependency('IsReadyToGenerate', 'HaveValidSeedPoint') self.AddDependency('StlFileUnit', 'StlFileUnitId') self.AddDependency('VoxelSizeMetres', 'VoxelSize') self.AddDependency('VoxelSizeMetres', 'StlFileUnit.SizeInMetres') # When the STL changes, we should reset the voxel size and # update the vtkSTLReader. self.AddObserver('StlFile', self.OnStlFileChanged) return def UpdateAttributesBasedOnCmdLineArgs(self, cmdLineArgsDict): """ Helper method that takes a dictionary with the arguments provided to the setup tool via command line (cmdLineArgsDict) and sets/updates the relevant class attributes. """ # Some attributes need to be set in a given order to avoid side effects. # Set them first for attrName in self._CloneOrder: if attrName in cmdLineArgsDict: val = cmdLineArgsDict[attrName] if val is not None: setattr(self, attrName, val) cmdLineArgsDict.pop(attrName) # Set the rest for k, val in cmdLineArgsDict.iteritems(): if val is not None: setattr(self, k, val) def OnStlFileChanged(self, change): self.StlReader.SetFileName(self.StlFile) self.VoxelSize = self.SideLengthCalculator.GetOutputValue() return @property def HaveValidStlFile(self): """Read only property indicating if our STL file is valid. """ return IsFileValid(self.StlFile, ext='.stl', exists=True) @property def HaveValidSeedPoint(self): if np.isfinite(self.SeedPoint.x) and np.isfinite( self.SeedPoint.y) and np.isfinite(self.SeedPoint.z): return True return False @property def HaveValidOutputXmlFile(self): return IsFileValid(self.OutputXmlFile, ext='.xml') @property def HaveValidOutputGeometryFile(self): return IsFileValid(self.OutputGeometryFile, ext='.gmy') @property def IsReadyToGenerate(self): """Read only property indicating if we have enough information to do the setup. """ if not self.HaveValidSeedPoint: return False if not self.HaveValidOutputXmlFile: return False if not self.HaveValidOutputGeometryFile: return False if not self.HaveValidStlFile: return False return True @property def StlFileUnit(self): return self._UnitChoices[self.StlFileUnitId] @property def VoxelSizeMetres(self): return self.VoxelSize * self.StlFileUnit.SizeInMetres @VoxelSizeMetres.setter def VoxelSizeMetres(self, value): self.VoxelSize = value / self.StlFileUnit.SizeInMetres return def LoadFromFile(self, filename): restored = cPickle.Unpickler(file(filename)).load() # Now adjust the paths of filenames relative to the Profile file. # Note that this will work if an absolute path has been pickled as # os.path.join will discard previous path elements when it gets an # absolute path. (Of course, this will only work if that path is # correct!) basePath = os.path.dirname(os.path.abspath(filename)) restored.StlFile = os.path.abspath( os.path.join(basePath, restored.StlFile)) restored.OutputGeometryFile = os.path.abspath( os.path.join(basePath, restored.OutputGeometryFile)) restored.OutputXmlFile = os.path.abspath( os.path.join(basePath, restored.OutputXmlFile)) self.CloneFrom(restored) return def Save(self, filename): outfile = file(filename, 'w') self.BasePath = os.path.dirname(filename) try: pickler = cPickle.Pickler(outfile, protocol=2) pickler.dump(self) finally: del self.BasePath return def Generate(self): from HemeLbSetupTool.Model.OutputGeneration import PolyDataGenerator generator = PolyDataGenerator(self) generator.Execute() return def ResetVoxelSize(self, ignored=None): """Action to reset the voxel size to its default value. """ self.VoxelSize = self.SideLengthCalculator.GetOutputValue() return def __getstate__(self): # First, use the superclass's getstate state = Observable.__getstate__(self) # Now we need to make the paths relative to the directory of the pickle file state['StlFile'] = os.path.relpath(self.StlFile, self.BasePath) state['OutputXmlFile'] = os.path.relpath(self.OutputXmlFile, self.BasePath) state['OutputGeometryFile'] = os.path.relpath(self.OutputGeometryFile, self.BasePath) return state pass