NCCOOS Trac Projects: Top | Web | Platforms | Processing | Viz | Sprints | Sandbox | (Wind)

root/spongenet/trunk/spongenet/query.py

Revision 380 (checked in by cbc, 14 years ago)

More work on CSV creation framework.

Line 
1 #!/usr/bin/env python
2
3 """
4 Create CSV spreadsheets from sponge data NetCDF files.
5
6 Usage:
7
8    > python query.py path/to/config/file
9    > python query.py -t
10    > python query.py --test
11
12 Test silent import:
13
14 >>> import expand
15 """
16
17 __author__ = "Chris Calloway"
18 __email__ = "cbc@chriscalloway.org"
19 __copyright__ = "Copyright 2010 UNC-CH Department of Marine Science"
20 __license__ = "GPL2"
21
22 import sys
23 import os
24 import glob
25 import csv
26 from pycdf import CDF, CDFError
27 import doctest
28 import unittest
29 from StringIO import StringIO
30
31 USAGE = "\n".join(__doc__.splitlines()[3:8])
32 TEST_PATH = os.path.join("tests", "query")
33
34
35 def _test():
36     """
37     Run doctests as unittest suite.
38
39     Test silent import:
40
41     >>> from expand import _test
42     """
43
44     suite = []
45     suite.append(doctest.DocTestSuite())
46     suite = unittest.TestSuite(suite)
47     unittest.TextTestRunner().run(suite)
48
49     return
50
51
52 def config_path():
53     """
54     Return the configuration file path from the command line.
55
56     Supply too few arguments on command line:
57
58     >>> save_stdout = sys.stdout
59     >>> temp_stdout = StringIO()
60     >>> sys.stdout = temp_stdout
61     >>> sys.argv = []
62     >>> _config_path = config_path()
63     >>> sys.stdout = save_stdout
64     >>> USAGE == temp_stdout.getvalue()[:-1]
65     True
66
67     Supply too many arguments on the command line:
68
69     >>> save_stdout = sys.stdout
70     >>> temp_stdout = StringIO()
71     >>> sys.stdout = temp_stdout
72     >>> sys.argv = ["", "", "",]
73     >>> _config_path = config_path()
74     >>> sys.stdout = save_stdout
75     >>> USAGE == temp_stdout.getvalue()[:-1]
76     True
77
78     Supply non-file argument:
79
80     >>> save_stdout = sys.stdout
81     >>> temp_stdout = StringIO()
82     >>> sys.stdout = temp_stdout
83     >>> _config_path = os.path.join(
84     ...                    os.path.dirname(
85     ...                        os.path.abspath(__file__)),
86     ...                    TEST_PATH)
87     >>> sys.argv = ["", _config_path]
88     >>> _config_path = config_path()
89     >>> sys.stdout = save_stdout
90     >>> USAGE == temp_stdout.getvalue()[:-1]
91     True
92
93     Supply nonexistent file argument:
94
95     >>> save_stdout = sys.stdout
96     >>> temp_stdout = StringIO()
97     >>> sys.stdout = temp_stdout
98     >>> _config_path = os.path.join(
99     ...                    os.path.dirname(
100     ...                        os.path.abspath(__file__)),
101     ...                    TEST_PATH, "xxxxx")
102     >>> sys.argv = ["", _config_path]
103     >>> _config_path = config_path()
104     >>> sys.stdout = save_stdout
105     >>> USAGE == temp_stdout.getvalue()[:-1]
106     True
107
108     Supply valid config path argument:
109
110     >>> _config_path = os.path.join(
111     ...                    os.path.dirname(
112     ...                        os.path.abspath(__file__)),
113     ...                    TEST_PATH, "config.py")
114     >>> sys.argv = ["", _config_path]
115     >>> _config_path == config_path()
116     True
117     """
118
119     path = None
120     try:
121         if len(sys.argv) == 2:
122             if sys.argv[1] == "-t" or sys.argv[1] == "--test":
123                 _test()
124             else:
125                 path = sys.argv[1]
126                 if not os.path.exists(path):
127                     raise IOError(path + \
128                                   " does not exist.")
129                 elif not os.path.isfile(path):
130                     raise IOError(path + \
131                                   " is not a file.")
132         else:
133             raise IOError("Incorrect number of arguments supplied.")
134     except IOError:
135         print USAGE
136     return path
137
138
139 def config(path):
140     """
141     Return the configuration from a file.
142
143     Execute empty configuration:
144
145     >>> _config_path = os.path.join(
146     ...                    os.path.dirname(
147     ...                        os.path.abspath(__file__)),
148     ...                    TEST_PATH, "empty_config.py")
149     >>> ncdir,csvdir, \
150             ncfile_pattern,csvfile_pattern, \
151             location,platform,packages = \
152             config(_config_path)
153     >>> ncdir
154     >>> csvdir
155     >>> ncfile_pattern
156     >>> csvfile_pattern
157     >>> location
158     >>> platform
159     >>> packages
160
161     Execute nonexistent configuration:
162
163     >>> save_stdout = sys.stdout
164     >>> temp_stdout = StringIO()
165     >>> sys.stdout = temp_stdout
166     >>> _config_path = os.path.join(
167     ...                    os.path.dirname(
168     ...                        os.path.abspath(__file__)),
169     ...                    TEST_PATH, "xxxxx")
170     >>> ncdir,csvdir, \
171             ncfile_pattern,csvfile_pattern, \
172             location,platform,packages = \
173             config(_config_path)
174     >>> sys.stdout = save_stdout
175     >>> USAGE == temp_stdout.getvalue()[:-1]
176     True
177     >>> ncdir
178     >>> csvdir
179     >>> ncfile_pattern
180     >>> csvfile_pattern
181     >>> location
182     >>> platform
183     >>> packages
184
185     Execute bad configuration:
186
187     >>> save_stdout = sys.stdout
188     >>> temp_stdout = StringIO()
189     >>> sys.stdout = temp_stdout
190     >>> _config_path = os.path.join(
191     ...                    os.path.dirname(
192     ...                        os.path.abspath(__file__)),
193     ...                    TEST_PATH, "bad_config.py")
194     >>> ncdir,csvdir, \
195             ncfile_pattern,csvfile_pattern, \
196             location,platform,packages = \
197             config(_config_path)
198     >>> sys.stdout = save_stdout
199     >>> USAGE == temp_stdout.getvalue()[:-1]
200     True
201     >>> ncdir
202     >>> csvdir
203     >>> ncfile_pattern
204     >>> csvfile_pattern
205     >>> location
206     >>> platform
207     >>> packages
208
209     Execute valid configuration:
210
211     >>> _config_path = os.path.join(
212     ...                    os.path.dirname(
213     ...                        os.path.abspath(__file__)),
214     ...                    TEST_PATH, "config.py")
215     >>> ncdir,csvdir, \
216             ncfile_pattern,csvfile_pattern, \
217             location,platform,packages = \
218             config(_config_path)
219     >>> ncdir == os.path.join(os.path.dirname(os.path.abspath(__file__)),
220     ...                       TEST_PATH, "nc")
221     True
222     >>> csvdir == os.path.join(os.path.dirname(os.path.abspath(__file__)),
223     ...                        TEST_PATH, "csv")
224     True
225     >>> ncfile_pattern == "%(location)s_%(platform)s_%(package)s_" \
226                           "[0-9][0-9][0-9][0-9]_[0-9][0-9].nc"
227     True
228     >>> csvfile_pattern == "%(location)s_%(platform)s_%(month)s.csv"
229     True
230     >>> location == "location"
231     True
232     >>> platform == "platform"
233     True
234     >>> packages == (('system', ('voltage',
235     ...                          'memory',
236     ...                          'interval', )),
237     ...              ('turbidity', ('turbidity', )),
238     ...              ('optode_127', ('o2concentration',
239     ...                              'airsaturation',
240     ...                              'temperature',
241     ...                              'calphase',
242     ...                              'tcphase',
243     ...                              'c1rph',
244     ...                              'c2rph',
245     ...                              'c1amp',
246     ...                              'c2amp',
247     ...                              'rawtemp', )),
248     ...              ('optode_167', ('o2concentration',
249     ...                              'airsaturation',
250     ...                              'temperature',
251     ...                              'calphase',
252     ...                              'tcphase',
253     ...                              'c1rph',
254     ...                              'c2rph',
255     ...                              'c1amp',
256     ...                              'c2amp',
257     ...                              'rawtemp', )),
258     ...              ('optode_169', ('o2concentration',
259     ...                              'airsaturation',
260     ...                              'temperature',
261     ...                              'calphase',
262     ...                              'tcphase',
263     ...                              'c1rph',
264     ...                              'c2rph',
265     ...                              'c1amp',
266     ...                              'c2amp',
267     ...                              'rawtemp', )),
268     ...              ('optode_170', ('o2concentration',
269     ...                              'airsaturation',
270     ...                              'temperature',
271     ...                              'calphase',
272     ...                              'tcphase',
273     ...                              'c1rph',
274     ...                              'c2rph',
275     ...                              'c1amp',
276     ...                              'c2amp',
277     ...                              'rawtemp', )),
278     ...              ('optode_171', ('o2concentration',
279     ...                              'airsaturation',
280     ...                              'temperature',
281     ...                              'calphase',
282     ...                              'tcphase',
283     ...                              'c1rph',
284     ...                              'c2rph',
285     ...                              'c1amp',
286     ...                              'c2amp',
287     ...                              'rawtemp', )),
288     ...              ('optode_172', ('o2concentration',
289     ...                              'airsaturation',
290     ...                              'temperature',
291     ...                              'calphase',
292     ...                              'tcphase',
293     ...                              'c1rph',
294     ...                              'c2rph',
295     ...                              'c1amp',
296     ...                              'c2amp',
297     ...                              'rawtemp', )),
298     ...              ('optode_173', ('o2concentration',
299     ...                              'airsaturation',
300     ...                              'temperature',
301     ...                              'calphase',
302     ...                              'tcphase',
303     ...                              'c1rph',
304     ...                              'c2rph',
305     ...                              'c1amp',
306     ...                              'c2amp',
307     ...                              'rawtemp', )),
308     ...              ('optode_175', ('o2concentration',
309     ...                              'airsaturation',
310     ...                              'temperature',
311     ...                              'calphase',
312     ...                              'tcphase',
313     ...                              'c1rph',
314     ...                              'c2rph',
315     ...                              'c1amp',
316     ...                              'c2amp',
317     ...                              'rawtemp', )),
318     ...              ('optode_176', ('o2concentration',
319     ...                              'airsaturation',
320     ...                              'temperature',
321     ...                              'calphase',
322     ...                              'tcphase',
323     ...                              'c1rph',
324     ...                              'c2rph',
325     ...                              'c1amp',
326     ...                              'c2amp',
327     ...                              'rawtemp', )),
328     ...              ('optode_178', ('o2concentration',
329     ...                              'airsaturation',
330     ...                              'temperature',
331     ...                              'calphase',
332     ...                              'tcphase',
333     ...                              'c1rph',
334     ...                              'c2rph',
335     ...                              'c1amp',
336     ...                              'c2amp',
337     ...                              'rawtemp', )),
338     ...              ('optode_179', ('o2concentration',
339     ...                              'airsaturation',
340     ...                              'temperature',
341     ...                              'calphase',
342     ...                              'tcphase',
343     ...                              'c1rph',
344     ...                              'c2rph',
345     ...                              'c1amp',
346     ...                              'c2amp',
347     ...                              'rawtemp', )),
348     ...              ('conductivity', ('conductivity',
349     ...                                'temperature', )),
350     ...              ('pressure', ('pressure',
351     ...                            'temperature', )),
352     ...              ('current', ('abs_speed',
353     ...                           'direction',
354     ...                           'v',
355     ...                           'u',
356     ...                           'heading',
357     ...                           'tiltx',
358     ...                           'tilty',
359     ...                           'std_speed',
360     ...                           'strength',
361     ...                           'pings', )),
362     ...             )
363     True
364     """
365
366     namespace = {}
367     namespace["NCDIR"] = None
368     namespace["CSVDIR"] = None
369     namespace["NCFILE_PATTERN"] = None
370     namespace["CSVFILE_PATTERN"] = None
371     namespace["LOCATION"] = None
372     namespace["PLATFORM"] = None
373     namespace["PACKAGES"] = None
374     try:
375         execfile(path, globals(), namespace)
376     except IOError:
377         print USAGE
378     except SyntaxError:
379         print USAGE
380     return (namespace["NCDIR"],
381             namespace["CSVDIR"],
382             namespace["NCFILE_PATTERN"],
383             namespace["CSVFILE_PATTERN"],
384             namespace["LOCATION"],
385             namespace["PLATFORM"],
386             namespace["PACKAGES"],
387            )
388
389
390 def create(csvpath, ncdir, ncfile_pattern,
391            location, platform, month, packages):
392     """
393     Create a specific month of CSV spreadsheet from sponge data NetCDF files.
394     """
395
396     columns = ["time", ]
397     columns.extend([".".join([package, variable])
398                     for package, variables in packages
399                     for variable in variables])
400
401     for package, variables in packages:
402         ncpath = ncfile_pattern % {"location": location,
403                                    "platform": platform,
404                                    "package": package, }
405         ncpath = ncpath[:-34] + month + ".nc"
406         ncpath = os.path.join(ncdir, ncpath)
407         try:
408             cdf = CDF(ncpath)
409             for variable in variables:
410                 cdf.var(variable).get()
411         except CDFError:
412             pass
413
414     handle = open(csvpath, "wb")
415     writer = csv.DictWriter(handle, columns)
416     headers = dict([(column,column) for column in columns])
417     writer.writerow(headers)
418     handle.close()
419
420     return columns
421
422
423 def query(ncdir, csvdir,
424           ncfile_pattern, csvfile_pattern,
425           location, platform, packages):
426     """
427     Create CSV spreadsheets from sponge data NetCDF files.
428     """
429
430     # Find all monthly NetCDF files for location/platform
431     ncfile_patterns = [(package,
432                         ncfile_pattern % {"location":location,
433                                           "platform":platform,
434                                           "package":package, },
435                        ) for package, variables in packages]
436     paths = dict([(package,
437                    [month
438                     for month in glob.glob(os.path.join(ncdir, pattern))
439                     if os.path.isfile(month)],
440                   ) for package, pattern in ncfile_patterns])
441
442     # Find all months for location/platform
443     months = list(set([os.path.splitext(path)[0][-7:]
444                        for package, variables in packages
445                        for path in paths[package]]))
446     months.sort()
447
448     # Create a directory for monthly CSV files.
449     if not os.path.exists(csvdir):
450         os.mkdir(csvdir, 0755)
451     elif not os.path.isdir(csvdir):
452         raise IOError("CSV directory name " + \
453                        csvdir + \
454                        " exists and is not a directory.")
455
456     # Create a CSV file for each month
457     for month in months:
458         path = csvfile_pattern % {"location": location,
459                                   "platform": platform,
460                                   "month": month}
461         path = os.path.join(csvdir, path)
462         if not os.path.exists(path):
463             create(path, ncdir, ncfile_pattern,
464                    location, platform, month, packages)
465         elif not os.path.isfile(path):
466             raise IOError("CSV file name " + \
467                           path + \
468                           " exists and is not a file.")
469         elif month == months[-1]:
470             # Always create last month
471             create(path + "new", ncdir, ncfile_pattern,
472                    location, platform, month, packages)
473             os.remove(path)
474             os.rename(path + "new", path)
475
476     return
477
478
479 def _main():
480     """
481     Run module as script.
482
483     Supply incomplete config file:
484
485     >>> save_stdout = sys.stdout
486     >>> temp_stdout = StringIO()
487     >>> sys.stdout = temp_stdout
488     >>> _config_path = os.path.join(
489     ...                    os.path.dirname(
490     ...                        os.path.abspath(__file__)),
491     ...                    TEST_PATH, "incomplete_config.py")
492     >>> sys.argv = ["", _config_path]
493     >>> _main()
494     >>> sys.stdout = save_stdout
495     >>> USAGE == temp_stdout.getvalue()[:-1]
496     True
497     """
498
499     _config_path = config_path()
500     if _config_path:
501         _config = config(_config_path)
502         if all(_config):
503             query(*_config)
504         else:
505             print USAGE
506
507     return
508
509 if __name__ == "__main__":
510     _main()
Note: See TracBrowser for help on using the browser.