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.
Files changed (50) hide show
  1. {rda_python_miscs-1.0.6/src/rda_python_miscs.egg-info → rda_python_miscs-2.0.0}/PKG-INFO +1 -1
  2. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/pyproject.toml +5 -11
  3. 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
  4. rda_python_miscs-2.0.0/src/rda_python_miscs/bashqsub.py +182 -0
  5. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/bashqsub.usg +11 -11
  6. rda_python_miscs-2.0.0/src/rda_python_miscs/gdexls.py +240 -0
  7. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/gdexls_standalone.py +2 -2
  8. rda_python_miscs-2.0.0/src/rda_python_miscs/pgwget.py +171 -0
  9. rda_python_miscs-2.0.0/src/rda_python_miscs/rdacp.py +190 -0
  10. rda_python_miscs-2.0.0/src/rda_python_miscs/rdakill.py +231 -0
  11. rda_python_miscs-2.0.0/src/rda_python_miscs/rdamod.py +152 -0
  12. rda_python_miscs-2.0.0/src/rda_python_miscs/rdaown.py +150 -0
  13. rda_python_miscs-2.0.0/src/rda_python_miscs/rdaps.py +173 -0
  14. rda_python_miscs-2.0.0/src/rda_python_miscs/rdasub.py +112 -0
  15. rda_python_miscs-2.0.0/src/rda_python_miscs/rdazip.py +66 -0
  16. 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
  17. rda_python_miscs-2.0.0/src/rda_python_miscs/tcshqsub.py +182 -0
  18. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/tcshqsub.usg +13 -13
  19. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0/src/rda_python_miscs.egg-info}/PKG-INFO +1 -1
  20. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/SOURCES.txt +11 -0
  21. rda_python_miscs-2.0.0/tests/test_miscs.py +16 -0
  22. rda_python_miscs-1.0.6/tests/test_miscs.py +0 -6
  23. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/LICENSE +0 -0
  24. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/MANIFEST.in +0 -0
  25. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/README.md +0 -0
  26. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/setup.cfg +0 -0
  27. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/__init__.py +0 -0
  28. /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
  29. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/gdexls.usg +0 -0
  30. /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
  31. /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
  32. /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
  33. /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
  34. /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
  35. /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
  36. /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
  37. /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
  38. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdacp.usg +0 -0
  39. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdakill.usg +0 -0
  40. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdals.py +0 -0
  41. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdals.usg +0 -0
  42. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdamod.usg +0 -0
  43. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdaown.usg +0 -0
  44. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdaps.usg +0 -0
  45. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdasub.usg +0 -0
  46. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs/rdazip.usg +0 -0
  47. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/dependency_links.txt +0 -0
  48. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/entry_points.txt +0 -0
  49. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/requires.txt +0 -0
  50. {rda_python_miscs-1.0.6 → rda_python_miscs-2.0.0}/src/rda_python_miscs.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_miscs
3
- Version: 1.0.6
3
+ Version: 2.0.0
4
4
  Summary: RDA Python package to hold RDA miscellaneous utility programs
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_miscs"
9
- version = "1.0.6"
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.setuptools]
28
- include-package-data = true
29
-
30
- [tool.setuptools.packages.find]
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-casper",
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' : "rda@casper-pbs",
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 = 'rdaqsub'
53
+ pname = 'gdexqsub'
54
54
  PgLOG.set_help_path(__file__)
55
- rdasub = PgLOG.BCHCMDS['PBS']
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(rdasub): PgLOG.pglog("{}: miss {} command to submit batch job".format(rdasub, PgLOG.PGLOG['PBSNAME']), PgLOG.LGWNEX)
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, rdasub), PgLOG.LGEREX)
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'].find('$'): coptions['cwd'] = PgLOG.replace_environments(coptions['cwd'], '', PgLOG.LGWNEX)
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, rdasub)
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(rdasub, PgLOG.LOGWRN, 6, sbuf)
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, rdasub):
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: rdaqsub [qsub-options] [-cwd WorkDir] [-env EnvironmentPairs] \
5
- [-mod Modules] [-res Reservation] -cmd Command [cmd-options]
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/rdaqsub/
11
- -e LOGPATH/rdaqsub/
10
+ -o LOGPATH/gdexqsub/
11
+ -e LOGPATH/gdexqsub/
12
12
  -A P43713000
13
13
  -m a
14
- -q regular
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/rdadata/dssdb/log/rdaqsub/
37
- #PBS -e /gpfs/u/home/rdadata/dssdb/log/rdaqsub/
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 rda@casper-pbs
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/rdadata/conda-envs/pg-casper
59
+ conda activate /glade/work/gdexdata/conda-envs/pg-casper
60
60
 
61
- echo /gpfs/u/home/rdadata/bin/dsrqst d277000 PR -RI 750748 -b -d
62
- /gpfs/u/home/rdadata/bin/dsrqst d277000 PR -RI 750748 -b -d
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-rda/bin/python
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-rda/lib/python3.10/site-packages'
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