ciocore 6.3.2rc1__py2.py3-none-any.whl → 6.4.0__py2.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.
Potentially problematic release.
This version of ciocore might be problematic. Click here for more details.
- ciocore/VERSION +1 -1
- ciocore/__about__.py +3 -20
- ciocore/api_client.py +116 -236
- ciocore/cli/__init__.py +3 -0
- ciocore/cli/conductor.py +206 -0
- ciocore/config.py +44 -50
- ciocore/data.py +131 -85
- ciocore/downloader.py +64 -46
- ciocore/hardware_set.py +99 -326
- ciocore/package_environment.py +74 -48
- ciocore/package_tree.py +377 -300
- ciocore/uploader/_uploader.py +2 -6
- ciocore-6.4.0.data/scripts/conductor +19 -0
- ciocore-6.4.0.data/scripts/conductor.bat +13 -0
- {ciocore-6.3.2rc1.dist-info → ciocore-6.4.0.dist-info}/METADATA +12 -35
- ciocore-6.4.0.dist-info/RECORD +51 -0
- {ciocore-6.3.2rc1.dist-info → ciocore-6.4.0.dist-info}/WHEEL +1 -1
- tests/instance_type_fixtures.py +9 -43
- tests/mocks/api_client_mock.py +31 -0
- tests/test_hardware_set.py +4 -50
- ciocore/cli.py +0 -336
- ciocore/dev_inst_tagger.py +0 -120
- ciocore/docsite/404.html +0 -723
- ciocore/docsite/apidoc/api_client/index.html +0 -2590
- ciocore/docsite/apidoc/apidoc/index.html +0 -868
- ciocore/docsite/apidoc/config/index.html +0 -1562
- ciocore/docsite/apidoc/data/index.html +0 -1550
- ciocore/docsite/apidoc/hardware_set/index.html +0 -2324
- ciocore/docsite/apidoc/package_environment/index.html +0 -1430
- ciocore/docsite/apidoc/package_tree/index.html +0 -2310
- ciocore/docsite/assets/_mkdocstrings.css +0 -16
- ciocore/docsite/assets/images/favicon.png +0 -0
- ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js +0 -29
- ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js.map +0 -8
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +0 -18
- ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +0 -1
- ciocore/docsite/assets/javascripts/lunr/tinyseg.js +0 -206
- ciocore/docsite/assets/javascripts/lunr/wordcut.js +0 -6708
- ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js +0 -42
- ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js.map +0 -8
- ciocore/docsite/assets/stylesheets/main.83068744.min.css +0 -1
- ciocore/docsite/assets/stylesheets/main.83068744.min.css.map +0 -1
- ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css +0 -1
- ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css.map +0 -1
- ciocore/docsite/cmdline/docs/index.html +0 -834
- ciocore/docsite/cmdline/downloader/index.html +0 -897
- ciocore/docsite/cmdline/packages/index.html +0 -841
- ciocore/docsite/cmdline/uploader/index.html +0 -950
- ciocore/docsite/how-to-guides/index.html +0 -831
- ciocore/docsite/index.html +0 -853
- ciocore/docsite/logo.png +0 -0
- ciocore/docsite/objects.inv +0 -0
- ciocore/docsite/search/search_index.json +0 -1
- ciocore/docsite/sitemap.xml +0 -3
- ciocore/docsite/sitemap.xml.gz +0 -0
- ciocore/docsite/stylesheets/extra.css +0 -26
- ciocore/docsite/stylesheets/tables.css +0 -170
- ciocore/package_query.py +0 -171
- ciocore-6.3.2rc1.dist-info/RECORD +0 -115
- ciocore-6.3.2rc1.dist-info/entry_points.txt +0 -2
- tests/test_cli.py +0 -161
- tests/test_downloader.py +0 -56
- {ciocore-6.3.2rc1.dist-info → ciocore-6.4.0.dist-info}/top_level.txt +0 -0
ciocore/hardware_set.py
CHANGED
|
@@ -1,314 +1,37 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module contains the **HardwareSet** class.
|
|
3
1
|
|
|
4
|
-
It is designed to allow submission tools and other clients that consume instance types to be able to display them in categories. This is particularly useful for UIs that utilize combo-boxes, since they can be orgnaized into a nested structure and displayed in a tree-like fashion.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
2
|
import copy
|
|
9
3
|
import logging
|
|
10
4
|
|
|
11
5
|
logger = logging.getLogger(__name__)
|
|
12
6
|
|
|
13
|
-
|
|
14
7
|
class HardwareSet(object):
|
|
15
|
-
"""A class to manage categorized instance types.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`content` is a list of instance types in the category. The order is used to sort the categories. The order of the instance types within a category is determined by the number of cores and memory.
|
|
24
|
-
|
|
25
|
-
If all instance_types have not been assigned any categories, then the structure is built with two default categories: CPU and GPU.
|
|
8
|
+
"""A class to manage the categorized instance types.
|
|
9
|
+
|
|
10
|
+
It takes flat instance types array and builds a nested structure where instance types exist in
|
|
11
|
+
categories.
|
|
12
|
+
|
|
13
|
+
If after categorization there is only one category and it is the misc category, then we
|
|
14
|
+
recategorize by cpu and gpu.
|
|
26
15
|
"""
|
|
27
16
|
|
|
28
17
|
def __init__(self, instance_types):
|
|
29
|
-
"""Initialize the HardwareSet with a list of instance types.
|
|
30
|
-
|
|
31
|
-
Typically, you would access the HardwareSet through the ciocore.data.data() function, which initializes it for you. However, you can also initialize it directly with a list of instance types straight from ciocore.api_client. The difference being that the latter contains all instance types, whereas the former contains only the instance types compatible with the products you have specified, as well as being cached.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
instance_types (list): A list of instance types.
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
HardwareSet: The initialized HardwareSet.
|
|
38
|
-
|
|
39
|
-
Examples:
|
|
40
|
-
### Initialize with a list of instance types
|
|
41
|
-
>>> from ciocore import api_client
|
|
42
|
-
>>> from ciocore.hardware_set import HardwareSet
|
|
43
|
-
>>> instance_types = api_client.request_instance_types()
|
|
44
|
-
>>> hardware_set = HardwareSet(instance_types)
|
|
45
|
-
<ciocore.hardware_set.HardwareSet object at 0x104c43d30>
|
|
46
|
-
|
|
47
|
-
### Initialize implicitly with a list of instance types from ciocore.data (recommended).
|
|
48
|
-
>>> from ciocore import data as coredata
|
|
49
|
-
>>> coredata.init("cinema4d")
|
|
50
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
51
|
-
<ciocore.hardware_set.HardwareSet object at 0x104c43ee0>
|
|
52
|
-
|
|
53
|
-
!!! note
|
|
54
|
-
To avoid repetition, we use the implicit initialization for the examples below.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
self.instance_types = self._build_unique(instance_types)
|
|
58
|
-
self.categories = self._build_categories()
|
|
59
|
-
self.provider = self._get_provider()
|
|
60
|
-
|
|
61
|
-
def labels(self):
|
|
62
|
-
"""Get the list of category labels.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
list: A list of category labels.
|
|
66
|
-
|
|
67
|
-
Example:
|
|
68
|
-
>>> from ciocore import data as coredata
|
|
69
|
-
>>> coredata.init()
|
|
70
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
71
|
-
>>> hardware_set.labels()
|
|
72
|
-
['CPU', 'GPU']
|
|
73
|
-
|
|
74
|
-
"""
|
|
75
|
-
return [c["label"] for c in self.categories]
|
|
76
|
-
|
|
77
|
-
def number_of_categories(self):
|
|
78
|
-
"""Get the number of categories in the data.
|
|
79
|
-
|
|
80
|
-
Returns:
|
|
81
|
-
int: The number of categories.
|
|
82
|
-
|
|
83
|
-
Example:
|
|
84
|
-
>>> from ciocore import data as coredata
|
|
85
|
-
>>> coredata.init()
|
|
86
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
87
|
-
>>> hardware_set.number_of_categories()
|
|
88
|
-
2
|
|
89
|
-
|
|
90
|
-
"""
|
|
91
|
-
return len(self.categories)
|
|
92
|
-
|
|
93
|
-
def recategorize(self, partitioner):
|
|
94
|
-
"""Recategorize the instance types.
|
|
95
|
-
|
|
96
|
-
Args:
|
|
97
|
-
partitioner (function): A function that takes an instance type and returns a list of categories to assign to it. The function should return an empty list if the instance type should not be categorized.
|
|
98
|
-
|
|
99
|
-
Example:
|
|
100
|
-
# Confirm current categories
|
|
101
|
-
>>> from ciocore import data as coredata
|
|
102
|
-
>>> coredata.init()
|
|
103
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
104
|
-
>>> print(hardware_set.labels()
|
|
105
|
-
['CPU', 'GPU']
|
|
106
|
-
|
|
107
|
-
# Recategorize
|
|
108
|
-
>>> hardware_set.recategorize(lambda x: [{'label': 'Low cores', 'order': 10}] if x["cores"] < 16 else [{'label': 'High cores', 'order': 20}])
|
|
109
|
-
>>> print(hardware_set.labels()
|
|
110
|
-
['Low cores', 'High cores']
|
|
111
|
-
"""
|
|
112
|
-
for key in self.instance_types:
|
|
113
|
-
self.instance_types[key]["categories"] = partitioner(
|
|
114
|
-
self.instance_types[key]
|
|
115
|
-
)
|
|
116
|
-
self.categories = self._build_categories()
|
|
117
|
-
|
|
118
|
-
def find(self, name, category=None):
|
|
119
|
-
"""Find an instance type by it's name (sku).
|
|
120
|
-
|
|
121
|
-
Args:
|
|
122
|
-
name (str): The name of the instance type.
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
dict: The instance type or None if not found.
|
|
126
|
-
|
|
127
|
-
Example:
|
|
128
|
-
>>> from ciocore import data as coredata
|
|
129
|
-
>>> coredata.init()
|
|
130
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
131
|
-
>>> hardware_set.find("n2-highmem-80")
|
|
132
|
-
{
|
|
133
|
-
'cores': 80,
|
|
134
|
-
'description': '80 core, 640GB Mem',
|
|
135
|
-
'gpu': None,
|
|
136
|
-
'memory': '640',
|
|
137
|
-
'name': 'n2-highmem-80',
|
|
138
|
-
'operating_system': 'linux',
|
|
139
|
-
'categories': [
|
|
140
|
-
{'label': 'High cores', 'order': 20}
|
|
141
|
-
]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
"""
|
|
145
|
-
if not category:
|
|
146
|
-
return self.instance_types.get(name)
|
|
147
|
-
|
|
148
|
-
return self.find_first(lambda x: x["name"] == name and category in [c["label"] for c in x["categories"]])
|
|
149
|
-
|
|
150
|
-
def find_category(self, label):
|
|
151
|
-
"""Find a category by label.
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
label (str): The label of the category.
|
|
155
|
-
|
|
156
|
-
Returns:
|
|
157
|
-
dict: The category or None if not found.
|
|
158
|
-
|
|
159
|
-
Example:
|
|
160
|
-
>>> from ciocore import data as coredata
|
|
161
|
-
>>> coredata.init()
|
|
162
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
163
|
-
>>> hardware_set.find_category("High cores")
|
|
164
|
-
{
|
|
165
|
-
"label": "Low cores",
|
|
166
|
-
"content": [
|
|
167
|
-
{
|
|
168
|
-
"cores": 8,
|
|
169
|
-
"description": "8 core, 52GB Mem",
|
|
170
|
-
"gpu": None,
|
|
171
|
-
"memory": "52",
|
|
172
|
-
"name": "n1-highmem-8",
|
|
173
|
-
"operating_system": "linux",
|
|
174
|
-
"categories": [{"label": "Low cores", "order": 10}],
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"cores": 8,
|
|
178
|
-
"description": "8 core, 7.2GB Mem",
|
|
179
|
-
"gpu": None,
|
|
180
|
-
"memory": "7.2",
|
|
181
|
-
"name": "n1-highcpu-8",
|
|
182
|
-
"operating_system": "linux",
|
|
183
|
-
"categories": [{"label": "Low cores", "order": 10}],
|
|
184
|
-
},
|
|
185
|
-
...
|
|
186
|
-
],
|
|
187
|
-
"order": 10
|
|
188
|
-
}
|
|
189
|
-
"""
|
|
190
|
-
return next((c for c in self.categories if c["label"] == label), None)
|
|
191
|
-
|
|
192
|
-
def find_all(self, condition):
|
|
193
|
-
"""Find all instance types that match a condition.
|
|
194
|
-
|
|
195
|
-
Args:
|
|
196
|
-
condition (function): A function that takes an instance type and returns True or False.
|
|
197
|
-
|
|
198
|
-
Returns:
|
|
199
|
-
list: A list of instance types that match the condition.
|
|
200
|
-
|
|
201
|
-
Example:
|
|
202
|
-
>>> from ciocore import data as coredata
|
|
203
|
-
>>> coredata.init()
|
|
204
|
-
>>> hardware_set = coredata.data()["instance_types"]
|
|
205
|
-
>>> hardware_set.find_all(lambda x: x["gpu"])
|
|
206
|
-
[
|
|
207
|
-
{
|
|
208
|
-
"cores": 4,
|
|
209
|
-
"description": "4 core, 15GB Mem (1 T4 Tensor GPU with 16GB Mem)",
|
|
210
|
-
"gpu": {
|
|
211
|
-
"gpu_architecture": "NVIDIA Turing",
|
|
212
|
-
"gpu_count": 1,
|
|
213
|
-
"gpu_cuda_cores": 2560,
|
|
214
|
-
"gpu_memory": "16",
|
|
215
|
-
"gpu_model": "T4 Tensor",
|
|
216
|
-
"gpu_rt_cores": 0,
|
|
217
|
-
"gpu_tensor_cores": 0,
|
|
218
|
-
"total_gpu_cuda_cores": 2560,
|
|
219
|
-
"total_gpu_memory": "16",
|
|
220
|
-
"total_gpu_rt_cores": 0,
|
|
221
|
-
"total_gpu_tensor_cores": 0,
|
|
222
|
-
},
|
|
223
|
-
"memory": "15",
|
|
224
|
-
"name": "n1-standard-4-t4-1",
|
|
225
|
-
"operating_system": "linux",
|
|
226
|
-
"categories": [{"label": "Low cores", "order": 10}],
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
"cores": 8,
|
|
230
|
-
"description": "8 core, 30GB Mem (1 T4 Tensor GPU with 16GB Mem)",
|
|
231
|
-
"gpu": {
|
|
232
|
-
"gpu_architecture": "NVIDIA Turing",
|
|
233
|
-
"gpu_count": 1,
|
|
234
|
-
"gpu_cuda_cores": 2560,
|
|
235
|
-
"gpu_memory": "16",
|
|
236
|
-
"gpu_model": "T4 Tensor",
|
|
237
|
-
"gpu_rt_cores": 0,
|
|
238
|
-
"gpu_tensor_cores": 0,
|
|
239
|
-
"total_gpu_cuda_cores": 2560,
|
|
240
|
-
"total_gpu_memory": "16",
|
|
241
|
-
"total_gpu_rt_cores": 0,
|
|
242
|
-
"total_gpu_tensor_cores": 0,
|
|
243
|
-
},
|
|
244
|
-
"memory": "30",
|
|
245
|
-
"name": "n1-standard-8-t4-1",
|
|
246
|
-
"operating_system": "linux",
|
|
247
|
-
"categories": [{"label": "Low cores", "order": 10}],
|
|
248
|
-
},
|
|
249
|
-
...
|
|
250
|
-
]
|
|
251
|
-
"""
|
|
252
|
-
result = []
|
|
253
|
-
for key in self.instance_types:
|
|
254
|
-
if condition(self.instance_types[key]):
|
|
255
|
-
result.append(self.instance_types[key])
|
|
256
|
-
return result
|
|
257
|
-
|
|
258
|
-
def find_first(self, condition):
|
|
259
|
-
"""Find the first instance type that matches a condition.
|
|
260
|
-
|
|
261
|
-
Please see find_all() above for more details. This method is just a convenience wrapper around find_all() that returns the first result or None if not found.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
condition (function): A function that takes an instance type and returns True or False.
|
|
265
|
-
|
|
266
|
-
Returns:
|
|
267
|
-
dict: The first instance type that matches the condition or None if not found.
|
|
268
|
-
"""
|
|
269
|
-
return next(iter(self.find_all(condition)), None)
|
|
270
|
-
|
|
271
|
-
# DEPRECATED
|
|
272
|
-
def get_model(self, with_misc=False):
|
|
273
|
-
"""Get the categories structure with renaming ready for some specific widget, such as a Qt Combobox.
|
|
274
|
-
|
|
275
|
-
Deprecated:
|
|
276
|
-
The get_model() method is deprecated. The `with_misc` parameter is no longer used, which means that this function only serves to rename a few keys. What's more, the init function ensures that every instance type has a category. This function is no longer needed. Submitters that use it will work but should be updated to use the categories structure directly as it minimizes the levels of indirection necessary to work with it.
|
|
277
|
-
"""
|
|
278
|
-
if with_misc:
|
|
279
|
-
logger.warning("with_misc is no longer used")
|
|
280
|
-
result = []
|
|
281
|
-
for category in self.categories:
|
|
282
|
-
result.append(
|
|
283
|
-
{
|
|
284
|
-
"label": category["label"],
|
|
285
|
-
"content": [
|
|
286
|
-
{"label": k["description"], "value": k["name"]}
|
|
287
|
-
for k in category["content"]
|
|
288
|
-
],
|
|
289
|
-
}
|
|
290
|
-
)
|
|
291
18
|
|
|
292
|
-
|
|
19
|
+
self.instance_types = self.build_unique(instance_types)
|
|
20
|
+
self.categories = self.build_categories()
|
|
293
21
|
|
|
294
|
-
# PRIVATE METHODS
|
|
295
22
|
@staticmethod
|
|
296
|
-
def
|
|
297
|
-
"""Build a dictionary of instance types using
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
23
|
+
def build_unique(instance_types):
|
|
24
|
+
"""Build a dictionary of instance types using name as key.
|
|
25
|
+
|
|
26
|
+
Remove any instance types whose description has already been seen. We can't have duplicate
|
|
27
|
+
descriptions.
|
|
28
|
+
|
|
29
|
+
If categories exist, then remove any instance types that don't have a category. Otherwise,
|
|
30
|
+
since there are no categories, we can't remove any instance types.
|
|
304
31
|
"""
|
|
305
|
-
categories = [
|
|
306
|
-
category
|
|
307
|
-
for it in instance_types
|
|
308
|
-
for category in (it.get("categories") or [])
|
|
309
|
-
]
|
|
32
|
+
categories = [category for it in instance_types for category in (it.get("categories") or [])]
|
|
310
33
|
result = {}
|
|
311
|
-
seen_descriptions = set()
|
|
34
|
+
seen_descriptions = set()
|
|
312
35
|
for it in instance_types:
|
|
313
36
|
if it["description"] in seen_descriptions:
|
|
314
37
|
continue
|
|
@@ -317,22 +40,15 @@ class HardwareSet(object):
|
|
|
317
40
|
continue
|
|
318
41
|
else:
|
|
319
42
|
# make our own categories GPU/CPU
|
|
320
|
-
it["categories"] =
|
|
321
|
-
[{"label": "GPU", "order": 2}]
|
|
322
|
-
if "gpu" in it and it["gpu"]
|
|
323
|
-
else [{"label": "CPU", "order": 1}]
|
|
324
|
-
)
|
|
43
|
+
it["categories"] = [{'label': 'GPU', 'order': 2}] if "gpu" in it and it["gpu"] else [{'label': 'CPU', 'order': 1}]
|
|
325
44
|
result[it["name"]] = it
|
|
326
45
|
seen_descriptions.add(it["description"])
|
|
327
46
|
return result
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
list: A list of categories where each category is a dictionary with keys: `label`, `content`, and `order`.
|
|
334
|
-
"""
|
|
335
|
-
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build_categories(self):
|
|
50
|
+
"""Build a sorted list of categories, each category containing a sorted list of machines"""
|
|
51
|
+
|
|
336
52
|
dikt = {}
|
|
337
53
|
for key in self.instance_types:
|
|
338
54
|
it = self.instance_types[key]
|
|
@@ -340,11 +56,7 @@ class HardwareSet(object):
|
|
|
340
56
|
for category in categories:
|
|
341
57
|
label = category["label"]
|
|
342
58
|
if label not in dikt:
|
|
343
|
-
dikt[label] = {
|
|
344
|
-
"label": label,
|
|
345
|
-
"content": [],
|
|
346
|
-
"order": category["order"],
|
|
347
|
-
}
|
|
59
|
+
dikt[label] = {"label": label, "content": [], "order": category["order"]}
|
|
348
60
|
dikt[label]["content"].append(it)
|
|
349
61
|
|
|
350
62
|
result = []
|
|
@@ -353,18 +65,79 @@ class HardwareSet(object):
|
|
|
353
65
|
category["content"].sort(key=lambda k: (k["cores"], k["memory"]))
|
|
354
66
|
result.append(category)
|
|
355
67
|
return sorted(result, key=lambda k: k["order"])
|
|
68
|
+
|
|
69
|
+
def recategorize(self, partitioner):
|
|
70
|
+
"""Recategorize the instance types.
|
|
71
|
+
|
|
72
|
+
Partitioner is a function that takes an instance type and returns a list of categories.
|
|
73
|
+
|
|
74
|
+
If for example you want to append to the existing categories, then you can use a function like this:
|
|
75
|
+
lambda x: x["categories"] + [{'label': 'Low cores', 'order': 10}] if x["cores"] < 16 else [{'label': 'High cores', 'order': 20}]
|
|
76
|
+
|
|
77
|
+
Rebuilds the categories structure after assigning the new categories.
|
|
78
|
+
"""
|
|
79
|
+
for key in self.instance_types:
|
|
80
|
+
self.instance_types[key]["categories"] = partitioner(self.instance_types[key])
|
|
81
|
+
self.categories = self.build_categories()
|
|
82
|
+
|
|
356
83
|
|
|
357
|
-
def
|
|
358
|
-
"""
|
|
84
|
+
def get_model(self, with_misc=False):
|
|
85
|
+
"""Returns the categories structure with renaming ready for some UI.
|
|
86
|
+
|
|
87
|
+
NOTE: THIS METHOD WILL BE DEPRECATED. with_misc is no longer used, which means that this
|
|
88
|
+
function just renames a few keys. What's more, the init function ensures that every instance
|
|
89
|
+
type has a (non-misc) category. So this function is no longer needed. Submitters that use
|
|
90
|
+
it will work fine, but should be updated to use the categories structure directly.
|
|
91
|
+
"""
|
|
92
|
+
if with_misc:
|
|
93
|
+
logger.warning("with_misc is no longer used")
|
|
94
|
+
result = []
|
|
95
|
+
for category in self.categories:
|
|
96
|
+
result.append({
|
|
97
|
+
"label": category["label"],
|
|
98
|
+
"content": [{"label": k["description"], "value": k["name"]} for k in category["content"]]
|
|
99
|
+
})
|
|
359
100
|
|
|
360
|
-
|
|
361
|
-
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
def find(self, name):
|
|
104
|
+
"""Find an instance type by name (sku).
|
|
105
|
+
|
|
106
|
+
Example: find("p3.2xlarge")
|
|
107
|
+
|
|
108
|
+
Returns and instance-type or None if not found.
|
|
109
|
+
"""
|
|
110
|
+
return self.instance_types.get(name)
|
|
111
|
+
|
|
112
|
+
def find_category(self, label):
|
|
113
|
+
"""Find a category by label.
|
|
114
|
+
|
|
115
|
+
Example: find_category("GPU")
|
|
116
|
+
|
|
117
|
+
Returns the entire category and its contents or None if not found.
|
|
118
|
+
"""
|
|
119
|
+
return next((c for c in self.categories if c["label"] == label), None)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def find_all(self, condition):
|
|
123
|
+
"""Find all instance types that match a condition.
|
|
124
|
+
|
|
125
|
+
Example: find_all(lambda x: x["gpu"])
|
|
126
|
+
"""
|
|
127
|
+
result = []
|
|
128
|
+
for key in self.instance_types:
|
|
129
|
+
if condition(self.instance_types[key]):
|
|
130
|
+
result.append(self.instance_types[key])
|
|
131
|
+
return result
|
|
132
|
+
|
|
133
|
+
def find_first(self, condition):
|
|
134
|
+
"""Find the first instance type that matches a condition.
|
|
135
|
+
|
|
136
|
+
Example: find_first(lambda x: x["cores"] == 4)"])
|
|
362
137
|
"""
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
return "aws"
|
|
370
|
-
return "gcp"
|
|
138
|
+
return next(iter(self.find_all(condition)), None)
|
|
139
|
+
|
|
140
|
+
def number_of_categories(self):
|
|
141
|
+
"""Return the number of categories in the data."""
|
|
142
|
+
return len(self.categories)
|
|
143
|
+
|
ciocore/package_environment.py
CHANGED
|
@@ -7,15 +7,21 @@ class PackageEnvironment(object):
|
|
|
7
7
|
|
|
8
8
|
def __init__(self, env_list=None, platform=None):
|
|
9
9
|
"""
|
|
10
|
-
|
|
10
|
+
Create a list of environment variables.
|
|
11
11
|
|
|
12
|
-
Typically, one would initialize a PackageEnvironment with a package, and then modify by
|
|
12
|
+
Typically, one would initialize a PackageEnvironment with a package, and then modify by
|
|
13
|
+
adding more packages or lists of variables. Extra variables can be added by the customer, or
|
|
14
|
+
programmatically such as during asset scraping.
|
|
15
|
+
|
|
16
|
+
Keyword Arguments:
|
|
17
|
+
|
|
18
|
+
* **`env_list`** -- Either a Package that contains an "environment" property, or a list of
|
|
19
|
+
environment objects. -- Defaults to `None`.
|
|
20
|
+
* **`platform`** -- If env_list is not a package, then the platform must be provided. --
|
|
21
|
+
Defaults to `None`.
|
|
22
|
+
|
|
23
|
+
On instantiation, delegete args to the [extend()](#extend) method.
|
|
13
24
|
|
|
14
|
-
Args:
|
|
15
|
-
env_list (object|list): An object that provides a list of dictionaries with properties: `name`, `value`, and `merge_policy`.
|
|
16
|
-
platform (str): If the env_list is a regular list, then this is required.
|
|
17
|
-
|
|
18
|
-
Args are delegated to [extend()](/package_environment/#ciocore.package_environment.PackageEnvironment.extend).
|
|
19
25
|
"""
|
|
20
26
|
self.platform = None
|
|
21
27
|
self._env = {}
|
|
@@ -27,53 +33,73 @@ class PackageEnvironment(object):
|
|
|
27
33
|
"""
|
|
28
34
|
Extend the Package environment with the given variable specifications.
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
env_list (object|list): Either:
|
|
32
|
-
* A list of dictionaries with properties: `name`, `value`, and `merge_policy`.
|
|
33
|
-
* An object with an `environment` key that contains a list of the dictionaries described above. The latter is the structure of a package. Therefore we can initialize or extend a PackageEnvironment with a package.
|
|
34
|
-
platform (str): Defaults to `None`. If env_list is a package, then the platform is taken from the package and the `platform` keyword is ignored. If env_list is a list, then if this is the first add, a platform should be specified, otherwise it will default to linux.
|
|
35
|
-
|
|
36
|
-
The first time data is added to a PackageEnvironment, the platform is set in stone. Subsequent `adds` that try to change the platform are considered an error.
|
|
36
|
+
Arguments:
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
* **`env_list`** -- Either:
|
|
39
|
+
1. A list of dictionaries with properties: `name`, `value`, and `merge_policy`.
|
|
40
|
+
2. An object with an `environment` key that contains a list of the dictionaries described
|
|
41
|
+
above. The latter is the structure of a package. Therefore we can initialize or extend a
|
|
42
|
+
PackageEnvironment with a package.
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
>>> pt = package_tree.PackageTree(packages, product="cinema4d")
|
|
51
|
-
>>> one_dcc_name = pt.supported_host_names()[0]
|
|
52
|
-
cinema4d 21.209.RB305619 linux
|
|
44
|
+
|
|
45
|
+
Keyword Arguments:
|
|
46
|
+
|
|
47
|
+
* **`platform`** -- Defaults to `None`.
|
|
48
|
+
If env_list is a package, then the platform is taken from the package and the `platform`
|
|
49
|
+
keyword is ignored. If env_list is a list, then if this is the first add, a platform
|
|
50
|
+
should be specified, otherwise it willl default to linux.
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
The first time data is added to a PackageEnvironment, the platform is set in stone.
|
|
53
|
+
Subsequent `adds` that try to change the platform are considered an error.
|
|
54
|
+
|
|
55
|
+
Each variable to be added specifies a merge_policy: `append` or `exclusive`. Once an
|
|
56
|
+
individual variable has been initialized with a merge policy, it can't be changed. This
|
|
57
|
+
means: 1. It's not possible to overwrite variables that have been set as append. 2.
|
|
58
|
+
Exclusive variables are always overwritten by subsequent adds.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
|
|
62
|
+
* **`ValueError`** -- Attempt to change the platform once initialized.
|
|
63
|
+
* **`ValueError`** -- Unknown merge policy
|
|
64
|
+
.
|
|
65
|
+
|
|
66
|
+
???+ example
|
|
67
|
+
``` python
|
|
68
|
+
|
|
69
|
+
from ciocore import api_client, package_tree, package_environment
|
|
70
|
+
packages = api_client.request_software_packages()
|
|
71
|
+
pt = package_tree.PackageTree(packages, product="cinema4d")
|
|
72
|
+
one_dcc_name = pt.supported_host_names()[0]
|
|
73
|
+
# 'cinema4d 21.209.RB305619 linux'
|
|
74
|
+
pkg = pt.find_by_name(one_dcc_name)
|
|
75
|
+
pe = package_environment.PackageEnvironment(pkg)
|
|
76
|
+
print(dict(pe))
|
|
77
|
+
|
|
78
|
+
# Result:
|
|
79
|
+
# {
|
|
80
|
+
# "PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin",
|
|
81
|
+
# "g_licenseServerRLM": "conductor-rlm:6112",
|
|
82
|
+
# "LD_LIBRARY_PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/lib64:/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64:/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/embree.module/libs/linux64",
|
|
83
|
+
# "PYTHONPATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64/python2.7/lib-dynload",
|
|
84
|
+
# }
|
|
85
|
+
|
|
86
|
+
extra_env = [
|
|
65
87
|
{"name":"PATH", "value": "/my/custom/scripts", "merge_policy":"append"},
|
|
66
88
|
{"name":"DEBUG_MODE", "value": "1", "merge_policy":"exclusive"}
|
|
67
89
|
]
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
|
|
91
|
+
pe.extend(extra_env)
|
|
92
|
+
print(dict(pe))
|
|
93
|
+
|
|
94
|
+
# Result:
|
|
95
|
+
# {
|
|
96
|
+
# "PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin:/my/custom/scripts",
|
|
97
|
+
# "g_licenseServerRLM": "conductor-rlm:6112",
|
|
98
|
+
# "LD_LIBRARY_PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/lib64:/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64:/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/embree.module/libs/linux64",
|
|
99
|
+
# "PYTHONPATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64/python2.7/lib-dynload",
|
|
100
|
+
# "DEBUG_MODE": "1",
|
|
101
|
+
# }
|
|
102
|
+
```
|
|
77
103
|
"""
|
|
78
104
|
|
|
79
105
|
if not env_list:
|