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

root/spongenet/trunk/spongenet/query.py

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

Cleanup loop variable nonsense in query module.

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