rda-python-common 3.0.14__tar.gz → 3.0.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rda_python_common-3.0.14/src/rda_python_common.egg-info → rda_python_common-3.0.16}/PKG-INFO +2 -2
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/README.md +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/pyproject.toml +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/__init__.py +1 -1
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_dbi.py +111 -23
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_file.py +61 -2
- {rda_python_common-3.0.14 → rda_python_common-3.0.16/src/rda_python_common.egg-info}/PKG-INFO +2 -2
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/LICENSE +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/setup.cfg +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgCMD.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgDBI.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgFile.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgLOG.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgLock.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgOPT.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgSIG.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgSplit.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/PgUtil.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_cmd.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_lock.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_log.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_opt.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_password.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_sig.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_split.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pg_util.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pgpassword.py +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common/pgpassword.usg +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/SOURCES.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/dependency_links.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/entry_points.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/requires.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/top_level.txt +0 -0
- {rda_python_common-3.0.14 → rda_python_common-3.0.16}/test/test_common.py +0 -0
{rda_python_common-3.0.14/src/rda_python_common.egg-info → rda_python_common-3.0.16}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.16
|
|
4
4
|
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
5
|
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
@@ -189,7 +189,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
189
189
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
You should see the installed version (currently `3.0.
|
|
192
|
+
You should see the installed version (currently `3.0.16`). If the import
|
|
193
193
|
fails, double-check that the active Python environment is the one where you
|
|
194
194
|
ran `pip install`.
|
|
195
195
|
|
|
@@ -165,7 +165,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
165
165
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
You should see the installed version (currently `3.0.
|
|
168
|
+
You should see the installed version (currently `3.0.16`). If the import
|
|
169
169
|
fails, double-check that the active Python environment is the one where you
|
|
170
170
|
ran `pip install`.
|
|
171
171
|
|
|
@@ -76,7 +76,7 @@ class PgDBI(PgLOG):
|
|
|
76
76
|
using psycopg (v3) when available, falling back to psycopg2. Supports single
|
|
77
77
|
and batch INSERT, SELECT, UPDATE, and DELETE operations, transaction
|
|
78
78
|
management, schema introspection, user lookups, usage tracking, and
|
|
79
|
-
credential retrieval from .pgpass or OpenBao.
|
|
79
|
+
credential retrieval from the environment, .pgpass or OpenBao.
|
|
80
80
|
|
|
81
81
|
Inherits all logging and utility helpers from PgLOG.
|
|
82
82
|
|
|
@@ -96,7 +96,10 @@ class PgDBI(PgLOG):
|
|
|
96
96
|
set from psycopg/psycopg2 depending on which driver is in use.
|
|
97
97
|
DBPORTS (dict): Mapping of database names to non-default TCP port numbers.
|
|
98
98
|
DBPASS (dict): Credentials loaded from .pgpass, keyed by (host, port, db, user).
|
|
99
|
-
DBBAOS (dict): Credentials loaded from OpenBao, keyed by
|
|
99
|
+
DBBAOS (dict): Credentials loaded from OpenBao, keyed by db server node.
|
|
100
|
+
DBNODES (dict): Mapping of database names to their db server nodes, used when the
|
|
101
|
+
node cannot be taken from the host being connected to.
|
|
102
|
+
DBSKEYS (dict): Mapping of login names to secret key names ('<lnname>pass' by default).
|
|
100
103
|
DBNAMES (dict): Mapping of schema names to their parent database names.
|
|
101
104
|
DBSOCKS (dict): Mapping of database names to Unix socket paths.
|
|
102
105
|
VIEWHOMES (dict): Mapping of hostnames to home directories for the view host.
|
|
@@ -139,6 +142,19 @@ class PgDBI(PgLOG):
|
|
|
139
142
|
self.DBPORTS = {'default': 0}
|
|
140
143
|
self.DBPASS = {}
|
|
141
144
|
self.DBBAOS = {}
|
|
145
|
+
# hard coded db server nodes for dbnames, for hosts not named for their nodes; a node
|
|
146
|
+
# names the OpenBao path (kv/gdex/<node>) and the password environment variable
|
|
147
|
+
# (<NODE>_<KEY>) the same secrets are passed in through
|
|
148
|
+
self.DBNODES = {
|
|
149
|
+
'ivaddb': 'pgdb03',
|
|
150
|
+
'ispddb': 'pgdb03',
|
|
151
|
+
'default': 'pgdb01',
|
|
152
|
+
}
|
|
153
|
+
# hard coded secret key names for db login names, defaulting to <lnname>pass
|
|
154
|
+
self.DBSKEYS = {
|
|
155
|
+
'postgres': 'password',
|
|
156
|
+
'metadata': 'metapass',
|
|
157
|
+
}
|
|
142
158
|
# hard coded db names for given schema names
|
|
143
159
|
self.DBNAMES = {
|
|
144
160
|
'ivaddb': 'ivaddb',
|
|
@@ -2617,19 +2633,91 @@ class PgDBI(PgLOG):
|
|
|
2617
2633
|
def get_pgpass_password(self):
|
|
2618
2634
|
"""Return the database password for the current connection settings.
|
|
2619
2635
|
|
|
2620
|
-
Checks PGDBI['PWNAME'] first, then
|
|
2621
|
-
|
|
2636
|
+
Checks PGDBI['PWNAME'] first, then the environment (get_envpassword(), as set
|
|
2637
|
+
for containers on CIRRUS), then the .pgpass file (get_pgpassword()), and
|
|
2638
|
+
finally falls back to OpenBao (get_baopassword()). A password found on local
|
|
2639
|
+
or batch hosts is cached in the environment (set_envpassword()) so that the
|
|
2640
|
+
child processes inherit it instead of looking it up again.
|
|
2622
2641
|
|
|
2623
2642
|
Returns:
|
|
2624
2643
|
str | None: Password string, or None when no credential is found.
|
|
2625
2644
|
"""
|
|
2626
2645
|
if self.PGDBI['PWNAME']: return self.PGDBI['PWNAME']
|
|
2646
|
+
pwname = self.get_envpassword()
|
|
2647
|
+
if pwname: return pwname
|
|
2627
2648
|
pwname = self.get_pgpassword()
|
|
2628
2649
|
if not pwname: pwname = self.get_baopassword()
|
|
2629
|
-
if
|
|
2630
|
-
self.
|
|
2650
|
+
if pwname:
|
|
2651
|
+
self.set_envpassword(pwname)
|
|
2652
|
+
else:
|
|
2653
|
+
self.pglog("Unable to find password for {} in environment, .pgpass or OpenBao".format(self.PGDBI['DBNAME']), self.PGDBI['ERRLOG'])
|
|
2631
2654
|
return pwname
|
|
2632
2655
|
|
|
2656
|
+
def get_dbnodes(self):
|
|
2657
|
+
"""Return the db server nodes holding the secrets of the current connection.
|
|
2658
|
+
|
|
2659
|
+
The node named by DBSHOST comes first, such as pgdb02 for the view-only host,
|
|
2660
|
+
so that a node with its own passwords is served its own secrets. The DBNODES
|
|
2661
|
+
node of the current DBNAME follows it as a fallback, such as pgdb01 for pgdb02,
|
|
2662
|
+
for a node that shares the passwords of the default one without holding secrets
|
|
2663
|
+
of its own.
|
|
2664
|
+
|
|
2665
|
+
Returns:
|
|
2666
|
+
list: Node names, such as ['pgdb02', 'pgdb01'], the first one preferred.
|
|
2667
|
+
"""
|
|
2668
|
+
dbnodes = []
|
|
2669
|
+
ms = re.match(r'^(pgdb\d+)$', self.PGDBI['DBSHOST']) if self.PGDBI['DBSHOST'] else None
|
|
2670
|
+
if ms: dbnodes.append(ms.group(1))
|
|
2671
|
+
dbnode = self.DBNODES.get(self.PGDBI['DBNAME'], self.DBNODES['default'])
|
|
2672
|
+
if dbnode not in dbnodes: dbnodes.append(dbnode)
|
|
2673
|
+
|
|
2674
|
+
return dbnodes
|
|
2675
|
+
|
|
2676
|
+
def get_secret_name(self, dbnode):
|
|
2677
|
+
"""Build the name of the secret holding the password of the current connection.
|
|
2678
|
+
|
|
2679
|
+
The key comes from DBSKEYS for the current LNNAME, defaulting to '<lnname>pass'.
|
|
2680
|
+
The pair names the secret in OpenBao (kv/gdex/<node> key <key>) and the
|
|
2681
|
+
environment variable (<NODE>_<KEY>) the same secret is passed in through
|
|
2682
|
+
on CIRRUS.
|
|
2683
|
+
|
|
2684
|
+
Args:
|
|
2685
|
+
dbnode (str): Db server node holding the secret, such as 'pgdb01'.
|
|
2686
|
+
|
|
2687
|
+
Returns:
|
|
2688
|
+
tuple: (node, key) naming the db server node and the secret key.
|
|
2689
|
+
"""
|
|
2690
|
+
lnname = self.PGDBI['LNNAME']
|
|
2691
|
+
|
|
2692
|
+
return (dbnode, self.DBSKEYS.get(lnname, lnname + 'pass'))
|
|
2693
|
+
|
|
2694
|
+
def get_envpassword(self):
|
|
2695
|
+
"""Look up the password in the environment, as set for containers on CIRRUS.
|
|
2696
|
+
|
|
2697
|
+
The variable name is the uppercased '<node>_<key>' secret name, for example
|
|
2698
|
+
PGDB01_DSSDBPASS for login name dssdb and PGDB03_IVADDBPASS for ivaddb. The
|
|
2699
|
+
fallback nodes of get_dbnodes() are tried in turn.
|
|
2700
|
+
|
|
2701
|
+
Returns:
|
|
2702
|
+
str | None: Password string, or None when no variable is set.
|
|
2703
|
+
"""
|
|
2704
|
+
for dbnode in self.get_dbnodes():
|
|
2705
|
+
pwname = os.environ.get("{}_{}".format(*self.get_secret_name(dbnode)).upper())
|
|
2706
|
+
if pwname: return pwname
|
|
2707
|
+
|
|
2708
|
+
return None
|
|
2709
|
+
|
|
2710
|
+
def set_envpassword(self, pwname):
|
|
2711
|
+
"""Cache a password in the environment under the name get_envpassword() reads.
|
|
2712
|
+
|
|
2713
|
+
Called for a password found in .pgpass or OpenBao, on local and PBS batch hosts,
|
|
2714
|
+
so that the child processes of the current one inherit it and skip the lookup.
|
|
2715
|
+
|
|
2716
|
+
Args:
|
|
2717
|
+
pwname (str): Password to pass on to the child processes.
|
|
2718
|
+
"""
|
|
2719
|
+
os.environ["{}_{}".format(*self.get_secret_name(self.get_dbnodes()[0])).upper()] = pwname
|
|
2720
|
+
|
|
2633
2721
|
def get_pgpassword(self):
|
|
2634
2722
|
"""Look up the password in the cached .pgpass credentials.
|
|
2635
2723
|
|
|
@@ -2646,16 +2734,20 @@ class PgDBI(PgLOG):
|
|
|
2646
2734
|
return pwname
|
|
2647
2735
|
|
|
2648
2736
|
def get_baopassword(self):
|
|
2649
|
-
"""Look up the password from OpenBao for the current
|
|
2737
|
+
"""Look up the password from OpenBao for the current db server node and login name.
|
|
2650
2738
|
|
|
2651
|
-
Loads OpenBao secrets
|
|
2739
|
+
Loads the OpenBao secrets of a node on first call (or when not cached), trying
|
|
2740
|
+
the fallback nodes of get_dbnodes() in turn.
|
|
2652
2741
|
|
|
2653
2742
|
Returns:
|
|
2654
2743
|
str | None: Password string, or None when not found in OpenBao.
|
|
2655
2744
|
"""
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2745
|
+
for dbnode in self.get_dbnodes():
|
|
2746
|
+
if dbnode not in self.DBBAOS: self.read_openbao(dbnode)
|
|
2747
|
+
pwname = self.DBBAOS[dbnode].get(self.PGDBI['LNNAME'])
|
|
2748
|
+
if pwname: return pwname
|
|
2749
|
+
|
|
2750
|
+
return None
|
|
2659
2751
|
|
|
2660
2752
|
def read_pgpass(self):
|
|
2661
2753
|
"""Read the .pgpass file and populate DBPASS with credentials.
|
|
@@ -2675,21 +2767,17 @@ class PgDBI(PgLOG):
|
|
|
2675
2767
|
except Exception:
|
|
2676
2768
|
pass
|
|
2677
2769
|
|
|
2678
|
-
def read_openbao(self):
|
|
2679
|
-
"""Read OpenBao secrets and populate DBBAOS with credentials
|
|
2770
|
+
def read_openbao(self, dbnode):
|
|
2771
|
+
"""Read OpenBao secrets and populate DBBAOS with the credentials of a db server node.
|
|
2680
2772
|
|
|
2681
2773
|
Uses the hvac client to fetch key-value secrets from the configured BAOURL.
|
|
2682
2774
|
Parses keys matching 'pass' patterns to extract database usernames and passwords.
|
|
2775
|
+
|
|
2776
|
+
Args:
|
|
2777
|
+
dbnode (str): Db server node naming the secret path, such as 'pgdb01'.
|
|
2683
2778
|
"""
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
url = 'https://bao.k8s.ucar.edu/'
|
|
2687
|
-
baopath = {
|
|
2688
|
-
'ivaddb': 'gdex/pgdb03',
|
|
2689
|
-
'ispddb': 'gdex/pgdb03',
|
|
2690
|
-
'default': 'gdex/pgdb01'
|
|
2691
|
-
}
|
|
2692
|
-
dbpath = baopath[dbname] if dbname in baopath else baopath['default']
|
|
2779
|
+
self.DBBAOS[dbnode] = {}
|
|
2780
|
+
dbpath = 'gdex/' + dbnode
|
|
2693
2781
|
client = hvac.Client(url=self.PGDBI.get('BAOURL'))
|
|
2694
2782
|
client.token = self.PGLOG.get('BAOTOKEN')
|
|
2695
2783
|
try:
|
|
@@ -2711,4 +2799,4 @@ class PgDBI(PgLOG):
|
|
|
2711
2799
|
baoname = 'metadata' if pre == 'meta' else pre
|
|
2712
2800
|
elif suf == 'word':
|
|
2713
2801
|
baoname = 'postgres'
|
|
2714
|
-
if baoname: self.DBBAOS[
|
|
2802
|
+
if baoname: self.DBBAOS[dbnode][baoname] = baos[key]
|
|
@@ -766,7 +766,9 @@ class PgFile(PgUtil, PgSIG):
|
|
|
766
766
|
"""Download a file from the object store to the local filesystem.
|
|
767
767
|
|
|
768
768
|
Changes to the target directory, downloads using isd_s3_cli, verifies size,
|
|
769
|
-
sets permissions, and renames if needed. Retries once on failure.
|
|
769
|
+
sets permissions, and renames if needed. Retries once on failure. A key that
|
|
770
|
+
is a prefix of multiple objects, such as a zarr store, is downloaded as a
|
|
771
|
+
directory by object_copy_local_directory().
|
|
770
772
|
|
|
771
773
|
Args:
|
|
772
774
|
tofile (str): Destination local file path.
|
|
@@ -783,6 +785,28 @@ class PgFile(PgUtil, PgSIG):
|
|
|
783
785
|
if not finfo:
|
|
784
786
|
if finfo != None: return ret
|
|
785
787
|
return self.lmsg(fromfile, "{}-{} to copy to {}".format(self.OHOST, self.PGLOG['MISSFILE'], tofile), logact)
|
|
788
|
+
if not finfo['isfile']: return self.object_copy_local_directory(tofile, fromfile, bucket, logact)
|
|
789
|
+
return self.object_get_local(tofile, fromfile, finfo['data_size'], bucket, logact)
|
|
790
|
+
|
|
791
|
+
# Download a single object of a known size to a local file
|
|
792
|
+
# tofile - target file name
|
|
793
|
+
# fromfile - source object key name
|
|
794
|
+
# fsize - size of the object, to verify the download against
|
|
795
|
+
# bucket - bucket name on Object store
|
|
796
|
+
def object_get_local(self, tofile, fromfile, fsize, bucket, logact = 0):
|
|
797
|
+
"""Download one object key to a local file and verify its size.
|
|
798
|
+
|
|
799
|
+
Args:
|
|
800
|
+
tofile (str): Destination local file path.
|
|
801
|
+
fromfile (str): Object key (source path in the bucket).
|
|
802
|
+
fsize (int): Expected size of the object.
|
|
803
|
+
bucket (str): Source bucket.
|
|
804
|
+
logact (int): Logging action flags; default 0.
|
|
805
|
+
|
|
806
|
+
Returns:
|
|
807
|
+
int: self.SUCCESS on success, self.FAILURE on error.
|
|
808
|
+
"""
|
|
809
|
+
ret = self.FAILURE
|
|
786
810
|
ocmd = self.OBJCTCMD
|
|
787
811
|
cmd = "{} go -k {} -b {}".format(ocmd, fromfile, bucket)
|
|
788
812
|
fromname = op.basename(fromfile)
|
|
@@ -797,7 +821,7 @@ class PgFile(PgUtil, PgSIG):
|
|
|
797
821
|
buf = self.pgsystem(cmd, logact, self.CMDBTH)
|
|
798
822
|
info = self.check_local_file(fromname, 143, logact|self.PFSIZE) # 1+2+4+8+128
|
|
799
823
|
if info:
|
|
800
|
-
if info['data_size'] ==
|
|
824
|
+
if info['data_size'] == fsize:
|
|
801
825
|
self.set_local_mode(fromfile, info['isfile'], 0, info['mode'], info['logname'], logact)
|
|
802
826
|
if toname == fromname or self.move_local_file(toname, fromname, logact):
|
|
803
827
|
ret = self.SUCCESS
|
|
@@ -811,6 +835,41 @@ class PgFile(PgUtil, PgSIG):
|
|
|
811
835
|
self.change_local_directory(odir, logact)
|
|
812
836
|
return ret
|
|
813
837
|
|
|
838
|
+
# Copy an object directory, a key prefix holding multiple objects, to local
|
|
839
|
+
# todir - target local directory name
|
|
840
|
+
# fromdir - source object key prefix
|
|
841
|
+
# bucket - bucket name on Object store
|
|
842
|
+
def object_copy_local_directory(self, todir, fromdir, bucket = None, logact = 0):
|
|
843
|
+
"""Download every object under a key prefix into a local directory.
|
|
844
|
+
|
|
845
|
+
The object store has no directories; a zarr store and the like is a set of
|
|
846
|
+
objects sharing a key prefix. Each object is downloaded individually and
|
|
847
|
+
keeps its position relative to the prefix under todir.
|
|
848
|
+
|
|
849
|
+
Args:
|
|
850
|
+
todir (str): Destination local directory path.
|
|
851
|
+
fromdir (str): Object key prefix (source path in the bucket).
|
|
852
|
+
bucket (str | None): Source bucket; defaults to PGLOG['OBJCTBKT'].
|
|
853
|
+
logact (int): Logging action flags; default 0.
|
|
854
|
+
|
|
855
|
+
Returns:
|
|
856
|
+
int: self.SUCCESS on success, self.FAILURE on error.
|
|
857
|
+
"""
|
|
858
|
+
if not bucket: bucket = self.PGLOG['OBJCTBKT']
|
|
859
|
+
ms = re.match(r'^(.+)/$', fromdir)
|
|
860
|
+
if ms: fromdir = ms.group(1)
|
|
861
|
+
flist = self.object_glob(fromdir, bucket, 0, logact)
|
|
862
|
+
if flist == self.FAILURE: return self.FAILURE
|
|
863
|
+
prefix = fromdir + '/'
|
|
864
|
+
keys = [key for key in flist if key.startswith(prefix)]
|
|
865
|
+
if not keys:
|
|
866
|
+
return self.lmsg(fromdir, "{}-{} to copy to {}".format(self.OHOST, self.PGLOG['MISSFILE'], todir), logact)
|
|
867
|
+
plen = len(prefix)
|
|
868
|
+
for key in keys:
|
|
869
|
+
tofile = "{}/{}".format(todir, key[plen:])
|
|
870
|
+
if not self.object_get_local(tofile, key, flist[key]['data_size'], bucket, logact): return self.FAILURE
|
|
871
|
+
return self.SUCCESS
|
|
872
|
+
|
|
814
873
|
# Copy a remote file to object
|
|
815
874
|
# tofile - target object file name
|
|
816
875
|
# fromfile - source remote file name
|
{rda_python_common-3.0.14 → rda_python_common-3.0.16/src/rda_python_common.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rda_python_common
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.16
|
|
4
4
|
Summary: RDA Python common library codes shared by other RDA python packages
|
|
5
5
|
Author-email: Zaihua Ji <zji@ucar.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/NCAR/rda-python-common
|
|
@@ -189,7 +189,7 @@ PgLOG.pglog("hello", PgLOG.LOGWRN)
|
|
|
189
189
|
python -c "import rda_python_common; print(rda_python_common.__version__)"
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
You should see the installed version (currently `3.0.
|
|
192
|
+
You should see the installed version (currently `3.0.16`). If the import
|
|
193
193
|
fails, double-check that the active Python environment is the one where you
|
|
194
194
|
ran `pip install`.
|
|
195
195
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/requires.txt
RENAMED
|
File without changes
|
{rda_python_common-3.0.14 → rda_python_common-3.0.16}/src/rda_python_common.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|