rda-python-miscs 2.0.15__tar.gz → 3.0.1__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 (67) hide show
  1. rda_python_miscs-3.0.1/PKG-INFO +161 -0
  2. rda_python_miscs-3.0.1/README.md +144 -0
  3. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/pyproject.toml +11 -5
  4. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/bashqsub.py +60 -5
  5. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/bashqsub.usg +7 -7
  6. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/gdexls.py +99 -8
  7. rda_python_miscs-3.0.1/src/rda_python_miscs/gdexls.usg +74 -0
  8. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/pg_rst.py +5 -0
  9. rda_python_miscs-3.0.1/src/rda_python_miscs/pg_rst.usg +60 -0
  10. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/pg_wget.py +21 -8
  11. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/pgwget.py +41 -24
  12. rda_python_miscs-3.0.1/src/rda_python_miscs/pgwget.usg +75 -0
  13. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdacp.py +61 -6
  14. rda_python_miscs-3.0.1/src/rda_python_miscs/rdacp.usg +77 -0
  15. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdakill.py +93 -12
  16. rda_python_miscs-3.0.1/src/rda_python_miscs/rdakill.usg +66 -0
  17. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdamod.py +63 -10
  18. rda_python_miscs-3.0.1/src/rda_python_miscs/rdamod.usg +71 -0
  19. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdaown.py +55 -6
  20. rda_python_miscs-3.0.1/src/rda_python_miscs/rdaown.usg +60 -0
  21. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdaps.py +37 -5
  22. rda_python_miscs-3.0.1/src/rda_python_miscs/rdaps.usg +55 -0
  23. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdasub.py +45 -8
  24. rda_python_miscs-3.0.1/src/rda_python_miscs/rdasub.usg +49 -0
  25. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdazip.py +20 -4
  26. rda_python_miscs-3.0.1/src/rda_python_miscs/rdazip.usg +56 -0
  27. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/tcshqsub.py +58 -3
  28. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/tcshqsub.usg +9 -9
  29. rda_python_miscs-3.0.1/src/rda_python_miscs.egg-info/PKG-INFO +161 -0
  30. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs.egg-info/SOURCES.txt +2 -0
  31. rda_python_miscs-3.0.1/src/rda_python_miscs.egg-info/entry_points.txt +20 -0
  32. rda_python_miscs-2.0.15/PKG-INFO +0 -18
  33. rda_python_miscs-2.0.15/README.md +0 -1
  34. rda_python_miscs-2.0.15/src/rda_python_miscs/gdexls.usg +0 -60
  35. rda_python_miscs-2.0.15/src/rda_python_miscs/rdacp.usg +0 -62
  36. rda_python_miscs-2.0.15/src/rda_python_miscs/rdakill.usg +0 -36
  37. rda_python_miscs-2.0.15/src/rda_python_miscs/rdamod.usg +0 -51
  38. rda_python_miscs-2.0.15/src/rda_python_miscs/rdaown.usg +0 -46
  39. rda_python_miscs-2.0.15/src/rda_python_miscs/rdaps.usg +0 -29
  40. rda_python_miscs-2.0.15/src/rda_python_miscs/rdasub.usg +0 -12
  41. rda_python_miscs-2.0.15/src/rda_python_miscs/rdazip.usg +0 -20
  42. rda_python_miscs-2.0.15/src/rda_python_miscs.egg-info/PKG-INFO +0 -18
  43. rda_python_miscs-2.0.15/src/rda_python_miscs.egg-info/entry_points.txt +0 -14
  44. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/LICENSE +0 -0
  45. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/MANIFEST.in +0 -0
  46. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/setup.cfg +0 -0
  47. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/__init__.py +0 -0
  48. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/bash_qsub.py +0 -0
  49. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/gdex_ls.py +0 -0
  50. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/gdexls_standalone.py +0 -0
  51. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/pg_docs.py +0 -0
  52. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_cp.py +0 -0
  53. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_kill.py +0 -0
  54. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_mod.py +0 -0
  55. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_own.py +0 -0
  56. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_ps.py +0 -0
  57. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_sub.py +0 -0
  58. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rda_zip.py +0 -0
  59. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdals.py +0 -0
  60. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rdals.usg +0 -0
  61. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rst_templates/index.rst.temp +0 -0
  62. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/rst_templates/section.rst.temp +0 -0
  63. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs/tcsh_qsub.py +0 -0
  64. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs.egg-info/dependency_links.txt +0 -0
  65. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs.egg-info/requires.txt +0 -0
  66. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/src/rda_python_miscs.egg-info/top_level.txt +0 -0
  67. {rda_python_miscs-2.0.15 → rda_python_miscs-3.0.1}/tests/test_miscs.py +0 -0
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: rda_python_miscs
3
+ Version: 3.0.1
4
+ Summary: RDA Python package to hold RDA miscellaneous utility programs
5
+ Author-email: Zaihua Ji <zji@ucar.edu>
6
+ Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: rda_python_common
15
+ Requires-Dist: rda_python_setuid
16
+ Dynamic: license-file
17
+
18
+ # rda_python_miscs
19
+
20
+ RDA Python package to hold miscellaneous utility programs for the
21
+ [NSF NCAR Geoscience Data Exchange (GDEX)](https://gdex.ucar.edu).
22
+
23
+ ## Programs
24
+
25
+ The package provides two categories of programs:
26
+
27
+ **Run as current user (no setuid required):**
28
+
29
+ | Command | Alias | Description |
30
+ |---------|-------|-------------|
31
+ | `bashqsub` | | Submit a job as a bash batch job on a PBS node via qsub |
32
+ | `tcshqsub` | | Submit a job as a tcsh batch job on a PBS node via qsub |
33
+ | `rdasub` | `gdexsub` | Submit a command as a nohup background process on the local machine |
34
+ | `pgwget` | | Download remote files by root name pattern, combining downloaded parts into a single file |
35
+ | `gdexls` | | List local files and directories with matching metadata from the GDEX database |
36
+ | `rdaps` | `gdexps` | Show process status for local or PBS batch processes, with filtering by PID, owner, or name |
37
+ | `rdazip` | `gdexzip` | Compress or uncompress files using a supported format |
38
+ | `rdaown` | `gdexown` | Change ownership of files and directories to rdadata (must be run as root) |
39
+ | `pgrst` | | Convert .usg files to RST and push to gdex-docs-* repos on GitHub for readthedocs.io |
40
+
41
+ **Run as gdexdata via setuid (requires setup below):**
42
+
43
+ | Command | Alias | Connector script | Description |
44
+ |---------|-------|-----------------|-------------|
45
+ | `rdacp` | `gdexcp` | `setuid_rdacp` / `setuid_gdexcp` | Copy files and directories across local, remote, Object Store, or Globus endpoints |
46
+ | `rdakill` | `gdexkill` | `setuid_rdakill` / `setuid_gdexkill` | Kill local processes and their children, or cancel PBS batch jobs |
47
+ | `rdamod` | `gdexmod` | `setuid_rdamod` / `setuid_gdexmod` | Change permission modes for files and directories owned by rdadata |
48
+
49
+ ## Environment setup
50
+
51
+ Create a Python environment first; package installs in the next section run
52
+ inside whichever environment you activate here.
53
+
54
+ ### Option A — Python venv (DECS machines)
55
+
56
+ ```bash
57
+ python3 -m venv $ENVHOME # e.g. /glade/u/home/gdexdata/gdexmsenv
58
+ source $ENVHOME/bin/activate
59
+ ```
60
+
61
+ ### Option B — Conda (DAV/Casper)
62
+
63
+ ```bash
64
+ conda create --prefix $ENVHOME python=3.12 # e.g. /glade/work/gdexdata/conda-envs/pg-gdex
65
+ conda activate $ENVHOME
66
+ ```
67
+
68
+ ## Installing rda-python-miscs
69
+
70
+ Pick whichever install mode fits your workflow. All four pull in the
71
+ transitive dependencies (`rda_python_common`, `rda_python_setuid`)
72
+ automatically.
73
+
74
+ For local development, clone this repo alongside your project and install it
75
+ in editable mode so that changes are picked up without re-installing:
76
+
77
+ ```bash
78
+ git clone https://github.com/NCAR/rda-python-miscs.git
79
+ cd rda-python-miscs
80
+ pip install -e .
81
+ ```
82
+
83
+ To test a specific branch (e.g. an in-progress feature or fix branch), pass
84
+ `-b/--branch` to `git clone`:
85
+
86
+ ```bash
87
+ git clone -b <branch-name> https://github.com/NCAR/rda-python-miscs.git
88
+ cd rda-python-miscs
89
+ pip install -e .
90
+ ```
91
+
92
+ For a regular (non-editable) install from a checkout:
93
+
94
+ ```bash
95
+ pip install /path/to/rda-python-miscs
96
+ ```
97
+
98
+ For a production install on a system that uses the published distribution:
99
+
100
+ ```bash
101
+ pip install rda_python_miscs
102
+ ```
103
+
104
+ ## Setuid Setup
105
+
106
+ The setuid programs (`rdacp`, `rdakill`, `rdamod` and their `gdex*` aliases)
107
+ execute as the common user `PGLOG['COMMONUSER']` (default `gdexdata`) via
108
+ the `rda_python_setuid` mechanism, which is pulled in automatically as a
109
+ dependency. After `pip install` above, choose one of the wiring options
110
+ below.
111
+
112
+ > **Note:** If `rda_python_setuid` is already installed and fully set up in
113
+ > your environment, you can skip the compile step (`-c/--compile`) and the
114
+ > optional `pgstart` step (`-p/--pgstart`). The `-l/--link` step is still
115
+ > required to wire up this package's own setuid programs.
116
+
117
+ ### Full setuid install (requires sudo access to COMMONUSER)
118
+
119
+ Run these steps once per environment:
120
+
121
+ ```bash
122
+ # 1. Compile the pywrapper C binary (once per environment):
123
+ pywrapper-install -c|--compile -n|--username gdexdata
124
+
125
+ # 2. Wire up all setuid programs in one pass:
126
+ pywrapper-install -l|--link all
127
+
128
+ # 3. Optionally, install a pgstart_<loginname> binary so <loginname> (any
129
+ # user in the same group as PGLOG['COMMONUSER']) can run commands as
130
+ # themselves. Run either by PGLOG['ADMINUSER'] (default zji, if it has
131
+ # 'sudo -u <loginname>'), or by <loginname> directly:
132
+ pywrapper-install -p|--pgstart -n|--username <loginname>
133
+ ```
134
+
135
+ `pywrapper-install` with no arguments displays the full user guide.
136
+
137
+ ### Simple install (no sudo required, runs as current user)
138
+
139
+ Users who do not need the setuid mechanism can create direct symlinks instead:
140
+
141
+ ```bash
142
+ pywrapper-install -l|--link all -s|--simple
143
+ ```
144
+
145
+ This creates `bin/<name> -> bin/setuid_<name>` for every setuid program and
146
+ they run as the current user with no privilege change.
147
+
148
+ ### Update an existing installation (no sudo required)
149
+
150
+ When the package is upgraded and a new `pywrapper.c` is bundled, recompile and
151
+ reinstall all setuid binaries using the existing `pgstart_*` binaries:
152
+
153
+ ```bash
154
+ pywrapper-install -u|--update
155
+ ```
156
+
157
+ ### Setup guide
158
+
159
+ The shared setuid setup guide is shown automatically if any `setuid_*`
160
+ connector script is invoked directly before the setuid wrapper has been
161
+ configured.
@@ -0,0 +1,144 @@
1
+ # rda_python_miscs
2
+
3
+ RDA Python package to hold miscellaneous utility programs for the
4
+ [NSF NCAR Geoscience Data Exchange (GDEX)](https://gdex.ucar.edu).
5
+
6
+ ## Programs
7
+
8
+ The package provides two categories of programs:
9
+
10
+ **Run as current user (no setuid required):**
11
+
12
+ | Command | Alias | Description |
13
+ |---------|-------|-------------|
14
+ | `bashqsub` | | Submit a job as a bash batch job on a PBS node via qsub |
15
+ | `tcshqsub` | | Submit a job as a tcsh batch job on a PBS node via qsub |
16
+ | `rdasub` | `gdexsub` | Submit a command as a nohup background process on the local machine |
17
+ | `pgwget` | | Download remote files by root name pattern, combining downloaded parts into a single file |
18
+ | `gdexls` | | List local files and directories with matching metadata from the GDEX database |
19
+ | `rdaps` | `gdexps` | Show process status for local or PBS batch processes, with filtering by PID, owner, or name |
20
+ | `rdazip` | `gdexzip` | Compress or uncompress files using a supported format |
21
+ | `rdaown` | `gdexown` | Change ownership of files and directories to rdadata (must be run as root) |
22
+ | `pgrst` | | Convert .usg files to RST and push to gdex-docs-* repos on GitHub for readthedocs.io |
23
+
24
+ **Run as gdexdata via setuid (requires setup below):**
25
+
26
+ | Command | Alias | Connector script | Description |
27
+ |---------|-------|-----------------|-------------|
28
+ | `rdacp` | `gdexcp` | `setuid_rdacp` / `setuid_gdexcp` | Copy files and directories across local, remote, Object Store, or Globus endpoints |
29
+ | `rdakill` | `gdexkill` | `setuid_rdakill` / `setuid_gdexkill` | Kill local processes and their children, or cancel PBS batch jobs |
30
+ | `rdamod` | `gdexmod` | `setuid_rdamod` / `setuid_gdexmod` | Change permission modes for files and directories owned by rdadata |
31
+
32
+ ## Environment setup
33
+
34
+ Create a Python environment first; package installs in the next section run
35
+ inside whichever environment you activate here.
36
+
37
+ ### Option A — Python venv (DECS machines)
38
+
39
+ ```bash
40
+ python3 -m venv $ENVHOME # e.g. /glade/u/home/gdexdata/gdexmsenv
41
+ source $ENVHOME/bin/activate
42
+ ```
43
+
44
+ ### Option B — Conda (DAV/Casper)
45
+
46
+ ```bash
47
+ conda create --prefix $ENVHOME python=3.12 # e.g. /glade/work/gdexdata/conda-envs/pg-gdex
48
+ conda activate $ENVHOME
49
+ ```
50
+
51
+ ## Installing rda-python-miscs
52
+
53
+ Pick whichever install mode fits your workflow. All four pull in the
54
+ transitive dependencies (`rda_python_common`, `rda_python_setuid`)
55
+ automatically.
56
+
57
+ For local development, clone this repo alongside your project and install it
58
+ in editable mode so that changes are picked up without re-installing:
59
+
60
+ ```bash
61
+ git clone https://github.com/NCAR/rda-python-miscs.git
62
+ cd rda-python-miscs
63
+ pip install -e .
64
+ ```
65
+
66
+ To test a specific branch (e.g. an in-progress feature or fix branch), pass
67
+ `-b/--branch` to `git clone`:
68
+
69
+ ```bash
70
+ git clone -b <branch-name> https://github.com/NCAR/rda-python-miscs.git
71
+ cd rda-python-miscs
72
+ pip install -e .
73
+ ```
74
+
75
+ For a regular (non-editable) install from a checkout:
76
+
77
+ ```bash
78
+ pip install /path/to/rda-python-miscs
79
+ ```
80
+
81
+ For a production install on a system that uses the published distribution:
82
+
83
+ ```bash
84
+ pip install rda_python_miscs
85
+ ```
86
+
87
+ ## Setuid Setup
88
+
89
+ The setuid programs (`rdacp`, `rdakill`, `rdamod` and their `gdex*` aliases)
90
+ execute as the common user `PGLOG['COMMONUSER']` (default `gdexdata`) via
91
+ the `rda_python_setuid` mechanism, which is pulled in automatically as a
92
+ dependency. After `pip install` above, choose one of the wiring options
93
+ below.
94
+
95
+ > **Note:** If `rda_python_setuid` is already installed and fully set up in
96
+ > your environment, you can skip the compile step (`-c/--compile`) and the
97
+ > optional `pgstart` step (`-p/--pgstart`). The `-l/--link` step is still
98
+ > required to wire up this package's own setuid programs.
99
+
100
+ ### Full setuid install (requires sudo access to COMMONUSER)
101
+
102
+ Run these steps once per environment:
103
+
104
+ ```bash
105
+ # 1. Compile the pywrapper C binary (once per environment):
106
+ pywrapper-install -c|--compile -n|--username gdexdata
107
+
108
+ # 2. Wire up all setuid programs in one pass:
109
+ pywrapper-install -l|--link all
110
+
111
+ # 3. Optionally, install a pgstart_<loginname> binary so <loginname> (any
112
+ # user in the same group as PGLOG['COMMONUSER']) can run commands as
113
+ # themselves. Run either by PGLOG['ADMINUSER'] (default zji, if it has
114
+ # 'sudo -u <loginname>'), or by <loginname> directly:
115
+ pywrapper-install -p|--pgstart -n|--username <loginname>
116
+ ```
117
+
118
+ `pywrapper-install` with no arguments displays the full user guide.
119
+
120
+ ### Simple install (no sudo required, runs as current user)
121
+
122
+ Users who do not need the setuid mechanism can create direct symlinks instead:
123
+
124
+ ```bash
125
+ pywrapper-install -l|--link all -s|--simple
126
+ ```
127
+
128
+ This creates `bin/<name> -> bin/setuid_<name>` for every setuid program and
129
+ they run as the current user with no privilege change.
130
+
131
+ ### Update an existing installation (no sudo required)
132
+
133
+ When the package is upgraded and a new `pywrapper.c` is bundled, recompile and
134
+ reinstall all setuid binaries using the existing `pgstart_*` binaries:
135
+
136
+ ```bash
137
+ pywrapper-install -u|--update
138
+ ```
139
+
140
+ ### Setup guide
141
+
142
+ The shared setuid setup guide is shown automatically if any `setuid_*`
143
+ connector script is invoked directly before the setuid wrapper has been
144
+ configured.
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "rda_python_miscs"
9
- version = "2.0.15"
9
+ version = "3.0.1"
10
10
  authors = [
11
11
  { name="Zaihua Ji", email="zji@ucar.edu" },
12
12
  ]
@@ -36,13 +36,19 @@ pythonpath = [
36
36
  "bashqsub" = "rda_python_miscs.bashqsub:main"
37
37
  "tcshqsub" = "rda_python_miscs.tcshqsub:main"
38
38
  "rdasub" = "rda_python_miscs.rdasub:main"
39
+ "gdexsub" = "rda_python_miscs.rdasub:main"
39
40
  "pgwget" = "rda_python_miscs.pgwget:main"
40
- "rdals" = "rda_python_miscs.rdals:main"
41
41
  "gdexls" = "rda_python_miscs.gdexls:main"
42
42
  "rdaps" = "rda_python_miscs.rdaps:main"
43
+ "gdexps" = "rda_python_miscs.rdaps:main"
43
44
  "rdazip" = "rda_python_miscs.rdazip:main"
45
+ "gdexzip" = "rda_python_miscs.rdazip:main"
44
46
  "rdaown" = "rda_python_miscs.rdaown:main"
45
- "rdacp.py" = "rda_python_miscs.rdacp:main"
46
- "rdakill.py" = "rda_python_miscs.rdakill:main"
47
- "rdamod.py" = "rda_python_miscs.rdamod:main"
47
+ "gdexown" = "rda_python_miscs.rdaown:main"
48
+ "setuid_rdacp" = "rda_python_miscs.rdacp:main"
49
+ "setuid_gdexcp" = "rda_python_miscs.rdacp:main"
50
+ "setuid_rdakill" = "rda_python_miscs.rdakill:main"
51
+ "setuid_gdexkill" = "rda_python_miscs.rdakill:main"
52
+ "setuid_rdamod" = "rda_python_miscs.rdamod:main"
53
+ "setuid_gdexmod" = "rda_python_miscs.rdamod:main"
48
54
  "pgrst" = "rda_python_miscs.pg_rst:main"
@@ -7,7 +7,7 @@
7
7
  # https://github.com/NCAR/rda-utility-programs.git
8
8
  # 2025-12-29 convert to class BashQsub
9
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
10
+ # Github: https://github.com/NCAR/rda-python-miscs.git
11
11
  ##################################################################################
12
12
  import os
13
13
  import sys
@@ -16,8 +16,14 @@ from os import path as op
16
16
  from rda_python_common.pg_log import PgLOG
17
17
 
18
18
  class BashQsub(PgLOG):
19
+ """Submit a PBS batch job via a dynamically generated bash script using qsub.
20
+
21
+ Builds a bash script with PBS directives, module loads, and conda environment
22
+ activation, then submits it through the PBS qsub command.
23
+ """
19
24
 
20
25
  def __init__(self):
26
+ """Initialize BashQsub with default PBS resource settings and options."""
21
27
  super().__init__()
22
28
  self.DEFMODS = {
23
29
  'default': "ncarenv,netcdf,ncl,nco,cdo,conda,grib-util,wgrib2"
@@ -42,8 +48,15 @@ class BashQsub(PgLOG):
42
48
  self.gdexsub = self.BCHCMDS['PBS']
43
49
  self.args = None
44
50
 
45
- # function to readparameters
51
+ # function to read parameters
46
52
  def read_parameters(self):
53
+ """Parse command-line arguments and populate PBS options and customized options.
54
+
55
+ Handles single-dash qsub options (e.g. -q, -A, -l) and long custom options
56
+ (-cmd, -cwd, -env, -mod, -res). Validates that the qsub command is available
57
+ and that a -cmd value is provided. Sets default log paths and job name if not
58
+ specified, and changes the working directory if -cwd is given.
59
+ """
47
60
  aname = 'bashqsub'
48
61
  pname = 'gdexqsub'
49
62
  self.set_help_path(__file__)
@@ -88,11 +101,12 @@ class BashQsub(PgLOG):
88
101
  if not self.SOPTIONS['e']: self.SOPTIONS['e'] = "{}/{}/".format(self.PGLOG['LOGPATH'], pname)
89
102
  if 'N' not in self.SOPTIONS: self.SOPTIONS['N'] = op.basename(self.coptions['cmd'])
90
103
  if self.coptions['cwd']:
91
- if 's' in self.coptions['cwd']: self.coptions['cwd'] = self.replace_environments(self.coptions['cwd'], '', self.LGWNEX)
104
+ if '$' in self.coptions['cwd']: self.coptions['cwd'] = self.replace_environments(self.coptions['cwd'], '', self.LGWNEX)
92
105
  os.chdir(self.coptions['cwd'])
93
106
 
94
107
  # function to start actions
95
108
  def start_actions(self):
109
+ """Resolve the command path, build the bash script, and submit it via qsub."""
96
110
  cmd = self.valid_command(self.coptions['cmd'])
97
111
  if not cmd and not re.match(r'^/', self.coptions['cmd']): cmd = self.valid_command('./' + self.coptions['cmd'])
98
112
  if not cmd: self.pglog(self.coptions['cmd'] + ": Cannot find given command to run", self.LGWNEX)
@@ -105,6 +119,17 @@ class BashQsub(PgLOG):
105
119
 
106
120
  # build bash script to submit a PBS batch job
107
121
  def build_bash_script(self, cmd):
122
+ """Build and return a bash script string with PBS directives for the given command.
123
+
124
+ Sets HOME, sources system and conda profile scripts and the user's .bashrc,
125
+ loads modules, activates the conda environment, then runs the command.
126
+
127
+ Args:
128
+ cmd (str): The fully-resolved command (with arguments) to execute in the job.
129
+
130
+ Returns:
131
+ str: The complete bash batch script content.
132
+ """
108
133
  buf = "#!/usr/bin/bash\n\n" # qsub starting bash script
109
134
  if 'l' in self.SOPTIONS: self.add_resources()
110
135
  # add options to bash script for qsub
@@ -128,8 +153,13 @@ class BashQsub(PgLOG):
128
153
  buf += "\necho {}\n{}\n\ndate\n".format(cmd, cmd)
129
154
  return buf
130
155
 
131
- # check and add resource options
156
+ # check and add resource options
132
157
  def add_resources(self):
158
+ """Parse -l option value into the RESOURCES dict and remove the raw -l entry.
159
+
160
+ Expects comma-separated name=value pairs (e.g. 'walltime=2:00:00,select=1:ncpus=4').
161
+ Logs an error if a token does not contain '='.
162
+ """
133
163
  for res in re.split(',', self.SOPTIONS['l']):
134
164
  ms = re.match(r'^([^=]+)=(.+)$', res)
135
165
  if ms:
@@ -140,6 +170,20 @@ class BashQsub(PgLOG):
140
170
 
141
171
  # add module loads for modules provided
142
172
  def add_modules(self, res, mods):
173
+ """Build and return module load/unload commands for the bash script.
174
+
175
+ Loads the default module set for the given reservation (or the 'default' set).
176
+ Additional modules in ``mods`` are appended; path-style entries (starting with
177
+ '/') use 'module use' instead of 'module load'. Modules already in the default
178
+ set are skipped. SWAPMODS entries trigger an unload before the new load.
179
+
180
+ Args:
181
+ res (str): Reservation name used to look up DEFMODS; falls back to 'default'.
182
+ mods (str): Comma-separated list of extra modules (or None).
183
+
184
+ Returns:
185
+ str: Shell commands to load/unload modules.
186
+ """
143
187
  mbuf = "\n"
144
188
  defmods = self.DEFMODS[res] if res in self.DEFMODS else self.DEFMODS['default']
145
189
  dmods = re.split(',', defmods)
@@ -163,6 +207,16 @@ class BashQsub(PgLOG):
163
207
 
164
208
  # set virtual machine libraries
165
209
  def set_vm_libs(self, res):
210
+ """Build and return conda/VM library activation commands for the bash script.
211
+
212
+ Looks up DEFLIBS for the given reservation (falls back to 'default').
213
+
214
+ Args:
215
+ res (str): Reservation name used to look up DEFLIBS; falls back to 'default'.
216
+
217
+ Returns:
218
+ str: Shell commands to activate virtual environment libraries, or '' if none.
219
+ """
166
220
  deflibs = self.DEFLIBS[res] if res in self.DEFLIBS else self.DEFLIBS['default']
167
221
  if not deflibs: return ''
168
222
  dlibs = re.split(',', deflibs)
@@ -171,8 +225,9 @@ class BashQsub(PgLOG):
171
225
  libbuf += dlib + "\n"
172
226
  return libbuf
173
227
 
174
- # main function to excecute this script
228
+ # main function to execute this script
175
229
  def main():
230
+ """Entry point: instantiate BashQsub, parse arguments, run, and exit."""
176
231
  object = BashQsub()
177
232
  object.read_parameters()
178
233
  object.start_actions()
@@ -10,9 +10,9 @@
10
10
  -o LOGPATH/gdexqsub/
11
11
  -e LOGPATH/gdexqsub/
12
12
  -A P43713000
13
- -m a
14
- -q gdex
15
- -l walltime=6:00:00,select=1:node=1:mem=1gb
13
+ -m n
14
+ -q gdex@casper-pbs
15
+ -l walltime=6:00:00,select=1:ncpus=1:mem=1gb
16
16
 
17
17
  - Option -cwd, set the working directory for the Command to be executed. If
18
18
  it is not specified, it defaults to the current directory where qsub
@@ -33,18 +33,18 @@
33
33
  A bash script example:
34
34
  #!/usr/bin/bash
35
35
 
36
- #PBS -o /gpfs/u/home/gdexdata/dssdb/log/gdexqsub/
37
- #PBS -e /gpfs/u/home/gdexdata/dssdb/log/gdexqsub/
36
+ #PBS -o /glade/u/home/gdexdata/dssdb/log/gdexqsub/
37
+ #PBS -e /glade/u/home/gdexdata/dssdb/log/gdexqsub/
38
38
  #PBS -A P43713000
39
39
  #PBS -q gdex@casper-pbs
40
40
  #PBS -m n
41
41
  #PBS -N dsrqst
42
42
  #PBS -l walltime=1:00:00
43
43
  #PBS -l select=1:ncpus=1:mem=1gb
44
- export HOME=/gpfs/u/home/zji
44
+ export HOME=/glade/u/home/zji
45
45
  source /etc/profile.d/z00_modules.sh
46
46
  source /glade/u/apps/opt/conda/etc/profile.d/conda.sh
47
- source /gpfs/u/home/zji/.bashrc
47
+ source /glade/u/home/zji/.bashrc
48
48
  pwd; hostname; date
49
49
 
50
50
  module load ncarenv