forked from AmbaPant/mantid
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SelectNexusFilesByMetadata.py
130 lines (107 loc) · 5.24 KB
/
SelectNexusFilesByMetadata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
#pylint: disable=eval-used
from mantid.simpleapi import *
from mantid.kernel import *
from mantid.api import *
class SelectNexusFilesByMetadata(PythonAlgorithm):
_criteria_splitted = []
def category(self):
return "DataHandling\\Nexus"
def summary(self):
return 'Filters nexus files by metadata criteria'
def validateInputs(self):
issues = dict()
criteria = self.getPropertyValue('NexusCriteria')
# at least one nexus entry should be specified
dollars = criteria.count('$')
if dollars % 2 != 0 or dollars < 2:
issues['NexusCriteria'] = 'Make sure the nexus entry name is enclosed with $ sybmols'
else:
# check if the syntax of criteria is valid by replacing the nexus entries with dummy values
self._criteria_splitted = criteria.split('$')
toeval = ''
for i, item in enumerate(self._criteria_splitted):
if i % 2 == 1: # at odd indices will always be the nexus entry names
# replace nexus entry names by 0
toeval += '0'
else:
# keep other portions intact
toeval += item
try:
eval(toeval)
except (NameError, ValueError, SyntaxError):
issues['NexusCriteria'] = 'Invalid syntax, check NexusCriteria.'
return issues
def PyInit(self):
self.declareProperty(MultipleFileProperty('FileList',extensions=['nxs','hdf']),doc='List of input files')
self.declareProperty(name='NexusCriteria',defaultValue='',
doc='Logical expresion for metadata criteria using python syntax. '
'Provide full absolute names for nexus entries enclosed with $ symbol from both sides.')
self.declareProperty(name='Result', defaultValue='', direction=Direction.Output,
doc='Comma separated list of the fully resolved file names satisfying the given criteria.')
def PyExec(self):
# run only if h5py is present
try:
import h5py
except ImportError:
raise RuntimeError('This algorithm requires h5py package. See https://pypi.python.org/pypi/h5py')
outputfiles = ''
# first split by ,
for runs in self.getPropertyValue('FileList').split(','):
filestosum = ''
# then split each by +
for run in runs.split('+'):
with h5py.File(run, 'r') as nexusfile:
if self.checkCriteria(run, nexusfile):
filestosum += run + '+'
if filestosum:
# trim the last +
filestosum = filestosum[:-1]
outputfiles += filestosum + ','
# trim the last ,
if outputfiles:
outputfiles = outputfiles[:-1]
else:
self.log().notice('No files where found to satisfy the criteria, check the FileList and/or NexusCriteria')
self.setPropertyValue('Result',outputfiles)
def checkCriteria(self, run, nexusfile):
toeval = ''
item = None # for pylint
for i, item in enumerate(self._criteria_splitted):
if i % 2 == 1: # at odd indices will always be the nexus entry names
try:
# try to get the entry from the file
entry = nexusfile.get(item)
if len(entry.shape) > 1 or len(entry) > 1:
self.log().warning('Nexus entry %s has more than one dimension or more than one element'
'in file %s. Skipping the file.' % (item, run))
return False
# replace entry name by it's value
value = entry[0]
if str(value.dtype).startswith('|S'):
# string value, need to quote for eval
value = value.decode()
toeval += '\"' + value + '\"'
else:
toeval += str(value)
except (TypeError, AttributeError):
self.log().warning('Nexus entry %s does not exist in file %s. Skipping the file.' % (item, run))
return False
else:
# keep other portions intact
toeval += item
self.log().debug('Expression to be evaluated for file %s :\n %s' % (run, toeval))
try:
return eval(toeval)
except (NameError, ValueError, SyntaxError):
# even if syntax is validated, eval can still throw, since
# the nexus entry value itself can be spurious for a given file
self.log().warning('Invalid value for the nexus entry %s in file %s. Skipping the file.' % (item, run))
return False
# Register algorithm with Mantid
AlgorithmFactory.subscribe(SelectNexusFilesByMetadata)