fprime-gds 3.4.1__tar.gz → 3.4.2__tar.gz

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 (274) hide show
  1. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/pull_request_template.md +0 -5
  2. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/workflows/fprime-gds-tests.yml +2 -2
  3. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/PKG-INFO +1 -1
  4. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/seq_writer.py +2 -2
  5. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/files/uplinker.py +4 -4
  6. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/xml_loader.py +9 -0
  7. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/files.py +5 -4
  8. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/standard.py +23 -5
  9. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/testing_fw/api.py +4 -3
  10. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/cli.py +19 -6
  11. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/comm.py +1 -1
  12. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/run_deployment.py +1 -1
  13. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/utils.py +11 -8
  14. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/app.py +4 -9
  15. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/default_settings.py +1 -12
  16. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-history.js +23 -2
  17. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/updown.py +57 -6
  18. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/PKG-INFO +1 -1
  19. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/SOURCES.txt +0 -1
  20. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/testing_fw/api_unit_test.py +2 -2
  21. fprime-gds-3.4.1/src/fprime_gds/flask/flask_uploads.py +0 -542
  22. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/actions/codeql/security-pack.yml +0 -0
  24. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/actions/spelling/excludes.txt +0 -0
  25. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/actions/spelling/expect.txt +0 -0
  26. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/actions/spelling/patterns.txt +0 -0
  27. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/resources/RefTopologyAppDictionary.xml +0 -0
  28. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/workflows/codeql-security-scan.yml +0 -0
  29. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/workflows/gds-cli-tests.yml +0 -0
  30. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/workflows/publish.yml +0 -0
  31. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.github/workflows/spelling.yml +0 -0
  32. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/.gitignore +0 -0
  33. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/Doxyfile +0 -0
  34. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/LICENSE.txt +0 -0
  35. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/NOTICE.txt +0 -0
  36. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/README.md +0 -0
  37. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/configs/__init__.py +0 -0
  38. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/docs/README.md +0 -0
  39. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/docs/_static/css/rtd_width.css +0 -0
  40. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/docs/conf.py +0 -0
  41. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/docs/gendoc.bash +0 -0
  42. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/docs/index.rst +0 -0
  43. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/examples/simple_sequence.bin +0 -0
  44. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/examples/simple_sequence.seq +0 -0
  45. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/pyproject.toml +0 -0
  46. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/pytest.ini +0 -0
  47. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/setup.cfg +0 -0
  48. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/setup.py +0 -0
  49. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fastentrypoints.py +0 -0
  50. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/__init__.py +0 -0
  51. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/__init__.py +0 -0
  52. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/__init__.py +0 -0
  53. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/adapters/__init__.py +0 -0
  54. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/adapters/base.py +0 -0
  55. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/adapters/ip.py +0 -0
  56. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/adapters/uart.py +0 -0
  57. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/checksum.py +0 -0
  58. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/framing.py +0 -0
  59. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/ground.py +0 -0
  60. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/communication/updown.py +0 -0
  61. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/controllers/__init__.py +0 -0
  62. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/__init__.py +0 -0
  63. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/ch_data.py +0 -0
  64. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/cmd_data.py +0 -0
  65. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/event_data.py +0 -0
  66. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/exceptions.py +0 -0
  67. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/file_data.py +0 -0
  68. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/pkt_data.py +0 -0
  69. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/data_types/sys_data.py +0 -0
  70. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/__init__.py +0 -0
  71. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/ch_decoder.py +0 -0
  72. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/decoder.py +0 -0
  73. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/event_decoder.py +0 -0
  74. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/file_decoder.py +0 -0
  75. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/decoders/pkt_decoder.py +0 -0
  76. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/distributor/__init__.py +0 -0
  77. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/distributor/distributor.py +0 -0
  78. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/__init__.py +0 -0
  79. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/ch_encoder.py +0 -0
  80. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/cmd_encoder.py +0 -0
  81. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/encoder.py +0 -0
  82. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/event_encoder.py +0 -0
  83. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/file_encoder.py +0 -0
  84. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/encoders/pkt_encoder.py +0 -0
  85. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/files/File Decoder Documentation.txt +0 -0
  86. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/files/__init__.py +0 -0
  87. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/files/downlinker.py +0 -0
  88. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/files/helpers.py +0 -0
  89. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/__init__.py +0 -0
  90. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/base_commands.py +0 -0
  91. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/channels.py +0 -0
  92. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/command_send.py +0 -0
  93. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/events.py +0 -0
  94. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/filtering_utils.py +0 -0
  95. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/gds_cli/test_api_utils.py +0 -0
  96. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/handlers.py +0 -0
  97. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/history/__init__.py +0 -0
  98. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/history/chrono.py +0 -0
  99. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/history/history.py +0 -0
  100. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/history/ram.py +0 -0
  101. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/history/test.py +0 -0
  102. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/__init__.py +0 -0
  103. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/ch_py_loader.py +0 -0
  104. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/ch_xml_loader.py +0 -0
  105. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/cmd_py_loader.py +0 -0
  106. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/cmd_xml_loader.py +0 -0
  107. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/dict_loader.py +0 -0
  108. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/event_py_loader.py +0 -0
  109. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/event_xml_loader.py +0 -0
  110. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/pkt_xml_loader.py +0 -0
  111. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/loaders/python_loader.py +0 -0
  112. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/logger/__init__.py +0 -0
  113. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/logger/data_logger.py +0 -0
  114. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/logger/test_logger.py +0 -0
  115. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/models/__init__.py +0 -0
  116. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/models/common/__init__.py +0 -0
  117. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/models/common/channel_telemetry.py +0 -0
  118. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/models/common/command.py +0 -0
  119. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/models/common/event.py +0 -0
  120. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/parsers/__init__.py +0 -0
  121. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/parsers/seq_file_parser.py +0 -0
  122. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/__init__.py +0 -0
  123. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/dictionaries.py +0 -0
  124. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/encoding.py +0 -0
  125. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/histories.py +0 -0
  126. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/pipeline/router.py +0 -0
  127. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/__init__.py +0 -0
  128. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/ch_template.py +0 -0
  129. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/cmd_template.py +0 -0
  130. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/data_template.py +0 -0
  131. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/event_template.py +0 -0
  132. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/templates/pkt_template.py +0 -0
  133. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/testing_fw/__init__.py +0 -0
  134. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/testing_fw/predicates.py +0 -0
  135. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/testing_fw/pytest_integration.py +0 -0
  136. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/tools/__init__.py +0 -0
  137. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/tools/seqgen.py +0 -0
  138. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/transport.py +0 -0
  139. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/utils/__init__.py +0 -0
  140. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/utils/config_manager.py +0 -0
  141. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/utils/data_desc_type.py +0 -0
  142. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/utils/event_severity.py +0 -0
  143. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/utils/string_util.py +0 -0
  144. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/common/zmq_transport.py +0 -0
  145. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/__init__.py +0 -0
  146. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/fprime_cli.py +0 -0
  147. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/executables/tcpserver.py +0 -0
  148. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/__init__.py +0 -0
  149. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/channels.py +0 -0
  150. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/commands.py +0 -0
  151. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/components.py +0 -0
  152. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/errors.py +0 -0
  153. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/events.py +0 -0
  154. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/json.py +0 -0
  155. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/logs.py +0 -0
  156. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/requirements.txt +0 -0
  157. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/resource.py +0 -0
  158. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/sequence.py +0 -0
  159. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/.idea/.gitignore +0 -0
  160. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/.idea/misc.xml +0 -0
  161. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/.idea/modules.xml +0 -0
  162. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/.idea/static.iml +0 -0
  163. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/.idea/vcs.xml +0 -0
  164. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/advanced-settings/addon-templates.js +0 -0
  165. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/advanced-settings/addon.js +0 -0
  166. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/channel-render/addon.js +0 -0
  167. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/channel-render/channel-render-template.js +0 -0
  168. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/channel-render/channel-render.js +0 -0
  169. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/addon-templates.js +0 -0
  170. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/addon.js +0 -0
  171. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/config.js +0 -0
  172. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/modified-vendor/chartjs-plugin-streaming.js +0 -0
  173. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/modified-vendor/chartjs-plugin-zoom.js +0 -0
  174. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/modified-vendor/flat.js +0 -0
  175. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/sibling.js +0 -0
  176. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/vendor/chart.js +0 -0
  177. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/vendor/chartjs-adapter-luxon.min.js +0 -0
  178. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/chart-display/vendor/hammer.min.js +0 -0
  179. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/addon.js +0 -0
  180. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/argument-templates.js +0 -0
  181. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/arguments.js +0 -0
  182. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-history-template.js +0 -0
  183. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-input-template.js +0 -0
  184. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-input.js +0 -0
  185. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-string-template.js +0 -0
  186. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/commanding/command-string.js +0 -0
  187. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/dictionary/addon-templates.js +0 -0
  188. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/dictionary/addon.js +0 -0
  189. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/enabled.js +0 -0
  190. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/image-display/addon.js +0 -0
  191. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/image-display/dashboard.xml +0 -0
  192. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/README.md +0 -0
  193. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/addon-templates.js +0 -0
  194. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/addon.js +0 -0
  195. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/autocomplete.js +0 -0
  196. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/lint.js +0 -0
  197. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/code-mirror.es.js +0 -0
  198. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/rollup/.gitignore +0 -0
  199. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/rollup/index.js +0 -0
  200. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/rollup/language.grammer +0 -0
  201. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/rollup/package.json +0 -0
  202. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/addons/sequencer/third/rollup/rollup.config.js +0 -0
  203. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/css/fprime.css +0 -0
  204. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/css/fpstyle.css +0 -0
  205. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/favicon.ico +0 -0
  206. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/img/error.svg +0 -0
  207. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/img/logo.svg +0 -0
  208. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/img/success.svg +0 -0
  209. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/index.html +0 -0
  210. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/config.js +0 -0
  211. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/datastore.js +0 -0
  212. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/gds.js +0 -0
  213. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/loader.js +0 -0
  214. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/performance.js +0 -0
  215. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/settings.js +0 -0
  216. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/uploader.js +0 -0
  217. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/validate.js +0 -0
  218. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/channel.js +0 -0
  219. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/dashboard-box.js +0 -0
  220. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/dashboard-row.js +0 -0
  221. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/dashboard.js +0 -0
  222. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/downlink.js +0 -0
  223. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/event.js +0 -0
  224. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/fp-row.js +0 -0
  225. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/fptable.js +0 -0
  226. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/log.js +0 -0
  227. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/tabetc.js +0 -0
  228. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/uplink.js +0 -0
  229. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/js/vue-support/utils.js +0 -0
  230. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/css/all.min.css +0 -0
  231. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/css/bootstrap.min.css +0 -0
  232. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/css/vue-select.css +0 -0
  233. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/js/luxon.min.js +0 -0
  234. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/js/sorttable.js +0 -0
  235. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/js/v-runtime-template.js +0 -0
  236. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/js/vue-select.js +0 -0
  237. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/js/vue.min.js +0 -0
  238. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-brands-400.eot +0 -0
  239. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-brands-400.svg +0 -0
  240. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-brands-400.ttf +0 -0
  241. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-brands-400.woff +0 -0
  242. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-brands-400.woff2 +0 -0
  243. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-regular-400.eot +0 -0
  244. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-regular-400.svg +0 -0
  245. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-regular-400.ttf +0 -0
  246. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-regular-400.woff +0 -0
  247. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-regular-400.woff2 +0 -0
  248. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-solid-900.eot +0 -0
  249. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-solid-900.svg +0 -0
  250. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-solid-900.ttf +0 -0
  251. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff +0 -0
  252. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2 +0 -0
  253. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/flask/stats.py +0 -0
  254. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds/version.py +0 -0
  255. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/dependency_links.txt +0 -0
  256. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/entry_points.txt +0 -0
  257. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/requires.txt +0 -0
  258. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/src/fprime_gds.egg-info/top_level.txt +0 -0
  259. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/distributor/test_distributor.py +0 -0
  260. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/encoders/test_ch_encoder.py +0 -0
  261. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/encoders/test_event_encoder.py +0 -0
  262. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/encoders/test_pkt_encoder.py +0 -0
  263. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/gds_cli/filtering_utils_test.py +0 -0
  264. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/gds_cli/utils_test.py +0 -0
  265. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/history/chronohistory_unit_test.py +0 -0
  266. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/history/testhistory_unit_test.py +0 -0
  267. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/testing_fw/UnitTestDictionary.xml +0 -0
  268. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/testing_fw/logs/.gitignore +0 -0
  269. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/testing_fw/predicate_unit_test.py +0 -0
  270. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/tools/seqgen_unit_test.py +0 -0
  271. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/common/utils/test_string_util.py +0 -0
  272. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/executables/test_run_deployment.py +0 -0
  273. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/fprime_gds/executables/test_utils.py +0 -0
  274. {fprime-gds-3.4.1 → fprime-gds-3.4.2}/test/gui/GUI_Test_Procedure.md +0 -0
@@ -1,12 +1,7 @@
1
1
  | | |
2
2
  |:---|:---|
3
- |**_Originating Project/Creator_**| |
4
- |**_Affected Component_**| |
5
- |**_Affected Architectures(s)_**| |
6
3
  |**_Related Issue(s)_**| |
7
4
  |**_Has Unit Tests (y/n)_**| |
8
- |**_Builds Without Errors (y/n)_**| |
9
- |**_Unit Tests Pass (y/n)_**| |
10
5
  |**_Documentation Included (y/n)_**| |
11
6
 
12
7
  ---
@@ -16,9 +16,9 @@ jobs:
16
16
  python-version: ["3.8", "3.9", "3.10", "3.11"]
17
17
 
18
18
  steps:
19
- - uses: actions/checkout@v3
19
+ - uses: actions/checkout@v4
20
20
  - name: Set up Python ${{ matrix.python-version }}
21
- uses: actions/setup-python@v2
21
+ uses: actions/setup-python@v4
22
22
  with:
23
23
  python-version: ${{ matrix.python-version }}
24
24
  - name: Install dependencies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fprime-gds
3
- Version: 3.4.1
3
+ Version: 3.4.2
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:
@@ -137,9 +137,9 @@ class SeqBinaryWriter:
137
137
  for cmd in seq_cmds_list:
138
138
  sequence += self.__binaryCmdRecord(cmd)
139
139
  size = len(sequence)
140
- tb_txt = b"ANY" if self.__timebase == 0xFFFF else bytes(self.__timebase)
140
+ tb_txt = "ANY" if self.__timebase == 0xFFFF else hex(self.__timebase)
141
141
 
142
- print("Sequence is %d bytes with timebase %s" % (size, tb_txt))
142
+ print(f"Sequence is {size} bytes with timebase {tb_txt}")
143
143
 
144
144
  header = b""
145
145
  header += U32Type(
@@ -47,7 +47,9 @@ class UplinkQueue:
47
47
  self.queue = queue.Queue()
48
48
  self.__file_store = []
49
49
  self.__exit = threading.Event()
50
- self.__thread = threading.Thread(target=self.run, name="UplinkerThread", args=())
50
+ self.__thread = threading.Thread(
51
+ target=self.run, name="UplinkerThread", args=()
52
+ )
51
53
  self.__thread.start()
52
54
 
53
55
  def enqueue(self, filepath, destination):
@@ -228,9 +230,7 @@ class FileUplinker(fprime_gds.common.handlers.DataHandler):
228
230
  # Prevent multiple uplinks at once
229
231
  if self.state != FileStates.IDLE:
230
232
  msg = f"Currently uplinking file '{self.active.source}' cannot start uplinking '{file_obj.source}'"
231
- raise FileUplinkerBusyException(
232
- msg
233
- )
233
+ raise FileUplinkerBusyException(msg)
234
234
  self.state = FileStates.RUNNING
235
235
  self.active = file_obj
236
236
  self.active.open(TransmitFileState.READ)
@@ -61,6 +61,7 @@ class XmlLoader(dict_loader.DictLoader):
61
61
  SER_MEMB_FMT_STR_TAG = "format_specifier"
62
62
  SER_MEMB_DESC_TAG = "description"
63
63
  SER_MEMB_TYPE_TAG = "type"
64
+ SER_MEMB_SIZE_TAG = "size"
64
65
 
65
66
  # Xml section names and tags for array types
66
67
  ARR_SECT = "arrays"
@@ -256,7 +257,15 @@ class XmlLoader(dict_loader.DictLoader):
256
257
  fmt_str = memb.get(self.SER_MEMB_FMT_STR_TAG)
257
258
  desc = memb.get(self.SER_MEMB_DESC_TAG)
258
259
  memb_type_name = memb.get(self.SER_MEMB_TYPE_TAG)
260
+ memb_size = memb.get(self.SER_MEMB_SIZE_TAG)
259
261
  type_obj = self.parse_type(memb_type_name, memb, xml_obj)
262
+ # memb_size is not None for member array
263
+ if(memb_size is not None):
264
+ type_obj = ArrayType.construct_type(
265
+ f"Array_{type_obj.__name__}_{memb_size}",
266
+ type_obj,
267
+ int(memb_size),
268
+ fmt_str)
260
269
 
261
270
  members.append((name, type_obj, fmt_str, desc))
262
271
 
@@ -7,7 +7,7 @@ communications layer.
7
7
 
8
8
  @author mstarch
9
9
  """
10
- import os
10
+ from pathlib import Path
11
11
  import fprime_gds.common.files.downlinker
12
12
  import fprime_gds.common.files.uplinker
13
13
 
@@ -43,10 +43,11 @@ class Filing:
43
43
  )
44
44
  file_decoder.register(self.__downlinker)
45
45
  distributor.register("FW_PACKET_HAND", self.__uplinker)
46
- if not os.access(down_store, os.W_OK):
46
+ try:
47
+ Path(down_store).mkdir(parents=True, exist_ok=True)
48
+ except PermissionError:
47
49
  raise PermissionError(
48
- f"{down_store} is not writable. Downlinker not be able to save files. "
49
- "Fix permissions or change storage directory with --file-storage-directory."
50
+ f"{down_store} is not writable. Fix permissions or change storage directory with --file-storage-directory."
50
51
  )
51
52
 
52
53
  @property
@@ -44,6 +44,8 @@ class StandardPipeline:
44
44
  self.client_socket = None
45
45
  self.logger = None
46
46
  self.dictionary_path = None
47
+ self.up_store = None
48
+ self.down_store = None
47
49
 
48
50
  self.__dictionaries = dictionaries.Dictionaries()
49
51
  self.__coders = encoding.EncodingDecoding()
@@ -52,7 +54,7 @@ class StandardPipeline:
52
54
  self.__transport_type = ThreadedTCPSocketClient
53
55
 
54
56
  def setup(
55
- self, config, dictionary, down_store, logging_prefix=None, packet_spec=None
57
+ self, config, dictionary, file_store, logging_prefix=None, packet_spec=None
56
58
  ):
57
59
  """
58
60
  Setup the standard pipeline for moving data from the middleware layer through the GDS layers using the standard
@@ -60,11 +62,23 @@ class StandardPipeline:
60
62
 
61
63
  :param config: config object used when constructing the pipeline.
62
64
  :param dictionary: dictionary path. Used to setup loading of dictionaries.
63
- :param down_store: downlink storage directory
65
+ :param file_store: uplink/downlink storage directory
64
66
  :param logging_prefix: logging prefix. Defaults to not logging at all.
65
67
  :param packet_spec: location of packetized telemetry XML specification.
66
68
  """
67
- assert dictionary is not None and Path(dictionary).is_file(), f"Dictionary {dictionary} does not exist"
69
+ assert (
70
+ dictionary is not None and Path(dictionary).is_file()
71
+ ), f"Dictionary {dictionary} does not exist"
72
+ # File storage configuration for uplink and downlink
73
+ self.up_store = Path(file_store) / "fprime-uplink"
74
+ self.down_store = Path(file_store) / "fprime-downlink"
75
+ try:
76
+ self.down_store.mkdir(parents=True, exist_ok=True)
77
+ self.up_store.mkdir(parents=True, exist_ok=True)
78
+ except PermissionError:
79
+ raise PermissionError(
80
+ f"{file_store} is not writable. Fix permissions or change storage directory with --file-storage-directory."
81
+ )
68
82
  self.dictionary_path = Path(dictionary)
69
83
  # Loads the distributor and client socket
70
84
  self.distributor = fprime_gds.common.distributor.distributor.Distributor(config)
@@ -76,7 +90,7 @@ class StandardPipeline:
76
90
  )
77
91
  self.histories.setup_histories(self.coders)
78
92
  self.files.setup_file_handling(
79
- down_store,
93
+ self.down_store,
80
94
  self.coders.file_encoder,
81
95
  self.coders.file_decoder,
82
96
  self.distributor,
@@ -152,7 +166,11 @@ class StandardPipeline:
152
166
  outgoing_tag: this pipeline will produce data for supplied tag (FSW, GUI). Default: FSW
153
167
  """
154
168
  # Backwards compatibility with the old method .connect(host, port)
155
- if isinstance(incoming_tag, int) and ":" not in connection_uri and outgoing_tag == RoutingTag.FSW:
169
+ if (
170
+ isinstance(incoming_tag, int)
171
+ and ":" not in connection_uri
172
+ and outgoing_tag == RoutingTag.FSW
173
+ ):
156
174
  connection_uri = f"{connection_uri}:{incoming_tag}"
157
175
  incoming_tag = RoutingTag.GUI
158
176
  self.client_socket.connect(connection_uri, incoming_tag, outgoing_tag)
@@ -402,7 +402,7 @@ class IntegrationTestAPI(DataHandler):
402
402
  return self.await_event_sequence(events, start=start, timeout=timeout)
403
403
  return self.await_event(events, start=start, timeout=timeout)
404
404
 
405
- def send_and_assert_command(self, command, args=[], max_delay=None, timeout=5, events=None):
405
+ def send_and_assert_command(self, command, args=[], max_delay=None, timeout=5, events=None, commander="cmdDisp"):
406
406
  """
407
407
  This helper will send a command and verify that the command was dispatched and completed
408
408
  within the F' deployment. This helper can retroactively check that the delay between
@@ -414,12 +414,13 @@ class IntegrationTestAPI(DataHandler):
414
414
  max_delay: the maximum allowable delay between dispatch and completion (int/float)
415
415
  timeout: the number of seconds to wait before terminating the search (int)
416
416
  events: extra event predicates to check between dispatch and complete
417
+ commander: the command dispatching component. Defaults to cmdDisp
417
418
  Return:
418
419
  returns a list of the EventData objects found by the search
419
420
  """
420
421
  cmd_id = self.translate_command_name(command)
421
- dispatch = [self.get_event_pred("cmdDisp.OpCodeDispatched", [cmd_id, None])]
422
- complete = [self.get_event_pred("cmdDisp.OpCodeCompleted", [cmd_id])]
422
+ dispatch = [self.get_event_pred(f"{commander}.OpCodeDispatched", [cmd_id, None])]
423
+ complete = [self.get_event_pred(f"{commander}.OpCodeCompleted", [cmd_id])]
423
424
  events = dispatch + (events if events else []) + complete
424
425
  results = self.send_and_assert_event(command, args, events, timeout=timeout)
425
426
  if max_delay is not None:
@@ -547,18 +547,31 @@ class FileHandlingParser(ParserBase):
547
547
 
548
548
  return {
549
549
  ("--file-storage-directory",): {
550
- "dest": "files_directory",
550
+ "dest": "files_storage_directory",
551
551
  "action": "store",
552
- "default": "/tmp/" + username + "/fprime-downlink/",
552
+ "default": "/tmp/" + username,
553
553
  "required": False,
554
554
  "type": str,
555
- "help": "File to store uplink and downlink files. Default: %(default)s",
556
- }
555
+ "help": "Directory to store uplink and downlink files. Default: %(default)s",
556
+ },
557
+ ("--remote-sequence-directory",): {
558
+ "dest": "remote_sequence_directory",
559
+ "action": "store",
560
+ "default": "/seq",
561
+ "required": False,
562
+ "type": str,
563
+ "help": "Directory to save command sequence binaries, on the remote FSW. Default: %(default)s",
564
+ },
557
565
  }
558
566
 
559
567
  def handle_arguments(self, args, **kwargs):
560
568
  """Handle arguments as parsed"""
561
- os.makedirs(args.files_directory, exist_ok=True)
569
+ try:
570
+ Path(args.files_storage_directory).mkdir(parents=True, exist_ok=True)
571
+ except PermissionError:
572
+ raise PermissionError(
573
+ f"{args.files_storage_directory} is not writable. Fix permissions or change storage directory with --file-storage-directory."
574
+ )
562
575
  return args
563
576
 
564
577
 
@@ -584,7 +597,7 @@ class StandardPipelineParser(CompositeParser):
584
597
  pipeline_arguments = {
585
598
  "config": ConfigManager(),
586
599
  "dictionary": args_ns.dictionary,
587
- "down_store": args_ns.files_directory,
600
+ "file_store": args_ns.files_storage_directory,
588
601
  "packet_spec": args_ns.packet_spec,
589
602
  "logging_prefix": args_ns.logs,
590
603
  }
@@ -64,7 +64,7 @@ def main():
64
64
  )
65
65
  fprime_gds.common.communication.checksum = args.checksum_type
66
66
  if args.comm_adapter == "none":
67
- print("[ERROR] Comm adapter set to 'none'. Nothing to do but exit.")
67
+ print("[ERROR] Comm adapter set to 'none'. Nothing to do but exit.", file=sys.stderr)
68
68
  sys.exit(-1)
69
69
 
70
70
  # Create the handling components for either side of this script, adapter for hardware, and ground for the GDS side
@@ -168,7 +168,7 @@ def main():
168
168
  if parsed_args.adapter == "ip":
169
169
  launchers.append(launch_app)
170
170
  else:
171
- print("[WARNING] App cannot be auto-launched without IP adapter")
171
+ print("[WARNING] App cannot be auto-launched without IP adapter", file=sys.stderr)
172
172
 
173
173
  # Launch the desired GUI package
174
174
  if parsed_args.gui == "html":
@@ -146,11 +146,12 @@ def get_artifacts_root() -> Path:
146
146
  ini_settings = IniSettings.load(ini_file)
147
147
  except FprimeLocationUnknownException:
148
148
  print(
149
- "[ERROR] Not in fprime project and no deployment path provided, unable to find dictionary and/or app"
149
+ "[ERROR] Not in fprime project and no deployment path provided, unable to find dictionary and/or app",
150
+ file=sys.stderr
150
151
  )
151
152
  sys.exit(-1)
152
153
  except FprimeSettingsException as e:
153
- print("[ERROR]", e)
154
+ print("[ERROR]", e, file=sys.stderr)
154
155
  sys.exit(-1)
155
156
  assert (
156
157
  "install_destination" in ini_settings
@@ -165,17 +166,18 @@ def find_app(root: Path) -> Path:
165
166
  bin_dir = root / "bin"
166
167
 
167
168
  if not bin_dir.exists():
168
- print(f"[ERROR] binary location {bin_dir} does not exist")
169
+ print(f"[ERROR] binary location {bin_dir} does not exist", file=sys.stderr)
169
170
  sys.exit(-1)
170
171
 
171
172
  files = [child for child in bin_dir.iterdir() if child.is_file()]
172
173
  if not files:
173
- print(f"[ERROR] App not found in {bin_dir}")
174
+ print(f"[ERROR] App not found in {bin_dir}", file=sys.stderr)
174
175
  sys.exit(-1)
175
176
 
176
177
  if len(files) > 1:
177
178
  print(
178
- f"[ERROR] Multiple app candidates in binary location {bin_dir}. Specify app manually with --app."
179
+ f"[ERROR] Multiple app candidates in binary location {bin_dir}. Specify app manually with --app.",
180
+ file=sys.stderr
179
181
  )
180
182
  sys.exit(-1)
181
183
 
@@ -186,7 +188,7 @@ def find_dict(root: Path) -> Path:
186
188
  dict_dir = root / "dict"
187
189
 
188
190
  if not dict_dir.exists():
189
- print(f"[ERROR] dictionary location {dict_dir} does not exist")
191
+ print(f"[ERROR] dictionary location {dict_dir} does not exist", file=sys.stderr)
190
192
  sys.exit(-1)
191
193
 
192
194
  files = [
@@ -196,12 +198,13 @@ def find_dict(root: Path) -> Path:
196
198
  ]
197
199
 
198
200
  if not files:
199
- print(f"[ERROR] No xml dictionary found in dictionary location {dict_dir}")
201
+ print(f"[ERROR] No xml dictionary found in dictionary location {dict_dir}", file=sys.stderr)
200
202
  sys.exit(-1)
201
203
 
202
204
  if len(files) > 1:
203
205
  print(
204
- f"[ERROR] Multiple xml dictionaries found in dictionary location {dict_dir}. Specify dictionary manually with --dictionary."
206
+ f"[ERROR] Multiple xml dictionaries found in dictionary location {dict_dir}. Specify dictionary manually with --dictionary.",
207
+ file=sys.stderr
205
208
  )
206
209
  sys.exit(-1)
207
210
 
@@ -30,7 +30,6 @@ import fprime_gds.flask.sequence
30
30
  import fprime_gds.flask.stats
31
31
  import fprime_gds.flask.updown
32
32
  from fprime_gds.executables.cli import ParserBase, StandardPipelineParser
33
- from fprime_gds.flask import flask_uploads
34
33
 
35
34
  from . import components
36
35
 
@@ -49,8 +48,7 @@ def construct_app():
49
48
  2. Setup JSON encoding for Flask and flask_restful to handle F prime types natively
50
49
  3. Setup standard pipeline used throughout the system
51
50
  4. Create Restful API for registering flask items
52
- 5. Setup flask_uploads settings
53
- 6. Register all restful endpoints
51
+ 5. Register all restful endpoints
54
52
 
55
53
  :return: setup app
56
54
  """
@@ -77,9 +75,6 @@ def construct_app():
77
75
 
78
76
  # Restful API registration
79
77
  api = fprime_gds.flask.errors.setup_error_handling(app)
80
- # File upload configuration, 1 set for everything
81
- uplink_set = flask_uploads.UploadSet("uplink", flask_uploads.ALL)
82
- flask_uploads.configure_uploads(app, [uplink_set])
83
78
 
84
79
  # Application routes
85
80
  api.add_resource(
@@ -137,7 +132,7 @@ def construct_app():
137
132
  api.add_resource(
138
133
  fprime_gds.flask.updown.FileUploads,
139
134
  "/upload/files",
140
- resource_class_args=[pipeline.files.uplinker, uplink_set],
135
+ resource_class_args=[pipeline.files.uplinker, pipeline.up_store],
141
136
  )
142
137
  api.add_resource(
143
138
  fprime_gds.flask.updown.FileDownload,
@@ -150,9 +145,9 @@ def construct_app():
150
145
  "/sequence",
151
146
  resource_class_args=[
152
147
  args_ns.dictionary,
153
- app.config["UPLOADED_UPLINK_DEST"],
148
+ pipeline.up_store,
154
149
  pipeline.files.uplinker,
155
- app.config["REMOTE_SEQ_DIRECTORY"],
150
+ args_ns.remote_sequence_directory,
156
151
  ],
157
152
  )
158
153
  api.add_resource(
@@ -9,23 +9,12 @@
9
9
  #
10
10
  ####
11
11
  import os
12
- import getpass
13
-
14
- # Select uploads directory and create it
15
- username = getpass.getuser()
16
- uplink_dir = os.environ.get("UP_FILES_DIR", "/tmp/" + username + "/fprime-uplink/")
17
- DOWNLINK_DIR = os.environ.get("DOWN_FILES_DIR", "/tmp/" + username + "/fprime-downlink/")
18
12
 
19
13
  STANDARD_PIPELINE_ARGUMENTS = os.environ.get("STANDARD_PIPELINE_ARGUMENTS").split("|")
20
14
 
21
15
  SERVE_LOGS = os.environ.get("SERVE_LOGS", "YES") == "YES"
22
- UPLOADED_UPLINK_DEST = uplink_dir
23
- UPLOADS_DEFAULT_DEST = uplink_dir
24
- REMOTE_SEQ_DIRECTORY = "/seq"
25
- MAX_CONTENT_LENGTH = 32 * 1024 * 1024 # Max length of request is 32MiB
26
16
 
17
+ MAX_CONTENT_LENGTH = 32 * 1024 * 1024 # Max length of request is 32MiB
27
18
 
28
- for directory in [UPLOADED_UPLINK_DEST, UPLOADS_DEFAULT_DEST, DOWNLINK_DIR]:
29
- os.makedirs(directory, exist_ok=True)
30
19
 
31
20
  # TODO: load real config
@@ -102,8 +102,29 @@ Vue.component("command-history", {
102
102
  cmd.full_name = template.full_name;
103
103
  // Can only set command if it is a child of a command input
104
104
  if (this.$parent.selectCmd) {
105
- this.$parent.selectCmd(cmd.full_name, cmd.args);
105
+ // command-input expects an array of strings as arguments
106
+ this.$parent.selectCmd(cmd.full_name, this.preprocess_args(cmd.args));
107
+ }
108
+ },
109
+ /**
110
+ * Process the arguments for a command. If the argument is (or contains) a number, it
111
+ * is converted to a string. Other types that should be pre-processed can be added here.
112
+ *
113
+ * @param {*} args
114
+ * @returns args processed for command input (numbers converted to strings)
115
+ */
116
+ preprocess_args(args) {
117
+ if (Array.isArray(args)) {
118
+ return args.map(el => this.preprocess_args(el));
119
+ } else if (typeof args === 'object' && args !== null) {
120
+ return Object.fromEntries(
121
+ Object.entries(args).map(([key, value]) => [key, this.preprocess_args(value)])
122
+ );
123
+ } else if (typeof args === 'number') {
124
+ return args.toString();
125
+ } else {
126
+ return args;
106
127
  }
107
128
  }
108
129
  }
109
- });
130
+ });
@@ -11,6 +11,9 @@ import os
11
11
 
12
12
  import flask
13
13
  import flask_restful
14
+ from werkzeug.datastructures import FileStorage
15
+ from werkzeug.utils import secure_filename
16
+ from pathlib import Path
14
17
 
15
18
 
16
19
  class Destination(flask_restful.Resource):
@@ -51,12 +54,12 @@ class FileUploads(flask_restful.Resource):
51
54
  A data model for the current uplinking file set.
52
55
  """
53
56
 
54
- def __init__(self, uplinker, uplink_set):
57
+ def __init__(self, uplinker, dest_dir):
55
58
  """
56
59
  Constructor: setup the uplinker and argument parsing
57
60
  """
58
61
  self.uplinker = uplinker
59
- self.uplink_set = uplink_set
62
+ self.dest_dir = dest_dir
60
63
  self.parser = flask_restful.reqparse.RequestParser()
61
64
  self.parser.add_argument(
62
65
  "action", required=True, help="Action to take against files"
@@ -99,11 +102,9 @@ class FileUploads(flask_restful.Resource):
99
102
  failed = []
100
103
  for key, file in flask.request.files.items():
101
104
  try:
102
- filename = self.uplink_set.save(file)
105
+ filename = self.save(file)
103
106
  flask.current_app.logger.info(f"Received file. Saved to: {filename}")
104
- self.uplinker.enqueue(
105
- os.path.join(self.uplink_set.config.destination, filename)
106
- )
107
+ self.uplinker.enqueue(os.path.join(self.dest_dir, filename))
107
108
  successful.append(key)
108
109
  except Exception as exc:
109
110
  flask.current_app.logger.warning(
@@ -112,6 +113,56 @@ class FileUploads(flask_restful.Resource):
112
113
  failed.append(key)
113
114
  return {"successful": successful, "failed": failed}
114
115
 
116
+ def save(self, file_storage: FileStorage):
117
+ """
118
+ This saves a `werkzeug.FileStorage` into this upload set.
119
+
120
+ :param file_storage: The uploaded file to save.
121
+ """
122
+ if not isinstance(file_storage, FileStorage):
123
+ raise TypeError("file_storage must be a werkzeug.FileStorage")
124
+
125
+ filename = Path(secure_filename(file_storage.filename)).name
126
+ dest_dir = Path(self.dest_dir)
127
+
128
+ try:
129
+ dest_dir.mkdir(parents=True, exist_ok=True)
130
+ except PermissionError:
131
+ raise PermissionError(
132
+ f"{dest_dir} is not writable. Fix permissions or change storage directory with --file-storage-directory."
133
+ )
134
+
135
+ # resolve conflict may not be needed
136
+ if (dest_dir / filename).exists():
137
+ filename = self.resolve_conflict(dest_dir, filename)
138
+
139
+ target = dest_dir / filename
140
+ file_storage.save(str(target))
141
+
142
+ return filename
143
+
144
+ def resolve_conflict(self, target_folder: Path, filename: str):
145
+ """
146
+ If a file with the selected name already exists in the target folder,
147
+ this method is called to resolve the conflict. It should return a new
148
+ filename for the file.
149
+
150
+ The default implementation splits the name and extension and adds a
151
+ suffix to the name consisting of an underscore and a number, and tries
152
+ that until it finds one that doesn't exist.
153
+
154
+ :param target_folder: The absolute path to the target.
155
+ :param filename: The file's original filename.
156
+ """
157
+ path = Path(filename)
158
+ name, ext = path.stem, path.suffix
159
+ count = 0
160
+ while True:
161
+ count = count + 1
162
+ newname = f"{name}_{count}{ext}"
163
+ if not (Path(target_folder) / newname).exists():
164
+ return newname
165
+
115
166
 
116
167
  class FileDownload(flask_restful.Resource):
117
168
  """ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fprime-gds
3
- Version: 3.4.1
3
+ Version: 3.4.2
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:
@@ -150,7 +150,6 @@ src/fprime_gds/flask/components.py
150
150
  src/fprime_gds/flask/default_settings.py
151
151
  src/fprime_gds/flask/errors.py
152
152
  src/fprime_gds/flask/events.py
153
- src/fprime_gds/flask/flask_uploads.py
154
153
  src/fprime_gds/flask/json.py
155
154
  src/fprime_gds/flask/logs.py
156
155
  src/fprime_gds/flask/requirements.txt
@@ -77,8 +77,8 @@ class APITestCases(unittest.TestCase):
77
77
  cls.pipeline = UTPipeline()
78
78
  config = ConfigManager()
79
79
  path = os.path.join(os.path.dirname(__file__), "./UnitTestDictionary.xml")
80
- down_store = os.path.join(os.path.dirname(__file__), "./")
81
- cls.pipeline.setup(config, path, down_store)
80
+ file_store = os.path.join(os.path.dirname(__file__), "./")
81
+ cls.pipeline.setup(config, path, file_store)
82
82
  log_path = os.path.join(os.path.dirname(__file__), "./logs")
83
83
  cls.api = IntegrationTestAPI(cls.pipeline, log_path)
84
84
  cls.case_list = [] # TODO find a better way to do this.