pytesdaqx 0.2.0__tar.gz → 0.2.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 (212) hide show
  1. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/PKG-INFO +1 -1
  2. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/data_io.md +15 -0
  3. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pyproject.toml +1 -1
  4. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/zarr_reader.py +9 -3
  5. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/recorder/zarr.py +24 -2
  6. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/run/yaml_run.py +4 -0
  7. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/tes_bias.py +17 -1
  8. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/PKG-INFO +1 -1
  9. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/SOURCES.txt +1 -0
  10. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_feb_signal_generator_didv.py +21 -0
  11. pytesdaqx-0.2.2/tests/test_finite_record_metadata.py +89 -0
  12. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/MANIFEST.in +0 -0
  13. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/README.md +0 -0
  14. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/acquisition_pipeline.md +0 -0
  15. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/adding_hardware.md +0 -0
  16. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/architecture.md +0 -0
  17. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/configuration_pipeline.md +0 -0
  18. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/hardware_support.md +0 -0
  19. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/index.md +0 -0
  20. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/package_structure.md +0 -0
  21. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/release_process.md +0 -0
  22. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/developer/testing.md +0 -0
  23. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/index.md +0 -0
  24. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/index.md +0 -0
  25. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/rocky_linux_9.md +0 -0
  26. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/troubleshooting.md +0 -0
  27. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/ubuntu.md +0 -0
  28. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/validation.md +0 -0
  29. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/installation/visa.md +0 -0
  30. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/cli/acquisition.md +0 -0
  31. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/cli/data_inspection.md +0 -0
  32. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/cli/index.md +0 -0
  33. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/cli/instrument_control.md +0 -0
  34. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/cli/lab_diagnostics.md +0 -0
  35. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/acquisition_config.md +0 -0
  36. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/hardware_yaml.md +0 -0
  37. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/index.md +0 -0
  38. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/resolution.md +0 -0
  39. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/run_setup_yaml.md +0 -0
  40. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/scans.md +0 -0
  41. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/configuration/temperature_controllers.md +0 -0
  42. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/data_format.md +0 -0
  43. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/quickstart.md +0 -0
  44. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/terminology.md +0 -0
  45. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/troubleshooting.md +0 -0
  46. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/docs/user/workflows.md +0 -0
  47. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/README.md +0 -0
  48. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/acquisition_background.yaml +0 -0
  49. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/acquisition_didv_background.yaml +0 -0
  50. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/acquisition_notebook_demo.yaml +0 -0
  51. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/hardware_fake.yaml +0 -0
  52. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/hardware_feb_signal_generator.yaml +0 -0
  53. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/basic/run_setup.yaml +0 -0
  54. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/calibration/acquisition_laser.yaml +0 -0
  55. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/pxi_loopback/README.md +0 -0
  56. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/pxi_loopback/acquisition_didv.yaml +0 -0
  57. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/pxi_loopback/acquisition_iv_restore.yaml +0 -0
  58. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/scans/acquisition_didv_ac.yaml +0 -0
  59. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/scans/acquisition_didv_frequency_focus.yaml +0 -0
  60. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/scans/acquisition_temperature_fake.yaml +0 -0
  61. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/scans/acquisition_tes_bias_iv_didv.yaml +0 -0
  62. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/scans/acquisition_transducer_vibration_scan.yaml +0 -0
  63. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/temperature/hardware_lakeshore372.yaml +0 -0
  64. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/temperature/hardware_macrt.yaml +0 -0
  65. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/temperature/run_setup_lakeshore372.yaml +0 -0
  66. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/configuration/temperature/run_setup_macrt.yaml +0 -0
  67. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/simulation/README.md +0 -0
  68. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/examples/simulation/write_simulated_zarr.py +0 -0
  69. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/mkdocs.yml +0 -0
  70. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/__init__.py +0 -0
  71. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/__init__.py +0 -0
  72. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/fake.py +0 -0
  73. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/nidaq_ai.py +0 -0
  74. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/segment.py +0 -0
  75. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/session.py +0 -0
  76. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/acquisition/streaming.py +0 -0
  77. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/analysis/__init__.py +0 -0
  78. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/analysis/continuity.py +0 -0
  79. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/__init__.py +0 -0
  80. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/build_manifest.py +0 -0
  81. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/display_metadata.py +0 -0
  82. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/laser.py +0 -0
  83. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/run.py +0 -0
  84. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/signal_generator.py +0 -0
  85. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/squid.py +0 -0
  86. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/temperature.py +0 -0
  87. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/tes_bias.py +0 -0
  88. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/transducer.py +0 -0
  89. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/validate_config.py +0 -0
  90. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/cli/view_traces.py +0 -0
  91. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/__init__.py +0 -0
  92. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/durations.py +0 -0
  93. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/models.py +0 -0
  94. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/resolver.py +0 -0
  95. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/scan_values.py +0 -0
  96. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/schema.py +0 -0
  97. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/temperature.py +0 -0
  98. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/config/validators.py +0 -0
  99. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/control/__init__.py +0 -0
  100. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/control/coordinator.py +0 -0
  101. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/hardware/__init__.py +0 -0
  102. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/hardware/base.py +0 -0
  103. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/hardware/factory.py +0 -0
  104. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/hardware/legacy.py +0 -0
  105. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/hardware/registry.py +0 -0
  106. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/__init__.py +0 -0
  107. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/base.py +0 -0
  108. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/builtins.py +0 -0
  109. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/communication.py +0 -0
  110. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/external.py +0 -0
  111. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/remote.py +0 -0
  112. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/signal_generator/__init__.py +0 -0
  113. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/signal_generator/agilent33500B.py +0 -0
  114. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/signal_generator/keithley2400.py +0 -0
  115. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/signal_generator/keysightDSOX1200.py +0 -0
  116. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/signal_generator/rigoldg800.py +0 -0
  117. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/temperature_controller/__init__.py +0 -0
  118. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/temperature_controller/base.py +0 -0
  119. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/temperature_controller/lakeshore.py +0 -0
  120. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/temperature_controller/macrt.py +0 -0
  121. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/temperature_controller/macrt_module.py +0 -0
  122. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/tes_squid/__init__.py +0 -0
  123. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/tes_squid/feb.py +0 -0
  124. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/instruments/tes_squid/magnicon.py +0 -0
  125. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/__init__.py +0 -0
  126. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/acquisition_catalog.py +0 -0
  127. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/catalog.py +0 -0
  128. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/hdf5_layout.py +0 -0
  129. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/hdf5_reader.py +0 -0
  130. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/metadata_compat.py +0 -0
  131. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/raw_data_reader.py +0 -0
  132. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/raw_data_writer.py +0 -0
  133. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/reader_utils.py +0 -0
  134. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/stream_reader.py +0 -0
  135. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/io/zarr_utils.py +0 -0
  136. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/naming.py +0 -0
  137. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/processing/__init__.py +0 -0
  138. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/processing/downsample.py +0 -0
  139. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/recorder/__init__.py +0 -0
  140. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/recorder/async_writer.py +0 -0
  141. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/recorder/base.py +0 -0
  142. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/recorder/hdf5.py +0 -0
  143. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/run/__init__.py +0 -0
  144. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/run/runner.py +0 -0
  145. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/sequencer/__init__.py +0 -0
  146. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/sequencer/scan.py +0 -0
  147. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/sequencer/sequencer.py +0 -0
  148. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/__init__.py +0 -0
  149. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/laser.py +0 -0
  150. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/signal_generator_load.py +0 -0
  151. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/squid.py +0 -0
  152. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/temperature.py +0 -0
  153. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/services/transducer.py +0 -0
  154. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/__init__.py +0 -0
  155. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/analyze_continuity.py +0 -0
  156. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/lab_check.py +0 -0
  157. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/ni_cli_common.py +0 -0
  158. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/real_ni_benchmark.py +0 -0
  159. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/real_ni_continuity_test.py +0 -0
  160. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/real_ni_run_continuous.py +0 -0
  161. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/real_ni_smoke.py +0 -0
  162. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx/testing/real_ni_trigger_test.py +0 -0
  163. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/dependency_links.txt +0 -0
  164. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/entry_points.txt +0 -0
  165. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/requires.txt +0 -0
  166. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/pytesdaqx.egg-info/top_level.txt +0 -0
  167. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/setup.cfg +0 -0
  168. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_acquisition_catalog_api_cleanup.py +0 -0
  169. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_acquisition_catalog_naming.py +0 -0
  170. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_api_cleanup.py +0 -0
  171. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_cli_contract.py +0 -0
  172. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_code_cleanup_regressions.py +0 -0
  173. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_detector_settings_normalization.py +0 -0
  174. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_developer_documentation.py +0 -0
  175. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_distribution_readiness.py +0 -0
  176. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_facility_catalog_metadata.py +0 -0
  177. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_feb_driver.py +0 -0
  178. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_io_coordinate_cleanup.py +0 -0
  179. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_lakeshore372_driver.py +0 -0
  180. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_laser_configuration_ownership.py +0 -0
  181. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_macrt_driver.py +0 -0
  182. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_magnicon_driver.py +0 -0
  183. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_manifest_and_zarr_metadata.py +0 -0
  184. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_metadata_canonical_schema.py +0 -0
  185. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_optional_hdf5_import.py +0 -0
  186. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_partition_planning.py +0 -0
  187. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_raw_data_writer.py +0 -0
  188. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_release_cleanup.py +0 -0
  189. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_repository_layout.py +0 -0
  190. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_run_cli_cleanup.py +0 -0
  191. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_scan_documentation.py +0 -0
  192. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_scan_values.py +0 -0
  193. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_signal_generator_cli.py +0 -0
  194. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_signal_generator_drivers.py +0 -0
  195. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_signal_generator_load_policy.py +0 -0
  196. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_stream_reader_api_cleanup.py +0 -0
  197. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_temperature_acquisition_integration.py +0 -0
  198. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_temperature_cli.py +0 -0
  199. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_temperature_configuration.py +0 -0
  200. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_temperature_safety_cleanup.py +0 -0
  201. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_temperature_service.py +0 -0
  202. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_transducer_configuration_ownership.py +0 -0
  203. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_user_documentation.py +0 -0
  204. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_view_trace_partitions.py +0 -0
  205. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_chunking_and_sharding.py +0 -0
  206. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_compression.py +0 -0
  207. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_default_and_naming.py +0 -0
  208. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_manifest_sidecars.py +0 -0
  209. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_metadata_layout.py +0 -0
  210. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_native_backend.py +0 -0
  211. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_read_block_terminology.py +0 -0
  212. {pytesdaqx-0.2.0 → pytesdaqx-0.2.2}/tests/test_zarr_trace_labels.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytesdaqx
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: TES detector acquisition, instrument control, and raw-data recording
5
5
  Author: TESSERACT DAQ developers
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -25,6 +25,7 @@ Important behavior:
25
25
  - Zarr v3 group and array metadata.
26
26
  - Continuous array shape `[channel, sample]`.
27
27
  - Finite array shape `[trace, channel, sample]`.
28
+ - Finite `trace_time[trace]` array of float64 Unix acquisition timestamps.
28
29
  - Native zarr-python writing.
29
30
  - Optional compression and sharding configuration.
30
31
  - Stream metadata updated as read blocks or traces are appended.
@@ -32,6 +33,20 @@ Important behavior:
32
33
 
33
34
  Zarr does not use HDF5 file rotation. Recorder options such as `segments_per_file` are ignored for Zarr by the run controller.
34
35
 
36
+ Finite-record timestamps are copied from `SegmentMetadata.segment_timestamp`
37
+ to `trace_time`, preserving gaps between triggers. An absent timestamp is NaN;
38
+ the recorder does not substitute its write time. `get_trace()` and
39
+ `StreamReader` return the selected value as `trace_time`. Older stores without
40
+ this array remain readable and omit the unavailable timestamp. The compact
41
+ timestamp array is separate from waveform chunking/sharding and is not a JSONL
42
+ sidecar.
43
+
44
+ The NI run controller records `pretrigger_length_samples: 0` for finite
45
+ acquisitions, whose digital/analog triggers start acquisition rather than
46
+ referencing a pretrigger buffer. Historical pretrigger metadata is preserved
47
+ by the readers; consumers must not assume that an arbitrary finite record is
48
+ centered on its trigger.
49
+
35
50
  ## Compression and chunking defaults
36
51
 
37
52
  `ZarrRecorder` defaults to zstd compression (level 9) and to sharded arrays for
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pytesdaqx"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "TES detector acquisition, instrument control, and raw-data recording"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.13"
@@ -283,8 +283,7 @@ class ZarrReader:
283
283
  )
284
284
  info = self._native_info(
285
285
  record_type="trace",
286
- trace_index=index,
287
- n_samples=int(out.shape[1]),
286
+ **self._native_trace_info(index),
288
287
  selected_channels=selected_channels,
289
288
  units=units,
290
289
  )
@@ -505,10 +504,17 @@ class ZarrReader:
505
504
  return (out, info) if include_metadata else out
506
505
 
507
506
  def _native_trace_info(self, trace_index: int) -> dict[str, Any]:
508
- return {
507
+ info = {
509
508
  "trace_index": int(trace_index),
510
509
  "n_samples": self.trace_length_samples,
511
510
  }
511
+ time_path = self.path / 'trace_time'
512
+ if is_array(time_path):
513
+ values = read_array_slice(time_path, (slice(trace_index, trace_index + 1),))
514
+ if np.asarray(values).size != 1:
515
+ raise ValueError('trace_time must contain one timestamp per finite trace')
516
+ info['trace_time'] = float(np.asarray(values).reshape(-1)[0])
517
+ return info
512
518
 
513
519
  def _native_read_block_info(self, read_block_index: int) -> dict[str, Any]:
514
520
  start, length = self._continuous_read_block_bounds(read_block_index)
@@ -99,6 +99,7 @@ class ZarrRecorder:
99
99
  self._raw_path: Path | None = None
100
100
  self._native_group = None
101
101
  self._native_raw = None
102
+ self._native_trace_time = None
102
103
  self._native_raw_supports_shards = False
103
104
  self._raw_shape_model: str | None = None
104
105
  self._segment_length_samples: int | None = None
@@ -123,6 +124,7 @@ class ZarrRecorder:
123
124
  _require_zarr_python()
124
125
  self._native_group = None
125
126
  self._native_raw = None
127
+ self._native_trace_time = None
126
128
  self._native_raw_supports_shards = False
127
129
  try:
128
130
  self._open_stream_store()
@@ -182,6 +184,7 @@ class ZarrRecorder:
182
184
  self._raw_path = None
183
185
  self._native_group = None
184
186
  self._native_raw = None
187
+ self._native_trace_time = None
185
188
 
186
189
  if self.on_file_closed is not None:
187
190
  try:
@@ -209,6 +212,24 @@ class ZarrRecorder:
209
212
  self._native_raw.resize((n_traces, int(trace.shape[1]), int(trace.shape[2])))
210
213
  self._native_raw[int(trace_index), :, :] = np.ascontiguousarray(trace[0])
211
214
 
215
+ def _write_trace_time(self, trace_index: int, timestamp: float | None) -> None:
216
+ """Persist finite-record timestamps independently of waveform chunks.
217
+
218
+ Finite triggers need not be consecutive in time. Missing acquisition
219
+ timestamps remain NaN; write time is not an acquisition timestamp.
220
+ """
221
+ if self._native_trace_time is None:
222
+ self._native_trace_time = self._native_group.create_array(
223
+ 'trace_time', shape=(0,), chunks=(1024,), dtype='float64',
224
+ fill_value=np.nan, dimension_names=('trace',),
225
+ attributes={'units': 's', 'time_reference': 'unix',
226
+ 'description': 'Acquisition timestamp for each finite trace'},
227
+ )
228
+ self._native_trace_time.resize((int(trace_index) + 1,))
229
+ self._native_trace_time[int(trace_index)] = (
230
+ np.nan if timestamp is None else float(timestamp)
231
+ )
232
+
212
233
  def write_segment(self, data, metadata: SegmentMetadata):
213
234
  if self._store is None:
214
235
  raise RuntimeError("ZarrRecorder is not open")
@@ -232,6 +253,7 @@ class ZarrRecorder:
232
253
  else:
233
254
  trace = data.reshape((1, int(data.shape[0]), int(data.shape[1])))
234
255
  self._write_native_trace(trace, segment_num - 1)
256
+ self._write_trace_time(segment_num - 1, metadata.segment_timestamp)
235
257
  self._chunk_shapes.append([1, int(data.shape[0]), int(data.shape[1])])
236
258
  self._n_samples_total = n_samples
237
259
 
@@ -244,8 +266,8 @@ class ZarrRecorder:
244
266
 
245
267
  # Zarr stores do not write per-block JSONL sidecars by default.
246
268
  # The stream/raw metadata carry n_samples, n_traces, chunking, and
247
- # timing summaries; detailed per-write provenance can be added later
248
- # behind an explicit debug/provenance option if needed.
269
+ # timing summaries. Finite acquisition timestamps live in the aligned
270
+ # trace_time array, because gaps cannot be recovered from trace indices.
249
271
 
250
272
  update_attrs(
251
273
  self._store,
@@ -647,6 +647,10 @@ class YAMLRunController:
647
647
  "downsample_method": ds_method,
648
648
  "adc_physical_channels": [r.get("adc_physical_channel") for r in rows],
649
649
  }
650
+ # Finite NI tasks use start triggers (including analog threshold),
651
+ # not reference triggers with a pretrigger buffer.
652
+ if adc_mode.lower() == "finite":
653
+ adc_attrs["pretrigger_length_samples"] = 0
650
654
  return adc_attrs, rows
651
655
 
652
656
  def _build_detconfig_attrs(self, measurement_cfg: dict[str, Any], *, record_channels: list[str] | None = None) -> dict[str, Any]:
@@ -819,7 +819,23 @@ class FEBPlusSignalGeneratorBiasPath(BaseBiasPath):
819
819
  self.feb_channel,
820
820
  )
821
821
  if source == "hardware" and value is not None:
822
- return {"value": value, "units": self.last_dc_units, "source": "hardware"}
822
+ # last_dc_units is only populated by a set_dc() call made this
823
+ # session - if the FEB was already biased beforehand (the usual
824
+ # case: bias set once, then a viewer/reader process attaches
825
+ # later), it's still None here. Unlike PXI4322BiasPath (whose
826
+ # get_dc() falls back to "V", correctly paired with returning a
827
+ # raw voltage in that same branch), this class's `value` is the
828
+ # FEB's own already-calibrated current reading - falling back to
829
+ # None left callers with no unit at all, which a units-string
830
+ # lookup (e.g. PytesdaqxBoardReader.read_tes_bias) can silently
831
+ # misread as "not a recognized current unit, must be volts" and
832
+ # divide by a bias resistor instead of doing nothing - turning a
833
+ # ~uA reading into a value several orders of magnitude off.
834
+ return {
835
+ "value": value,
836
+ "units": self.last_dc_units or self.dc_default_units or "uA",
837
+ "source": "hardware",
838
+ }
823
839
  return super().get_dc()
824
840
 
825
841
  def configure_ac(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytesdaqx
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: TES detector acquisition, instrument control, and raw-data recording
5
5
  Author: TESSERACT DAQ developers
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -172,6 +172,7 @@ tests/test_distribution_readiness.py
172
172
  tests/test_facility_catalog_metadata.py
173
173
  tests/test_feb_driver.py
174
174
  tests/test_feb_signal_generator_didv.py
175
+ tests/test_finite_record_metadata.py
175
176
  tests/test_io_coordinate_cleanup.py
176
177
  tests/test_lakeshore372_driver.py
177
178
  tests/test_laser_configuration_ownership.py
@@ -225,3 +225,24 @@ def test_preflight_fails_on_generator_clipping_and_leaves_feb_disconnected():
225
225
  assert ("output_off", 1) in sg.calls
226
226
  assert ("connect_tes_ac", "A", False) in feb.calls
227
227
  assert ("connect_tes_ac", "B", False) in feb.calls
228
+
229
+
230
+ def test_get_dc_falls_back_to_configured_units_when_never_set_this_session():
231
+ # Regression test: the FEB is normally already biased before a viewer
232
+ # process ever attaches (bias set once, kept for the whole run) - so
233
+ # set_dc() (the only thing that used to populate last_dc_units) is often
234
+ # never called this session at all. get_dc() used to return units=None
235
+ # in that case, unlike PXI4322BiasPath.get_dc() (which falls back to
236
+ # "V", correctly paired with the raw voltage it returns in that same
237
+ # branch). A caller that maps a units *string* to a conversion factor
238
+ # (e.g. pytesscope's PytesdaqxBoardReader.read_tes_bias) can silently
239
+ # read units=None as "not a recognized current unit, must be volts" and
240
+ # divide the FEB's already-in-uA reading by a bias resistor instead -
241
+ # producing a value several orders of magnitude off, with no error
242
+ # raised anywhere.
243
+ service, feb, _sg = _service()
244
+
245
+ state = service.get_dc("TES_A")
246
+
247
+ assert state["value"] == feb.bias_by_channel["A"]
248
+ assert state["units"] == "uA" # from dc_default_units, not left as None
@@ -0,0 +1,89 @@
1
+ """Finite acquisition timing must survive recording and reader selection."""
2
+
3
+ from types import SimpleNamespace
4
+
5
+ import numpy as np
6
+ import pytest
7
+ import zarr
8
+
9
+ from pytesdaqx.io import StreamReader
10
+ from pytesdaqx.io.zarr_utils import read_array, read_attrs
11
+ from pytesdaqx.recorder import HDF5Recorder, RunMetadata, SegmentMetadata, ZarrRecorder
12
+ from pytesdaqx.run.yaml_run import YAMLRunController
13
+
14
+
15
+ def run_metadata(tmp_path):
16
+ return RunMetadata(
17
+ run_name='threshold_I2_D20260914_T120001', output_dir=tmp_path,
18
+ detector_channels=['TES_A'], sample_rate_hz=1000.,
19
+ root_attrs={'measurement': 'threshold', 'measurement_type': 'threshold',
20
+ 'stream_start': 1000., 'facility': 2},
21
+ adc_attrs={'adc_mode': 'finite', 'sample_rate_hz': 1000.,
22
+ 'pretrigger_length_samples': 0},
23
+ )
24
+
25
+
26
+ @pytest.mark.parametrize('storage', ['hdf5', 'zarr'])
27
+ def test_finite_timestamps_and_pretrigger_survive_recording(tmp_path, storage):
28
+ recorder = HDF5Recorder() if storage == 'hdf5' else ZarrRecorder()
29
+ recorder.open(run_metadata(tmp_path))
30
+ timestamps = [1000.125, 1007.75, 1018.3125]
31
+ for index, timestamp in enumerate(timestamps):
32
+ recorder.write_segment(np.full((1, 32), index, dtype=np.int16), SegmentMetadata(
33
+ measurement='threshold', sample_rate_hz=1000., segment_timestamp=timestamp))
34
+ recorder.close()
35
+
36
+ with StreamReader(tmp_path) as reader:
37
+ records = list(reader.iter_records())
38
+ assert len(records) == 3
39
+ for index, (trace, info) in enumerate(records):
40
+ np.testing.assert_array_equal(trace, np.full((1, 32), index))
41
+ key = 'segment_time' if storage == 'hdf5' else 'trace_time'
42
+ assert info[key] == timestamps[index]
43
+ assert info['pretrigger_length_samples'] == 0
44
+ if storage == 'zarr':
45
+ _, info = reader.read_record({'trace_index': 1})
46
+ assert info['trace_time'] == timestamps[1]
47
+ if storage == 'zarr':
48
+ time_path = next(tmp_path.glob('*.zarr')) / 'trace_time'
49
+ np.testing.assert_array_equal(read_array(time_path), timestamps)
50
+ assert read_attrs(time_path)['time_reference'] == 'unix'
51
+
52
+
53
+ def test_missing_finite_timestamp_is_not_replaced_with_write_time(tmp_path):
54
+ recorder = ZarrRecorder()
55
+ recorder.open(run_metadata(tmp_path))
56
+ recorder.write_segment(np.zeros((1, 32)), SegmentMetadata(measurement='threshold', sample_rate_hz=1000.))
57
+ recorder.close()
58
+ with StreamReader(tmp_path) as reader:
59
+ _, info = reader.read_next()
60
+ assert np.isnan(info['trace_time'])
61
+
62
+
63
+ def test_older_finite_zarr_without_timestamp_array_still_reads(tmp_path):
64
+ recorder = ZarrRecorder()
65
+ recorder.open(run_metadata(tmp_path))
66
+ recorder.write_segment(np.zeros((1, 32)), SegmentMetadata(measurement='threshold', sample_rate_hz=1000.))
67
+ recorder.close()
68
+ group = zarr.open_group(str(next(tmp_path.glob('*.zarr'))), mode='a')
69
+ del group['trace_time']
70
+ with StreamReader(tmp_path) as reader:
71
+ _, info = reader.read_next()
72
+ assert info['trace_index'] == 0
73
+ assert 'trace_time' not in info
74
+
75
+
76
+ @pytest.mark.parametrize('trigger', ['none', 'analog_threshold', 'digital_edge'])
77
+ @pytest.mark.parametrize('mode', ['finite', 'continuous'])
78
+ def test_acquisition_builder_records_zero_pretrigger_for_finite_start_triggers(mode, trigger):
79
+ # Metadata building is hardware independent; the configured NI finite
80
+ # implementation uses start triggers, not reference-trigger buffers.
81
+ controller = SimpleNamespace(processors=[], _channel_map_for=lambda channels: [
82
+ {'detector_channel': channels[0], 'array_index': 0, 'adc_physical_channel': 'Dev1/ai0'}])
83
+ attrs, _ = YAMLRunController._build_adc_metadata(controller, {
84
+ 'adc': {'mode': mode, 'sample_rate': 1000.}, 'trigger': {'type': trigger},
85
+ }, record_channels=['TES_A'])
86
+ if mode == 'finite':
87
+ assert attrs['pretrigger_length_samples'] == 0
88
+ else:
89
+ assert 'pretrigger_length_samples' not in attrs
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes