rcsb.utils.io 1.53__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.
- rcsb/__init__.py +1 -0
- rcsb/utils/__init__.py +1 -0
- rcsb/utils/io/CacheUtils.py +66 -0
- rcsb/utils/io/CryptUtils.py +193 -0
- rcsb/utils/io/ExecUtils.py +111 -0
- rcsb/utils/io/FastaUtil.py +364 -0
- rcsb/utils/io/FileLock.py +175 -0
- rcsb/utils/io/FileUtil.py +671 -0
- rcsb/utils/io/FtpUtil.py +339 -0
- rcsb/utils/io/GitUtil.py +167 -0
- rcsb/utils/io/HashableDict.py +57 -0
- rcsb/utils/io/IndexUtils.py +259 -0
- rcsb/utils/io/IoUtil.py +833 -0
- rcsb/utils/io/LogUtil.py +142 -0
- rcsb/utils/io/MarshalUtil.py +150 -0
- rcsb/utils/io/ProcessStatusUtil.py +159 -0
- rcsb/utils/io/SftpUtil.py +187 -0
- rcsb/utils/io/SingletonClass.py +37 -0
- rcsb/utils/io/SplitJoin.py +45 -0
- rcsb/utils/io/StashUtil.py +275 -0
- rcsb/utils/io/StashableBase.py +263 -0
- rcsb/utils/io/TimeUtil.py +98 -0
- rcsb/utils/io/UrlRequestUtil.py +355 -0
- rcsb/utils/io/__init__.py +0 -0
- rcsb/utils/io/decorators.py +145 -0
- rcsb_utils_io-1.53.dist-info/METADATA +162 -0
- rcsb_utils_io-1.53.dist-info/RECORD +29 -0
- rcsb_utils_io-1.53.dist-info/WHEEL +4 -0
- rcsb_utils_io-1.53.dist-info/licenses/LICENSE +12 -0
rcsb/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
|
rcsb/utils/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
##
|
|
2
|
+
# File: CacheUtils.py
|
|
3
|
+
# Date: 18-Jul-2019 jdw
|
|
4
|
+
#
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from collections import OrderedDict
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class CacheUtils:
|
|
14
|
+
"""LRU style cache.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, size=10, label="cache"):
|
|
18
|
+
"""LRU style cache
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
size (int, optional): maximum number of elements in the cache. Defaults to 10.
|
|
22
|
+
label (str, optional): A label an instance of the cache. Defaults to "cache".
|
|
23
|
+
"""
|
|
24
|
+
self.__size = size
|
|
25
|
+
self.__cache = OrderedDict()
|
|
26
|
+
self.__label = label
|
|
27
|
+
|
|
28
|
+
def get(self, key):
|
|
29
|
+
"""Return the cached value associated with the input key. The key:value
|
|
30
|
+
combination are moved to top of the cache.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
key (hashable): identifier for cached object
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
(any): Cached object associated with the input key or None
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
value = self.__cache.pop(key)
|
|
40
|
+
self.__cache[key] = value
|
|
41
|
+
return value
|
|
42
|
+
except KeyError:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
def set(self, key, value):
|
|
46
|
+
"""Store the input value in the cache. The cache contents of the cache
|
|
47
|
+
are adjusted if the size limit is exceeded.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
key (hashable): identifier for cached object
|
|
51
|
+
value (any): value to be cached
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
bool: True for success or false otherwise
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
try:
|
|
58
|
+
self.__cache.pop(key)
|
|
59
|
+
except KeyError:
|
|
60
|
+
if len(self.__cache) >= self.__size:
|
|
61
|
+
self.__cache.popitem(last=False)
|
|
62
|
+
self.__cache[key] = value
|
|
63
|
+
return True
|
|
64
|
+
except Exception as e:
|
|
65
|
+
logger.exception("Failing for %s with %s", self.__label, str(e))
|
|
66
|
+
return False
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
##
|
|
2
|
+
# File: CryptUtils.py
|
|
3
|
+
# Date: 12-Aug-2019 Jdw
|
|
4
|
+
#
|
|
5
|
+
# Updates:
|
|
6
|
+
#
|
|
7
|
+
##
|
|
8
|
+
"""
|
|
9
|
+
Utilities supporting encrypting and decrypting flat files and messages.
|
|
10
|
+
"""
|
|
11
|
+
__docformat__ = "google en"
|
|
12
|
+
__author__ = "John Westbrook"
|
|
13
|
+
__email__ = "john.westbrook@rcsb.org"
|
|
14
|
+
__license__ = "Apache 2.0"
|
|
15
|
+
|
|
16
|
+
import base64
|
|
17
|
+
import binascii
|
|
18
|
+
import hashlib
|
|
19
|
+
import logging
|
|
20
|
+
|
|
21
|
+
from nacl.encoding import HexEncoder, RawEncoder
|
|
22
|
+
from nacl.secret import SecretBox
|
|
23
|
+
from nacl.utils import random
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class CryptUtils(object):
|
|
29
|
+
"""Utility class for encrypting and decrypting data files and messages
|
|
30
|
+
|
|
31
|
+
** This class does not yet support any stream operations so resources must be
|
|
32
|
+
available to load data sets in memory -
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args, **kwargs):
|
|
37
|
+
_ = args
|
|
38
|
+
_ = kwargs
|
|
39
|
+
|
|
40
|
+
def newKey(self):
|
|
41
|
+
"""Generate a new encryption key.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
(str): encryption key
|
|
45
|
+
"""
|
|
46
|
+
key = random(SecretBox.KEY_SIZE)
|
|
47
|
+
return binascii.hexlify(key).decode("utf-8")
|
|
48
|
+
|
|
49
|
+
def encryptMessage(self, msg, hexKey):
|
|
50
|
+
"""Encrypt the input message.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
msg (str): input message
|
|
54
|
+
hexKey (str): encryption key
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
(str): encrypted message text
|
|
58
|
+
"""
|
|
59
|
+
txt = None
|
|
60
|
+
try:
|
|
61
|
+
box = SecretBox(hexKey.encode("utf-8"), encoder=HexEncoder)
|
|
62
|
+
bMsg = msg.encode("utf-8")
|
|
63
|
+
encMsg = box.encrypt(bMsg, encoder=RawEncoder)
|
|
64
|
+
txt = base64.b64encode(encMsg).decode("ascii")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.exception("Failing with %s", str(e))
|
|
67
|
+
|
|
68
|
+
return txt
|
|
69
|
+
|
|
70
|
+
def decryptMessage(self, msg, hexKey):
|
|
71
|
+
"""Decrypt the input message.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
msg (str): input message
|
|
75
|
+
hexKey (str): encryption key
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
(str): decrypted message text
|
|
79
|
+
"""
|
|
80
|
+
txt = None
|
|
81
|
+
try:
|
|
82
|
+
box = SecretBox(hexKey.encode("utf-8"), encoder=HexEncoder)
|
|
83
|
+
bMsg = base64.b64decode(msg)
|
|
84
|
+
dcrMsg = box.decrypt(bMsg)
|
|
85
|
+
logger.debug("type %r text %r", type(dcrMsg), dcrMsg)
|
|
86
|
+
txt = dcrMsg.decode("utf-8")
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.exception("Failing with %s", str(e))
|
|
89
|
+
|
|
90
|
+
return txt
|
|
91
|
+
|
|
92
|
+
def encryptFile(self, inpPath, outPath, hexKey, chunkSize=65536):
|
|
93
|
+
"""Encrypt the data in the input file store this in the output file.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
inpPath (str): input file path
|
|
97
|
+
outPath (str): output file path (encrypted)
|
|
98
|
+
hexKey (str): encryption key
|
|
99
|
+
chunkSize (int, optional): the size of incremental copy operations. Defaults to 65536.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
(bool): True for success or False otherwise
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
box = SecretBox(hexKey.encode("utf-8"), encoder=HexEncoder)
|
|
106
|
+
tL = []
|
|
107
|
+
with open(inpPath, "rb") as ifh:
|
|
108
|
+
while True:
|
|
109
|
+
chunk = ifh.read(chunkSize)
|
|
110
|
+
if not chunk:
|
|
111
|
+
break
|
|
112
|
+
tL.append(chunk)
|
|
113
|
+
#
|
|
114
|
+
txt = b"".join(tL)
|
|
115
|
+
logger.debug("Read %s size %d", inpPath, len(txt))
|
|
116
|
+
enctxt = box.encrypt(txt, encoder=RawEncoder)
|
|
117
|
+
tL = [enctxt[i : i + chunkSize] for i in range(0, len(enctxt), chunkSize)]
|
|
118
|
+
logger.debug("Chunks %d size %d", len(tL), len(enctxt))
|
|
119
|
+
#
|
|
120
|
+
with open(outPath, "wb") as ofh:
|
|
121
|
+
for tV in tL:
|
|
122
|
+
ofh.write(tV)
|
|
123
|
+
return True
|
|
124
|
+
except Exception as e:
|
|
125
|
+
logger.exception("Failing with %r", str(e))
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
def decryptFile(self, inpPath, outPath, hexKey, chunkSize=65536):
|
|
129
|
+
"""Decrypt the data in the input file store the result in the output file.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
inpPath ([type]): input file path (encrypted)
|
|
133
|
+
outPath ([type]): output file path
|
|
134
|
+
hexKey ([type]): encryption key
|
|
135
|
+
chunkSize (int, optional): the size of incremental copy operations. Defaults to 65536.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
(bool): True for success or False otherwise
|
|
139
|
+
"""
|
|
140
|
+
try:
|
|
141
|
+
box = SecretBox(hexKey.encode("utf-8"), encoder=HexEncoder)
|
|
142
|
+
tL = []
|
|
143
|
+
with open(inpPath, "rb") as ifh:
|
|
144
|
+
while True:
|
|
145
|
+
chunk = ifh.read(chunkSize)
|
|
146
|
+
if not chunk:
|
|
147
|
+
break
|
|
148
|
+
tL.append(chunk)
|
|
149
|
+
#
|
|
150
|
+
enctxt = b"".join(tL)
|
|
151
|
+
#
|
|
152
|
+
txt = box.decrypt(enctxt)
|
|
153
|
+
tL = [txt[i : i + chunkSize] for i in range(0, len(txt), chunkSize)]
|
|
154
|
+
logger.debug("Chunks %d size %d", len(tL), len(txt))
|
|
155
|
+
#
|
|
156
|
+
with open(outPath, "wb") as ofh:
|
|
157
|
+
for tV in tL:
|
|
158
|
+
ofh.write(tV)
|
|
159
|
+
return True
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logger.exception("Failing with %r", str(e))
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
def getFileHash(self, filePath, hashType="SHA1", blockSize=65536):
|
|
165
|
+
"""Return the hash (hashType) for the input file.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
filePath (str): for input file path
|
|
169
|
+
hashType (str, optional): one of MD5, SHA1, or SHA256. Defaults to "SHA1".
|
|
170
|
+
blockSize (int, optional): the size of incremental read operations. Defaults to 65536.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
(dict): {"hashDigest": xxxx , "hashType": 'SHA1|MD5|SHA256'}
|
|
174
|
+
"""
|
|
175
|
+
rD = {}
|
|
176
|
+
hashObj = None
|
|
177
|
+
if hashType not in ["MD5", "SHA1", "SHA256"]:
|
|
178
|
+
return rD
|
|
179
|
+
try:
|
|
180
|
+
if hashType == "SHA1":
|
|
181
|
+
hashObj = hashlib.sha1()
|
|
182
|
+
elif hashType == "SHA256":
|
|
183
|
+
hashObj = hashlib.sha256()
|
|
184
|
+
elif hashType == "MD5":
|
|
185
|
+
hashObj = hashlib.md5()
|
|
186
|
+
|
|
187
|
+
with open(filePath, "rb") as ifh:
|
|
188
|
+
for block in iter(lambda: ifh.read(blockSize), b""):
|
|
189
|
+
hashObj.update(block)
|
|
190
|
+
rD = {"hashDigest": hashObj.hexdigest(), "hashType": hashType}
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.exception("Failing with file %s %r", filePath, str(e))
|
|
193
|
+
return rD
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
##
|
|
2
|
+
# File: ExeceUtils.py
|
|
3
|
+
# Date: 24-Jan-2020 jdw
|
|
4
|
+
#
|
|
5
|
+
##
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExecUtils(object):
|
|
15
|
+
"""Wrapper for subprocess execution."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
"""Wrapper for subprocess execution"""
|
|
19
|
+
|
|
20
|
+
def run(self, execPath, execArgList=None, outPath=None, outAppend=False, timeOut=None, inpPath=None, suppressStderr=False):
|
|
21
|
+
"""Execute the input program as a blocking subprocess with optional timeout.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
execPath (str): path to executable program or script
|
|
25
|
+
execArgList (list, optional): argument list. Defaults to None.
|
|
26
|
+
outPath (str, optional): redirect stdout and stderr to this file handle. Defaults to None.
|
|
27
|
+
inpPath (str, optional): redirect stdin to this file handle. Defaults to None.
|
|
28
|
+
outAppend (bool, optional): append output. Defaults to False.
|
|
29
|
+
timeOut (float, optional): timeout (seconds). Defaults to None.
|
|
30
|
+
suppressStderr (bool, optional): suppress stderr output (default: combined with stdout)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
bool: true for sucess or False otherwise
|
|
35
|
+
"""
|
|
36
|
+
retCode = False
|
|
37
|
+
subProcResult = None
|
|
38
|
+
kwD = {}
|
|
39
|
+
if suppressStderr:
|
|
40
|
+
myStderr = subprocess.DEVNULL
|
|
41
|
+
else:
|
|
42
|
+
myStderr = subprocess.STDOUT
|
|
43
|
+
try:
|
|
44
|
+
if not os.path.isfile(execPath) and os.access(execPath, os.X_OK):
|
|
45
|
+
return retCode
|
|
46
|
+
if sys.version_info[0] > 2 and timeOut:
|
|
47
|
+
kwD = {"timeout": timeOut}
|
|
48
|
+
cmdL = [execPath]
|
|
49
|
+
if execArgList:
|
|
50
|
+
cmdL.extend(execArgList)
|
|
51
|
+
if outPath and inpPath:
|
|
52
|
+
myMode = "a" if outAppend else "w"
|
|
53
|
+
with open(outPath, myMode) as ofh, open(inpPath, "r") as ifh:
|
|
54
|
+
subProcResult = subprocess.call(cmdL, stdout=ofh, stdin=ifh, stderr=myStderr, **kwD)
|
|
55
|
+
elif outPath:
|
|
56
|
+
myMode = "a" if outAppend else "w"
|
|
57
|
+
with open(outPath, myMode) as ofh:
|
|
58
|
+
subProcResult = subprocess.call(cmdL, stdout=ofh, stderr=myStderr, **kwD)
|
|
59
|
+
else:
|
|
60
|
+
subProcResult = subprocess.call(cmdL, **kwD)
|
|
61
|
+
retCode = not subProcResult
|
|
62
|
+
except Exception as e:
|
|
63
|
+
logger.exception("Failing execution of %s (%s) with %s", execPath, execArgList, str(e))
|
|
64
|
+
#
|
|
65
|
+
if subProcResult != 0:
|
|
66
|
+
logger.error("return code is %r", subProcResult)
|
|
67
|
+
return retCode
|
|
68
|
+
|
|
69
|
+
def runShell(self, script, outPath=None, outAppend=False, timeOut=None, inpPath=None, suppressStderr=False):
|
|
70
|
+
"""Execute the input program as a blocking subprocess with optional timeout.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
script (str): script
|
|
74
|
+
outPath (str, optional): redirect stdout and stderr to this file handle. Defaults to None.
|
|
75
|
+
inpPath (str, optional): redirect stdin to this file handle. Defaults to None.
|
|
76
|
+
outAppend (bool, optional): append output. Defaults to False.
|
|
77
|
+
timeOut (float, optional): timeout (seconds). Defaults to None.
|
|
78
|
+
suppressStderr (bool, optional): suppress stderr output (default: combined with stdout)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
bool: true for sucess or False otherwise
|
|
83
|
+
"""
|
|
84
|
+
retCode = 0
|
|
85
|
+
kwD = {}
|
|
86
|
+
subProcResult = None
|
|
87
|
+
if suppressStderr:
|
|
88
|
+
myStderr = subprocess.DEVNULL
|
|
89
|
+
else:
|
|
90
|
+
myStderr = subprocess.STDOUT
|
|
91
|
+
try:
|
|
92
|
+
if sys.version_info[0] > 2 and timeOut:
|
|
93
|
+
kwD = {"timeout": timeOut}
|
|
94
|
+
#
|
|
95
|
+
if outPath and inpPath:
|
|
96
|
+
myMode = "a" if outAppend else "w"
|
|
97
|
+
with open(outPath, myMode) as ofh, open(inpPath, "r") as ifh:
|
|
98
|
+
subProcResult = subprocess.run(script, stdout=ofh, stdin=ifh, stderr=myStderr, shell=True, check=False, **kwD)
|
|
99
|
+
elif outPath:
|
|
100
|
+
myMode = "a" if outAppend else "w"
|
|
101
|
+
with open(outPath, myMode) as ofh:
|
|
102
|
+
subProcResult = subprocess.run(script, stdout=ofh, stderr=myStderr, shell=True, check=False, **kwD)
|
|
103
|
+
else:
|
|
104
|
+
subProcResult = subprocess.run(script, shell=True, check=False, **kwD)
|
|
105
|
+
retCode = not subProcResult.returncode
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.exception("Failing execution of %r with %s", subProcResult, str(e))
|
|
108
|
+
#
|
|
109
|
+
if subProcResult and subProcResult.returncode != 0:
|
|
110
|
+
logger.warning("return code is %r", subProcResult.returncode)
|
|
111
|
+
return retCode
|