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

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

Stable-ish version with fully-ish working dxc 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={"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 intAll(stringList):
138    """
139    Takes a list of strings and returns them as ints.
140    """
141    return [int(i) for i in stringList]
142
143
144def convertDateTimeStringToYYYYMMDDHH(timeString):
145    """
146    Takes in a long CF-compliant time string and returns a shorter
147    YYYYMMDDHH string.
148    """
149    match=re.match(r"(\d{4}).(\d{1,2}).(\d{1,2})(\s+|T)(\d+):", timeString)
150    if match:
151        (y,m,d,blank,h)=match.groups()
152        timeString="%.4d%.2d%.2d%.2d" % (int(y), int(m), int(d), int(h))
153       
154    return timeString
155
156
157def deUnicodeObject(obj):
158    """
159    Returns the object identical except unicode strings are all
160    converted to normal strings.
161    """
162    tupleFound=None
163    if type(obj)==type((1,2)): 
164        tupleFound=1
165        obj=list(obj)
166
167    if type(obj)==type([]):
168        rtobj=[]
169        for i in obj:
170            if type(i) in (type([]), type((1,2))):
171                rtobj.append(deUnicodeObject(i)) 
172            elif type(i)==type(u""):
173                rtobj.append(str(i))
174            else:
175                rtobj.append(i)
176        if tupleFound==1: rtobj=tuple(rtobj)
177
178    elif type(obj)==type(u""):
179        rtobj=str(obj)
180    else: 
181        rtobj=obj
182    return rtobj
183
184
185def translateURI(uri):
186    """
187    Takes a URL and returns the location of the file on the local network
188    or takes a local path and returns the URL of the file/directory.
189    """
190    if uri.find("http")>-1:
191        newpath=uri.replace(OUTPUT_DIR_URL, OUTPUT_DIR)
192    else:
193        newpath=uri.replace(OUTPUT_DIR, OUTPUT_DIR_URL)
194    return newpath
195
196
197
198def overlap(list1, list2):
199    """
200    overlap function - returns a list of overlapping items in list1 and list2.
201    Otherwise returns None.
202    """ 
203    rtlist=[]
204    for i in list1:
205       if i in list2: rtlist.append(i)
206
207    if len(rtlist)>0:
208        return rtlist
209    else:
210        return None
211
212
213def compareAxes(ax1, ax2):
214    """Takes 2 cdms axis objects returning 1 if they are essentially
215    the same and 0 if not."""
216    import cdms
217    for axtype in ("time", "level", "latitude", "longitude"):
218        if cdms.axisMatches(ax1, axtype) and not cdms.axisMatches(ax2, axtype):
219            return 0
220
221    # Check ids
222    if ax1.id!=ax2.id: return 0
223    # Check lengths
224    if len(ax1)!=len(ax2): return 0
225    # Check values
226    if ax1._data_!=ax2._data_: return 0
227    # Check units
228    if ax1.units!=ax2.units: return 0
229    # OK, I think they are the same axis!
230    return 1
231
232
233def compareGrids(grid1, grid2):
234    """Takes 2 cdms grid objects returning 1 if they are essentially
235    the same and 0 if not."""
236    import cdms
237    if compareAxes(grid1.getLatitude(), grid2.getLatitude())==0: return 0
238    if compareAxes(grid1.getLongitude(), grid2.getLongitude())==0: return 0
239    return 1
240   
241
242def nudgeSingleValuesToAxisValues(value, axisValues, axisType):
243        """
244        Takes a value and checks if it is in the axisValues array. If not, it nudges the
245        value to the nearest neighbour in axis. It returns the new value twice along
246        with a message describing the change.
247        """
248        import cdms
249        rtMessage=""
250        newValue=None
251       
252        if value in axisValues:
253            newValue=value
254        else:
255            sortedAxis=[]
256            for i in axisValues:
257                sortedAxis.append(i)
258            sortedAxis.sort()
259           
260            if value<sortedAxis[0]:
261                newValue=sortedAxis[0]
262            elif value>sortedAxis[-1]:
263                newValue=sortedAxis[-1]
264            else:
265                for i in range(len(axisValues)):
266                    if i<(len(axisValues)-1):
267                        (current, nextone)=(axisValues[i], axisValues[i+1])
268                        if current>nextone:
269                            tempc=nextone
270                            nextone=current
271                            current=tempc
272                   
273                        if value>current and value<nextone:
274                            lowergap=value-current
275                            uppergap=nextone-value
276                            if uppergap==lowergap:
277                                newValue=nextone
278                            elif uppergap>lowergap:
279                                newValue=current
280                            elif uppergap<lowergap:
281                                newValue=nextone                       
282                            break
283            if newValue==None:
284                raise DXProcessingError, ("Could not nudge selected value '%s' into axis '%s'." % (value, axisType))
285            rtMessage="%s axis selected value '%s' nudged to nearest value in real axis '%s' ;" % (axisType, value, newValue)                   
286            print rtMessage
287           
288        return (newValue, newValue, rtMessage)   
289
290
291def createSummaryString(reqDict):
292    """
293    Returns a summary string of a request dictionary.
294    """
295    exclusions=("callMethod", "secureToken", "optionCategoryRequested", 
296                "action", "targetPage", "sessionID")
297       
298    summaryString=""   
299    for key in reqDict.keys():
300        if reqDict[key]!="" and key not in exclusions: 
301            summaryString=summaryString+("%s:\t%s\n" % (key, reqDict[key]))
302   
303    return summaryString
304
305
306def makeDirsAndPerms(basedir, dirs, permissions, owner, verbose="no"):
307    """
308    A function for making directories recursively and setting permissions/ownership.
309    """
310    if type(dirs)==str: dirs=[dirs]
311    dirs=[basedir]+list(dirs)
312    dir=None
313
314    while len(dirs)>0:
315
316        if dir:
317            dir=os.path.join(dir, dirs[0])
318        else:
319            dir=dirs[0]
320        dirs=dirs[1:]
321
322        if not os.path.exists(dir):
323            if verbose=="yes":   print "Making directory:", dir
324            os.mkdir(dir)
325            os.chmod(dir, permissions)
326            os.system('/bin/chown %s %s' % (owner, dir))
327
328    return
329   
330   
331def checkSubDirectory(user=None):
332    """
333    checkSubDirectory method - checks if the required sub-directory exists
334    to write the output and if not it creates it.
335    """ 
336    if user==None or user=="None":   user="anonymous"
337    outputDir=os.path.join(OUTPUT_DIR, user, "dx_output")
338    if not os.path.isdir(outputDir):
339        makeDirsAndPerms(OUTPUT_DIR, (user, "dx_output"), OUTPUT_DIR_PERMISSION, "%s.%s" %
340                                           (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP))
341    # Local rule follows
342    if LOCAL_RULES==1:  makeAccessControlFile(user)     
343    return outputDir
344
345
346def fixFilePermissions(path):
347    """
348    Fixes permissions on a file.
349    """
350    os.chmod(path, OUTPUT_FILE_PERMISSION)
351    os.system("chown %s.%s %s" % (OUTPUT_FILE_USER, OUTPUT_FILE_GROUP, path))   
352   
353   
354# Set up common classes
355class RedirectStdout:
356    """
357    RedirectStdout class - used to direct standard output away from
358    the screen in CGI scripts.
359    """
360
361    def write(self, item):
362        """
363        write method - allows dummy standard out to work.
364        """
365        pass
366
367    def flush(self):
368        """
369        Method to do nothing, again!
370        """
371        pass
Note: See TracBrowser for help on using the repository browser.