rda-python-miscs 1.0.6__tar.gz → 2.0.0__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.
- {rda_python_miscs-1.0.6/src/rda_python_miscs.egg-info → rda_python_miscs-2.0.0}/PKG-INFO +1 -1
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/pyproject.toml +5 -11
- rda_python_miscs-1.0.6/src/rda_python_miscs/bashqsub.py → rda_python_miscs-2.0.0/src/rda_python_miscs/bash_qsub.py +10 -10
- rda_python_miscs-2.0.0/src/rda_python_miscs/bashqsub.py +182 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/bashqsub.usg +11 -11
- rda_python_miscs-2.0.0/src/rda_python_miscs/gdexls.py +240 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/gdexls_standalone.py +2 -2
- rda_python_miscs-2.0.0/src/rda_python_miscs/pgwget.py +171 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdacp.py +190 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdakill.py +231 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdamod.py +152 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdaown.py +150 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdaps.py +173 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdasub.py +112 -0
- rda_python_miscs-2.0.0/src/rda_python_miscs/rdazip.py +66 -0
- rda_python_miscs-1.0.6/src/rda_python_miscs/tcshqsub.py → rda_python_miscs-2.0.0/src/rda_python_miscs/tcsh_qsub.py +8 -8
- rda_python_miscs-2.0.0/src/rda_python_miscs/tcshqsub.py +182 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/tcshqsub.usg +13 -13
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0/src/rda_python_miscs.egg-info}/PKG-INFO +1 -1
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/SOURCES.txt +11 -0
- rda_python_miscs-2.0.0/tests/test_miscs.py +16 -0
- rda_python_miscs-1.0.6/tests/test_miscs.py +0 -6
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/LICENSE +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/MANIFEST.in +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/README.md +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/setup.cfg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/__init__.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/gdexls.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/gdex_ls.py +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/gdexls.usg +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/pgwget.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/pg_wget.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdacp.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_cp.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdakill.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_kill.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdamod.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_mod.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdaown.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_own.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdaps.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_ps.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdasub.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_sub.py +0 -0
- /rda_python_miscs-1.0.6/src/rda_python_miscs/rdazip.py → /rda_python_miscs-2.0.0/src/rda_python_miscs/rda_zip.py +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdacp.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdakill.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdals.py +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdals.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdamod.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdaown.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdaps.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdasub.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdazip.usg +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/dependency_links.txt +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/entry_points.txt +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/requires.txt +0 -0
- {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "rda_python_miscs"
|
|
9
|
-
version = "
|
|
9
|
+
version = "2.0.0"
|
|
10
10
|
authors = [
|
|
11
11
|
{ name="Zaihua Ji", email="zji@ucar.edu" },
|
|
12
12
|
]
|
|
@@ -24,16 +24,10 @@ dependencies = [
|
|
|
24
24
|
"rda_python_setuid",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
|
-
[tool.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
where = ["src"]
|
|
32
|
-
|
|
33
|
-
[tool.setuptools.package-data]
|
|
34
|
-
"rda_python_miscs" = ["bashqsub.usg", "tcshqsub.usg", "rdasub.usg", "rdacp.usg",
|
|
35
|
-
"rdakill.usg", "rdals.usg", "rdamod.usg", "rdaown.usg",
|
|
36
|
-
"rdaps.usg", "rdazip.usg"]
|
|
27
|
+
[tool.pytest.ini_options]
|
|
28
|
+
pythonpath = [
|
|
29
|
+
"src"
|
|
30
|
+
]
|
|
37
31
|
|
|
38
32
|
[project.urls]
|
|
39
33
|
"Homepage" = "https://github.com/NCAR/rda-python-miscs"
|
|
@@ -24,7 +24,7 @@ DEFMODS = {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
DEFLIBS = {
|
|
27
|
-
'default' : "conda activate /glade/work/gdexdata/conda-envs/pg-
|
|
27
|
+
'default' : "conda activate /glade/work/gdexdata/conda-envs/pg-gdex",
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
SWAPMODS = {
|
|
@@ -39,7 +39,7 @@ SOPTIONS = { # single-dash option values
|
|
|
39
39
|
'o' : None, # will set to default if not provided
|
|
40
40
|
'e' : None,
|
|
41
41
|
'A' : "P43713000",
|
|
42
|
-
'q' : "
|
|
42
|
+
'q' : "gdex@casper-pbs",
|
|
43
43
|
# 'm' : 'a',
|
|
44
44
|
'm' : 'n',
|
|
45
45
|
}
|
|
@@ -50,9 +50,9 @@ SOPTIONS = { # single-dash option values
|
|
|
50
50
|
def main():
|
|
51
51
|
|
|
52
52
|
aname = 'bashqsub'
|
|
53
|
-
pname = '
|
|
53
|
+
pname = 'gdexqsub'
|
|
54
54
|
PgLOG.set_help_path(__file__)
|
|
55
|
-
|
|
55
|
+
gdexsub = PgLOG.BCHCMDS['PBS']
|
|
56
56
|
coptions = {'cmd' : None, 'cwd' : None, 'env' : None, 'mod' : None, 'res' : 'default'} # customized options
|
|
57
57
|
copts = '|'.join(coptions)
|
|
58
58
|
option = None
|
|
@@ -61,7 +61,7 @@ def main():
|
|
|
61
61
|
if not argv: PgLOG.show_usage(aname)
|
|
62
62
|
PgLOG.PGLOG['LOGFILE'] = pname + ".log"
|
|
63
63
|
PgLOG.cmdlog("{} {}".format(aname, ' '.join(argv)))
|
|
64
|
-
if not PgLOG.valid_command(
|
|
64
|
+
if not PgLOG.valid_command(gdexsub): PgLOG.pglog("{}: miss {} command to submit batch job".format(gdexsub, PgLOG.PGLOG['PBSNAME']), PgLOG.LGWNEX)
|
|
65
65
|
|
|
66
66
|
while argv:
|
|
67
67
|
arg = argv.pop(0)
|
|
@@ -80,7 +80,7 @@ def main():
|
|
|
80
80
|
if option == "env": option = 'v'
|
|
81
81
|
continue
|
|
82
82
|
|
|
83
|
-
if not option: PgLOG.pglog("{}: Value passed in without leading option for {}".format(arg,
|
|
83
|
+
if not option: PgLOG.pglog("{}: Value passed in without leading option for {}".format(arg, gdexsub), PgLOG.LGEREX)
|
|
84
84
|
if arg.find(' ') > -1 and not re.match(r'^[\'\"].*[\'\"]$', arg): # quote string with space but not quoted yet
|
|
85
85
|
if arg.find("'") > -1:
|
|
86
86
|
arg = '"{}"'.format(arg)
|
|
@@ -102,7 +102,7 @@ def main():
|
|
|
102
102
|
msg = "{}-{}{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.PGLOG['CURUID'], PgLOG.current_datetime())
|
|
103
103
|
|
|
104
104
|
if coptions['cwd']:
|
|
105
|
-
if coptions['cwd']
|
|
105
|
+
if 's' in coptions['cwd']: coptions['cwd'] = PgLOG.replace_environments(coptions['cwd'], '', PgLOG.LGWNEX)
|
|
106
106
|
msg += "-" + coptions['cwd']
|
|
107
107
|
os.chdir(coptions['cwd'])
|
|
108
108
|
|
|
@@ -111,10 +111,10 @@ def main():
|
|
|
111
111
|
if not cmd: PgLOG.pglog(coptions['cmd'] + ": Cannot find given command to run", PgLOG.LGWNEX)
|
|
112
112
|
if args: cmd += " " + args
|
|
113
113
|
|
|
114
|
-
sbuf = build_bash_script(cmd, coptions,
|
|
114
|
+
sbuf = build_bash_script(cmd, coptions, gdexsub)
|
|
115
115
|
PgLOG.pglog(sbuf, PgLOG.MSGLOG)
|
|
116
116
|
PgLOG.PGLOG['ERR2STD'] = ['bind mouting']
|
|
117
|
-
PgLOG.pgsystem(
|
|
117
|
+
PgLOG.pgsystem(gdexsub, PgLOG.LOGWRN, 6, sbuf)
|
|
118
118
|
PgLOG.PGLOG['ERR2STD'] = []
|
|
119
119
|
|
|
120
120
|
sys.exit(0)
|
|
@@ -122,7 +122,7 @@ def main():
|
|
|
122
122
|
#
|
|
123
123
|
# build bash script to submit a PBS batch job
|
|
124
124
|
#
|
|
125
|
-
def build_bash_script(cmd, coptions,
|
|
125
|
+
def build_bash_script(cmd, coptions, gdexsub):
|
|
126
126
|
|
|
127
127
|
buf = "#!/usr/bin/bash\n\n" # qsub starting bash script
|
|
128
128
|
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
##################################################################################
|
|
3
|
+
# Title: bashqsub
|
|
4
|
+
# Author: Zaihua Ji, zji@ucar.edu
|
|
5
|
+
# Date: 11/19/2020
|
|
6
|
+
# 2025-03-07 transferred to package rda_python_miscs from
|
|
7
|
+
# https://github.com/NCAR/rda-utility-programs.git
|
|
8
|
+
# 2025-12-29 convert to class BashQsub
|
|
9
|
+
# Purpose: python script to submit a batch job on PBS node via bash script
|
|
10
|
+
# Github: https://github.com/NCAR/rda-pythn-miscs.git
|
|
11
|
+
##################################################################################
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
import re
|
|
15
|
+
from os import path as op
|
|
16
|
+
from rda_python_common.pg_log import PgLOG
|
|
17
|
+
|
|
18
|
+
class BashQsub(PgLOG):
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
super().__init__()
|
|
22
|
+
self.DEFMODS = {
|
|
23
|
+
'default': "ncarenv,netcdf,ncl,nco,cdo,conda,grib-util,wgrib2"
|
|
24
|
+
}
|
|
25
|
+
self.DEFLIBS = {
|
|
26
|
+
'default': "conda activate /glade/work/gdexdata/conda-envs/pg-gdex"
|
|
27
|
+
}
|
|
28
|
+
self.SWAPMODS = {}
|
|
29
|
+
self.RESOURCES = { # resource list for option -l
|
|
30
|
+
'walltime': '6:00:00', # if this is changed, change defpbstime in PgCheck.py too
|
|
31
|
+
'select': '1:ncpus=1:mem=1gb'
|
|
32
|
+
}
|
|
33
|
+
self.SOPTIONS = { # single-dash option values
|
|
34
|
+
'o': None, # will set to default if not provided
|
|
35
|
+
'e': None,
|
|
36
|
+
'A': "P43713000",
|
|
37
|
+
'q': "gdex@casper-pbs",
|
|
38
|
+
# 'm': 'a',
|
|
39
|
+
'm': 'n',
|
|
40
|
+
}
|
|
41
|
+
self.coptions = {'cmd': None, 'cwd': None, 'env': None, 'mod': None, 'res': 'default'} # customized options
|
|
42
|
+
self.gdexsub = self.BCHCMDS['PBS']
|
|
43
|
+
self.args = None
|
|
44
|
+
|
|
45
|
+
# function to readparameters
|
|
46
|
+
def read_parameters(self):
|
|
47
|
+
aname = 'bashqsub'
|
|
48
|
+
pname = 'gdexqsub'
|
|
49
|
+
self.set_help_path(__file__)
|
|
50
|
+
copts = '|'.join(self.coptions)
|
|
51
|
+
option = None
|
|
52
|
+
argv = sys.argv[1:]
|
|
53
|
+
if not argv: self.show_usage(aname)
|
|
54
|
+
self.PGLOG['LOGFILE'] = pname + ".log"
|
|
55
|
+
self.cmdlog("{} {}".format(aname, ' '.join(argv)))
|
|
56
|
+
if not self.valid_command(self.gdexsub): self.pglog("{}: miss {} command to submit batch job".format(self.gdexsub, self.PGLOG['PBSNAME']), self.LGWNEX)
|
|
57
|
+
while argv:
|
|
58
|
+
arg = argv.pop(0)
|
|
59
|
+
ms = re.match(r'^-(\w)$', arg)
|
|
60
|
+
if ms:
|
|
61
|
+
option = ms.group(1)
|
|
62
|
+
if option == "b":
|
|
63
|
+
self.PGLOG['BCKGRND'] = 1
|
|
64
|
+
option = None
|
|
65
|
+
else:
|
|
66
|
+
self.SOPTIONS[option] = ''
|
|
67
|
+
continue
|
|
68
|
+
ms = re.match(r'^-({})$'.format(copts), arg)
|
|
69
|
+
if ms:
|
|
70
|
+
option = ms.group(1)
|
|
71
|
+
if option == "env": option = 'v'
|
|
72
|
+
continue
|
|
73
|
+
if not option: self.pglog("{}: Value passed in without leading option for {}".format(arg, self.gdexsub), self.LGEREX)
|
|
74
|
+
if arg.find(' ') > -1 and not re.match(r'^[\'\"].*[\'\"]$', arg): # quote string with space but not quoted yet
|
|
75
|
+
if arg.find("'") > -1:
|
|
76
|
+
arg = '"{}"'.format(arg)
|
|
77
|
+
else:
|
|
78
|
+
arg = "'{}'".format(arg)
|
|
79
|
+
if option in self.coptions:
|
|
80
|
+
self.coptions[option] = arg
|
|
81
|
+
if option == "cmd": break
|
|
82
|
+
else:
|
|
83
|
+
self.SOPTIONS[option] = arg
|
|
84
|
+
option = None
|
|
85
|
+
self.args = self.argv_to_string(argv, 0) # append command options
|
|
86
|
+
if not self.coptions['cmd']: self.pglog(aname + ": specify command via option -cmd to run", self.LGWNEX)
|
|
87
|
+
if not self.SOPTIONS['o']: self.SOPTIONS['o'] = "{}/{}/".format(self.PGLOG['LOGPATH'], pname)
|
|
88
|
+
if not self.SOPTIONS['e']: self.SOPTIONS['e'] = "{}/{}/".format(self.PGLOG['LOGPATH'], pname)
|
|
89
|
+
if 'N' not in self.SOPTIONS: self.SOPTIONS['N'] = op.basename(self.coptions['cmd'])
|
|
90
|
+
if self.coptions['cwd']:
|
|
91
|
+
if 's' in self.coptions['cwd']: self.coptions['cwd'] = self.replace_environments(self.coptions['cwd'], '', self.LGWNEX)
|
|
92
|
+
os.chdir(self.coptions['cwd'])
|
|
93
|
+
|
|
94
|
+
# function to start actions
|
|
95
|
+
def start_actions(self):
|
|
96
|
+
cmd = self.valid_command(self.coptions['cmd'])
|
|
97
|
+
if not cmd and not re.match(r'^/', self.coptions['cmd']): cmd = self.valid_command('./' + self.coptions['cmd'])
|
|
98
|
+
if not cmd: self.pglog(self.coptions['cmd'] + ": Cannot find given command to run", self.LGWNEX)
|
|
99
|
+
if self.args: cmd += " " + self.args
|
|
100
|
+
sbuf = self.build_bash_script(cmd)
|
|
101
|
+
self.pglog(sbuf, self.MSGLOG)
|
|
102
|
+
self.PGLOG['ERR2STD'] = ['bind mouting']
|
|
103
|
+
self.pgsystem(self.gdexsub, self.LOGWRN, 6, sbuf)
|
|
104
|
+
self.PGLOG['ERR2STD'] = []
|
|
105
|
+
|
|
106
|
+
# build bash script to submit a PBS batch job
|
|
107
|
+
def build_bash_script(self, cmd):
|
|
108
|
+
buf = "#!/usr/bin/bash\n\n" # qsub starting bash script
|
|
109
|
+
if 'l' in self.SOPTIONS: self.add_resources()
|
|
110
|
+
# add options to bash script for qsub
|
|
111
|
+
for option in self.SOPTIONS:
|
|
112
|
+
buf += "#PBS -" + option
|
|
113
|
+
if self.SOPTIONS[option]: buf += " {}".format(self.SOPTIONS[option])
|
|
114
|
+
buf += "\n"
|
|
115
|
+
for option in self.RESOURCES:
|
|
116
|
+
buf += "#PBS -l"
|
|
117
|
+
if self.RESOURCES[option]: buf += " {}={}".format(option, self.RESOURCES[option])
|
|
118
|
+
buf += "\n"
|
|
119
|
+
# always include the login user's bash resource file
|
|
120
|
+
homedir = "{}/{}".format(self.PGLOG['USRHOME'], self.PGLOG['CURUID'])
|
|
121
|
+
buf += "export HOME={}\n".format(homedir)
|
|
122
|
+
buf += "source /etc/profile.d/z00_modules.sh\n"
|
|
123
|
+
buf += "source /glade/u/apps/opt/conda/etc/profile.d/conda.sh\n"
|
|
124
|
+
buf += "source {}/.bashrc\n".format(homedir)
|
|
125
|
+
buf += "pwd; hostname; date\n"
|
|
126
|
+
buf += self.add_modules(self.coptions['res'], self.coptions['mod'])
|
|
127
|
+
buf += self.set_vm_libs(self.coptions['res'])
|
|
128
|
+
buf += "\necho {}\n{}\n\ndate\n".format(cmd, cmd)
|
|
129
|
+
return buf
|
|
130
|
+
|
|
131
|
+
# check and add resource options
|
|
132
|
+
def add_resources(self):
|
|
133
|
+
for res in re.split(',', self.SOPTIONS['l']):
|
|
134
|
+
ms = re.match(r'^([^=]+)=(.+)$', res)
|
|
135
|
+
if ms:
|
|
136
|
+
self.RESOURCES[ms.group(1)] = ms.group(2)
|
|
137
|
+
else:
|
|
138
|
+
self.pglog(res + ": use '=' to separate resource name & value", self.LGEREX)
|
|
139
|
+
del self.SOPTIONS['l']
|
|
140
|
+
|
|
141
|
+
# add module loads for modules provided
|
|
142
|
+
def add_modules(self, res, mods):
|
|
143
|
+
mbuf = "\n"
|
|
144
|
+
defmods = self.DEFMODS[res] if res in self.DEFMODS else self.DEFMODS['default']
|
|
145
|
+
dmods = re.split(',', defmods)
|
|
146
|
+
for dmod in dmods:
|
|
147
|
+
ms = re.match(r'^(.+)/', dmod)
|
|
148
|
+
smod = ms.group(1) if ms else dmod
|
|
149
|
+
if smod in self.SWAPMODS: mbuf += "module unload {}\n".format(self.SWAPMODS[smod])
|
|
150
|
+
mbuf += "module load {}\n".format(dmod)
|
|
151
|
+
if mods:
|
|
152
|
+
amods = re.split(',', mods)
|
|
153
|
+
for amod in amods:
|
|
154
|
+
if re.match(r'^/', amod):
|
|
155
|
+
mbuf += "module use {}\n".format(amod)
|
|
156
|
+
else:
|
|
157
|
+
ms = re.match(r'^(.+)/', amod)
|
|
158
|
+
smod = ms.group(1) if ms else amod
|
|
159
|
+
if smod in dmods: continue
|
|
160
|
+
if smod in self.SWAPMODS: mbuf += "module unload {}\n".format(self.SWAPMODS[smod])
|
|
161
|
+
mbuf += "module load {}\n".format(amod)
|
|
162
|
+
return mbuf
|
|
163
|
+
|
|
164
|
+
# set virtual machine libraries
|
|
165
|
+
def set_vm_libs(self, res):
|
|
166
|
+
deflibs = self.DEFLIBS[res] if res in self.DEFLIBS else self.DEFLIBS['default']
|
|
167
|
+
if not deflibs: return ''
|
|
168
|
+
dlibs = re.split(',', deflibs)
|
|
169
|
+
libbuf = "\n"
|
|
170
|
+
for dlib in dlibs:
|
|
171
|
+
libbuf += dlib + "\n"
|
|
172
|
+
return libbuf
|
|
173
|
+
|
|
174
|
+
# main function to excecute this script
|
|
175
|
+
def main():
|
|
176
|
+
object = BashQsub()
|
|
177
|
+
object.read_parameters()
|
|
178
|
+
object.start_actions()
|
|
179
|
+
object.pgexit(0)
|
|
180
|
+
|
|
181
|
+
# call main() to start program
|
|
182
|
+
if __name__ == "__main__": main()
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
|
|
2
2
|
To submit a job execution as a batch job in bash script on a PBS node via 'qsub'.
|
|
3
3
|
|
|
4
|
-
Usage:
|
|
5
|
-
|
|
4
|
+
Usage: bashqsub [qsub-options] [-cwd WorkDir] [-env EnvironmentPairs] \
|
|
5
|
+
[-mod Modules] [-res Reservation] -cmd Command [cmd-options]
|
|
6
6
|
|
|
7
7
|
- qsub-options, accepts options that can be passed to 'qsub' in a bash script.
|
|
8
8
|
Check qsub man page for help on the PBS batch options. Here is the list of
|
|
9
9
|
qsub options that are included at default:
|
|
10
|
-
-o LOGPATH/
|
|
11
|
-
-e LOGPATH/
|
|
10
|
+
-o LOGPATH/gdexqsub/
|
|
11
|
+
-e LOGPATH/gdexqsub/
|
|
12
12
|
-A P43713000
|
|
13
13
|
-m a
|
|
14
|
-
-q
|
|
14
|
+
-q gdex
|
|
15
15
|
-l walltime=6:00:00,select=1:node=1:mem=1gb
|
|
16
16
|
|
|
17
17
|
- Option -cwd, set the working directory for the Command to be executed. If
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
A bash script example:
|
|
34
34
|
#!/usr/bin/bash
|
|
35
35
|
|
|
36
|
-
#PBS -o /gpfs/u/home/
|
|
37
|
-
#PBS -e /gpfs/u/home/
|
|
36
|
+
#PBS -o /gpfs/u/home/gdexdata/dssdb/log/gdexqsub/
|
|
37
|
+
#PBS -e /gpfs/u/home/gdexdata/dssdb/log/gdexqsub/
|
|
38
38
|
#PBS -A P43713000
|
|
39
|
-
#PBS -q
|
|
39
|
+
#PBS -q gdex@casper-pbs
|
|
40
40
|
#PBS -m n
|
|
41
41
|
#PBS -N dsrqst
|
|
42
42
|
#PBS -l walltime=1:00:00
|
|
@@ -56,9 +56,9 @@ module load conda
|
|
|
56
56
|
module load grib-util
|
|
57
57
|
module load wgrib2
|
|
58
58
|
|
|
59
|
-
conda activate /glade/work/
|
|
59
|
+
conda activate /glade/work/gdexdata/conda-envs/pg-casper
|
|
60
60
|
|
|
61
|
-
echo /
|
|
62
|
-
/
|
|
61
|
+
echo /glade/work/gdexdata/conda-envs/pg-casper/bin/dsrqst d277000 PR -RI 750748 -b -d
|
|
62
|
+
/glade/work/gdexdata/conda-envs/pg-casper/bin/dsrqst d277000 PR -RI 750748 -b -d
|
|
63
63
|
|
|
64
64
|
date
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
##################################################################################
|
|
3
|
+
# Title: gdexls
|
|
4
|
+
# Author: Zaihua Ji, zji@ucar.edu
|
|
5
|
+
# Date: 10/20/2020
|
|
6
|
+
# 2025-03-10 transferred to package rda_python_miscs from
|
|
7
|
+
# https://github.com/NCAR/rda-utility-programs.git
|
|
8
|
+
# 2025-09-21 copied from rdals to gdexls
|
|
9
|
+
# Purpose: list files/directories in a local directory and show additional
|
|
10
|
+
# information recorded in GDEXDB if any
|
|
11
|
+
# Github: https://github.com/NCAR/rda-python-miscs.git
|
|
12
|
+
##################################################################################
|
|
13
|
+
import re
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
import glob
|
|
17
|
+
from os import path as op
|
|
18
|
+
from rda_python_common.pg_split import PgSplit
|
|
19
|
+
|
|
20
|
+
class GdexLs(PgSplit):
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
super().__init__()
|
|
24
|
+
# define some constants for gdexls actions
|
|
25
|
+
self.DIDX = 3 # description column index
|
|
26
|
+
self.CLMT = 500 # reformat list if count reach this limit
|
|
27
|
+
self.WIDTHS = [0, 0, 0] # WIDTHS for formated display
|
|
28
|
+
self.ALIGNS = [0, 1, 1] # alignment, 0 - left; 1 - right
|
|
29
|
+
self.GDEXLS = {
|
|
30
|
+
'd': 0, # 1 to list directory information only
|
|
31
|
+
'f': 0, # 1 to list file information only
|
|
32
|
+
'N': 0, # 1 to list files unformatted
|
|
33
|
+
'r': 0, # 1 if recursive all
|
|
34
|
+
'R': 0, # > 0 to set recursive limit
|
|
35
|
+
'D': None, # specify delimiting symbols, default to ' '
|
|
36
|
+
}
|
|
37
|
+
self.LINFO = {
|
|
38
|
+
'files': [],
|
|
39
|
+
'curdir': None,
|
|
40
|
+
'tpath': None,
|
|
41
|
+
'dhome': None,
|
|
42
|
+
'dsid': None,
|
|
43
|
+
'dcnt': 0,
|
|
44
|
+
'gcnt': 0,
|
|
45
|
+
'fcnt': 0,
|
|
46
|
+
'pcnt': 0,
|
|
47
|
+
'pgrecs': []
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# function to read parameters
|
|
51
|
+
def read_parameters(self):
|
|
52
|
+
self.set_help_path(__file__)
|
|
53
|
+
self.PGLOG['LOGFILE'] = "gdexls.log" # set different log file
|
|
54
|
+
self.LINFO['curdir'] = self.get_real_path(os.getcwd())
|
|
55
|
+
argv = sys.argv[1:]
|
|
56
|
+
self.pglog("gdexls {} ({})".format(' '.join(argv), self.LINFO['curdir']))
|
|
57
|
+
option = defopt = 'l'
|
|
58
|
+
for arg in argv:
|
|
59
|
+
if re.match(r'-(h|-*help|\?)$', arg): self.show_usage("gdexls")
|
|
60
|
+
ms = re.match(r'-(\w)$', arg)
|
|
61
|
+
if ms:
|
|
62
|
+
option = ms.group(1)
|
|
63
|
+
if option not in self.GDEXLS: self.pglog(arg + ": Unknown Option", self.LGEREX)
|
|
64
|
+
if 'dfNr'.find(option) > -1:
|
|
65
|
+
self.GDEXLS[option] = 1
|
|
66
|
+
option = defopt
|
|
67
|
+
continue
|
|
68
|
+
if not option: self.pglog(arg + ": Value provided without option", self.LGEREX)
|
|
69
|
+
if option == 'l':
|
|
70
|
+
self.LINFO['files'].append(self.get_real_path(arg))
|
|
71
|
+
defopt = None
|
|
72
|
+
else:
|
|
73
|
+
if option == 'R':
|
|
74
|
+
self.GDEXLS[option] = int(arg)
|
|
75
|
+
else:
|
|
76
|
+
self.GDEXLS[option] = arg
|
|
77
|
+
option = defopt
|
|
78
|
+
|
|
79
|
+
# functio to start actions
|
|
80
|
+
def start_actions(self):
|
|
81
|
+
self.view_dbinfo()
|
|
82
|
+
if not self.LINFO['files']:
|
|
83
|
+
self.LINFO['files'] = sorted(glob.glob('*')) # view all files in current directory
|
|
84
|
+
if not self.LINFO['files']:
|
|
85
|
+
sys.stderr.write(self.LINFO['curdir'] + ": Empty directory\n")
|
|
86
|
+
self.pgexit(1)
|
|
87
|
+
|
|
88
|
+
if not (self.GDEXLS['d'] or self.GDEXLS['f']):
|
|
89
|
+
self.GDEXLS['d'] = self.GDEXLS['f'] = 1 # list both directories and files as default
|
|
90
|
+
if not self.GDEXLS['D']: self.GDEXLS['D'] = '|' if self.GDEXLS['N'] else " " # default delimiter for no format display
|
|
91
|
+
if not self.GDEXLS['R'] and self.GDEXLS['r']: self.GDEXLS['R'] = 1000
|
|
92
|
+
|
|
93
|
+
self.display_top_list(self.LINFO['files']) # display or cache file/directory list
|
|
94
|
+
if self.LINFO['pcnt'] > 0: self.display_format_list() # if some left over
|
|
95
|
+
if (self.LINFO['dcnt'] + self.LINFO['gcnt'] + self.LINFO['fcnt']) > 1:
|
|
96
|
+
msg = ''
|
|
97
|
+
if self.LINFO['dcnt'] > 0:
|
|
98
|
+
s = 's' if self.LINFO['dcnt'] > 1 else ''
|
|
99
|
+
msg += "{} Dataset{}".format(self.LINFO['dcnt'], s)
|
|
100
|
+
if self.LINFO['gcnt'] > 0:
|
|
101
|
+
s = 's' if self.LINFO['gcnt'] > 1 else ''
|
|
102
|
+
if msg: msg += " & "
|
|
103
|
+
msg += "{} Group{}".format(self.LINFO['gcnt'], s)
|
|
104
|
+
if self.LINFO['fcnt'] > 0:
|
|
105
|
+
s = 's' if self.LINFO['fcnt'] > 1 else ''
|
|
106
|
+
if msg: msg += " & "
|
|
107
|
+
msg += "{} File{}".format(self.LINFO['fcnt'], s)
|
|
108
|
+
print("Total {} displayed".format(msg))
|
|
109
|
+
elif (self.LINFO['dcnt'] + self.LINFO['gcnt'] + self.LINFO['fcnt']) == 0:
|
|
110
|
+
sys.stderr.write((self.LINFO['tpath'] if self.LINFO['tpath'] else self.LINFO['curdir']) + ": No GDEX data information found\n")
|
|
111
|
+
self.pgexit(1)
|
|
112
|
+
|
|
113
|
+
# display the top level list
|
|
114
|
+
def display_top_list(self, files):
|
|
115
|
+
for file in files:
|
|
116
|
+
if not op.exists(file):
|
|
117
|
+
sys.stderr.write(file + ": NOT exists\n")
|
|
118
|
+
continue
|
|
119
|
+
isdir = 1 if op.isdir(file) else 0
|
|
120
|
+
display = 1
|
|
121
|
+
if isdir and re.search(r'/$', file):
|
|
122
|
+
display = 0 # do not display the directory info if it is ended by '/'
|
|
123
|
+
file = re.sub(r'/$', '', file)
|
|
124
|
+
if not re.match(r'^/', file): file = self.join_paths(self.LINFO['curdir'], file)
|
|
125
|
+
self.LINFO['tpath'] = (op.dirname(file) if display else file) + "/"
|
|
126
|
+
if display: self.display_line(file, isdir)
|
|
127
|
+
if isdir and (self.GDEXLS['R'] or not display or not self.LINFO['dsid']):
|
|
128
|
+
fs = sorted(glob.glob(file + "/*"))
|
|
129
|
+
self.display_list(fs, 1)
|
|
130
|
+
if self.LINFO['pcnt'] > self.CLMT: self.display_format_list()
|
|
131
|
+
|
|
132
|
+
# recursively display directory/file info
|
|
133
|
+
def display_list(self, files, level):
|
|
134
|
+
for file in files:
|
|
135
|
+
isdir = 1 if op.isdir(file) else 0
|
|
136
|
+
self.display_line(file, isdir)
|
|
137
|
+
if isdir and level < self.GDEXLS['R']:
|
|
138
|
+
fs = sorted(glob.glob(file + "/*"))
|
|
139
|
+
self.display_list(fs, level+1)
|
|
140
|
+
if self.LINFO['pcnt'] > self.CLMT: self.display_format_list()
|
|
141
|
+
|
|
142
|
+
# find dataset/group info; display or cache file
|
|
143
|
+
def display_line(self, file, isdir):
|
|
144
|
+
getwfile = 1
|
|
145
|
+
if self.LINFO['dsid'] and self.LINFO['dhome']:
|
|
146
|
+
ms = re.match(r'^{}/(.*)$'.format(self.LINFO['dhome']), file)
|
|
147
|
+
if ms:
|
|
148
|
+
wfile = ms.group(1)
|
|
149
|
+
getwfile = 0
|
|
150
|
+
if getwfile:
|
|
151
|
+
self.LINFO['dsid'] = self.find_dataset_id(file)
|
|
152
|
+
if self.LINFO['dsid'] is None: return # skip for missing dsid
|
|
153
|
+
pgrec = self.pgget("dataset", "title, (dwebcnt + nwebcnt) nc, (dweb_size + nweb_size) ns", "dsid = '{}'".format(self.LINFO['dsid']), self.LGEREX)
|
|
154
|
+
if not pgrec: return None
|
|
155
|
+
self.LINFO['dhome'] = "{}/{}".format(self.PGLOG['DSDHOME'], self.LINFO['dsid'])
|
|
156
|
+
if self.LINFO['dhome'] == file:
|
|
157
|
+
file = re.sub(r'^{}'.format(self.LINFO['tpath']), '', file, 1)
|
|
158
|
+
if self.GDEXLS['d']:
|
|
159
|
+
title = pgrec['title'] if pgrec['title'] else ''
|
|
160
|
+
self.display_record(["D" + file, pgrec['ns'], str(pgrec['nc']), title])
|
|
161
|
+
self.LINFO['dcnt'] += 1
|
|
162
|
+
return
|
|
163
|
+
ms = re.match(r'^{}/(.*)$'.format(self.LINFO['dhome']), file)
|
|
164
|
+
if ms:
|
|
165
|
+
wfile = ms.group(1)
|
|
166
|
+
else:
|
|
167
|
+
return
|
|
168
|
+
if isdir:
|
|
169
|
+
if self.GDEXLS['d']: # check and display group info for directory
|
|
170
|
+
pgrec = self.pgget("dsgroup", "title, (dwebcnt + nwebcnt) nc, (dweb_size + nweb_size) ns",
|
|
171
|
+
"dsid = '{}' AND webpath = '{}'".format(self.LINFO['dsid'], wfile), self.LGEREX)
|
|
172
|
+
if pgrec:
|
|
173
|
+
file = re.sub(r'^{}'.format(self.LINFO['tpath']), '', file, 1)
|
|
174
|
+
title = pgrec['title'] if pgrec['title'] else ''
|
|
175
|
+
self.display_record(["G" + file, pgrec['ns'], str(pgrec['nc']), title])
|
|
176
|
+
self.LINFO['gcnt'] += 1
|
|
177
|
+
elif self.GDEXLS['f']: # check and display file info
|
|
178
|
+
pgrec = self.pgget_wfile(self.LINFO['dsid'], "data_size, data_format, note",
|
|
179
|
+
"wfile = '{}'".format(wfile), self.LGEREX)
|
|
180
|
+
if pgrec:
|
|
181
|
+
note = re.sub(r'\n', ' ', pgrec['note']) if pgrec['note'] else ''
|
|
182
|
+
file = re.sub(r'^{}'.format(self.LINFO['tpath']), '', file, 1)
|
|
183
|
+
self.display_record(["F" + file, pgrec['data_size'], pgrec['data_format'], note])
|
|
184
|
+
self.LINFO['fcnt'] += 1
|
|
185
|
+
|
|
186
|
+
# display one file info
|
|
187
|
+
def display_record(self, disp):
|
|
188
|
+
disp[1] = self.get_float_string(disp[1])
|
|
189
|
+
if self.GDEXLS['N']:
|
|
190
|
+
print(self.GDEXLS['D'].join(disp))
|
|
191
|
+
else:
|
|
192
|
+
self.LINFO['pgrecs'].append(disp)
|
|
193
|
+
self.LINFO['pcnt'] += 1
|
|
194
|
+
for i in range(self.DIDX):
|
|
195
|
+
dlen = len(disp[i])
|
|
196
|
+
if dlen > self.WIDTHS[i]: self.WIDTHS[i] = dlen
|
|
197
|
+
|
|
198
|
+
# display cached list with format
|
|
199
|
+
def display_format_list(self):
|
|
200
|
+
for j in range(self.LINFO['pcnt']):
|
|
201
|
+
disp = self.LINFO['pgrecs'][j]
|
|
202
|
+
for i in range(self.DIDX):
|
|
203
|
+
if self.ALIGNS[i] == 1:
|
|
204
|
+
disp[i] = "{:>{}}".format(disp[i], self.WIDTHS[i])
|
|
205
|
+
else:
|
|
206
|
+
disp[i] = "{:{}}".format(disp[i], self.WIDTHS[i])
|
|
207
|
+
print(self.GDEXLS['D'].join(disp))
|
|
208
|
+
self.LINFO['pcnt'] = 0
|
|
209
|
+
|
|
210
|
+
# change size to floating point value with unit
|
|
211
|
+
@staticmethod
|
|
212
|
+
def get_float_string(val):
|
|
213
|
+
units = ['B', 'K', 'M', 'G', 'T', 'P']
|
|
214
|
+
idx = 0
|
|
215
|
+
while val > 1000 and idx < 5:
|
|
216
|
+
val /= 1000
|
|
217
|
+
idx += 1
|
|
218
|
+
if idx > 0:
|
|
219
|
+
return "{:.2f}{}".format(val, units[idx])
|
|
220
|
+
else:
|
|
221
|
+
return "{}{}".format(val, units[idx])
|
|
222
|
+
|
|
223
|
+
# replace /gpfs to the path /glade
|
|
224
|
+
@staticmethod
|
|
225
|
+
def get_real_path(path):
|
|
226
|
+
if re.match(r'^/gpfs/u', path):
|
|
227
|
+
path = re.sub(r'^/gpfs', '/glade', path, 1)
|
|
228
|
+
elif re.match(r'^/gpfs/csfs1/', path):
|
|
229
|
+
path = re.sub(r'^/gpfs/csfs1', '/glade/campaign', path, 1)
|
|
230
|
+
return op.realpath(path)
|
|
231
|
+
|
|
232
|
+
# main function to excecute this script
|
|
233
|
+
def main():
|
|
234
|
+
object = GdexLs()
|
|
235
|
+
object.read_parameters()
|
|
236
|
+
object.start_actions()
|
|
237
|
+
object.pgexit(0)
|
|
238
|
+
|
|
239
|
+
# call main() to start program
|
|
240
|
+
if __name__ == "__main__": main()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#!/glade/work/zji/conda-envs/pg-
|
|
1
|
+
#!/glade/work/zji/conda-envs/pg-gdex/bin/python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
# 2025-09-23, zji@ucar.edu, created for a standalone version of gdexls
|
|
4
4
|
import re
|
|
5
5
|
import sys
|
|
6
|
-
pgpath = '/glade/work/zji/conda-envs/pg-
|
|
6
|
+
pgpath = '/glade/work/zji/conda-envs/pg-gdex/lib/python3.12/site-packages'
|
|
7
7
|
if pgpath not in sys.path: sys.path.insert(0, pgpath)
|
|
8
8
|
|
|
9
9
|
from rda_python_miscs.gdexls import main
|