oscura 0.0.1__py3-none-any.whl → 0.1.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 (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.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.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.0.dist-info}/WHEEL +0 -0
oscura/loaders/lazy.py ADDED
@@ -0,0 +1,370 @@
1
+ """Lazy loading for huge waveform files.
2
+
3
+ This module provides memory-mapped file loading where metadata is loaded
4
+ immediately but data is deferred until first access. Useful for multi-GB files.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ import numpy as np
13
+
14
+ from oscura.core.exceptions import LoaderError
15
+
16
+ if TYPE_CHECKING:
17
+ from numpy.typing import DTypeLike, NDArray
18
+
19
+ from oscura.core.types import WaveformTrace
20
+
21
+
22
+ class LazyWaveformTrace:
23
+ """Lazy-loading wrapper for WaveformTrace.
24
+
25
+ Loads metadata immediately but defers data loading until first access.
26
+ Uses numpy.memmap for efficient memory-mapped file access.
27
+
28
+ Example:
29
+ >>> from oscura.loaders.lazy import load_trace_lazy
30
+ >>> trace = load_trace_lazy('huge_trace.npy', lazy=True)
31
+ >>> # Metadata available immediately
32
+ >>> print(f"Length: {trace.length}, Sample rate: {trace.sample_rate}")
33
+ >>> # Data loaded on first access
34
+ >>> data = trace.data # Loads data now
35
+ >>> subset = trace[1000:2000] # Only loads requested slice
36
+
37
+ References:
38
+ API-017: Lazy Loading for Huge Files
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ file_path: str | Path,
44
+ sample_rate: float,
45
+ length: int,
46
+ *,
47
+ dtype: DTypeLike = np.float64,
48
+ offset: int = 0,
49
+ metadata: dict[str, Any] | None = None,
50
+ ) -> None:
51
+ """Initialize lazy trace.
52
+
53
+ Args:
54
+ file_path: Path to binary data file.
55
+ sample_rate: Sample rate in Hz.
56
+ length: Number of samples.
57
+ dtype: Data type of samples.
58
+ offset: Byte offset to start of data in file.
59
+ metadata: Additional metadata.
60
+
61
+ Raises:
62
+ LoaderError: If file not found.
63
+
64
+ Example:
65
+ >>> trace = LazyWaveformTrace(
66
+ ... file_path='trace.npy',
67
+ ... sample_rate=1e9,
68
+ ... length=10_000_000
69
+ ... )
70
+ """
71
+ self._file_path = Path(file_path)
72
+ self._sample_rate = sample_rate
73
+ self._length = length
74
+ self._dtype = np.dtype(dtype)
75
+ self._offset = offset
76
+ self._metadata = metadata or {}
77
+
78
+ # Deferred data - loaded on first access
79
+ self._data: NDArray[np.float64] | None = None
80
+ self._memmap: np.memmap[Any, np.dtype[Any]] | None = None
81
+
82
+ # Verify file exists
83
+ if not self._file_path.exists():
84
+ raise LoaderError(f"File not found: {self._file_path}")
85
+
86
+ @property
87
+ def sample_rate(self) -> float:
88
+ """Sample rate in Hz."""
89
+ return self._sample_rate
90
+
91
+ @property
92
+ def length(self) -> int:
93
+ """Number of samples."""
94
+ return self._length
95
+
96
+ @property
97
+ def duration(self) -> float:
98
+ """Duration in seconds."""
99
+ return self._length / self._sample_rate
100
+
101
+ @property
102
+ def metadata(self) -> dict[str, Any]:
103
+ """Metadata dictionary."""
104
+ return self._metadata
105
+
106
+ @property
107
+ def data(self) -> NDArray[np.float64]:
108
+ """Waveform data array.
109
+
110
+ Loads data on first access. Subsequent accesses return cached data.
111
+
112
+ Returns:
113
+ Numpy array of waveform samples.
114
+ """
115
+ if self._data is None:
116
+ self._load_data()
117
+ return self._data # type: ignore[return-value]
118
+
119
+ @property
120
+ def time_vector(self) -> NDArray[np.float64]:
121
+ """Time vector in seconds.
122
+
123
+ Returns:
124
+ Array of time values corresponding to samples.
125
+ """
126
+ return np.arange(self._length) / self._sample_rate
127
+
128
+ def _load_data(self) -> None:
129
+ """Load data from file using memory mapping."""
130
+ try:
131
+ # Use memmap for efficient access
132
+ self._memmap = np.memmap(
133
+ self._file_path,
134
+ dtype=self._dtype,
135
+ mode="r",
136
+ offset=self._offset,
137
+ shape=(self._length,),
138
+ )
139
+
140
+ # Convert to regular array (copies data into memory)
141
+ self._data = np.array(self._memmap, dtype=np.float64)
142
+
143
+ except Exception as e:
144
+ raise LoaderError(f"Failed to load data from {self._file_path}: {e}") from e
145
+
146
+ def __getitem__(self, key: int | slice) -> LazyWaveformTrace | float:
147
+ """Slice the trace.
148
+
149
+ Slicing remains lazy - only loads requested portion.
150
+
151
+ Args:
152
+ key: Index or slice.
153
+
154
+ Returns:
155
+ LazyWaveformTrace for slice, float for single index.
156
+
157
+ Raises:
158
+ TypeError: If key is not int or slice.
159
+
160
+ Example:
161
+ >>> subset = trace[1000:2000] # Lazy - doesn't load full data
162
+ >>> sample = trace[500] # Loads single sample
163
+ """
164
+ if isinstance(key, int):
165
+ # Load single sample
166
+ if self._memmap is None:
167
+ self._memmap = np.memmap(
168
+ self._file_path,
169
+ dtype=self._dtype,
170
+ mode="r",
171
+ offset=self._offset,
172
+ shape=(self._length,),
173
+ )
174
+ return float(self._memmap[key])
175
+
176
+ elif isinstance(key, slice):
177
+ # Create new lazy trace for slice
178
+ start, stop, step = key.indices(self._length)
179
+
180
+ if step != 1:
181
+ # Non-unit step requires loading data
182
+ if self._data is None:
183
+ self._load_data()
184
+ sliced_data = self._data[key] # type: ignore[index]
185
+
186
+ # Return eager trace
187
+ from oscura.core.types import TraceMetadata, WaveformTrace
188
+
189
+ metadata = TraceMetadata(
190
+ sample_rate=self._sample_rate,
191
+ **self._metadata, # type: ignore[arg-type]
192
+ )
193
+ return WaveformTrace(data=sliced_data, metadata=metadata) # type: ignore[return-value]
194
+
195
+ # Create lazy slice
196
+ length = stop - start
197
+ offset = self._offset + start * self._dtype.itemsize
198
+
199
+ return LazyWaveformTrace(
200
+ file_path=self._file_path,
201
+ sample_rate=self._sample_rate,
202
+ length=length,
203
+ dtype=self._dtype,
204
+ offset=offset,
205
+ metadata=self._metadata.copy(),
206
+ )
207
+
208
+ else:
209
+ raise TypeError(f"Indices must be int or slice, not {type(key)}")
210
+
211
+ def to_eager(self) -> WaveformTrace:
212
+ """Convert to regular WaveformTrace by loading all data.
213
+
214
+ Returns:
215
+ WaveformTrace with data loaded in memory.
216
+
217
+ Example:
218
+ >>> eager_trace = lazy_trace.to_eager()
219
+ """
220
+ from oscura.core.types import TraceMetadata, WaveformTrace
221
+
222
+ metadata = TraceMetadata(
223
+ sample_rate=self._sample_rate,
224
+ **self._metadata, # type: ignore[arg-type]
225
+ )
226
+ return WaveformTrace(data=self.data, metadata=metadata)
227
+
228
+ def close(self) -> None:
229
+ """Close memory-mapped file handle.
230
+
231
+ Should be called when done with the trace to free resources.
232
+
233
+ Example:
234
+ >>> trace = load_trace_lazy('huge_file.npy', lazy=True)
235
+ >>> # ... use trace ...
236
+ >>> trace.close()
237
+ """
238
+ if self._memmap is not None:
239
+ del self._memmap
240
+ self._memmap = None
241
+
242
+ def __del__(self) -> None:
243
+ """Cleanup memory map on deletion."""
244
+ self.close()
245
+
246
+ def __repr__(self) -> str:
247
+ """String representation."""
248
+ return (
249
+ f"LazyWaveformTrace(file={self._file_path.name}, "
250
+ f"sample_rate={self._sample_rate:.2e}, "
251
+ f"length={self._length}, "
252
+ f"loaded={self._data is not None})"
253
+ )
254
+
255
+ def __len__(self) -> int:
256
+ """Number of samples."""
257
+ return self._length
258
+
259
+
260
+ def load_trace_lazy(
261
+ file_path: str | Path,
262
+ sample_rate: float | None = None,
263
+ *,
264
+ lazy: bool = True,
265
+ **kwargs: Any,
266
+ ) -> LazyWaveformTrace | WaveformTrace:
267
+ """Load trace with optional lazy loading.
268
+
269
+ Loads metadata immediately but defers data loading until first access
270
+ if lazy=True.
271
+
272
+ Args:
273
+ file_path: Path to trace file (must be .npy or raw binary).
274
+ sample_rate: Sample rate in Hz (required for raw files).
275
+ lazy: If True, defer data loading. If False, load immediately.
276
+ **kwargs: Additional arguments (dtype, offset, etc.).
277
+
278
+ Returns:
279
+ LazyWaveformTrace if lazy=True, otherwise WaveformTrace.
280
+
281
+ Raises:
282
+ LoaderError: If file not found or has invalid format.
283
+
284
+ Example:
285
+ >>> # Lazy loading for huge files
286
+ >>> trace = load_trace_lazy('10GB_trace.npy', lazy=True)
287
+ >>> print(f"Duration: {trace.duration} seconds") # No data loaded yet
288
+ >>> data_subset = trace[1000:2000].data # Only loads this slice
289
+ >>>
290
+ >>> # Eager loading
291
+ >>> trace = load_trace_lazy('small_trace.npy', lazy=False)
292
+ >>> data = trace.data # Already loaded
293
+
294
+ References:
295
+ API-017: Lazy Loading for Huge Files
296
+ """
297
+ file_path = Path(file_path)
298
+
299
+ if not file_path.exists():
300
+ raise LoaderError(f"File not found: {file_path}")
301
+
302
+ # Determine format
303
+ suffix = file_path.suffix.lower()
304
+
305
+ if suffix == ".npy":
306
+ # NumPy format - can read shape and dtype without loading data
307
+ with open(file_path, "rb") as f:
308
+ # Read NumPy header
309
+ import numpy.lib.format as npf
310
+
311
+ npf.read_magic(f) # type: ignore[no-untyped-call]
312
+ shape, _fortran_order, dtype = npf.read_array_header_1_0(f) # type: ignore[no-untyped-call]
313
+ offset = f.tell()
314
+
315
+ if not isinstance(shape, tuple) or len(shape) != 1:
316
+ raise LoaderError(f"Expected 1D array, got shape {shape}")
317
+
318
+ length = shape[0]
319
+
320
+ # Get sample rate from metadata or argument
321
+ if sample_rate is None:
322
+ raise LoaderError("sample_rate is required for .npy files")
323
+
324
+ if lazy:
325
+ return LazyWaveformTrace(
326
+ file_path=file_path,
327
+ sample_rate=sample_rate,
328
+ length=length,
329
+ dtype=dtype,
330
+ offset=offset,
331
+ )
332
+ else:
333
+ # Load eagerly
334
+ from oscura.core.types import TraceMetadata, WaveformTrace
335
+
336
+ data = np.load(file_path).astype(np.float64)
337
+ metadata = TraceMetadata(sample_rate=sample_rate)
338
+ return WaveformTrace(data=data, metadata=metadata)
339
+
340
+ else:
341
+ # Raw binary - need sample rate and dtype
342
+ if sample_rate is None:
343
+ raise LoaderError("sample_rate is required for raw binary files")
344
+
345
+ dtype = kwargs.get("dtype", np.float64)
346
+ offset = kwargs.get("offset", 0)
347
+
348
+ # Compute length from file size
349
+ file_size = file_path.stat().st_size - offset
350
+ dtype_size = np.dtype(dtype).itemsize
351
+ length = file_size // dtype_size
352
+
353
+ if lazy:
354
+ return LazyWaveformTrace(
355
+ file_path=file_path,
356
+ sample_rate=sample_rate,
357
+ length=length,
358
+ dtype=dtype,
359
+ offset=offset,
360
+ )
361
+ else:
362
+ # Load eagerly
363
+ from oscura.core.types import TraceMetadata, WaveformTrace
364
+
365
+ data = np.fromfile(file_path, dtype=dtype, count=length, offset=offset)
366
+ metadata = TraceMetadata(sample_rate=sample_rate)
367
+ return WaveformTrace(data=data.astype(np.float64), metadata=metadata)
368
+
369
+
370
+ __all__ = ["LazyWaveformTrace", "load_trace_lazy"]