fprime-gds 4.0.0a1__py3-none-any.whl → 4.0.0a2__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.
- fprime_gds/common/communication/adapters/uart.py +34 -25
- fprime_gds/executables/cli.py +163 -3
- fprime_gds/executables/run_deployment.py +2 -1
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/METADATA +2 -1
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/RECORD +10 -10
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/WHEEL +1 -1
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/entry_points.txt +0 -0
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/licenses/LICENSE.txt +0 -0
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/licenses/NOTICE.txt +0 -0
- {fprime_gds-4.0.0a1.dist-info → fprime_gds-4.0.0a2.dist-info}/top_level.txt +0 -0
@@ -59,7 +59,7 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
59
59
|
4000000,
|
60
60
|
]
|
61
61
|
|
62
|
-
def __init__(self, device, baud):
|
62
|
+
def __init__(self, device, baud, skip_check):
|
63
63
|
"""
|
64
64
|
Initialize the serial adapter using the default settings. This does not open the serial port, but sets up all
|
65
65
|
the internal variables used when opening the device.
|
@@ -77,9 +77,14 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
77
77
|
Opens the serial port based on previously supplied settings. If the port is already open, then close it first.
|
78
78
|
Then open the port up again.
|
79
79
|
"""
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
try:
|
81
|
+
self.close()
|
82
|
+
self.serial = serial.Serial(self.device, self.baud)
|
83
|
+
return self.serial is not None
|
84
|
+
except serial.serialutil.SerialException as exc:
|
85
|
+
LOGGER.warning("Serial exception caught: %s. Reconnecting.", (str(exc)))
|
86
|
+
self.close()
|
87
|
+
return False
|
83
88
|
|
84
89
|
def close(self):
|
85
90
|
"""
|
@@ -100,12 +105,11 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
100
105
|
:return: True, when data was sent through the UART. False otherwise.
|
101
106
|
"""
|
102
107
|
try:
|
103
|
-
if self.serial is None:
|
104
|
-
self.
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
return True
|
108
|
+
if self.serial is not None or self.open():
|
109
|
+
written = self.serial.write(frame)
|
110
|
+
# Not believed to be possible to not send everything without getting a timeout exception
|
111
|
+
assert written == len(frame)
|
112
|
+
return True
|
109
113
|
except serial.serialutil.SerialException as exc:
|
110
114
|
LOGGER.warning("Serial exception caught: %s. Reconnecting.", (str(exc)))
|
111
115
|
self.close()
|
@@ -121,17 +125,16 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
121
125
|
"""
|
122
126
|
data = b""
|
123
127
|
try:
|
124
|
-
if self.serial is None:
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
) # Drain the incoming data queue
|
128
|
+
if self.serial is not None or self.open():
|
129
|
+
# Read as much data as possible, while ensuring to block if no data is available at this time. Note: as much
|
130
|
+
# data is read as possible to avoid a long-return time to this call. Minimum data to read is one byte in
|
131
|
+
# order to block this function while data is incoming.
|
132
|
+
self.serial.timeout = timeout
|
133
|
+
data = self.serial.read(1) # Force a block for at least 1 character
|
134
|
+
while self.serial.in_waiting:
|
135
|
+
data += self.serial.read(
|
136
|
+
self.serial.in_waiting
|
137
|
+
) # Drain the incoming data queue
|
135
138
|
except serial.serialutil.SerialException as exc:
|
136
139
|
LOGGER.warning("Serial exception caught: %s. Reconnecting.", (str(exc)))
|
137
140
|
self.close()
|
@@ -161,6 +164,12 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
161
164
|
"default": 9600,
|
162
165
|
"help": "Baud rate of the serial device.",
|
163
166
|
},
|
167
|
+
("--uart-skip-port-check",): {
|
168
|
+
"dest": "skip_check",
|
169
|
+
"default": False,
|
170
|
+
"action": "store_true",
|
171
|
+
"help": "Skip checking that the port exists"
|
172
|
+
}
|
164
173
|
}
|
165
174
|
|
166
175
|
@classmethod
|
@@ -175,20 +184,20 @@ class SerialAdapter(fprime_gds.common.communication.adapters.base.BaseAdapter):
|
|
175
184
|
return cls
|
176
185
|
|
177
186
|
@classmethod
|
178
|
-
def check_arguments(cls, device, baud):
|
187
|
+
def check_arguments(cls, device, baud, skip_check):
|
179
188
|
"""
|
180
189
|
Code that should check arguments of this adapter. If there is a problem with this code, then a "ValueError"
|
181
190
|
should be raised describing the problem with these arguments.
|
182
191
|
|
183
192
|
:param args: arguments as dictionary
|
184
193
|
"""
|
185
|
-
ports = map(lambda info: info.device, list_ports.comports(include_links=True))
|
186
|
-
if device not in ports:
|
194
|
+
ports = list(map(lambda info: info.device, list_ports.comports(include_links=True)))
|
195
|
+
if not skip_check and device not in ports:
|
187
196
|
msg = f"Serial port '{device}' not valid. Available ports: {ports}"
|
188
197
|
raise ValueError(
|
189
198
|
msg
|
190
199
|
)
|
191
|
-
# Note: baud rate may not *always* work. These are a superset
|
200
|
+
# Note: baud rate may not *always* work. These are a superset.
|
192
201
|
try:
|
193
202
|
baud = int(baud)
|
194
203
|
except ValueError:
|
fprime_gds/executables/cli.py
CHANGED
@@ -19,6 +19,9 @@ import os
|
|
19
19
|
import platform
|
20
20
|
import re
|
21
21
|
import sys
|
22
|
+
|
23
|
+
import yaml
|
24
|
+
|
22
25
|
from abc import ABC, abstractmethod
|
23
26
|
from pathlib import Path
|
24
27
|
from typing import Any, Dict, List, Tuple
|
@@ -185,8 +188,32 @@ class ParserBase(ABC):
|
|
185
188
|
Returns: namespace with processed results of arguments.
|
186
189
|
"""
|
187
190
|
|
188
|
-
@
|
191
|
+
@classmethod
|
192
|
+
def parse_known_args(
|
193
|
+
cls,
|
194
|
+
parser_classes,
|
195
|
+
description="No tool description provided",
|
196
|
+
arguments=None,
|
197
|
+
**kwargs,
|
198
|
+
):
|
199
|
+
"""Parse and post-process arguments
|
200
|
+
|
201
|
+
Create a parser for the given application using the description provided. This will then add all specified
|
202
|
+
ParserBase subclasses' get_parser output as parent parses for the created parser. Then all of the handle
|
203
|
+
arguments methods will be called, and the final namespace will be returned. This will allow unknown arguments
|
204
|
+
which are returned as the last tuple result.
|
205
|
+
|
206
|
+
Args:
|
207
|
+
parser_classes: a list of ParserBase subclasses that will be used to
|
208
|
+
description: description passed ot the argument parser
|
209
|
+
arguments: arguments to process, None to use command line input
|
210
|
+
Returns: namespace with all parsed arguments from all provided ParserBase subclasses
|
211
|
+
"""
|
212
|
+
return cls._parse_args(parser_classes, description, arguments, use_parse_known=True, **kwargs)
|
213
|
+
|
214
|
+
@classmethod
|
189
215
|
def parse_args(
|
216
|
+
cls,
|
190
217
|
parser_classes,
|
191
218
|
description="No tool description provided",
|
192
219
|
arguments=None,
|
@@ -194,20 +221,53 @@ class ParserBase(ABC):
|
|
194
221
|
):
|
195
222
|
"""Parse and post-process arguments
|
196
223
|
|
224
|
+
Create a parser for the given application using the description provided. This will then add all specified
|
225
|
+
ParserBase subclasses' get_parser output as parent parses for the created parser. Then all of the handle
|
226
|
+
arguments methods will be called, and the final namespace will be returned. This does not allow unknown
|
227
|
+
arguments.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
parser_classes: a list of ParserBase subclasses that will be used to
|
231
|
+
description: description passed ot the argument parser
|
232
|
+
arguments: arguments to process, None to use command line input
|
233
|
+
Returns: namespace with all parsed arguments from all provided ParserBase subclasses
|
234
|
+
"""
|
235
|
+
return cls._parse_args(parser_classes, description, arguments, **kwargs)
|
236
|
+
|
237
|
+
|
238
|
+
@staticmethod
|
239
|
+
def _parse_args(
|
240
|
+
parser_classes,
|
241
|
+
description="No tool description provided",
|
242
|
+
arguments=None,
|
243
|
+
use_parse_known=False,
|
244
|
+
**kwargs,
|
245
|
+
):
|
246
|
+
"""Parse and post-process arguments helper
|
247
|
+
|
197
248
|
Create a parser for the given application using the description provided. This will then add all specified
|
198
249
|
ParserBase subclasses' get_parser output as parent parses for the created parser. Then all of the handle
|
199
250
|
arguments methods will be called, and the final namespace will be returned.
|
200
251
|
|
252
|
+
This takes a function that will take in a parser and return the parsing function to call on arguments.
|
253
|
+
|
201
254
|
Args:
|
255
|
+
parse_function_processor: takes a parser, returns the parse function to call
|
202
256
|
parser_classes: a list of ParserBase subclasses that will be used to
|
203
257
|
description: description passed ot the argument parser
|
204
258
|
arguments: arguments to process, None to use command line input
|
259
|
+
use_parse_known: use parse_known_arguments from argparse
|
260
|
+
|
205
261
|
Returns: namespace with all parsed arguments from all provided ParserBase subclasses
|
206
262
|
"""
|
207
263
|
composition = CompositeParser(parser_classes, description)
|
208
264
|
parser = composition.get_parser()
|
209
265
|
try:
|
210
|
-
|
266
|
+
if use_parse_known:
|
267
|
+
args_ns, *unknowns = parser.parse_known_args(arguments)
|
268
|
+
else:
|
269
|
+
args_ns = parser.parse_args(arguments)
|
270
|
+
unknowns = []
|
211
271
|
args_ns = composition.handle_arguments(args_ns, **kwargs)
|
212
272
|
except ValueError as ver:
|
213
273
|
print(f"[ERROR] Failed to parse arguments: {ver}", file=sys.stderr)
|
@@ -216,7 +276,7 @@ class ParserBase(ABC):
|
|
216
276
|
except Exception as exc:
|
217
277
|
print(f"[ERROR] {exc}", file=sys.stderr)
|
218
278
|
sys.exit(-1)
|
219
|
-
return args_ns, parser
|
279
|
+
return args_ns, parser, *unknowns
|
220
280
|
|
221
281
|
@staticmethod
|
222
282
|
def find_in(token, deploy, is_file=True):
|
@@ -236,6 +296,106 @@ class ParserBase(ABC):
|
|
236
296
|
return None
|
237
297
|
|
238
298
|
|
299
|
+
class ConfigDrivenParser(ParserBase):
|
300
|
+
""" Parser that allows options from configuration and command line
|
301
|
+
|
302
|
+
This parser reads a configuration file (if supplied) and uses the values to drive the inputs to arguments. Command
|
303
|
+
line arguments will still take precedence over the configured values.
|
304
|
+
"""
|
305
|
+
DEFAULT_CONFIGURATION_PATH = Path("fprime-gds.yml")
|
306
|
+
|
307
|
+
@classmethod
|
308
|
+
def set_default_configuration(cls, path: Path):
|
309
|
+
""" Set path for (global) default configuration file
|
310
|
+
|
311
|
+
Set the path for default configuration file. If unset, will use 'fprime-gds.yml'. Set to None to disable default
|
312
|
+
configuration.
|
313
|
+
"""
|
314
|
+
cls.DEFAULT_CONFIGURATION_PATH = path
|
315
|
+
|
316
|
+
@classmethod
|
317
|
+
def parse_args(
|
318
|
+
cls,
|
319
|
+
parser_classes,
|
320
|
+
description="No tool description provided",
|
321
|
+
arguments=None,
|
322
|
+
**kwargs,
|
323
|
+
):
|
324
|
+
""" Parse and post-process arguments using inputs and config
|
325
|
+
|
326
|
+
Parse the arguments in two stages: first parse the configuration data, ignoring unknown inputs, then parse the
|
327
|
+
full argument set with the supplied configuration to fill in additional options.
|
328
|
+
|
329
|
+
Args:
|
330
|
+
parser_classes: a list of ParserBase subclasses that will be used to
|
331
|
+
description: description passed ot the argument parser
|
332
|
+
arguments: arguments to process, None to use command line input
|
333
|
+
Returns: namespace with all parsed arguments from all provided ParserBase subclasses
|
334
|
+
"""
|
335
|
+
arguments = sys.argv[1:] if arguments is None else arguments
|
336
|
+
|
337
|
+
# Help should spill all the arguments, so delegate to the normal parsing flow including
|
338
|
+
# this and supplied parsers
|
339
|
+
if "-h" in arguments or "--help" in arguments:
|
340
|
+
parsers = [ConfigDrivenParser] + parser_classes
|
341
|
+
ParserBase.parse_args(parsers, description, arguments, **kwargs)
|
342
|
+
sys.exit(0)
|
343
|
+
|
344
|
+
# Custom flow involving parsing the arguments of this parser first, then passing the configured values
|
345
|
+
# as part of the argument source
|
346
|
+
ns_config, _, remaining = ParserBase.parse_known_args([ConfigDrivenParser], description, arguments, **kwargs)
|
347
|
+
config_options = ns_config.config_values.get("command-line-options", {})
|
348
|
+
config_args = cls.flatten_options(config_options)
|
349
|
+
# Argparse allows repeated (overridden) arguments, thus the CLI override is accomplished by providing
|
350
|
+
# remaining arguments after the configured ones
|
351
|
+
ns_full, parser = ParserBase.parse_args(parser_classes, description, config_args + remaining, **kwargs)
|
352
|
+
ns_final = argparse.Namespace(**vars(ns_config), **vars(ns_full))
|
353
|
+
return ns_final, parser
|
354
|
+
|
355
|
+
@staticmethod
|
356
|
+
def flatten_options(configured_options):
|
357
|
+
""" Flatten options down to arguments """
|
358
|
+
flattened = []
|
359
|
+
for option, value in configured_options.items():
|
360
|
+
flattened.append(f"--{option}")
|
361
|
+
if value is not None:
|
362
|
+
flattened.extend(value if isinstance(value, (list, tuple)) else [f"{value}"])
|
363
|
+
return flattened
|
364
|
+
|
365
|
+
def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
|
366
|
+
"""Arguments needed for config processing"""
|
367
|
+
return {
|
368
|
+
("-c", "--config"): {
|
369
|
+
"dest": "config",
|
370
|
+
"required": False,
|
371
|
+
"default": self.DEFAULT_CONFIGURATION_PATH,
|
372
|
+
"type": Path,
|
373
|
+
"help": f"Argument configuration file path.",
|
374
|
+
}
|
375
|
+
}
|
376
|
+
|
377
|
+
def handle_arguments(self, args, **kwargs):
|
378
|
+
""" Handle the arguments
|
379
|
+
|
380
|
+
Loads the configuration file specified and fills in the `config_values` attribute of the namespace with the
|
381
|
+
loaded configuration dictionary.
|
382
|
+
"""
|
383
|
+
args.config_values = {}
|
384
|
+
# Specified but non-existent config file is a hard error
|
385
|
+
if ("-c" in sys.argv[1:] or "--config" in sys.argv[1:]) and not args.config.exists():
|
386
|
+
raise ValueError(f"Specified configuration file '{args.config}' does not exist")
|
387
|
+
# Read configuration if the file was set and exists
|
388
|
+
if args.config is not None and args.config.exists():
|
389
|
+
print(f"[INFO] Reading command-line configuration from: {args.config}")
|
390
|
+
with open(args.config, "r") as file_handle:
|
391
|
+
try:
|
392
|
+
loaded = yaml.safe_load(file_handle)
|
393
|
+
args.config_values = loaded if loaded is not None else {}
|
394
|
+
except Exception as exc:
|
395
|
+
raise ValueError(f"Malformed configuration {args.config}: {exc}", exc)
|
396
|
+
return args
|
397
|
+
|
398
|
+
|
239
399
|
class DetectionParser(ParserBase):
|
240
400
|
"""Parser that detects items from a root/directory or deployment"""
|
241
401
|
|
@@ -9,6 +9,7 @@ import webbrowser
|
|
9
9
|
|
10
10
|
from fprime_gds.executables.cli import (
|
11
11
|
BinaryDeployment,
|
12
|
+
ConfigDrivenParser,
|
12
13
|
CommParser,
|
13
14
|
GdsParser,
|
14
15
|
ParserBase,
|
@@ -37,7 +38,7 @@ def parse_args():
|
|
37
38
|
PluginArgumentParser,
|
38
39
|
]
|
39
40
|
# Parse the arguments, and refine through all handlers
|
40
|
-
args, parser =
|
41
|
+
args, parser = ConfigDrivenParser.parse_args(arg_handlers, "Run F prime deployment and GDS")
|
41
42
|
return args
|
42
43
|
|
43
44
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fprime-gds
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.0a2
|
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:
|
@@ -240,6 +240,7 @@ Requires-Dist: Jinja2>=2.11.3
|
|
240
240
|
Requires-Dist: openpyxl>=3.0.10
|
241
241
|
Requires-Dist: pyserial>=3.5
|
242
242
|
Requires-Dist: pydantic>=2.6
|
243
|
+
Requires-Dist: PyYAML>=6.0.2
|
243
244
|
Dynamic: license-file
|
244
245
|
|
245
246
|
# F´ GDS
|
@@ -13,7 +13,7 @@ fprime_gds/common/communication/updown.py,sha256=UhfCIIA2eM5g2FsIhOGJJH6HzHurUPg
|
|
13
13
|
fprime_gds/common/communication/adapters/__init__.py,sha256=ivGtzUTqhBYuve5mhN9VOHITwgZjNMVv7sxuac2Ll3c,470
|
14
14
|
fprime_gds/common/communication/adapters/base.py,sha256=i3mf4HC-4tuf4mNkhdXCKlngRhODyTriia2pw6XBoSQ,3393
|
15
15
|
fprime_gds/common/communication/adapters/ip.py,sha256=vCDclpsb3rVRXSxKqdt9UfkM2M6oCxnsKdzbzhMc0kM,17074
|
16
|
-
fprime_gds/common/communication/adapters/uart.py,sha256=
|
16
|
+
fprime_gds/common/communication/adapters/uart.py,sha256=5WkA8xpQ8E7nv2DbN168fibz1l-GddJUKnf6Hcd4hvU,7194
|
17
17
|
fprime_gds/common/controllers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
fprime_gds/common/data_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
fprime_gds/common/data_types/ch_data.py,sha256=RP9zSyzNcH0nJ3MYyW_IATnmnHYZ6d0KmoJUJantdBI,6111
|
@@ -112,11 +112,11 @@ fprime_gds/common/utils/event_severity.py,sha256=7qPXHrDaM_REJ7sKBUEJTZIE0D4qVnV
|
|
112
112
|
fprime_gds/common/utils/string_util.py,sha256=u_2iahRG3ROu3lAAt_KVcK226gEByElXqrA8mH8eDpI,3584
|
113
113
|
fprime_gds/executables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
114
114
|
fprime_gds/executables/apps.py,sha256=iyHloLaHJOkcZF6O3oXZX6YpoS2SBBZVPilf25l0Q98,13138
|
115
|
-
fprime_gds/executables/cli.py,sha256=
|
115
|
+
fprime_gds/executables/cli.py,sha256=7tqSMgFTSb20g9iMb02LOWrTYhePhX8Qe2kPZCzvquI,50381
|
116
116
|
fprime_gds/executables/comm.py,sha256=08rO0o0MJgTRngB7Ygu2IL_gEAWKF7WFvFyro1CqReE,5214
|
117
117
|
fprime_gds/executables/data_product_writer.py,sha256=aXnQ75hQ8bapz-sr21mrPCrXIfqQblfBuB49GGZrFLg,34965
|
118
118
|
fprime_gds/executables/fprime_cli.py,sha256=CMoT7zWNwM8h2mSZW03AR96wl_XnZXoLNiOZN_sDi38,12431
|
119
|
-
fprime_gds/executables/run_deployment.py,sha256=
|
119
|
+
fprime_gds/executables/run_deployment.py,sha256=x6auxjsDyCj4216JbO0bSskv2H9r7n3vuu5Z3O5cGwY,7209
|
120
120
|
fprime_gds/executables/tcpserver.py,sha256=KspVpu5YIuiWKOk5E6UDMKvqXYrRB1j9aX8CkMxysfw,17555
|
121
121
|
fprime_gds/executables/utils.py,sha256=SbzXRe1p41qMPdifvPap5_4v0T42gZZ_Rs_OYfITd80,7626
|
122
122
|
fprime_gds/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -233,10 +233,10 @@ fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2,sha256=mDS4KtJuK
|
|
233
233
|
fprime_gds/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
234
234
|
fprime_gds/plugin/definitions.py,sha256=QlxW1gNvoiqGMslSJjh3dTFZuv0igFHawN__3XJ0Wns,5355
|
235
235
|
fprime_gds/plugin/system.py,sha256=UiNrUqfi-KJOgRIOR8uyFMKdquSPZh_txpNq8eH35-Y,13285
|
236
|
-
fprime_gds-4.0.
|
237
|
-
fprime_gds-4.0.
|
238
|
-
fprime_gds-4.0.
|
239
|
-
fprime_gds-4.0.
|
240
|
-
fprime_gds-4.0.
|
241
|
-
fprime_gds-4.0.
|
242
|
-
fprime_gds-4.0.
|
236
|
+
fprime_gds-4.0.0a2.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
237
|
+
fprime_gds-4.0.0a2.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
|
238
|
+
fprime_gds-4.0.0a2.dist-info/METADATA,sha256=8DZ3LB73jYM-qOHVEWFVzK_R2pfh18gkk1zWK0LIHhE,24486
|
239
|
+
fprime_gds-4.0.0a2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
240
|
+
fprime_gds-4.0.0a2.dist-info/entry_points.txt,sha256=qFBHIR7CZ5CEeSEdZ-ZVQN9ZfUOZfm0PvvDZAAheuLk,445
|
241
|
+
fprime_gds-4.0.0a2.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
|
242
|
+
fprime_gds-4.0.0a2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|