fprime-gds 3.4.2__py3-none-any.whl → 3.4.4a1__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.
@@ -13,6 +13,7 @@ from fprime_gds.executables.cli import (
13
13
  GdsParser,
14
14
  ParserBase,
15
15
  StandardPipelineParser,
16
+ PluginArgumentParser,
16
17
  )
17
18
  from fprime_gds.executables.utils import AppWrapperException, run_wrapped_application
18
19
 
@@ -20,14 +21,20 @@ BASE_MODULE_ARGUMENTS = [sys.executable, "-u", "-m"]
20
21
 
21
22
 
22
23
  def parse_args():
23
- """ Parse command line arguments
24
+ """Parse command line arguments
24
25
  Gets an argument parsers to read the command line and process the arguments. Return
25
26
  the arguments in their namespace.
26
27
 
27
28
  :return: parsed argument namespace
28
29
  """
29
30
  # Get custom handlers for all executables we are running
30
- arg_handlers = [StandardPipelineParser, GdsParser, BinaryDeployment, CommParser]
31
+ arg_handlers = [
32
+ StandardPipelineParser,
33
+ GdsParser,
34
+ BinaryDeployment,
35
+ CommParser,
36
+ PluginArgumentParser,
37
+ ]
31
38
  # Parse the arguments, and refine through all handlers
32
39
  args, parser = ParserBase.parse_args(arg_handlers, "Run F prime deployment and GDS")
33
40
  return args
@@ -63,7 +70,7 @@ def launch_process(cmd, logfile=None, name=None, env=None, launch_time=5):
63
70
 
64
71
 
65
72
  def launch_tts(parsed_args):
66
- """ Launch the ThreadedTcpServer middleware application
73
+ """Launch the ThreadedTcpServer middleware application
67
74
 
68
75
 
69
76
  Args:
@@ -85,7 +92,7 @@ def launch_tts(parsed_args):
85
92
 
86
93
 
87
94
  def launch_html(parsed_args):
88
- """ Launch the Flask application
95
+ """Launch the Flask application
89
96
 
90
97
  Args:
91
98
  parsed_args: parsed argument namespace
@@ -112,14 +119,18 @@ def launch_html(parsed_args):
112
119
  str(parsed_args.gui_port),
113
120
  ]
114
121
  ret = launch_process(gse_args, name="HTML GUI", env=flask_env, launch_time=2)
122
+ ui_url = f"http://{str(parsed_args.gui_addr)}:{str(parsed_args.gui_port)}/"
123
+ print(f"[INFO] Launched UI at: {ui_url}")
115
124
  webbrowser.open(
116
- f"http://{str(parsed_args.gui_addr)}:{str(parsed_args.gui_port)}/", new=0, autoraise=True
125
+ ui_url,
126
+ new=0,
127
+ autoraise=True,
117
128
  )
118
129
  return ret
119
130
 
120
131
 
121
132
  def launch_app(parsed_args):
122
- """ Launch the raw application
133
+ """Launch the raw application
123
134
 
124
135
  Args:
125
136
  parsed_args: parsed argument namespace
@@ -128,14 +139,20 @@ def launch_app(parsed_args):
128
139
  """
129
140
  app_path = parsed_args.app
130
141
  logfile = os.path.join(parsed_args.logs, f"{app_path.name}.log")
131
- app_cmd = [app_path.absolute(), "-p", str(parsed_args.port), "-a", parsed_args.address]
142
+ app_cmd = [
143
+ app_path.absolute(),
144
+ "-p",
145
+ str(parsed_args.port),
146
+ "-a",
147
+ parsed_args.address,
148
+ ]
132
149
  return launch_process(
133
150
  app_cmd, name=f"{app_path.name} Application", logfile=logfile, launch_time=1
134
151
  )
135
152
 
136
153
 
137
154
  def launch_comm(parsed_args):
138
- """ Launch the communication adapter process
155
+ """Launch the communication adapter process
139
156
 
140
157
  Args:
141
158
  parsed_args: parsed argument namespace
@@ -143,9 +160,27 @@ def launch_comm(parsed_args):
143
160
  launched process
144
161
  """
145
162
  arguments = CommParser().reproduce_cli_args(parsed_args)
146
- arguments = arguments + ["--log-directly"] if "--log-directly" not in arguments else arguments
163
+ arguments = (
164
+ arguments + ["--log-directly"]
165
+ if "--log-directly" not in arguments
166
+ else arguments
167
+ )
147
168
  app_cmd = BASE_MODULE_ARGUMENTS + ["fprime_gds.executables.comm"] + arguments
148
- return launch_process(app_cmd, name=f'comm[{parsed_args.adapter}] Application', launch_time=1)
169
+ return launch_process(
170
+ app_cmd,
171
+ name=f"comm[{parsed_args.communication_selection}] Application",
172
+ launch_time=1,
173
+ )
174
+
175
+
176
+ def launch_plugin(plugin_class_instance):
177
+ """ Launch a plugin instance """
178
+ plugin_name = getattr(plugin_class_instance, "get_name", lambda: cls.__name__)()
179
+ return launch_process(
180
+ plugin_class_instance.get_process_invocation(),
181
+ name=f"{ plugin_name } Plugin App",
182
+ launch_time=1,
183
+ )
149
184
 
150
185
 
151
186
  def main():
@@ -155,20 +190,23 @@ def main():
155
190
  parsed_args = parse_args()
156
191
  launchers = []
157
192
 
158
- # Launch a gui, if specified
193
+ # Launch middleware layer if not using ZMQ
159
194
  if not parsed_args.zmq:
160
195
  launchers.append(launch_tts)
161
196
 
162
197
  # Check if we are running with communications
163
- if parsed_args.adapter != "none":
198
+ if parsed_args.communication_selection != "none":
164
199
  launchers.append(launch_comm)
165
200
 
166
201
  # Add app, if possible
167
202
  if parsed_args.app:
168
- if parsed_args.adapter == "ip":
203
+ if parsed_args.communication_selection == "ip":
169
204
  launchers.append(launch_app)
170
205
  else:
171
- print("[WARNING] App cannot be auto-launched without IP adapter", file=sys.stderr)
206
+ print(
207
+ "[WARNING] App cannot be auto-launched without IP adapter",
208
+ file=sys.stderr,
209
+ )
172
210
 
173
211
  # Launch the desired GUI package
174
212
  if parsed_args.gui == "html":
@@ -177,6 +215,9 @@ def main():
177
215
  # Launch launchers and wait for the last app to finish
178
216
  try:
179
217
  procs = [launcher(parsed_args) for launcher in launchers]
218
+ _ = [launch_plugin(cls) for cls in parsed_args.gds_app_enabled_instances]
219
+ _ = [instance.run() for instance in parsed_args.gds_function_enabled_instances]
220
+
180
221
  print("[INFO] F prime is now running. CTRL-C to shutdown all components.")
181
222
  procs[-1].wait()
182
223
  except KeyboardInterrupt:
@@ -118,7 +118,7 @@ def run_wrapped_application(arguments, logfile=None, env=None, launch_time=None)
118
118
  if launch_time is not None:
119
119
  time.sleep(launch_time)
120
120
  child.poll()
121
- if child.returncode is not None:
121
+ if child.returncode is not None and child.returncode != 0:
122
122
  raise ProcessNotStableException(
123
123
  arguments[0], child.returncode, launch_time
124
124
  )
File without changes
@@ -0,0 +1,71 @@
1
+ """ fprime_gds.plugin.definitions: definitions of plugin specifications and decorators
2
+
3
+ In order to define a plugin, an implementation decorator is used. Users can import `gds_plugin_implementation` from this
4
+ file to decorate functions that implement plugins.
5
+
6
+ This file also defines helper classes to support the plugin system.
7
+
8
+ @author lestarch
9
+ """
10
+ import pluggy
11
+ from enum import Enum, auto
12
+ from typing import Any, Dict, Tuple, Type
13
+
14
+ PROJECT_NAME = "fprime_gds"
15
+
16
+ gds_plugin_specification = pluggy.HookspecMarker(PROJECT_NAME)
17
+ gds_plugin_implementation = pluggy.HookimplMarker(PROJECT_NAME)
18
+
19
+
20
+ class PluginType(Enum):
21
+ """ Enumeration of plugin types"""
22
+ ALL = auto()
23
+ """ Plugin selection including all types of plugins """
24
+
25
+ SELECTION = auto()
26
+ """ Plugin that provides a selection between implementations """
27
+
28
+ FEATURE = auto()
29
+ """ Plugin that provides a feature """
30
+
31
+
32
+ class Plugin(object):
33
+ """ Plugin wrapper object """
34
+
35
+ def __init__(self, category: str, plugin_type: PluginType, plugin_class: Type[Any]):
36
+ """ Initialize the plugin
37
+
38
+ Args:
39
+ category: category of the plugin (i.e. register_<category>_function)
40
+ plugin_type: type of plugin
41
+ plugin_class: implementation class of the plugin
42
+ """
43
+ self.category = category
44
+ self.type = plugin_type
45
+ self.plugin_class = plugin_class
46
+
47
+ def get_name(self):
48
+ """ Get the name of the plugin
49
+
50
+ Plugin names are derived from the `get_name` class method of the plugin's implementation class. When not defined
51
+ that name is derived from the plugin's implementation class __name__ property instead.
52
+
53
+ Returns:
54
+ name of plugin
55
+ """
56
+ return (
57
+ self.plugin_class.get_name() if hasattr(self.plugin_class, "get_name")
58
+ else self.plugin_class.__name__
59
+ )
60
+
61
+ def get_arguments(self) -> Dict[Tuple[str, ...], Dict[str, Any]]:
62
+ """ Get arguments needed by plugin
63
+
64
+ Plugin argument are derived from the `get_arguments` class method of the plugin's implementation class. When not
65
+ defined an empty dictionary is returned.
66
+
67
+ Returns:
68
+ argument specification for plugin
69
+ """
70
+ return self.plugin_class.get_arguments() if hasattr(self.plugin_class, "get_arguments") else {}
71
+
@@ -0,0 +1,225 @@
1
+ """ fprime_gds.plugin.system: implementation of plugins
2
+
3
+ This file contains the implementation and registration of plugins for fprime_gds. Primarily, it defines the Plugins
4
+ class that handles plugins. Users can acquire the Plugin singleton with `Plugin.system()`.
5
+
6
+ This file also imports and registers plugin implementations built-into fprime-gds. These plugins are not registered
7
+ using entrypoints.
8
+
9
+ @author lestarch
10
+ """
11
+ import os
12
+ import importlib
13
+ import inspect
14
+ import logging
15
+ from typing import Iterable, List, Union
16
+
17
+ import pluggy
18
+
19
+ from fprime_gds.plugin.definitions import Plugin, PluginType, PROJECT_NAME
20
+
21
+ # For automatic validation of plugins, each plugin class type must be imported here
22
+ from fprime_gds.executables.apps import GdsFunction, GdsApp
23
+ from fprime_gds.common.communication.framing import FramerDeframer, FpFramerDeframer
24
+ from fprime_gds.common.communication.adapters.base import BaseAdapter, NoneAdapter
25
+ from fprime_gds.common.communication.adapters.ip import IpAdapter
26
+
27
+ try:
28
+ from fprime_gds.common.communication.adapters.uart import SerialAdapter
29
+ except ImportError:
30
+ SerialAdapter = None
31
+
32
+ # Handy constants
33
+ LOGGER = logging.getLogger(__name__)
34
+
35
+
36
+ # Metadata regarding each plugin:
37
+ _PLUGIN_METADATA = {
38
+ "framing": {
39
+ "class": FramerDeframer,
40
+ "type": PluginType.SELECTION,
41
+ "built-in": [FpFramerDeframer]
42
+ },
43
+ "communication": {
44
+ "class": BaseAdapter,
45
+ "type": PluginType.SELECTION,
46
+ "built-in": [adapter for adapter in [NoneAdapter, IpAdapter, SerialAdapter] if adapter is not None]
47
+ },
48
+ "gds_function": {
49
+ "class": GdsFunction,
50
+ "type": PluginType.FEATURE,
51
+ "built-in": []
52
+ },
53
+ "gds_app": {
54
+ "class": GdsApp,
55
+ "type": PluginType.FEATURE,
56
+ "built-in": []
57
+ }
58
+ }
59
+
60
+
61
+ class PluginException(Exception):
62
+ pass
63
+
64
+
65
+ class InvalidCategoryException(PluginException):
66
+ pass
67
+
68
+
69
+ class Plugins(object):
70
+ """GDS plugin system providing a plugin Singleton for use across the GDS
71
+
72
+ GDS plugins are broken into categories (e.g. framing) that represent the key features users can adjust. Each GDS
73
+ application will support and load the plugins for a given category.
74
+ """
75
+ PLUGIN_ENVIRONMENT_VARIABLE = "FPRIME_GDS_EXTRA_PLUGINS"
76
+ _singleton = None
77
+
78
+ def __init__(self, categories: Union[None, List] = None):
79
+ """ Initialize the plugin system with specific categories
80
+
81
+ Initialize the plugin system with support for the supplied categories. Only plugins for the specified categories
82
+ will be loaded for use. Other plugins will not be available for use.
83
+
84
+ Args:
85
+ categories: None for all categories otherwise a list of categories
86
+ """
87
+ categories = self.get_all_categories() if categories is None else categories
88
+ self.categories = categories
89
+ self.manager = pluggy.PluginManager(PROJECT_NAME)
90
+
91
+ # Load hook specifications from only the configured categories
92
+ for category in categories:
93
+ self.manager.add_hookspecs(_PLUGIN_METADATA[category]["class"])
94
+
95
+ # Load plugins from setuptools entrypoints and the built-in plugins (limited to category)
96
+ self.manager.load_setuptools_entrypoints(PROJECT_NAME)
97
+
98
+ # Load plugins from environment variable specified modules
99
+ for token in [token for token in os.environ.get(self.PLUGIN_ENVIRONMENT_VARIABLE, "").split(";") if token]:
100
+ module, class_token = token.split(":")
101
+ try:
102
+ imported_module = importlib.import_module(module)
103
+ module_class = module if class_token == "" else getattr(imported_module, class_token, imported_module)
104
+ self.register_plugin(module_class)
105
+ except ImportError as imp:
106
+ LOGGER.debug("Failed to load %s.%s as plugin", module, class_token)
107
+
108
+ # Load built-in plugins
109
+ for category in categories:
110
+ for built_in in _PLUGIN_METADATA[category]["built-in"]:
111
+ self.register_plugin(built_in)
112
+
113
+ def get_plugins(self, category) -> Iterable:
114
+ """Get available plugins for the given category
115
+
116
+ Gets all plugin implementors of "category" by looking for register_<category>_plugin implementors. If such a
117
+ function does not exist then this results in an exception.
118
+
119
+ Args:
120
+ category: category of the plugin requested
121
+
122
+ Return:
123
+ validated list of plugin implementor classes
124
+ """
125
+ try:
126
+ plugin_classes = getattr(self.manager.hook, f"register_{category}_plugin")()
127
+ except KeyError as error:
128
+ raise InvalidCategoryException(f"Invalid plugin category: {error}")
129
+
130
+ return [
131
+ Plugin(category, self.get_category_plugin_type(category), plugin_class)
132
+ for plugin_class in plugin_classes
133
+ if self.validate_selection(category, plugin_class)
134
+ ]
135
+
136
+ def register_plugin(self, module_or_class):
137
+ """Register a plugin directly
138
+
139
+ Allows local registration of plugin implementations that are shipped as part of the GDS package.
140
+
141
+ Args:
142
+ module_or_class: module or class that has plugin implementations
143
+ """
144
+ self.manager.register(module_or_class)
145
+
146
+ def get_categories(self):
147
+ """ Get plugin categories """
148
+ return self.categories
149
+
150
+ @staticmethod
151
+ def get_all_categories():
152
+ """ Get all plugin categories """
153
+ return _PLUGIN_METADATA.keys()
154
+
155
+ @staticmethod
156
+ def get_plugin_metadata(category):
157
+ """ Get the plugin metadata for a given plugin category """
158
+ return _PLUGIN_METADATA[category]
159
+
160
+ @classmethod
161
+ def get_category_plugin_type(cls, category):
162
+ """ Get the plugin type given the category """
163
+ return cls.get_plugin_metadata(category)["type"]
164
+
165
+ @classmethod
166
+ def get_category_specification_class(cls, category):
167
+ """ Get the plugin class given the category """
168
+ return cls.get_plugin_metadata(category)["class"]
169
+
170
+ @classmethod
171
+ def validate_selection(cls, category, result):
172
+ """Validate the result of plugin hook
173
+
174
+ Validates the result of a plugin hook call to ensure the result meets the expected properties for plugins of the
175
+ given category. Primarily this ensures that this plugin returns a concrete subclass of the expected type.
176
+
177
+ Args:
178
+ category: category of plugin used
179
+ result: result from the plugin hook call
180
+ Return:
181
+ True when the plugin passes validation, False otherwise
182
+ """
183
+ # Typing library not intended for introspection at runtime, thus we maintain a map of plugin specification
184
+ # functions to the types expected as a return value. When this is not found, plugins may continue without
185
+ # automatic validation.
186
+ try:
187
+ expected_class = cls.get_category_specification_class(category)
188
+ # Validate the result
189
+ if not issubclass(result, expected_class):
190
+ LOGGER.warning(
191
+ f"{result.__name__} is not a subclass of {expected_class.__name__}. Not registering."
192
+ )
193
+ return False
194
+ elif inspect.isabstract(result):
195
+ LOGGER.warning(
196
+ f"{result.__name__} is an abstract class. Not registering."
197
+ )
198
+ return False
199
+ except KeyError:
200
+ LOGGER.warning(
201
+ f"Plugin not registered for validation. Continuing without validation."
202
+ )
203
+ return True
204
+
205
+ @classmethod
206
+ def system(cls, categories: Union[None, List] = None) -> "Plugins":
207
+ """ Get plugin system singleton
208
+
209
+ Constructs the plugin system singleton (when it has yet to be constructed) then returns the singleton. The
210
+ singleton will support specific categories and further requests for a singleton will cause an assertion error
211
+ unless the categories match or is None.
212
+
213
+ Args:
214
+ categories: a list of categories to support or None to use the existing categories
215
+
216
+ Returns:
217
+ plugin system
218
+ """
219
+ # Singleton undefined, construct it
220
+ if cls._singleton is None:
221
+ cls._singleton = cls(cls.get_all_categories() if categories is None else categories)
222
+ # Ensure categories was unspecified or matches the singleton
223
+ assert categories is None or cls._singleton.categories == categories, "Inconsistent plugin categories"
224
+ return cls._singleton
225
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fprime-gds
3
- Version: 3.4.2
3
+ Version: 3.4.4a1
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:
@@ -234,7 +234,7 @@ Requires-Dist: pyzmq >=24.0.1
234
234
  Requires-Dist: pexpect >=4.8.0
235
235
  Requires-Dist: pytest >=6.2.4
236
236
  Requires-Dist: flask-restful >=0.3.8
237
- Requires-Dist: fprime-tools >=3.1.2a1
237
+ Requires-Dist: fprime-tools >=3.4.3
238
238
  Requires-Dist: argcomplete >=1.12.3
239
239
  Requires-Dist: Jinja2 >=2.11.3
240
240
  Requires-Dist: openpyxl >=3.0.10
@@ -4,16 +4,16 @@ fprime_gds/version.py,sha256=dlUlfOKTsGaqz_L7TjhCVC-Vanx5cK67kdZlqcHCM8M,395
4
4
  fprime_gds/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  fprime_gds/common/handlers.py,sha256=t2-st-C3Z486kfcu2cpf-wHJQmpaaHQYj1dyXJEMmSU,2632
6
6
  fprime_gds/common/transport.py,sha256=y9HiupzsCRF5_JFMMtMWQxcEYPvPuxX1P_oBeqosKR0,10565
7
- fprime_gds/common/zmq_transport.py,sha256=TyYc--9rzjCSc8FxNran-i9CWK2pV-07T6NO7z2AzjY,12162
7
+ fprime_gds/common/zmq_transport.py,sha256=Wb9IFFyp89S6y2okYavmVygOSqg7IJMbBoyBOR4iIrg,12291
8
8
  fprime_gds/common/communication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- fprime_gds/common/communication/checksum.py,sha256=Oz2E1zM2xc-wIFp9ruYWmWrQmHhCQFmdGZhW2oBdSRU,789
10
- fprime_gds/common/communication/framing.py,sha256=oKZf4aptvgskh2R-GxzrzYRIXzLY9Zx6i8383cHyRcU,11081
9
+ fprime_gds/common/communication/checksum.py,sha256=f6W0Tr68U-XGnFmysMqsFzoGYZVE8clKf-VIJja_1YM,741
10
+ fprime_gds/common/communication/framing.py,sha256=TPpVn5JfGJxdc9BuKJzm5LXo6OQKtkSqX695UdN-Ezk,12915
11
11
  fprime_gds/common/communication/ground.py,sha256=9SD3AoyHA43yNE8UYkWnu5nEJt1PgyB3sU3QLDc4eDY,3619
12
12
  fprime_gds/common/communication/updown.py,sha256=UhfCIIA2eM5g2FsIhOGJJH6HzHurUPgcKIJ5fsLb2lE,9888
13
13
  fprime_gds/common/communication/adapters/__init__.py,sha256=ivGtzUTqhBYuve5mhN9VOHITwgZjNMVv7sxuac2Ll3c,470
14
- fprime_gds/common/communication/adapters/base.py,sha256=BqIjt6jzjn2ViqDHLKAV7Tez7OburnUahbu4I2CU3hI,4782
15
- fprime_gds/common/communication/adapters/ip.py,sha256=h1WJSq0GZ2pngn-Uzu3vixJzsPS-xai0ufSJSYoeKZU,16644
16
- fprime_gds/common/communication/adapters/uart.py,sha256=ArOGmo79JD2jWN8J7vb4pZcfUXxMJpa2urt1hY2Q8OQ,6373
14
+ fprime_gds/common/communication/adapters/base.py,sha256=i3mf4HC-4tuf4mNkhdXCKlngRhODyTriia2pw6XBoSQ,3393
15
+ fprime_gds/common/communication/adapters/ip.py,sha256=vCDclpsb3rVRXSxKqdt9UfkM2M6oCxnsKdzbzhMc0kM,17074
16
+ fprime_gds/common/communication/adapters/uart.py,sha256=6SrN42ShVjwNubFg-1YrO09o1uJtu1rFqeMpLDNWlW4,6647
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
@@ -66,7 +66,7 @@ fprime_gds/common/loaders/event_py_loader.py,sha256=m4KlDl0mXn8ZQr-IfpUg0KaGIOJU
66
66
  fprime_gds/common/loaders/event_xml_loader.py,sha256=DXyriGpGiuzG1a5Eyb8PLH3x7X1-hNxiIpY_yC3UPgQ,2790
67
67
  fprime_gds/common/loaders/pkt_xml_loader.py,sha256=ZS4qchqQnIBx0Tw69ehP8yqm1g_uYSQzmnijR3FxqJg,4795
68
68
  fprime_gds/common/loaders/python_loader.py,sha256=FUNQbFy75bpqvss1JDu2UWZBMrtnMpFegM6mcglh42I,4858
69
- fprime_gds/common/loaders/xml_loader.py,sha256=inrVbfhPOHzziGdZgdR1wgspdXYXvh-I9zgf_knPZeo,13914
69
+ fprime_gds/common/loaders/xml_loader.py,sha256=QqNYFjxLB7mmj-9rsqKHB1QunC-dcj1cBHrvhhZvakw,14121
70
70
  fprime_gds/common/logger/__init__.py,sha256=YBrr9An0fZbp4kvphRl8nLfolkdBqFAsSGzEZXQiH6g,1448
71
71
  fprime_gds/common/logger/data_logger.py,sha256=VjfhTGO1gGw954xNhSc0_zpw8JexCho5f8BlXDEYkL4,2505
72
72
  fprime_gds/common/logger/test_logger.py,sha256=wL8Lq49sVmxGRALgv-ei6AnXFh79qlHFehmKJ1A8X28,6475
@@ -102,12 +102,13 @@ fprime_gds/common/utils/data_desc_type.py,sha256=9GV8hV5q1dDxdfF-1-Wty5MBrFd94Eb
102
102
  fprime_gds/common/utils/event_severity.py,sha256=7qPXHrDaM_REJ7sKBUEJTZIE0D4qVnVajsPDUuHg7sI,300
103
103
  fprime_gds/common/utils/string_util.py,sha256=jqut5Dd0EjvTHMci1mvs_8KQ1Nq-38xZofeaaSoiJEY,3985
104
104
  fprime_gds/executables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
- fprime_gds/executables/cli.py,sha256=F4qkckoYCoGlh5T_WByOj6CDI3wm_nBM1K57wzkXmtM,31127
106
- fprime_gds/executables/comm.py,sha256=86CO8eczu5y2lsdPnPPFtK1pEUVLrSyU9smC09bON-Q,5382
105
+ fprime_gds/executables/apps.py,sha256=h2acqdOyMgv77IMEQUc41QcwAZ-_DToX6sZplCk17Zg,6543
106
+ fprime_gds/executables/cli.py,sha256=bitIny2JYApMVuu3G4adnxB9iI-pieDaXAWJjNcHcLo,36942
107
+ fprime_gds/executables/comm.py,sha256=KMoAtcUdE_KOFg4DynHCCCc3rfIiedjexx_FP6oN77s,5259
107
108
  fprime_gds/executables/fprime_cli.py,sha256=GvvuUQuoDGBrqQB867bDjUR3Kn5yPUckAY2rdfTa8jo,12432
108
- fprime_gds/executables/run_deployment.py,sha256=4M5646tH-LdjEgQGwAIJ3mf10pfivHlDBPrUwhLkJWI,6157
109
+ fprime_gds/executables/run_deployment.py,sha256=01tI0JVONRkKaPPdfJS0Qt1mWm_7Wgf3N9iknozXmYc,7043
109
110
  fprime_gds/executables/tcpserver.py,sha256=KspVpu5YIuiWKOk5E6UDMKvqXYrRB1j9aX8CkMxysfw,17555
110
- fprime_gds/executables/utils.py,sha256=CTw2gMO3vguqra8V8AEJodY6zcX18zO4AyA-EKwThmM,7195
111
+ fprime_gds/executables/utils.py,sha256=cBCFOpQthjxohWZmsdAQL1Y_lFYw73SQ-ANDjUoe33w,7221
111
112
  fprime_gds/flask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
113
  fprime_gds/flask/app.py,sha256=kJDCziri_BwZWKUszkR7u3RaNG_FWRzDkdCPsVDAtYM,6720
113
114
  fprime_gds/flask/channels.py,sha256=sOeL-UmWPh2hqYvqj81STpABLlPcjdPgkRwjd3Qx77k,735
@@ -218,10 +219,13 @@ fprime_gds/flask/static/third-party/webfonts/fa-solid-900.svg,sha256=lnTrG9VQRxe
218
219
  fprime_gds/flask/static/third-party/webfonts/fa-solid-900.ttf,sha256=r2OXUD_O-9YTl2whrVweNymMGLvgfQltsDzNOvbgW6g,202744
219
220
  fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff,sha256=P200iM9lN09vZ2wxU0CwrCvoMr1VJAyAlEjjbvm5YyY,101648
220
221
  fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2,sha256=mDS4KtJuKjdYPSJnahLdLrD-fIA1aiEU0NsaqLOJlTc,78268
221
- fprime_gds-3.4.2.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
222
- fprime_gds-3.4.2.dist-info/METADATA,sha256=WUBi5_aQB8mc7eqrif1-T3rFL6pYeQLv6K5VC_BcE58,24755
223
- fprime_gds-3.4.2.dist-info/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
224
- fprime_gds-3.4.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
225
- fprime_gds-3.4.2.dist-info/entry_points.txt,sha256=UisSXL905z4YEjwd7c-I2o6ZKmOw1xDDdO1mN0VPu6c,271
226
- fprime_gds-3.4.2.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
227
- fprime_gds-3.4.2.dist-info/RECORD,,
222
+ fprime_gds/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
+ fprime_gds/plugin/definitions.py,sha256=5rHGSOrr62qRNVfX9bZIo4HDAKG62lKteNum9G40y3g,2347
224
+ fprime_gds/plugin/system.py,sha256=uWd6DVW90Re0FoNMPNCx0cXXTJUdpgAAO0mtakzRNgk,8564
225
+ fprime_gds-3.4.4a1.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
226
+ fprime_gds-3.4.4a1.dist-info/METADATA,sha256=TiKl7YCs8sVBbCDBfQm6EK67tFvTtfH3f_hl3ewZ-tY,24755
227
+ fprime_gds-3.4.4a1.dist-info/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
228
+ fprime_gds-3.4.4a1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
229
+ fprime_gds-3.4.4a1.dist-info/entry_points.txt,sha256=UisSXL905z4YEjwd7c-I2o6ZKmOw1xDDdO1mN0VPu6c,271
230
+ fprime_gds-3.4.4a1.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
231
+ fprime_gds-3.4.4a1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5