CMIP7-data-request-api 1.1.2__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.
Files changed (36) hide show
  1. CMIP7_data_request_api-1.1.2.dist-info/LICENSE +21 -0
  2. CMIP7_data_request_api-1.1.2.dist-info/METADATA +210 -0
  3. CMIP7_data_request_api-1.1.2.dist-info/RECORD +36 -0
  4. CMIP7_data_request_api-1.1.2.dist-info/WHEEL +5 -0
  5. CMIP7_data_request_api-1.1.2.dist-info/entry_points.txt +2 -0
  6. CMIP7_data_request_api-1.1.2.dist-info/top_level.txt +1 -0
  7. data_request_api/__init__.py +1 -0
  8. data_request_api/command_line/__init__.py +0 -0
  9. data_request_api/command_line/export_dreq_lists_json.py +136 -0
  10. data_request_api/dev/JA/__init__.py +0 -0
  11. data_request_api/dev/JA/check_plev_requests.py +416 -0
  12. data_request_api/dev/JA/read_feedback_spreadsheet.py +141 -0
  13. data_request_api/dev/JA/workflow_example_GRtest.py +275 -0
  14. data_request_api/dev/JA/workflow_example_test.py +222 -0
  15. data_request_api/dev/MM/checksum.py +68 -0
  16. data_request_api/dev/MM/walking_data_request.ipynb +380 -0
  17. data_request_api/dev/MS/dreq_content_and_walking_data_request.ipynb +3755 -0
  18. data_request_api/dev/__init__.py +0 -0
  19. data_request_api/stable/__init__.py +0 -0
  20. data_request_api/stable/content/README.MD +106 -0
  21. data_request_api/stable/content/__init__.py +0 -0
  22. data_request_api/stable/content/dreq_api/__init__.py +0 -0
  23. data_request_api/stable/content/dreq_api/consolidate_export.py +488 -0
  24. data_request_api/stable/content/dreq_api/dreq_content.py +593 -0
  25. data_request_api/stable/content/dreq_api/mapping_table.py +335 -0
  26. data_request_api/stable/content/dreq_api/test_dreq_content.py +194 -0
  27. data_request_api/stable/content/dump_transformation.py +550 -0
  28. data_request_api/stable/query/__init__.py +0 -0
  29. data_request_api/stable/query/data_request.py +1120 -0
  30. data_request_api/stable/query/dreq_classes.py +372 -0
  31. data_request_api/stable/query/dreq_query.py +981 -0
  32. data_request_api/stable/query/vocabulary_server.py +208 -0
  33. data_request_api/stable/utilities/__init__.py +0 -0
  34. data_request_api/stable/utilities/logger.py +71 -0
  35. data_request_api/stable/utilities/tools.py +49 -0
  36. data_request_api/version.py +16 -0
File without changes
File without changes
@@ -0,0 +1,106 @@
1
+
2
+ **dreq_content.py**
3
+ ====================
4
+
5
+ A Python script for retrieving and managing CMIP7 DReq content.
6
+ It is meant as a building block of the DReq API.
7
+
8
+ **Visible Functions**
9
+ --------------------
10
+
11
+ The following functions are available for use:
12
+
13
+ ### `retrieve(version="latest_stable")`
14
+
15
+ Retrieve the JSON file for the specified version.
16
+
17
+ * `version`: The version to retrieve. Can be 'latest', 'latest_stable', 'dev', or a specific version, eg. '1.0.0', or even a branch like 'first_export'.
18
+ 'dev' points to the main development branch (in this case 'main'). In case of 'latest' or 'latest_stable', the tags on GitHub will be taken into account.
19
+ Default is 'latest_stable'.
20
+ * Returns: A dictionary containing the path to the retrieved JSON file.
21
+
22
+ ### `load(version="latest_stable")`
23
+
24
+ Load the JSON file for the specified version.
25
+
26
+ * `version`: The version to load. Can be 'latest', 'latest_stable', 'dev', or a specific version/branch, eg. '1.0.0'. Default is 'latest_stable'. Will attempt to `retrieve` the version to the local cache if needed.
27
+ * Returns: A dictionary containing the loaded JSON data.
28
+
29
+ ### `get_versions(target="tags")`
30
+
31
+ Fetch the list of available versions (tags and main development branch).
32
+
33
+ * `target`: Can be 'tags' or 'branches'. The main development branch is excluded from 'branches' and considered under 'tags'.
34
+ * Returns: A list of available versions.
35
+
36
+ ### `get_cached()`
37
+
38
+ * Returns: A list of locally cached versions (tags and branches).
39
+
40
+ ### `delete(version="all", keep_latest=False)`
41
+
42
+ Delete one or all cached versions with option to keep latest versions.
43
+
44
+ * `version`: The version to delete. Can be 'all' or a specific version, eg. '1.0.0'. Default is 'all'.
45
+ * `keep_latest`: If True, keep the latest stable, prerelease and "dev" versions. If False, delete all locally cached versions.
46
+ Has no application if `version` is not `"all"`. Note that 'latest' and 'latest_stable' apply on the locally cached
47
+ versions only. More recent versions that might be available online are not considered. Default is False.
48
+
49
+ ### Function `kwargs`
50
+
51
+ Mainly to support the development and not intended for common usage, some functions allow `kwargs`to be passed
52
+ These are:
53
+ - export: "raw" or "release" (supported for `get_cached`, `retrieve`, `load`, `delete`)
54
+ whether to respect the raw or release export json file. Per default, for official releases / tags, the release export json file is processed,
55
+ and else the raw export json file.
56
+ - consolidate: True or False (supported for `load`)
57
+ whether to consolidate in case a raw export json file is loaded. The default is to consolidate.
58
+ - dryrun: True or False (supported for `delete`)
59
+ whether to only list the files that would be deleted instead of actually deleting them. The default is to delete the files and not to list them.
60
+
61
+ **Usage Examples**
62
+ -----------------
63
+
64
+ ```python
65
+ import data_request_api.stable.content.dreq_api.dreq_content as dc
66
+
67
+ # Get the list of available versions
68
+ versions = dc.get_versions()
69
+ print(versions)
70
+
71
+ # List all available branches
72
+ branches = dc.get_versions('branches')
73
+ print(branches)
74
+
75
+ # Retrieve the latest stable version
76
+ version_dict = dc.retrieve() # or dc.retrieve("latest_stable")
77
+ print(version_dict)
78
+
79
+ # Retrieve a certain branch/tag
80
+ version_dict = dc.retrieve("v1.0beta")
81
+ print(version_dict)
82
+
83
+ # Retrieve all available releases
84
+ version_dict = dc.retrieve("all")
85
+ print(version_dict)
86
+
87
+ # Load the latest stable version
88
+ dreq = dc.load() # or dc.load("latest_stable")
89
+
90
+ # Load the latest version
91
+ dreq = dc.load("latest")
92
+
93
+ # Load the development version
94
+ dreq = dc.load("dev")
95
+
96
+ # Get list of locally cached versions
97
+ versions = dc.get_cached()
98
+ print(versions)
99
+
100
+ # Delete all cached versions except the latest, latest stable and "dev" versions
101
+ dc.delete(keep_latest=True)
102
+
103
+ # Delete a certain version
104
+ dc.delete("v1.0alpha")
105
+ ```
106
+
File without changes
File without changes
@@ -0,0 +1,488 @@
1
+ import json
2
+ import os
3
+ import re
4
+ import warnings
5
+
6
+ from data_request_api.stable.utilities.logger import get_logger # noqa
7
+ from .mapping_table import version_consistency
8
+
9
+ # UID generation
10
+ default_count = 0
11
+ default_template = "default_{:d}"
12
+
13
+ # Filtered records
14
+ filtered_records = []
15
+
16
+
17
+ def _correct_key_string(input_string, *to_remove_strings):
18
+ """
19
+ Corrects a string by removing certain strings, stripping, and replacing some characters.
20
+
21
+ Parameters
22
+ ----------
23
+ input_string : str
24
+ The string to be corrected
25
+ *to_remove_strings : str
26
+ The strings to be removed from the input string
27
+
28
+ Returns
29
+ -------
30
+ str
31
+ The corrected string
32
+ """
33
+ # Convert the input string to lowercase
34
+ input_string = input_string.lower()
35
+ # Remove the specified strings from the input string
36
+ for to_remove_string in to_remove_strings:
37
+ input_string = input_string.replace(to_remove_string, "")
38
+ # Strip leading and trailing whitespace from the input string
39
+ input_string = input_string.strip()
40
+ # Replace '&' with 'and' and ' ' with '_' in the input string
41
+ input_string = input_string.replace("&", "and").replace(" ", "_")
42
+ return input_string
43
+
44
+
45
+ def _correct_dictionaries(input_dict):
46
+ """
47
+ Corrects the keys in a dictionary.
48
+ """
49
+ rep = dict()
50
+ for key, value in input_dict.items():
51
+ # Correct the key using the correct_key_string function
52
+ new_key = _correct_key_string(key)
53
+ # If the value is a dictionary, recursively correct its keys
54
+ if isinstance(value, dict):
55
+ for elt in value:
56
+ value[elt] = _correct_dictionaries(value[elt])
57
+ rep[new_key] = value
58
+ # If the value is not a dictionary, simply assign it to the corrected key
59
+ else:
60
+ rep[new_key] = value
61
+ return rep
62
+
63
+
64
+ def _map_record_id(record, records, keys):
65
+ """
66
+ Identifies a record_id in list of records using key.
67
+ """
68
+ global filtered_records
69
+ matches = []
70
+ # For each of the specified "keys", check if there is an entry in "records" that matches with "record"
71
+ for key in keys:
72
+ if key in record:
73
+ recval = record[key]
74
+ matches_tmp = [
75
+ r for r, v in records.items() if key in v and v[key] == recval
76
+ ]
77
+ matches = [m for m in matches_tmp if m not in filtered_records]
78
+ if len(matches) == 1:
79
+ break
80
+ if len(matches) == 1:
81
+ return matches[0]
82
+ elif len(matches) == 0:
83
+ if len(matches_tmp) == 0:
84
+ raise KeyError(f"No matches when consolidating '{record}' via '{keys}'.")
85
+ else:
86
+ raise KeyError(f"Multiple matches when consolidating '{record}'.")
87
+
88
+
89
+ def _map_attribute(attr, records, key):
90
+ """
91
+ Identifies a record_id in list of records using key and matching with the attribute value.
92
+ """
93
+ global filtered_records
94
+ # For the specified "key", check if there is an entry in "records" that matches with "attr"
95
+ matches_tmp = [r for r, v in records.items() if key in v and v[key] == attr]
96
+ matches = [m for m in matches_tmp if m not in filtered_records]
97
+ if len(matches) == 1:
98
+ return matches[0]
99
+ elif len(matches) == 0:
100
+ if len(matches_tmp) == 0:
101
+ raise KeyError(f"No matches when consolidating '{attr}' via '{key}'.")
102
+ else:
103
+ raise KeyError(f"Multiple matches when consolidating '{attr}' via '{key}'.")
104
+
105
+
106
+ def map_data(data, mapping_table):
107
+ """
108
+ Maps the data to the one-base structure using the mapping table.
109
+
110
+ Parameters
111
+ ----------
112
+ data : dict
113
+ Three-base or one-base Airtable export.
114
+ mapping_table dict
115
+ The mapping table to apply to map to one base.
116
+
117
+ Returns
118
+ -------
119
+ dict
120
+ Mapped data with one-base structure.
121
+
122
+ Note
123
+ ----
124
+ Returns the input dict if the data is already one-base.
125
+ """
126
+ logger = get_logger()
127
+ missing_bases = []
128
+ missing_tables = []
129
+ mapped_data = {"Data Request": {}}
130
+
131
+ # Reset filtered records
132
+ global filtered_records
133
+ if filtered_records:
134
+ filtered_records = []
135
+
136
+ if len(data.keys()) in [3, 4]:
137
+
138
+ # Get filtered records
139
+ for table, mapinfo in mapping_table.items():
140
+ if (
141
+ mapinfo["source_base"] in data
142
+ and mapinfo["source_table"] in data[mapinfo["source_base"]]
143
+ ):
144
+ if "internal_filters" in mapinfo:
145
+ for record_id, record in data[mapinfo["source_base"]][
146
+ mapinfo["source_table"]
147
+ ]["records"].items():
148
+ filter_results = []
149
+ for filter_key, filter_val in mapinfo[
150
+ "internal_filters"
151
+ ].items():
152
+ if filter_key not in record:
153
+ filter_results.append(False)
154
+ elif filter_val["operator"] == "nonempty":
155
+ filter_results.append(bool(record[filter_key]))
156
+ elif filter_val["operator"] == "in":
157
+ if isinstance(record[filter_key], list):
158
+ filter_results.append(
159
+ any(
160
+ fj in filter_val["values"]
161
+ for fj in record[filter_key]
162
+ )
163
+ )
164
+ else:
165
+ filter_results.append(
166
+ record[filter_key] in filter_val["values"]
167
+ )
168
+ elif filter_val["operator"] == "not in":
169
+ if isinstance(record[filter_key], list):
170
+ filter_results.append(
171
+ any(
172
+ fj not in filter_val["values"]
173
+ for fj in record[filter_key]
174
+ )
175
+ )
176
+ else:
177
+ filter_results.append(
178
+ record[filter_key] not in filter_val["values"]
179
+ )
180
+ if not all(filter_results):
181
+ logger.debug(
182
+ f"Filtered out record '{record_id}' {'('+record['name']+')' if 'name' in record else ''} from '{table}'."
183
+ )
184
+ filtered_records.append(record_id)
185
+ logger.info(f"Filtered {len(filtered_records)} records.")
186
+
187
+ # Perform mapping in case of three-base structure
188
+ for table, mapinfo in mapping_table.items():
189
+ intm = mapinfo["internal_mapping"]
190
+ if (
191
+ mapinfo["source_base"] in data
192
+ and mapinfo["source_table"] in data[mapinfo["source_base"]]
193
+ ):
194
+ # Copy the selected data to the one-base structure
195
+ logger.debug(f"Mapping '{mapinfo['source_base']}' -> '{table}'")
196
+ mapped_data["Data Request"][table] = {
197
+ **data[mapinfo["source_base"]][mapinfo["source_table"]],
198
+ "records": {
199
+ record_id: record
200
+ for record_id, record in data[mapinfo["source_base"]][
201
+ mapinfo["source_table"]
202
+ ]["records"].items()
203
+ if record_id not in filtered_records
204
+ },
205
+ }
206
+
207
+ # If record attributes require mapping
208
+ if intm != {}:
209
+ # for each attribute that requires mapping
210
+ for attr in intm.keys():
211
+ for record_id, record in data[mapinfo["source_base"]][
212
+ mapinfo["source_table"]
213
+ ]["records"].items():
214
+ if (
215
+ attr not in record
216
+ or record[attr] is None
217
+ or record[attr] == ""
218
+ or record[attr] == []
219
+ ):
220
+ logger.debug(
221
+ f"{table}: Attribute '{attr}' not found for record '{record_id}'."
222
+ )
223
+ continue
224
+ attr_vals = record[attr]
225
+
226
+ # operation
227
+ if intm[attr]["operation"] == "split":
228
+ attr_vals = re.split(r"\s*,\s*", attr_vals)
229
+ elif intm[attr]["operation"] == "":
230
+ if isinstance(attr_vals, str):
231
+ attr_vals = [attr_vals]
232
+ else:
233
+ raise ValueError(
234
+ f"Unknown internal mapping operation for attribute '{attr}' ('{mapinfo['source_table']}'): '{intm[attr]['operation']}'"
235
+ )
236
+
237
+ # Get mapped record_ids
238
+ # entry_type - single record_id or list of record_ids
239
+ # - map by record_id
240
+ if intm[attr]["entry_type"] == "record_id":
241
+ if not intm[attr]["base_copy_of_table"]:
242
+ raise ValueError(
243
+ "A copy of the table in the same base is required if 'entry_type' is set to 'record_id', "
244
+ f"but 'base_copy_of_table' is set to False: '{mapinfo['source_table']}' - '{attr}'"
245
+ )
246
+ elif not intm[attr]["base"] in data:
247
+ raise KeyError(
248
+ f"Base '{intm[attr]['base']}' not found in data."
249
+ )
250
+ elif (
251
+ intm[attr]["base_copy_of_table"]
252
+ not in data[mapinfo["source_base"]]
253
+ ):
254
+ raise KeyError(
255
+ f"Table '{intm[attr]['table']}' not found in base '{intm[attr]['base_copy']}'."
256
+ )
257
+ recordIDs_new = []
258
+ for attr_val in attr_vals:
259
+ # The record copy in the current base
260
+ record_copy = data[mapinfo["source_base"]][
261
+ intm[attr]["base_copy_of_table"]
262
+ ]["records"][attr_val]
263
+ # The entire list of records in the base of origin
264
+ recordlist = data[intm[attr]["base"]][
265
+ intm[attr]["table"]
266
+ ]["records"]
267
+ recordID_new = _map_record_id(
268
+ record_copy,
269
+ recordlist,
270
+ intm[attr]["map_by_key"],
271
+ )
272
+ if recordID_new:
273
+ recordIDs_new.append(recordID_new)
274
+ # entry_type - name (eg. unique label or similar)
275
+ # - map by attribute value
276
+ elif intm[attr]["entry_type"] == "name":
277
+ recordIDs_new = []
278
+ for attr_val in attr_vals:
279
+ recordID_new = _map_attribute(
280
+ attr_val,
281
+ data[intm[attr]["base"]][intm[attr]["table"]][
282
+ "records"
283
+ ],
284
+ (
285
+ intm[attr]["map_by_key"]
286
+ if isinstance(intm[attr]["map_by_key"], str)
287
+ else intm[attr]["map_by_key"][0]
288
+ ),
289
+ )
290
+ if recordID_new:
291
+ recordIDs_new.append(recordID_new)
292
+ else:
293
+ raise ValueError(
294
+ f"Unknown 'entry_type' specified for attribute '{attr}' ('{mapinfo['source_table']}'): '{intm[attr]['entry_type']}'"
295
+ )
296
+ if not recordIDs_new:
297
+ raise KeyError(
298
+ f"{table} (record '{record_id}'): For attribute '{attr}' no records could be mapped."
299
+ )
300
+ mapped_data["Data Request"][table]["records"][record_id][
301
+ attr
302
+ ] = recordIDs_new
303
+
304
+ else:
305
+ if mapinfo["source_base"] not in data:
306
+ missing_tables.append(mapinfo["source_base"])
307
+ elif mapinfo["source_table"] not in data[mapinfo["source_base"]]:
308
+ missing_bases.append(mapinfo["source_table"])
309
+ if len(missing_bases) > 0:
310
+ warnings.warn(
311
+ f"Encountered missing bases when consolidating the data: {set(missing_bases)}"
312
+ )
313
+ if len(missing_tables) > 0:
314
+ warnings.warn(
315
+ f"Encountered missing tables when consolidating the data: {missing_tables}"
316
+ )
317
+ return mapped_data
318
+ # Return the data if it is already one-base
319
+ elif len(data.keys()) == 1:
320
+ version = next(iter(data.keys())).replace("Data Request ", "")
321
+ mapped_data = next(iter(data.values()))
322
+ if version in version_consistency:
323
+ for tfrom, tto in version_consistency[version].items():
324
+ logger.debug(
325
+ f"Consistency across versions - renaming table: {tfrom} -> {tto}"
326
+ )
327
+ mapped_data[tto] = mapped_data.pop(tfrom)
328
+ return {"Data Request": mapped_data}
329
+ else:
330
+ raise ValueError("The loaded Data Request has an unexpected data structure.")
331
+
332
+
333
+ def transform_content(data):
334
+ """
335
+ Transform the data request content into a tidy format.
336
+
337
+ This function takes the data request content as input, tidies it up by removing
338
+ unnecessary keys and renaming others, and returns the transformed data request
339
+ and vocabulary server.
340
+
341
+ Parameters:
342
+ data (dict): The data request content to be transformed.
343
+
344
+ Returns:
345
+ tuple: A tuple containing the transformed data request and vocabulary server.
346
+ """
347
+ logger = get_logger()
348
+ global default_count
349
+
350
+ # Create an index to map record IDs to UIDs
351
+ record_to_uid_index = dict()
352
+ # Separate dreq and vocabulary information
353
+ data_request = dict()
354
+ vocabulary_server = dict()
355
+ # Get the content of the Data Request
356
+ content = data["Data Request"]
357
+
358
+ # Define the keys to remove from each table
359
+ to_remove_keys = {}
360
+
361
+ # Iterate over each table in the content
362
+ for subelt in sorted(list(content)):
363
+ for record_id in sorted(list(content[subelt]["records"])):
364
+ # Get the keys to remove for this table
365
+ if subelt in to_remove_keys:
366
+ keys_to_remove = to_remove_keys[subelt]
367
+ else:
368
+ keys_to_remove = list()
369
+
370
+ # Get the list of keys for this record
371
+ list_keys = list(content[subelt]["records"][record_id])
372
+
373
+ # Add keys that match certain patterns to the list of keys to remove
374
+ keys_to_remove.extend(
375
+ [
376
+ key
377
+ for key in list_keys
378
+ if "(MJ)" in key
379
+ or "test" in key.lower()
380
+ or ("last" in key.lower() and "modified" in key.lower())
381
+ or "count" in key.lower()
382
+ ]
383
+ )
384
+
385
+ # Remove the keys that should be removed
386
+ for key in set(keys_to_remove) & set(list_keys):
387
+ del content[subelt]["records"][record_id][key]
388
+
389
+ # Rename the "UID" key to "uid" if it exists
390
+ if "UID" in list_keys:
391
+ content[subelt]["records"][record_id]["uid"] = content[subelt][
392
+ "records"
393
+ ][record_id].pop("UID")
394
+ elif "uid" not in list_keys:
395
+ # If no "uid" key exists, create a default one
396
+ uid = default_template.format(default_count)
397
+ content[subelt]["records"][record_id]["uid"] = uid
398
+ default_count += 1
399
+ logger.debug(
400
+ f"Undefined uid for element {os.sep.join([subelt, 'records', record_id])}, set {uid}"
401
+ )
402
+
403
+ # Add the record ID to UID mapping to the index
404
+ record_to_uid_index[record_id] = content[subelt]["records"][record_id][
405
+ "uid"
406
+ ]
407
+ if (
408
+ subelt
409
+ in [
410
+ "Opportunity",
411
+ ]
412
+ and "Title of Opportunity" in list_keys
413
+ ):
414
+ content[subelt]["records"][record_id]["name"] = content[subelt][
415
+ "records"
416
+ ][record_id].pop("Title of Opportunity")
417
+ elif "name" not in list_keys and "Name" not in list_keys:
418
+ content[subelt]["records"][record_id]["name"] = "undef"
419
+
420
+ # Replace record_id by uid
421
+ logger.debug("Replace record ids by uids")
422
+ content_string = json.dumps(content)
423
+ for record_id, uid in record_to_uid_index.items():
424
+ content_string = content_string.replace(f'"{record_id}"', f'"{uid}"')
425
+ content = json.loads(content_string)
426
+
427
+ # Alternative
428
+ # for key, value in content.items():
429
+ # if isinstance(value, dict):
430
+ # content[key] = {record_to_uid_index.get(k, k): v for k, v in value.items()}
431
+ # elif isinstance(value, list):
432
+ # content[key] = [{record_to_uid_index.get(k, k): v for k, v in item.items()} if isinstance(item, dict) else item for item in value]
433
+
434
+ # Build the data request
435
+ logger.debug("Build DR and VS")
436
+ for subelt in sorted(list(content)):
437
+ if subelt in [
438
+ "Opportunity",
439
+ ]:
440
+ new_subelt = "opportunities"
441
+ data_request[new_subelt] = dict()
442
+ vocabulary_server[new_subelt] = dict()
443
+ for uid in content[subelt]["records"]:
444
+ value = content[subelt]["records"][uid]
445
+ data_request[new_subelt][uid] = dict(
446
+ experiments_groups=value.pop("Experiment Groups", list()),
447
+ variables_groups=value.pop("Variable Groups", list()),
448
+ themes=value.pop("Themes", list()),
449
+ ensemble_size=value.pop("Ensemble Size", 1),
450
+ )
451
+ vocabulary_server[new_subelt][uid] = value
452
+ elif subelt in [
453
+ "Variable Group",
454
+ ]:
455
+ new_subelt = "variable_groups"
456
+ data_request[new_subelt] = dict()
457
+ vocabulary_server[new_subelt] = dict()
458
+ for uid in content[subelt]["records"]:
459
+ value = content[subelt]["records"][uid]
460
+ data_request[new_subelt][uid] = dict(
461
+ variables=value.pop("Variables", list()),
462
+ mips=value.pop("MIPs", list()),
463
+ priority=value.pop("Priority Level", None),
464
+ )
465
+ vocabulary_server[new_subelt][uid] = value
466
+ elif subelt in [
467
+ "Experiment Group",
468
+ ]:
469
+ new_subelt = "experiment_groups"
470
+ data_request[new_subelt] = dict()
471
+ vocabulary_server[new_subelt] = dict()
472
+ for uid in content[subelt]["records"]:
473
+ value = content[subelt]["records"][uid]
474
+ data_request[new_subelt][uid] = dict(
475
+ experiments=value.pop("Experiments", list())
476
+ )
477
+ vocabulary_server[new_subelt][uid] = value
478
+ else:
479
+ vocabulary_server[subelt] = content[subelt]["records"]
480
+ return data_request, vocabulary_server
481
+
482
+
483
+ # def write_json_output_file_content(filename, content):
484
+ # with open(filename, "w") as fic:
485
+ # json.dump(content, fic, indent=4, allow_nan=True, sort_keys=True)
486
+ # data_request, vocabulary_server = transform_content(content, args.version)
487
+ # write_json_output_file_content(os.path.sep.join([output_directory, "DR_content.json"]), data_request)
488
+ # write_json_output_file_content(os.path.sep.join([output_directory, "VS_content.json"]), vocabulary_server)