fprime-gds 4.0.0a4__py3-none-any.whl → 4.0.0a6__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.
@@ -128,7 +128,13 @@ class Dictionaries:
128
128
  msg = f"[ERROR] Dictionary '{dictionary}' does not exist."
129
129
  raise Exception(msg)
130
130
  # Check for packet specification
131
- if self._metadata["dictionary_type"] == "json":
131
+ if packet_spec is not None:
132
+ packet_loader = fprime_gds.common.loaders.pkt_xml_loader.PktXmlLoader()
133
+ self._packet_dict = packet_loader.get_id_dict(
134
+ packet_spec, self._channel_name_dict
135
+ )
136
+ # Otherwise use JSON dictionary to attempt automatic packet loading
137
+ elif self._metadata["dictionary_type"] == "json":
132
138
  packet_loader = fprime_gds.common.loaders.pkt_json_loader.PktJsonLoader(dictionary)
133
139
  if packet_set_name is None:
134
140
  names = packet_loader.get_packet_set_names(None)
@@ -141,11 +147,6 @@ class Dictionaries:
141
147
  self._packet_dict = packet_loader.get_id_dict(
142
148
  None, packet_set_name, self._channel_name_dict
143
149
  )
144
- elif packet_spec is not None:
145
- packet_loader = fprime_gds.common.loaders.pkt_xml_loader.PktXmlLoader(dictionary)
146
- self._packet_dict = packet_loader.get_id_dict(
147
- packet_spec, self._channel_name_dict
148
- )
149
150
  else:
150
151
  self._packet_dict = None
151
152
 
@@ -11,6 +11,7 @@ import signal
11
11
  import time
12
12
  from pathlib import Path
13
13
  import shutil
14
+ import json
14
15
 
15
16
  from fprime.common.models.serialize.time_type import TimeType
16
17
 
@@ -30,15 +31,17 @@ class IntegrationTestAPI(DataHandler):
30
31
 
31
32
  NOW = "NOW"
32
33
 
33
- def __init__(self, pipeline, logpath=None, fsw_order=True):
34
+ def __init__(self, pipeline, deployment_config=None, logpath=None, fsw_order=True):
34
35
  """
35
36
  Initializes API: constructs and registers test histories.
36
37
  Args:
37
38
  pipeline: a pipeline object providing access to basic GDS functionality
39
+ deployment_config: path to deployment configuration file
38
40
  logpath: an optional output destination for the api test log
39
41
  fsw_order: a flag to determine whether the API histories will maintain FSW time order.
40
42
  """
41
43
  self.pipeline = pipeline
44
+ self.deployment_config = deployment_config
42
45
 
43
46
  # these are owned by the GDS and will not be modified by the test API.
44
47
  self.aggregate_command_history = pipeline.histories.commands
@@ -228,11 +231,29 @@ class IntegrationTestAPI(DataHandler):
228
231
 
229
232
  def get_deployment(self):
230
233
  """
231
- Get the deployment of the target using the loaded FSW dictionary path
234
+ Get the deployment of the target using the loaded FSW dictionary.
235
+
232
236
  Returns:
233
- The name of the deployment (str)
234
- """
235
- return Path(self.pipeline.dictionary_path).parent.parent.name
237
+ The name of the deployment (str) or None if not found
238
+ """
239
+ dictionary = str(self.pipeline.dictionary_path)
240
+
241
+ try:
242
+ with open(dictionary, 'r') as file:
243
+ data = json.load(file)
244
+ return data['metadata'].get("deploymentName")
245
+ except FileNotFoundError:
246
+ msg = f"Error: File not found at path: {dictionary}"
247
+ self.__log(msg, TestLogger.YELLOW)
248
+ return None
249
+ except json.JSONDecodeError as e:
250
+ msg = f"Error decoding JSON: {e}"
251
+ self.__log(msg, TestLogger.YELLOW)
252
+ return None
253
+ except Exception as e:
254
+ msg = f"An unexpected error occurred: {e} is an unknown key"
255
+ self.__log(msg, TestLogger.YELLOW)
256
+ return None
236
257
 
237
258
  def wait_for_dataflow(self, count=1, channels=None, start=None, timeout=120):
238
259
  """
@@ -257,6 +278,90 @@ class IntegrationTestAPI(DataHandler):
257
278
  assert False, msg
258
279
  self.remove_telemetry_subhistory(history)
259
280
 
281
+ def get_config_file_path(self):
282
+ """
283
+ Accessor for IntegrationTestAPI's deployment configuration file.
284
+
285
+ Returns:
286
+ path to user-specified deployment configuration file (str) or None if not defined
287
+ """
288
+ if self.deployment_config:
289
+ return self.deployment_config
290
+ else:
291
+ return None
292
+
293
+ def load_config_file(self):
294
+ """
295
+ Load user-specified deployment configuration JSON file.
296
+
297
+ Returns:
298
+ JSON object as a dictionary
299
+ """
300
+ config_file = self.get_config_file_path()
301
+
302
+ try:
303
+ with open(config_file, 'r') as file:
304
+ result = json.load(file)
305
+ return result
306
+ except FileNotFoundError:
307
+ msg = f"Error: File not found at path {config_file}"
308
+ self.__log(msg, TestLogger.RED)
309
+ assert False, msg
310
+ except json.JSONDecodeError as e:
311
+ msg = f"Error decoding JSON: {e}"
312
+ self.__log(msg, TestLogger.RED)
313
+ assert False, msg
314
+ except Exception as e:
315
+ msg = f"An unexpected error occurred: {e}"
316
+ self.__log(msg, TestLogger.RED)
317
+ assert False, msg
318
+
319
+ def get_mnemonic(self, comp=None, name=None):
320
+ """
321
+ Get deployment mnemonic of specified item from user-specified deployment
322
+ configuration file.
323
+
324
+ Args:
325
+ comp: qualified name of the component instance (str), i.e. "<component>.<instance>"
326
+ name: command, channel, or event name (str) [optional]
327
+ Returns:
328
+ deployment mnemonic of specified item (str) or native mnemonic (str) if not found
329
+ """
330
+ data = self.load_config_file()
331
+
332
+ if data:
333
+ try:
334
+ mnemonic = data[comp]
335
+ return f"{mnemonic}.{name}" if name else f"{mnemonic}"
336
+ except KeyError:
337
+ self.__log(f"Error: {comp} not found", TestLogger.YELLOW)
338
+ return f"{comp}.{name}" if name else f"{comp}"
339
+ else:
340
+ return f"{comp}.{name}" if name else f"{comp}"
341
+
342
+ def get_prm_db_path(self) -> str:
343
+ """
344
+ Get file path to parameter db from user-specified deployment configuration file.
345
+
346
+ Returns:
347
+ file path to parameter db (str) or None if not found
348
+ """
349
+ data = self.load_config_file()
350
+
351
+ if data:
352
+ try:
353
+ filepath = data["Svc.PrmDb.filename"]
354
+ if filepath.startswith('/'):
355
+ return filepath
356
+ else:
357
+ msg = f"Error: {filepath} did not start with a forward slash"
358
+ self.__log(msg, TestLogger.RED)
359
+ assert False, msg
360
+ except KeyError:
361
+ return None
362
+ else:
363
+ return None
364
+
260
365
  ######################################################################################
261
366
  # History Functions
262
367
  ######################################################################################
@@ -52,6 +52,12 @@ def pytest_addoption(parser):
52
52
  action="store_true",
53
53
  help="Enable JUnitXML report generation to a specified location"
54
54
  )
55
+ # Add an option to specify a json config file that maps components
56
+ parser.addoption(
57
+ "--deployment-config",
58
+ action="store",
59
+ help="Path to JSON configuration file for mapping deployment components"
60
+ )
55
61
 
56
62
  def pytest_configure(config):
57
63
  """ This is a hook to allow plugins and conftest files to perform initial configuration
@@ -85,6 +91,7 @@ def fprime_test_api_session(request):
85
91
  pipeline_parser = StandardPipelineParser()
86
92
  pipeline = None
87
93
  api = None
94
+ deployment_config = None
88
95
  try:
89
96
  # Parse the command line arguments into a client connection
90
97
  arg_ns = pipeline_parser.handle_arguments(request.config.known_args_namespace, client=True)
@@ -92,8 +99,12 @@ def fprime_test_api_session(request):
92
99
  # Build a new pipeline with the parsed and processed arguments
93
100
  pipeline = pipeline_parser.pipeline_factory(arg_ns, pipeline)
94
101
 
102
+ # Get deployment configuration from command line arguments
103
+ if request.config.option.deployment_config:
104
+ deployment_config = request.config.option.deployment_config
105
+
95
106
  # Build and set up the integration test api
96
- api = IntegrationTestAPI(pipeline, arg_ns.logs)
107
+ api = IntegrationTestAPI(pipeline, deployment_config, arg_ns.logs)
97
108
  api.setup()
98
109
 
99
110
  # Return the API. Note: the second call here-in will begin after the yield and clean-up after the test
@@ -237,14 +237,18 @@ class GdsStandardApp(GdsApp):
237
237
  arguments needed for the given parsers. When main is loaded, it will dispatch to the sub-classing plugin's
238
238
  start method. The subclassing plugin will already have had the arguments supplied via the PluginParser's
239
239
  construction of plugin objects.
240
+
241
+ Returns:
242
+ list of arguments to pass to subprocess
240
243
  """
241
244
  cls = self.__class__.__name__
242
245
  module = self.__class__.__module__
243
246
 
244
- namespace = Namespace(**self.arguments)
245
- args = CompositeParser(
247
+ composite_parser = CompositeParser(
246
248
  [self.get_cli_parser(), StandardPipelineParser]
247
- ).reproduce_cli_args(namespace)
249
+ )
250
+ namespace, _, _ = ParserBase.parse_known_args([composite_parser])
251
+ args = composite_parser.reproduce_cli_args(namespace)
248
252
  return [sys.executable, "-c", f"import {module}\n{module}.{cls}.main()"] + args
249
253
 
250
254
  @classmethod
@@ -260,9 +264,10 @@ class GdsStandardApp(GdsApp):
260
264
  # triggered by the code above that turns it off in the not-setup case.
261
265
  except AssertionError:
262
266
  pass
267
+ plugin_name = getattr(cls, "get_name", lambda: cls.__name__)()
263
268
  parsed_arguments, _ = ParserBase.parse_args(
264
269
  [cls.get_cli_parser(), StandardPipelineParser, PluginArgumentParser],
265
- f"{cls.get_name()}: a standard app plugin",
270
+ f"{plugin_name}: a standard app plugin",
266
271
  )
267
272
  pipeline = StandardPipeline()
268
273
  # Turn off history and filing
@@ -72,7 +72,7 @@ import json
72
72
  import os
73
73
  import sys
74
74
  from typing import List, Dict, Union, ForwardRef
75
- from pydantic import BaseModel, field_validator
75
+ from pydantic import BaseModel, field_validator, computed_field, model_validator
76
76
  from typing import List, Union
77
77
  import argparse
78
78
  from binascii import crc32
@@ -88,128 +88,7 @@ class bcolors:
88
88
  UNDERLINE = '\033[4m'
89
89
 
90
90
 
91
- # This defines the data in the container header. When this is ultimately defined in the json dictionary,
92
- # then this can be removed.
93
- header_data = {
94
- "typeDefinitions" : [
95
- {
96
- "kind": "array",
97
- "qualifiedName": "UserDataArray",
98
- "size": 32,
99
- "elementType": {
100
- "name": "U8",
101
- "kind": "integer",
102
- "signed": False,
103
- "size": 8
104
- }
105
- },
106
-
107
- {
108
- "kind": "struct",
109
- "qualifiedName": "timeStruct",
110
- "members": {
111
- "seconds": {
112
- "type": {
113
- "name": "U32",
114
- "kind": "integer",
115
- "signed": False,
116
- "size": 32
117
- }
118
- },
119
- "useconds": {
120
- "type": {
121
- "name": "U32",
122
- "kind": "integer",
123
- "signed": False,
124
- "size": 32
125
- }
126
- },
127
- "timeBase": {
128
- "type": {
129
- "name": "U16",
130
- "kind": "integer",
131
- "signed": False,
132
- "size": 16
133
- }
134
- },
135
- "context": {
136
- "type": {
137
- "name": "U8",
138
- "kind": "integer",
139
- "signed": False,
140
- "size": 8
141
- }
142
- }
143
- }
144
- }
145
- ],
146
-
147
- "enums" : [
148
- ],
149
-
150
- "header": {
151
- "PacketDescriptor": {
152
- "type": {
153
- "name": "U32",
154
- "kind": "integer",
155
- "signed": False,
156
- "size": 32
157
- }
158
- },
159
- "Id": {
160
- "type": {
161
- "name": "U32",
162
- "kind": "integer",
163
- "signed": False,
164
- "size": 32
165
- }
166
- },
167
- "Priority": {
168
- "type": {
169
- "name": "U32",
170
- "kind": "integer",
171
- "signed": False,
172
- "size": 32
173
- }
174
- },
175
- "TimeTag": {
176
- "type": {
177
- "name": "timeStruct",
178
- "kind": "qualifiedIdentifier"
179
- }
180
- },
181
- "ProcTypes": {
182
- "type": {
183
- "name": "U8",
184
- "kind": "integer",
185
- "signed": False,
186
- "size": 8
187
- }
188
- },
189
- "UserData": {
190
- "type": {
191
- "name": "UserDataArray",
192
- "kind": "qualifiedIdentifier"
193
- }
194
- },
195
- "DpState": {
196
- "type": {
197
- "name": "U8",
198
- "kind": "integer",
199
- "signed": False,
200
- "size": 8
201
- }
202
- },
203
- "DataSize": {
204
- "type": {
205
- "name": "U16",
206
- "kind": "integer",
207
- "signed": False,
208
- "size": 16
209
- }
210
- }
211
- },
212
-
91
+ header_hash_data = {
213
92
  "headerHash": {
214
93
  "type": {
215
94
  "name": "U32",
@@ -218,25 +97,6 @@ header_data = {
218
97
  "size": 32
219
98
  }
220
99
  },
221
-
222
- "dataId": {
223
- "type": {
224
- "name": "U32",
225
- "kind": "integer",
226
- "signed": False,
227
- "size": 32
228
- }
229
- },
230
-
231
- "dataSize": {
232
- "type": {
233
- "name": "U16",
234
- "kind": "integer",
235
- "signed": False,
236
- "size": 16
237
- }
238
- },
239
-
240
100
  "dataHash": {
241
101
  "type": {
242
102
  "name": "U32",
@@ -305,9 +165,21 @@ class BoolType(BaseModel):
305
165
  if v != "bool":
306
166
  raise ValueError('Check the "kind" field')
307
167
  return v
168
+
169
+ class StringType(BaseModel):
170
+ name: str
171
+ kind: str
172
+ size: int
173
+
174
+ @field_validator('kind')
175
+ def kind_qualifiedIdentifier(cls, v):
176
+ if v != "string":
177
+ raise ValueError('Check the "kind" field')
178
+ return v
308
179
 
309
180
  Type = ForwardRef('Type')
310
181
  ArrayType = ForwardRef('ArrayType')
182
+ AliasType = ForwardRef('AliasType')
311
183
 
312
184
  class QualifiedType(BaseModel):
313
185
  kind: str
@@ -320,7 +192,7 @@ class QualifiedType(BaseModel):
320
192
  return v
321
193
 
322
194
  class StructMember(BaseModel):
323
- type: Union[IntegerType, FloatType, BoolType, QualifiedType]
195
+ type: Union[IntegerType, FloatType, BoolType, StringType, QualifiedType]
324
196
  size: int = 1
325
197
 
326
198
  class StructType(BaseModel):
@@ -333,12 +205,24 @@ class StructType(BaseModel):
333
205
  if v != "struct":
334
206
  raise ValueError('Check the "kind" field')
335
207
  return v
208
+
209
+ class AliasType(BaseModel):
210
+ kind: str
211
+ qualifiedName: str
212
+ type: Union[AliasType, StructType, ArrayType, IntegerType, FloatType, QualifiedType, StringType]
213
+ underlyingType: Union[StructType, ArrayType, IntegerType, BoolType, FloatType, StringType, QualifiedType]
214
+
215
+ @field_validator('kind')
216
+ def kind_qualifiedIdentifier(cls, v):
217
+ if v != "alias":
218
+ raise ValueError('Check the "kind" field')
219
+ return v
336
220
 
337
221
  class ArrayType(BaseModel):
338
222
  kind: str
339
223
  qualifiedName: str
340
224
  size: int
341
- elementType: Union[StructType, ArrayType, IntegerType, FloatType, QualifiedType]
225
+ elementType: Union[AliasType, StructType, ArrayType, IntegerType, FloatType, QualifiedType, StringType]
342
226
 
343
227
  @field_validator('kind')
344
228
  def kind_qualifiedIdentifier(cls, v):
@@ -346,6 +230,12 @@ class ArrayType(BaseModel):
346
230
  raise ValueError('Check the "kind" field')
347
231
  return v
348
232
 
233
+ class Constant(BaseModel):
234
+ qualifiedName: str
235
+ type: Union[IntegerType, FloatType, BoolType, StringType]
236
+ value: Union[int, float, bool, str]
237
+
238
+
349
239
  class EnumeratedConstant(BaseModel):
350
240
  name: str
351
241
  value: int
@@ -366,11 +256,11 @@ class EnumType(BaseModel):
366
256
 
367
257
 
368
258
  class Type(BaseModel):
369
- type: Union[StructType, ArrayType, IntegerType, FloatType, BoolType, QualifiedType]
259
+ type: Union[AliasType, StructType, ArrayType, IntegerType, FloatType, BoolType, QualifiedType, StringType]
370
260
 
371
261
  class RecordStruct(BaseModel):
372
262
  name: str
373
- type: Union[StructType, ArrayType, IntegerType, FloatType, BoolType, QualifiedType]
263
+ type: Union[AliasType, StructType, ArrayType, IntegerType, FloatType, BoolType, QualifiedType, StringType]
374
264
  array: bool
375
265
  id: int
376
266
  annotation: str
@@ -388,7 +278,8 @@ class ContainerStruct(BaseModel):
388
278
 
389
279
  class FprimeDict(BaseModel):
390
280
  metadata: Dict[str, Union[str, List[str]]]
391
- typeDefinitions: List[Union[ArrayType, StructType, EnumType]]
281
+ typeDefinitions: List[Union[AliasType, ArrayType, StructType, EnumType]]
282
+ constants: List[Constant]
392
283
  records: List[RecordStruct]
393
284
  containers: List[ContainerStruct]
394
285
 
@@ -398,19 +289,75 @@ class FprimeDict(BaseModel):
398
289
  # -------------------------------------------------------------------------------------
399
290
 
400
291
  class DPHeader(BaseModel):
401
- typeDefinitions: List[Union[ArrayType, StructType, EnumType]]
402
- header: Dict[str, Type]
292
+ typeDefinitions: List[Union[AliasType, ArrayType, StructType, EnumType]]
293
+ constants: List[Constant]
403
294
  headerHash: Type
404
- dataId: Type
405
- dataSize: Type
406
295
  dataHash: Type
407
296
 
297
+ @computed_field
298
+ @property
299
+ def header(self) -> Dict[str, Union[Type, ArrayType, EnumType]]:
300
+ # All types/constants that make up the DP header
301
+ header_dict = {
302
+ "FwPacketDescriptorType": None,
303
+ "FwDpIdType": None,
304
+ "FwDpPriorityType" : None,
305
+ "Seconds": None,
306
+ "USeconds": None,
307
+ "FwTimeBaseStoreType": None,
308
+ "FwTimeContextStoreType": None,
309
+ "Fw.DpCfg.ProcType": None,
310
+ "Fw.DpCfg.CONTAINER_USER_DATA_SIZE": None,
311
+ "Fw.DpState": None,
312
+ "FwSizeStoreType": None
313
+ }
314
+ for k in header_dict.keys():
315
+ # Seconds and USeconds are not in the dictionary, but are both always U32
316
+ if k == "Seconds" or k == "USeconds":
317
+ header_dict[k] = Type(type=IntegerType(name="U32", kind="integer", size=32, signed=False))
318
+ # According to Fw.Dp SDD, Header::UserData is an array of U8 of size Fw::DpCfg::CONTAINER_USER_DATA_SIZE.
319
+ elif k == "Fw.DpCfg.CONTAINER_USER_DATA_SIZE":
320
+ for t in self.constants:
321
+ if t.qualifiedName == k:
322
+ header_dict[k] = ArrayType(
323
+ kind="array",
324
+ qualifiedName="UserData",
325
+ size=t.value,
326
+ elementType=IntegerType(name="U8", kind="integer", size=8, signed=False)
327
+ )
328
+ break
329
+ else:
330
+ for t in self.typeDefinitions:
331
+ if t.qualifiedName == k:
332
+ header_dict[k] = t
333
+ break
334
+
335
+ return header_dict
336
+
337
+ @computed_field
338
+ @property
339
+ def dataId(self) -> Type:
340
+ return self.header.get("FwDpIdType")
341
+
342
+ @computed_field
343
+ @property
344
+ def dataSize(self) -> Type:
345
+ return self.header.get("FwSizeStoreType")
346
+
347
+ @model_validator(mode='after')
348
+ def validate_header(self) -> 'DPHeader':
349
+ for k, v in self.header.items():
350
+ if not v:
351
+ raise ValueError(f'Dictionary is missing type definition or constant {k}.')
352
+ return self
353
+
408
354
  ArrayType.model_rebuild()
355
+ AliasType.model_rebuild()
409
356
  StructType.model_rebuild()
410
357
  Type.model_rebuild()
411
358
 
412
- TypeKind = Union[StructType, ArrayType, IntegerType, FloatType, EnumType, BoolType, QualifiedType]
413
- TypeDef = Union[ArrayType, StructType]
359
+ TypeKind = Union[AliasType, ArrayType, StructType, IntegerType, FloatType, EnumType, BoolType, QualifiedType, StringType]
360
+ TypeDef = Union[AliasType, ArrayType, StructType]
414
361
 
415
362
  # Map the JSON types to struct format strings
416
363
  type_mapping = {
@@ -646,6 +593,7 @@ class DataProductWriter:
646
593
  # The process varies depending on the field's type:
647
594
  # - For basic types (IntegerType, FloatType, BoolType), it directly reads and assigns the value.
648
595
  # - For EnumType, it reads the value, finds the corresponding enum identifier, and assigns it.
596
+ # - For AliasType, it reads and assigns the value based on the alias' underlying type.
649
597
  # - For ArrayType, it creates a list, iteratively fills it with elements read recursively, and assigns the list.
650
598
  # - For StructType, it constructs a nested dictionary by recursively processing each struct member.
651
599
  # - For QualifiedType, it resolves the actual type from typeList and recursively processes the field.
@@ -685,6 +633,8 @@ class DataProductWriter:
685
633
  reverse_mapping = {enum.value: enum.name for enum in enum_mapping}
686
634
  parent_dict[field_name] = reverse_mapping[value]
687
635
 
636
+ elif isinstance(typeKind, AliasType):
637
+ self.get_struct_item(field_name, typeKind.underlyingType, typeList, parent_dict)
688
638
 
689
639
  elif isinstance(typeKind, ArrayType):
690
640
  array_list = []
@@ -738,7 +688,13 @@ class DataProductWriter:
738
688
  rootDict = {}
739
689
 
740
690
  for field_name, field_info in header_fields.items():
741
- self.get_struct_item(field_name, field_info.type, headerJSON.typeDefinitions, rootDict)
691
+ # Header is composed of enums, arrays, and aliases
692
+ if isinstance(field_info, EnumType):
693
+ self.get_struct_item(field_name, field_info.representationType, headerJSON.typeDefinitions, rootDict)
694
+ elif isinstance(field_info, ArrayType):
695
+ self.get_struct_item(field_name, field_info, headerJSON.typeDefinitions, rootDict)
696
+ else:
697
+ self.get_struct_item(field_name, field_info.type, headerJSON.typeDefinitions, rootDict)
742
698
 
743
699
  computedHash = self.calculatedCRC
744
700
  rootDict['headerHash'] = self.read_field(headerJSON.headerHash.type)
@@ -866,21 +822,28 @@ class DataProductWriter:
866
822
  print(f"Parsing {self.jsonDict}...")
867
823
  try:
868
824
  with open(self.jsonDict, 'r') as fprimeDictFile:
869
- dictJSON = FprimeDict(**json.load(fprimeDictFile))
825
+ dict_json = json.load(fprimeDictFile)
826
+ dictJSON = FprimeDict(**dict_json)
827
+
828
+ header_json = header_hash_data
829
+ if "typeDefinitions" in dict_json:
830
+ header_json["typeDefinitions"] = dict_json["typeDefinitions"]
831
+ if "constants" in dict_json:
832
+ header_json["constants"] = dict_json["constants"]
833
+ headerJSON = DPHeader(**header_json)
834
+
870
835
  except json.JSONDecodeError as e:
871
836
  raise DictionaryError(self.jsonDict, e.lineno)
872
837
 
873
838
  self.check_record_data(dictJSON)
874
839
 
875
- headerJSON = DPHeader(**header_data)
876
-
877
840
  with open(self.binaryFileName, 'rb') as self.binaryFile:
878
841
 
879
842
  # Read the header data up until the Records
880
843
  headerData = self.get_header_info(headerJSON)
881
844
 
882
845
  # Read the total data size
883
- dataSize = headerData['DataSize']
846
+ dataSize = headerData['FwSizeStoreType']
884
847
 
885
848
  # Restart the count of bytes read
886
849
  self.totalBytesRead = 0
@@ -177,7 +177,7 @@ def launch_comm(parsed_args):
177
177
 
178
178
  def launch_plugin(plugin_class_instance):
179
179
  """Launch a plugin instance"""
180
- plugin_name = getattr(plugin_class_instance, "get_name", lambda: cls.__name__)()
180
+ plugin_name = getattr(plugin_class_instance, "get_name", lambda: plugin_class_instance.__class__.__name__)()
181
181
  return launch_process(
182
182
  plugin_class_instance.get_process_invocation(),
183
183
  name=f"{ plugin_name } Plugin App",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fprime-gds
3
- Version: 4.0.0a4
3
+ Version: 4.0.0a6
4
4
  Summary: F Prime Flight Software Ground Data System layer
5
5
  Author-email: Michael Starch <Michael.D.Starch@jpl.nasa.gov>, Thomas Boyer-Chammard <Thomas.Boyer.Chammard@jpl.nasa.gov>
6
6
  License:
@@ -89,7 +89,7 @@ fprime_gds/common/models/common/event.py,sha256=gSFrCJT9ZddGJfkf3fGCCqk0aMIQV-SN
89
89
  fprime_gds/common/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
90
  fprime_gds/common/parsers/seq_file_parser.py,sha256=6DZrA0jmt8IqsutfK7pdLtYn4oVHO593rWgAOH63yRg,9587
91
91
  fprime_gds/common/pipeline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- fprime_gds/common/pipeline/dictionaries.py,sha256=oZwRhGsrSRt9ptlMkUKsbFbxgoumE7MXwf0xkq1dKCg,7943
92
+ fprime_gds/common/pipeline/dictionaries.py,sha256=x3QCZAg6YB9bEumZ330PGo0ilJqODGyo_K70RgbQ53M,8009
93
93
  fprime_gds/common/pipeline/encoding.py,sha256=PttJ8NmXm75mLXyhlmxOJqE8RFt46q1dThaV19PyAr4,7216
94
94
  fprime_gds/common/pipeline/files.py,sha256=J2zm0sucvImtmSnv0iUp5uTpvUO8nlmz2lUdMuMC5aM,2244
95
95
  fprime_gds/common/pipeline/histories.py,sha256=7KyboNnm9OARQk4meVPSSeYpeqH0G8RWRiy0BLBL1rw,3671
@@ -103,9 +103,9 @@ fprime_gds/common/templates/event_template.py,sha256=L0hkWB_kEMhTNodPUqBAev76SMm
103
103
  fprime_gds/common/templates/pkt_template.py,sha256=5Wi6389m5j8w7JITBGfeUnw6CYE1-hjcVJ42NJmLDcE,1794
104
104
  fprime_gds/common/templates/prm_template.py,sha256=qd0UX4ARZuPWvnFbU_DO3HkQY4QgMfqPxNcNhk-dl9A,2303
105
105
  fprime_gds/common/testing_fw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
- fprime_gds/common/testing_fw/api.py,sha256=mp93lZtAOcFj3sPS5Otk4CCu37680_QgWN8fDIj7jNs,62379
106
+ fprime_gds/common/testing_fw/api.py,sha256=lnDiyCrnj8Q8uzrmPeFOewSUPX_BvHRisY2jk-4G3eg,66045
107
107
  fprime_gds/common/testing_fw/predicates.py,sha256=CsHsVs_EVXCLQLd2NVOvy8MxmUQVxLMr3i1ouEUqOtQ,18371
108
- fprime_gds/common/testing_fw/pytest_integration.py,sha256=BqIevoSBDoKvLBy3HIGtxGbbvOit1a7Ea5X1SSBCK8M,5728
108
+ fprime_gds/common/testing_fw/pytest_integration.py,sha256=CAvuH9_3RuKplKQVB3t_jerPr-LPzwPWoM6z3lMs16g,6203
109
109
  fprime_gds/common/tools/README.md,sha256=WVEciyfsbEVGmb9xR5A6Ioy5pBVnCsWOIJfySLeq9YM,2325
110
110
  fprime_gds/common/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
111
  fprime_gds/common/tools/params.py,sha256=htnMLlUW9HmBo4Qc7kYhnWr1sO6bK2mckdskLt5rDUk,9323
@@ -116,12 +116,12 @@ fprime_gds/common/utils/data_desc_type.py,sha256=0AkEMfEa5refd_moovf1hkgKiNakADR
116
116
  fprime_gds/common/utils/event_severity.py,sha256=7qPXHrDaM_REJ7sKBUEJTZIE0D4qVnVajsPDUuHg7sI,300
117
117
  fprime_gds/common/utils/string_util.py,sha256=u_2iahRG3ROu3lAAt_KVcK226gEByElXqrA8mH8eDpI,3584
118
118
  fprime_gds/executables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
- fprime_gds/executables/apps.py,sha256=iyHloLaHJOkcZF6O3oXZX6YpoS2SBBZVPilf25l0Q98,13138
119
+ fprime_gds/executables/apps.py,sha256=u79T_PlgMmNmA4YwWjs7LvPMCJnrjnURr05NMthOYP0,13350
120
120
  fprime_gds/executables/cli.py,sha256=aNO8saIKuTDQMwWNFlrpIL5HuwIWWei94Wxf3G0lY3k,50382
121
121
  fprime_gds/executables/comm.py,sha256=08rO0o0MJgTRngB7Ygu2IL_gEAWKF7WFvFyro1CqReE,5214
122
- fprime_gds/executables/data_product_writer.py,sha256=aXnQ75hQ8bapz-sr21mrPCrXIfqQblfBuB49GGZrFLg,34965
122
+ fprime_gds/executables/data_product_writer.py,sha256=cM_OsISsy0bwONrvUu9pYZRhaHeY_GNxsyM18k85wZM,35801
123
123
  fprime_gds/executables/fprime_cli.py,sha256=CMoT7zWNwM8h2mSZW03AR96wl_XnZXoLNiOZN_sDi38,12431
124
- fprime_gds/executables/run_deployment.py,sha256=x6auxjsDyCj4216JbO0bSskv2H9r7n3vuu5Z3O5cGwY,7209
124
+ fprime_gds/executables/run_deployment.py,sha256=Zl0Y9-6i6c8tZhcS7XkAeVQtzn0d9fV-3UJQZ0bnBrc,7237
125
125
  fprime_gds/executables/tcpserver.py,sha256=KspVpu5YIuiWKOk5E6UDMKvqXYrRB1j9aX8CkMxysfw,17555
126
126
  fprime_gds/executables/utils.py,sha256=SbzXRe1p41qMPdifvPap5_4v0T42gZZ_Rs_OYfITd80,7626
127
127
  fprime_gds/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -238,10 +238,10 @@ fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2,sha256=mDS4KtJuK
238
238
  fprime_gds/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
239
  fprime_gds/plugin/definitions.py,sha256=QlxW1gNvoiqGMslSJjh3dTFZuv0igFHawN__3XJ0Wns,5355
240
240
  fprime_gds/plugin/system.py,sha256=M9xb-8jBhCUUx3X1z2uAP8Wx_v6NkL8JeaFgGcMnQqY,13432
241
- fprime_gds-4.0.0a4.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
242
- fprime_gds-4.0.0a4.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
243
- fprime_gds-4.0.0a4.dist-info/METADATA,sha256=RAq6BEVxVXtPSIGAg-p23Xd4Zdww9JEHJzeO8imSsLc,24549
244
- fprime_gds-4.0.0a4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
245
- fprime_gds-4.0.0a4.dist-info/entry_points.txt,sha256=qFBHIR7CZ5CEeSEdZ-ZVQN9ZfUOZfm0PvvDZAAheuLk,445
246
- fprime_gds-4.0.0a4.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
247
- fprime_gds-4.0.0a4.dist-info/RECORD,,
241
+ fprime_gds-4.0.0a6.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
242
+ fprime_gds-4.0.0a6.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
243
+ fprime_gds-4.0.0a6.dist-info/METADATA,sha256=1UB0xbbo6uXm-Skimx0uePjGF1cxgisaEo_Y072HiKA,24549
244
+ fprime_gds-4.0.0a6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
245
+ fprime_gds-4.0.0a6.dist-info/entry_points.txt,sha256=qFBHIR7CZ5CEeSEdZ-ZVQN9ZfUOZfm0PvvDZAAheuLk,445
246
+ fprime_gds-4.0.0a6.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
247
+ fprime_gds-4.0.0a6.dist-info/RECORD,,