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
@@ -0,0 +1,448 @@
1
+ """Comprehensive analysis report system main entry point.
2
+
3
+ This module provides the primary `analyze()` function for running
4
+ comprehensive analysis on any supported input data type.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import time
11
+ from collections.abc import Callable
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+ from typing import TYPE_CHECKING, Any
15
+
16
+ from oscura.reporting.config import (
17
+ AnalysisConfig,
18
+ AnalysisDomain,
19
+ AnalysisError,
20
+ AnalysisResult,
21
+ InputType,
22
+ ProgressInfo,
23
+ get_available_analyses,
24
+ )
25
+ from oscura.reporting.output import OutputManager
26
+
27
+ if TYPE_CHECKING:
28
+ from oscura.core.types import Trace
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ class UnsupportedFormatError(Exception):
34
+ """Raised when input file format is not recognized."""
35
+
36
+
37
+ def analyze(
38
+ input_path: str | Path | None = None,
39
+ data: Trace | bytes | list[Any] | None = None,
40
+ *,
41
+ output_dir: str | Path | None = None,
42
+ config: AnalysisConfig | None = None,
43
+ progress_callback: Callable[[ProgressInfo], None] | None = None,
44
+ ) -> AnalysisResult:
45
+ """Run comprehensive analysis on data.
46
+
47
+ Provide EITHER input_path (file) OR data (in-memory), not both.
48
+
49
+ Args:
50
+ input_path: Path to input data file (any supported format).
51
+ data: In-memory data (Trace, bytes, list of packets).
52
+ output_dir: Base directory for output. Default: input file's directory
53
+ or current directory for in-memory data.
54
+ config: Analysis configuration. Default: analyze all applicable domains.
55
+ progress_callback: Called with progress updates during analysis.
56
+
57
+ Returns:
58
+ AnalysisResult with paths to all outputs and summary statistics.
59
+
60
+ Raises:
61
+ FileNotFoundError: If the input file does not exist.
62
+ ValueError: If neither or both input_path and data are provided.
63
+
64
+ Examples:
65
+ # From file
66
+ result = analyze("capture.wfm")
67
+ print(result.output_dir) # 20260101_120000_capture_analysis/
68
+
69
+ # From in-memory data
70
+ result = analyze(data=my_waveform_trace, output_dir="/reports")
71
+
72
+ # With configuration
73
+ config = AnalysisConfig(domains=[AnalysisDomain.SPECTRAL])
74
+ result = analyze("capture.wfm", config=config)
75
+
76
+ # With progress callback
77
+ def on_progress(info):
78
+ print(f"{info.domain}: {info.percent}%")
79
+ result = analyze("capture.wfm", progress_callback=on_progress)
80
+ """
81
+ # Validate inputs
82
+ if input_path is None and data is None:
83
+ raise ValueError("Either input_path or data must be provided")
84
+ if input_path is not None and data is not None:
85
+ raise ValueError("Provide input_path OR data, not both")
86
+
87
+ # Use default config if not provided
88
+ if config is None:
89
+ config = AnalysisConfig()
90
+
91
+ # Track timing
92
+ start_time = time.time()
93
+
94
+ # Determine input name and type
95
+ if input_path is not None:
96
+ input_path = Path(input_path)
97
+ if not input_path.exists():
98
+ raise FileNotFoundError(f"Input file not found: {input_path}")
99
+ input_name = input_path.stem
100
+ input_type = _detect_input_type_from_file(input_path)
101
+ loaded_data = _load_input_file(input_path, input_type)
102
+ else:
103
+ input_name = "memory_data"
104
+ input_type = _detect_input_type_from_data(data)
105
+ loaded_data = data
106
+
107
+ # Determine output directory
108
+ if output_dir is None:
109
+ if input_path is not None:
110
+ base_dir = input_path.parent
111
+ else:
112
+ base_dir = Path.cwd()
113
+ else:
114
+ base_dir = Path(output_dir)
115
+
116
+ # Create output manager with timestamp
117
+ timestamp = datetime.now()
118
+ output_manager = OutputManager(base_dir, input_name, timestamp)
119
+ output_manager.create()
120
+
121
+ # Report progress: starting
122
+ _report_progress(
123
+ progress_callback,
124
+ phase="initializing",
125
+ domain=None,
126
+ function=None,
127
+ percent=0.0,
128
+ message="Initializing analysis",
129
+ elapsed=time.time() - start_time,
130
+ )
131
+
132
+ # Determine applicable domains
133
+ applicable_domains = get_available_analyses(input_type)
134
+ enabled_domains = [d for d in applicable_domains if config.is_domain_enabled(d)]
135
+
136
+ logger.info(f"Running analysis on {input_name} ({input_type.value})")
137
+ logger.info(f"Enabled domains: {[d.value for d in enabled_domains]}")
138
+
139
+ # Execute analysis engine
140
+ from oscura.reporting.engine import AnalysisEngine
141
+
142
+ engine = AnalysisEngine(config)
143
+ engine_result = engine.run(
144
+ input_path=input_path,
145
+ data=loaded_data,
146
+ progress_callback=progress_callback,
147
+ )
148
+
149
+ # Generate plots
150
+ plot_paths: list[Path] = []
151
+ if config.generate_plots:
152
+ _report_progress(
153
+ progress_callback,
154
+ phase="plotting",
155
+ domain=None,
156
+ function=None,
157
+ percent=70.0,
158
+ message="Generating visualizations",
159
+ elapsed=time.time() - start_time,
160
+ )
161
+
162
+ from oscura.reporting.plots import PlotGenerator
163
+
164
+ plot_gen = PlotGenerator(config)
165
+ for domain, results in engine_result["results"].items():
166
+ domain_plots = plot_gen.generate_plots(domain, results, output_manager)
167
+ plot_paths.extend(domain_plots)
168
+
169
+ # Save data outputs
170
+ _report_progress(
171
+ progress_callback,
172
+ phase="saving",
173
+ domain=None,
174
+ function=None,
175
+ percent=85.0,
176
+ message="Saving analysis results",
177
+ elapsed=time.time() - start_time,
178
+ )
179
+
180
+ # Save summary data
181
+ summary_data = {
182
+ "input": {
183
+ "name": input_name,
184
+ "type": input_type.value,
185
+ "path": str(input_path) if input_path else None,
186
+ },
187
+ "timestamp": timestamp.isoformat(),
188
+ "duration_seconds": time.time() - start_time,
189
+ "stats": engine_result["stats"],
190
+ "domains": {d.value: r for d, r in engine_result["results"].items()},
191
+ }
192
+
193
+ summary_json = output_manager.save_json("summary", summary_data)
194
+ summary_yaml = None
195
+ if "yaml" in config.output_formats:
196
+ summary_yaml = output_manager.save_yaml("summary", summary_data)
197
+
198
+ # Save metadata
199
+ metadata = {
200
+ "oscura_version": _get_version(),
201
+ "analysis_version": "2.0",
202
+ "timestamp": timestamp.isoformat(),
203
+ "input_file": str(input_path) if input_path else None,
204
+ "input_type": input_type.value,
205
+ "duration_seconds": time.time() - start_time,
206
+ "total_analyses": engine_result["stats"]["total_analyses"],
207
+ "successful": engine_result["stats"]["successful_analyses"],
208
+ "failed": engine_result["stats"]["failed_analyses"],
209
+ "skipped": engine_result["stats"].get("skipped_analyses", 0),
210
+ }
211
+ metadata_json = output_manager.save_json("metadata", metadata)
212
+
213
+ # Save configuration
214
+ config_data = {
215
+ "domains": [d.value for d in enabled_domains],
216
+ "generate_plots": config.generate_plots,
217
+ "plot_format": config.plot_format,
218
+ "plot_dpi": config.plot_dpi,
219
+ "output_formats": config.output_formats,
220
+ "index_formats": config.index_formats,
221
+ }
222
+ config_yaml = output_manager.save_yaml("config", config_data)
223
+
224
+ # Save domain results
225
+ domain_dirs: dict[AnalysisDomain, Path] = {}
226
+ for domain, results in engine_result["results"].items():
227
+ domain_dir = output_manager.create_domain_dir(domain)
228
+ domain_dirs[domain] = domain_dir
229
+ output_manager.save_json("results", results, subdir=domain.value)
230
+
231
+ # Save errors if any
232
+ error_log: Path | None = None
233
+ errors: list[AnalysisError] = engine_result["errors"]
234
+ if errors:
235
+ error_list = [
236
+ {
237
+ "domain": e.domain.value,
238
+ "function": e.function,
239
+ "error_type": e.error_type,
240
+ "error_message": e.error_message,
241
+ "duration_ms": e.duration_ms,
242
+ }
243
+ for e in errors
244
+ ]
245
+ error_data = {"errors": error_list, "count": len(error_list)}
246
+ error_log = output_manager.save_json("failed_analyses", error_data, subdir="errors")
247
+
248
+ # Build AnalysisResult for index generation
249
+ partial_result = AnalysisResult(
250
+ output_dir=output_manager.root,
251
+ index_html=None,
252
+ index_md=None,
253
+ index_pdf=None,
254
+ summary_json=summary_json,
255
+ summary_yaml=summary_yaml,
256
+ metadata_json=metadata_json,
257
+ config_yaml=config_yaml,
258
+ domain_dirs=domain_dirs,
259
+ plot_paths=plot_paths,
260
+ error_log=error_log,
261
+ input_file=str(input_path) if input_path else None,
262
+ input_type=input_type,
263
+ total_analyses=engine_result["stats"]["total_analyses"],
264
+ successful_analyses=engine_result["stats"]["successful_analyses"],
265
+ failed_analyses=engine_result["stats"]["failed_analyses"],
266
+ skipped_analyses=engine_result["stats"].get("skipped_analyses", 0),
267
+ duration_seconds=time.time() - start_time,
268
+ domain_summaries=engine_result["results"],
269
+ errors=errors,
270
+ )
271
+
272
+ # Generate index files
273
+ _report_progress(
274
+ progress_callback,
275
+ phase="indexing",
276
+ domain=None,
277
+ function=None,
278
+ percent=95.0,
279
+ message="Generating index files",
280
+ elapsed=time.time() - start_time,
281
+ )
282
+
283
+ from oscura.reporting.index import IndexGenerator
284
+
285
+ index_gen = IndexGenerator(output_manager)
286
+ index_paths = index_gen.generate(partial_result, config.index_formats)
287
+
288
+ # Complete result
289
+ result = AnalysisResult(
290
+ output_dir=output_manager.root,
291
+ index_html=index_paths.get("html"),
292
+ index_md=index_paths.get("md"),
293
+ index_pdf=index_paths.get("pdf"),
294
+ summary_json=summary_json,
295
+ summary_yaml=summary_yaml,
296
+ metadata_json=metadata_json,
297
+ config_yaml=config_yaml,
298
+ domain_dirs=domain_dirs,
299
+ plot_paths=plot_paths,
300
+ error_log=error_log,
301
+ input_file=str(input_path) if input_path else None,
302
+ input_type=input_type,
303
+ total_analyses=engine_result["stats"]["total_analyses"],
304
+ successful_analyses=engine_result["stats"]["successful_analyses"],
305
+ failed_analyses=engine_result["stats"]["failed_analyses"],
306
+ skipped_analyses=engine_result["stats"].get("skipped_analyses", 0),
307
+ duration_seconds=time.time() - start_time,
308
+ domain_summaries=engine_result["results"],
309
+ errors=errors,
310
+ )
311
+
312
+ # Report completion
313
+ _report_progress(
314
+ progress_callback,
315
+ phase="complete",
316
+ domain=None,
317
+ function=None,
318
+ percent=100.0,
319
+ message=f"Analysis complete: {result.successful_analyses}/{result.total_analyses} successful",
320
+ elapsed=time.time() - start_time,
321
+ )
322
+
323
+ logger.info(f"Analysis complete. Output: {result.output_dir}")
324
+ return result
325
+
326
+
327
+ def _detect_input_type_from_file(path: Path) -> InputType:
328
+ """Detect input type from file extension."""
329
+ suffix = path.suffix.lower()
330
+
331
+ waveform_extensions = {".wfm", ".csv", ".npz", ".hdf5", ".h5", ".wav", ".tdms"}
332
+ digital_extensions = {".vcd", ".sr"}
333
+ binary_extensions = {".bin", ".raw"}
334
+ pcap_extensions = {".pcap", ".pcapng"}
335
+ sparams_extensions = {".s1p", ".s2p", ".s3p", ".s4p", ".s5p", ".s6p", ".s7p", ".s8p"}
336
+
337
+ if suffix in waveform_extensions:
338
+ return InputType.WAVEFORM
339
+ elif suffix in digital_extensions:
340
+ return InputType.DIGITAL
341
+ elif suffix in binary_extensions:
342
+ return InputType.BINARY
343
+ elif suffix in pcap_extensions:
344
+ return InputType.PCAP
345
+ elif suffix in sparams_extensions:
346
+ return InputType.SPARAMS
347
+ else:
348
+ raise UnsupportedFormatError(f"Unsupported file format: {suffix}")
349
+
350
+
351
+ def _detect_input_type_from_data(data: Any) -> InputType:
352
+ """Detect input type from in-memory data."""
353
+ # Check for Trace object (time + voltage = waveform)
354
+ # Check this BEFORE SParameterData to avoid MagicMock false positives
355
+ if hasattr(data, "time") and hasattr(data, "voltage"):
356
+ # Verify these are not just mock/placeholder attributes
357
+ try:
358
+ _ = data.time
359
+ _ = data.voltage
360
+ return InputType.WAVEFORM
361
+ except (AttributeError, TypeError):
362
+ pass
363
+
364
+ # Check for SParameterData
365
+ if hasattr(data, "s_matrix") and hasattr(data, "frequencies"):
366
+ return InputType.SPARAMS
367
+
368
+ # Check for bytes
369
+ if isinstance(data, bytes | bytearray):
370
+ return InputType.BINARY
371
+
372
+ # Check for list of packets
373
+ if isinstance(data, list) and len(data) > 0:
374
+ first = data[0]
375
+ if hasattr(first, "timestamp") or isinstance(first, dict):
376
+ return InputType.PACKETS
377
+
378
+ # Default to waveform
379
+ return InputType.WAVEFORM
380
+
381
+
382
+ def _load_input_file(path: Path, input_type: InputType) -> Any:
383
+ """Load input file based on type."""
384
+ try:
385
+ from oscura.loaders import load
386
+
387
+ if input_type == InputType.WAVEFORM:
388
+ return load(path)
389
+ elif input_type == InputType.DIGITAL:
390
+ # Use VCD/SR loader
391
+ from oscura.loaders.vcd import load_vcd
392
+
393
+ return load_vcd(path)
394
+ elif input_type == InputType.BINARY:
395
+ return path.read_bytes()
396
+ elif input_type == InputType.PCAP:
397
+ from oscura.loaders.pcap import load_pcap
398
+
399
+ return load_pcap(path)
400
+ elif input_type == InputType.SPARAMS:
401
+ from oscura.analyzers.signal_integrity.sparams import load_touchstone
402
+
403
+ return load_touchstone(path)
404
+ else:
405
+ return load(path)
406
+ except ImportError as e:
407
+ logger.warning(f"Loader not available: {e}")
408
+ # Fall back to raw bytes
409
+ return path.read_bytes()
410
+
411
+
412
+ def _report_progress(
413
+ callback: Callable[[ProgressInfo], None] | None,
414
+ phase: str,
415
+ domain: AnalysisDomain | None,
416
+ function: str | None,
417
+ percent: float,
418
+ message: str,
419
+ elapsed: float,
420
+ ) -> None:
421
+ """Report progress to callback if provided."""
422
+ if callback is not None:
423
+ info = ProgressInfo(
424
+ phase=phase,
425
+ domain=domain,
426
+ function=function,
427
+ percent=percent,
428
+ message=message,
429
+ elapsed_seconds=elapsed,
430
+ estimated_remaining_seconds=None,
431
+ )
432
+ callback(info)
433
+
434
+
435
+ def _get_version() -> str:
436
+ """Get TraceKit version."""
437
+ try:
438
+ from oscura import __version__
439
+
440
+ return __version__
441
+ except ImportError:
442
+ return "unknown"
443
+
444
+
445
+ __all__ = [
446
+ "UnsupportedFormatError",
447
+ "analyze",
448
+ ]