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.

Files changed (91) hide show
  1. ciocore/VERSION +1 -1
  2. ciocore/__about__.py +3 -20
  3. ciocore/api_client.py +116 -236
  4. ciocore/cli/__init__.py +3 -0
  5. ciocore/cli/conductor.py +206 -0
  6. ciocore/config.py +44 -50
  7. ciocore/data.py +131 -85
  8. ciocore/downloader.py +64 -46
  9. ciocore/hardware_set.py +99 -326
  10. ciocore/package_environment.py +74 -48
  11. ciocore/package_tree.py +377 -300
  12. ciocore/uploader/_uploader.py +2 -6
  13. ciocore-6.4.0.data/scripts/conductor +19 -0
  14. ciocore-6.4.0.data/scripts/conductor.bat +13 -0
  15. {ciocore-6.3.2rc1.dist-info → ciocore-6.4.0.dist-info}/METADATA +12 -35
  16. ciocore-6.4.0.dist-info/RECORD +51 -0
  17. {ciocore-6.3.2rc1.dist-info → ciocore-6.4.0.dist-info}/WHEEL +1 -1
  18. tests/instance_type_fixtures.py +9 -43
  19. tests/mocks/api_client_mock.py +31 -0
  20. tests/test_hardware_set.py +4 -50
  21. ciocore/cli.py +0 -336
  22. ciocore/dev_inst_tagger.py +0 -120
  23. ciocore/docsite/404.html +0 -723
  24. ciocore/docsite/apidoc/api_client/index.html +0 -2590
  25. ciocore/docsite/apidoc/apidoc/index.html +0 -868
  26. ciocore/docsite/apidoc/config/index.html +0 -1562
  27. ciocore/docsite/apidoc/data/index.html +0 -1550
  28. ciocore/docsite/apidoc/hardware_set/index.html +0 -2324
  29. ciocore/docsite/apidoc/package_environment/index.html +0 -1430
  30. ciocore/docsite/apidoc/package_tree/index.html +0 -2310
  31. ciocore/docsite/assets/_mkdocstrings.css +0 -16
  32. ciocore/docsite/assets/images/favicon.png +0 -0
  33. ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js +0 -29
  34. ciocore/docsite/assets/javascripts/bundle.4e31edb1.min.js.map +0 -8
  35. ciocore/docsite/assets/javascripts/lunr/min/lunr.ar.min.js +0 -1
  36. ciocore/docsite/assets/javascripts/lunr/min/lunr.da.min.js +0 -18
  37. ciocore/docsite/assets/javascripts/lunr/min/lunr.de.min.js +0 -18
  38. ciocore/docsite/assets/javascripts/lunr/min/lunr.du.min.js +0 -18
  39. ciocore/docsite/assets/javascripts/lunr/min/lunr.es.min.js +0 -18
  40. ciocore/docsite/assets/javascripts/lunr/min/lunr.fi.min.js +0 -18
  41. ciocore/docsite/assets/javascripts/lunr/min/lunr.fr.min.js +0 -18
  42. ciocore/docsite/assets/javascripts/lunr/min/lunr.hi.min.js +0 -1
  43. ciocore/docsite/assets/javascripts/lunr/min/lunr.hu.min.js +0 -18
  44. ciocore/docsite/assets/javascripts/lunr/min/lunr.hy.min.js +0 -1
  45. ciocore/docsite/assets/javascripts/lunr/min/lunr.it.min.js +0 -18
  46. ciocore/docsite/assets/javascripts/lunr/min/lunr.ja.min.js +0 -1
  47. ciocore/docsite/assets/javascripts/lunr/min/lunr.jp.min.js +0 -1
  48. ciocore/docsite/assets/javascripts/lunr/min/lunr.kn.min.js +0 -1
  49. ciocore/docsite/assets/javascripts/lunr/min/lunr.ko.min.js +0 -1
  50. ciocore/docsite/assets/javascripts/lunr/min/lunr.multi.min.js +0 -1
  51. ciocore/docsite/assets/javascripts/lunr/min/lunr.nl.min.js +0 -18
  52. ciocore/docsite/assets/javascripts/lunr/min/lunr.no.min.js +0 -18
  53. ciocore/docsite/assets/javascripts/lunr/min/lunr.pt.min.js +0 -18
  54. ciocore/docsite/assets/javascripts/lunr/min/lunr.ro.min.js +0 -18
  55. ciocore/docsite/assets/javascripts/lunr/min/lunr.ru.min.js +0 -18
  56. ciocore/docsite/assets/javascripts/lunr/min/lunr.sa.min.js +0 -1
  57. ciocore/docsite/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +0 -1
  58. ciocore/docsite/assets/javascripts/lunr/min/lunr.sv.min.js +0 -18
  59. ciocore/docsite/assets/javascripts/lunr/min/lunr.ta.min.js +0 -1
  60. ciocore/docsite/assets/javascripts/lunr/min/lunr.te.min.js +0 -1
  61. ciocore/docsite/assets/javascripts/lunr/min/lunr.th.min.js +0 -1
  62. ciocore/docsite/assets/javascripts/lunr/min/lunr.tr.min.js +0 -18
  63. ciocore/docsite/assets/javascripts/lunr/min/lunr.vi.min.js +0 -1
  64. ciocore/docsite/assets/javascripts/lunr/min/lunr.zh.min.js +0 -1
  65. ciocore/docsite/assets/javascripts/lunr/tinyseg.js +0 -206
  66. ciocore/docsite/assets/javascripts/lunr/wordcut.js +0 -6708
  67. ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js +0 -42
  68. ciocore/docsite/assets/javascripts/workers/search.dfff1995.min.js.map +0 -8
  69. ciocore/docsite/assets/stylesheets/main.83068744.min.css +0 -1
  70. ciocore/docsite/assets/stylesheets/main.83068744.min.css.map +0 -1
  71. ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css +0 -1
  72. ciocore/docsite/assets/stylesheets/palette.ecc896b0.min.css.map +0 -1
  73. ciocore/docsite/cmdline/docs/index.html +0 -834
  74. ciocore/docsite/cmdline/downloader/index.html +0 -897
  75. ciocore/docsite/cmdline/packages/index.html +0 -841
  76. ciocore/docsite/cmdline/uploader/index.html +0 -950
  77. ciocore/docsite/how-to-guides/index.html +0 -831
  78. ciocore/docsite/index.html +0 -853
  79. ciocore/docsite/logo.png +0 -0
  80. ciocore/docsite/objects.inv +0 -0
  81. ciocore/docsite/search/search_index.json +0 -1
  82. ciocore/docsite/sitemap.xml +0 -3
  83. ciocore/docsite/sitemap.xml.gz +0 -0
  84. ciocore/docsite/stylesheets/extra.css +0 -26
  85. ciocore/docsite/stylesheets/tables.css +0 -170
  86. ciocore/package_query.py +0 -171
  87. ciocore-6.3.2rc1.dist-info/RECORD +0 -115
  88. ciocore-6.3.2rc1.dist-info/entry_points.txt +0 -2
  89. tests/test_cli.py +0 -161
  90. tests/test_downloader.py +0 -56
  91. {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
- A HardwareSet encapsulates the instance types available to an account. It accepts a flat list of instance types and builds a nested structure where those instance types exist in categories.
18
-
19
- It keeps a dictionary of instance types (`instance_types`) with the name field as key. This allows easy lookup by name.
20
-
21
- In addition, it keeps the nested structure of categories (`categories`) that contain the instance types. Each category is a dictionary with keys: `label`, `content`, and `order`.
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
- return result
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 _build_unique(instance_types):
297
- """Build a dictionary of instance types using the name field as key. This allows fast lookup by name.
298
-
299
- Args:
300
- instance_types (list): A list of instance types.
301
-
302
- Returns:
303
- dict: A dictionary of instance types with the name field as key.
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
- def _build_categories(self):
330
- """Build a sorted list of categories where each category contains a sorted list of machines.
331
-
332
- Returns:
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 _get_provider(self):
358
- """Get the provider from the first instance type.
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
- Returns:
361
- str: The provider.
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
- first_name = next(iter(self.instance_types))
364
- if not first_name:
365
- return None
366
- if first_name.startswith("cw-"):
367
- return "cw"
368
- if "." in first_name:
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
+
@@ -7,15 +7,21 @@ class PackageEnvironment(object):
7
7
 
8
8
  def __init__(self, env_list=None, platform=None):
9
9
  """
10
- Encapsulate a list of environment variables.
10
+ Create a list of environment variables.
11
11
 
12
- Typically, one would initialize a PackageEnvironment with a package, and then modify by adding more packages or lists of variables. Extra variables can be added by the customer, or programmatically such as during asset scraping.
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
- Args:
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
- Each variable to be added specifies a merge_policy: `append` or `exclusive`. Once an individual variable has been initialized with a merge policy, it can't be changed. This means:
39
-
40
- 1. It's not possible to overwrite variables that have been set as append.
41
- 2. Exclusive variables are always overwritten by subsequent adds.
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
- Raises:
44
- ValueError: Either an attempt to change the platform once initialized, or an invalid merge policy.
45
-
46
-
47
- Example:
48
- >>> from ciocore import api_client, package_tree, package_environment
49
- >>> packages = api_client.request_software_packages()
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
- >>> pkg = pt.find_by_name(one_dcc_name)
55
- >>> pe = package_environment.PackageEnvironment(pkg)
56
- >>> print(dict(pe))
57
- {
58
- "PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin",
59
- "g_licenseServerRLM": "conductor-rlm:6112",
60
- "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",
61
- "PYTHONPATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64/python2.7/lib-dynload",
62
- }
63
-
64
- >>> extra_env = [
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
- >>> pe.extend(extra_env)
69
- >>> print(dict(pe))
70
- {
71
- "PATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin:/my/custom/scripts",
72
- "g_licenseServerRLM": "conductor-rlm:6112",
73
- "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",
74
- "PYTHONPATH": "/opt/maxon/cinema4d/21/cinema4d21.209vRB305619/bin/resource/modules/python/libs/linux64/python.linux64.framework/lib64/python2.7/lib-dynload",
75
- "DEBUG_MODE": "1",
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: