source: cows_wps/trunk/cows_wps/process_handler/validate_arguments.py @ 5615

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows_wps/trunk/cows_wps/process_handler/validate_arguments.py@5615
Revision 5615, 8.3 KB checked in by spascoe, 11 years ago (diff)

COWS WPS package copied from
 http://proj.badc.rl.ac.uk/svn/dcip/cows-wps/trunk.

This is a stripped down version of the DDP WPS. Some features are
removed and others have been deactivated until we reimplement them in a
more generic way.

Line 
1"""
2validate_arguments.py
3=====================
4
5Takes an argument dictionary being sent to a WPS process (or optionally to any callable
6object) and checks contents against the argument signature defined in the parsed
7configuration file.
8
9Holds ValidateArguments class to do this.
10
11Requires third party typecheck package to be installed.
12
13"""
14# Import standard library modules
15import os
16import sys
17import re
18
19import logging
20log = logging.getLogger(__name__)
21
22# Import local modules
23import cows_wps.utils.parse_capabilities_config as parse_capabilities_config
24from cows_wps.utils.parse_capabilities_config import caps_config_dict
25
26
27def convertType(dtype, item):
28    "Returns item converted to dtype data type or raises error."
29   
30    if dtype == "bool":
31       
32        if item.__class__ == bool:
33            return item
34       
35        item = parse_capabilities_config.fixTrueFalse(item)
36        if item not in (True, False):
37            raise Exception("Data type of '" + str(item) + "' must be 'True' or 'False'.")
38        else:
39            return item
40
41    if dtype == "xml": 
42        dtype = "string"
43
44    transformer = dtype
45    if transformer == "string": transformer = "str"
46   
47    try:
48        item = eval("%s('%s')" % (transformer, item))
49    except:
50        raise Exception("Could not convert item '" + str(item) + "' to data type '" + `dtype` + ".")
51   
52    return item
53
54
55def checkArgInList(item, enumeration):
56    "Returns True if item is in enumeration and raises error if not."
57   
58    if item not in enumeration:
59       
60        #check that the enumerations are strings
61        if type(enumeration[0]) == str:
62            enumerationString = ",".join(enumeration)
63        else:
64            enumerationString = ",".join([str(x) for x in enumeration])
65
66        raise Exception("Item %s not allowed in enumerated list: %s" % (item, enumerationString))
67   
68    return True
69
70
71def parseSimpleItem(item, dtype, enumeration):
72    """
73    Returns a parsed and correctly typed item checking it is of type dtype
74    and it is in enumeration if provided.
75    """
76    item = convertType(dtype, item)
77
78    # Check if enumeration specified and if given values are allowed
79    if enumeration:
80        enum_typed = [convertType(dtype, x) for x in enumeration] 
81        checkArgInList(item, enum_typed)   
82   
83    return item
84
85
86def parseSimpleArray(item, dtype, allowed_length, enumeration):
87    """
88    Returns a list of items following pattern '<x>|<y>|<z>',
89    checking against the valid lengths in allowed_length.
90    """
91#    log.debug('parseSimpleArray: allowed_length = %s' % allowed_length)
92    if type(item) in (type("string"), type(u"hi")):
93        items = item.split("|")
94    else:
95        items = item
96   
97#    log.debug('parseSimpleArray: %s' % ((item, dtype, allowed_length, enumeration),))
98
99    # Generate array
100    array = [convertType(dtype, x) for x in items]
101
102    # Check length of array is allowed
103    # Simple list of lengths first
104    l = len(array)
105    if allowed_length != None:
106   
107        if allowed_length.find("-") < 0:
108            allowed_lengths = [int(x) for x in allowed_length.split(",")]
109            if l not in allowed_lengths:
110                raise Exception("Array length of %s is not in list of allowed lengths: %s" \
111                                % (l, allowed_lengths))
112
113        elif allowed_length.find("-") > -1:     
114            low_high_match = re.match("(\d+)*-(\d+)*$", allowed_length.strip())
115            (low, high) = low_high_match.groups()
116            if low != None:
117                if l < int(low):
118                    raise Exception("Array length of '" + str(l) + "' is less than minimum allowed: " + str(low))
119
120            if high != None:
121                    if l > int(high):
122                        raise Exception("Array length of '" + str(l) + "' is greater than maximum allowed: " + str(high))
123
124    # Check if enumeration specified and if given values are allowed
125    if enumeration:
126        enum_typed = [convertType(dtype, x) for x in enumeration] 
127        for i in array:
128            checkArgInList(i, enum_typed)   
129
130    return array
131
132
133class ValidateArguments:
134
135    def __init__(self, process_name, arg_dict, config_file="capabilities.ini"):
136        "Initialises dictionaries of input and validation rules."
137        log.info("Validation Arguments object created")
138        self.process_name = process_name
139        self.args = arg_dict
140#        log.debug('Config file: %s' % config_file)
141 
142        try:
143            self.valids = caps_config_dict[self.process_name]
144        except:
145            raise Exception("Cannot find entry for process '" + self.process_name + "' in config file.")
146
147    def validate(self):
148        """
149        Performs validation.
150        Raises exception if bad arguments given.
151        Returns a new dictionary of valid arguments of the correct type if valid.
152        """
153        new_dict = {}
154
155#        log.info("running validation")
156
157        # Step through each arg testing for validity
158        arg_names = self.valids["DataInputs"].keys()
159        arg_names.sort()
160               
161        log.debug("Validating list of arguments:(%s)" % (self.args,))
162       
163#        log.debug("NOTE: policy of this code is to ignore any unknown arguments but not to raise an exception")
164        for name in arg_names:
165#            log.debug('Validating argument %s' % name)
166            try:
167                # define d as the entry for this particular argument
168                d = self.valids["DataInputs"][name]
169               
170                # If did not get this arg test whether allowed and insert default value if given
171                if name not in self.args.keys():
172                    log.debug ("DataInput %s not present in args" % (name,))
173                    #check if it is optional or has a default value
174                   
175                    if d.has_key("default"):
176                        value = d["default"]
177                        new_dict[name] = parseValue(value, d)
178                        log.debug("Using default value of %s for %s" % (new_dict[name], name))
179                       
180                    elif d.has_key('optional'):
181   
182                        if not d['optional']:
183                            raise Exception("key %s does not exist in args (%s)" % (name, self.args.keys()))
184       
185                    else:
186                        raise Exception("key %s does not exist in args (%s)" % (name, self.args.keys()))
187                   
188                    continue
189   
190                # Test the value provided
191                value_given = self.args[name]
192             
193                new_dict[name] = parseValue(value_given, d)
194#                log.debug("Using value of %s for %s" % (new_dict[name], name))
195               
196            except:
197                log.warning("Error occurred while parsing the %s parameter." \
198                            % (name,))
199                raise
200       
201        #log a warning if there are parameters that arn't needed
202        for recievedParam in self.args.keys():
203            if recievedParam not in arg_names:
204                log.warning("Parameter %s was recieved but not needed for a %s process." \
205                            % (recievedParam, self.process_name))
206       
207#        log.debug("VALID DICT: %s" % new_dict)
208        return new_dict
209
210def parseValue(value, d):
211    parsedValue = None
212   
213    if d["item_type"] == "list":
214        parsedValue = parseSimpleArray(value, d["type"], d["allowed_length"], d["possible_values"])
215    elif d["item_type"] == "item":
216        parsedValue = parseSimpleItem(value, d["type"], d["possible_values"])
217    else:
218        raise ValueError(d["item_type"])   
219
220    return parsedValue
221
222def makeDict(qs):
223        dct = {}
224        items = qs.split(",")
225        for c in range(0, len(items)-1, 2):
226            dct[items[c]] = items[(c + 1)]
227        return dct
228
229if __name__ == "__main__":
230
231
232    qs = ("Username,astephens,RequestID,session32432,Dataset,probdata,Variables,precip,EmissionsScenarios,a1b,",
233         "TimeSlices,2020-2049|2030-2059,TemporalAveragingPeriod,sep,LocationType,region,Location,south_west,",
234         "ProbabilityDataType,cdf,ImageOutputFormat,ps,ImageWidth,900,ImageHeight,600,",
235         "LegendPosition,bc,YLimits,0|100")
236
237    qs = "".join(qs)
238   
239    dct = makeDict(qs)
240    x = ValidateArguments("AsyncTest", dct, ["/home/ashaon/wps/wps-ng_new/wps-ng/configs/AsyncTest.ini"])
241    print x.validate()
Note: See TracBrowser for help on using the repository browser.