rda-python-common 1.0.15__py3-none-any.whl → 1.0.18__py3-none-any.whl

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.

Potentially problematic release.


This version of rda-python-common might be problematic. Click here for more details.

@@ -236,7 +236,6 @@ def set_dbname(scname = None, lnname = None, pwname = None, dbhost = None, dbpor
236
236
  #
237
237
  def set_scname(dbname = None, scname = None, lnname = None, pwname = None, dbhost = None, dbport = None, socket = None):
238
238
 
239
- global pgdb
240
239
  changed = 0
241
240
 
242
241
  if dbname and dbname != PGDBI['DBNAME']:
@@ -274,7 +273,6 @@ def set_scname(dbname = None, scname = None, lnname = None, pwname = None, dbhos
274
273
  def starttran():
275
274
 
276
275
  global curtran
277
- global pgdb
278
276
 
279
277
  if curtran == 1: endtran() # try to end previous transaction
280
278
  if not pgdb:
@@ -296,7 +294,6 @@ def starttran():
296
294
  def endtran(autocommit = True):
297
295
 
298
296
  global curtran
299
- global pgdb
300
297
  if curtran and pgdb:
301
298
  if not pgdb.closed: pgdb.commit()
302
299
  pgdb.autocommit = autocommit
@@ -308,7 +305,6 @@ def endtran(autocommit = True):
308
305
  def aborttran(autocommit = True):
309
306
 
310
307
  global curtran
311
- global pgdb
312
308
  if curtran and pgdb:
313
309
  if not pgdb.closed: pgdb.rollback()
314
310
  pgdb.autocommit = autocommit
@@ -535,7 +531,6 @@ def pgconnect(reconnect = 0, pgcnt = 0, autocommit = True):
535
531
  #
536
532
  def pgcursor():
537
533
 
538
- global pgdb
539
534
  pgcur = None
540
535
 
541
536
  if not pgdb:
@@ -1125,7 +1125,8 @@ def make_one_remote_directory(dir, odir, host, logact = 0):
1125
1125
  if is_root_directory(dir, 'R', host, "make directory {} on {}".format(odir, host), logact): return PgLOG.FAILURE
1126
1126
 
1127
1127
  if make_one_remote_directory(op.dirname(dir), odir, host, logact):
1128
- if PgLOG.pgsystem("{} {} {}".format(PgLOG.get_sync_command(host), PgLOG.PGLOG['TMPSYNC'], dir), logact, 5):
1128
+ tmpsync = PgLOG.get_tmpsync_path()
1129
+ if PgLOG.pgsystem("{} {} {}".format(PgLOG.get_sync_command(host), tmpsync, dir), logact, 5):
1129
1130
  set_remote_mode(dir, 0, host, PgLOG.PGLOG['EXECMODE'])
1130
1131
  return PgLOG.SUCCESS
1131
1132
 
@@ -11,7 +11,7 @@
11
11
  # message on screen and exit script
12
12
  #
13
13
  # Github : https://github.com/NCAR/rda-python-common.git
14
- #
14
+ #
15
15
  ###############################################################################
16
16
 
17
17
  import sys
@@ -29,8 +29,8 @@ import traceback
29
29
 
30
30
  # define some constants for logging actions
31
31
  MSGLOG = (0x00001) # logging message
32
- WARNLG = (0x00002) # show logging message as warning
33
- EXITLG = (0x00004) # exit after logging
32
+ WARNLG = (0x00002) # show logging message as warning
33
+ EXITLG = (0x00004) # exit after logging
34
34
  LOGWRN = (0x00003) # MSGLOG|WARNLG
35
35
  LOGEXT = (0x00005) # MSGLOG|EXITLG
36
36
  WRNEXT = (0x00006) # WARNLG|EXITLG
@@ -57,7 +57,7 @@ MISLOG = (0x00811) # cannot access logfile
57
57
  EMLSUM = (0x08000) # record as email summary
58
58
  EMEROL = (0x10000) # record error as email only
59
59
  EMLALL = (0x1D208) # all email acts
60
- DOSUDO = (0x20000) # add 'sudo -u PGLOG['RDAUSER']'
60
+ DOSUDO = (0x20000) # add 'sudo -u PGLOG['RDAUSER']'
61
61
  NOTLOG = (0x40000) # do not log any thing
62
62
  OVRIDE = (0x80000) # do override existing file or record
63
63
  NOWAIT = (0x100000) # do not wait on globus task to finish
@@ -95,7 +95,7 @@ PGLOG = { # more defined in untaint_suid() with environment variables
95
95
  'ARCHROOT': "/FS/DECS", # root path for segregated tape on hpss
96
96
  'BACKROOT': "/DRDATA/DECS", # backup path for desaster recovering tape on hpss
97
97
  'OLDAROOT': "/FS/DSS", # old root path on hpss
98
- 'OLDBROOT': "/DRDATA/DSS", # old backup tape on hpss
98
+ 'OLDBROOT': "/DRDATA/DSS", # old backup tape on hpss
99
99
  'RDAUSER' : "rdadata", # common rda user name
100
100
  'RDAEMAIL' : "zji", # specialist to receipt email intead of common rda user name
101
101
  'SUDORDA' : 0, # 1 to allow sudo to PGLOG['RDAUSER']
@@ -112,7 +112,7 @@ PGLOG = { # more defined in untaint_suid() with environment variables
112
112
  'PUSGDIR' : None,
113
113
  'BCHHOSTS' : "PBS",
114
114
  'HOSTTYPE' : 'dav', # default HOSTTYPE
115
- 'EMLMAX' : 256, # up limit of email line count
115
+ 'EMLMAX' : 256, # up limit of email line count
116
116
  'PGBATCH' : '', # current batch service name, SLURM or PBS
117
117
  'PGBINDIR' : '',
118
118
  'SLMTIME' : 604800, # max runtime for SLURM bath job, (7x24x60x60 seconds)
@@ -121,7 +121,7 @@ PGLOG = { # more defined in untaint_suid() with environment variables
121
121
  'RDAGRP' : "decs",
122
122
  'DSCHECK' : None, # carry some cached dscheck information
123
123
  'PGDBBUF' : None, # reference to a connected database object
124
- 'HPSSLMT' : 10, # up limit of HPSS streams
124
+ 'HPSSLMT' : 10, # up limit of HPSS streams
125
125
  'NOQUIT' : 0, # do not quit if this flag is set for daemons
126
126
  'DBRETRY' : 2, # db retry count after error
127
127
  'TIMEOUT' : 15, # default timeout (in seconds) for tosystem()
@@ -174,15 +174,15 @@ def current_datetime(ctime = 0):
174
174
  # get an environment variable and untaint it
175
175
  #
176
176
  def get_environment(name, default = None, logact = 0):
177
-
177
+
178
178
  env = os.getenv(name, default)
179
179
  if env is None and logact:
180
180
  pglog(name + ": Environment variable is not defined", logact)
181
181
 
182
182
  return env
183
-
183
+
184
184
  #
185
- # cache the msg string to global email entries for later call of send_email()
185
+ # cache the msg string to global email entries for later call of send_email()
186
186
  #
187
187
  def set_email(msg, logact = 0):
188
188
 
@@ -192,7 +192,7 @@ def set_email(msg, logact = 0):
192
192
  msg = PGLOG['PRGMSG'] + "\n" + msg
193
193
  PGLOG['PRGMSG'] = ""
194
194
  if PGLOG['ERRCNT'] == 0:
195
- if not re.search(r'\n$', msg): msg += "!\n"
195
+ if not re.search(r'\n$', msg): msg += "!\n"
196
196
  else:
197
197
  if PGLOG['ERRCNT'] == 1:
198
198
  msg += " with 1 Error:\n"
@@ -299,7 +299,7 @@ def send_email(subject = None, receiver = None, msg = None, sender = None, logac
299
299
  if receiver == PGLOG['RDAUSER']: receiver = PGLOG['RDAEMAIL']
300
300
  if receiver.find('@') == -1: receiver += "@ucar.edu"
301
301
 
302
- if docc and not re.match(PGLOG['RDAUSER'], sender): add_carbon_copy(sender, 1)
302
+ if docc and not re.match(PGLOG['RDAUSER'], sender): add_carbon_copy(sender, 1)
303
303
 
304
304
  emlmsg = "From: {}\nTo: {}\n".format(sender, receiver)
305
305
  logmsg = "Email " + receiver
@@ -336,7 +336,7 @@ def log_email(emlmsg):
336
336
  #
337
337
  # Function: cmdlog(cmdline)
338
338
  # cmdline - program name and all arguments
339
- # ctime - time (in seconds) when the command starts
339
+ # ctime - time (in seconds) when the command starts
340
340
  #
341
341
  def cmdlog(cmdline = None, ctime = 0, logact = None):
342
342
 
@@ -418,7 +418,11 @@ def pglog(msg, logact = MSGLOG):
418
418
  if not logact&NOTLOG:
419
419
  if logact&ERRLOG:
420
420
  if not PGLOG['ERRFILE']: PGLOG['ERRFILE'] = re.sub(r'.log$', '.err', PGLOG['LOGFILE'])
421
- ERR = open("{}/{}".format(PGLOG['LOGPATH'], PGLOG['ERRFILE']), 'a')
421
+ try:
422
+ ERR = open("{}/{}".format(PGLOG['LOGPATH'], PGLOG['ERRFILE']), 'a')
423
+ except FileNotFoundError:
424
+ ERR = open("error.log", 'a')
425
+ ERR.write(f"Error File not found: {PGLOG['LOGPATH']}/{PGLOG['ERRFILE']}")
422
426
  ERR.write(msg)
423
427
  if not logact&(EMLALL|SKPTRC): ERR.write(get_call_trace())
424
428
  ERR.close()
@@ -437,7 +441,7 @@ def pglog(msg, logact = MSGLOG):
437
441
  if logact&SEPLIN: OUT.write(PGLOG['SEPLINE'])
438
442
  OUT.write(msg)
439
443
 
440
-
444
+
441
445
  if logact&EXITLG:
442
446
  pgexit(1)
443
447
  else:
@@ -488,7 +492,7 @@ def get_caller_file(cidx = 0):
488
492
  return traceback.extract_stack()[cidx][0]
489
493
 
490
494
  #
491
- # log message, msg, for degugging processes according to the debug level
495
+ # log message, msg, for degugging processes according to the debug level
492
496
  #
493
497
  def pgdbg(level, msg = None, do_trace = True):
494
498
 
@@ -510,7 +514,7 @@ def pgdbg(level, msg = None, do_trace = True):
510
514
  if ms:
511
515
  levels[0] = int(ms.group(1)) if ms.group(1) else 0
512
516
  levels[1] = int(ms.group(2)) if ms.group(2) else 9999
513
-
517
+
514
518
  if level > levels[1] or level < levels[0]: return # debug level is out of range
515
519
 
516
520
  if 'DBGPATH' in PGLOG:
@@ -553,9 +557,9 @@ def pgtrim(line, rmcmt = 1):
553
557
  # set PGLOG['PUSGDIR'] from the program file with full path
554
558
  #
555
559
  def set_help_path(progfile):
556
-
560
+
557
561
  PGLOG['PUSGDIR'] = op.dirname(op.abspath(progfile))
558
-
562
+
559
563
  #
560
564
  # Function: show_usage(progname: Perl program name to get file "progname.usg")
561
565
  #
@@ -564,7 +568,7 @@ def set_help_path(progfile):
564
568
  #
565
569
  def show_usage(progname, opts = None):
566
570
 
567
- if PGLOG['PUSGDIR'] is None: set_help_path(get_caller_file())
571
+ if PGLOG['PUSGDIR'] is None: set_help_path(get_caller_file(1))
568
572
  usgname = join_paths(PGLOG['PUSGDIR'], progname + '.usg')
569
573
 
570
574
  if opts:
@@ -597,7 +601,7 @@ def show_usage(progname, opts = None):
597
601
  IN.close()
598
602
  else:
599
603
  os.system("more " + usgname)
600
-
604
+
601
605
  pgexit(0)
602
606
 
603
607
  #
@@ -647,7 +651,7 @@ def pgsystem(pgcmd, logact = LOGWRN, cmdopt = 5, instr = None, seconds = 0):
647
651
  if not pgcmd: return ret # empty command
648
652
 
649
653
  act = logact&~EXITLG
650
- if act&ERRLOG:
654
+ if act&ERRLOG:
651
655
  act &= ~ERRLOG
652
656
  act |= WARNLG
653
657
 
@@ -670,7 +674,7 @@ def pgsystem(pgcmd, logact = LOGWRN, cmdopt = 5, instr = None, seconds = 0):
670
674
  pglog("> " + cmdstr, cmdact)
671
675
  if cmdopt&512 and (instr or seconds):
672
676
  msg = ''
673
- if seconds: msg = 'Timeout = {} Seconds'.format(seconds)
677
+ if seconds: msg = 'Timeout = {} Seconds'.format(seconds)
674
678
  if instr: msg += ' With STDIN:\n' + instr
675
679
  if msg: pglog(msg, cmdact)
676
680
  stdlog = act if cmdopt&2 else 0
@@ -762,7 +766,7 @@ def pgsystem(pgcmd, logact = LOGWRN, cmdopt = 5, instr = None, seconds = 0):
762
766
  if ret == SUCCESS or loop >= loops: break
763
767
  time.sleep(6)
764
768
 
765
- if ret == FAILURE and retbuf and cmdopt&272 == 272:
769
+ if ret == FAILURE and retbuf and cmdopt&272 == 272:
766
770
  if PGLOG['SYSERR']: PGLOG['SYSERR'] += '\n'
767
771
  PGLOG['SYSERR'] += retbuf
768
772
  retbuf = ''
@@ -783,7 +787,7 @@ def strip_output_line(line):
783
787
  return line
784
788
 
785
789
  #
786
- # show command running time string formated by seconds_to_string_time()
790
+ # show command running time string formated by seconds_to_string_time()
787
791
  #
788
792
  def cmd_execute_time(cmdstr, last, logact = None):
789
793
 
@@ -816,7 +820,7 @@ def seconds_to_string_time(seconds, showzero = 0):
816
820
  msg += "{}D".format(int(hours/24)) # days
817
821
  if h: msg += "{}H".format(h)
818
822
  if m: msg += "{}M".format(m)
819
- if s:
823
+ if s:
820
824
  msg += "%dS"%(s) if isinstance(s, int) else "{:.3f}S".format(s)
821
825
  elif showzero:
822
826
  msg = "0S"
@@ -907,7 +911,7 @@ def break_long_string(lstr, limit = 1024, bsign = "\n", mline = 200, bchars = '
907
911
  # 1: remove path1 from path2
908
912
  #
909
913
  def join_paths(path1, path2, diff = 0):
910
-
914
+
911
915
  if not path2: return path1
912
916
  if not path1 or not diff and re.match('/', path2): return path2
913
917
 
@@ -1017,7 +1021,7 @@ def get_host(getbatch = 0):
1017
1021
  return PGLOG['HOSTNAME']
1018
1022
  else:
1019
1023
  host = socket.gethostname()
1020
-
1024
+
1021
1025
  return get_short_host(host)
1022
1026
 
1023
1027
  #
@@ -1069,7 +1073,7 @@ def get_pbs_host():
1069
1073
  return None
1070
1074
 
1071
1075
  #
1072
- # set host status, 0 dead & 1 live, for one or all avalaible slurm hosts
1076
+ # set host status, 0 dead & 1 live, for one or all avalaible slurm hosts
1073
1077
  #
1074
1078
  def set_slurm_host(host = None, stat = 0):
1075
1079
 
@@ -1084,7 +1088,7 @@ def set_slurm_host(host = None, stat = 0):
1084
1088
  SLMSTATS[host] = stat
1085
1089
 
1086
1090
  #
1087
- # set host status, 0 dead & 1 live, for one or all avalaible pbs hosts
1091
+ # set host status, 0 dead & 1 live, for one or all avalaible pbs hosts
1088
1092
  #
1089
1093
  def set_pbs_host(host = None, stat = 0):
1090
1094
 
@@ -1164,7 +1168,7 @@ def get_hpss_command(cmd, asuser = None, hcmd = None):
1164
1168
 
1165
1169
  cuser = PGLOG['SETUID'] if PGLOG['SETUID'] else PGLOG['CURUID']
1166
1170
  if not hcmd: hcmd = 'hsi'
1167
-
1171
+
1168
1172
  if asuser and cuser != asuser:
1169
1173
  if cuser == PGLOG['RDAUSER']:
1170
1174
  return "{} sudo -u {} {}".format(hcmd, asuser, cmd) # setuid wrapper as user asuser
@@ -1187,8 +1191,8 @@ def get_hpss_command(cmd, asuser = None, hcmd = None):
1187
1191
  def get_sync_command(host, asuser = None):
1188
1192
 
1189
1193
  host = get_short_host(host)
1190
-
1191
- if (not (PGLOG['SETUID'] and PGLOG['SETUID'] == PGLOG['RDAUSER']) and
1194
+
1195
+ if (not (PGLOG['SETUID'] and PGLOG['SETUID'] == PGLOG['RDAUSER']) and
1192
1196
  (not asuser or asuser == PGLOG['RDAUSER'])):
1193
1197
  return "sync" + host
1194
1198
 
@@ -1321,7 +1325,7 @@ def set_common_pglog():
1321
1325
  SETPGLOG("PVIEWHOST", "rda-pgdb-02.ucar.edu") # host name for view only postgresql server
1322
1326
  SETPGLOG("FTPUPLD", PGLOG['TRANSFER']+"/rossby") # ftp upload path
1323
1327
  PGLOG['GPFSROOTS'] = "{}|{}|{}".format(PGLOG['DSDHOME'], PGLOG['UPDTWKP'], PGLOG['RQSTHOME'])
1324
-
1328
+
1325
1329
  if 'ECCODES_DEFINITION_PATH' not in os.environ:
1326
1330
  os.environ['ECCODES_DEFINITION_PATH'] = "/usr/local/share/eccodes/definitions"
1327
1331
  os.environ['history'] = '0'
@@ -1336,12 +1340,20 @@ def set_common_pglog():
1336
1340
  os.environ['TMPDIR'] = PGLOG['TMPDIR']
1337
1341
 
1338
1342
  # empty diretory for HOST-sync
1343
+
1339
1344
  PGLOG['TMPSYNC'] = PGLOG['DSSDBHM'] + "/tmp/.syncdir"
1345
+
1346
+ os.umask(2)
1347
+
1348
+ #
1349
+ # check and return TMPSYNC path, and add it if not exists
1350
+ #
1351
+ def get_tmpsync_path():
1352
+
1340
1353
  if 'DSSHOME' in PGLOG and PGLOG['DSSHOME'] and not op.exists(PGLOG['TMPSYNC']):
1341
1354
  pgsystem("mkdir " + PGLOG['TMPSYNC'], 0, LGWNEX, 4)
1342
1355
  pgsystem("chmod 775 " + PGLOG['TMPSYNC'], LOGWRN, 4)
1343
-
1344
- os.umask(2)
1356
+ return PGLOG['TMPSYNC']
1345
1357
 
1346
1358
  #
1347
1359
  # append or prepend locpath to pgpath
@@ -1380,7 +1392,7 @@ def SETPGLOG(name, value = ''):
1380
1392
  # set specialist home and return the default shell
1381
1393
  #
1382
1394
  def set_specialist_home(specialist):
1383
-
1395
+
1384
1396
  if specialist == PGLOG['CURUID']: return # no need reset
1385
1397
  if 'MAIL' in os.environ and re.search(PGLOG['CURUID'], os.environ['MAIL']):
1386
1398
  os.environ['MAIL'] = re.sub(PGLOG['CURUID'], specialist, os.environ['MAIL'])
@@ -1501,11 +1513,11 @@ def check_process_host(hosts, chost = None, mflag = None, pinfo = None, logact =
1501
1513
  error = ''
1502
1514
  if not mflag: mflag = 'G'
1503
1515
  if not chost: chost = get_host(1)
1504
-
1516
+
1505
1517
  if mflag == 'M': # exact match
1506
1518
  if not hosts or hosts != chost:
1507
1519
  ret = 0
1508
- if pinfo: error = "not matched exactly"
1520
+ if pinfo: error = "not matched exactly"
1509
1521
  elif mflag == 'I': # inclusive match
1510
1522
  if not hosts or hosts.find('!') == 0 or hosts.find(chost) < 0:
1511
1523
  ret = 0
@@ -1514,7 +1526,7 @@ def check_process_host(hosts, chost = None, mflag = None, pinfo = None, logact =
1514
1526
  if hosts.find(chost) >= 0:
1515
1527
  if hosts.find('!') == 0:
1516
1528
  ret = 0
1517
- if pinfo: error = "matched exclusively"
1529
+ if pinfo: error = "matched exclusively"
1518
1530
  elif hosts.find('!') != 0:
1519
1531
  ret = 0
1520
1532
  if pinfo: error = "not matched"
@@ -1560,7 +1572,7 @@ def convert_chars(name, default = 'X'):
1560
1572
  # Retrieve host and process id
1561
1573
  #
1562
1574
  def current_process_info(realpid = 0):
1563
-
1575
+
1564
1576
  if realpid or PGLOG['CURBID'] < 1:
1565
1577
  return [PGLOG['HOSTNAME'], os.getpid()]
1566
1578
  else:
@@ -1589,7 +1601,7 @@ def argv_to_string(argv = None, quote = 1, action = None):
1589
1601
  return argstr
1590
1602
 
1591
1603
  #
1592
- # convert an integer to non-10 based string
1604
+ # convert an integer to non-10 based string
1593
1605
  #
1594
1606
  def int2base(x, base):
1595
1607
 
@@ -1607,9 +1619,9 @@ def int2base(x, base):
1607
1619
  dgts.reverse()
1608
1620
 
1609
1621
  return ''.join(dgts)
1610
-
1622
+
1611
1623
  #
1612
- # convert a non-10 based string to an integer
1624
+ # convert a non-10 based string to an integer
1613
1625
  #
1614
1626
  def base2int(x, base):
1615
1627
 
@@ -1633,7 +1645,7 @@ def base2int(x, base):
1633
1645
 
1634
1646
  #
1635
1647
  # convert integer to ordinal string
1636
- #
1648
+ #
1637
1649
  def int2order(num):
1638
1650
 
1639
1651
  ordstr = ['th', 'st', 'nd', 'rd']
@@ -9,7 +9,7 @@
9
9
  # Purpose : python library module for global misc utilities
10
10
  #
11
11
  # Github : https://github.com/NCAR/rda-python-common.git
12
- #
12
+ #
13
13
  ###############################################################################
14
14
  #
15
15
  import os
@@ -47,7 +47,7 @@ MDAYS = [365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
47
47
  # dt: optional given date in format of "YYYY-MM-DD"
48
48
  # return weekday: 0 - Sunday, 1 - Monday, ..., 6 - Saturday
49
49
  #
50
- def get_weekday(date = None):
50
+ def get_weekday(date = None):
51
51
 
52
52
  if date is None:
53
53
  ct = time.gmtime() if PgLOG.PGLOG['GMTZ'] else time.localtime()
@@ -117,23 +117,23 @@ def get_wday(wday, fmt = None):
117
117
  elif re.match(r'^WW', fmt):
118
118
  swday = swday.upper()
119
119
  else:
120
- swday = str(wday)
120
+ swday = str(wday)
121
121
  return swday
122
122
  else:
123
123
  return wday
124
124
 
125
125
  #
126
- # file: given file name
126
+ # file: given file name
127
127
  # Return: type if given file name is a valid online file; '' otherwise
128
128
  #
129
129
  def valid_online_file(file, type = None, exists = None):
130
-
130
+
131
131
  if exists is None or exists:
132
132
  if not op.exists(file): return '' # file does not exist
133
133
 
134
134
  bname = op.basename(file)
135
135
  if re.match(r'^,.*', bname): return '' # hidden file
136
-
136
+
137
137
  if re.search(r'index\.(htm|html|shtml)$', bname, re.I): return '' # index file
138
138
 
139
139
  if type and type != 'D': return type
@@ -166,9 +166,9 @@ def curdatetime():
166
166
  def curdatehour(fmt = None):
167
167
 
168
168
  ct = time.gmtime() if PgLOG.PGLOG['GMTZ'] else time.localtime()
169
-
169
+
170
170
  dt = fmtdate(ct[0], ct[1], ct[2], fmt) if fmt else time.strftime("%Y-%m-%d", ct)
171
-
171
+
172
172
  return [dt, ct[3]]
173
173
 
174
174
  #
@@ -187,9 +187,9 @@ def get_date_time(tm = None):
187
187
  elif isinstance(tm, datetime.datetime):
188
188
  act = str(tm).split(' ')
189
189
  elif isinstance(tm, datetime.date):
190
- act = [str(tm), '00:00:00']
190
+ act = [str(tm), '00:00:00']
191
191
  elif isinstance(tm, datetime.time):
192
- act = [None, str(tm)]
192
+ act = [None, str(tm)]
193
193
 
194
194
  if ct == None:
195
195
  return act if act else None
@@ -209,7 +209,7 @@ def get_datetime(tm = None):
209
209
  return tm
210
210
  elif isinstance(tm, (int, float)):
211
211
  ct = time.localtime(tm)
212
- return time.strftime("%Y-%m-%d %H:%M:%S", ct)
212
+ return time.strftime("%Y-%m-%d %H:%M:%S", ct)
213
213
  elif isinstance(tm, datetime.datetime):
214
214
  return str(tm)
215
215
  elif isinstance(tm, datetime.date):
@@ -223,7 +223,7 @@ def get_datetime(tm = None):
223
223
  # Return: timestsmp string in format of 'YYYYMMDDHHMMSS
224
224
  #
225
225
  def timestamp(file = None):
226
-
226
+
227
227
  if file is None:
228
228
  ct = time.gmtime() if PgLOG.PGLOG['GMTZ'] else time.localtime()
229
229
  else:
@@ -251,7 +251,7 @@ def check_datetime(date, default):
251
251
  def curdate(fmt = None):
252
252
 
253
253
  ct = time.gmtime() if PgLOG.PGLOG['GMTZ'] else time.localtime()
254
-
254
+
255
255
  return fmtdate(ct[0], ct[1], ct[2], fmt) if fmt else time.strftime("%Y-%m-%d", ct)
256
256
 
257
257
  #
@@ -314,19 +314,19 @@ def format_datehour(date, hour, tofmt = None, fromfmt = None):
314
314
  # split a date, time or datetime into an array according to
315
315
  # the sep value; str to int for digital values
316
316
  #
317
- def split_datetime(sdt, sep = '\D'):
317
+ def split_datetime(sdt, sep = r'\D'):
318
318
 
319
319
  if not isinstance(sdt, str): sdt = str(sdt)
320
320
  adt = re.split(sep, sdt)
321
321
  acnt = len(adt)
322
322
  for i in range(acnt):
323
- if re.match('^\d+$', adt[i]): adt[i] = int(adt[i])
323
+ if re.match(r'^\d+$', adt[i]): adt[i] = int(adt[i])
324
324
  return adt
325
325
 
326
326
  #
327
327
  # date: given date in format of fromfmt
328
328
  # tofmt: date formats; ex. "Month D, YYYY"
329
- # fromfmt: date formats, default to YYYY-MM-DD
329
+ # fromfmt: date formats, default to YYYY-MM-DD
330
330
  # Return: new formated date string according to tofmt
331
331
  #
332
332
  def format_date(cdate, tofmt = None, fromfmt = None):
@@ -338,8 +338,8 @@ def format_date(cdate, tofmt = None, fromfmt = None):
338
338
  mns = sep.join(MNS)
339
339
  months = sep.join(MONTHS)
340
340
  mkeys = ['D', 'M', 'Q', 'Y', 'C', 'H']
341
- PATTERNS = ['(\d\d\d\d)', '(\d+)', '(\d\d)',
342
- '(\d\d\d)', '(' + mns + ')', '(' + months + ')']
341
+ PATTERNS = [r'(\d\d\d\d)', r'(\d+)', r'(\d\d)',
342
+ r'(\d\d\d)', '(' + mns + ')', '(' + months + ')']
343
343
 
344
344
  if not fromfmt:
345
345
  if not tofmt:
@@ -358,7 +358,7 @@ def format_date(cdate, tofmt = None, fromfmt = None):
358
358
  if ms:
359
359
  fmts[mkey] = ms.group(1)
360
360
  pattern = re.sub(fmts[mkey], '', pattern)
361
-
361
+
362
362
  cnt = 0
363
363
  for mkey in fmts:
364
364
  fmt = fmts[mkey]
@@ -372,7 +372,7 @@ def format_date(cdate, tofmt = None, fromfmt = None):
372
372
  formats[fromfmt.find(fmt)] = fmt
373
373
  fromfmt = fromfmt.replace(fmt, PATTERNS[i])
374
374
  cnt += 1
375
-
375
+
376
376
  ms = re.findall(fromfmt, cdate)
377
377
  mcnt = len(ms[0]) if ms else 0
378
378
  i = 0
@@ -534,7 +534,7 @@ def fmtdate(yr, mn, dy, tofmt = None):
534
534
  if md:
535
535
  fmt = md.group(1) # quarter
536
536
  m = int((m+2)/3)
537
- smn = "{:02}".format(m) if len(fmt) == 2 else str(m)
537
+ smn = "{:02}".format(m) if len(fmt) == 2 else str(m)
538
538
  tofmt = re.sub(fmt, smn, tofmt, 1)
539
539
 
540
540
  if yr != None:
@@ -548,7 +548,7 @@ def fmtdate(yr, mn, dy, tofmt = None):
548
548
  if y > 999: y = int(y/10)
549
549
  syr = "{:03}".format(y)
550
550
  else:
551
- if re.search(r'^YY00', fmt, re.I): y = 100*int(y/100) # hundred years
551
+ if re.search(r'^YY00', fmt, re.I): y = 100*int(y/100) # hundred years
552
552
  syr = "{:04}".format(y)
553
553
  tofmt = re.sub(fmt, syr, tofmt, 1)
554
554
  else:
@@ -594,7 +594,7 @@ def date_and_time(sdt):
594
594
 
595
595
  #
596
596
  # convert given date/time to unix epoch time; -1 if cannot
597
- #
597
+ #
598
598
  def unixtime(stime):
599
599
 
600
600
  pt = [0]*9
@@ -666,7 +666,7 @@ def dtrange(dates):
666
666
  # Return: a string of formated period
667
667
  #
668
668
  def format_period(sdate, edate, fmt = None):
669
-
669
+
670
670
  period = ''
671
671
 
672
672
  if not fmt:
@@ -828,7 +828,7 @@ def addrecord(records, record, idx):
828
828
  records[key] = []
829
829
 
830
830
  for key in record:
831
- slen = len(records[key])
831
+ slen = len(records[key])
832
832
  if idx < slen:
833
833
  records[key][idx] = record[key]
834
834
  else:
@@ -851,7 +851,7 @@ def hash2array(hrecs, hkeys = None):
851
851
  arec = {}
852
852
  for hkey in hkeys: arec[hkey] = hrecs[hkey][i]
853
853
  arecs[i] = arec
854
-
854
+
855
855
  return arecs
856
856
 
857
857
  #
@@ -886,7 +886,7 @@ def hashcount(records, opt = 0):
886
886
  ret[0] = clen
887
887
  if opt == 1 or opt == 2:
888
888
  ret[1] = len(next(iter(records.values())))
889
-
889
+
890
890
  return ret if opt == 2 else ret[opt]
891
891
 
892
892
  #
@@ -950,7 +950,7 @@ def joinhash(adict, bdict, default = None, unique = None):
950
950
  # Return: the joined list
951
951
  #
952
952
  def joinarray(lst1, lst2, unique = None):
953
-
953
+
954
954
  if not lst2: return lst1
955
955
  if not lst1: return lst2
956
956
 
@@ -970,7 +970,7 @@ def joinarray(lst1, lst2, unique = None):
970
970
 
971
971
  #
972
972
  # Function: crosshash(ahash, bhash)
973
- # Return: a reference to the cross-joined hash records
973
+ # Return: a reference to the cross-joined hash records
974
974
  #
975
975
  def crosshash(ahash, bhash):
976
976
 
@@ -997,7 +997,7 @@ def crosshash(ahash, bhash):
997
997
  def strip_field(field):
998
998
  ms = re.search(r'\.([^\.]+)$', field)
999
999
  if ms: field = ms.group(1)
1000
-
1000
+
1001
1001
  return field
1002
1002
 
1003
1003
  #
@@ -1008,7 +1008,7 @@ def strip_field(field):
1008
1008
  # Return: a sorted dict list
1009
1009
  #
1010
1010
  def sorthash(pgrecs, flds, hash, patterns = None):
1011
-
1011
+
1012
1012
  fcnt = len(flds) # count of fields to be sorted on
1013
1013
 
1014
1014
  # set sorting order, descenting (-1) or ascenting (1)
@@ -1066,7 +1066,7 @@ def diffdate(date1, date2):
1066
1066
  ut1 = ut2 = 0
1067
1067
  if date1: ut1 = unixtime(date1)
1068
1068
  if date2: ut2 = unixtime(date2)
1069
- return round((ut1 - ut2)/86400) # 24*60*60
1069
+ return round((ut1 - ut2)/86400) # 24*60*60
1070
1070
 
1071
1071
  #
1072
1072
  # Return: the number of seconds bewteen time1 and time2
@@ -1089,7 +1089,7 @@ def get_days(cdate):
1089
1089
 
1090
1090
  #
1091
1091
  # Function: get_month_days(date)
1092
- #
1092
+ #
1093
1093
  # Return: the number of days in given month
1094
1094
  #
1095
1095
  def get_month_days(cdate):
@@ -1104,7 +1104,7 @@ def get_month_days(cdate):
1104
1104
 
1105
1105
  #
1106
1106
  # Function: validate_date(date)
1107
- #
1107
+ #
1108
1108
  # Return: a date in format of YYYY-MM-DD thar all year/month/day are validated
1109
1109
  #
1110
1110
  def validate_date(cdate):
@@ -1131,7 +1131,7 @@ def validate_date(cdate):
1131
1131
 
1132
1132
  #
1133
1133
  # Function: get_date(days)
1134
- #
1134
+ #
1135
1135
  # Return: the date in format of "YYYY-MM-DD" for given number of days
1136
1136
  # from '1970-01-01 00:00:00'
1137
1137
  #
@@ -1148,8 +1148,8 @@ def diffdatehour(date1, hour1, date2, hour2):
1148
1148
  if hour2 is None: hour2 = 23
1149
1149
  return (hour1 - hour2) + 24*diffdate(date1, date2)
1150
1150
 
1151
- #
1152
- # hour difference between GMT and local time
1151
+ #
1152
+ # hour difference between GMT and local time
1153
1153
  #
1154
1154
  def diffgmthour():
1155
1155
 
@@ -1206,7 +1206,7 @@ def addmonth(cdate, mf, nf = 1):
1206
1206
  mn -= 1
1207
1207
 
1208
1208
  dy += ody
1209
- cdate = fmtdate(yr, mn, dy)
1209
+ cdate = fmtdate(yr, mn, dy)
1210
1210
 
1211
1211
  return cdate
1212
1212
 
@@ -1230,7 +1230,7 @@ def addyearmonth(ym, yr, mn):
1230
1230
  yr += 1
1231
1231
  mn -= 12
1232
1232
 
1233
- ym = "{:04}{:02}".format(yr, mn)
1233
+ ym = "{:04}{:02}".format(yr, mn)
1234
1234
 
1235
1235
  return ym
1236
1236
 
@@ -1258,7 +1258,7 @@ def set_leap_mdays(year):
1258
1258
  # wrap on calendar.isleap()
1259
1259
  #
1260
1260
  def is_leapyear(year): return calendar.isleap(year)
1261
-
1261
+
1262
1262
  #
1263
1263
  # reutn 1 if is end of month
1264
1264
  #
@@ -1317,7 +1317,7 @@ def adjust_ymd(yr, mn, dy):
1317
1317
  # yr: the number of years to add/subtract from the odate for positive/negative value,
1318
1318
  # mn: the number of months to add/subtract from the odate for positive/negative value,
1319
1319
  # dy: the number of days to add/subtract from the odate for positive/negative value)
1320
- #
1320
+ #
1321
1321
  # Return: new date
1322
1322
  #
1323
1323
  def adddate(cdate, yr, mn = 0, dy = 0, tofmt = None):
@@ -1401,7 +1401,7 @@ def adddatehour(sdate, nhour, yr, mn, dy, hr = 0):
1401
1401
  if nhour != None: nhour = hr
1402
1402
 
1403
1403
  if yr or mn or dy: sdate = adddate(sdate, yr, mn, dy)
1404
-
1404
+
1405
1405
  return [sdate, nhour]
1406
1406
 
1407
1407
  #
@@ -1486,7 +1486,7 @@ def addintervals(sdatetime, intv, opt = 1):
1486
1486
  for v in intv:
1487
1487
  tv[i] = v
1488
1488
  i += 1
1489
-
1489
+
1490
1490
  # assume the given datetime is end of the current interval;
1491
1491
  # add one second to set it to beginning of the next one
1492
1492
  if opt == 0: sdatetime = adddatetime(sdatetime, 0, 0, 0 ,0, 0, 1)
@@ -1530,7 +1530,7 @@ def enddate(sdate, days, unit, nf = 0):
1530
1530
  dy = 1
1531
1531
  else:
1532
1532
  return sdate
1533
-
1533
+
1534
1534
  if not nf or nf == 1:
1535
1535
  nd = days if days else calendar.monthrange(yr, mn)[1]
1536
1536
  if nd != dy: sdate = fmtdate(yr, mn, nd)
@@ -1632,7 +1632,7 @@ def hour2time(sdate, nhour, endtime = 0):
1632
1632
  # Return: list of date and hour
1633
1633
  #
1634
1634
  def time2hour(stime):
1635
-
1635
+
1636
1636
  sdate = nhour = None
1637
1637
  times = stime.split(' ')
1638
1638
 
@@ -1691,14 +1691,14 @@ def pgcmp(val1, val2, ignorecase = 0, num = 0):
1691
1691
  val1 = int(val1)
1692
1692
  if typ2 is str:
1693
1693
  typ2 = int
1694
- val2 = int(val2)
1694
+ val2 = int(val2)
1695
1695
  else:
1696
1696
  if typ1 != str:
1697
1697
  typ1 = str
1698
- val1 = str(val1)
1698
+ val1 = str(val1)
1699
1699
  if typ2 != str:
1700
1700
  typ2 = str
1701
- val2 = str(val2)
1701
+ val2 = str(val2)
1702
1702
 
1703
1703
  if typ1 is str:
1704
1704
  if num:
@@ -1788,13 +1788,13 @@ def psearch(lidx, hidx, key, list):
1788
1788
  # quicksort for pattern
1789
1789
  #
1790
1790
  def quicksort(srecs, lo, hi, desc, cnt, nums = None):
1791
-
1791
+
1792
1792
  i = lo
1793
1793
  j = hi
1794
1794
  mrec = srecs[int((lo+hi)/2)]
1795
1795
 
1796
1796
  while True:
1797
- while cmp_records(srecs[i], mrec, desc, cnt, nums) < 0: i += 1
1797
+ while cmp_records(srecs[i], mrec, desc, cnt, nums) < 0: i += 1
1798
1798
  while cmp_records(srecs[j], mrec, desc, cnt, nums) > 0: j -= 1
1799
1799
  if i <= j:
1800
1800
  if i < j:
@@ -1808,11 +1808,11 @@ def quicksort(srecs, lo, hi, desc, cnt, nums = None):
1808
1808
  #recursion
1809
1809
  if lo < j: srecs = quicksort(srecs, lo, j, desc, cnt, nums)
1810
1810
  if i < hi: srecs = quicksort(srecs, i, hi, desc, cnt, nums)
1811
-
1811
+
1812
1812
  return srecs
1813
1813
 
1814
1814
  def cmp_records(arec, brec, desc, cnt, nums):
1815
-
1815
+
1816
1816
  for i in range(cnt):
1817
1817
  num = nums[i] if nums else 0
1818
1818
  ret = pgcmp(arec[i], brec[i], 0, num)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_common
3
- Version: 1.0.15
3
+ Version: 1.0.18
4
4
  Summary: RDA Python common library codes shared by other RDA python packages
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-common
@@ -11,6 +11,7 @@ Classifier: Development Status :: 5 - Production/Stable
11
11
  Requires-Python: >=3.7
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
+ Requires-Dist: psycopg2-binary
14
15
  Dynamic: license-file
15
16
 
16
17
  # rda-python-common
@@ -0,0 +1,15 @@
1
+ rda_python_common/PgCMD.py,sha256=dsFL_hiAHRZ-BwncgZhxQ7p9O10ox9lUSXOIePjZ-PQ,20487
2
+ rda_python_common/PgDBI.py,sha256=iGy0SQZsdVbSz2ewTIUK3e-RQBC5eQM9-_XUcFU1c50,74211
3
+ rda_python_common/PgFile.py,sha256=nCZcSYdKaa1okVVEvj1Wx6OUbYNAbPWYedoCNvqevQU,98405
4
+ rda_python_common/PgLOG.py,sha256=DFCQgcmbU04H6Kz9X9nxuFdLA1VNRBQefRvK8LvO9Pw,54273
5
+ rda_python_common/PgLock.py,sha256=12i84nsGBuifSyPnm8IR63LvHvRuVU573D5QKFlHdOI,22623
6
+ rda_python_common/PgOPT.py,sha256=BAfuNi_1jEK-UyYVfPY_0f4b7KLhpcFM3BDShLRvT7w,55446
7
+ rda_python_common/PgSIG.py,sha256=oDXcSnnzW6wKm_cSpFxQZWAo2hpPPTcuNDYhPSNQcRc,35607
8
+ rda_python_common/PgSplit.py,sha256=QKPbF55m8KCTGmwVwL3uG_nuylCC4FSVfLuXeLjJHbE,8816
9
+ rda_python_common/PgUtil.py,sha256=OqESKCd72b9g8m8jwjPJhXDtPYlW6G8oSOhwChvz2Cg,48600
10
+ rda_python_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ rda_python_common-1.0.18.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
12
+ rda_python_common-1.0.18.dist-info/METADATA,sha256=R0h15OPh-QBlAFt9CaFf1MdUAGZfqX4IAjwciMPPnHo,683
13
+ rda_python_common-1.0.18.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
+ rda_python_common-1.0.18.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
15
+ rda_python_common-1.0.18.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- rda_python_common/PgCMD.py,sha256=dsFL_hiAHRZ-BwncgZhxQ7p9O10ox9lUSXOIePjZ-PQ,20487
2
- rda_python_common/PgDBI.py,sha256=kDawKAKDYr8jLWl1RAS-6fbZOPrLv7SMjvvi4bx_638,74286
3
- rda_python_common/PgFile.py,sha256=RSCnABv7jOLmalzkQJnvXe-VgP6OQl3boeL8-Ja9qfY,98379
4
- rda_python_common/PgLOG.py,sha256=5j3vyZNJM3K0kECiJYVs9Y-I9gzoeE28Tlj5F1v7foo,54033
5
- rda_python_common/PgLock.py,sha256=12i84nsGBuifSyPnm8IR63LvHvRuVU573D5QKFlHdOI,22623
6
- rda_python_common/PgOPT.py,sha256=BAfuNi_1jEK-UyYVfPY_0f4b7KLhpcFM3BDShLRvT7w,55446
7
- rda_python_common/PgSIG.py,sha256=oDXcSnnzW6wKm_cSpFxQZWAo2hpPPTcuNDYhPSNQcRc,35607
8
- rda_python_common/PgSplit.py,sha256=QKPbF55m8KCTGmwVwL3uG_nuylCC4FSVfLuXeLjJHbE,8816
9
- rda_python_common/PgUtil.py,sha256=OpkNDwt694ebttNNUEDrrtDKyITZkx8g3uAI3b_FF4c,48737
10
- rda_python_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- rda_python_common-1.0.15.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
12
- rda_python_common-1.0.15.dist-info/METADATA,sha256=pjXuN892u24qa-KwVU46JJJsbRz_n-eDATkYn7JsQC4,652
13
- rda_python_common-1.0.15.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
- rda_python_common-1.0.15.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
15
- rda_python_common-1.0.15.dist-info/RECORD,,