source: TI03-DataExtractor/trunk/pydxs/common.py @ 1160

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/trunk/pydxs/common.py@1160
Revision 1160, 11.2 KB checked in by astephen, 14 years ago (diff)

A number of minor bug-fixes including full time validation in client.

Line 
1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
5"""
6common.py
7=========
8
9Holds common functions and classes used in the package.
10
11"""
12
13# Import python modules
14import os, re
15
16# Import package modules
17from serverConfig import *
18
19# Set up commmon variables. These are CAPITALISED to
20# improve visibility in other modules.
21
22STAGES=["DatasetGroupPage", "DatasetPage", "VariablesPage", "DomainPage", "ResultsPage"]
23
24DOMAIN_PARAMS=("start_time", "end_time", "time_interval", "horiz_domain", 
25                      "resolution", "vertical_units", "vertical_domain", 
26                       "outputFormat")
27
28TIME_KEYS=["Year", "Month", "Day", "Hour", "Minute", "Second"]
29
30HORIZ_KEYS=["northernExtent", "easternExtent", "southernExtent", "westernExtent"]
31
32CF_METADATA_GLOBAL_ATTRIBUTE_KEYS="Conventions title source institution history references comment".split()
33
34# Set up common functions
35
36def mapFileFormatToExtension(format):
37    """
38    Returns a suitable file extension for a known file format.
39    """
40    extMap={"CSML/NetCDF":"nc", "NetCDF":"nc", "NASA Ames":"na"}
41    return extMap[format]
42   
43
44def createTimeKeyList():
45    """
46    Returns all the separate date and time component arguments required as a list.
47    """
48    allTimeKeys=[]
49    for ts in ["start", "end"]:
50        for i in range(1, MAX_NUM_DATASETS+1):
51            for key in TIME_KEYS:
52                allTimeKeys.append("%s%s_%s" % (ts, key, i))
53    return allTimeKeys
54
55
56def isUndefined(dict, item): 
57    """
58    Function that returns 1 if item is not a key in dict or
59    is defined as None in dict.
60    """
61    if dict.has_key(item):
62        if dict[item]!=None:
63            return 0
64    return 1
65
66
67def keyPatternMatch(dct, pattern, mode="string match"):
68    """
69    Returns 1 if one or more keys in the dictionary 'dct' match the
70    pattern provided using string.find(). Returns 0 otherwise.
71    """
72    for key in dct.keys():
73        if mode=="string match":
74            if key.find(pattern)>-1:
75                return 1
76        elif mode=="regex":
77            match=re.search(pattern, key)
78            if match:
79                return 1
80    return 0
81
82
83def getValuesInRange(start, end, array):
84    """
85    Takes a start and end value and returns the values in the array that are between them.
86    If not in range and are the same value then returns [start].
87    """
88    # check all are floats
89    array=map(lambda x: float(x), list(array))
90    if array[0]>array[-1]: array.reverse()
91    if start>end:  (start, end)=(end, start)
92    (start, end)=(float(start), float(end))
93    rtarray=[]
94    for i in array:
95        if i>=start and i<=end:
96            rtarray.append(i)
97    if rtarray==[] and start==end:
98        rtarray=[start]     
99    return rtarray
100
101
102def getSortedKeysLike(dct, pattern, mode="string match"):
103    """
104    Returns a list of all keys in the dictionary 'dct' that do a
105    string match on 'pattern'.
106    """
107    rtlist=[]
108    for key in dct.keys():
109        if mode=="string match":
110            if key.find(pattern)>-1:
111                rtlist.append(key)
112        elif mode=="regex":
113            match=re.search(pattern, key)
114            if match:
115                rtlist.append(key)
116    rtlist.sort()       
117    return rtlist
118   
119 
120def getDictSubsetMatching(dct, pattern, mode="string match"):
121    """
122    Returns a dictionary of all items in input dictionary 'dct'
123    where keys match 'pattern'.
124    """
125    rtdict={}
126    for key in dct.keys():
127        if mode=="string match":
128            if key.find(pattern)>-1:
129                rtdict[key]=dct[key]
130        elif mode=="regex":
131            match=re.search(pattern, key)
132            if match:
133                rtdict[key]=dct[key]       
134    return rtdict
135
136   
137def deleteDictSubsetMatching(dct, pattern, mode="string match"):
138    """
139    Deletes any items in the dictionary subset matched when calling
140    getDictSubsetMatching above. Returns the number of items deleted.
141    """
142    subdict=getDictSubsetMatching(dct, pattern, mode)
143    counter=0;
144    for key in subdict.keys():
145        del dct[key]
146        counter=counter+1
147    return counter
148   
149   
150def constructOutputInformation(pathDict, sizeDict, durationDict):
151    """
152    Constructs some output information to return to the client.
153    """
154    outputFilePaths=[]
155    outputSize=0
156    duration=0
157       
158    for key in pathDict.keys():
159        outputSize=outputSize+sizeDict[key]
160        duration=duration+durationDict[key]
161        outputFilePaths=outputFilePaths+pathDict[key]
162       
163    return (outputFilePaths, outputSize, duration)
164
165
166def intAll(stringList):
167    """
168    Takes a list of strings and returns them as ints.
169    """
170    return [int(i) for i in stringList]
171
172
173def convertDateTimeStringToYYYYMMDDHH(timeString):
174    """
175    Takes in a long CF-compliant time string and returns a shorter
176    YYYYMMDDHH string.
177    """
178    match=re.match(r"(\d{4}).(\d{1,2}).(\d{1,2})(\s+|T)(\d+):", timeString)
179    if match:
180        (y,m,d,blank,h)=match.groups()
181        timeString="%.4d%.2d%.2d%.2d" % (int(y), int(m), int(d), int(h))
182       
183    return timeString
184
185
186def deUnicodeObject(obj):
187    """
188    Returns the object identical except unicode strings are all
189    converted to normal strings.
190    """
191    tupleFound=None
192    if type(obj)==type((1,2)): 
193        tupleFound=1
194        obj=list(obj)
195
196    if type(obj)==type([]):
197        rtobj=[]
198        for i in obj:
199            if type(i) in (type([]), type((1,2))):
200                rtobj.append(deUnicodeObject(i)) 
201            elif type(i)==type(u""):
202                rtobj.append(str(i))
203            else:
204                rtobj.append(i)
205        if tupleFound==1: rtobj=tuple(rtobj)
206
207    elif type(obj)==type(u""):
208        rtobj=str(obj)
209    else: 
210        rtobj=obj
211       
212    return rtobj
213
214
215def translateURI(uri):
216    """
217    Takes a URL and returns the location of the file on the local network
218    or takes a local path and returns the URL of the file/directory.
219    """
220    if uri.find("http")>-1:
221        newpath=uri.replace(OUTPUT_DIR_URL, OUTPUT_DIR)
222    else:
223        newpath=uri.replace(OUTPUT_DIR, OUTPUT_DIR_URL)
224    return newpath
225
226
227
228def overlap(list1, list2):
229    """
230    overlap function - returns a list of overlapping items in list1 and list2.
231    Otherwise returns None.
232    """ 
233    rtlist=[]
234    for i in list1:
235       if i in list2: rtlist.append(i)
236
237    if len(rtlist)>0:
238        return rtlist
239    else:
240        return None
241
242
243def compareAxes(ax1, ax2):
244    """Takes 2 cdms axis objects returning 1 if they are essentially
245    the same and 0 if not."""
246    import cdms
247    for axtype in ("time", "level", "latitude", "longitude"):
248        if cdms.axisMatches(ax1, axtype) and not cdms.axisMatches(ax2, axtype):
249            return 0
250
251    # Check ids
252    if ax1.id!=ax2.id: return 0
253    # Check lengths
254    if len(ax1)!=len(ax2): return 0
255    # Check values
256    if ax1._data_!=ax2._data_: return 0
257    # Check units
258    if ax1.units!=ax2.units: return 0
259    # OK, I think they are the same axis!
260    return 1
261
262
263def compareGrids(grid1, grid2):
264    """Takes 2 cdms grid objects returning 1 if they are essentially
265    the same and 0 if not."""
266    import cdms
267    if compareAxes(grid1.getLatitude(), grid2.getLatitude())==0: return 0
268    if compareAxes(grid1.getLongitude(), grid2.getLongitude())==0: return 0
269    return 1
270   
271
272def nudgeSingleValuesToAxisValues(value, axisValues, axisType):
273        """
274        Takes a value and checks if it is in the axisValues array. If not, it nudges the
275        value to the nearest neighbour in axis. It returns the new value twice along
276        with a message describing the change.
277        """
278        import cdms
279        rtMessage=""
280        newValue=None
281       
282        if value in axisValues:
283            newValue=value
284        else:
285            sortedAxis=[]
286            for i in axisValues:
287                sortedAxis.append(i)
288            sortedAxis.sort()
289           
290            if value<sortedAxis[0]:
291                newValue=sortedAxis[0]
292            elif value>sortedAxis[-1]:
293                newValue=sortedAxis[-1]
294            else:
295                for i in range(len(axisValues)):
296                    if i<(len(axisValues)-1):
297                        (current, nextone)=(axisValues[i], axisValues[i+1])
298                        if current>nextone:
299                            tempc=nextone
300                            nextone=current
301                            current=tempc
302                   
303                        if value>current and value<nextone:
304                            lowergap=value-current
305                            uppergap=nextone-value
306                            if uppergap==lowergap:
307                                newValue=nextone
308                            elif uppergap>lowergap:
309                                newValue=current
310                            elif uppergap<lowergap:
311                                newValue=nextone                       
312                            break
313            if newValue==None:
314                raise DXProcessingError, ("Could not nudge selected value '%s' into axis '%s'." % (value, axisType))
315            rtMessage="%s axis selected value '%s' nudged to nearest value in real axis '%s' ;" % (axisType, value, newValue)                   
316            print rtMessage
317           
318        return (newValue, newValue, rtMessage)   
319
320
321def createSummaryString(reqDict):
322    """
323    Returns a summary string of a request dictionary.
324    """
325    exclusions=("callMethod", "secureToken", "optionCategoryRequested", 
326                "action", "targetPage", "sessionID")
327       
328    summaryString=""   
329    for key in reqDict.keys():
330        if reqDict[key]!="" and key not in exclusions: 
331            summaryString=summaryString+("%s:\t%s\n" % (key, reqDict[key]))
332   
333    return summaryString
334
335
336def makeDirsAndPerms(basedir, dirs, permissions, owner, verbose="no"):
337    """
338    A function for making directories recursively and setting permissions/ownership.
339    """
340    if type(dirs)==str: dirs=[dirs]
341    dirs=[basedir]+list(dirs)
342    dir=None
343
344    while len(dirs)>0:
345
346        if dir:
347            dir=os.path.join(dir, dirs[0])
348        else:
349            dir=dirs[0]
350        dirs=dirs[1:]
351
352        if not os.path.exists(dir):
353            if verbose=="yes":   print "Making directory:", dir
354            os.mkdir(dir)
355            os.chmod(dir, permissions)
356            os.system('/bin/chown %s %s' % (owner, dir))
357
358    return
359   
360   
361def checkSubDirectory(user=None):
362    """
363    checkSubDirectory method - checks if the required sub-directory exists
364    to write the output and if not it creates it.
365    """ 
366    if user==None or user=="None":   user="anonymous"
367    outputDir=os.path.join(OUTPUT_DIR, user, "dx_output")
368    if not os.path.isdir(outputDir):
369        makeDirsAndPerms(OUTPUT_DIR, (user, "dx_output"), OUTPUT_DIR_PERMISSION, "%s.%s" %
370                                           (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP))
371    # Local rule follows
372    if LOCAL_RULES==1:  makeAccessControlFile(user)     
373    return outputDir
374
375
376def fixFilePermissions(path):
377    """
378    Fixes permissions on a file.
379    """
380    os.chmod(path, OUTPUT_FILE_PERMISSION)
381    os.system("chown %s.%s %s" % (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP, path))   
382   
383   
384# Set up common classes
385class RedirectStdout:
386    """
387    RedirectStdout class - used to direct standard output away from
388    the screen in CGI scripts.
389    """
390
391    def write(self, item):
392        """
393        write method - allows dummy standard out to work.
394        """
395        pass
396
397    def flush(self):
398        """
399        Method to do nothing, again!
400        """
401        pass
Note: See TracBrowser for help on using the repository browser.