def test_InheritFrom(self): from niprov.inheriting import inheritFrom parentProv = { 'acquired': datetime.now(), 'subject': 'JD', 'protocol': 'X', 'technique': 'abc', 'repetition-time': 1.0, 'epi-factor': 1.0, 'magnetization-transfer-contrast': True, 'diffusion': True, 'echo-time': 123, 'flip-angle': 892, 'inversion-time': 123 } prov = inheritFrom({'a': 1}, parentProv) self.assertEqual(prov['acquired'], parentProv['acquired']) self.assertEqual(prov['subject'], parentProv['subject']) self.assertEqual(prov['protocol'], parentProv['protocol']) self.assertEqual(prov['technique'], parentProv['technique']) self.assertEqual(prov['repetition-time'], parentProv['repetition-time']) self.assertEqual(prov['epi-factor'], parentProv['epi-factor']) self.assertEqual(prov['magnetization-transfer-contrast'], parentProv['magnetization-transfer-contrast']) self.assertEqual(prov['diffusion'], parentProv['diffusion']) self.assertEqual(prov['echo-time'], parentProv['echo-time']) self.assertEqual(prov['flip-angle'], parentProv['flip-angle']) self.assertEqual(prov['inversion-time'], parentProv['inversion-time'])
def test_InheritFrom(self): from niprov.inheriting import inheritFrom parentProv = {'acquired':datetime.now(), 'subject':'JD', 'protocol':'X', 'technique':'abc', 'repetition-time':1.0, 'epi-factor':1.0, 'magnetization-transfer-contrast':True, 'diffusion':True, 'echo-time':123, 'flip-angle':892, 'inversion-time':123} prov = inheritFrom({'a':1}, parentProv) self.assertEqual(prov['acquired'], parentProv['acquired']) self.assertEqual(prov['subject'], parentProv['subject']) self.assertEqual(prov['protocol'], parentProv['protocol']) self.assertEqual(prov['technique'], parentProv['technique']) self.assertEqual(prov['repetition-time'], parentProv['repetition-time']) self.assertEqual(prov['epi-factor'], parentProv['epi-factor']) self.assertEqual(prov['magnetization-transfer-contrast'], parentProv['magnetization-transfer-contrast']) self.assertEqual(prov['diffusion'], parentProv['diffusion']) self.assertEqual(prov['echo-time'], parentProv['echo-time']) self.assertEqual(prov['flip-angle'], parentProv['flip-angle']) self.assertEqual(prov['inversion-time'], parentProv['inversion-time'])
def test_Doesnt_complain_if_parent_is_missing_basic_fields(self): from niprov.inheriting import inheritFrom prov = inheritFrom({'a':1}, {'b':2})
def add(filepath, transient=False, provenance=None, dependencies=Dependencies()): """ Simply register the file. Inspects the file and makes it known to the provenance data, such that image files can be logged that have been created using this file. Useful also for temporary files. Example: (provenance, status) = niprov.add('/path/to/my.nii') Args: filepath (str): Path to the newly created file. transient (bool, optional): Set this to True to indicate that the file is only temporary and future checks should not expect it to be physically present. Defaults to False, assuming that the file remains. provenance (dict, optional): Add the key-value pairs in this dictionary to the provenance record for the new file. Returns: tuple: Tuple of new provenance and status. Status is a string with one of the following values: 'new': File was not known yet and has been added. 'series': The file was deemed part of a series and has been added. 'failed': There was an error inspecting the file. 'known': The file was already known to niprov, nothing happened. 'dryrun': Function called with config.dryrun, database not touched. """ config = dependencies.getConfiguration() file = dependencies.getFileFactory() repository = dependencies.getRepository() listener = dependencies.getListener() filesys = dependencies.getFilesystem() query = dependencies.getQuery() if provenance is None: provenance = {} provenance['transient'] = transient provenance['added'] = datetime.now() provenance['id'] = shortuuid.uuid()[:6] vparts = pkg_resources.get_distribution("niprov").version.split('.') provenance['version-added'] = float(vparts[0] + '.' + ''.join(vparts[1:])) img = file.locatedAt(filepath, provenance=provenance) if config.dryrun: return img if not transient: if not filesys.fileExists(img.location.path): raise IOError(errno.ENOENT, 'File not found', img.location.path) try: img.inspect() except: img.status = 'failed' listener.fileError(img.path) return img if config.attach: img.attach(config.attach_format) if not provenance.get('parents', []): for copy in query.copiesOf(img): if not copy.location == img.location: inheritFrom(img.provenance, copy.provenance) img.provenance['parents'] = [copy.location.toString()] img.provenance['copy-as-parent'] = True listener.usingCopyAsParent(copy) break previousVersion = repository.byLocation(img.location.toString()) series = repository.getSeries(img) if previousVersion: img.keepVersionsFromPrevious(previousVersion) elif series: if series.hasFile(img): img.keepVersionsFromPrevious(series) else: img = series.mergeWith(img) if not previousVersion and not series: repository.add(img) else: repository.update(img) listener.fileAdded(img) return img
def log(new, transformation, parents, code=None, logtext=None, transient=False, script=None, user=None, provenance=None, opts=None, dependencies=Dependencies()): """ Register a transformation that creates a new image (or several). This will retrieve the primary parent's provenance. if no provenance is availale for the primary parent, calls listener.unknownFile. Otherwise, some fields are copied from the primary parent, subject to availability. For instance, if the parent has no 'subject' field, the new file's provenance won't either. Args: new (str or list): Path(s) to the newly created file(s). transformation (str): Name of the operation that has been used. parents (str or list): Path(s) to the file(s) that were used as the basis of the transformation. Assumes that the first file in the list is the primary parent for which basic provenance is known. code (str, optional): Code that was used to generate the new file logtext (str, optional): Any information about the transformation that was logged. script (str, optional): Path to the code file that contains the transformation code. transient (bool, optional): Set this to True to indicate that the file is only temporary and future checks should not expect it to be physically present. Defaults to False, assuming that the file remains. user (string, optional): Name of the user logging provenance. provenance (dict, optional): Add the key-value pairs in this dictionary to the provenance record for the new files. opts (Configuration): General settings for niprov. See :py:mod:`niprov.config` Raises: IOError: '[Errno 2] File not found' is raised if the new file does not exist on the filesystem and is not marked as transient. Returns: BaseFile: New provenance, if multiple files were created, this is a list of images, otherwise, it is a single object. """ repository = dependencies.getRepository() listener = dependencies.getListener() factory = dependencies.getFileFactory() filesys = dependencies.getFilesystem() opts = dependencies.reconfigureOrGetConfiguration(opts) location = dependencies.getLocationFactory() users = dependencies.getUsers() if isinstance(new, basestring): new = [new] if isinstance(parents, basestring): parents = [parents] if provenance is None: provenance = {} #gather provenance common to all new files parents = [location.completeString(p) for p in parents] commonProvenance = provenance commonProvenance['parents'] = parents commonProvenance['transformation'] = transformation commonProvenance['script'] = script commonProvenance['user'] = users.determineUser(user) if code: commonProvenance['code'] = code if logtext: commonProvenance['logtext'] = logtext parent = repository.byLocation(parents[0]) if parent is None: parent = add(parents[0], dependencies=dependencies) listener.addUnknownParent(parents[0]) inheritFrom(commonProvenance, parent.provenance) # do things specific to each new file newImages = [] for newfile in new: singleProvenance = copy.deepcopy(commonProvenance) image = add(newfile, transient=transient, provenance=singleProvenance, dependencies=dependencies) newImages.append(image) # only return one image if only one file was created if len(new) == 1: return image return newImages
def test_Doesnt_complain_if_parent_is_missing_basic_fields(self): from niprov.inheriting import inheritFrom prov = inheritFrom({'a': 1}, {'b': 2})