rda-python-icoads 3.0.2__tar.gz → 3.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {rda_python_icoads-3.0.2/src/rda_python_icoads.egg-info → rda_python_icoads-3.0.3}/PKG-INFO +1 -1
  2. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/pyproject.toml +1 -1
  3. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/fillicoads.py +132 -8
  4. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/pg_imma.py +21 -1
  5. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3/src/rda_python_icoads.egg-info}/PKG-INFO +1 -1
  6. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/LICENSE +0 -0
  7. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/MANIFEST.in +0 -0
  8. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/README.md +0 -0
  9. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/setup.cfg +0 -0
  10. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/PgIMMA.py +0 -0
  11. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/R3.0-stat_doc.pdf +0 -0
  12. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/README_R3.0_Subset.html +0 -0
  13. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/__init__.py +0 -0
  14. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/checkicoads.py +0 -0
  15. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/cleanicoads.py +0 -0
  16. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/countattm.py +0 -0
  17. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/countattmvar.py +0 -0
  18. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/counticoads.py +0 -0
  19. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/countsst.py +0 -0
  20. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/fillinventory.py +0 -0
  21. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/fillitable.py +0 -0
  22. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/fillmonth.py +0 -0
  23. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/fixiidx.py +0 -0
  24. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/imma1_subset.py +0 -0
  25. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/maxsst.py +0 -0
  26. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/msg +0 -0
  27. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/msg3.0_subset_readme.txt +0 -0
  28. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/msg3_subset.py +0 -0
  29. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/msg_download.py +0 -0
  30. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/msgsubset.f +0 -0
  31. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/rdimma1_csv.f +0 -0
  32. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads/writeicoads.py +0 -0
  33. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads.egg-info/SOURCES.txt +0 -0
  34. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads.egg-info/dependency_links.txt +0 -0
  35. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads.egg-info/entry_points.txt +0 -0
  36. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads.egg-info/requires.txt +0 -0
  37. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/src/rda_python_icoads.egg-info/top_level.txt +0 -0
  38. {rda_python_icoads-3.0.2 → rda_python_icoads-3.0.3}/tests/test_icoads.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_icoads
3
- Version: 3.0.2
3
+ Version: 3.0.3
4
4
  Summary: RDA python package to manage RDA ICOADS datasets
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-icoads
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_icoads"
9
- version = "3.0.2"
9
+ version = "3.0.3"
10
10
  authors = [
11
11
  { name="Zaihua Ji", email="zji@ucar.edu" },
12
12
  ]
@@ -29,7 +29,8 @@ class FillIcoads(PgIMMA):
29
29
  'names' : None,
30
30
  'files' : [],
31
31
  'dates' : [],
32
- 'dtlen' : 0
32
+ 'dtlen' : 0,
33
+ 'zipped' : 0
33
34
  }
34
35
 
35
36
  #
@@ -111,12 +112,125 @@ class FillIcoads(PgIMMA):
111
112
  fcnt = 0
112
113
  tcounts = [0]*self.TABLECOUNT
113
114
  for file in self.PVALS['files']:
115
+ pfile = self.get_partial_month_file(file) if addinventory else None
116
+ if pfile:
117
+ fcnt += 1
118
+ acnts = self.process_imma_file(pfile, addinventory)
119
+ for i in range(self.TABLECOUNT): tcounts[i] += acnts[i]
120
+ if self.PVALS['zipped']: self.pgsystem("gzip " + pfile, self.LOGWRN, 5)
114
121
  fcnt += 1
115
122
  acnts = self.process_imma_file(file, addinventory)
116
123
  for i in range(self.TABLECOUNT): tcounts[i] += acnts[i]
117
124
 
118
125
  if fcnt > 1: self.pglog("{} ({}) filled for {} files".format('/'.join(map(str, tcounts)), self.PVALS['names'], fcnt), self.LOGWRN)
119
126
 
127
+ #
128
+ # get the first data date in a given imma file
129
+ #
130
+ def get_imma_file_date(self, fname):
131
+
132
+ fdate = None
133
+ IMMA = open(fname, 'r', encoding = 'latin_1')
134
+ line = IMMA.readline()
135
+ self.identify_attm_name(line) # the date offset depends on the attm name
136
+ while line:
137
+ if not (self.PVALS['uatti'] and line[0:2] == self.PVALS['uatti']):
138
+ fdate = self.get_imma_date(line)
139
+ if fdate: break
140
+ line = IMMA.readline()
141
+ IMMA.close()
142
+
143
+ return fdate
144
+
145
+ #
146
+ # get the latest date filled into the inventory
147
+ #
148
+ def get_max_filled_date(self):
149
+
150
+ pgrec = self.pgget(f"{self.CNTLSC}.inventory", "max(date) mdate", "", self.LGEREX)
151
+
152
+ return self.format_date(pgrec['mdate']) if pgrec and pgrec['mdate'] else None
153
+
154
+ #
155
+ # locate a data file, gunzip it if only the gzipped one is on file
156
+ #
157
+ def locate_imma_file(self, fname):
158
+
159
+ self.PVALS['zipped'] = 0
160
+ if op.isfile(fname): return fname
161
+
162
+ zfile = fname + ".gz"
163
+ if op.isfile(zfile):
164
+ self.pgsystem("gunzip " + zfile, self.LOGWRN, 5)
165
+ if op.isfile(fname):
166
+ self.PVALS['zipped'] = 1
167
+ return fname
168
+
169
+ return None
170
+
171
+ #
172
+ # a month is filled up only if its last day is in the inventory; if an earlier month is
173
+ # filled partially, return the name of its data file, to fill up the missing dates before
174
+ # the given file is filled
175
+ #
176
+ def get_partial_month_file(self, fname):
177
+
178
+ mdate = self.get_max_filled_date()
179
+ if not mdate: return None # nothing filled yet
180
+
181
+ edate = self.enddate(mdate, 0, 'M')
182
+ if mdate == edate: return None # the latest filled month is filled up
183
+
184
+ fdate = self.get_imma_file_date(fname)
185
+ if not fdate or self.diffdate(fdate, edate) <= 0: return None # the given file holds the partial month
186
+
187
+ pgrec = self.pgget(f"{self.CNTLSC}.inventory", "fname", "date = '{}'".format(mdate), self.LGEREX)
188
+ pfile = self.locate_imma_file(pgrec['fname']) if pgrec and pgrec['fname'] else None
189
+ if not pfile:
190
+ self.pglog("{}: month is filled through {} only, and its data file is not found in {} to "
191
+ "fill it up before filling {}".format(mdate[0:7], mdate, op.abspath('.'), fdate[0:7]), self.LGEREX)
192
+
193
+ # the leading '>' propagates the note up through the calling processes, into the email report
194
+ self.pglog("> {}: filled through {} only, fill it up from {} before filling {}".format(
195
+ mdate[0:7], mdate, pfile, fdate[0:7]), self.LOGWRN)
196
+
197
+ return pfile
198
+
199
+ #
200
+ # skip the dates that are filled already if the month of the given file is resumed
201
+ #
202
+ def get_resume_date(self, fname, fdate, bdate):
203
+
204
+ mdate = self.get_max_filled_date()
205
+ if not mdate: return bdate # nothing filled yet
206
+ if self.diffdate(mdate, fdate) < 0: return bdate # none of this file is filled yet
207
+ if self.diffdate(mdate, self.enddate(fdate, 0, 'M')) > 0: return bdate # refilling an earlier month
208
+
209
+ rdate = self.adddate(mdate, 0, 0, 1)
210
+ if bdate and self.diffdate(bdate, rdate) >= 0: return bdate
211
+
212
+ self.pglog("> {}: filled through {} already, continue filling from {}".format(
213
+ op.basename(fname), mdate, rdate), self.LOGWRN)
214
+
215
+ return rdate
216
+
217
+ #
218
+ # log an error, without stopping, if the month of the given file is not filled up, so that
219
+ # a partial fill is reported by the calling process and the month is resumed on a rerun
220
+ #
221
+ def check_month_filled(self, fname, fdate, bdate):
222
+
223
+ edate = self.enddate(fdate, 0, 'M')
224
+ pgrec = self.pgget(f"{self.CNTLSC}.inventory", "max(date) mdate",
225
+ "date BETWEEN '{}-01' AND '{}'".format(fdate[0:7], edate), self.LGEREX)
226
+ mdate = self.format_date(pgrec['mdate']) if pgrec and pgrec['mdate'] else None
227
+ if mdate == edate:
228
+ if bdate: self.pglog("> {}: filled up through {}".format(fdate[0:7], edate), self.LOGWRN)
229
+ return
230
+
231
+ self.pglog("{}: PARTIAL fill of {}, filled through {} of {}; rerun to fill the remaining dates".format(
232
+ op.basename(fname), fdate[0:7], (mdate if mdate else 'nothing'), edate), self.LOGERR)
233
+
120
234
  #
121
235
  # read icoads record from given file name and save them into IVADDB
122
236
  #
@@ -125,19 +239,27 @@ class FillIcoads(PgIMMA):
125
239
  iname = fname if addinventory else None
126
240
  self.pglog("Record IMMA records in File '{}' into IVADDB".format(fname), self.WARNLG)
127
241
 
128
- IMMA = open(fname, 'r', encoding = 'latin_1')
129
242
  acounts = [0]*self.TABLECOUNT
130
243
  records = {}
244
+ bdate = self.PVALS['dates'][0] if self.PVALS['dtlen'] > 0 else None
245
+ edate = self.PVALS['dates'][1] if self.PVALS['dtlen'] > 1 else None
246
+
247
+ fdate = self.get_imma_file_date(fname) if iname else None
248
+ if fdate: bdate = self.get_resume_date(fname, fdate, bdate)
249
+
250
+ IMMA = open(fname, 'r', encoding = 'latin_1')
131
251
 
132
252
  # get the first valid date and do initialization
253
+ cdate = None
133
254
  line = IMMA.readline()
134
255
  self.identify_attm_name(line) # check and record standalone attm name
135
256
  while line:
136
- idate = cdate = self.get_imma_date(line)
137
- if cdate and (self.PVALS['dtlen'] == 0 or self.diffdate(cdate, self.PVALS['dates'][0]) >= 0):
138
- self.init_indices_for_date(cdate, iname)
139
- records = self.get_imma_records(cdate, line, records)
140
- break
257
+ if not (self.PVALS['uatti'] and line[0:2] == self.PVALS['uatti']): # a standalone attm line holds no date
258
+ cdate = self.get_imma_date(line)
259
+ if cdate and (not bdate or self.diffdate(cdate, bdate) >= 0):
260
+ self.init_indices_for_date(cdate, iname)
261
+ records = self.get_imma_records(cdate, line, records)
262
+ break
141
263
  line = IMMA.readline()
142
264
 
143
265
  line = IMMA.readline()
@@ -152,7 +274,7 @@ class FillIcoads(PgIMMA):
152
274
  for i in range(self.TABLECOUNT): acounts[i] += acnts[i]
153
275
  records = {}
154
276
  cdate = idate
155
- if self.PVALS['dtlen'] == 2 and self.diffdate(cdate, self.PVALS['dates'][1]) > 0: break
277
+ if edate and self.diffdate(cdate, edate) > 0: break
156
278
  self.init_indices_for_date(cdate, iname)
157
279
  records = self.get_imma_records(idate, line, records)
158
280
  line = IMMA.readline()
@@ -165,6 +287,8 @@ class FillIcoads(PgIMMA):
165
287
 
166
288
  self.pglog("{} ({}) filled from {}".format(' '.join(map(str, acounts)), self.PVALS['names'], op.basename(fname)), self.LOGWRN)
167
289
 
290
+ if fdate and self.PVALS['dtlen'] == 0: self.check_month_filled(fname, fdate, bdate)
291
+
168
292
  return acounts
169
293
 
170
294
  # main function to execute this script
@@ -375,7 +375,7 @@ class PgIMMA(PgOPT):
375
375
  self.UIDOFFSET = 4
376
376
  self.UIDLENGTH = 15
377
377
  atti = line[15:17]
378
- CURRN3 = int(line[12])
378
+ self.CURRN3 = int(line[12])
379
379
  else:
380
380
  atti = None
381
381
 
@@ -622,8 +622,28 @@ class PgIMMA(PgOPT):
622
622
  #
623
623
  # add multiple imma records into different tables in RDADB
624
624
  #
625
+ # all writes for one date are wrapped in a single transaction, so an interrupted
626
+ # fill can never leave an inventory record behind without its data; the date is
627
+ # then simply refilled when the file is processed again
628
+ #
625
629
  def add_imma_records(self, cdate, records):
626
630
 
631
+ self.starttran()
632
+ try:
633
+ acnts = self.add_date_records(cdate, records)
634
+ except BaseException:
635
+ self.aborttran()
636
+ self.pglog("{}: records rolled back for the date".format(cdate), self.LOGWRN)
637
+ raise
638
+ self.endtran()
639
+
640
+ return acnts
641
+
642
+ #
643
+ # add all records of one date into the attm and the control tables
644
+ #
645
+ def add_date_records(self, cdate, records):
646
+
627
647
  if self.INVENTORY and self.IMMA_NAMES[0] in records: # add counting record into inventory table
628
648
  rcnt = len(records[self.IMMA_NAMES[0]]['iidx'])
629
649
  if rcnt > 0: self.INVENTORY = self.add_inventory_record(self.INVENTORY['fname'], cdate, rcnt, self.INVENTORY)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_icoads
3
- Version: 3.0.2
3
+ Version: 3.0.3
4
4
  Summary: RDA python package to manage RDA ICOADS datasets
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-icoads