source: cows_wps/trunk/cows_wps/utils/parse_capabilities_config.py @ 7535

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows_wps/trunk/cows_wps/utils/parse_capabilities_config.py@7575
Revision 7535, 11.0 KB checked in by astephen, 9 years ago (diff)

Fixed to async argument handler working.

Line 
1"""
2parseCapabilitiesConfig.py
3==========================
4
5Code to parse the capabilities.ini config file for WPS in Python Paste.
6
7Follows rules set out in:
8
9http://proj.badc.rl.ac.uk/dcip/wiki/UkcipDdp/Tasks/BADCDevtTeam/WPSCode/DataTypeDescriptions
10
11Name of entry    Values (or patterns)    Comments
12-------------------------------------------------
13Sequence or not         "array" OR "item"       Only one of these used for every single entry
14Type (or python type)   "string", "float", "int", OR "bool"     Booleans must be expressed as "True" or "False"
15Length restrictions     <low>-<high>    Only relevant to "array" type. <low> and/or <high> can be omitted. Use just "-" for non-array types.
16Keywords        "default:<default_value>" AND/OR "optional"     None, one or both, comma-separated. For neither just use "-"
17Enumerated Values       <s1>,<s2>,<s3>  Comma-separated list of values that all entries must be one of. Use "-" for none.
18"""
19
20# Import standard library modules
21import ConfigParser
22from cStringIO import StringIO
23import time
24import datetime
25import os
26import sys
27import re
28import glob 
29
30# Local modules
31import cows_wps.utils.case_sensitive_ordered_config_parser as cp
32
33import logging
34log = logging.getLogger(__name__)
35
36from cows_wps.utils.parse_wps_config import wps_config_dict
37
38def fixTrueFalse(value):
39    "Make true or false value a lower title cased version."
40    if value.lower() in ("true", "false"):
41        value = eval(value.title())
42    return value
43 
44def isValidLengthDescription(item):
45    "Returns False if length description doesn't match patterns allowed and True if it does."
46    # Check "<low>-<high>" pattern first
47    low_high_match = re.match("(\d+)*-(\d+)*$", item)
48    if low_high_match:
49        # Now check low is not bigger than high (only if both provided)
50       
51        (low, high) = [int(x) for x in low_high_match.groups()]
52        if low > high:
53            raise Exception("Minimum array length cannot be greater than maximum: " + item)
54        return True
55
56    # Now check other patterns
57    for pattern in ("\d+$", "(\d+)(,\d+)*$"):
58        if re.match(pattern, item): return True
59   
60    return False
61
62
63def commaSplitOrNone(s):
64    if s == None:
65        return None
66
67    return s.strip().split(",")
68
69
70def stripOrNone(s):
71    if s == None:
72        return None
73
74    return s.strip()
75
76def boolOrFalse(s):
77    if s:
78        return fixTrueFalse(s.strip())
79
80    return False
81
82
83
84def parseDataOutputInputs(outputInputDict):
85    outin_dict = {}
86
87    allowed_types = ("xml", 'complex','xml_complex_value',"string", "float", "int", "bool", "filepath", "bbox", "datetime")
88    additional_param_options = ("extent", "basedir", 
89                               "possible_values_url_template",
90                               "possible_values_xml_path")
91
92    # Create short name for d
93    d = outputInputDict
94
95    for item in d:
96
97        item_with_params = item.split(".")
98        p = item_with_params[0]
99
100        if not outin_dict.has_key(p):
101
102            item_dict = {}
103            item_type = d[p].strip().split(".")
104
105            if item_type[0] not in allowed_types:
106                raise Exception("Type must be %s, cannot recognise: %s" % (allowed_types, item_type[0]))
107            else:
108                item_dict["type"] = item_type[0]
109
110                if item_type[0] == "xml_complex_value":
111                    try:
112                        item_dict["template"] = d[p + ".template"]
113                    except:
114                        raise Exception("xml_complex_value type must have a template")
115                   
116                if len(item_type) > 1:
117                    if item_type[1] == "list":
118                        item_dict["item_type"] = item_type[1]
119                    else:
120                        raise Exception("Type must be 'list', cannot recognise: " + item_type[1])
121                else:
122                    item_dict["item_type"] = "item"
123
124                item_dict["possible_values"] = commaSplitOrNone(d.get(p + ".possible_values", None)) 
125
126                item_dict["dynamic"] = boolOrFalse(d.get(p + ".dynamic", False))
127
128                """
129                if d.has_key(p + ".possible_values"):
130                    item_dict["possible_values"] = d[p + ".possible_values"].strip().split(",")
131                else:
132                    item_dict["possible_values"]=None
133"""
134
135                if d.has_key(p + ".default"):
136                    value = fixTrueFalse(d[p + ".default"].strip()) 
137                    if value == "now":
138                        value = apply(datetime.datetime, time.localtime(time.time())[:6])
139
140                    item_dict["default"] = value
141
142                if d.has_key(p + ".optional"):
143                    item_dict["optional"] = fixTrueFalse(d[p + ".optional"].strip())
144
145                if d.has_key(p + ".length"):
146                    if isValidLengthDescription(d[p + ".length"].strip()):
147                        item_dict["allowed_length"] = d[p + ".length"].strip().replace(" ","-")
148                    else:
149                        raise Exception("Variable length %s not recognised" % d[p + ".length"].strip())
150                else:
151                    item_dict["allowed_length"] = None
152
153                # Loop through items that are strings or should be set to None
154                for i in ("schema", "encoding", "mime_type"):
155
156                    item_dict[i] = stripOrNone(d.get(p + "." + i, None))
157
158                """
159                if d.has_key(p + ".schema"):
160                    item_dict["schema"] = d[p + ".schema"].strip()
161                else:
162                    item_dict["schema"] = None
163
164                if d.has_key(p + ".encoding"):
165                    item_dict["encoding"] = d[p + ".encoding"].strip()
166
167                if d.has_key(p + ".mime_type"):
168                    item_dict["mime_type"] = d[p + ".mime_type"].strip()
169                else:
170                    item_dict["mime_type"] = None
171"""
172
173                for add_option in additional_param_options:
174                    key_name = p + "." + add_option
175
176                    if d.has_key(key_name):
177                        value = d[key_name].strip()
178                        item_dict[add_option] = value
179
180                outin_dict[p.strip()] = item_dict
181
182    return outin_dict
183
184def parseWpsInterface(wps_interface):
185    wps_dict = {}
186    for item in wps_interface:
187        value = wps_interface[item].strip()
188        if item == "response_types":
189                mappings = value.split(" ")
190                map_dict = {}
191                for i in mappings:
192                   map = i.split(":")
193                   if len (map) ==2 :
194                       map_dict[map[0]] = map[1]
195                   else:
196                       raise Exception ('Invalid response types values')
197                wps_dict[item] = map_dict
198        else:
199                wps_dict[item]= fixTrueFalse(value)
200
201
202    if wps_dict.has_key('response_types') == False:
203        wps_dict['response_types'] = {}
204
205#    log.debug('wps_dict["process_type"] = %s' % wps_dict.has_key('process_type'))
206
207    if not wps_dict.has_key('process_type'):
208        raise Exception ('A correct process type must be specified')
209    else:
210        if wps_dict.has_key('status'):
211                if wps_dict['status'] and wps_dict['process_type'] == 'sync':
212                        raise Exception ('Status cannot supported by a synchronous process')
213    return wps_dict
214   
215def parseGlobals(globals):
216    identifier= ""
217    global_dict={}
218    for item in globals:
219        if item == "Identifier":
220                identifier = globals[item].strip()
221        else:
222                global_dict[item] = fixTrueFalse(globals[item].strip())
223    return identifier, global_dict
224               
225def makeCapabilitiesConfigDict(config_file_list=None): #fname=capabilities_file):
226    '''Parses capabilities config file to return dictionary of:
227    {"identifiers" = [id1, id2...]
228    id1 = {"wps_interface":{"call_locally": "package.module#callable",....},
229           "globals" : {"Title" : "jsdkfjdslfj", "Abstract" : "lllll"...},
230           "DataInputs" : {"plotType" : {"item_type": "array",
231                                         "type": "string"
232                                         "allowed_length": "1-5",
233                                         "optional": True,
234                                         "default": True,
235                                         "enumeration" : ["yvsx", "....]},
236           "OrderedDataInputs": [key1, key2,....],
237           "ProcessOutputs" : {"title": {"item_type" : "item",
238                                         "type" : "string",
239                                         "allowed_length" : "-",
240                                         "enumeration": "-" } }
241    '''
242    global caps_config_dict
243   
244    if config_file_list == None:
245        try:
246            config_dir = wps_config_dict['proc_config_dir']
247        except KeyError:
248            log.warn('No process_config_dir option in application configuration')
249            base_dir = os.environ.get("WPS_BASE", ".")
250            config_dir = os.path.join(base_dir, "configs")
251           
252        config_file_list = glob.glob("%s/*.ini" % config_dir)
253   
254    caps_config_dict={}
255    ids = []
256    caps_config_dict["Identifiers"] = ids
257    for confFile in config_file_list:
258#        log.debug('Reading process config file %s' % confFile)
259       
260        try:
261            process_config = {}
262            config =  cp.CaseSensitiveOrderedConfigParser()
263            config.read([confFile])
264
265            identifier, process_config["globals"] = parseGlobals(dict(config.items("globals")))
266                                                         
267            process_config["wps_interface"] = parseWpsInterface(dict(config.items("wps_interface")))
268           
269            process_config["DataInputs"] = parseDataOutputInputs(dict(config.items("DataInputs")))
270            process_config["ProcessOutputs"] = parseDataOutputInputs(dict(config.items("ProcessOutputs")))
271           
272            # Correct code for parsing in options ordered within each section
273            all_data_input_options_ordered = config._option_orders["DataInputs"]
274            process_config["OrderedDataInputs"] = [di_opt for di_opt in all_data_input_options_ordered if di_opt.find(".") < 0]
275
276
277            ids.append(identifier)
278            caps_config_dict[identifier] = process_config
279        except:
280            print >> sys.stderr, "Exception occurred while reading config file %s" % (confFile)
281            raise
282
283
284caps_config_dict = None
285makeCapabilitiesConfigDict()
286
287if __name__=="__main__":
288    #setup the test wps dict and re-import
289    import cows_wps.tests.setup_test_wps_config
290    from cows_wps.utils.parse_wps_config import wps_config_dict
291   
292    makeCapabilitiesConfigDict()
293   
294   
295    def printDict(d, indent=None):
296        if indent == None: indent = ''
297       
298        for k in sorted(d):
299           
300            if d[k].__class__ == dict:
301                print indent + k, ':'
302                printDict(d[k], indent + ' ')
303            else:
304                print indent + k,'=',d[k], d[k].__class__
305   
306    printDict(caps_config_dict['GetData'])
307    print caps_config_dict['GetData'].keys()
308    print caps_config_dict['GetData']['DataInputs']
309
310
Note: See TracBrowser for help on using the repository browser.