oscura 0.0.1__py3-none-any.whl → 0.1.1__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 (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,445 @@
1
+ """Analysis session management.
2
+
3
+ This module provides session save/restore functionality for Oscura.
4
+
5
+
6
+ Example:
7
+ >>> session = Session()
8
+ >>> session.load_trace('capture.wfm')
9
+ >>> session.save('debug_session.tks')
10
+ >>>
11
+ >>> # Later...
12
+ >>> session = load_session('debug_session.tks')
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import gzip
18
+ import pickle
19
+ from dataclasses import dataclass, field
20
+ from datetime import datetime
21
+ from pathlib import Path
22
+ from typing import Any
23
+
24
+ import numpy as np
25
+
26
+ from oscura.session.annotations import AnnotationLayer
27
+ from oscura.session.history import OperationHistory
28
+
29
+
30
+ @dataclass
31
+ class Session:
32
+ """Analysis session container.
33
+
34
+ Manages traces, annotations, measurements, and history for a complete
35
+ analysis session. Sessions can be saved and restored.
36
+
37
+ Attributes:
38
+ name: Session name
39
+ traces: Dictionary of loaded traces (name -> trace)
40
+ annotation_layers: Annotation layers
41
+ measurements: Recorded measurements
42
+ history: Operation history
43
+ metadata: Session metadata
44
+ created_at: Creation timestamp
45
+ modified_at: Last modification timestamp
46
+ """
47
+
48
+ name: str = "Untitled Session"
49
+ traces: dict[str, Any] = field(default_factory=dict)
50
+ annotation_layers: dict[str, AnnotationLayer] = field(default_factory=dict)
51
+ measurements: dict[str, Any] = field(default_factory=dict)
52
+ history: OperationHistory = field(default_factory=OperationHistory)
53
+ metadata: dict[str, Any] = field(default_factory=dict)
54
+ created_at: datetime = field(default_factory=datetime.now)
55
+ modified_at: datetime = field(default_factory=datetime.now)
56
+ _file_path: Path | None = None
57
+
58
+ def __post_init__(self) -> None:
59
+ """Initialize default annotation layer."""
60
+ if "default" not in self.annotation_layers:
61
+ self.annotation_layers["default"] = AnnotationLayer("Default")
62
+
63
+ def load_trace(
64
+ self,
65
+ path: str | Path,
66
+ name: str | None = None,
67
+ **load_kwargs: Any,
68
+ ) -> Any:
69
+ """Load a trace into the session.
70
+
71
+ Args:
72
+ path: Path to trace file.
73
+ name: Name for trace in session (default: filename).
74
+ **load_kwargs: Additional arguments for load().
75
+
76
+ Returns:
77
+ Loaded trace.
78
+ """
79
+ from oscura.loaders import load
80
+
81
+ path = Path(path)
82
+ trace = load(str(path), **load_kwargs)
83
+
84
+ if name is None:
85
+ name = path.stem
86
+
87
+ self.traces[name] = trace
88
+ self._mark_modified()
89
+
90
+ self.history.record(
91
+ "load_trace",
92
+ {"path": str(path), "name": name},
93
+ result=f"Loaded {name}",
94
+ )
95
+
96
+ return trace
97
+
98
+ def add_trace(
99
+ self,
100
+ name: str,
101
+ trace: Any,
102
+ ) -> None:
103
+ """Add an in-memory trace to the session.
104
+
105
+ This method allows adding traces that were created programmatically
106
+ or loaded separately, rather than loading from a file.
107
+
108
+ Args:
109
+ name: Name for the trace in the session.
110
+ trace: Trace object (WaveformTrace, DigitalTrace, etc.).
111
+
112
+ Raises:
113
+ ValueError: If name is empty or already exists.
114
+ TypeError: If trace doesn't have expected attributes.
115
+
116
+ Example:
117
+ >>> session = Session()
118
+ >>> data = np.sin(np.linspace(0, 2*np.pi, 1000))
119
+ >>> trace = osc.WaveformTrace(data=data, metadata=osc.TraceMetadata(sample_rate=1e6))
120
+ >>> session.add_trace("my_trace", trace)
121
+ """
122
+ if not name:
123
+ raise ValueError("Trace name cannot be empty")
124
+
125
+ if not hasattr(trace, "data"):
126
+ raise TypeError("Trace must have a 'data' attribute")
127
+
128
+ self.traces[name] = trace
129
+ self._mark_modified()
130
+
131
+ self.history.record(
132
+ "add_trace",
133
+ {"name": name, "type": type(trace).__name__},
134
+ result=f"Added {name}",
135
+ )
136
+
137
+ def remove_trace(self, name: str) -> None:
138
+ """Remove a trace from the session.
139
+
140
+ Args:
141
+ name: Name of the trace to remove.
142
+
143
+ Raises:
144
+ KeyError: If trace not found.
145
+ """
146
+ if name not in self.traces:
147
+ raise KeyError(f"Trace '{name}' not found in session")
148
+
149
+ del self.traces[name]
150
+ self._mark_modified()
151
+
152
+ self.history.record(
153
+ "remove_trace",
154
+ {"name": name},
155
+ result=f"Removed {name}",
156
+ )
157
+
158
+ def get_trace(self, name: str) -> Any:
159
+ """Get trace by name.
160
+
161
+ Args:
162
+ name: Trace name.
163
+
164
+ Returns:
165
+ Trace object.
166
+ """
167
+ return self.traces[name]
168
+
169
+ def list_traces(self) -> list[str]:
170
+ """List all trace names."""
171
+ return list(self.traces.keys())
172
+
173
+ def annotate(
174
+ self,
175
+ text: str,
176
+ *,
177
+ time: float | None = None,
178
+ time_range: tuple[float, float] | None = None,
179
+ layer: str = "default",
180
+ **kwargs: Any,
181
+ ) -> None:
182
+ """Add annotation to session.
183
+
184
+ Args:
185
+ text: Annotation text.
186
+ time: Time point for annotation.
187
+ time_range: Time range for annotation.
188
+ layer: Annotation layer name.
189
+ **kwargs: Additional annotation parameters.
190
+ """
191
+ if layer not in self.annotation_layers:
192
+ self.annotation_layers[layer] = AnnotationLayer(layer)
193
+
194
+ self.annotation_layers[layer].add(
195
+ text=text,
196
+ time=time,
197
+ time_range=time_range,
198
+ **kwargs,
199
+ )
200
+ self._mark_modified()
201
+
202
+ self.history.record(
203
+ "annotate",
204
+ {"text": text, "time": time, "layer": layer},
205
+ )
206
+
207
+ def get_annotations(
208
+ self,
209
+ layer: str | None = None,
210
+ time_range: tuple[float, float] | None = None,
211
+ ) -> list[Any]:
212
+ """Get annotations.
213
+
214
+ Args:
215
+ layer: Filter by layer name (None for all layers).
216
+ time_range: Filter by time range.
217
+
218
+ Returns:
219
+ List of annotations.
220
+ """
221
+ annotations = []
222
+
223
+ layers = [self.annotation_layers[layer]] if layer else self.annotation_layers.values()
224
+
225
+ for ann_layer in layers:
226
+ if time_range:
227
+ annotations.extend(ann_layer.find_in_range(time_range[0], time_range[1]))
228
+ else:
229
+ annotations.extend(ann_layer.annotations)
230
+
231
+ return annotations
232
+
233
+ def record_measurement(
234
+ self,
235
+ name: str,
236
+ value: Any,
237
+ unit: str = "",
238
+ trace_name: str | None = None,
239
+ **metadata: Any,
240
+ ) -> None:
241
+ """Record a measurement result.
242
+
243
+ Args:
244
+ name: Measurement name (e.g., 'rise_time').
245
+ value: Measurement value.
246
+ unit: Unit of measurement.
247
+ trace_name: Associated trace name.
248
+ **metadata: Additional metadata.
249
+ """
250
+ self.measurements[name] = {
251
+ "value": value,
252
+ "unit": unit,
253
+ "trace": trace_name,
254
+ "timestamp": datetime.now().isoformat(),
255
+ **metadata,
256
+ }
257
+ self._mark_modified()
258
+
259
+ self.history.record(
260
+ f"measure_{name}",
261
+ {"trace": trace_name},
262
+ result=f"{value} {unit}".strip(),
263
+ )
264
+
265
+ def get_measurements(self) -> dict[str, Any]:
266
+ """Get all recorded measurements."""
267
+ return self.measurements.copy()
268
+
269
+ def save(
270
+ self,
271
+ path: str | Path | None = None,
272
+ *,
273
+ include_traces: bool = True,
274
+ compress: bool = True,
275
+ ) -> Path:
276
+ """Save session to file.
277
+
278
+ Args:
279
+ path: Output path (default: use existing or generate).
280
+ include_traces: Include trace data in session file.
281
+ compress: Compress session file with gzip.
282
+
283
+ Returns:
284
+ Path to saved file.
285
+
286
+ Example:
287
+ >>> session.save('analysis.tks')
288
+
289
+ Security Note:
290
+ Session files use pickle serialization for flexibility. Share
291
+ session files only with trusted parties. For secure data exchange
292
+ with untrusted parties, use JSON or HDF5 export formats instead.
293
+ """
294
+ if path is None:
295
+ path = self._file_path or Path(f"{self.name.replace(' ', '_')}.tks")
296
+ else:
297
+ path = Path(path)
298
+
299
+ self._file_path = path
300
+ self._mark_modified()
301
+
302
+ # Build session data
303
+ data = self._to_dict(include_traces=include_traces)
304
+
305
+ # Serialize
306
+ if compress:
307
+ with gzip.open(path, "wb") as f:
308
+ pickle.dump(data, f)
309
+ else:
310
+ with open(path, "wb") as f:
311
+ pickle.dump(data, f)
312
+
313
+ self.history.record("save", {"path": str(path)})
314
+
315
+ return path
316
+
317
+ def _to_dict(self, include_traces: bool = True) -> dict[str, Any]:
318
+ """Convert session to dictionary."""
319
+ data: dict[str, Any] = {
320
+ "version": "1.0",
321
+ "name": self.name,
322
+ "created_at": self.created_at.isoformat(),
323
+ "modified_at": self.modified_at.isoformat(),
324
+ "annotation_layers": {
325
+ name: layer.to_dict() for name, layer in self.annotation_layers.items()
326
+ },
327
+ "measurements": self.measurements,
328
+ "history": self.history.to_dict(),
329
+ "metadata": self.metadata,
330
+ }
331
+
332
+ if include_traces:
333
+ # Store traces with their data
334
+ data["traces"] = {}
335
+ for name, trace in self.traces.items():
336
+ trace_data = {
337
+ "type": type(trace).__name__,
338
+ "data": trace.data.tolist() if hasattr(trace, "data") else None,
339
+ "sample_rate": (
340
+ trace.metadata.sample_rate if hasattr(trace, "metadata") else None
341
+ ),
342
+ }
343
+ data["traces"][name] = trace_data
344
+ else:
345
+ data["traces"] = {}
346
+
347
+ return data
348
+
349
+ @classmethod
350
+ def _from_dict(cls, data: dict[str, Any]) -> Session:
351
+ """Create session from dictionary."""
352
+ session = cls(
353
+ name=data.get("name", "Untitled Session"),
354
+ metadata=data.get("metadata", {}),
355
+ )
356
+
357
+ if "created_at" in data:
358
+ session.created_at = datetime.fromisoformat(data["created_at"])
359
+ if "modified_at" in data:
360
+ session.modified_at = datetime.fromisoformat(data["modified_at"])
361
+
362
+ # Restore annotation layers
363
+ for name, layer_data in data.get("annotation_layers", {}).items():
364
+ session.annotation_layers[name] = AnnotationLayer.from_dict(layer_data)
365
+
366
+ # Restore measurements
367
+ session.measurements = data.get("measurements", {})
368
+
369
+ # Restore history
370
+ if "history" in data:
371
+ session.history = OperationHistory.from_dict(data["history"])
372
+
373
+ # Restore traces (if included)
374
+ if "traces" in data:
375
+ from oscura.core.types import WaveformTrace
376
+
377
+ for name, trace_data in data["traces"].items():
378
+ if trace_data.get("data") is not None:
379
+ session.traces[name] = WaveformTrace( # type: ignore[call-arg]
380
+ data=np.array(trace_data["data"]),
381
+ sample_rate=trace_data.get("sample_rate", 1.0),
382
+ )
383
+
384
+ return session
385
+
386
+ def _mark_modified(self) -> None:
387
+ """Update modification timestamp."""
388
+ self.modified_at = datetime.now()
389
+
390
+ def summary(self) -> str:
391
+ """Get session summary."""
392
+ lines = [
393
+ f"Session: {self.name}",
394
+ f"Created: {self.created_at.strftime('%Y-%m-%d %H:%M')}",
395
+ f"Modified: {self.modified_at.strftime('%Y-%m-%d %H:%M')}",
396
+ f"Traces: {len(self.traces)}",
397
+ f"Annotations: {sum(len(l.annotations) for l in self.annotation_layers.values())}", # noqa: E741
398
+ f"Measurements: {len(self.measurements)}",
399
+ f"History entries: {len(self.history.entries)}",
400
+ ]
401
+ return "\n".join(lines)
402
+
403
+
404
+ def load_session(path: str | Path) -> Session:
405
+ """Load session from file.
406
+
407
+ Args:
408
+ path: Path to session file (.tks).
409
+
410
+ Returns:
411
+ Loaded Session object.
412
+
413
+ Example:
414
+ >>> session = load_session('debug_session.tks')
415
+ >>> print(session.list_traces())
416
+
417
+ Security Warning:
418
+ Session files use pickle serialization. Only load session files from
419
+ trusted sources. Loading a malicious .tks file could execute arbitrary
420
+ code. Never load session files from untrusted or unknown sources.
421
+
422
+ For secure data exchange, consider exporting to JSON or HDF5 formats
423
+ instead of using pickle-based session files.
424
+ """
425
+ path = Path(path)
426
+
427
+ try:
428
+ # Try gzip compressed first
429
+ with gzip.open(path, "rb") as f:
430
+ data = pickle.load(f)
431
+ except gzip.BadGzipFile:
432
+ # Fall back to uncompressed
433
+ with open(path, "rb") as f:
434
+ data = pickle.load(f)
435
+
436
+ session = Session._from_dict(data)
437
+ session._file_path = path
438
+
439
+ return session
440
+
441
+
442
+ __all__ = [
443
+ "Session",
444
+ "load_session",
445
+ ]
@@ -0,0 +1,43 @@
1
+ """Streaming APIs for memory-efficient large file processing.
2
+
3
+ This package provides chunk-by-chunk processing capabilities for huge
4
+ waveform files that don't fit in memory, plus real-time streaming APIs.
5
+ """
6
+
7
+ from .chunked import (
8
+ StreamingAnalyzer,
9
+ chunked_fft,
10
+ chunked_spectrogram,
11
+ load_trace_chunks,
12
+ )
13
+ from .progressive import (
14
+ ProgressiveAnalyzer,
15
+ StreamingConfig,
16
+ StreamingProgress,
17
+ create_progressive_analyzer,
18
+ )
19
+ from .realtime import (
20
+ RealtimeAnalyzer,
21
+ RealtimeBuffer,
22
+ RealtimeConfig,
23
+ RealtimeSource,
24
+ RealtimeStream,
25
+ SimulatedSource,
26
+ )
27
+
28
+ __all__ = [
29
+ "ProgressiveAnalyzer",
30
+ "RealtimeAnalyzer",
31
+ "RealtimeBuffer",
32
+ "RealtimeConfig",
33
+ "RealtimeSource",
34
+ "RealtimeStream",
35
+ "SimulatedSource",
36
+ "StreamingAnalyzer",
37
+ "StreamingConfig",
38
+ "StreamingProgress",
39
+ "chunked_fft",
40
+ "chunked_spectrogram",
41
+ "create_progressive_analyzer",
42
+ "load_trace_chunks",
43
+ ]