workbench 0.8.198__py3-none-any.whl → 0.8.203__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.
- workbench/algorithms/dataframe/proximity.py +11 -4
- workbench/api/__init__.py +2 -1
- workbench/api/df_store.py +17 -108
- workbench/api/feature_set.py +48 -11
- workbench/api/model.py +1 -1
- workbench/api/parameter_store.py +3 -52
- workbench/core/artifacts/__init__.py +11 -2
- workbench/core/artifacts/artifact.py +5 -5
- workbench/core/artifacts/df_store_core.py +114 -0
- workbench/core/artifacts/endpoint_core.py +261 -78
- workbench/core/artifacts/feature_set_core.py +69 -1
- workbench/core/artifacts/model_core.py +48 -14
- workbench/core/artifacts/parameter_store_core.py +98 -0
- workbench/core/transforms/features_to_model/features_to_model.py +50 -33
- workbench/core/transforms/pandas_transforms/pandas_to_features.py +11 -2
- workbench/core/views/view.py +2 -2
- workbench/model_scripts/chemprop/chemprop.template +933 -0
- workbench/model_scripts/chemprop/generated_model_script.py +933 -0
- workbench/model_scripts/chemprop/requirements.txt +11 -0
- workbench/model_scripts/custom_models/chem_info/fingerprints.py +134 -0
- workbench/model_scripts/custom_models/chem_info/morgan_fingerprints.py +1 -1
- workbench/model_scripts/custom_models/proximity/proximity.py +11 -4
- workbench/model_scripts/custom_models/uq_models/ensemble_xgb.template +11 -5
- workbench/model_scripts/custom_models/uq_models/meta_uq.template +11 -5
- workbench/model_scripts/custom_models/uq_models/ngboost.template +11 -5
- workbench/model_scripts/custom_models/uq_models/proximity.py +11 -4
- workbench/model_scripts/ensemble_xgb/ensemble_xgb.template +11 -5
- workbench/model_scripts/pytorch_model/generated_model_script.py +365 -173
- workbench/model_scripts/pytorch_model/pytorch.template +362 -170
- workbench/model_scripts/scikit_learn/generated_model_script.py +302 -0
- workbench/model_scripts/script_generation.py +10 -7
- workbench/model_scripts/uq_models/generated_model_script.py +43 -27
- workbench/model_scripts/uq_models/mapie.template +40 -24
- workbench/model_scripts/xgb_model/generated_model_script.py +36 -7
- workbench/model_scripts/xgb_model/xgb_model.template +36 -7
- workbench/repl/workbench_shell.py +14 -5
- workbench/resources/open_source_api.key +1 -1
- workbench/scripts/endpoint_test.py +162 -0
- workbench/scripts/{lambda_launcher.py → lambda_test.py} +10 -0
- workbench/utils/chemprop_utils.py +761 -0
- workbench/utils/pytorch_utils.py +527 -0
- workbench/utils/xgboost_model_utils.py +10 -5
- workbench/web_interface/components/model_plot.py +7 -1
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/METADATA +3 -3
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/RECORD +49 -43
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/entry_points.txt +2 -1
- workbench/core/cloud_platform/aws/aws_df_store.py +0 -404
- workbench/core/cloud_platform/aws/aws_parameter_store.py +0 -280
- workbench/model_scripts/__pycache__/script_generation.cpython-312.pyc +0 -0
- workbench/model_scripts/__pycache__/script_generation.cpython-313.pyc +0 -0
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/WHEEL +0 -0
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/licenses/LICENSE +0 -0
- {workbench-0.8.198.dist-info → workbench-0.8.203.dist-info}/top_level.txt +0 -0
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
"""AWSParameterStore: Manages Workbench parameters in AWS Systems Manager Parameter Store."""
|
|
2
|
-
|
|
3
|
-
from typing import Union
|
|
4
|
-
import logging
|
|
5
|
-
import json
|
|
6
|
-
import zlib
|
|
7
|
-
import base64
|
|
8
|
-
from botocore.exceptions import ClientError
|
|
9
|
-
|
|
10
|
-
# Workbench Imports
|
|
11
|
-
from workbench.core.cloud_platform.aws.aws_session import AWSSession
|
|
12
|
-
from workbench.utils.json_utils import CustomEncoder
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class AWSParameterStore:
|
|
16
|
-
"""AWSParameterStore: Manages Workbench parameters in AWS Systems Manager Parameter Store.
|
|
17
|
-
|
|
18
|
-
Common Usage:
|
|
19
|
-
```python
|
|
20
|
-
params = AWSParameterStore()
|
|
21
|
-
|
|
22
|
-
# List Parameters
|
|
23
|
-
params.list()
|
|
24
|
-
|
|
25
|
-
['/workbench/abalone_info',
|
|
26
|
-
'/workbench/my_data',
|
|
27
|
-
'/workbench/test',
|
|
28
|
-
'/workbench/pipelines/my_pipeline']
|
|
29
|
-
|
|
30
|
-
# Add Key
|
|
31
|
-
params.upsert("key", "value")
|
|
32
|
-
value = params.get("key")
|
|
33
|
-
|
|
34
|
-
# Add any data (lists, dictionaries, etc..)
|
|
35
|
-
my_data = {"key": "value", "number": 4.2, "list": [1,2,3]}
|
|
36
|
-
params.upsert("my_data", my_data)
|
|
37
|
-
|
|
38
|
-
# Retrieve data
|
|
39
|
-
return_value = params.get("my_data")
|
|
40
|
-
pprint(return_value)
|
|
41
|
-
|
|
42
|
-
{'key': 'value', 'list': [1, 2, 3], 'number': 4.2}
|
|
43
|
-
|
|
44
|
-
# Delete parameters
|
|
45
|
-
param_store.delete("my_data")
|
|
46
|
-
```
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
def __init__(self):
|
|
50
|
-
"""AWSParameterStore Init Method"""
|
|
51
|
-
self.log = logging.getLogger("workbench")
|
|
52
|
-
|
|
53
|
-
# Initialize a Workbench Session (to assume the Workbench ExecutionRole)
|
|
54
|
-
self.boto3_session = AWSSession().boto3_session
|
|
55
|
-
|
|
56
|
-
# Create a Systems Manager (SSM) client for Parameter Store operations
|
|
57
|
-
self.ssm_client = self.boto3_session.client("ssm")
|
|
58
|
-
|
|
59
|
-
def list(self, prefix: str = None) -> list:
|
|
60
|
-
"""List all parameters in the AWS Parameter Store, optionally filtering by a prefix.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
prefix (str, optional): A prefix to filter the parameters by. Defaults to None.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
list: A list of parameter names and details.
|
|
67
|
-
"""
|
|
68
|
-
try:
|
|
69
|
-
# Set up parameters for the query
|
|
70
|
-
params = {"MaxResults": 50}
|
|
71
|
-
|
|
72
|
-
# If a prefix is provided, add the 'ParameterFilters' for optimization
|
|
73
|
-
if prefix:
|
|
74
|
-
params["ParameterFilters"] = [{"Key": "Name", "Option": "BeginsWith", "Values": [prefix]}]
|
|
75
|
-
|
|
76
|
-
# Initialize the list to collect parameter names
|
|
77
|
-
all_parameters = []
|
|
78
|
-
|
|
79
|
-
# Make the initial call to describe parameters
|
|
80
|
-
response = self.ssm_client.describe_parameters(**params)
|
|
81
|
-
|
|
82
|
-
# Aggregate the names from the initial response
|
|
83
|
-
all_parameters.extend(param["Name"] for param in response["Parameters"])
|
|
84
|
-
|
|
85
|
-
# Continue to paginate if there's a NextToken
|
|
86
|
-
while "NextToken" in response:
|
|
87
|
-
# Update the parameters with the NextToken for subsequent calls
|
|
88
|
-
params["NextToken"] = response["NextToken"]
|
|
89
|
-
response = self.ssm_client.describe_parameters(**params)
|
|
90
|
-
|
|
91
|
-
# Aggregate the names from the subsequent responses
|
|
92
|
-
all_parameters.extend(param["Name"] for param in response["Parameters"])
|
|
93
|
-
|
|
94
|
-
except Exception as e:
|
|
95
|
-
self.log.error(f"Failed to list parameters: {e}")
|
|
96
|
-
return []
|
|
97
|
-
|
|
98
|
-
# Return the aggregated list of parameter names
|
|
99
|
-
return all_parameters
|
|
100
|
-
|
|
101
|
-
def get(self, name: str, warn: bool = True, decrypt: bool = True) -> Union[str, list, dict, None]:
|
|
102
|
-
"""Retrieve a parameter value from the AWS Parameter Store.
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
name (str): The name of the parameter to retrieve.
|
|
106
|
-
warn (bool): Whether to log a warning if the parameter is not found.
|
|
107
|
-
decrypt (bool): Whether to decrypt secure string parameters.
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
Union[str, list, dict, None]: The value of the parameter or None if not found.
|
|
111
|
-
"""
|
|
112
|
-
try:
|
|
113
|
-
# Retrieve the parameter from Parameter Store
|
|
114
|
-
response = self.ssm_client.get_parameter(Name=name, WithDecryption=decrypt)
|
|
115
|
-
value = response["Parameter"]["Value"]
|
|
116
|
-
|
|
117
|
-
# Auto-detect and decompress if needed
|
|
118
|
-
if value.startswith("COMPRESSED:"):
|
|
119
|
-
# Base64 decode and decompress
|
|
120
|
-
self.log.important(f"Decompressing parameter '{name}'...")
|
|
121
|
-
compressed_value = base64.b64decode(value[len("COMPRESSED:") :])
|
|
122
|
-
value = zlib.decompress(compressed_value).decode("utf-8")
|
|
123
|
-
|
|
124
|
-
# Attempt to parse the value back to its original type
|
|
125
|
-
try:
|
|
126
|
-
parsed_value = json.loads(value)
|
|
127
|
-
return parsed_value
|
|
128
|
-
except (json.JSONDecodeError, TypeError):
|
|
129
|
-
# If parsing fails, return the value as is "hope for the best"
|
|
130
|
-
return value
|
|
131
|
-
|
|
132
|
-
except ClientError as e:
|
|
133
|
-
if e.response["Error"]["Code"] == "ParameterNotFound":
|
|
134
|
-
if warn:
|
|
135
|
-
self.log.warning(f"Parameter '{name}' not found")
|
|
136
|
-
else:
|
|
137
|
-
self.log.error(f"Failed to get parameter '{name}': {e}")
|
|
138
|
-
return None
|
|
139
|
-
|
|
140
|
-
def upsert(self, name: str, value, precision: int = 3):
|
|
141
|
-
"""Insert or update a parameter in the AWS Parameter Store.
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
name (str): The name of the parameter.
|
|
145
|
-
value (str | list | dict): The value of the parameter.
|
|
146
|
-
precision (int): The precision for float values in the JSON encoding.
|
|
147
|
-
"""
|
|
148
|
-
try:
|
|
149
|
-
# Convert to JSON and check if compression is needed
|
|
150
|
-
json_value = json.dumps(value, cls=CustomEncoder, precision=precision)
|
|
151
|
-
if len(json_value) <= 4096:
|
|
152
|
-
# Store normally if under 4KB
|
|
153
|
-
self._store_parameter(name, json_value)
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
# Need compression - log warning
|
|
157
|
-
self.log.important(
|
|
158
|
-
f"Parameter {name} exceeds 4KB ({len(json_value)} bytes): compressing and reducing precision..."
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
# Try compression with precision reduction
|
|
162
|
-
compressed_value = self._compress_value(value)
|
|
163
|
-
|
|
164
|
-
if len(compressed_value) <= 4096:
|
|
165
|
-
self._store_parameter(name, compressed_value)
|
|
166
|
-
return
|
|
167
|
-
|
|
168
|
-
# Try clipping the data
|
|
169
|
-
clipped_value = self._clip_data(value)
|
|
170
|
-
compressed_clipped = self._compress_value(clipped_value)
|
|
171
|
-
|
|
172
|
-
if len(compressed_clipped) <= 4096:
|
|
173
|
-
self.log.warning(
|
|
174
|
-
f"Parameter {name} data clipped to 100 items/elements: ({len(compressed_clipped)} bytes)"
|
|
175
|
-
)
|
|
176
|
-
self._store_parameter(name, compressed_clipped)
|
|
177
|
-
return
|
|
178
|
-
|
|
179
|
-
# Still too large - give up
|
|
180
|
-
self._handle_oversized_data(name, len(compressed_clipped))
|
|
181
|
-
|
|
182
|
-
except Exception as e:
|
|
183
|
-
self.log.critical(f"Failed to add/update parameter '{name}': {e}")
|
|
184
|
-
raise
|
|
185
|
-
|
|
186
|
-
@staticmethod
|
|
187
|
-
def _compress_value(value) -> str:
|
|
188
|
-
"""Compress a value with precision reduction."""
|
|
189
|
-
json_value = json.dumps(value, cls=CustomEncoder, precision=3)
|
|
190
|
-
compressed = zlib.compress(json_value.encode("utf-8"), level=9)
|
|
191
|
-
return "COMPRESSED:" + base64.b64encode(compressed).decode("utf-8")
|
|
192
|
-
|
|
193
|
-
@staticmethod
|
|
194
|
-
def _clip_data(value):
|
|
195
|
-
"""Clip data to reduce size, clip to first 100 items/elements."""
|
|
196
|
-
if isinstance(value, dict):
|
|
197
|
-
return dict(list(value.items())[:100])
|
|
198
|
-
elif isinstance(value, list):
|
|
199
|
-
return value[:100]
|
|
200
|
-
return value
|
|
201
|
-
|
|
202
|
-
def _store_parameter(self, name: str, value: str):
|
|
203
|
-
"""Store parameter in AWS Parameter Store."""
|
|
204
|
-
self.ssm_client.put_parameter(Name=name, Value=value, Type="String", Overwrite=True)
|
|
205
|
-
self.log.info(f"Parameter '{name}' added/updated successfully.")
|
|
206
|
-
|
|
207
|
-
def _handle_oversized_data(self, name: str, size: int):
|
|
208
|
-
"""Handle data that's too large even after compression and clipping."""
|
|
209
|
-
doc_link = "https://supercowpowers.github.io/workbench/api_classes/df_store"
|
|
210
|
-
self.log.error(f"Compressed size {size} bytes, cannot store > 4KB")
|
|
211
|
-
self.log.error(f"For larger data use the DFStore() class ({doc_link})")
|
|
212
|
-
|
|
213
|
-
def delete(self, name: str):
|
|
214
|
-
"""Delete a parameter from the AWS Parameter Store.
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
name (str): The name of the parameter to delete.
|
|
218
|
-
"""
|
|
219
|
-
try:
|
|
220
|
-
# Delete the parameter from Parameter Store
|
|
221
|
-
self.ssm_client.delete_parameter(Name=name)
|
|
222
|
-
self.log.info(f"Parameter '{name}' deleted successfully.")
|
|
223
|
-
except Exception as e:
|
|
224
|
-
self.log.error(f"Failed to delete parameter '{name}': {e}")
|
|
225
|
-
|
|
226
|
-
def delete_recursive(self, prefix: str):
|
|
227
|
-
"""Delete all parameters with a given prefix from the AWS Parameter Store.
|
|
228
|
-
|
|
229
|
-
Args:
|
|
230
|
-
prefix (str): The prefix of the parameters to delete.
|
|
231
|
-
"""
|
|
232
|
-
# List all parameters with the given prefix
|
|
233
|
-
parameters = self.list(prefix=prefix)
|
|
234
|
-
for param in parameters:
|
|
235
|
-
self.delete(param)
|
|
236
|
-
|
|
237
|
-
def __repr__(self):
|
|
238
|
-
"""Return a string representation of the AWSParameterStore object."""
|
|
239
|
-
return "\n".join(self.list())
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if __name__ == "__main__":
|
|
243
|
-
"""Exercise the AWSParameterStore Class"""
|
|
244
|
-
|
|
245
|
-
# Create a AWSParameterStore manager
|
|
246
|
-
param_store = AWSParameterStore()
|
|
247
|
-
|
|
248
|
-
# List the parameters
|
|
249
|
-
print("Listing Parameters...")
|
|
250
|
-
print(param_store.list())
|
|
251
|
-
|
|
252
|
-
# Add a new parameter
|
|
253
|
-
param_store.upsert("/workbench/test", "value")
|
|
254
|
-
|
|
255
|
-
# Get the parameter
|
|
256
|
-
print(f"Getting parameter 'test': {param_store.get('/workbench/test')}")
|
|
257
|
-
|
|
258
|
-
# Add a dictionary as a parameter
|
|
259
|
-
sample_dict = {"key": "str_value", "awesome_value": 4.2}
|
|
260
|
-
param_store.upsert("/workbench/my_data", sample_dict)
|
|
261
|
-
|
|
262
|
-
# Retrieve the parameter as a dictionary
|
|
263
|
-
retrieved_value = param_store.get("/workbench/my_data")
|
|
264
|
-
print("Retrieved value:", retrieved_value)
|
|
265
|
-
|
|
266
|
-
# List the parameters
|
|
267
|
-
print("Listing Parameters...")
|
|
268
|
-
print(param_store.list())
|
|
269
|
-
|
|
270
|
-
# List the parameters with a prefix
|
|
271
|
-
print("Listing Parameters with prefix '/workbench':")
|
|
272
|
-
print(param_store.list("/workbench"))
|
|
273
|
-
|
|
274
|
-
# Delete the parameters
|
|
275
|
-
param_store.delete("/workbench/test")
|
|
276
|
-
param_store.delete("/workbench/my_data")
|
|
277
|
-
|
|
278
|
-
# Out of scope tests
|
|
279
|
-
param_store.upsert("test", "value")
|
|
280
|
-
param_store.delete("test")
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|