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

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

added date time validator and data type.

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
20import ConfigParser
21from cStringIO import StringIO
22
23
24# Import standard library modules
25#import ConfigParser
26import os
27import sys
28import re
29import glob 
30# Local modules
31#from common import fixTrueFalse
32import cows_wps.utils.case_sensitive_ordered_config_parser as cp
33
34import logging
35log = logging.getLogger(__name__)
36
37from cows_wps.utils.parse_wps_config import wps_config_dict
38
39def fixTrueFalse(value):
40    "Make true or false value a lower title cased version."
41    if value.lower() in ("true", "false"):
42        value = eval(value.title())
43    return value
44 
45def isValidLengthDescription(item):
46    "Returns False if length description doesn't match patterns allowed and True if it does."
47    # Check "<low>-<high>" pattern first
48    low_high_match = re.match("(\d+)*-(\d+)*$", item)
49    if low_high_match:
50        # Now check low is not bigger than high (only if both provided)
51       
52        (low, high) = [int(x) for x in low_high_match.groups()]
53        if low > high:
54            raise Exception("Minimum array length cannot be greater than maximum: " + item)
55        return True
56
57    # Now check other patterns
58    for pattern in ("\d+$", "(\d+)(,\d+)*$"):
59        if re.match(pattern, item): return True
60   
61    return False
62
63
64def parseDataOutputInputs(outputInputDict):
65    outin_dict = {}
66
67    allowed_types = ("xml", 'complex','xml_complex_value',"string", "float", "int", "bool", "filepath", "bbox", "datetime")
68
69    for item in outputInputDict:
70        item_with_params= item.split(".")
71        param = item_with_params[0]
72
73        if not outin_dict.has_key(param):
74            item_dict = {}
75            item_type = outputInputDict[param].strip().split(".")
76
77            if item_type[0] not in allowed_types:
78                raise Exception("Type must be %s, cannot recognise: %s" % (allowed_types, item_type[0]))
79            else:
80                item_dict["type"] = item_type[0]
81
82                if item_type[0] == "xml_complex_value":
83                    try:
84                        item_dict["template"] = outputInputDict[param+".template"]
85                    except:
86                        raise Exception("xml_complex_value type must have a template")
87                   
88                if len(item_type) > 1:
89                    if item_type[1] == "list":
90                        item_dict["item_type"] = item_type[1]
91                    else:
92                        raise Exception("Type must be 'list', cannot recognise: " + item_type[1])
93                else:
94                    item_dict["item_type"] = "item"
95
96                if outputInputDict.has_key(param+".possible_values"):
97                    item_dict["possible_values"] = outputInputDict[param+".possible_values"].strip().split(",")
98                else:
99                    item_dict["possible_values"]=None
100
101                if outputInputDict.has_key(param+".default"):
102                    item_dict["default"] = fixTrueFalse(outputInputDict[param+".default"].strip())
103
104                if outputInputDict.has_key(param+".optional"):
105                    item_dict["optional"] = fixTrueFalse(outputInputDict[param+".optional"].strip())
106
107                if outputInputDict.has_key(param+".length"):
108                    if isValidLengthDescription(outputInputDict[param+".length"].strip()):
109                        item_dict["allowed_length"] = outputInputDict[param+".length"].strip().replace(" ","-")
110                    else:
111                        raise Exception("varilable length %s not recognised" % outputInputDict[param+".length"].strip())
112                else:
113                    item_dict["allowed_length"] = None
114
115                if outputInputDict.has_key(param+".schema"):
116                    item_dict["schema"] = outputInputDict[param+".schema"].strip()
117                else:
118                    item_dict["schema"] = None
119
120                if outputInputDict.has_key(param+".encoding"):
121                    item_dict["encoding"] = outputInputDict[param+".encoding"].strip()
122
123                if outputInputDict.has_key(param+".mime_type"):
124                    item_dict["mime_type"] = outputInputDict[param+".mime_type"].strip()
125                else:
126                    item_dict["mime_type"] = None
127
128                if  outputInputDict.has_key(param + ".basedir"):
129                    item_dict["basedir"] = outputInputDict[param+ ".basedir"].strip()
130
131                if outputInputDict.has_key(param + ".extent"):
132                    item_dict["extent"] = outputInputDict[param + ".extent"].strip()
133
134                outin_dict[param.strip()] = item_dict
135
136    return outin_dict
137
138def parseWpsInterface(wps_interface):
139    wps_dict = {}
140    for item in wps_interface:
141        value = wps_interface[item].strip()
142        if item == "response_types":
143                mappings = value.split(" ")
144                map_dict = {}
145                for i in mappings:
146                   map = i.split(":")
147                   if len (map) ==2 :
148                       map_dict[map[0]] = map[1]
149                   else:
150                       raise Exception ('Invalid response types values')
151                wps_dict[item] = map_dict
152        else:
153                wps_dict[item]= fixTrueFalse(value)
154
155
156    if wps_dict.has_key('response_types') == False:
157        wps_dict['response_types'] = {}
158
159#    log.debug('wps_dict["process_type"] = %s' % wps_dict.has_key('process_type'))
160
161    if not wps_dict.has_key('process_type'):
162        raise Exception ('A correct process type must be specified')
163    else:
164        if wps_dict.has_key('status'):
165                if wps_dict['status'] and wps_dict['process_type'] == 'sync':
166                        raise Exception ('Status cannot supported by a synchronous process')
167    return wps_dict
168   
169def parseGlobals(globals):
170    identifier= ""
171    global_dict={}
172    for item in globals:
173        if item == "Identifier":
174                identifier = globals[item].strip()
175        else:
176                global_dict[item] = fixTrueFalse(globals[item].strip())
177    return identifier, global_dict
178               
179def makeCapabilitiesConfigDict(config_file_list=None): #fname=capabilities_file):
180    '''Parses capabilities config file to return dictionary of:
181    {"identifiers" = [id1, id2...]
182    id1 = {"wps_interface":{"call_locally": "package.module#callable",....},
183           "globals" : {"Title" : "jsdkfjdslfj", "Abstract" : "lllll"...},
184           "DataInputs" : {"plotType" : {"item_type": "array",
185                                         "type": "string"
186                                         "allowed_length": "1-5",
187                                         "optional": True,
188                                         "default": True,
189                                         "enumeration" : ["yvsx", "....]},
190           "OrderedDataInputs": [key1, key2,....],
191           "ProcessOutputs" : {"title": {"item_type" : "item",
192                                         "type" : "string",
193                                         "allowed_length" : "-",
194                                         "enumeration": "-" } }
195    '''
196    global caps_config_dict
197   
198    if config_file_list == None:
199        try:
200            config_dir = wps_config_dict['proc_config_dir']
201        except KeyError:
202            log.warn('No process_config_dir option in application configuration')
203            base_dir = os.environ.get("WPS_BASE", ".")
204            config_dir = os.path.join(base_dir, "configs")
205           
206        config_file_list = glob.glob("%s/*.ini" % config_dir)
207   
208    caps_config_dict={}
209    ids = []
210    caps_config_dict["Identifiers"] = ids
211    for confFile in config_file_list:
212#        log.debug('Reading process config file %s' % confFile)
213       
214        try:
215            process_config = {}
216            config =  cp.CaseSensitiveOrderedConfigParser()
217            config.read([confFile])
218
219            identifier, process_config["globals"] = parseGlobals(dict(config.items("globals")))
220                                                         
221            process_config["wps_interface"] = parseWpsInterface(dict(config.items("wps_interface")))
222           
223            process_config["DataInputs"] = parseDataOutputInputs(dict(config.items("DataInputs")))
224            process_config["ProcessOutputs"] = parseDataOutputInputs(dict(config.items("ProcessOutputs")))
225           
226            # Correct code for parsing in options ordered within each section
227            all_data_input_options_ordered = config._option_orders["DataInputs"]
228            process_config["OrderedDataInputs"] = [di_opt for di_opt in all_data_input_options_ordered if di_opt.find(".") < 0]
229
230
231            ids.append(identifier)
232            caps_config_dict[identifier] = process_config
233        except:
234            print >> sys.stderr, "Exception occurred while reading config file %s" % (confFile)
235            raise
236
237
238caps_config_dict = None
239makeCapabilitiesConfigDict()
240
241if __name__=="__main__":
242    #setup the test wps dict and re-import
243    import cows_wps.tests.setup_test_wps_config
244    from cows_wps.utils.parse_wps_config import wps_config_dict
245   
246    makeCapabilitiesConfigDict()
247   
248   
249    def printDict(d, indent=None):
250        if indent == None: indent = ''
251       
252        for k in sorted(d):
253           
254            if d[k].__class__ == dict:
255                print indent + k, ':'
256                printDict(d[k], indent + ' ')
257            else:
258                print indent + k,'=',d[k], d[k].__class__
259   
260    printDict(caps_config_dict['GetData'])
261    print caps_config_dict['GetData'].keys()
262    print caps_config_dict['GetData']['DataInputs']
263
264
Note: See TracBrowser for help on using the repository browser.