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

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

Close to alpha version.

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    print "\n\n", uri, "\n\n", newpath, "\n\n"
225    return newpath
226
227
228
229def overlap(list1, list2):
230    """
231    overlap function - returns a list of overlapping items in list1 and list2.
232    Otherwise returns None.
233    """ 
234    rtlist=[]
235    for i in list1:
236       if i in list2: rtlist.append(i)
237
238    if len(rtlist)>0:
239        return rtlist
240    else:
241        return None
242
243
244def compareAxes(ax1, ax2):
245    """Takes 2 cdms axis objects returning 1 if they are essentially
246    the same and 0 if not."""
247    import cdms
248    for axtype in ("time", "level", "latitude", "longitude"):
249        if cdms.axisMatches(ax1, axtype) and not cdms.axisMatches(ax2, axtype):
250            return 0
251
252    # Check ids
253    if ax1.id!=ax2.id: return 0
254    # Check lengths
255    if len(ax1)!=len(ax2): return 0
256    # Check values
257    if ax1._data_!=ax2._data_: return 0
258    # Check units
259    if ax1.units!=ax2.units: return 0
260    # OK, I think they are the same axis!
261    return 1
262
263
264def compareGrids(grid1, grid2):
265    """Takes 2 cdms grid objects returning 1 if they are essentially
266    the same and 0 if not."""
267    import cdms
268    if compareAxes(grid1.getLatitude(), grid2.getLatitude())==0: return 0
269    if compareAxes(grid1.getLongitude(), grid2.getLongitude())==0: return 0
270    return 1
271   
272
273def nudgeSingleValuesToAxisValues(value, axisValues, axisType):
274        """
275        Takes a value and checks if it is in the axisValues array. If not, it nudges the
276        value to the nearest neighbour in axis. It returns the new value twice along
277        with a message describing the change.
278        """
279        import cdms
280        rtMessage=""
281        newValue=None
282       
283        if value in axisValues:
284            newValue=value
285        else:
286            sortedAxis=[]
287            for i in axisValues:
288                sortedAxis.append(i)
289            sortedAxis.sort()
290           
291            if value<sortedAxis[0]:
292                newValue=sortedAxis[0]
293            elif value>sortedAxis[-1]:
294                newValue=sortedAxis[-1]
295            else:
296                for i in range(len(axisValues)):
297                    if i<(len(axisValues)-1):
298                        (current, nextone)=(axisValues[i], axisValues[i+1])
299                        if current>nextone:
300                            tempc=nextone
301                            nextone=current
302                            current=tempc
303                   
304                        if value>current and value<nextone:
305                            lowergap=value-current
306                            uppergap=nextone-value
307                            if uppergap==lowergap:
308                                newValue=nextone
309                            elif uppergap>lowergap:
310                                newValue=current
311                            elif uppergap<lowergap:
312                                newValue=nextone                       
313                            break
314            if newValue==None:
315                raise DXProcessingError, ("Could not nudge selected value '%s' into axis '%s'." % (value, axisType))
316            rtMessage="%s axis selected value '%s' nudged to nearest value in real axis '%s' ;" % (axisType, value, newValue)                   
317            print rtMessage
318           
319        return (newValue, newValue, rtMessage)   
320
321
322def createSummaryString(reqDict):
323    """
324    Returns a summary string of a request dictionary.
325    """
326    exclusions=("callMethod", "secureToken", "optionCategoryRequested", 
327                "action", "targetPage", "sessionID")
328       
329    summaryString=""   
330    for key in reqDict.keys():
331        if reqDict[key]!="" and key not in exclusions: 
332            summaryString=summaryString+("%s:\t%s\n" % (key, reqDict[key]))
333   
334    return summaryString
335
336
337def makeDirsAndPerms(basedir, dirs, permissions, owner, verbose="no"):
338    """
339    A function for making directories recursively and setting permissions/ownership.
340    """
341    if type(dirs)==str: dirs=[dirs]
342    dirs=[basedir]+list(dirs)
343    dir=None
344
345    while len(dirs)>0:
346
347        if dir:
348            dir=os.path.join(dir, dirs[0])
349        else:
350            dir=dirs[0]
351        dirs=dirs[1:]
352
353        if not os.path.exists(dir):
354            if verbose=="yes":   print "Making directory:", dir
355            os.mkdir(dir)
356            os.chmod(dir, permissions)
357            os.system('/bin/chown %s %s' % (owner, dir))
358
359    return
360   
361   
362def checkSubDirectory(user=None):
363    """
364    checkSubDirectory method - checks if the required sub-directory exists
365    to write the output and if not it creates it.
366    """ 
367    if user==None or user=="None":   user="anonymous"
368    outputDir=os.path.join(OUTPUT_DIR, user, "dx_output")
369    if not os.path.isdir(outputDir):
370        makeDirsAndPerms(OUTPUT_DIR, (user, "dx_output"), OUTPUT_DIR_PERMISSION, "%s.%s" %
371                                           (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP))
372    # Local rule follows
373    if LOCAL_RULES==1:  makeAccessControlFile(user)     
374    return outputDir
375
376
377def fixFilePermissions(path):
378    """
379    Fixes permissions on a file.
380    """
381    os.chmod(path, OUTPUT_FILE_PERMISSION)
382    os.system("chown %s.%s %s" % (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP, path))   
383   
384   
385# Set up common classes
386class RedirectStdout:
387    """
388    RedirectStdout class - used to direct standard output away from
389    the screen in CGI scripts.
390    """
391
392    def write(self, item):
393        """
394        write method - allows dummy standard out to work.
395        """
396        pass
397
398    def flush(self):
399        """
400        Method to do nothing, again!
401        """
402        pass
Note: See TracBrowser for help on using the repository browser.