rda-python-common 2.1.7__py3-none-any.whl → 2.1.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rda_python_common/__init__.py +38 -0
- rda_python_common/pg_dbi.py +7 -7
- rda_python_common/pg_file.py +2 -2
- rda_python_common/pg_lock.py +1 -1
- rda_python_common/pg_log.py +6 -6
- rda_python_common/pg_opt.py +1 -1
- rda_python_common/pg_sig.py +1 -1
- rda_python_common/pg_split.py +3 -2
- rda_python_common/pg_util.py +24 -23
- rda_python_common/pgpassword.py +55 -14
- rda_python_common-2.1.8.dist-info/METADATA +305 -0
- rda_python_common-2.1.8.dist-info/RECORD +27 -0
- rda_python_common-2.1.7.dist-info/METADATA +0 -21
- rda_python_common-2.1.7.dist-info/RECORD +0 -27
- {rda_python_common-2.1.7.dist-info → rda_python_common-2.1.8.dist-info}/WHEEL +0 -0
- {rda_python_common-2.1.7.dist-info → rda_python_common-2.1.8.dist-info}/entry_points.txt +0 -0
- {rda_python_common-2.1.7.dist-info → rda_python_common-2.1.8.dist-info}/licenses/LICENSE +0 -0
- {rda_python_common-2.1.7.dist-info → rda_python_common-2.1.8.dist-info}/top_level.txt +0 -0
rda_python_common/__init__.py
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""rda_python_common: shared utility package for RDA Python tools.
|
|
2
|
+
|
|
3
|
+
This package exposes two parallel APIs:
|
|
4
|
+
|
|
5
|
+
1. Legacy module-based API (back-compat). Import the capitalized submodules
|
|
6
|
+
and call their module-level functions, e.g.::
|
|
7
|
+
|
|
8
|
+
from rda_python_common import PgLOG
|
|
9
|
+
PgLOG.pglog("message", PgLOG.LOGWRN)
|
|
10
|
+
|
|
11
|
+
2. Class-based API (preferred for new code). Import the class from the
|
|
12
|
+
lower-case module and either instantiate or subclass it, e.g.::
|
|
13
|
+
|
|
14
|
+
from rda_python_common.pg_log import PgLOG
|
|
15
|
+
log = PgLOG()
|
|
16
|
+
log.pglog("message", log.LOGWRN)
|
|
17
|
+
|
|
18
|
+
The legacy submodules are eagerly imported below so that
|
|
19
|
+
``from rda_python_common import PgLOG`` continues to return the module
|
|
20
|
+
object that existing callers expect.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from . import PgLOG, PgUtil, PgDBI, PgFile, PgLock, PgCMD, PgSIG, PgOPT, PgSplit
|
|
24
|
+
|
|
25
|
+
__version__ = "2.1.8"
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"PgLOG",
|
|
29
|
+
"PgUtil",
|
|
30
|
+
"PgDBI",
|
|
31
|
+
"PgFile",
|
|
32
|
+
"PgLock",
|
|
33
|
+
"PgCMD",
|
|
34
|
+
"PgSIG",
|
|
35
|
+
"PgOPT",
|
|
36
|
+
"PgSplit",
|
|
37
|
+
"__version__",
|
|
38
|
+
]
|
rda_python_common/pg_dbi.py
CHANGED
|
@@ -62,12 +62,12 @@ class PgDBI(PgLOG):
|
|
|
62
62
|
super().__init__() # initialize parent class
|
|
63
63
|
|
|
64
64
|
# PostgreSQL specified query timestamp format
|
|
65
|
-
self.fmtyr = lambda fn
|
|
66
|
-
self.fmtqt = lambda fn
|
|
67
|
-
self.fmtmn = lambda fn
|
|
68
|
-
self.fmtdt = lambda fn
|
|
69
|
-
self.fmtym = lambda fn
|
|
70
|
-
self.fmthr = lambda fn
|
|
65
|
+
self.fmtyr = lambda fn: "extract(year from {})::int".format(fn)
|
|
66
|
+
self.fmtqt = lambda fn: "extract(quarter from {})::int".format(fn)
|
|
67
|
+
self.fmtmn = lambda fn: "extract(month from {})::int".format(fn)
|
|
68
|
+
self.fmtdt = lambda fn: "date({})".format(fn)
|
|
69
|
+
self.fmtym = lambda fn: "to_char({}, 'yyyy-mm')".format(fn)
|
|
70
|
+
self.fmthr = lambda fn: "extract(hour from {})::int".format(fn)
|
|
71
71
|
|
|
72
72
|
self.pgdb = None # reference to a connected database object
|
|
73
73
|
self.curtran = 0 # 0 - no transaction, 1 - in transaction
|
|
@@ -577,7 +577,7 @@ class PgDBI(PgLOG):
|
|
|
577
577
|
self.qelog(dberror, 0, "Retry Connecting", ary, pgcnt, self.LOGWRN)
|
|
578
578
|
self.pgconnect(1, pgcnt + 1)
|
|
579
579
|
return (self.FAILURE if not self.pgdb else self.SUCCESS)
|
|
580
|
-
elif
|
|
580
|
+
elif pgcode.startswith('55'): # try to lock again
|
|
581
581
|
self.qelog(dberror, 10, "Retry Locking", ary, pgcnt, self.LOGWRN)
|
|
582
582
|
return self.SUCCESS
|
|
583
583
|
elif pgcode == '25P02': # try to add table
|
rda_python_common/pg_file.py
CHANGED
|
@@ -2595,7 +2595,7 @@ class PgFile(PgUtil, PgSIG):
|
|
|
2595
2595
|
if opt&17:
|
|
2596
2596
|
dy = int(items[6])
|
|
2597
2597
|
mn = self.get_month(items[5])
|
|
2598
|
-
if
|
|
2598
|
+
if items[7].isdigit():
|
|
2599
2599
|
yr = int(items[7])
|
|
2600
2600
|
mtime = "00:00:00"
|
|
2601
2601
|
else:
|
|
@@ -2972,7 +2972,7 @@ class PgFile(PgUtil, PgSIG):
|
|
|
2972
2972
|
if dir is None:
|
|
2973
2973
|
if isinstance(val, int):
|
|
2974
2974
|
self.DIRLVLS = val
|
|
2975
|
-
elif
|
|
2975
|
+
elif val.isdigit():
|
|
2976
2976
|
self.DIRLVLS = int(val)
|
|
2977
2977
|
elif dir and not re.match(r'^(\.|\./|/)$', dir) and dir not in self.DELDIRS:
|
|
2978
2978
|
self.DELDIRS[dir] = val
|
rda_python_common/pg_lock.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
###############################################################################
|
|
2
2
|
# Title: pg_lock.py
|
|
3
3
|
# Author: Zaihua Ji, zji@ucar.edu
|
|
4
|
-
# Date: 08/
|
|
4
|
+
# Date: 08/18/2020
|
|
5
5
|
# 2025-01-10 transferred to package rda_python_common from
|
|
6
6
|
# https://github.com/NCAR/rda-shared-libraries.git
|
|
7
7
|
# 2025-12-01 convert to class PgLock
|
rda_python_common/pg_log.py
CHANGED
|
@@ -252,7 +252,7 @@ class PgLOG:
|
|
|
252
252
|
msg = self.PGLOG['PRGMSG'] + "\n" + msg
|
|
253
253
|
self.PGLOG['PRGMSG'] = ""
|
|
254
254
|
if self.PGLOG['ERRCNT'] == 0:
|
|
255
|
-
if not
|
|
255
|
+
if not msg.endswith('\n'): msg += "!\n"
|
|
256
256
|
else:
|
|
257
257
|
if self.PGLOG['ERRCNT'] == 1:
|
|
258
258
|
msg += " with 1 Error:\n"
|
|
@@ -1423,7 +1423,7 @@ class PgLOG:
|
|
|
1423
1423
|
try:
|
|
1424
1424
|
self.PGLOG['RDAUID'] = self.PGLOG['GDEXUID'] = pwd.getpwnam(self.PGLOG['GDEXUSER']).pw_uid
|
|
1425
1425
|
self.PGLOG['RDAGID'] = self.PGLOG['GDEXGID'] = grp.getgrnam(self.PGLOG['GDEXGRP']).gr_gid
|
|
1426
|
-
except:
|
|
1426
|
+
except KeyError:
|
|
1427
1427
|
self.PGLOG['RDAUID'] = self.PGLOG['GDEXUID'] = 0
|
|
1428
1428
|
self.PGLOG['RDAGID'] = self.PGLOG['GDEXGID'] = 0
|
|
1429
1429
|
if self.PGLOG['CURUID'] == self.PGLOG['GDEXUSER']: self.PGLOG['SETUID'] = self.PGLOG['GDEXUSER']
|
|
@@ -1624,8 +1624,8 @@ class PgLOG:
|
|
|
1624
1624
|
missthen = 0
|
|
1625
1625
|
try:
|
|
1626
1626
|
rf = open(resource, 'r')
|
|
1627
|
-
except:
|
|
1628
|
-
return # skip if cannot open
|
|
1627
|
+
except OSError:
|
|
1628
|
+
return # skip if cannot open
|
|
1629
1629
|
nline = rf.readline()
|
|
1630
1630
|
while nline:
|
|
1631
1631
|
line = self.pgtrim(nline)
|
|
@@ -1638,12 +1638,12 @@ class PgLOG:
|
|
|
1638
1638
|
missthen = 0
|
|
1639
1639
|
if re.match(r'^then$', line): continue # then on next line
|
|
1640
1640
|
checkif = 0 # end of inline if
|
|
1641
|
-
elif
|
|
1641
|
+
elif line.startswith('endif'):
|
|
1642
1642
|
checkif = 0 # end of if
|
|
1643
1643
|
continue
|
|
1644
1644
|
elif checkif == -1: # skip the line
|
|
1645
1645
|
continue
|
|
1646
|
-
elif checkif == 2 and
|
|
1646
|
+
elif checkif == 2 and line.startswith('else'):
|
|
1647
1647
|
checkif = -1 # done check envs in if
|
|
1648
1648
|
continue
|
|
1649
1649
|
if checkif == 1:
|
rda_python_common/pg_opt.py
CHANGED
|
@@ -1158,7 +1158,7 @@ class PgOPT(PgFile):
|
|
|
1158
1158
|
if self.OPTS[opt][2]&16:
|
|
1159
1159
|
if not val:
|
|
1160
1160
|
val = 0
|
|
1161
|
-
elif
|
|
1161
|
+
elif val.isdigit():
|
|
1162
1162
|
val = int(val)
|
|
1163
1163
|
elif val and (opt == 'DS' or opt == 'OD'):
|
|
1164
1164
|
val = self.format_dataset_id(val)
|
rda_python_common/pg_sig.py
CHANGED
|
@@ -961,7 +961,7 @@ class PgSIG(PgDBI):
|
|
|
961
961
|
lines = buf.split('\n')
|
|
962
962
|
for line in lines:
|
|
963
963
|
if chkt:
|
|
964
|
-
if
|
|
964
|
+
if line.startswith('Job'):
|
|
965
965
|
line = re.sub(r'^Job ID', 'JobID', line, 1)
|
|
966
966
|
line = re.sub(r'Finish Time', 'FinishTime', line, 1)
|
|
967
967
|
line = re.sub(r'Req Mem', 'ReqMem', line, 1)
|
rda_python_common/pg_split.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
###############################################################################
|
|
2
2
|
# Title: pg_split.py -- PostgreSQL DataBase Interface foe table wfile
|
|
3
3
|
# Author: Zaihua Ji, zji@ucar.edu
|
|
4
|
-
# Date: 09/
|
|
4
|
+
# Date: 09/10/2024
|
|
5
5
|
# 2025-01-10 transferred to package rda_python_common from
|
|
6
6
|
# https://github.com/NCAR/rda-shared-libraries.git
|
|
7
7
|
# 2025-12-01 convert to class PgSplit
|
|
@@ -12,8 +12,9 @@ import os
|
|
|
12
12
|
import re
|
|
13
13
|
from os import path as op
|
|
14
14
|
from .pg_util import PgUtil
|
|
15
|
+
from .pg_dbi import PgDBI
|
|
15
16
|
|
|
16
|
-
class PgSplit(PgUtil):
|
|
17
|
+
class PgSplit(PgUtil, PgDBI):
|
|
17
18
|
"""Manages synchronisation of wfile records between shared and per-dataset tables.
|
|
18
19
|
|
|
19
20
|
Handles compare, add, update, and delete operations between the shared
|
rda_python_common/pg_util.py
CHANGED
|
@@ -93,22 +93,22 @@ class PgUtil(PgLOG):
|
|
|
93
93
|
int | str: Numeric month (1-12) when fmt is None; formatted string otherwise.
|
|
94
94
|
"""
|
|
95
95
|
if not isinstance(mn, int):
|
|
96
|
-
if
|
|
96
|
+
if mn.isdigit():
|
|
97
97
|
mn = int(mn)
|
|
98
98
|
else:
|
|
99
99
|
for m in range(12):
|
|
100
100
|
if re.match(mn, self.MONTHS[m], re.I):
|
|
101
101
|
mn = m + 1
|
|
102
102
|
break
|
|
103
|
-
if fmt and
|
|
103
|
+
if fmt and 0 < mn < 13:
|
|
104
104
|
slen = len(fmt)
|
|
105
105
|
if slen == 2:
|
|
106
106
|
smn = "{:02}".format(mn)
|
|
107
|
-
elif
|
|
107
|
+
elif fmt[:3].lower() == 'mon':
|
|
108
108
|
smn = self.MNS[mn-1] if slen == 3 else self.MONTHS[mn-1]
|
|
109
|
-
if
|
|
109
|
+
if fmt.startswith('Mon'):
|
|
110
110
|
smn = smn.capitalize()
|
|
111
|
-
elif
|
|
111
|
+
elif fmt.startswith('MON'):
|
|
112
112
|
smn = smn.upper()
|
|
113
113
|
else:
|
|
114
114
|
smn = str(mn)
|
|
@@ -131,26 +131,26 @@ class PgUtil(PgLOG):
|
|
|
131
131
|
formatted string otherwise.
|
|
132
132
|
"""
|
|
133
133
|
if not isinstance(wday, int):
|
|
134
|
-
if
|
|
134
|
+
if wday.isdigit():
|
|
135
135
|
wday = int(wday)
|
|
136
136
|
else:
|
|
137
137
|
for w in range(7):
|
|
138
138
|
if re.match(wday, self.WDAYS[w], re.I):
|
|
139
139
|
wday = w
|
|
140
140
|
break
|
|
141
|
-
if fmt and
|
|
141
|
+
if fmt and 0 <= wday <= 6:
|
|
142
142
|
slen = len(fmt)
|
|
143
143
|
if slen == 4:
|
|
144
144
|
swday = self.WDAYS[wday]
|
|
145
|
-
if
|
|
145
|
+
if fmt.startswith('We'):
|
|
146
146
|
swday = swday.capitalize()
|
|
147
|
-
elif
|
|
147
|
+
elif fmt.startswith('WE'):
|
|
148
148
|
swday = swday.upper()
|
|
149
149
|
elif slen == 3:
|
|
150
150
|
swday = self.WDS[wday]
|
|
151
|
-
if
|
|
151
|
+
if fmt.startswith('Ww'):
|
|
152
152
|
swday = swday.capitalize()
|
|
153
|
-
elif
|
|
153
|
+
elif fmt.startswith('WW'):
|
|
154
154
|
swday = swday.upper()
|
|
155
155
|
else:
|
|
156
156
|
swday = str(wday)
|
|
@@ -179,7 +179,7 @@ class PgUtil(PgLOG):
|
|
|
179
179
|
if exists is None or exists:
|
|
180
180
|
if not op.exists(file): return '' # file does not exist
|
|
181
181
|
bname = op.basename(file)
|
|
182
|
-
if
|
|
182
|
+
if bname.startswith(','): return '' # hidden file
|
|
183
183
|
if re.search(r'index\.(htm|html|shtml)$', bname, re.I): return '' # index file
|
|
184
184
|
if type and type != 'D': return type
|
|
185
185
|
if re.search(r'\.(doc|php|html|shtml)(\.|$)', bname, re.I): return '' # file with special extention
|
|
@@ -314,7 +314,7 @@ class PgUtil(PgLOG):
|
|
|
314
314
|
"""
|
|
315
315
|
if not date: return default
|
|
316
316
|
if not isinstance(date, str): date = str(date)
|
|
317
|
-
if
|
|
317
|
+
if date.startswith('0000'): return default
|
|
318
318
|
return date
|
|
319
319
|
|
|
320
320
|
# fmt: date format, default to "YYYY-MM-DD"
|
|
@@ -422,7 +422,7 @@ class PgUtil(PgLOG):
|
|
|
422
422
|
adt = re.split(sep, sdt)
|
|
423
423
|
acnt = len(adt)
|
|
424
424
|
for i in range(acnt):
|
|
425
|
-
if
|
|
425
|
+
if adt[i].isdigit(): adt[i] = int(adt[i])
|
|
426
426
|
return adt
|
|
427
427
|
|
|
428
428
|
# date: given date in format of fromfmt
|
|
@@ -490,19 +490,20 @@ class PgUtil(PgLOG):
|
|
|
490
490
|
if i >= mcnt: break
|
|
491
491
|
fmt = formats[k]
|
|
492
492
|
val = ms[0][i]
|
|
493
|
-
|
|
493
|
+
head = fmt[:1].upper()
|
|
494
|
+
if head == 'Y':
|
|
494
495
|
dates[0] = int(val)
|
|
495
496
|
if len(fmt) == 3: dates[0] *= 10
|
|
496
|
-
elif
|
|
497
|
+
elif head == 'C':
|
|
497
498
|
dates[0] = 100 * int(val) # year at end of century
|
|
498
|
-
elif
|
|
499
|
-
if
|
|
499
|
+
elif head == 'M':
|
|
500
|
+
if fmt[:3].upper() == 'MON':
|
|
500
501
|
dates[1] = self.get_month(val)
|
|
501
502
|
else:
|
|
502
503
|
dates[1] = int(val)
|
|
503
|
-
elif
|
|
504
|
+
elif head == 'Q':
|
|
504
505
|
dates[1] = 3 * int(val) # month at end of quarter
|
|
505
|
-
elif
|
|
506
|
+
elif head == 'H': # hour
|
|
506
507
|
dates.append(int(val))
|
|
507
508
|
else: # day
|
|
508
509
|
dates[2] = int(val)
|
|
@@ -653,11 +654,11 @@ class PgUtil(PgLOG):
|
|
|
653
654
|
slen = len(fmt)
|
|
654
655
|
if slen == 2:
|
|
655
656
|
smn = "{:02}".format(m)
|
|
656
|
-
elif
|
|
657
|
+
elif fmt[:3].lower() == 'mon':
|
|
657
658
|
smn = self.MNS[m-1] if slen == 3 else self.MONTHS[m-1]
|
|
658
|
-
if
|
|
659
|
+
if fmt.startswith('Mo'):
|
|
659
660
|
smn = smn.capitalize()
|
|
660
|
-
elif
|
|
661
|
+
elif fmt.startswith('MO'):
|
|
661
662
|
smn = smn.upper()
|
|
662
663
|
else:
|
|
663
664
|
smn = str(m)
|
rda_python_common/pgpassword.py
CHANGED
|
@@ -4,17 +4,42 @@
|
|
|
4
4
|
# Author: Zaihua Ji, zji@ucar.edu
|
|
5
5
|
# Date: 2025-10-27
|
|
6
6
|
# 2025-12-02 convert to class PgPassword
|
|
7
|
-
# Purpose: python script to retrieve passwords for
|
|
7
|
+
# Purpose: python script to retrieve passwords for postgresql login to connect a
|
|
8
8
|
# gdex database from inside an python application
|
|
9
9
|
# Github: https://github.com/NCAR/rda-python-common.git
|
|
10
10
|
##################################################################################
|
|
11
|
+
"""
|
|
12
|
+
pgpassword.py - Command-line helper that retrieves a PostgreSQL password.
|
|
13
|
+
|
|
14
|
+
Provides the PgPassword class and a ``main`` entry point used by the
|
|
15
|
+
``pgpassword`` console script. The password is looked up first from
|
|
16
|
+
OpenBao (using the URL/token configured in PgDBI) and, if not found,
|
|
17
|
+
from the user's ``.pgpass`` file. The result is printed to stdout so
|
|
18
|
+
that shell wrappers and other RDA utilities can capture it.
|
|
19
|
+
"""
|
|
11
20
|
import sys
|
|
12
21
|
import re
|
|
13
22
|
from .pg_dbi import PgDBI
|
|
14
23
|
|
|
15
24
|
class PgPassword(PgDBI):
|
|
25
|
+
"""
|
|
26
|
+
Command-line helper for retrieving a PostgreSQL login password.
|
|
27
|
+
|
|
28
|
+
Inherits from PgDBI to reuse its database-connection metadata
|
|
29
|
+
(PGDBI), default schema handling, and password-lookup methods
|
|
30
|
+
(``get_baopassword`` / ``get_pgpassword``).
|
|
31
|
+
|
|
32
|
+
Instance attributes set in __init__:
|
|
33
|
+
DBFLDS -- mapping of CLI option letters to PGDBI field names
|
|
34
|
+
DBINFO -- per-invocation overrides for dbname/scname/lnname/
|
|
35
|
+
dbhost/dbport supplied via CLI options
|
|
36
|
+
dbopt -- True once at least one DB-override option is seen,
|
|
37
|
+
triggering ``default_scinfo`` before lookup
|
|
38
|
+
password -- the retrieved password (set by ``start_actions``)
|
|
39
|
+
"""
|
|
16
40
|
|
|
17
41
|
def __init__(self):
|
|
42
|
+
"""Initialize PgPassword with empty DB-override info and option maps."""
|
|
18
43
|
super().__init__() # initialize parent class
|
|
19
44
|
self.DBFLDS = {
|
|
20
45
|
'd': 'dbname',
|
|
@@ -34,12 +59,28 @@ class PgPassword(PgDBI):
|
|
|
34
59
|
self.password = ''
|
|
35
60
|
|
|
36
61
|
# read in command line parameters
|
|
37
|
-
def read_parameters(self):
|
|
62
|
+
def read_parameters(self):
|
|
63
|
+
"""
|
|
64
|
+
Parse ``sys.argv`` and apply CLI overrides.
|
|
65
|
+
|
|
66
|
+
Recognized options:
|
|
67
|
+
-l URL -- OpenBao URL (stored in self.PGDBI['BAOURL'])
|
|
68
|
+
-k TOKEN -- OpenBao token name (stored in self.PGDBI['BAOTOKEN'])
|
|
69
|
+
-d NAME -- PostgreSQL database name
|
|
70
|
+
-c NAME -- PostgreSQL schema name
|
|
71
|
+
-u NAME -- PostgreSQL login user name
|
|
72
|
+
-h HOST -- PostgreSQL server host name
|
|
73
|
+
-p PORT -- PostgreSQL port number
|
|
74
|
+
|
|
75
|
+
If no arguments are supplied a usage message is printed and the
|
|
76
|
+
process exits with status 0. Unknown options or stray values
|
|
77
|
+
cause an immediate error exit via ``self.pglog(..., LGEREX)``.
|
|
78
|
+
"""
|
|
38
79
|
argv = sys.argv[1:]
|
|
39
80
|
opt = None
|
|
40
81
|
dohelp = True
|
|
41
82
|
for arg in argv:
|
|
42
|
-
if re.match(r'
|
|
83
|
+
if re.match(r'^-[a-zA-Z]$', arg):
|
|
43
84
|
opt = arg[1:]
|
|
44
85
|
elif opt:
|
|
45
86
|
if opt == 'l':
|
|
@@ -55,27 +96,27 @@ class PgPassword(PgDBI):
|
|
|
55
96
|
else:
|
|
56
97
|
self.pglog(arg + ": Value provided without option", self.LGEREX)
|
|
57
98
|
if dohelp:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
print(" -l OpenBao URL to retrieve passwords")
|
|
61
|
-
print(" -k OpenBao Token Name to retrieve passwords")
|
|
62
|
-
print(" -d PostgreSQL Database Name")
|
|
63
|
-
print(" -c PostgreSQL Schema Name")
|
|
64
|
-
print(" -u PostgreSQL Login User Name")
|
|
65
|
-
print(" -h PostgreSQL Server Host Name")
|
|
66
|
-
print(" -p PostgreSQL Port Number")
|
|
67
|
-
sys.exit(0)
|
|
99
|
+
self.set_help_path(__file__)
|
|
100
|
+
self.show_usage("pgpassword")
|
|
68
101
|
|
|
69
102
|
# get the pgpassword
|
|
70
103
|
def start_actions(self):
|
|
104
|
+
"""
|
|
105
|
+
Look up the password and store it in ``self.password``.
|
|
106
|
+
|
|
107
|
+
Applies any CLI-supplied DB overrides via ``default_scinfo``, then
|
|
108
|
+
tries OpenBao first (``get_baopassword``) and falls back to the
|
|
109
|
+
``.pgpass`` file (``get_pgpassword``) if OpenBao returns nothing.
|
|
110
|
+
"""
|
|
71
111
|
if self.dbopt:
|
|
72
112
|
self.default_scinfo(self.DBINFO['dbname'], self.DBINFO['scname'], self.DBINFO['dbhost'],
|
|
73
113
|
self.DBINFO['lnname'], None, self.DBINFO['dbport'])
|
|
74
114
|
self.password = self.get_baopassword()
|
|
75
|
-
if not self.password: self.password = self.
|
|
115
|
+
if not self.password: self.password = self.get_pgpassword()
|
|
76
116
|
|
|
77
117
|
# main function to excecute this script
|
|
78
118
|
def main():
|
|
119
|
+
"""Entry point for the ``pgpassword`` console script: print the retrieved password to stdout."""
|
|
79
120
|
object = PgPassword()
|
|
80
121
|
object.read_parameters()
|
|
81
122
|
object.start_actions()
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rda_python_common
|
|
3
|
+
Version: 2.1.8
|
|
4
|
+
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
|
+
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
|
+
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
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: hvac
|
|
15
|
+
Requires-Dist: psycopg2==2.9.10
|
|
16
|
+
Requires-Dist: rda-python-globus
|
|
17
|
+
Requires-Dist: unidecode
|
|
18
|
+
Requires-Dist: hvac
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# rda-python-common
|
|
22
|
+
|
|
23
|
+
Python common library codes to be shared by other RDA python utility programs.
|
|
24
|
+
|
|
25
|
+
## Installing and using in another RDA python repo
|
|
26
|
+
|
|
27
|
+
`rda-python-common` is the foundation that every other `rda-python-*` repo
|
|
28
|
+
builds on. To consume it from a new or existing repo, follow these steps.
|
|
29
|
+
|
|
30
|
+
### 1. Install the package
|
|
31
|
+
|
|
32
|
+
For local development, clone this repo alongside your project and install it
|
|
33
|
+
in editable mode so that changes are picked up without re-installing:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git clone https://github.com/NCAR/rda-python-common.git
|
|
37
|
+
cd rda-python-common
|
|
38
|
+
pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For a regular (non-editable) install from a checkout:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install /path/to/rda-python-common
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For a production install on a system that uses the published distribution:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install rda_python_common
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The package brings in its own transitive dependencies (`psycopg2-binary`,
|
|
54
|
+
`rda-python-globus`, `unidecode`, `hvac`).
|
|
55
|
+
|
|
56
|
+
### 2. Declare it as a dependency in your project
|
|
57
|
+
|
|
58
|
+
Add `rda_python_common` to the `dependencies` list of your project's
|
|
59
|
+
`pyproject.toml` so that downstream installs pull it in automatically:
|
|
60
|
+
|
|
61
|
+
```toml
|
|
62
|
+
[project]
|
|
63
|
+
name = "rda_python_yourtool"
|
|
64
|
+
version = "0.1.0"
|
|
65
|
+
dependencies = [
|
|
66
|
+
"rda_python_common",
|
|
67
|
+
# ... other deps
|
|
68
|
+
]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
This is the same pattern used by `rda-python-dsarch`, `rda-python-dsupdt`,
|
|
72
|
+
`rda-python-dsrqst`, `rda-python-dscheck`, `rda-python-metrics`, and
|
|
73
|
+
`rda-python-miscs`.
|
|
74
|
+
|
|
75
|
+
### 3. Import the modules you need
|
|
76
|
+
|
|
77
|
+
Two import styles are supported (see [Usage examples](#usage-examples) below):
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Preferred for new code -- import the class from the lower-case module
|
|
81
|
+
from rda_python_common.pg_log import PgLOG
|
|
82
|
+
from rda_python_common.pg_dbi import PgDBI
|
|
83
|
+
|
|
84
|
+
# Legacy module-style imports remain supported for back-compatibility
|
|
85
|
+
from rda_python_common import PgLOG, PgDBI
|
|
86
|
+
PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 4. Verify the install
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
You should see the installed version (currently `2.1.8`). If the import
|
|
96
|
+
fails, double-check that the active Python environment is the one where you
|
|
97
|
+
ran `pip install`.
|
|
98
|
+
|
|
99
|
+
## Modules
|
|
100
|
+
|
|
101
|
+
All shared functionality lives under `src/rda_python_common/` and is organised as
|
|
102
|
+
a single-inheritance class hierarchy. Each module defines exactly one class;
|
|
103
|
+
later classes extend earlier ones, so an application that instantiates the
|
|
104
|
+
top-of-chain class (typically `PgOPT` or `PgCMD`) gets every helper through one
|
|
105
|
+
object.
|
|
106
|
+
|
|
107
|
+
Inheritance tree (top-down; multi-inheritance shown as two arrows
|
|
108
|
+
converging on the same child):
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
PgLOG
|
|
112
|
+
┌────┴────┐
|
|
113
|
+
▼ ▼
|
|
114
|
+
PgUtil PgDBI
|
|
115
|
+
│ │ │ │ │
|
|
116
|
+
│ └────┐ ┌─┘ │ └─► PgPassword
|
|
117
|
+
│ ▼ ▼ │
|
|
118
|
+
│ PgSplit │ (multi-inherits
|
|
119
|
+
│ │ PgUtil + PgDBI)
|
|
120
|
+
│ ▼
|
|
121
|
+
│ PgSIG
|
|
122
|
+
│ │
|
|
123
|
+
│ ┌──────────┘
|
|
124
|
+
▼ ▼
|
|
125
|
+
PgFile (multi-inherits
|
|
126
|
+
│ PgUtil + PgSIG)
|
|
127
|
+
├─► PgOPT
|
|
128
|
+
│
|
|
129
|
+
└─► PgLock
|
|
130
|
+
│
|
|
131
|
+
└─► PgCMD
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The tree is single inheritance everywhere except at two join points:
|
|
135
|
+
|
|
136
|
+
- **`PgFile(PgUtil, PgSIG)`** — combines date/record utilities (`PgUtil`
|
|
137
|
+
via `PgLOG`) with daemon/signal/DB control (`PgSIG` → `PgDBI` → `PgLOG`),
|
|
138
|
+
so its descendants `PgOPT`, `PgLock`, and `PgCMD` inherit logging, DB,
|
|
139
|
+
util, signal, and file facilities through one MRO.
|
|
140
|
+
- **`PgSplit(PgUtil, PgDBI)`** — combines record-manipulation helpers
|
|
141
|
+
(`PgUtil`) with the `pgadd`/`pgget`/`pgmget`/`pgupdt`/`pgdel` DB
|
|
142
|
+
operations (`PgDBI`) it needs to keep the shared `wfile` table and the
|
|
143
|
+
per-dataset `wfile_<dsid>` partitions in sync.
|
|
144
|
+
|
|
145
|
+
- **`pg_log.py`** — `PgLOG`. Root of the hierarchy. Provides the central
|
|
146
|
+
logging facility (bit-mask `logact` flags such as `MSGLOG`, `WARNLG`,
|
|
147
|
+
`ERRLOG`, `EXITLG`), e-mail dispatch, system-command execution, process
|
|
148
|
+
metadata lookup, and the global `PGLOG` settings dictionary used by every
|
|
149
|
+
other module.
|
|
150
|
+
|
|
151
|
+
- **`pg_util.py`** — `PgUtil(PgLOG)`. Miscellaneous date/time, dataset-ID,
|
|
152
|
+
and column-oriented record-manipulation helpers. Holds the `DATEFMTS`
|
|
153
|
+
regex table, `MONTHS`/`MNS`/`WDAYS`/`WDS` lookup lists, and the `MDAYS`
|
|
154
|
+
days-per-month array used for date arithmetic, formatting, parsing, and
|
|
155
|
+
record sort/search/classification across all RDA tools.
|
|
156
|
+
|
|
157
|
+
- **`pg_file.py`** — `PgFile(PgUtil, PgSIG)`. Unified file-operation layer
|
|
158
|
+
spanning local file systems, remote hosts (rsync/ssh/scp), AWS S3 / object
|
|
159
|
+
store, and Globus endpoints. Used by `rdacp`, `dsarch`, `dsupdt`, and
|
|
160
|
+
related tools whenever data is moved, listed, or stat-ed.
|
|
161
|
+
|
|
162
|
+
- **`pg_lock.py`** — `PgLock(PgFile)`. RDADB record-locking primitives for
|
|
163
|
+
the `dscheck`, `dsrqst`, `dlupdt`, `dcupdt`, `ptrqst`, and `dataset`
|
|
164
|
+
tables. Acquires, refreshes, and releases per-record locks so that
|
|
165
|
+
long-running batch jobs coordinate cleanly.
|
|
166
|
+
|
|
167
|
+
- **`pg_dbi.py`** — `PgDBI(PgLOG)`. PostgreSQL database interface built on
|
|
168
|
+
`psycopg2`. Wraps connection management, batch `INSERT`/`SELECT`/
|
|
169
|
+
`UPDATE`/`DELETE`, transaction control, and credential lookup from
|
|
170
|
+
`.pgpass` or OpenBao. All RDA tools talk to the `rdadb` database through
|
|
171
|
+
this class.
|
|
172
|
+
|
|
173
|
+
- **`pg_sig.py`** — `PgSIG(PgDBI)`. Daemon process control, POSIX signal
|
|
174
|
+
handling, child/background-process management, and PBS/Torque batch-job
|
|
175
|
+
status queries. Provides the `PGSIG` runtime dictionary plus `VUSERS`,
|
|
176
|
+
`CPIDS`, `CBIDS`, and `SDUMP` tables that drive RDA daemon programs.
|
|
177
|
+
|
|
178
|
+
- **`pg_cmd.py`** — `PgCMD(PgLock)`. Manages `dscheck` batch and delayed-
|
|
179
|
+
mode command tracking. Records, updates, and reaps the per-command rows
|
|
180
|
+
that let RDA utilities resume or be monitored across PBS batch jobs.
|
|
181
|
+
|
|
182
|
+
- **`pg_split.py`** — `PgSplit(PgUtil, PgDBI)`. Synchronises `wfile` records
|
|
183
|
+
between the shared `wfile` table and the per-dataset `wfile_<dsid>`
|
|
184
|
+
partition tables. Provides compare/add/update/delete helpers used when
|
|
185
|
+
archiving or reconciling dataset file inventories.
|
|
186
|
+
|
|
187
|
+
- **`pg_opt.py`** — `PgOPT(PgFile)`. Command-line option parsing and
|
|
188
|
+
application configuration framework for RDA tools (`dsarch`, `dsupdt`,
|
|
189
|
+
`dsrqst`, ...). Holds the master `OPTS` definition table, parsed
|
|
190
|
+
`params`, command-line vs. input-file option tracking (`CMDOPTS`/
|
|
191
|
+
`INOPTS`), output formatting, dataset/help/media/storage/backup type
|
|
192
|
+
maps, and the global `PGOPT` settings.
|
|
193
|
+
|
|
194
|
+
- **`pgpassword.py`** — `PgPassword(PgDBI)`. Standalone CLI entry point
|
|
195
|
+
(`pgpassword`) that resolves a PostgreSQL login password from OpenBao
|
|
196
|
+
(`get_baopassword`) or `~/.pgpass` (`get_pgpassword()`) given database/schema/
|
|
197
|
+
host/port/user selectors via `-d`, `-c`, `-h`, `-p`, `-u`, `-l`, `-k`.
|
|
198
|
+
Prints the resolved password to stdout so shell scripts can capture it.
|
|
199
|
+
|
|
200
|
+
## Usage examples
|
|
201
|
+
|
|
202
|
+
Each class lives in its own submodule. Import the class you need, then
|
|
203
|
+
either instantiate it directly or subclass it to add application-specific
|
|
204
|
+
state and methods.
|
|
205
|
+
|
|
206
|
+
### 1. Direct instantiation — use the helpers as-is
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
# Logging only
|
|
210
|
+
from rda_python_common.pg_log import PgLOG
|
|
211
|
+
|
|
212
|
+
log = PgLOG()
|
|
213
|
+
log.pglog("dsarch started", log.LOGWRN)
|
|
214
|
+
|
|
215
|
+
# Database access (PgDBI inherits PgLOG, so you get logging too)
|
|
216
|
+
from rda_python_common.pg_dbi import PgDBI
|
|
217
|
+
|
|
218
|
+
db = PgDBI()
|
|
219
|
+
rec = db.pgget('dataset', 'dsid, title', "dsid = 'd633000'")
|
|
220
|
+
print(rec)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 2. Subclassing a single common class
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
# A small utility that needs date/record helpers plus logging.
|
|
227
|
+
from rda_python_common.pg_util import PgUtil
|
|
228
|
+
|
|
229
|
+
class DateReport(PgUtil):
|
|
230
|
+
def __init__(self):
|
|
231
|
+
super().__init__() # initialise PgUtil (and PgLOG)
|
|
232
|
+
self.today = self.curtime() # method inherited from PgUtil
|
|
233
|
+
|
|
234
|
+
def run(self):
|
|
235
|
+
self.pglog(f"report date: {self.today}", self.LOGWRN)
|
|
236
|
+
|
|
237
|
+
DateReport().run()
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 3. Subclassing one of the multi-inheriting joins
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# A worker that needs file I/O (PgFile) and dscheck command tracking (PgCMD).
|
|
244
|
+
# PgCMD already extends PgFile via PgLock, so a single base is enough.
|
|
245
|
+
from rda_python_common.pg_cmd import PgCMD
|
|
246
|
+
|
|
247
|
+
class Worker(PgCMD):
|
|
248
|
+
def __init__(self):
|
|
249
|
+
super().__init__()
|
|
250
|
+
self.jobs = []
|
|
251
|
+
|
|
252
|
+
def archive_one(self, src, dst):
|
|
253
|
+
# PgFile method, available through the inheritance chain
|
|
254
|
+
self.local_copy_local(src, dst)
|
|
255
|
+
# PgDBI method, available through PgCMD -> PgLock -> PgFile -> PgSIG -> PgDBI
|
|
256
|
+
self.pgupdt('wfile', {'status': 'A'}, f"wfile = '{dst}'")
|
|
257
|
+
|
|
258
|
+
Worker().archive_one('/in/file', '/out/file')
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### 4. Combining multiple common classes (application action class)
|
|
262
|
+
|
|
263
|
+
This mirrors how RDA tools such as `dsarch` are structured. The leaf class
|
|
264
|
+
multi-inherits several common classes so a single object exposes options,
|
|
265
|
+
command tracking, and wfile splitting.
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
# Excerpt of the pattern used by rda_python_dsarch/dsarch.py
|
|
269
|
+
from rda_python_common.pg_opt import PgOPT
|
|
270
|
+
from rda_python_common.pg_cmd import PgCMD
|
|
271
|
+
from rda_python_common.pg_split import PgSplit
|
|
272
|
+
|
|
273
|
+
class PgArch(PgOPT, PgCMD, PgSplit):
|
|
274
|
+
"""Shared state + helpers for a CLI archiving tool."""
|
|
275
|
+
def __init__(self):
|
|
276
|
+
super().__init__()
|
|
277
|
+
self.RTPATH = {} # runtime path cache
|
|
278
|
+
self.OPTS = {} # option table (populated by subclass)
|
|
279
|
+
|
|
280
|
+
class DsArch(PgArch):
|
|
281
|
+
def __init__(self):
|
|
282
|
+
super().__init__()
|
|
283
|
+
self.ALLCNT = self.ADDCNT = self.MODCNT = 0
|
|
284
|
+
|
|
285
|
+
def main(self):
|
|
286
|
+
self.read_parameters() # from PgOPT
|
|
287
|
+
self.start_actions() # dispatch
|
|
288
|
+
|
|
289
|
+
if __name__ == "__main__":
|
|
290
|
+
DsArch().main()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 5. Reading a PostgreSQL password from OpenBao or ~/.pgpass
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from rda_python_common.pgpassword import PgPassword
|
|
297
|
+
|
|
298
|
+
pw = PgPassword()
|
|
299
|
+
pw.default_scinfo('rdadb', 'dssdb', 'rda-pgdb', 'gdexweb', None, 5432)
|
|
300
|
+
password = pw.get_baopassword() or pw.get_pgpassword()
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
In every case `super().__init__()` cooperates correctly across the
|
|
304
|
+
multi-inheriting joins (`PgFile` and `PgSplit`), so subclasses only need
|
|
305
|
+
to call it once.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
rda_python_common/PgCMD.py,sha256=EYjG2Z4zEnvsXE1z-jt5UaNoEKxnOYYiMMzvW6HrKA4,20597
|
|
2
|
+
rda_python_common/PgDBI.py,sha256=sOKQmzF_qmLR_vnj-NnFEYbLI05t2bVbhqlqy46iluA,76424
|
|
3
|
+
rda_python_common/PgFile.py,sha256=7hyDFm40_NjQ_tg5WviMw_waYPdyXCi0DRCf0Av8eNE,99370
|
|
4
|
+
rda_python_common/PgLOG.py,sha256=43YVpMjWEOLpaMUb4YTEYlDTvp7FTmDQ8V3TAKQrC4M,55228
|
|
5
|
+
rda_python_common/PgLock.py,sha256=12i84nsGBuifSyPnm8IR63LvHvRuVU573D5QKFlHdOI,22623
|
|
6
|
+
rda_python_common/PgOPT.py,sha256=Kn4JYezZhZwAn2usiIYHoHiymGHRgsN299dxyXbKwkI,56244
|
|
7
|
+
rda_python_common/PgSIG.py,sha256=eTJJ3XxutsQ3JSg6uYRpH26ZmrVUup3ShqDFLWXLruA,35803
|
|
8
|
+
rda_python_common/PgSplit.py,sha256=SSg5_Qu5PqP44EkqebO-V_cErNcdE2QtORgFHQ7RqlQ,8822
|
|
9
|
+
rda_python_common/PgUtil.py,sha256=OqESKCd72b9g8m8jwjPJhXDtPYlW6G8oSOhwChvz2Cg,48600
|
|
10
|
+
rda_python_common/__init__.py,sha256=6JXEmVcGzKGHOOqOIqeAg_fXqr5PXHlIHiLvwH5D8ac,994
|
|
11
|
+
rda_python_common/pg_cmd.py,sha256=hQZaW80eFqEUoF0vZHtGuvBEWXbXdY0Nvj6rFIQGboo,32856
|
|
12
|
+
rda_python_common/pg_dbi.py,sha256=q6LT4a4lwo-sM2LEqgrEVkAlh886xeKiz4feqRKw-7c,116238
|
|
13
|
+
rda_python_common/pg_file.py,sha256=RzQTxnht4bFOVty4qoYPREawMCUsnFIbWm2pfEez1fE,161993
|
|
14
|
+
rda_python_common/pg_lock.py,sha256=31EaVDjCkcx3-n8-KnzG18R8Pz7Z6KyFsEqcml6Iq5c,32702
|
|
15
|
+
rda_python_common/pg_log.py,sha256=5kasi1aucWWhlGRlvOG9MT4eHmNsPqEb09rFn_kHPjg,80669
|
|
16
|
+
rda_python_common/pg_opt.py,sha256=sXrlzFWpR2XMak6NlA0MPvErBuQnY6gHM5OsHtoeIPQ,82496
|
|
17
|
+
rda_python_common/pg_password.py,sha256=X-eIDwdqBhtrhrbDTNWle-0JtWsyIVZdDOZaBu7cFHM,2343
|
|
18
|
+
rda_python_common/pg_sig.py,sha256=wLKBmFNWAmxWJFC2L3SLsD4n464kzzHbIFFNBlCW6kI,52759
|
|
19
|
+
rda_python_common/pg_split.py,sha256=aAWKUZPmZ-LQ_fJ3DSKzPKxJw0fMDJ2fgP8ZT629M30,16375
|
|
20
|
+
rda_python_common/pg_util.py,sha256=bjp2civRIhqaBSR8oOtyRzYIZBdwB90SzmJLjRIA7fc,87280
|
|
21
|
+
rda_python_common/pgpassword.py,sha256=PVbF_ereAuNf1oy17-KPBycH9-Muy2gWlry9cQIW4sg,4711
|
|
22
|
+
rda_python_common-2.1.8.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
|
|
23
|
+
rda_python_common-2.1.8.dist-info/METADATA,sha256=aiikhrncVk_IyHLmsTwFmjqC0hLD8YELRPszQZHa_f8,11090
|
|
24
|
+
rda_python_common-2.1.8.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
25
|
+
rda_python_common-2.1.8.dist-info/entry_points.txt,sha256=pZgVNWspcK-F1TbPav7C3C9NdeHDZMm_25fW9weix00,65
|
|
26
|
+
rda_python_common-2.1.8.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
|
|
27
|
+
rda_python_common-2.1.8.dist-info/RECORD,,
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: rda_python_common
|
|
3
|
-
Version: 2.1.7
|
|
4
|
-
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
|
-
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
|
-
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
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: hvac
|
|
15
|
-
Requires-Dist: psycopg2==2.9.10
|
|
16
|
-
Requires-Dist: rda-python-globus
|
|
17
|
-
Requires-Dist: unidecode
|
|
18
|
-
Dynamic: license-file
|
|
19
|
-
|
|
20
|
-
# rda-python-common
|
|
21
|
-
Python common library codes to be shared by other RDA python utility programs.
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
rda_python_common/PgCMD.py,sha256=EYjG2Z4zEnvsXE1z-jt5UaNoEKxnOYYiMMzvW6HrKA4,20597
|
|
2
|
-
rda_python_common/PgDBI.py,sha256=sOKQmzF_qmLR_vnj-NnFEYbLI05t2bVbhqlqy46iluA,76424
|
|
3
|
-
rda_python_common/PgFile.py,sha256=7hyDFm40_NjQ_tg5WviMw_waYPdyXCi0DRCf0Av8eNE,99370
|
|
4
|
-
rda_python_common/PgLOG.py,sha256=43YVpMjWEOLpaMUb4YTEYlDTvp7FTmDQ8V3TAKQrC4M,55228
|
|
5
|
-
rda_python_common/PgLock.py,sha256=12i84nsGBuifSyPnm8IR63LvHvRuVU573D5QKFlHdOI,22623
|
|
6
|
-
rda_python_common/PgOPT.py,sha256=Kn4JYezZhZwAn2usiIYHoHiymGHRgsN299dxyXbKwkI,56244
|
|
7
|
-
rda_python_common/PgSIG.py,sha256=eTJJ3XxutsQ3JSg6uYRpH26ZmrVUup3ShqDFLWXLruA,35803
|
|
8
|
-
rda_python_common/PgSplit.py,sha256=SSg5_Qu5PqP44EkqebO-V_cErNcdE2QtORgFHQ7RqlQ,8822
|
|
9
|
-
rda_python_common/PgUtil.py,sha256=OqESKCd72b9g8m8jwjPJhXDtPYlW6G8oSOhwChvz2Cg,48600
|
|
10
|
-
rda_python_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
rda_python_common/pg_cmd.py,sha256=hQZaW80eFqEUoF0vZHtGuvBEWXbXdY0Nvj6rFIQGboo,32856
|
|
12
|
-
rda_python_common/pg_dbi.py,sha256=R-ZzHUItAxma_rCTrelDakFQDl8yEtOTKo4IRfzKl_Q,116269
|
|
13
|
-
rda_python_common/pg_file.py,sha256=doIXpl0I8gO1yiNofipjwZmHF6TYQkWIEj9XrMRz4XQ,162013
|
|
14
|
-
rda_python_common/pg_lock.py,sha256=Il-pY81JtEDMWtwqW6lEM-EtKbhNI6rug8VMCdkGgNc,32703
|
|
15
|
-
rda_python_common/pg_log.py,sha256=Zte9joy46hn2RsJPNpisHLjxZI-mDdcXY4aSiMNlIoY,80661
|
|
16
|
-
rda_python_common/pg_opt.py,sha256=N45DIY2O3S7ogABOHUecfiKwQY1_O4X7WYYZGLdnhOI,82506
|
|
17
|
-
rda_python_common/pg_password.py,sha256=X-eIDwdqBhtrhrbDTNWle-0JtWsyIVZdDOZaBu7cFHM,2343
|
|
18
|
-
rda_python_common/pg_sig.py,sha256=Dz7QKOkwYchbhVZgQxQqFrUmGaxer2bm8D2K99ig5L0,52760
|
|
19
|
-
rda_python_common/pg_split.py,sha256=yOeUSRzgQlwNGzv76ZLCZtsjzDQw0NeYXz0IV0RZgXQ,16343
|
|
20
|
-
rda_python_common/pg_util.py,sha256=1f25D4xyPMerW55q42CQOD0WYAoFYL2A8Opl4rHA8N4,87393
|
|
21
|
-
rda_python_common/pgpassword.py,sha256=WXEq88XgkQSmJ2j2MX0HSVEUFZOFu-gokRJYvEQj_u4,2900
|
|
22
|
-
rda_python_common-2.1.7.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
|
|
23
|
-
rda_python_common-2.1.7.dist-info/METADATA,sha256=HBIupC4bHGhJ3H9tanrlZxjiw_SuDKChlvB7E06YfGs,761
|
|
24
|
-
rda_python_common-2.1.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
25
|
-
rda_python_common-2.1.7.dist-info/entry_points.txt,sha256=pZgVNWspcK-F1TbPav7C3C9NdeHDZMm_25fW9weix00,65
|
|
26
|
-
rda_python_common-2.1.7.dist-info/top_level.txt,sha256=KVQmx7D3DD-jsiheqL8HdTrRE14hpRnZY5_ioMArA5k,18
|
|
27
|
-
rda_python_common-2.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|