oscura 0.5.1__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (497) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/edges.py +325 -65
  5. oscura/analyzers/digital/quality.py +293 -166
  6. oscura/analyzers/digital/timing.py +260 -115
  7. oscura/analyzers/digital/timing_numba.py +334 -0
  8. oscura/analyzers/entropy.py +605 -0
  9. oscura/analyzers/eye/diagram.py +176 -109
  10. oscura/analyzers/eye/metrics.py +5 -5
  11. oscura/analyzers/jitter/__init__.py +6 -4
  12. oscura/analyzers/jitter/ber.py +52 -52
  13. oscura/analyzers/jitter/classification.py +156 -0
  14. oscura/analyzers/jitter/decomposition.py +163 -113
  15. oscura/analyzers/jitter/spectrum.py +80 -64
  16. oscura/analyzers/ml/__init__.py +39 -0
  17. oscura/analyzers/ml/features.py +600 -0
  18. oscura/analyzers/ml/signal_classifier.py +604 -0
  19. oscura/analyzers/packet/daq.py +246 -158
  20. oscura/analyzers/packet/parser.py +12 -1
  21. oscura/analyzers/packet/payload.py +50 -2110
  22. oscura/analyzers/packet/payload_analysis.py +361 -181
  23. oscura/analyzers/packet/payload_patterns.py +133 -70
  24. oscura/analyzers/packet/stream.py +84 -23
  25. oscura/analyzers/patterns/__init__.py +26 -5
  26. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  27. oscura/analyzers/patterns/clustering.py +169 -108
  28. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  29. oscura/analyzers/patterns/discovery.py +1 -1
  30. oscura/analyzers/patterns/matching.py +581 -197
  31. oscura/analyzers/patterns/pattern_mining.py +778 -0
  32. oscura/analyzers/patterns/periodic.py +121 -38
  33. oscura/analyzers/patterns/sequences.py +175 -78
  34. oscura/analyzers/power/conduction.py +1 -1
  35. oscura/analyzers/power/soa.py +6 -6
  36. oscura/analyzers/power/switching.py +250 -110
  37. oscura/analyzers/protocol/__init__.py +17 -1
  38. oscura/analyzers/protocols/base.py +6 -6
  39. oscura/analyzers/protocols/ble/__init__.py +38 -0
  40. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  41. oscura/analyzers/protocols/ble/uuids.py +288 -0
  42. oscura/analyzers/protocols/can.py +257 -127
  43. oscura/analyzers/protocols/can_fd.py +107 -80
  44. oscura/analyzers/protocols/flexray.py +139 -80
  45. oscura/analyzers/protocols/hdlc.py +93 -58
  46. oscura/analyzers/protocols/i2c.py +247 -106
  47. oscura/analyzers/protocols/i2s.py +138 -86
  48. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  49. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  50. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  51. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  52. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  53. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  54. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  55. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  56. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  57. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  58. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  59. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  60. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  61. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  62. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  63. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  64. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  65. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  66. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  67. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  68. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  69. oscura/analyzers/protocols/jtag.py +180 -98
  70. oscura/analyzers/protocols/lin.py +219 -114
  71. oscura/analyzers/protocols/manchester.py +4 -4
  72. oscura/analyzers/protocols/onewire.py +253 -149
  73. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  74. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  75. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  76. oscura/analyzers/protocols/spi.py +192 -95
  77. oscura/analyzers/protocols/swd.py +321 -167
  78. oscura/analyzers/protocols/uart.py +267 -125
  79. oscura/analyzers/protocols/usb.py +235 -131
  80. oscura/analyzers/side_channel/power.py +17 -12
  81. oscura/analyzers/signal/__init__.py +15 -0
  82. oscura/analyzers/signal/timing_analysis.py +1086 -0
  83. oscura/analyzers/signal_integrity/__init__.py +4 -1
  84. oscura/analyzers/signal_integrity/sparams.py +2 -19
  85. oscura/analyzers/spectral/chunked.py +129 -60
  86. oscura/analyzers/spectral/chunked_fft.py +300 -94
  87. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  88. oscura/analyzers/statistical/checksum.py +376 -217
  89. oscura/analyzers/statistical/classification.py +229 -107
  90. oscura/analyzers/statistical/entropy.py +78 -53
  91. oscura/analyzers/statistics/correlation.py +407 -211
  92. oscura/analyzers/statistics/outliers.py +2 -2
  93. oscura/analyzers/statistics/streaming.py +30 -5
  94. oscura/analyzers/validation.py +216 -101
  95. oscura/analyzers/waveform/measurements.py +9 -0
  96. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  97. oscura/analyzers/waveform/spectral.py +500 -228
  98. oscura/api/__init__.py +31 -5
  99. oscura/api/dsl/__init__.py +582 -0
  100. oscura/{dsl → api/dsl}/commands.py +43 -76
  101. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  102. oscura/{dsl → api/dsl}/parser.py +107 -77
  103. oscura/{dsl → api/dsl}/repl.py +2 -2
  104. oscura/api/dsl.py +1 -1
  105. oscura/{integrations → api/integrations}/__init__.py +1 -1
  106. oscura/{integrations → api/integrations}/llm.py +201 -102
  107. oscura/api/operators.py +3 -3
  108. oscura/api/optimization.py +144 -30
  109. oscura/api/rest_server.py +921 -0
  110. oscura/api/server/__init__.py +17 -0
  111. oscura/api/server/dashboard.py +850 -0
  112. oscura/api/server/static/README.md +34 -0
  113. oscura/api/server/templates/base.html +181 -0
  114. oscura/api/server/templates/export.html +120 -0
  115. oscura/api/server/templates/home.html +284 -0
  116. oscura/api/server/templates/protocols.html +58 -0
  117. oscura/api/server/templates/reports.html +43 -0
  118. oscura/api/server/templates/session_detail.html +89 -0
  119. oscura/api/server/templates/sessions.html +83 -0
  120. oscura/api/server/templates/waveforms.html +73 -0
  121. oscura/automotive/__init__.py +8 -1
  122. oscura/automotive/can/__init__.py +10 -0
  123. oscura/automotive/can/checksum.py +3 -1
  124. oscura/automotive/can/dbc_generator.py +590 -0
  125. oscura/automotive/can/message_wrapper.py +121 -74
  126. oscura/automotive/can/patterns.py +98 -21
  127. oscura/automotive/can/session.py +292 -56
  128. oscura/automotive/can/state_machine.py +6 -3
  129. oscura/automotive/can/stimulus_response.py +97 -75
  130. oscura/automotive/dbc/__init__.py +10 -2
  131. oscura/automotive/dbc/generator.py +84 -56
  132. oscura/automotive/dbc/parser.py +6 -6
  133. oscura/automotive/dtc/data.json +17 -102
  134. oscura/automotive/dtc/database.py +2 -2
  135. oscura/automotive/flexray/__init__.py +31 -0
  136. oscura/automotive/flexray/analyzer.py +504 -0
  137. oscura/automotive/flexray/crc.py +185 -0
  138. oscura/automotive/flexray/fibex.py +449 -0
  139. oscura/automotive/j1939/__init__.py +45 -8
  140. oscura/automotive/j1939/analyzer.py +605 -0
  141. oscura/automotive/j1939/spns.py +326 -0
  142. oscura/automotive/j1939/transport.py +306 -0
  143. oscura/automotive/lin/__init__.py +47 -0
  144. oscura/automotive/lin/analyzer.py +612 -0
  145. oscura/automotive/loaders/blf.py +13 -2
  146. oscura/automotive/loaders/csv_can.py +143 -72
  147. oscura/automotive/loaders/dispatcher.py +50 -2
  148. oscura/automotive/loaders/mdf.py +86 -45
  149. oscura/automotive/loaders/pcap.py +111 -61
  150. oscura/automotive/uds/__init__.py +4 -0
  151. oscura/automotive/uds/analyzer.py +725 -0
  152. oscura/automotive/uds/decoder.py +140 -58
  153. oscura/automotive/uds/models.py +7 -1
  154. oscura/automotive/visualization.py +1 -1
  155. oscura/cli/analyze.py +348 -0
  156. oscura/cli/batch.py +142 -122
  157. oscura/cli/benchmark.py +275 -0
  158. oscura/cli/characterize.py +137 -82
  159. oscura/cli/compare.py +224 -131
  160. oscura/cli/completion.py +250 -0
  161. oscura/cli/config_cmd.py +361 -0
  162. oscura/cli/decode.py +164 -87
  163. oscura/cli/export.py +286 -0
  164. oscura/cli/main.py +115 -31
  165. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  166. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  167. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  168. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  169. oscura/cli/progress.py +147 -0
  170. oscura/cli/shell.py +157 -135
  171. oscura/cli/validate_cmd.py +204 -0
  172. oscura/cli/visualize.py +158 -0
  173. oscura/convenience.py +125 -79
  174. oscura/core/__init__.py +4 -2
  175. oscura/core/backend_selector.py +3 -3
  176. oscura/core/cache.py +126 -15
  177. oscura/core/cancellation.py +1 -1
  178. oscura/{config → core/config}/__init__.py +20 -11
  179. oscura/{config → core/config}/defaults.py +1 -1
  180. oscura/{config → core/config}/loader.py +7 -5
  181. oscura/{config → core/config}/memory.py +5 -5
  182. oscura/{config → core/config}/migration.py +1 -1
  183. oscura/{config → core/config}/pipeline.py +99 -23
  184. oscura/{config → core/config}/preferences.py +1 -1
  185. oscura/{config → core/config}/protocol.py +3 -3
  186. oscura/{config → core/config}/schema.py +426 -272
  187. oscura/{config → core/config}/settings.py +1 -1
  188. oscura/{config → core/config}/thresholds.py +195 -153
  189. oscura/core/correlation.py +5 -6
  190. oscura/core/cross_domain.py +0 -2
  191. oscura/core/debug.py +9 -5
  192. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  193. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  194. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  195. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  196. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  197. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  198. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  199. oscura/core/gpu_backend.py +11 -7
  200. oscura/core/log_query.py +101 -11
  201. oscura/core/logging.py +126 -54
  202. oscura/core/logging_advanced.py +5 -5
  203. oscura/core/memory_limits.py +108 -70
  204. oscura/core/memory_monitor.py +2 -2
  205. oscura/core/memory_progress.py +7 -7
  206. oscura/core/memory_warnings.py +1 -1
  207. oscura/core/numba_backend.py +13 -13
  208. oscura/{plugins → core/plugins}/__init__.py +9 -9
  209. oscura/{plugins → core/plugins}/base.py +7 -7
  210. oscura/{plugins → core/plugins}/cli.py +3 -3
  211. oscura/{plugins → core/plugins}/discovery.py +186 -106
  212. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  213. oscura/{plugins → core/plugins}/manager.py +7 -7
  214. oscura/{plugins → core/plugins}/registry.py +3 -3
  215. oscura/{plugins → core/plugins}/versioning.py +1 -1
  216. oscura/core/progress.py +16 -1
  217. oscura/core/provenance.py +8 -2
  218. oscura/{schemas → core/schemas}/__init__.py +2 -2
  219. oscura/{schemas → core/schemas}/device_mapping.json +2 -8
  220. oscura/{schemas → core/schemas}/packet_format.json +4 -24
  221. oscura/{schemas → core/schemas}/protocol_definition.json +2 -12
  222. oscura/core/types.py +4 -0
  223. oscura/core/uncertainty.py +3 -3
  224. oscura/correlation/__init__.py +52 -0
  225. oscura/correlation/multi_protocol.py +811 -0
  226. oscura/discovery/auto_decoder.py +117 -35
  227. oscura/discovery/comparison.py +191 -86
  228. oscura/discovery/quality_validator.py +155 -68
  229. oscura/discovery/signal_detector.py +196 -79
  230. oscura/export/__init__.py +18 -8
  231. oscura/export/kaitai_struct.py +513 -0
  232. oscura/export/scapy_layer.py +801 -0
  233. oscura/export/wireshark/generator.py +1 -1
  234. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  235. oscura/export/wireshark_dissector.py +746 -0
  236. oscura/guidance/wizard.py +207 -111
  237. oscura/hardware/__init__.py +19 -0
  238. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  239. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  240. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  241. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  242. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  243. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  244. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  245. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  246. oscura/hardware/firmware/__init__.py +29 -0
  247. oscura/hardware/firmware/pattern_recognition.py +874 -0
  248. oscura/hardware/hal_detector.py +736 -0
  249. oscura/hardware/security/__init__.py +37 -0
  250. oscura/hardware/security/side_channel_detector.py +1126 -0
  251. oscura/inference/__init__.py +4 -0
  252. oscura/inference/active_learning/observation_table.py +4 -1
  253. oscura/inference/alignment.py +216 -123
  254. oscura/inference/bayesian.py +113 -33
  255. oscura/inference/crc_reverse.py +101 -55
  256. oscura/inference/logic.py +6 -2
  257. oscura/inference/message_format.py +342 -183
  258. oscura/inference/protocol.py +95 -44
  259. oscura/inference/protocol_dsl.py +180 -82
  260. oscura/inference/signal_intelligence.py +1439 -706
  261. oscura/inference/spectral.py +99 -57
  262. oscura/inference/state_machine.py +810 -158
  263. oscura/inference/stream.py +270 -110
  264. oscura/iot/__init__.py +34 -0
  265. oscura/iot/coap/__init__.py +32 -0
  266. oscura/iot/coap/analyzer.py +668 -0
  267. oscura/iot/coap/options.py +212 -0
  268. oscura/iot/lorawan/__init__.py +21 -0
  269. oscura/iot/lorawan/crypto.py +206 -0
  270. oscura/iot/lorawan/decoder.py +801 -0
  271. oscura/iot/lorawan/mac_commands.py +341 -0
  272. oscura/iot/mqtt/__init__.py +27 -0
  273. oscura/iot/mqtt/analyzer.py +999 -0
  274. oscura/iot/mqtt/properties.py +315 -0
  275. oscura/iot/zigbee/__init__.py +31 -0
  276. oscura/iot/zigbee/analyzer.py +615 -0
  277. oscura/iot/zigbee/security.py +153 -0
  278. oscura/iot/zigbee/zcl.py +349 -0
  279. oscura/jupyter/display.py +125 -45
  280. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  281. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  282. oscura/jupyter/exploratory/fuzzy.py +746 -0
  283. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  284. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  285. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  286. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  287. oscura/jupyter/exploratory/sync.py +612 -0
  288. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  289. oscura/jupyter/magic.py +4 -4
  290. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  291. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  292. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  293. oscura/loaders/__init__.py +183 -67
  294. oscura/loaders/binary.py +88 -1
  295. oscura/loaders/chipwhisperer.py +153 -137
  296. oscura/loaders/configurable.py +208 -86
  297. oscura/loaders/csv_loader.py +458 -215
  298. oscura/loaders/hdf5_loader.py +278 -119
  299. oscura/loaders/lazy.py +87 -54
  300. oscura/loaders/mmap_loader.py +1 -1
  301. oscura/loaders/numpy_loader.py +253 -116
  302. oscura/loaders/pcap.py +226 -151
  303. oscura/loaders/rigol.py +110 -49
  304. oscura/loaders/sigrok.py +201 -78
  305. oscura/loaders/tdms.py +81 -58
  306. oscura/loaders/tektronix.py +291 -174
  307. oscura/loaders/touchstone.py +182 -87
  308. oscura/loaders/tss.py +456 -0
  309. oscura/loaders/vcd.py +215 -117
  310. oscura/loaders/wav.py +155 -68
  311. oscura/reporting/__init__.py +9 -0
  312. oscura/reporting/analyze.py +352 -146
  313. oscura/reporting/argument_preparer.py +69 -14
  314. oscura/reporting/auto_report.py +97 -61
  315. oscura/reporting/batch.py +131 -58
  316. oscura/reporting/chart_selection.py +57 -45
  317. oscura/reporting/comparison.py +63 -17
  318. oscura/reporting/content/executive.py +76 -24
  319. oscura/reporting/core_formats/multi_format.py +11 -8
  320. oscura/reporting/engine.py +312 -158
  321. oscura/reporting/enhanced_reports.py +949 -0
  322. oscura/reporting/export.py +86 -43
  323. oscura/reporting/formatting/numbers.py +69 -42
  324. oscura/reporting/html.py +139 -58
  325. oscura/reporting/index.py +137 -65
  326. oscura/reporting/output.py +158 -67
  327. oscura/reporting/pdf.py +67 -102
  328. oscura/reporting/plots.py +191 -112
  329. oscura/reporting/sections.py +88 -47
  330. oscura/reporting/standards.py +104 -61
  331. oscura/reporting/summary_generator.py +75 -55
  332. oscura/reporting/tables.py +138 -54
  333. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  334. oscura/sessions/__init__.py +14 -23
  335. oscura/sessions/base.py +3 -3
  336. oscura/sessions/blackbox.py +106 -10
  337. oscura/sessions/generic.py +2 -2
  338. oscura/sessions/legacy.py +783 -0
  339. oscura/side_channel/__init__.py +63 -0
  340. oscura/side_channel/dpa.py +1025 -0
  341. oscura/utils/__init__.py +15 -1
  342. oscura/utils/bitwise.py +118 -0
  343. oscura/{builders → utils/builders}/__init__.py +1 -1
  344. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  345. oscura/{comparison → utils/comparison}/compare.py +202 -101
  346. oscura/{comparison → utils/comparison}/golden.py +83 -63
  347. oscura/{comparison → utils/comparison}/limits.py +313 -89
  348. oscura/{comparison → utils/comparison}/mask.py +151 -45
  349. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  350. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  351. oscura/{component → utils/component}/__init__.py +3 -3
  352. oscura/{component → utils/component}/impedance.py +122 -58
  353. oscura/{component → utils/component}/reactive.py +165 -168
  354. oscura/{component → utils/component}/transmission_line.py +3 -3
  355. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  356. oscura/{filtering → utils/filtering}/base.py +1 -1
  357. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  358. oscura/{filtering → utils/filtering}/design.py +169 -93
  359. oscura/{filtering → utils/filtering}/filters.py +2 -2
  360. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  361. oscura/utils/geometry.py +31 -0
  362. oscura/utils/imports.py +184 -0
  363. oscura/utils/lazy.py +1 -1
  364. oscura/{math → utils/math}/__init__.py +2 -2
  365. oscura/{math → utils/math}/arithmetic.py +114 -48
  366. oscura/{math → utils/math}/interpolation.py +139 -106
  367. oscura/utils/memory.py +129 -66
  368. oscura/utils/memory_advanced.py +92 -9
  369. oscura/utils/memory_extensions.py +10 -8
  370. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  371. oscura/{optimization → utils/optimization}/search.py +2 -2
  372. oscura/utils/performance/__init__.py +58 -0
  373. oscura/utils/performance/caching.py +889 -0
  374. oscura/utils/performance/lsh_clustering.py +333 -0
  375. oscura/utils/performance/memory_optimizer.py +699 -0
  376. oscura/utils/performance/optimizations.py +675 -0
  377. oscura/utils/performance/parallel.py +654 -0
  378. oscura/utils/performance/profiling.py +661 -0
  379. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  380. oscura/{pipeline → utils/pipeline}/composition.py +1 -1
  381. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  382. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  383. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  384. oscura/{search → utils/search}/__init__.py +3 -3
  385. oscura/{search → utils/search}/anomaly.py +188 -58
  386. oscura/utils/search/context.py +294 -0
  387. oscura/{search → utils/search}/pattern.py +138 -10
  388. oscura/utils/serial.py +51 -0
  389. oscura/utils/storage/__init__.py +61 -0
  390. oscura/utils/storage/database.py +1166 -0
  391. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  392. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  393. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  394. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  395. oscura/{triggering → utils/triggering}/base.py +6 -6
  396. oscura/{triggering → utils/triggering}/edge.py +2 -2
  397. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  398. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  399. oscura/{triggering → utils/triggering}/window.py +2 -2
  400. oscura/utils/validation.py +32 -0
  401. oscura/validation/__init__.py +121 -0
  402. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  403. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  404. oscura/{compliance → validation/compliance}/masks.py +1 -1
  405. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  406. oscura/{compliance → validation/compliance}/testing.py +114 -52
  407. oscura/validation/compliance_tests.py +915 -0
  408. oscura/validation/fuzzer.py +990 -0
  409. oscura/validation/grammar_tests.py +596 -0
  410. oscura/validation/grammar_validator.py +904 -0
  411. oscura/validation/hil_testing.py +977 -0
  412. oscura/{quality → validation/quality}/__init__.py +4 -4
  413. oscura/{quality → validation/quality}/ensemble.py +251 -171
  414. oscura/{quality → validation/quality}/explainer.py +3 -3
  415. oscura/{quality → validation/quality}/scoring.py +1 -1
  416. oscura/{quality → validation/quality}/warnings.py +4 -4
  417. oscura/validation/regression_suite.py +808 -0
  418. oscura/validation/replay.py +788 -0
  419. oscura/{testing → validation/testing}/__init__.py +2 -2
  420. oscura/{testing → validation/testing}/synthetic.py +5 -5
  421. oscura/visualization/__init__.py +9 -0
  422. oscura/visualization/accessibility.py +1 -1
  423. oscura/visualization/annotations.py +64 -67
  424. oscura/visualization/colors.py +7 -7
  425. oscura/visualization/digital.py +180 -81
  426. oscura/visualization/eye.py +236 -85
  427. oscura/visualization/interactive.py +320 -143
  428. oscura/visualization/jitter.py +587 -247
  429. oscura/visualization/layout.py +169 -134
  430. oscura/visualization/optimization.py +103 -52
  431. oscura/visualization/palettes.py +1 -1
  432. oscura/visualization/power.py +427 -211
  433. oscura/visualization/power_extended.py +626 -297
  434. oscura/visualization/presets.py +2 -0
  435. oscura/visualization/protocols.py +495 -181
  436. oscura/visualization/render.py +79 -63
  437. oscura/visualization/reverse_engineering.py +171 -124
  438. oscura/visualization/signal_integrity.py +460 -279
  439. oscura/visualization/specialized.py +190 -100
  440. oscura/visualization/spectral.py +670 -255
  441. oscura/visualization/thumbnails.py +166 -137
  442. oscura/visualization/waveform.py +150 -63
  443. oscura/workflows/__init__.py +3 -0
  444. oscura/{batch → workflows/batch}/__init__.py +5 -5
  445. oscura/{batch → workflows/batch}/advanced.py +150 -75
  446. oscura/workflows/batch/aggregate.py +531 -0
  447. oscura/workflows/batch/analyze.py +236 -0
  448. oscura/{batch → workflows/batch}/logging.py +2 -2
  449. oscura/{batch → workflows/batch}/metrics.py +1 -1
  450. oscura/workflows/complete_re.py +1144 -0
  451. oscura/workflows/compliance.py +44 -54
  452. oscura/workflows/digital.py +197 -51
  453. oscura/workflows/legacy/__init__.py +12 -0
  454. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  455. oscura/workflows/multi_trace.py +9 -9
  456. oscura/workflows/power.py +42 -62
  457. oscura/workflows/protocol.py +82 -49
  458. oscura/workflows/reverse_engineering.py +351 -150
  459. oscura/workflows/signal_integrity.py +157 -82
  460. oscura-0.7.0.dist-info/METADATA +661 -0
  461. oscura-0.7.0.dist-info/RECORD +591 -0
  462. oscura/batch/aggregate.py +0 -300
  463. oscura/batch/analyze.py +0 -139
  464. oscura/dsl/__init__.py +0 -73
  465. oscura/exceptions.py +0 -59
  466. oscura/exploratory/fuzzy.py +0 -513
  467. oscura/exploratory/sync.py +0 -384
  468. oscura/exporters/__init__.py +0 -94
  469. oscura/exporters/csv.py +0 -303
  470. oscura/exporters/exporters.py +0 -44
  471. oscura/exporters/hdf5.py +0 -217
  472. oscura/exporters/html_export.py +0 -701
  473. oscura/exporters/json_export.py +0 -291
  474. oscura/exporters/markdown_export.py +0 -367
  475. oscura/exporters/matlab_export.py +0 -354
  476. oscura/exporters/npz_export.py +0 -219
  477. oscura/exporters/spice_export.py +0 -210
  478. oscura/search/context.py +0 -149
  479. oscura/session/__init__.py +0 -34
  480. oscura/session/annotations.py +0 -289
  481. oscura/session/history.py +0 -313
  482. oscura/session/session.py +0 -520
  483. oscura/workflow/__init__.py +0 -13
  484. oscura-0.5.1.dist-info/METADATA +0 -583
  485. oscura-0.5.1.dist-info/RECORD +0 -481
  486. /oscura/core/{config.py → config/legacy.py} +0 -0
  487. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  488. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  489. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  490. /oscura/{schemas → core/schemas}/bus_configuration.json +0 -0
  491. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  492. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  493. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  494. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  495. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/WHEEL +0 -0
  496. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/entry_points.txt +0 -0
  497. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/licenses/LICENSE +0 -0
oscura/exporters/csv.py DELETED
@@ -1,303 +0,0 @@
1
- """CSV export functionality.
2
-
3
- This module provides trace and measurement export to CSV format.
4
-
5
-
6
- Example:
7
- >>> from oscura.exporters.csv import export_csv
8
- >>> export_csv(trace, "output.csv")
9
- >>> export_csv(measurements, "results.csv")
10
-
11
- References:
12
- RFC 4180 (CSV format)
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import csv
18
- from pathlib import Path
19
- from typing import TYPE_CHECKING, Any
20
-
21
- import numpy as np
22
-
23
- from oscura.core.types import DigitalTrace, WaveformTrace
24
-
25
- if TYPE_CHECKING:
26
- from numpy.typing import NDArray
27
-
28
-
29
- def export_csv(
30
- data: WaveformTrace | DigitalTrace | dict[str, Any] | NDArray[Any],
31
- path: str | Path,
32
- *,
33
- include_time: bool = True,
34
- time_unit: str = "s",
35
- precision: int = 9,
36
- delimiter: str = ",",
37
- header: bool = True,
38
- ) -> None:
39
- """Export data to CSV format.
40
-
41
- Args:
42
- data: Data to export. Can be:
43
- - WaveformTrace or DigitalTrace (with metadata as comments)
44
- - Dictionary of measurements
45
- - NumPy array
46
- path: Output file path.
47
- include_time: Include time column for traces.
48
- time_unit: Time unit ("s", "ms", "us", "ns").
49
- precision: Decimal precision for floating point values.
50
- delimiter: Column delimiter.
51
- header: Include header row and metadata comments.
52
-
53
- Raises:
54
- TypeError: If data type is not supported.
55
-
56
- Example:
57
- >>> export_csv(trace, "waveform.csv")
58
- >>> export_csv(trace, "data.csv", precision=6, delimiter="\t")
59
- >>> export_csv(measurements, "results.csv")
60
-
61
- Note:
62
- When exporting traces, metadata is included as comment lines
63
- starting with '#' when header=True.
64
-
65
- References:
66
- EXP-001
67
- """
68
- path = Path(path)
69
-
70
- if isinstance(data, WaveformTrace | DigitalTrace):
71
- _export_trace(data, path, include_time, time_unit, precision, delimiter, header)
72
- elif isinstance(data, dict):
73
- _export_dict(data, path, precision, delimiter, header)
74
- elif isinstance(data, np.ndarray):
75
- _export_array(data, path, precision, delimiter, header)
76
- else:
77
- raise TypeError(f"Unsupported data type: {type(data)}")
78
-
79
-
80
- def _export_trace(
81
- trace: WaveformTrace | DigitalTrace,
82
- path: Path,
83
- include_time: bool,
84
- time_unit: str,
85
- precision: int,
86
- delimiter: str,
87
- header: bool,
88
- ) -> None:
89
- """Export trace to CSV.
90
-
91
- Args:
92
- trace: Trace to export.
93
- path: Output file path.
94
- include_time: Include time column.
95
- time_unit: Time unit for column.
96
- precision: Decimal precision.
97
- delimiter: Column delimiter.
98
- header: Include header row.
99
- """
100
- time_multipliers = {"s": 1.0, "ms": 1e3, "us": 1e6, "ns": 1e9}
101
- multiplier = time_multipliers.get(time_unit, 1.0)
102
-
103
- with open(path, "w", newline="") as f:
104
- writer = csv.writer(f, delimiter=delimiter)
105
-
106
- # Write metadata as comments if header is enabled
107
- if header:
108
- # Metadata comments
109
- meta = trace.metadata
110
- f.write("# Oscura CSV Export\n")
111
- f.write(f"# Sample Rate: {meta.sample_rate} Hz\n")
112
- f.write(f"# Time Base: {meta.time_base} s\n")
113
- f.write(f"# Samples: {len(trace.data)}\n")
114
- f.write(f"# Duration: {trace.duration} s\n")
115
-
116
- if meta.vertical_scale is not None:
117
- f.write(f"# Vertical Scale: {meta.vertical_scale} V/div\n")
118
- if meta.vertical_offset is not None:
119
- f.write(f"# Vertical Offset: {meta.vertical_offset} V\n")
120
- if meta.acquisition_time is not None:
121
- f.write(f"# Acquisition Time: {meta.acquisition_time.isoformat()}\n")
122
- if meta.source_file is not None:
123
- f.write(f"# Source File: {meta.source_file}\n")
124
- if meta.channel_name is not None:
125
- f.write(f"# Channel: {meta.channel_name}\n")
126
-
127
- f.write("#\n")
128
-
129
- # Column headers
130
- if include_time:
131
- if isinstance(trace, WaveformTrace):
132
- writer.writerow([f"Time ({time_unit})", "Voltage"])
133
- else:
134
- writer.writerow([f"Time ({time_unit})", "Digital"])
135
- elif isinstance(trace, WaveformTrace):
136
- writer.writerow(["Voltage"])
137
- else:
138
- writer.writerow(["Digital"])
139
-
140
- # Data
141
- n_samples = len(trace.data)
142
- time_base = trace.metadata.time_base
143
-
144
- for i in range(n_samples):
145
- if include_time:
146
- time_val = i * time_base * multiplier
147
- if isinstance(trace, WaveformTrace):
148
- writer.writerow([f"{time_val:.{precision}g}", f"{trace.data[i]:.{precision}g}"])
149
- else:
150
- writer.writerow([f"{time_val:.{precision}g}", int(trace.data[i])])
151
- elif isinstance(trace, WaveformTrace):
152
- writer.writerow([f"{trace.data[i]:.{precision}g}"])
153
- else:
154
- writer.writerow([int(trace.data[i])])
155
-
156
-
157
- def _export_dict(
158
- data: dict[str, Any],
159
- path: Path,
160
- precision: int,
161
- delimiter: str,
162
- header: bool,
163
- ) -> None:
164
- """Export dictionary to CSV.
165
-
166
- Args:
167
- data: Dictionary to export.
168
- path: Output file path.
169
- precision: Decimal precision.
170
- delimiter: Column delimiter.
171
- header: Include header row.
172
- """
173
- with open(path, "w", newline="") as f:
174
- writer = csv.writer(f, delimiter=delimiter)
175
-
176
- if header:
177
- writer.writerow(["Parameter", "Value", "Unit"])
178
-
179
- for key, value in data.items():
180
- if isinstance(value, dict):
181
- # Nested dict with value/unit
182
- val = value.get("value", value)
183
- unit = value.get("unit", "")
184
- if isinstance(val, float):
185
- writer.writerow([key, f"{val:.{precision}g}", unit])
186
- else:
187
- writer.writerow([key, val, unit])
188
- elif isinstance(value, float):
189
- writer.writerow([key, f"{value:.{precision}g}", ""])
190
- else:
191
- writer.writerow([key, value, ""])
192
-
193
-
194
- def _export_array(
195
- data: NDArray[Any],
196
- path: Path,
197
- precision: int,
198
- delimiter: str,
199
- header: bool,
200
- ) -> None:
201
- """Export numpy array to CSV.
202
-
203
- Args:
204
- data: NumPy array to export.
205
- path: Output file path.
206
- precision: Decimal precision.
207
- delimiter: Column delimiter.
208
- header: Include header row.
209
- """
210
- # Handle different array dimensions
211
- if data.ndim == 1:
212
- data = data.reshape(-1, 1)
213
-
214
- with open(path, "w", newline="") as f:
215
- writer = csv.writer(f, delimiter=delimiter)
216
-
217
- if header:
218
- cols = [f"Column_{i}" for i in range(data.shape[1])]
219
- writer.writerow(cols)
220
-
221
- for row in data:
222
- formatted = []
223
- for val in row:
224
- if isinstance(val, float | np.floating):
225
- formatted.append(f"{val:.{precision}g}")
226
- else:
227
- formatted.append(str(val)) # type: ignore[unreachable]
228
- writer.writerow(formatted)
229
-
230
-
231
- def export_multi_trace_csv(
232
- traces: list[WaveformTrace | DigitalTrace],
233
- path: str | Path,
234
- *,
235
- names: list[str] | None = None,
236
- include_time: bool = True,
237
- time_unit: str = "s",
238
- precision: int = 9,
239
- ) -> None:
240
- """Export multiple traces to single CSV file.
241
-
242
- Args:
243
- traces: List of traces to export.
244
- path: Output file path.
245
- names: Column names for each trace.
246
- include_time: Include time column.
247
- time_unit: Time unit.
248
- precision: Decimal precision.
249
-
250
- Example:
251
- >>> export_multi_trace_csv([ch1, ch2, ch3], "channels.csv",
252
- ... names=["CH1", "CH2", "CH3"])
253
- """
254
- if len(traces) == 0:
255
- return
256
-
257
- path = Path(path)
258
-
259
- if names is None:
260
- names = [f"Trace_{i}" for i in range(len(traces))]
261
-
262
- # Use first trace for timing
263
- ref_trace = traces[0]
264
- n_samples = len(ref_trace.data)
265
- time_base = ref_trace.metadata.time_base
266
-
267
- time_multipliers = {"s": 1.0, "ms": 1e3, "us": 1e6, "ns": 1e9}
268
- multiplier = time_multipliers.get(time_unit, 1.0)
269
-
270
- with open(path, "w", newline="") as f:
271
- writer = csv.writer(f)
272
-
273
- # Header
274
- header_row = []
275
- if include_time:
276
- header_row.append(f"Time ({time_unit})")
277
- header_row.extend(names)
278
- writer.writerow(header_row)
279
-
280
- # Data
281
- for i in range(n_samples):
282
- row = []
283
-
284
- if include_time:
285
- time_val = i * time_base * multiplier
286
- row.append(f"{time_val:.{precision}g}")
287
-
288
- for trace in traces:
289
- if i < len(trace.data):
290
- if isinstance(trace, WaveformTrace):
291
- row.append(f"{trace.data[i]:.{precision}g}")
292
- else:
293
- row.append(str(int(trace.data[i])))
294
- else:
295
- row.append("")
296
-
297
- writer.writerow(row)
298
-
299
-
300
- __all__ = [
301
- "export_csv",
302
- "export_multi_trace_csv",
303
- ]
@@ -1,44 +0,0 @@
1
- """Exporters namespace module.
2
-
3
- This module provides a namespace for export functions to support:
4
- from oscura.exporters import exporters
5
- exporters.csv(trace, "output.csv")
6
-
7
- Re-exports main export functions with short names.
8
- """
9
-
10
- from oscura.exporters.csv import (
11
- export_csv as csv,
12
- )
13
- from oscura.exporters.hdf5 import (
14
- export_hdf5 as hdf5,
15
- )
16
- from oscura.exporters.html_export import (
17
- export_html as html,
18
- )
19
- from oscura.exporters.json_export import (
20
- export_json as json,
21
- )
22
- from oscura.exporters.markdown_export import (
23
- export_markdown as markdown,
24
- )
25
- from oscura.exporters.matlab_export import (
26
- export_mat as mat,
27
- )
28
- from oscura.exporters.npz_export import (
29
- export_npz as npz,
30
- )
31
- from oscura.exporters.spice_export import (
32
- export_pwl as pwl,
33
- )
34
-
35
- __all__ = [
36
- "csv",
37
- "hdf5",
38
- "html",
39
- "json",
40
- "markdown",
41
- "mat",
42
- "npz",
43
- "pwl",
44
- ]
oscura/exporters/hdf5.py DELETED
@@ -1,217 +0,0 @@
1
- """HDF5 export functionality.
2
-
3
- This module provides trace export to HDF5 format with metadata attributes.
4
-
5
-
6
- Example:
7
- >>> from oscura.exporters.hdf5 import export_hdf5
8
- >>> export_hdf5(trace, "output.h5")
9
-
10
- References:
11
- HDF5 specification (https://www.hdfgroup.org/)
12
- """
13
-
14
- from datetime import datetime
15
- from pathlib import Path
16
- from typing import Any
17
-
18
- import numpy as np
19
-
20
- try:
21
- import h5py
22
-
23
- HAS_H5PY = True
24
- except ImportError:
25
- HAS_H5PY = False
26
-
27
- from oscura.core.types import DigitalTrace, WaveformTrace
28
-
29
-
30
- def export_hdf5(
31
- data: WaveformTrace | DigitalTrace | dict[str, WaveformTrace | DigitalTrace],
32
- path: str | Path,
33
- *,
34
- compression: str | None = "gzip",
35
- compression_opts: int = 4,
36
- include_metadata: bool = True,
37
- ) -> None:
38
- """Export data to HDF5 format.
39
-
40
- Args:
41
- data: Data to export. Can be:
42
- - Single WaveformTrace or DigitalTrace
43
- - Dictionary mapping names to traces
44
- path: Output file path.
45
- compression: Compression algorithm ("gzip", "lzf", None).
46
- compression_opts: Compression level (1-9 for gzip).
47
- include_metadata: Include trace metadata as attributes.
48
-
49
- Raises:
50
- ImportError: If h5py is not installed.
51
-
52
- Example:
53
- >>> export_hdf5(trace, "waveform.h5")
54
- >>> export_hdf5({"ch1": ch1, "ch2": ch2}, "channels.h5")
55
- """
56
- if not HAS_H5PY:
57
- raise ImportError("h5py is required for HDF5 export. Install with: pip install h5py")
58
-
59
- path = Path(path)
60
-
61
- if isinstance(data, WaveformTrace | DigitalTrace):
62
- data = {"trace": data}
63
-
64
- with h5py.File(path, "w") as f:
65
- # Add file-level metadata
66
- f.attrs["created"] = datetime.now().isoformat()
67
- f.attrs["oscura_version"] = "1.0"
68
- f.attrs["format"] = "oscura_hdf5"
69
-
70
- for name, trace in data.items():
71
- _write_trace_dataset(
72
- f,
73
- name,
74
- trace,
75
- compression,
76
- compression_opts,
77
- include_metadata,
78
- )
79
-
80
-
81
- def _write_trace_dataset(
82
- f: "h5py.File",
83
- name: str,
84
- trace: WaveformTrace | DigitalTrace,
85
- compression: str | None,
86
- compression_opts: int,
87
- include_metadata: bool,
88
- ) -> None:
89
- """Write trace to HDF5 dataset.
90
-
91
- Args:
92
- f: HDF5 file object.
93
- name: Dataset name.
94
- trace: Trace to write.
95
- compression: Compression algorithm.
96
- compression_opts: Compression level.
97
- include_metadata: Include metadata as attributes.
98
- """
99
- # Create dataset
100
- dtype = np.float64 if isinstance(trace, WaveformTrace) else np.bool_
101
-
102
- kwargs = {}
103
- if compression:
104
- kwargs["compression"] = compression
105
- if compression == "gzip":
106
- kwargs["compression_opts"] = compression_opts # type: ignore[assignment]
107
-
108
- ds = f.create_dataset(name, data=trace.data.astype(dtype), **kwargs)
109
-
110
- # Add metadata attributes
111
- if include_metadata:
112
- meta = trace.metadata
113
-
114
- ds.attrs["sample_rate"] = meta.sample_rate
115
- ds.attrs["time_base"] = meta.time_base
116
-
117
- if meta.vertical_scale is not None:
118
- ds.attrs["vertical_scale"] = meta.vertical_scale
119
-
120
- if meta.vertical_offset is not None:
121
- ds.attrs["vertical_offset"] = meta.vertical_offset
122
-
123
- if meta.acquisition_time is not None:
124
- ds.attrs["acquisition_time"] = meta.acquisition_time.isoformat()
125
-
126
- if meta.source_file is not None:
127
- ds.attrs["source_file"] = str(meta.source_file)
128
-
129
- if meta.channel_name is not None:
130
- ds.attrs["channel_name"] = meta.channel_name
131
-
132
- if meta.trigger_info:
133
- for key, value in meta.trigger_info.items():
134
- ds.attrs[f"trigger_{key}"] = value
135
-
136
- # Type indicator
137
- ds.attrs["trace_type"] = "waveform" if isinstance(trace, WaveformTrace) else "digital"
138
-
139
-
140
- def export_measurement_results(
141
- results: dict[str, Any],
142
- path: str | Path,
143
- *,
144
- group_name: str = "measurements",
145
- ) -> None:
146
- """Export measurement results to HDF5.
147
-
148
- Args:
149
- results: Dictionary of measurement results.
150
- path: Output file path.
151
- group_name: HDF5 group name for results.
152
-
153
- Raises:
154
- ImportError: If h5py is not installed.
155
-
156
- Example:
157
- >>> results = measure(trace)
158
- >>> export_measurement_results(results, "measurements.h5")
159
- """
160
- if not HAS_H5PY:
161
- raise ImportError("h5py is required for HDF5 export")
162
-
163
- path = Path(path)
164
-
165
- with h5py.File(path, "a") as f:
166
- grp = f.require_group(group_name)
167
-
168
- for name, value in results.items():
169
- if isinstance(value, dict):
170
- # Nested dict (value/unit pairs)
171
- sub_grp = grp.require_group(name)
172
- for k, v in value.items():
173
- if isinstance(v, np.ndarray):
174
- sub_grp.create_dataset(k, data=v)
175
- else:
176
- sub_grp.attrs[k] = v
177
- elif isinstance(value, np.ndarray):
178
- grp.create_dataset(name, data=value)
179
- else:
180
- grp.attrs[name] = value
181
-
182
-
183
- def append_trace(
184
- path: str | Path,
185
- name: str,
186
- trace: WaveformTrace | DigitalTrace,
187
- *,
188
- compression: str | None = "gzip",
189
- ) -> None:
190
- """Append trace to existing HDF5 file.
191
-
192
- Args:
193
- path: HDF5 file path.
194
- name: Dataset name for new trace.
195
- trace: Trace to append.
196
- compression: Compression algorithm.
197
-
198
- Raises:
199
- ImportError: If h5py is not installed.
200
-
201
- Example:
202
- >>> append_trace("data.h5", "ch3", channel3_trace)
203
- """
204
- if not HAS_H5PY:
205
- raise ImportError("h5py is required for HDF5 export")
206
-
207
- path = Path(path)
208
-
209
- with h5py.File(path, "a") as f:
210
- _write_trace_dataset(f, name, trace, compression, 4, True)
211
-
212
-
213
- __all__ = [
214
- "append_trace",
215
- "export_hdf5",
216
- "export_measurement_results",
217
- ]