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 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