rda-python-common 1.0.16__tar.gz → 1.0.18__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.
Potentially problematic release.
This version of rda-python-common might be problematic. Click here for more details.
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/PKG-INFO +2 -1
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/pyproject.toml +9 -1
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgFile.py +2 -1
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgLOG.py +56 -44
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgUtil.py +52 -52
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/PKG-INFO +2 -1
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/SOURCES.txt +3 -1
- rda_python_common-1.0.18/src/rda_python_common.egg-info/requires.txt +1 -0
- rda_python_common-1.0.18/test/test_common.py +16 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/LICENSE +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/README.md +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/setup.cfg +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgCMD.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgDBI.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgLock.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgOPT.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgSIG.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/PgSplit.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common/__init__.py +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/dependency_links.txt +0 -0
- {rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 1.0.
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rda_python_common"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.18"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Zaihua Ji", email="zji@ucar.edu" },
|
|
10
10
|
]
|
|
@@ -17,6 +17,14 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
"Development Status :: 5 - Production/Stable",
|
|
19
19
|
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"psycopg2-binary"
|
|
22
|
+
]
|
|
20
23
|
|
|
21
24
|
[project.urls]
|
|
22
25
|
"Homepage" = "https://github.com/NCAR/rda-python-common"
|
|
26
|
+
|
|
27
|
+
[tool.pytest.ini_options]
|
|
28
|
+
pythonpath = [
|
|
29
|
+
"src"
|
|
30
|
+
]
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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,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)
|
{rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 1.0.
|
|
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
|
{rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/SOURCES.txt
RENAMED
|
@@ -14,4 +14,6 @@ src/rda_python_common/__init__.py
|
|
|
14
14
|
src/rda_python_common.egg-info/PKG-INFO
|
|
15
15
|
src/rda_python_common.egg-info/SOURCES.txt
|
|
16
16
|
src/rda_python_common.egg-info/dependency_links.txt
|
|
17
|
-
src/rda_python_common.egg-info/
|
|
17
|
+
src/rda_python_common.egg-info/requires.txt
|
|
18
|
+
src/rda_python_common.egg-info/top_level.txt
|
|
19
|
+
test/test_common.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
psycopg2-binary
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# test_hello_world.py
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_common():
|
|
8
|
+
import rda_python_common.PgCMD
|
|
9
|
+
import rda_python_common.PgDBI
|
|
10
|
+
import rda_python_common.PgFile
|
|
11
|
+
import rda_python_common.PgLock
|
|
12
|
+
import rda_python_common.PgLOG
|
|
13
|
+
import rda_python_common.PgOPT
|
|
14
|
+
import rda_python_common.PgSIG
|
|
15
|
+
import rda_python_common.PgSplit
|
|
16
|
+
import rda_python_common.PgUtil
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_common-1.0.16 → rda_python_common-1.0.18}/src/rda_python_common.egg-info/top_level.txt
RENAMED
|
File without changes
|