roc-film 1.13.5__py3-none-any.whl → 1.14.0__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 (52) hide show
  1. roc/__init__.py +2 -1
  2. roc/film/__init__.py +2 -2
  3. roc/film/commands.py +372 -323
  4. roc/film/config/__init__.py +0 -1
  5. roc/film/constants.py +101 -65
  6. roc/film/descriptor.json +127 -96
  7. roc/film/exceptions.py +28 -27
  8. roc/film/tasks/__init__.py +16 -16
  9. roc/film/tasks/cat_solo_hk.py +86 -74
  10. roc/film/tasks/cdf_postpro.py +438 -309
  11. roc/film/tasks/check_dds.py +39 -45
  12. roc/film/tasks/db_to_anc_bia_sweep_table.py +381 -0
  13. roc/film/tasks/dds_to_l0.py +232 -180
  14. roc/film/tasks/export_solo_coord.py +147 -0
  15. roc/film/tasks/file_handler.py +91 -75
  16. roc/film/tasks/l0_to_hk.py +117 -103
  17. roc/film/tasks/l0_to_l1_bia_current.py +38 -30
  18. roc/film/tasks/l0_to_l1_bia_sweep.py +417 -329
  19. roc/film/tasks/l0_to_l1_sbm.py +250 -208
  20. roc/film/tasks/l0_to_l1_surv.py +185 -130
  21. roc/film/tasks/make_daily_tm.py +40 -37
  22. roc/film/tasks/merge_tcreport.py +77 -71
  23. roc/film/tasks/merge_tmraw.py +101 -88
  24. roc/film/tasks/parse_dds_xml.py +21 -20
  25. roc/film/tasks/set_l0_utc.py +51 -49
  26. roc/film/tests/cdf_compare.py +565 -0
  27. roc/film/tests/hdf5_compare.py +84 -62
  28. roc/film/tests/test_dds_to_l0.py +93 -51
  29. roc/film/tests/test_dds_to_tc.py +8 -11
  30. roc/film/tests/test_dds_to_tm.py +8 -10
  31. roc/film/tests/test_film.py +161 -116
  32. roc/film/tests/test_l0_to_hk.py +64 -36
  33. roc/film/tests/test_l0_to_l1_bia.py +10 -14
  34. roc/film/tests/test_l0_to_l1_sbm.py +14 -19
  35. roc/film/tests/test_l0_to_l1_surv.py +68 -41
  36. roc/film/tests/test_metadata.py +21 -20
  37. roc/film/tests/tests.py +743 -396
  38. roc/film/tools/__init__.py +5 -5
  39. roc/film/tools/dataset_tasks.py +34 -2
  40. roc/film/tools/file_helpers.py +390 -269
  41. roc/film/tools/l0.py +402 -324
  42. roc/film/tools/metadata.py +147 -127
  43. roc/film/tools/skeleton.py +12 -17
  44. roc/film/tools/tools.py +109 -92
  45. roc/film/tools/xlsx2skt.py +161 -139
  46. {roc_film-1.13.5.dist-info → roc_film-1.14.0.dist-info}/LICENSE +127 -125
  47. roc_film-1.14.0.dist-info/METADATA +60 -0
  48. roc_film-1.14.0.dist-info/RECORD +50 -0
  49. {roc_film-1.13.5.dist-info → roc_film-1.14.0.dist-info}/WHEEL +1 -1
  50. roc/film/tasks/l0_to_anc_bia_sweep_table.py +0 -348
  51. roc_film-1.13.5.dist-info/METADATA +0 -120
  52. roc_film-1.13.5.dist-info/RECORD +0 -48
roc/film/tools/tools.py CHANGED
@@ -17,32 +17,38 @@ from poppy.core.generic.metaclasses import Singleton
17
17
  from poppy.core.configuration import Configuration
18
18
  from poppy.core.generic.paths import Paths
19
19
  from poppy.core.logger import logger
20
- from roc.film.constants import _ROOT_DIRECTORY, INPUT_DATETIME_STRFTIME, \
21
- DATA_VERSION, TIME_DAILY_STRFORMAT
20
+ from roc.film.constants import (
21
+ _ROOT_DIRECTORY,
22
+ INPUT_DATETIME_STRFTIME,
23
+ DATA_VERSION,
24
+ TIME_DAILY_STRFORMAT,
25
+ )
22
26
 
23
27
  from roc.film.exceptions import FilmException, HandlingFileError
24
28
 
25
- __all__ = ['paths', 'DESCRIPTOR',
26
- 'raise_error',
27
- 'valid_time',
28
- 'valid_date',
29
- 'valid_data_version',
30
- 'valid_single_file',
31
- 'valid_dir',
32
- 'extract_datetime',
33
- 'extract_file_fields',
34
- 'get_datasets',
35
- 'sort_indices',
36
- 'unique_dict_list',
37
- 'sort_dict_list',
38
- 'safe_move',
39
- 'setup_lock',
40
- 'get_latest_file',
41
- 'Map',
42
- 'glob_list',
43
- 'move_to_trash',
44
- 'decode',
45
- ]
29
+ __all__ = [
30
+ "paths",
31
+ "DESCRIPTOR",
32
+ "raise_error",
33
+ "valid_time",
34
+ "valid_date",
35
+ "valid_data_version",
36
+ "valid_single_file",
37
+ "valid_dir",
38
+ "extract_datetime",
39
+ "extract_file_fields",
40
+ "get_datasets",
41
+ "sort_indices",
42
+ "unique_dict_list",
43
+ "sort_dict_list",
44
+ "safe_move",
45
+ "setup_lock",
46
+ "get_latest_file",
47
+ "Map",
48
+ "glob_list",
49
+ "move_to_trash",
50
+ "decode",
51
+ ]
46
52
 
47
53
  # ________________ Global Variables _____________
48
54
  # (define here the global variables)
@@ -65,20 +71,18 @@ def get_descriptor():
65
71
  """
66
72
 
67
73
  class Descriptor(object, metaclass=Singleton):
68
-
69
74
  def __init__(self):
70
-
71
- descriptor = paths.from_root('descriptor.json')
75
+ descriptor = paths.from_root("descriptor.json")
72
76
 
73
77
  # Get descriptor content
74
- with open(descriptor, 'r') as file_buffer:
78
+ with open(descriptor, "r") as file_buffer:
75
79
  for key, val in json.load(file_buffer).items():
76
80
  setattr(self, key, val)
77
81
 
78
82
  # Re-organize task section
79
83
  tasks = dict()
80
84
  for task in self.tasks:
81
- tasks[task['name']] = task
85
+ tasks[task["name"]] = task
82
86
 
83
87
  self.tasks = tasks
84
88
 
@@ -107,8 +111,9 @@ def valid_time(t, format=INPUT_DATETIME_STRFTIME):
107
111
  try:
108
112
  return datetime.strptime(t, format)
109
113
  except ValueError:
110
- raise_error(f"Not a valid datetime: '{t}'.",
111
- exception=argparse.ArgumentTypeError)
114
+ raise_error(
115
+ f"Not a valid datetime: '{t}'.", exception=argparse.ArgumentTypeError
116
+ )
112
117
 
113
118
 
114
119
  def valid_date(t, format=TIME_DAILY_STRFORMAT):
@@ -123,8 +128,9 @@ def valid_date(t, format=TIME_DAILY_STRFORMAT):
123
128
  try:
124
129
  return datetime.strptime(t, format)
125
130
  except ValueError:
126
- raise_error(f"Not a valid date: '{t}'.",
127
- exception=argparse.ArgumentTypeError)
131
+ raise_error(
132
+ f"Not a valid date: '{t}'.", exception=argparse.ArgumentTypeError
133
+ )
128
134
 
129
135
 
130
136
  def valid_data_version(data_version):
@@ -138,9 +144,9 @@ def valid_data_version(data_version):
138
144
  if isinstance(data_version, list):
139
145
  data_version = data_version[0]
140
146
  data_version = int(data_version)
141
- return f'{data_version:02d}'
147
+ return f"{data_version:02d}"
142
148
  except ValueError:
143
- raise_error(f'Input value for --data-version is not valid! ({data_version})')
149
+ raise_error(f"Input value for --data-version is not valid! ({data_version})")
144
150
 
145
151
 
146
152
  def valid_single_file(file):
@@ -158,11 +164,11 @@ def valid_single_file(file):
158
164
  else:
159
165
  raise FileNotFoundError
160
166
  except FileNotFoundError:
161
- raise_error(f'Input file not found! ({file})', exception=FileNotFoundError)
167
+ raise_error(f"Input file not found! ({file})", exception=FileNotFoundError)
162
168
  except ValueError:
163
- raise_error(f'Input file is not valid! ({file})', exception=ValueError)
169
+ raise_error(f"Input file is not valid! ({file})", exception=ValueError)
164
170
  except Exception as e:
165
- raise_error(f'Problem with input file! ({file})', exception=e)
171
+ raise_error(f"Problem with input file! ({file})", exception=e)
166
172
 
167
173
 
168
174
  def valid_dir(dir):
@@ -180,11 +186,11 @@ def valid_dir(dir):
180
186
  else:
181
187
  raise IsADirectoryError
182
188
  except IsADirectoryError:
183
- raise_error(f'Input directory not found! ({dir})', exception=IsADirectoryError)
189
+ raise_error(f"Input directory not found! ({dir})", exception=IsADirectoryError)
184
190
  except ValueError:
185
- raise_error(f'Input directory is not valid! ({dir})', exception=ValueError)
191
+ raise_error(f"Input directory is not valid! ({dir})", exception=ValueError)
186
192
  except Exception as e:
187
- raise_error(f'Problem with input directory! ({dir})', exception=e)
193
+ raise_error(f"Problem with input directory! ({dir})", exception=e)
188
194
 
189
195
 
190
196
  def unique_dates(utc_times):
@@ -212,14 +218,15 @@ def extract_datetime(str_datetime):
212
218
  :return: 2-elements list containing Datetime start/end time (if input Datetime has a daily format, return the day twice).
213
219
  """
214
220
 
215
- str_datetime_list = str_datetime.split('-')
221
+ str_datetime_list = str_datetime.split("-")
216
222
  if len(str_datetime_list) == 1:
217
- out_datetime = [datetime.strptime(str_datetime, '%Y%m%d')] * 2
223
+ out_datetime = [datetime.strptime(str_datetime, "%Y%m%d")] * 2
218
224
  elif len(str_datetime_list) == 2:
219
- out_datetime = [datetime.strptime(
220
- dt, '%Y%m%dT%H%M%S') for dt in str_datetime_list]
225
+ out_datetime = [
226
+ datetime.strptime(dt, "%Y%m%dT%H%M%S") for dt in str_datetime_list
227
+ ]
221
228
  else:
222
- logger.error(f'Wrong input datetime format: {str_datetime}')
229
+ logger.error(f"Wrong input datetime format: {str_datetime}")
223
230
  return None
224
231
 
225
232
  return out_datetime
@@ -251,30 +258,29 @@ def get_datasets(task, task_name):
251
258
  """
252
259
 
253
260
  # Get dataset JSON file provided as an input argument (if any)
254
- dataset_file = task.pipeline.get(
255
- 'dataset_file', default=[None], args=True)[0]
261
+ dataset_file = task.pipeline.get("dataset_file", default=[None], args=True)[0]
256
262
  # Get --dataset input keyword value (if any)
257
- dataset_names = task.pipeline.get('dataset', default=[None], args=True)
263
+ dataset_names = task.pipeline.get("dataset", default=[None], args=True)
258
264
  # Get --data-version input keyword value (if any)
259
- data_version = task.pipeline.get('data_version', default=[
260
- DATA_VERSION], args=True)[0]
265
+ data_version = task.pipeline.get("data_version", default=[DATA_VERSION], args=True)[
266
+ 0
267
+ ]
261
268
 
262
269
  # Get task output dataset description list from the descriptor.json file
263
- task_output_list = DESCRIPTOR.tasks[task_name]['outputs']
270
+ task_output_list = DESCRIPTOR.tasks[task_name]["outputs"]
264
271
 
265
272
  # If dataset JSON file passed as an value of the --dataset_file input
266
273
  # keyword, load list of datasets to create and related data_version
267
274
  # (optional)
268
275
  if dataset_file and os.path.isfile(dataset_file):
269
- with open(dataset_file, 'r') as file_buff:
276
+ with open(dataset_file, "r") as file_buff:
270
277
  # Loop over dataset array in the JSON file to get the name and
271
278
  # optionally the version of the output file
272
279
  dataset_to_create = []
273
280
  data_versions = []
274
- for current_dataset_obj in json.load(file_buff)['dataset']:
275
- dataset_to_create.append(current_dataset_obj['name'])
276
- data_versions.append(
277
- current_dataset_obj.get('version', data_version))
281
+ for current_dataset_obj in json.load(file_buff)["dataset"]:
282
+ dataset_to_create.append(current_dataset_obj["name"])
283
+ data_versions.append(current_dataset_obj.get("version", data_version))
278
284
  elif dataset_names[0]:
279
285
  # Else if dataset list passed as values of the --dataset input keyword
280
286
  dataset_to_create = dataset_names
@@ -282,22 +288,25 @@ def get_datasets(task, task_name):
282
288
  else:
283
289
  # Else load all the output datasets listed in descriptor for the given
284
290
  # task by default
285
- dataset_to_create = list(DESCRIPTOR.tasks[task_name]['outputs'].keys())
291
+ dataset_to_create = list(DESCRIPTOR.tasks[task_name]["outputs"].keys())
286
292
  data_versions = [data_version] * len(dataset_to_create)
287
293
 
288
294
  # Retrieve dataset info from descriptor.json
289
295
  dataset_list = []
290
296
  for i, dataset_name in enumerate(dataset_to_create):
291
-
292
297
  # Check if current dataset is indeed a output dataset of the task (as
293
298
  # described in the descriptor.json file)
294
299
  if dataset_name not in task_output_list:
295
- logger.warning(f'{dataset_name} is not a valid dataset of the task {task_name}!')
300
+ logger.warning(
301
+ f"{dataset_name} is not a valid dataset of the task {task_name}!"
302
+ )
296
303
  else:
297
304
  # if yes, get description and store info in the dataset_list list
298
- current_dataset = {'name': dataset_name,
299
- 'version': data_versions[i],
300
- 'descr': task_output_list[dataset_name]}
305
+ current_dataset = {
306
+ "name": dataset_name,
307
+ "version": data_versions[i],
308
+ "descr": task_output_list[dataset_name],
309
+ }
301
310
  dataset_list.append(current_dataset)
302
311
 
303
312
  return dataset_list
@@ -310,7 +319,7 @@ def unique_dict_list(list_of_dict):
310
319
  :param list_of_dict: List of dict to unify
311
320
  :return: return list inside which each dict is unique
312
321
  """
313
- return [i for n, i in enumerate(list_of_dict) if i not in list_of_dict[n + 1:]]
322
+ return [i for n, i in enumerate(list_of_dict) if i not in list_of_dict[n + 1 :]]
314
323
 
315
324
 
316
325
  def sort_dict_list(list_of_dict, key):
@@ -333,8 +342,7 @@ def sort_indices(list_to_sort):
333
342
  :return: list of sorted indices
334
343
  """
335
344
 
336
- return sorted(range(len(list_to_sort)),
337
- key=lambda k: list_to_sort[k])
345
+ return sorted(range(len(list_to_sort)), key=lambda k: list_to_sort[k])
338
346
 
339
347
 
340
348
  def safe_move(src, dst, ignore_patterns=[]):
@@ -355,11 +363,14 @@ def safe_move(src, dst, ignore_patterns=[]):
355
363
  if os.path.isfile(src):
356
364
  shutil.copy(src, dst, follow_symlinks=True)
357
365
  elif os.path.isdir(src):
358
- shutil.copytree(src, dst,
359
- ignore=shutil.ignore_patterns(ignore_patterns),
360
- dirs_exist_ok=True)
366
+ shutil.copytree(
367
+ src,
368
+ dst,
369
+ ignore=shutil.ignore_patterns(ignore_patterns),
370
+ dirs_exist_ok=True,
371
+ )
361
372
  except Exception:
362
- raise HandlingFileError(f'Cannot move {src} into {dst}!')
373
+ raise HandlingFileError(f"Cannot move {src} into {dst}!")
363
374
  else:
364
375
  # then delete if the file has well copied
365
376
  if os.path.exists(dst):
@@ -382,10 +393,11 @@ def setup_lock(pipeline):
382
393
  """
383
394
 
384
395
  # Retrieve lock_file input argument value
385
- lock_file = pipeline.get('lock_file', default=[None], args=True)[0]
396
+ lock_file = pipeline.get("lock_file", default=[None], args=True)[0]
386
397
  if lock_file is not None:
387
398
  # Retrieve output directory path
388
399
  from roc.film.tools.file_helpers import get_output_dir
400
+
389
401
  output_dir = get_output_dir(pipeline)
390
402
 
391
403
  # Set the value of Pipeline.lock attribute filename
@@ -403,9 +415,9 @@ def sort_cdf_by_epoch(cdf, descending=False, zvar_list=[]):
403
415
  """
404
416
 
405
417
  try:
406
- epoch = cdf['Epoch']
418
+ epoch = cdf["Epoch"]
407
419
  except Exception:
408
- logger.error('Cannot get Epoch zVariable from input CDF!')
420
+ logger.error("Cannot get Epoch zVariable from input CDF!")
409
421
  return cdf
410
422
 
411
423
  sorted_idx = np.argsort(epoch[...])
@@ -417,18 +429,20 @@ def sort_cdf_by_epoch(cdf, descending=False, zvar_list=[]):
417
429
 
418
430
  for zvar in zvar_list:
419
431
  current_zvar = cdf[zvar][...]
420
- current_zvar = current_zvar[sorted_idx, ]
432
+ current_zvar = current_zvar[sorted_idx,]
421
433
  cdf[zvar] = current_zvar
422
434
 
423
435
  return cdf
424
436
 
425
437
 
426
- def extract_file_fields(rpw_file,
427
- get_source=False,
428
- get_level=False,
429
- get_descriptor=False,
430
- get_datetime=False,
431
- get_version=False):
438
+ def extract_file_fields(
439
+ rpw_file,
440
+ get_source=False,
441
+ get_level=False,
442
+ get_descriptor=False,
443
+ get_datetime=False,
444
+ get_version=False,
445
+ ):
432
446
  """
433
447
  Extract RPW file fields (assuming SolO file naming standards)
434
448
 
@@ -440,7 +454,7 @@ def extract_file_fields(rpw_file,
440
454
  :param get_version: return only data version field
441
455
  :return: list of file fields (or a scalar with expected field)
442
456
  """
443
- fields = os.path.splitext(os.path.basename(rpw_file))[0].split('_')
457
+ fields = os.path.splitext(os.path.basename(rpw_file))[0].split("_")
444
458
 
445
459
  if len(fields) < 5:
446
460
  logger.warning(f'Cannot extract file fields: invalid input file "{rpw_file}"!')
@@ -497,12 +511,14 @@ class Map(dict):
497
511
  del self.__dict__[key]
498
512
 
499
513
 
500
- def glob_list(list_of_files):
514
+ def glob_list(list_of_files: list) -> list:
501
515
  """
502
516
  Perform glob.glob on a list of input files.
503
517
 
504
- :param list_of_files: List of input files (passed as strings)
518
+ :param list_of_files: List of input files (strings)
519
+ :type:list
505
520
  :return: list of files globbed
521
+ :rtype: list
506
522
  """
507
523
  output_list = []
508
524
  for current_file in list_of_files:
@@ -526,7 +542,7 @@ def move_to_trash(file_or_dir):
526
542
  is_file = False
527
543
 
528
544
  try:
529
- logger.debug(f'Moving {file_or_dir} into {trash_dir}')
545
+ logger.debug(f"Moving {file_or_dir} into {trash_dir}")
530
546
  target_path = os.path.join(trash_dir, os.path.basename(file_or_dir))
531
547
  shutil.copyfile(file_or_dir, target_path)
532
548
  if os.path.exists(target_path):
@@ -536,7 +552,7 @@ def move_to_trash(file_or_dir):
536
552
  else:
537
553
  shutil.rmtree(file_or_dir)
538
554
  except Exception:
539
- logger.exception(f'Moving {file_or_dir} into {trash_dir} has failed!')
555
+ logger.exception(f"Moving {file_or_dir} into {trash_dir} has failed!")
540
556
  target_path = None
541
557
 
542
558
  return target_path
@@ -551,18 +567,17 @@ def get_trash_dir():
551
567
  """
552
568
 
553
569
  # Get trash folder path
554
- if 'ROC_PIP_TRASH_DIR' in Configuration.manager['pipeline']['environment']:
555
- trash_dir = Configuration.manager['pipeline'][
556
- 'environment.ROC_PIP_TRASH_DIR']
557
- elif 'ROC_PIP_TRASH_DIR' in os.environ:
558
- trash_dir = os.environ['ROC_PIP_TRASH_DIR']
570
+ if "ROC_PIP_TRASH_DIR" in Configuration.manager["pipeline"]["environment"]:
571
+ trash_dir = Configuration.manager["pipeline"]["environment.ROC_PIP_TRASH_DIR"]
572
+ elif "ROC_PIP_TRASH_DIR" in os.environ:
573
+ trash_dir = os.environ["ROC_PIP_TRASH_DIR"]
559
574
  else:
560
- raise MissingProperty('ROC_PIP_TRASH_DIR variable is not defined!')
575
+ raise MissingProperty("ROC_PIP_TRASH_DIR variable is not defined!")
561
576
 
562
577
  return trash_dir
563
578
 
564
579
 
565
- def decode(binary, encoding='UTF-8'):
580
+ def decode(binary, encoding="UTF-8"):
566
581
  """
567
582
  Decode input binary into string.
568
583
 
@@ -575,10 +590,12 @@ def decode(binary, encoding='UTF-8'):
575
590
  elif isinstance(binary, list):
576
591
  return [element.decode(encoding) for element in binary]
577
592
  elif isinstance(binary, np.ndarray):
593
+
578
594
  def f(x):
579
595
  return x.decode(encoding)
596
+
580
597
  return np.vectorize(f)(binary)
581
598
  elif isinstance(binary, bytes):
582
599
  return binary.decode(encoding)
583
600
  else:
584
- raise ValueError(f'Input binary type ({type(binary)}) is not valid!')
601
+ raise ValueError(f"Input binary type ({type(binary)}) is not valid!")