rda-python-common 1.0.6__tar.gz → 1.0.8__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.

Potentially problematic release.


This version of rda-python-common might be problematic. Click here for more details.

Files changed (21) hide show
  1. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/PKG-INFO +1 -1
  2. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/pyproject.toml +1 -1
  3. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgDBI.py +2 -0
  4. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgFile.py +51 -0
  5. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common.egg-info/PKG-INFO +1 -1
  6. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common.egg-info/SOURCES.txt +0 -2
  7. rda_python_common-1.0.6/src/rda_python_common/PgGLBS.py +0 -200
  8. rda_python_common-1.0.6/src/rda_python_common/PgPGS.py +0 -153
  9. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/LICENSE +0 -0
  10. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/README.md +0 -0
  11. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/setup.cfg +0 -0
  12. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgCMD.py +0 -0
  13. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgLOG.py +0 -0
  14. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgLock.py +0 -0
  15. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgOPT.py +0 -0
  16. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgSIG.py +0 -0
  17. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgSplit.py +0 -0
  18. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/PgUtil.py +0 -0
  19. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common/__init__.py +0 -0
  20. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common.egg-info/dependency_links.txt +0 -0
  21. {rda_python_common-1.0.6 → rda_python_common-1.0.8}/src/rda_python_common.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rda_python_common
3
- Version: 1.0.6
3
+ Version: 1.0.8
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rda_python_common"
7
- version = "1.0.6"
7
+ version = "1.0.8"
8
8
 
9
9
  authors = [
10
10
  { name="Zaihua Ji", email="zji@ucar.edu" },
@@ -2226,6 +2226,8 @@ def get_pgpass_password():
2226
2226
  pwname = DBPASS.get((PGDBI['DBSHOST'], dbport, PGDBI['DBNAME'], PGDBI['LNNAME']))
2227
2227
  if not pwname: pwname = DBPASS.get((PGDBI['DBHOST'], dbport, PGDBI['DBNAME'], PGDBI['LNNAME']))
2228
2228
 
2229
+ return pwname
2230
+
2229
2231
  #
2230
2232
  # Reads the .pgpass file and returns a dictionary of credentials.
2231
2233
  #
@@ -118,6 +118,8 @@ ENDPOINTS = {
118
118
  'rda-quasar-drdata' : "NCAR RDA Quasar DRDATA"
119
119
  }
120
120
 
121
+ BFILES = {} # cache backup file names and dates for each bid
122
+
121
123
  #
122
124
  # reset the up limit for a specified error type
123
125
  #
@@ -3012,3 +3014,52 @@ def check_storage_dflags(dflags, dscheck = None, logact = 0):
3012
3014
  if cidx: PgDBI.pgexec("UPDATE dscheck SET dflags = '' WHERE cindex = {}".format(cidx), logact)
3013
3015
 
3014
3016
  return msgary
3017
+
3018
+ #
3019
+ # check a RDA file is backed up or not for given file record;
3020
+ # clear the cached bfile records if frec is None.
3021
+ # return 0 if not yet, 1 if backed up, or -1 if backed up but modified
3022
+ #
3023
+ def file_backup_status(frec, chgdays = 1, logact = 0):
3024
+
3025
+ if frec is None:
3026
+ BFILES.clear()
3027
+ return 0
3028
+
3029
+ bid = frec['bid']
3030
+ if not bid: return 0
3031
+
3032
+ fields = 'bfile, dsid, date_modified'
3033
+ if chgdays > 0: fields += ', note'
3034
+ if bid not in BFILES: BFILES[bid] = PgDBI.pgget('bfile', fields, 'bid = {}'.format(bid), logact)
3035
+ brec = BFILES[bid]
3036
+ if not brec: return 0
3037
+
3038
+ if 'sfile' in frec:
3039
+ fname = frec['sfile']
3040
+ ftype = 'Saved'
3041
+ else:
3042
+ fname = frec['wfile']
3043
+ ftype = 'Web'
3044
+ ret = 1
3045
+ fdate = frec['date_modified']
3046
+ bdate = brec['date_modified']
3047
+ if chgdays > 0 and PgUtil.diffdate(fdate, bdate) >= chgdays:
3048
+ ret = -1
3049
+ if brec['note']:
3050
+ mp = r'{}<:>{}<:>(\d+)<:>(\w+)<:>'.format(fname, frec['type'])
3051
+ ms = re.search(mp, brec['note'])
3052
+ if ms:
3053
+ fsize = int(ms.group(1))
3054
+ cksum = ms.group(2)
3055
+ if cksum and cksum == frec['checksum'] or not cksum and fsize == frec['data_size']:
3056
+ ret = 1
3057
+
3058
+ if logact:
3059
+ if ret == 1:
3060
+ msg = "{}-{}: {} file backed up to /{}/{} by {}".format(frec['dsid'], fname, ftype, brec['dsid'], brec['bfile'], bdate)
3061
+ else:
3062
+ msg = "{}-{}: {} file changed on {}".format(frec['dsid'], fname, ftype, fdate)
3063
+ PgLOG.pglog(msg, logact)
3064
+
3065
+ return ret
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rda_python_common
3
- Version: 1.0.6
3
+ Version: 1.0.8
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
@@ -4,11 +4,9 @@ pyproject.toml
4
4
  src/rda_python_common/PgCMD.py
5
5
  src/rda_python_common/PgDBI.py
6
6
  src/rda_python_common/PgFile.py
7
- src/rda_python_common/PgGLBS.py
8
7
  src/rda_python_common/PgLOG.py
9
8
  src/rda_python_common/PgLock.py
10
9
  src/rda_python_common/PgOPT.py
11
- src/rda_python_common/PgPGS.py
12
10
  src/rda_python_common/PgSIG.py
13
11
  src/rda_python_common/PgSplit.py
14
12
  src/rda_python_common/PgUtil.py
@@ -1,200 +0,0 @@
1
- #
2
- ###############################################################################
3
- #
4
- # Title : PgGLBS.py
5
- # Author : Thomas Cram, tcram@ucar.edu
6
- # Date : 12/10/2014
7
- # 10/10/2020, Zaihua Ji, zji@ucar.edu:
8
- # converted from perl package to python module
9
- # 2025-01-10, Zaihua Ji, zji@ucar.edu:
10
- # transferred to package rda_python_common from
11
- # https://github.com/NCAR/rda-shared-libraries.git
12
- # Purpose : python library module for Globus functions and utilities
13
- #
14
- # Github : https://github.com/NCAR/rda-python-common.git
15
- #
16
- ###############################################################################
17
- #
18
- import os
19
- import re
20
- from . import PgLOG
21
- from . import PgUtil
22
- from MyGlobus import MyGlobus, MyEndpoints, GLOBUS_REQUEST_DOMAIN
23
- from . import PgDBI
24
-
25
- try:
26
- from urllib.parse import urlencode
27
- except:
28
- from urllib import urlencode
29
-
30
- BFILES = {} # cache backup file names and dates for each bid
31
-
32
- #
33
- # Remove the Globus share rule ID for a dsrqst share
34
- #
35
- def remove_globus_rid(ridx, dsid):
36
-
37
- if not ridx: return PgLOG.pglog("[remove_globus_rid] Request index is not defined", PgLOG.LOGWRN)
38
- if not dsid: return PgLOG.pglog("[remove_globus_rid] Dataset ID is not defined", PgLOG.LOGWRN)
39
-
40
- cmd = "dsglobus"
41
- args = "'-rp -ri {}'".format(ridx)
42
- action = "RP"
43
- host = "PBS"
44
- workdir = "/glade/u/home/tcram"
45
- opts = "'-l walltime=15:00'"
46
- spec = "tcram"
47
- check_cmd = "dscheck ac -cm {} -av {} -ds {} -an {} -hn {} -wd {} -sn {} -qs {} -md".format(cmd, args, dsid, action, host, workdir, spec, opts)
48
-
49
- PgLOG.pgsystem(check_cmd)
50
-
51
- #
52
- # Submit a Globus transfer of the request output on behalf of the user
53
- #
54
- def submit_globus_transfer(ridx):
55
-
56
- # call dsglobus to submit transfer
57
- cmd = "dsglobus -st -ri {}".format(ridx)
58
- return PgLOG.pgsystem(cmd, PgLOG.LOGWRN, 16)
59
-
60
- #
61
- # check a RDA file is backed up or not for given file record;
62
- # clear the cached bfile records if frec is None.
63
- # return 0 if not yet, 1 if backed up, or -1 if backed up but modified
64
- #
65
- def file_backup_status(frec, chgdays = 1, logact = 0):
66
-
67
- if frec is None:
68
- BFILES.clear()
69
- return 0
70
-
71
- bid = frec['bid']
72
- if not bid: return 0
73
-
74
- fields = 'bfile, dsid, date_modified'
75
- if chgdays > 0: fields += ', note'
76
- if bid not in BFILES: BFILES[bid] = PgDBI.pgget('bfile', fields, 'bid = {}'.format(bid), logact)
77
- brec = BFILES[bid]
78
- if not brec: return 0
79
-
80
- if 'sfile' in frec:
81
- fname = frec['sfile']
82
- ftype = 'Saved'
83
- else:
84
- fname = frec['wfile']
85
- ftype = 'Web'
86
- ret = 1
87
- fdate = frec['date_modified']
88
- bdate = brec['date_modified']
89
- if chgdays > 0 and PgUtil.diffdate(fdate, bdate) >= chgdays:
90
- ret = -1
91
- if brec['note']:
92
- mp = r'{}<:>{}<:>(\d+)<:>(\w+)<:>'.format(fname, frec['type'])
93
- ms = re.search(mp, brec['note'])
94
- if ms:
95
- fsize = int(ms.group(1))
96
- cksum = ms.group(2)
97
- if cksum and cksum == frec['checksum'] or not cksum and fsize == frec['data_size']:
98
- ret = 1
99
-
100
- if logact:
101
- if ret == 1:
102
- msg = "{}-{}: {} file backed up to /{}/{} by {}".format(frec['dsid'], fname, ftype, brec['dsid'], brec['bfile'], bdate)
103
- else:
104
- msg = "{}-{}: {} file changed on {}".format(frec['dsid'], fname, ftype, fdate)
105
- PgLOG.pglog(msg, logact)
106
-
107
- return ret
108
-
109
- #=========================================================================================
110
- def get_request_file_url(rfile, rpath=None, logact=0):
111
- """ Returns the URL for a request file
112
- Input arguments:
113
- rfile = request file
114
- dsid = dataset ID (dsnnn.n)
115
- rpath = path to request file, relatvie to RDA data base path (e.g. '/dsrqst/<rqstid>/'
116
- """
117
- domain = GLOBUS_REQUEST_DOMAIN
118
-
119
- if not rpath:
120
- try:
121
- cond = "wfile='{}'".format(rfile)
122
- wfrqst = PgDBI.pgget('wfrqst', 'rindex', cond, logact)
123
- except:
124
- msg = "[get_request_file_url] Problem getting rindex for request file {}".format(rfile)
125
- PgLOG.pglog(msg)
126
- if not wfrqst:
127
- raise TypeError("Request file {} not found in table 'wfrqst'".format(rfile))
128
- rpath = get_request_path(wfrqst['rindex'], logact=0)
129
-
130
- if (rpath.find('/',0,1) != -1):
131
- rpath = rpath.replace('/','',1)
132
-
133
- url = os.path.join(domain, rpath, rfile)
134
- return url
135
-
136
- #=========================================================================================
137
- def get_request_path(rindex, logact=0):
138
- """ Returns relative path to request file
139
- Example: '/dsrqst/<rqstid>/'
140
- """
141
- try:
142
- fields = 'rqstid, location'
143
- cond = 'rindex={}'.format(rindex)
144
- rqst_info = PgDBI.pgget('dsrqst', fields, cond, logact)
145
- except:
146
- msg = "[get_request_path] Problem getting info for request index {}".format(rindex)
147
- PgLOG.pglog(msg)
148
- if not rqst_info:
149
- raise TypeError("Request index {} not found in RDADB".format(rindex))
150
-
151
- if rqst_info['location']:
152
- base_path = MyGlobus['data_request_endpoint_base']
153
- loc = rqst_info['location']
154
- loc = loc.rstrip("/")
155
- if (loc.find(base_path) != -1):
156
- path_len = len(base_path)
157
- path = "/{0}/".format(loc[path_len:])
158
- else:
159
- path = "/"
160
- else:
161
- path = "/dsrqst/{0}/".format(rqst_info['rqstid'])
162
-
163
- return path
164
-
165
- #=========================================================================================
166
- def get_guest_collection_url(dsid=None, locflag=None, rindex=None, logact=0):
167
- """ Returns the URL for the guest collection endpoint in the Globus File Manager.
168
- Either dataset ID (dsid) or request index (rindex) is required. If neither
169
- dsid or rindex are provided, the default URL returned is the top level URL for
170
- the 'NCAR RDA Dataset Archive' guest collection.
171
-
172
- Optional argument locflag = location flag of dataset ('G' = glade, 'O' = stratus,
173
- 'B' = both glade and stratus, 'C' = CGD data under /glade/campaign/cgd/cesm)
174
- """
175
-
176
- if rindex:
177
- origin_id = MyEndpoints['rda#data_request']
178
- origin_path = get_request_path(rindex, logact=logact)
179
- elif dsid:
180
- if not locflag:
181
- cond = "dsid='{}'".format(dsid)
182
- pgloc = PgDBI.pgget('dataset', 'locflag', cond, logact)
183
- locflag = pgloc['locflag']
184
- if locflag == 'C':
185
- origin_id = MyEndpoints['rda-cgd']
186
- origin_path = "/"
187
- elif locflag == 'O' or locflag == 'B':
188
- origin_id = MyEndpoints['rda-stratus']
189
- origin_path = "/{}/".format(dsid)
190
- else:
191
- origin_id = MyEndpoints['rda#datashare']
192
- origin_path = "/{}/".format(dsid)
193
- else:
194
- origin_id = MyEndpoints['rda#datashare']
195
- origin_path = "/"
196
-
197
- params = {'origin_id': origin_id, 'origin_path': origin_path}
198
- url = '{0}?{1}'.format(MyGlobus['globus_share_url'], urlencode(params))
199
-
200
- return url
@@ -1,153 +0,0 @@
1
- #
2
- ###############################################################################
3
- #
4
- # Title : PgPGS.py -- PostgreSQL Interface for CDP DataBase Per psql
5
- # Author : Zaihua Ji, zji@ucar.edu
6
- # Date : 08/31/2020
7
- # 2025-01-10 transferred to package rda_python_common from
8
- # https://github.com/NCAR/rda-shared-libraries.git
9
- # Purpose : python library module to handle sql scripts to retrieve info
10
- # from cdp database per psql
11
- #
12
- # Github : https://github.com/NCAR/rda-python-common.git
13
- #
14
- ###############################################################################
15
- #
16
- import os
17
- import re
18
- from . import PgLOG
19
-
20
- PGPGS = {}
21
- PGPGS["PGSSERV"] = PgLOG.get_environment("PGSSERV", '-h vetsdbprod -p 5432 -U acadmin access_control');
22
- PGPGS["SQLPATH"] = PgLOG.get_environment("SQLPATH", PgLOG.PGLOG['DSSHOME']+ "/dssdb/sql");
23
-
24
- #
25
- # local function: create sql file
26
- #
27
- def pgs_sql_file(tablenames, fields, condition = None):
28
-
29
- sqlfile = "{}/pgs{}.sql".format(PGPGS['SQLPATH'], os.getpid())
30
-
31
- sqlstr = "SELECT {}\nFROM {}".format(fields, tablenames)
32
- if condition:
33
- if re.match(r'^\s*(ORDER|GROUP|HAVING)\s', condition, re.I):
34
- sqlstr += "\n{}".format(condition)
35
- else:
36
- sqlstr += "\nWHERE {}".format(condition)
37
- sqlstr += ";\n"
38
- try:
39
- SQL = open(sqlfile, 'w')
40
- SQL.write(sqlstr)
41
- SQL.close()
42
- except Exception as e:
43
- PgLOG.pglog("Error Open '{}': {}".format(sqlfile, str(e)), PgLOG.LGWNEX)
44
-
45
- if PgLOG.PGLOG['DBGLEVEL']: PgLOG.pgdbg(1000, sqlstr)
46
-
47
- return sqlfile
48
-
49
- #
50
- # tablenames: comma deliminated string of table names
51
- # fields: fieldnames for query pgscle database,
52
- # condition: querry conditions for where clause)
53
- # Return: one record from tablename, a hash reference with keys as field names
54
- # and values as field values upon success, FAILURE otherwise
55
- #
56
- def pgsget(tablenames, fields, condition = None, logact = 0):
57
-
58
- sqlfile = pgs_sql_file(tablenames, fields, condition)
59
- sqlout = PgLOG.pgsystem("psql {} < {}".format(PGPGS['PGSSERV'], sqlfile), logact, 273+1024) # 1+16+256
60
-
61
- colcnt = 0
62
- record = {}
63
- if sqlout:
64
- for line in re.split(r'\n', sqlout):
65
- vals = re.split(r'\s*\|\s+', line)
66
- if colcnt: # gather data
67
- record = dict(zip(fields, vals))
68
- break
69
- else: # gather field names
70
- flds = vals
71
- colcnt = len(flds)
72
- elif PgLOG.PGLOG['SYSERR']: # error happens
73
- PgLOG.pglog(PgLOG.PGLOG['SYSERR'], logact|PgLOG.ERRLOG)
74
-
75
- if PgLOG.PGLOG['DBGLEVEL']:
76
- if record:
77
- PgLOG.pgdbg(1000, "pgsget: 1 record retrieved from {}:\n{}".format(tablenames, str(record)))
78
- else:
79
- PgLOG.pgdbg(1000, "pgsget: 0 record retrieved from " + tablenames)
80
-
81
- os.remove(sqlfile)
82
-
83
- return record
84
-
85
- #
86
- # tablenames: comma deliminated string of tables
87
- # fields: fieldnames for query pgscle database,
88
- # condition: querry conditions for where clause)
89
- # Return: mutiple records from tablenames, a dict with field names as keys and lists
90
- # of retrieved values. All arrays are same size. FAILURE if not success
91
- #
92
- def pgsmget(tablenames, fields, condition = None, logact = 0):
93
-
94
- sqlfile = pgs_sql_file(tablenames, fields, condition)
95
- sqlout = PgLOG.pgsystem("psql {} < {}".format(PGPGS['PGSSERV'], sqlfile), logact, 273+1024) # 1+16+256
96
-
97
- rowcnt = colcnt = 0
98
- records = {}
99
- vals = []
100
- if sqlout:
101
- for line in re.split(r'\n', sqlout):
102
- row = re.split(r'\s*\|\s+', line)
103
- if colcnt: # gather data
104
- vals.append(row)
105
- rowcnt += 1
106
- else: # gather field names
107
- flds = row
108
- colcnt = len(flds)
109
- if rowcnt > 0:
110
- records = dict(zip(flds, list(zip(*vals))))
111
- elif PgLOG.PGLOG['SYSERR']: # error happens
112
- PgLOG.pglog(PgLOG.PGLOG['SYSERR'], logact|PgLOG.ERRLOG)
113
-
114
- if PgLOG.PGLOG['DBGLEVEL']:
115
- PgLOG.pgdbg(1000, "pgsmget: {} record(s) retrieved from {}".format(rowcnt, tablenames))
116
-
117
- os.remove(sqlfile) # remove sqlfile when successful
118
-
119
- return records
120
-
121
- #
122
- # email: cdp user email address,
123
- # userid: cdp user ID,
124
- # username: cdp user name
125
- # Return: one record from CDP PostGreSQL database; PGLOG.FAILURE otherwise
126
- #
127
- def get_cdp_user(email, userid = 0, username = None, logact = 0):
128
-
129
- if userid:
130
- condition = "id = {}".format(userid)
131
- elif email:
132
- condition = "email = '{}'".format(email)
133
- elif username:
134
- condition = "username = '{}'".format(username)
135
- else:
136
- return PgLOG.FAILURE
137
-
138
- fields = ("id as cdpid, firstname as fstname, middlename as midinit, " +
139
- "lastname as lstname, email, username as cdpname, " +
140
- "organization as org_name, organization_type as org_type, country")
141
- return pgsget('users', fields, condition, logact)
142
-
143
- #
144
- # name: field name
145
- # value: field value
146
- # Return: converted value from upcases to lower case
147
- #
148
- def convert_pgs_case(name, value):
149
-
150
- if name == "username" or name == "email":
151
- return value.lower()
152
- else:
153
- return value # no change