science-synapse 2.7.2__tar.gz → 2.7.4__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 (154) hide show
  1. {science_synapse-2.7.2/science_synapse.egg-info → science_synapse-2.7.4}/PKG-INFO +1 -1
  2. {science_synapse-2.7.2 → science_synapse-2.7.4/science_synapse.egg-info}/PKG-INFO +1 -1
  3. {science_synapse-2.7.2 → science_synapse-2.7.4}/science_synapse.egg-info/SOURCES.txt +9 -0
  4. {science_synapse-2.7.2 → science_synapse-2.7.4}/setup.py +1 -1
  5. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/_api_version.py +1 -1
  6. science_synapse-2.7.4/synapse/api/query_pb2.py +42 -0
  7. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/__main__.py +1 -1
  8. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/build.py +146 -42
  9. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/deploy.py +11 -1
  10. science_synapse-2.7.4/synapse/cli/gateware.py +396 -0
  11. science_synapse-2.7.4/synapse/cli/peripherals.py +1022 -0
  12. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/query.py +1 -0
  13. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/__init__.pyi +1 -0
  14. science_synapse-2.7.4/synapse/tests/cli/conftest.py +72 -0
  15. science_synapse-2.7.4/synapse/tests/cli/test_custom_gateware_packaging.py +450 -0
  16. science_synapse-2.7.4/synapse/tests/cli/test_gateware_passthrough.py +1045 -0
  17. science_synapse-2.7.4/synapse/tests/cli/test_gateware_runner.py +253 -0
  18. science_synapse-2.7.4/synapse/tests/cli/test_half_selectors.py +990 -0
  19. science_synapse-2.7.4/synapse/tests/cli/test_license_mode.py +268 -0
  20. science_synapse-2.7.4/synapse/utils/model_converter/docker/__init__.py +0 -0
  21. science_synapse-2.7.4/synapse/utils/model_converter/docker/__init__.pyi +0 -0
  22. science_synapse-2.7.2/synapse/api/query_pb2.py +0 -42
  23. science_synapse-2.7.2/synapse/cli/peripherals.py +0 -488
  24. {science_synapse-2.7.2 → science_synapse-2.7.4}/LICENSE +0 -0
  25. {science_synapse-2.7.2 → science_synapse-2.7.4}/MANIFEST.in +0 -0
  26. {science_synapse-2.7.2 → science_synapse-2.7.4}/README.md +0 -0
  27. {science_synapse-2.7.2 → science_synapse-2.7.4}/pyproject.toml +0 -0
  28. {science_synapse-2.7.2 → science_synapse-2.7.4}/science_synapse.egg-info/dependency_links.txt +0 -0
  29. {science_synapse-2.7.2 → science_synapse-2.7.4}/science_synapse.egg-info/entry_points.txt +0 -0
  30. {science_synapse-2.7.2 → science_synapse-2.7.4}/science_synapse.egg-info/requires.txt +0 -0
  31. {science_synapse-2.7.2 → science_synapse-2.7.4}/science_synapse.egg-info/top_level.txt +0 -0
  32. {science_synapse-2.7.2 → science_synapse-2.7.4}/setup.cfg +0 -0
  33. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/__init__.py +0 -0
  34. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/__init__.pyi +0 -0
  35. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/__init__.py +0 -0
  36. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/__init__.pyi +0 -0
  37. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/app_pb2.py +0 -0
  38. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/channel_pb2.py +0 -0
  39. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/datatype_pb2.py +0 -0
  40. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/device_pb2.py +0 -0
  41. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/files_pb2.py +0 -0
  42. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/logging_pb2.py +0 -0
  43. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/node_pb2.py +0 -0
  44. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/__init__.py +0 -0
  45. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/__init__.pyi +0 -0
  46. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/application_pb2.py +0 -0
  47. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/broadband_source_pb2.py +0 -0
  48. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/camera_pb2.py +0 -0
  49. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/disk_writer_pb2.py +0 -0
  50. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/electrical_stimulation_pb2.py +0 -0
  51. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/optical_stimulation_pb2.py +0 -0
  52. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/signal_config_pb2.py +0 -0
  53. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/signal_status_pb2.py +0 -0
  54. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/spectral_filter_pb2.py +0 -0
  55. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/spike_binner_pb2.py +0 -0
  56. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/spike_detector_pb2.py +0 -0
  57. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/nodes/spike_source_pb2.py +0 -0
  58. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/performance_pb2.py +0 -0
  59. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/status_pb2.py +0 -0
  60. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/synapse_pb2.py +0 -0
  61. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/synapse_pb2_grpc.py +0 -0
  62. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/tap_pb2.py +0 -0
  63. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/api/time_pb2.py +0 -0
  64. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/__init__.py +0 -0
  65. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/__init__.pyi +0 -0
  66. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/apps.py +0 -0
  67. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/deploy_model.py +0 -0
  68. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/device_info_display.py +0 -0
  69. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/discover.py +0 -0
  70. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/files.py +0 -0
  71. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/offline_hdf5_plotter.py +0 -0
  72. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/offline_plot.py +0 -0
  73. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/rpc.py +0 -0
  74. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/settings.py +0 -0
  75. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/streaming.py +0 -0
  76. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/synapse_plotter.py +0 -0
  77. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/cli/taps.py +0 -0
  78. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/__init__.py +0 -0
  79. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/__init__.pyi +0 -0
  80. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/channel.py +0 -0
  81. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/config.py +0 -0
  82. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/device.py +0 -0
  83. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/node.py +0 -0
  84. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/__init__.py +0 -0
  85. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/__init__.pyi +0 -0
  86. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/application_node.py +0 -0
  87. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/broadband_source.py +0 -0
  88. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/disk_writer.py +0 -0
  89. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/electrical_stimulation.py +0 -0
  90. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/optical_stimulation.py +0 -0
  91. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/signal_config.py +0 -0
  92. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/spectral_filter.py +0 -0
  93. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/spike_binner.py +0 -0
  94. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/spike_detector.py +0 -0
  95. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/nodes/spike_source.py +0 -0
  96. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/settings.py +0 -0
  97. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/sftp.py +0 -0
  98. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/signal_config.py +0 -0
  99. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/client/taps.py +0 -0
  100. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/examples/__init__.py +0 -0
  101. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/examples/__init__.pyi +0 -0
  102. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/examples/tap_example.py +0 -0
  103. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/__init__.py +0 -0
  104. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/__init__.pyi +0 -0
  105. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/autodiscovery.py +0 -0
  106. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/entrypoint.py +0 -0
  107. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/nodes/__init__.py +0 -0
  108. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/nodes/__init__.pyi +0 -0
  109. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/nodes/base.py +0 -0
  110. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/nodes/spectral_filter.py +0 -0
  111. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/rpc.py +0 -0
  112. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/server/status.py +0 -0
  113. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/__init__.py +0 -0
  114. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/__init__.pyi +0 -0
  115. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/__main__.py +0 -0
  116. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/nodes/__init__.py +0 -0
  117. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/nodes/__init__.pyi +0 -0
  118. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/nodes/broadband_source.py +0 -0
  119. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/nodes/optical_stimulation.py +0 -0
  120. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/simulator/nodes/spike_source.py +0 -0
  121. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/__init__.py +0 -0
  122. {science_synapse-2.7.2/synapse/tests/client → science_synapse-2.7.4/synapse/tests/cli}/__init__.py +0 -0
  123. {science_synapse-2.7.2/synapse/tests/client → science_synapse-2.7.4/synapse/tests/cli}/__init__.pyi +0 -0
  124. {science_synapse-2.7.2/synapse/tests/simulator → science_synapse-2.7.4/synapse/tests/client}/__init__.py +0 -0
  125. {science_synapse-2.7.2/synapse/tests/simulator → science_synapse-2.7.4/synapse/tests/client}/__init__.pyi +0 -0
  126. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/client/test_broadband_source.py +0 -0
  127. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/client/test_spike_detector.py +0 -0
  128. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/client/test_spike_source.py +0 -0
  129. {science_synapse-2.7.2/synapse/tests/util → science_synapse-2.7.4/synapse/tests/simulator}/__init__.py +0 -0
  130. {science_synapse-2.7.2/synapse/tests/util → science_synapse-2.7.4/synapse/tests/simulator}/__init__.pyi +0 -0
  131. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/simulator/test_broadband_source.py +0 -0
  132. {science_synapse-2.7.2/synapse/tests/utils → science_synapse-2.7.4/synapse/tests/util}/__init__.py +0 -0
  133. {science_synapse-2.7.2/synapse/tests/utils → science_synapse-2.7.4/synapse/tests/util}/__init__.pyi +0 -0
  134. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/util/test_packet_monitor.py +0 -0
  135. {science_synapse-2.7.2/synapse → science_synapse-2.7.4/synapse/tests}/utils/__init__.py +0 -0
  136. {science_synapse-2.7.2/synapse/utils/model_converter/docker → science_synapse-2.7.4/synapse/tests/utils}/__init__.pyi +0 -0
  137. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/tests/utils/test_log.py +0 -0
  138. {science_synapse-2.7.2/synapse/utils/model_converter/docker → science_synapse-2.7.4/synapse/utils}/__init__.py +0 -0
  139. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/__init__.pyi +0 -0
  140. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/discover.py +0 -0
  141. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/file.py +0 -0
  142. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/log.py +0 -0
  143. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/__init__.py +0 -0
  144. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/__init__.pyi +0 -0
  145. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/convert.py +0 -0
  146. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/docker/Dockerfile +0 -0
  147. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/docker/convert.py +0 -0
  148. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/onnx_to_dlc.py +0 -0
  149. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/model_converter/pt_to_onnx.py +0 -0
  150. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/packet_monitor.py +0 -0
  151. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/proto.py +0 -0
  152. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/time_sync.py +0 -0
  153. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/types.py +0 -0
  154. {science_synapse-2.7.2 → science_synapse-2.7.4}/synapse/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: science-synapse
3
- Version: 2.7.2
3
+ Version: 2.7.4
4
4
  Summary: Client library and CLI for the Synapse API
5
5
  Author: Science Team
6
6
  Author-email: team@science.xyz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: science-synapse
3
- Version: 2.7.2
3
+ Version: 2.7.4
4
4
  Summary: Client library and CLI for the Synapse API
5
5
  Author: Science Team
6
6
  Author-email: team@science.xyz
@@ -52,6 +52,7 @@ synapse/cli/deploy_model.py
52
52
  synapse/cli/device_info_display.py
53
53
  synapse/cli/discover.py
54
54
  synapse/cli/files.py
55
+ synapse/cli/gateware.py
55
56
  synapse/cli/offline_hdf5_plotter.py
56
57
  synapse/cli/offline_plot.py
57
58
  synapse/cli/peripherals.py
@@ -106,6 +107,14 @@ synapse/simulator/nodes/optical_stimulation.py
106
107
  synapse/simulator/nodes/spike_source.py
107
108
  synapse/tests/__init__.py
108
109
  synapse/tests/__init__.pyi
110
+ synapse/tests/cli/__init__.py
111
+ synapse/tests/cli/__init__.pyi
112
+ synapse/tests/cli/conftest.py
113
+ synapse/tests/cli/test_custom_gateware_packaging.py
114
+ synapse/tests/cli/test_gateware_passthrough.py
115
+ synapse/tests/cli/test_gateware_runner.py
116
+ synapse/tests/cli/test_half_selectors.py
117
+ synapse/tests/cli/test_license_mode.py
109
118
  synapse/tests/client/__init__.py
110
119
  synapse/tests/client/__init__.pyi
111
120
  synapse/tests/client/test_broadband_source.py
@@ -29,7 +29,7 @@ stamp_api_version()
29
29
 
30
30
  setup(
31
31
  name="science-synapse",
32
- version="2.7.2",
32
+ version="2.7.4",
33
33
  description="Client library and CLI for the Synapse API",
34
34
  author="Science Team",
35
35
  author_email="team@science.xyz",
@@ -1,2 +1,2 @@
1
1
  # Generated from synapse-api/VERSION by setup.py. Do not edit.
2
- SYNAPSE_API_VERSION = "2.4.0"
2
+ SYNAPSE_API_VERSION = "2.4.1"
@@ -0,0 +1,42 @@
1
+ """Generated protocol buffer code."""
2
+ from google.protobuf import descriptor as _descriptor
3
+ from google.protobuf import descriptor_pool as _descriptor_pool
4
+ from google.protobuf import runtime_version as _runtime_version
5
+ from google.protobuf import symbol_database as _symbol_database
6
+ from google.protobuf.internal import builder as _builder
7
+ _runtime_version.ValidateProtobufRuntimeVersion(_runtime_version.Domain.PUBLIC, 5, 29, 0, '', 'api/query.proto')
8
+ _sym_db = _symbol_database.Default()
9
+ from ..api import channel_pb2 as api_dot_channel__pb2
10
+ from ..api import status_pb2 as api_dot_status__pb2
11
+ from ..api import tap_pb2 as api_dot_tap__pb2
12
+ from ..api import device_pb2 as api_dot_device__pb2
13
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0fapi/query.proto\x12\x07synapse\x1a\x11api/channel.proto\x1a\x10api/status.proto\x1a\rapi/tap.proto\x1a\x10api/device.proto"G\n\x0bSampleQuery\x12"\n\x08channels\x18\x01 \x03(\x0b2\x10.synapse.Channel\x12\x14\n\x0csample_count\x18\x02 \x01(\r">\n\x0eImpedanceQuery\x12\x15\n\relectrode_ids\x18\x01 \x03(\r\x12\x15\n\rperipheral_id\x18\x02 \x01(\r"&\n\rSelfTestQuery\x12\x15\n\rperipheral_id\x18\x01 \x01(\r"N\n\x14ImpedanceMeasurement\x12\x14\n\x0celectrode_id\x18\x01 \x01(\r\x12\x11\n\tmagnitude\x18\x02 \x01(\x02\x12\r\n\x05phase\x18\x03 \x01(\x02"H\n\x11ImpedanceResponse\x123\n\x0cmeasurements\x18\x01 \x03(\x0b2\x1d.synapse.ImpedanceMeasurement"Y\n\x0cSelfTestItem\x12\x11\n\ttest_name\x18\x01 \x01(\t\x12\x0e\n\x06passed\x18\x02 \x01(\x08\x12\x11\n\ttest_data\x18\x03 \x03(\r\x12\x13\n\x0btest_report\x18\x04 \x01(\t"L\n\x10SelfTestResponse\x12\x12\n\nall_passed\x18\x01 \x01(\x08\x12$\n\x05tests\x18\x02 \x03(\x0b2\x15.synapse.SelfTestItem"\xb2\x03\n\x0cQueryRequest\x123\n\nquery_type\x18\x01 \x01(\x0e2\x1f.synapse.QueryRequest.QueryType\x122\n\x0fimpedance_query\x18\x02 \x01(\x0b2\x17.synapse.ImpedanceQueryH\x00\x12,\n\x0csample_query\x18\x03 \x01(\x0b2\x14.synapse.SampleQueryH\x00\x121\n\x0fself_test_query\x18\x04 \x01(\x0b2\x16.synapse.SelfTestQueryH\x00\x121\n\x0flist_taps_query\x18\x05 \x01(\x0b2\x16.synapse.ListTapsQueryH\x00\x127\n\x12get_settings_query\x18\x06 \x01(\x0b2\x19.synapse.GetSettingsQueryH\x00"c\n\tQueryType\x12\t\n\x05kNone\x10\x00\x12\x0e\n\nkImpedance\x10\x01\x12\x0b\n\x07kSample\x10\x02\x12\r\n\tkSelfTest\x10\x03\x12\r\n\tkListTaps\x10\x04\x12\x10\n\x0ckGetSettings\x10\x05B\x07\n\x05query"<\n\x12StreamQueryRequest\x12&\n\x07request\x18\x01 \x01(\x0b2\x15.synapse.QueryRequest"\xb5\x02\n\rQueryResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b2\x0f.synapse.Status\x12\x0c\n\x04data\x18\x02 \x03(\r\x128\n\x12impedance_response\x18\x03 \x01(\x0b2\x1a.synapse.ImpedanceResponseH\x00\x127\n\x12self_test_response\x18\x04 \x01(\x0b2\x19.synapse.SelfTestResponseH\x00\x127\n\x12list_taps_response\x18\x05 \x01(\x0b2\x19.synapse.ListTapsResponseH\x00\x12=\n\x15get_settings_response\x18\x06 \x01(\x0b2\x1c.synapse.GetSettingsResponseH\x00B\n\n\x08response"\xcc\x01\n\x13StreamQueryResponse\x12!\n\x04code\x18\x01 \x01(\x0e2\x13.synapse.StatusCode\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x14\n\x0ctimestamp_ns\x18\x03 \x01(\x04\x12/\n\timpedance\x18\x04 \x01(\x0b2\x1a.synapse.ImpedanceResponseH\x00\x12.\n\tself_test\x18\x05 \x01(\x0b2\x19.synapse.SelfTestResponseH\x00B\n\n\x08responseb\x06proto3')
14
+ _globals = globals()
15
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
16
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'api.query_pb2', _globals)
17
+ if not _descriptor._USE_C_DESCRIPTORS:
18
+ DESCRIPTOR._loaded_options = None
19
+ _globals['_SAMPLEQUERY']._serialized_start = 98
20
+ _globals['_SAMPLEQUERY']._serialized_end = 169
21
+ _globals['_IMPEDANCEQUERY']._serialized_start = 171
22
+ _globals['_IMPEDANCEQUERY']._serialized_end = 233
23
+ _globals['_SELFTESTQUERY']._serialized_start = 235
24
+ _globals['_SELFTESTQUERY']._serialized_end = 273
25
+ _globals['_IMPEDANCEMEASUREMENT']._serialized_start = 275
26
+ _globals['_IMPEDANCEMEASUREMENT']._serialized_end = 353
27
+ _globals['_IMPEDANCERESPONSE']._serialized_start = 355
28
+ _globals['_IMPEDANCERESPONSE']._serialized_end = 427
29
+ _globals['_SELFTESTITEM']._serialized_start = 429
30
+ _globals['_SELFTESTITEM']._serialized_end = 518
31
+ _globals['_SELFTESTRESPONSE']._serialized_start = 520
32
+ _globals['_SELFTESTRESPONSE']._serialized_end = 596
33
+ _globals['_QUERYREQUEST']._serialized_start = 599
34
+ _globals['_QUERYREQUEST']._serialized_end = 1033
35
+ _globals['_QUERYREQUEST_QUERYTYPE']._serialized_start = 925
36
+ _globals['_QUERYREQUEST_QUERYTYPE']._serialized_end = 1024
37
+ _globals['_STREAMQUERYREQUEST']._serialized_start = 1035
38
+ _globals['_STREAMQUERYREQUEST']._serialized_end = 1095
39
+ _globals['_QUERYRESPONSE']._serialized_start = 1098
40
+ _globals['_QUERYRESPONSE']._serialized_end = 1407
41
+ _globals['_STREAMQUERYRESPONSE']._serialized_start = 1410
42
+ _globals['_STREAMQUERYRESPONSE']._serialized_end = 1614
@@ -83,7 +83,7 @@ def main():
83
83
  peripherals.add_commands(subparsers)
84
84
  settings.add_commands(subparsers)
85
85
  deploy_model.add_commands(subparsers)
86
- args = parser.parse_args()
86
+ args = peripherals.parse_args_with_passthrough(parser)
87
87
 
88
88
  # If we need to setup the device URI, do that now
89
89
  args = setup_device_uri(args)
@@ -3,10 +3,11 @@ from __future__ import annotations
3
3
  import glob
4
4
  import json
5
5
  import os
6
+ import re
6
7
  import shutil
7
8
  import subprocess
8
9
  import tempfile
9
- from typing import Any
10
+ from typing import Any, Literal
10
11
 
11
12
  from rich import box
12
13
  from rich.console import Console
@@ -15,7 +16,7 @@ from rich.panel import Panel
15
16
  console = Console()
16
17
 
17
18
 
18
- def validate_manifest(manifest_path: str) -> dict[str, Any] | bool:
19
+ def validate_manifest(manifest_path: str) -> dict[str, Any] | Literal[False]:
19
20
  """Return the parsed ``manifest.json`` dictionary or ``False`` on error."""
20
21
 
21
22
  try:
@@ -71,42 +72,137 @@ def ensure_docker() -> bool:
71
72
  return False
72
73
 
73
74
 
74
- def build_docker_image(app_dir: str, app_name: str | None = None) -> str:
75
- """(Re)build the cross-compile SDK Docker image and return its tag."""
75
+ _ARG_HOST_UID_RE = re.compile(r"^ARG HOST_UID\b", re.MULTILINE)
76
+
77
+
78
+ def _resolve_host_uid() -> int:
79
+ """Return the invoking user's UID, falling back to 1000 on non-POSIX hosts."""
80
+ try:
81
+ return os.getuid()
82
+ except AttributeError:
83
+ console.print(
84
+ "[yellow]Warning:[/yellow] os.getuid() unavailable on this host; "
85
+ "falling back to HOST_UID=1000."
86
+ )
87
+ return 1000
88
+
89
+
90
+ def _dockerfile_needs_host_uid(dockerfile_path: str) -> bool:
91
+ """Return True iff *dockerfile_path* declares ``ARG HOST_UID`` at line start."""
92
+ with open(dockerfile_path, "r", encoding="utf-8") as fp:
93
+ return bool(_ARG_HOST_UID_RE.search(fp.read()))
94
+
95
+
96
+ def build_docker_image(
97
+ app_dir: str,
98
+ app_name: str | None = None,
99
+ roles: list[str] | None = None,
100
+ ) -> dict[str, str]:
101
+ """(Re)build the cross-compile SDK Docker image(s) and return role -> tag.
102
+
103
+ Discovers every ``*.Dockerfile`` directly under ``<app_dir>/Dockerfiles/``
104
+ and builds each as ``<app_name>-<role>:latest-<arch>`` where ``role`` is
105
+ the filename stem (e.g. ``gateware.Dockerfile`` -> ``gateware``). Returns
106
+ a dict mapping role -> image tag.
107
+
108
+ Back-compat: if ``<app_dir>/Dockerfiles/`` does not exist and
109
+ ``<app_dir>/Dockerfile`` does, builds the single legacy image tagged
110
+ ``<app_name>:latest-<arch>`` (no role suffix) and returns
111
+ ``{"driver": "<that tag>"}``.
112
+
113
+ If ``Dockerfiles/`` exists but is empty, or if neither path exists,
114
+ raises :class:`FileNotFoundError`.
115
+
116
+ For each Dockerfile whose contents contain a line matching
117
+ ``^ARG HOST_UID\\b`` the build additionally receives
118
+ ``--build-arg HOST_UID=<os.getuid()>``. On non-POSIX hosts (where
119
+ ``os.getuid()`` is unavailable) the value falls back to ``1000``.
120
+
121
+ Args:
122
+ app_dir, app_name: as before.
123
+ roles: when provided, restricts the build to Dockerfiles whose role
124
+ (filename stem) is in this list. If a requested role is not found
125
+ on disk, raises FileNotFoundError. When None (default), builds
126
+ every discovered Dockerfile. The back-compat legacy single-
127
+ ``./Dockerfile`` path is treated as role "driver"; pass
128
+ ``roles=["driver"]`` (or None) to consume it; passing
129
+ ``roles=["gateware"]`` against a legacy repo with no
130
+ ``Dockerfiles/`` raises FileNotFoundError.
131
+ """
76
132
 
77
133
  if app_name is None:
78
134
  app_name = os.path.basename(app_dir)
79
135
 
80
136
  arch_suffix = detect_arch() # "arm64" or "amd64"
81
137
 
82
- # Look for a Dockerfile at the top level of the app directory
83
- dockerfile_path = os.path.join(app_dir, "Dockerfile")
84
-
85
- if not os.path.exists(dockerfile_path):
138
+ dockerfiles_dir = os.path.join(app_dir, "Dockerfiles")
139
+ legacy_dockerfile = os.path.join(app_dir, "Dockerfile")
140
+
141
+ # Discovery: Dockerfiles/ wins over the legacy root ./Dockerfile.
142
+ discovered: list[tuple[str, str]] = []
143
+ is_legacy = False
144
+ if os.path.isdir(dockerfiles_dir):
145
+ for entry in sorted(os.listdir(dockerfiles_dir)):
146
+ if entry.endswith(".Dockerfile"):
147
+ role = entry[: -len(".Dockerfile")]
148
+ discovered.append((role, os.path.join(dockerfiles_dir, entry)))
149
+ elif os.path.exists(legacy_dockerfile):
150
+ discovered.append(("driver", legacy_dockerfile))
151
+ is_legacy = True
152
+
153
+ if not discovered:
86
154
  raise FileNotFoundError(
87
- f"Expected Dockerfile not found at {dockerfile_path}. "
88
- "Ensure your application provides the required Dockerfile."
155
+ f"Expected Dockerfile not found at {legacy_dockerfile} or any "
156
+ f"*.Dockerfile under {dockerfiles_dir}. Ensure your application "
157
+ "provides the required Dockerfile."
89
158
  )
90
159
 
91
- image_tag = f"{app_name}:latest-{arch_suffix}"
160
+ if roles is not None:
161
+ requested = set(roles)
162
+ available = {role for role, _ in discovered}
163
+ missing = requested - available
164
+ if missing:
165
+ raise FileNotFoundError(
166
+ f"Requested roles {sorted(missing)} not found in {dockerfiles_dir}. "
167
+ f"Available roles: {sorted(available)}."
168
+ )
169
+ discovered = [(role, path) for role, path in discovered if role in requested]
170
+
171
+ tags: dict[str, str] = {}
172
+ for role, dockerfile_path in discovered:
173
+ image_tag = (
174
+ f"{app_name}:latest-{arch_suffix}"
175
+ if is_legacy
176
+ else f"{app_name}-{role}:latest-{arch_suffix}"
177
+ )
92
178
 
93
- console.print(f"[yellow]Building Docker image [bold]{image_tag}[/bold]...[/yellow]")
94
- subprocess.run(
95
- [
96
- "docker",
97
- "build",
98
- "-t",
99
- image_tag,
100
- "-f",
101
- dockerfile_path,
102
- ".",
103
- ],
104
- check=True,
105
- cwd=app_dir,
106
- )
179
+ build_args: list[str] = []
180
+ if _dockerfile_needs_host_uid(dockerfile_path):
181
+ host_uid = _resolve_host_uid()
182
+ build_args.extend(["--build-arg", f"HOST_UID={host_uid}"])
107
183
 
108
- console.print(f"[green]Successfully built Docker image {image_tag}[/green]")
109
- return image_tag
184
+ console.print(
185
+ f"[yellow]Building Docker image [bold]{image_tag}[/bold]...[/yellow]"
186
+ )
187
+ subprocess.run(
188
+ [
189
+ "docker",
190
+ "build",
191
+ "-t",
192
+ image_tag,
193
+ "-f",
194
+ dockerfile_path,
195
+ *build_args,
196
+ ".",
197
+ ],
198
+ check=True,
199
+ cwd=app_dir,
200
+ )
201
+
202
+ console.print(f"[green]Successfully built Docker image {image_tag}[/green]")
203
+ tags[role] = image_tag
204
+
205
+ return tags
110
206
 
111
207
 
112
208
  def build_app(
@@ -127,12 +223,9 @@ def build_app(
127
223
 
128
224
  console.print("[yellow]Binary not found, attempting to build...[/yellow]")
129
225
 
130
- arch_suffix = detect_arch()
131
- image_tag = f"{os.path.basename(app_dir)}:latest-{arch_suffix}"
132
-
133
226
  # Build (or rebuild) the Docker image – this function is idempotent.
134
227
  try:
135
- image_tag = build_docker_image(app_dir, app_name)
228
+ image_tag = build_docker_image(app_dir, app_name)["driver"]
136
229
  except (subprocess.CalledProcessError, FileNotFoundError) as exc:
137
230
  console.print(
138
231
  f"[bold red]Error:[/bold red] Failed to build Docker image: {exc}"
@@ -317,10 +410,14 @@ WantedBy=multi-user.target
317
410
 
318
411
  lifecycle_scripts_tmp: list[str] = []
319
412
 
413
+ # 0o644 suffices for all three: fpm embeds each file's *contents* as a
414
+ # .deb maintainer script (--after-install / --before-remove /
415
+ # --after-remove below), and dpkg makes maintainer scripts executable
416
+ # itself at install time. The staging files' exec bits never ship.
320
417
  postinstall_path = os.path.join(staging_dir, "postinstall.sh")
321
418
  with open(postinstall_path, "w", encoding="utf-8") as fp:
322
419
  fp.write("#!/bin/bash\nset -e\nsystemctl daemon-reload\n")
323
- os.chmod(postinstall_path, 0o755)
420
+ os.chmod(postinstall_path, 0o644)
324
421
  lifecycle_scripts_tmp.append(postinstall_path)
325
422
 
326
423
  preremove_path = os.path.join(staging_dir, "preremove.sh")
@@ -328,13 +425,13 @@ WantedBy=multi-user.target
328
425
  fp.write(
329
426
  f"#!/bin/bash\nset -e\nsystemctl stop {app_name} || true\nsystemctl disable {app_name} || true\n"
330
427
  )
331
- os.chmod(preremove_path, 0o755)
428
+ os.chmod(preremove_path, 0o644)
332
429
  lifecycle_scripts_tmp.append(preremove_path)
333
430
 
334
431
  postremove_path = os.path.join(staging_dir, "postremove.sh")
335
432
  with open(postremove_path, "w", encoding="utf-8") as fp:
336
433
  fp.write("#!/bin/bash\nset -e\nsystemctl daemon-reload\n")
337
- os.chmod(postremove_path, 0o755)
434
+ os.chmod(postremove_path, 0o644)
338
435
  lifecycle_scripts_tmp.append(postremove_path)
339
436
 
340
437
  lib_dst_dir = os.path.join(staging_dir, "opt", "scifi", "lib")
@@ -538,15 +635,22 @@ def package_app(app_dir: str, app_name: str) -> bool:
538
635
  return build_deb_package(app_dir, app_name)
539
636
 
540
637
 
541
- def find_deb_package(dist_dir: str) -> str | None:
542
- """Return the path to the .deb generated in *app_dir* or *None*."""
543
- for file in os.listdir(dist_dir):
544
- if file.endswith(".deb"):
545
- return os.path.join(dist_dir, file)
638
+ def find_deb_package(dist_dir: str, package_name: str | None = None) -> str | None:
639
+ """Return the path to a .deb generated in *dist_dir* or ``None``.
546
640
 
547
- console.print(
548
- f"[bold red]Error:[/bold red] Could not find .deb package in {dist_dir}"
549
- )
641
+ With *package_name*, only ``<package_name>_*.deb`` matches — a peripheral
642
+ dist/ holds both the driver and the ``-gateware`` deb, and the driver name
643
+ is a strict prefix of the gateware name.
644
+ """
645
+ for file in sorted(os.listdir(dist_dir)):
646
+ if not file.endswith(".deb"):
647
+ continue
648
+ if package_name is not None and not file.startswith(f"{package_name}_"):
649
+ continue
650
+ return os.path.join(dist_dir, file)
651
+
652
+ wanted = f"{package_name} .deb package" if package_name else ".deb package"
653
+ console.print(f"[bold red]Error:[/bold red] Could not find {wanted} in {dist_dir}")
550
654
  return None
551
655
 
552
656
 
@@ -71,7 +71,13 @@ def create_metadata(file_path, console):
71
71
 
72
72
 
73
73
  def deploy_package(ip_address, deb_package_path):
74
- """Deploy the package to the device"""
74
+ """Deploy a .deb package to the device via gRPC DeployApp streaming.
75
+
76
+ Returns True when the package was streamed and all device responses were
77
+ received without error; False on any failure (connection, gRPC, or I/O).
78
+ Callers can use the return value to decide whether to continue with
79
+ subsequent packages.
80
+ """
75
81
  package_filename = os.path.basename(deb_package_path)
76
82
  console.clear_live()
77
83
 
@@ -178,6 +184,7 @@ def deploy_package(ip_address, deb_package_path):
178
184
  response_panel.renderable = Group(*display_items)
179
185
  response_panel.border_style = "red"
180
186
  live.refresh()
187
+ return False
181
188
 
182
189
  except Exception as e:
183
190
  # For the outer exception, also preserve any progress made
@@ -195,6 +202,9 @@ def deploy_package(ip_address, deb_package_path):
195
202
  response_panel.renderable = Group(*display_items)
196
203
  response_panel.border_style = "red"
197
204
  live.refresh()
205
+ return False
206
+
207
+ return True
198
208
 
199
209
 
200
210
  def deploy_cmd(args):