rda-python-common 1.0.17__py3-none-any.whl → 1.0.21__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.

@@ -67,7 +67,7 @@ OHOST = PgLOG.PGLOG['OBJCTSTR']
67
67
  BHOST = PgLOG.PGLOG['BACKUPNM']
68
68
  DHOST = PgLOG.PGLOG['DRDATANM']
69
69
  OBJCTCMD = "isd_s3_cli"
70
- BACKCMD = "dsglobus"
70
+ BACKCMD = "dsglobus"
71
71
 
72
72
  HLIMIT = 0 # HTAR file count limit
73
73
  BLIMIT = 2 # minimum back tar file size in DB
@@ -338,17 +338,28 @@ def local_copy_object(tofile, fromfile, bucket = None, meta = None, logact = 0):
338
338
  def quasar_multiple_trasnfer(tofiles, fromfiles, topoint, frompoint, logact = 0):
339
339
 
340
340
  ret = PgLOG.FAILURE
341
- qstr = '{"action":"transfer","label":"%s","verify_checksum":true,' % ENDPOINTS[topoint]
342
- # qstr = '{"action":"transfer","label":"%s",' % ENDPOINTS[topoint]
343
- qstr += '"source_endpoint":"%s","destination_endpoint":"%s","files":[\n' % (frompoint, topoint)
341
+
344
342
  fcnt = len(fromfiles)
345
- bstr = ''
343
+ transfer_files = {"files": []}
346
344
  for i in range(fcnt):
347
- qstr += '%s{"source_file":"%s","destination_file":"%s"}' % (bstr, fromfiles[i], tofiles[i])
348
- if i == 0: bstr = ',\n'
349
- qstr += ']}'
350
-
351
- task = submit_globus_task(BACKCMD, topoint, logact, qstr)
345
+ transfer_files["files"].append({
346
+ "source_file": fromfiles[i],
347
+ "destination_file": tofiles[i]
348
+ })
349
+ qstr = json.dumps(transfer_files)
350
+
351
+ action = 'transfer'
352
+ source_endpoint = frompoint
353
+ destination_endpoint = topoint
354
+ label = f"{ENDPOINTS[frompoint]} to {ENDPOINTS[topoint]} {action}"
355
+ verify_checksum = True
356
+
357
+ cmd = f'{BACKCMD} {action} -se {source_endpoint} -de {destination_endpoint} --label "{label}"'
358
+ if verify_checksum:
359
+ cmd += ' -vc'
360
+ cmd += ' --batch -'
361
+
362
+ task = submit_globus_task(cmd, topoint, logact, qstr)
352
363
  if task['stat'] == 'S':
353
364
  ret = PgLOG.SUCCESS
354
365
  elif task['stat'] == 'A':
@@ -379,7 +390,9 @@ def endpoint_copy_endpoint(tofile, fromfile, topoint, frompoint, logact = 0):
379
390
  if tinfo and tinfo['data_size'] > 0:
380
391
  return PgLOG.pglog("{}-{}: file exists already".format(topoint, tofile), logact)
381
392
 
382
- cmd = "{} -t -vc -se {} -de {} -sf {} -df {}".format(BACKCMD, frompoint, topoint, fromfile, tofile)
393
+ action = 'transfer'
394
+ cmd = f'{BACKCMD} {action} -se {frompoint} -de {topoint} -sf {fromfile} -df {tofile} -vc'
395
+
383
396
  task = submit_globus_task(cmd, topoint, logact)
384
397
  if task['stat'] == 'S':
385
398
  ret = PgLOG.SUCCESS
@@ -435,7 +448,8 @@ def check_globus_status(taskid, endpoint = None, logact = 0):
435
448
  if not taskid: return ret
436
449
  if not endpoint: endpoint = PgLOG.PGLOG['BACKUPEP']
437
450
  mp = r'Status:\s+({})'.format('|'.join(QSTATS.values()))
438
- cmd = "{} -gt --task-id {}".format(BACKCMD, taskid)
451
+
452
+ cmd = f"{BACKCMD} get-task {taskid}"
439
453
  astats = ['OK', 'Queued']
440
454
 
441
455
  for loop in range(2):
@@ -452,7 +466,7 @@ def check_globus_status(taskid, endpoint = None, logact = 0):
452
466
  if logact&PgLOG.NOWAIT:
453
467
  errmsg = "{}: Cancel Task due to {}:\n{}".format(taskid, detail, buf)
454
468
  errlog(errmsg, 'B', 1, logact)
455
- ccmd = "{} -ct --task-id {}".format(BACKCMD, taskid)
469
+ ccmd = f"{BACKCMD} cancel-task {taskid}"
456
470
  PgLOG.pgsystem(ccmd, logact, 7)
457
471
  else:
458
472
  time.sleep(PgSIG.PGSIG['ETIME'])
@@ -759,7 +773,7 @@ def delete_backup_file(file, endpoint = None, logact = 0):
759
773
  info = check_backup_file(file, endpoint, 0, logact)
760
774
  if not info: return PgLOG.FAILURE
761
775
 
762
- cmd = "{} -d -ep {} -tf {}".format(BACKCMD, endpoint, file)
776
+ cmd = f"{BACKCMD} delete -ep {endpoint} -tf {file}"
763
777
  task = submit_globus_task(cmd, endpoint, logact)
764
778
  if task['stat'] == 'S':
765
779
  return PgLOG.SUCCESS
@@ -1028,7 +1042,7 @@ def move_backup_file(tofile, fromfile, endpoint = None, logact = 0):
1028
1042
  elif tinfo != None:
1029
1043
  return ret
1030
1044
 
1031
- cmd = "{} --rename -ep {} --oldpath {} --newpath {}".format(BACKCMD, endpoint, fromfile, tofile)
1045
+ cmd = f"{BACKCMD} rename -ep {endpoint} --old-path {fromfile} --new-path {tofile}"
1032
1046
  loop = 0
1033
1047
  while loop < 2:
1034
1048
  buf = PgLOG.pgsystem(cmd, logact, CMDRET)
@@ -1158,7 +1172,7 @@ def make_one_backup_directory(dir, odir, endpoint = None, logact = 0):
1158
1172
  if not odir: odir = dir
1159
1173
  if not make_one_backup_directory(op.dirname(dir), odir, endpoint, logact): return PgLOG.FAILURE
1160
1174
 
1161
- cmd = "{} --mkdir -ep {} -p {}".format(BACKCMD, endpoint, dir)
1175
+ cmd = f"{BACKCMD} mkdir -ep {endpoint} -p {dir}"
1162
1176
  for loop in range(2):
1163
1177
  buf = PgLOG.pgsystem(cmd, logact, CMDRET)
1164
1178
  syserr = PgLOG.PGLOG['SYSERR']
@@ -1843,7 +1857,7 @@ def check_backup_file(file, endpoint = None, opt = 0, logact = 0):
1843
1857
  if not endpoint: endpoint = PgLOG.PGLOG['BACKUPEP']
1844
1858
  bdir = op.dirname(file)
1845
1859
  bfile = op.basename(file)
1846
- cmd = "{} -ls -ep {} -p {} --filter {}".format(BACKCMD, endpoint, bdir, bfile)
1860
+ cmd = f"{BACKCMD} ls -ep {endpoint} -p {bdir} --filter {bfile}"
1847
1861
  ccnt = loop = 0
1848
1862
  while loop < 2:
1849
1863
  buf = PgLOG.pgsystem(cmd, logact, CMDRET)
@@ -2208,7 +2222,8 @@ def backup_glob(dir, endpoint = None, opt = 0, logact = 0):
2208
2222
 
2209
2223
  if not dir: return None
2210
2224
  if not endpoint: endpoint = PgLOG.PGLOG['BACKUPEP']
2211
- cmd = "{} -ls -ep {} -p {}".format(BACKCMD, endpoint, dir)
2225
+
2226
+ cmd = f"{BACKCMD} ls -ep {endpoint} -p {dir}"
2212
2227
  flist = {}
2213
2228
  for loop in range(2):
2214
2229
  buf = PgLOG.pgsystem(cmd, logact, CMDRET)
@@ -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
  #
@@ -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,6 +1340,7 @@ 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"
1340
1345
 
1341
1346
  os.umask(2)
@@ -1387,7 +1392,7 @@ def SETPGLOG(name, value = ''):
1387
1392
  # set specialist home and return the default shell
1388
1393
  #
1389
1394
  def set_specialist_home(specialist):
1390
-
1395
+
1391
1396
  if specialist == PGLOG['CURUID']: return # no need reset
1392
1397
  if 'MAIL' in os.environ and re.search(PGLOG['CURUID'], os.environ['MAIL']):
1393
1398
  os.environ['MAIL'] = re.sub(PGLOG['CURUID'], specialist, os.environ['MAIL'])
@@ -1508,11 +1513,11 @@ def check_process_host(hosts, chost = None, mflag = None, pinfo = None, logact =
1508
1513
  error = ''
1509
1514
  if not mflag: mflag = 'G'
1510
1515
  if not chost: chost = get_host(1)
1511
-
1516
+
1512
1517
  if mflag == 'M': # exact match
1513
1518
  if not hosts or hosts != chost:
1514
1519
  ret = 0
1515
- if pinfo: error = "not matched exactly"
1520
+ if pinfo: error = "not matched exactly"
1516
1521
  elif mflag == 'I': # inclusive match
1517
1522
  if not hosts or hosts.find('!') == 0 or hosts.find(chost) < 0:
1518
1523
  ret = 0
@@ -1521,7 +1526,7 @@ def check_process_host(hosts, chost = None, mflag = None, pinfo = None, logact =
1521
1526
  if hosts.find(chost) >= 0:
1522
1527
  if hosts.find('!') == 0:
1523
1528
  ret = 0
1524
- if pinfo: error = "matched exclusively"
1529
+ if pinfo: error = "matched exclusively"
1525
1530
  elif hosts.find('!') != 0:
1526
1531
  ret = 0
1527
1532
  if pinfo: error = "not matched"
@@ -1567,7 +1572,7 @@ def convert_chars(name, default = 'X'):
1567
1572
  # Retrieve host and process id
1568
1573
  #
1569
1574
  def current_process_info(realpid = 0):
1570
-
1575
+
1571
1576
  if realpid or PGLOG['CURBID'] < 1:
1572
1577
  return [PGLOG['HOSTNAME'], os.getpid()]
1573
1578
  else:
@@ -1596,7 +1601,7 @@ def argv_to_string(argv = None, quote = 1, action = None):
1596
1601
  return argstr
1597
1602
 
1598
1603
  #
1599
- # convert an integer to non-10 based string
1604
+ # convert an integer to non-10 based string
1600
1605
  #
1601
1606
  def int2base(x, base):
1602
1607
 
@@ -1614,9 +1619,9 @@ def int2base(x, base):
1614
1619
  dgts.reverse()
1615
1620
 
1616
1621
  return ''.join(dgts)
1617
-
1622
+
1618
1623
  #
1619
- # convert a non-10 based string to an integer
1624
+ # convert a non-10 based string to an integer
1620
1625
  #
1621
1626
  def base2int(x, base):
1622
1627
 
@@ -1640,7 +1645,7 @@ def base2int(x, base):
1640
1645
 
1641
1646
  #
1642
1647
  # convert integer to ordinal string
1643
- #
1648
+ #
1644
1649
  def int2order(num):
1645
1650
 
1646
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.17
3
+ Version: 1.0.21
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,8 @@ 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
15
+ Requires-Dist: rda-python-globus
14
16
  Dynamic: license-file
15
17
 
16
18
  # rda-python-common
@@ -1,15 +1,15 @@
1
1
  rda_python_common/PgCMD.py,sha256=dsFL_hiAHRZ-BwncgZhxQ7p9O10ox9lUSXOIePjZ-PQ,20487
2
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=ZbXbOshjGwqYxpUAqTZqkViOBEZ_zVZF_t2SZ_q_AJg,54149
3
+ rda_python_common/PgFile.py,sha256=756onQnWH_MK8llF0-8b6yV6KC1eY_eCPEkygxeJQQU,98460
4
+ rda_python_common/PgLOG.py,sha256=DFCQgcmbU04H6Kz9X9nxuFdLA1VNRBQefRvK8LvO9Pw,54273
5
5
  rda_python_common/PgLock.py,sha256=12i84nsGBuifSyPnm8IR63LvHvRuVU573D5QKFlHdOI,22623
6
6
  rda_python_common/PgOPT.py,sha256=BAfuNi_1jEK-UyYVfPY_0f4b7KLhpcFM3BDShLRvT7w,55446
7
7
  rda_python_common/PgSIG.py,sha256=oDXcSnnzW6wKm_cSpFxQZWAo2hpPPTcuNDYhPSNQcRc,35607
8
8
  rda_python_common/PgSplit.py,sha256=QKPbF55m8KCTGmwVwL3uG_nuylCC4FSVfLuXeLjJHbE,8816
9
- rda_python_common/PgUtil.py,sha256=OpkNDwt694ebttNNUEDrrtDKyITZkx8g3uAI3b_FF4c,48737
9
+ rda_python_common/PgUtil.py,sha256=OqESKCd72b9g8m8jwjPJhXDtPYlW6G8oSOhwChvz2Cg,48600
10
10
  rda_python_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- rda_python_common-1.0.17.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
12
- rda_python_common-1.0.17.dist-info/METADATA,sha256=JOGDLYq0Z3xG0w-JTzBzmHg0WJCmIN0PBTd1DD8ZkuI,652
13
- rda_python_common-1.0.17.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
- rda_python_common-1.0.17.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
15
- rda_python_common-1.0.17.dist-info/RECORD,,
11
+ rda_python_common-1.0.21.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
12
+ rda_python_common-1.0.21.dist-info/METADATA,sha256=aDnBKTHLFSlswpAfmoCtJ6aK_rbymOqV1PkG5b1zUnU,716
13
+ rda_python_common-1.0.21.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
+ rda_python_common-1.0.21.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
15
+ rda_python_common-1.0.21.dist-info/RECORD,,