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,13 @@
1
+ """Workflow execution and DAG-based analysis.
2
+
3
+ This module provides directed acyclic graph (DAG) execution for complex
4
+ multi-step analysis workflows with automatic dependency resolution and
5
+ parallel execution.
6
+ """
7
+
8
+ from oscura.workflow.dag import TaskNode, WorkflowDAG
9
+
10
+ __all__ = [
11
+ "TaskNode",
12
+ "WorkflowDAG",
13
+ ]
oscura/workflow/dag.py ADDED
@@ -0,0 +1,377 @@
1
+ """Directed Acyclic Graph (DAG) execution for complex workflows.
2
+
3
+ This module provides DAG-based workflow execution with automatic dependency
4
+ resolution and parallel execution of independent tasks.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from collections import defaultdict, deque
10
+ from concurrent.futures import ThreadPoolExecutor, as_completed
11
+ from dataclasses import dataclass, field
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ from oscura.core.exceptions import AnalysisError
15
+
16
+ if TYPE_CHECKING:
17
+ from collections.abc import Callable
18
+
19
+
20
+ @dataclass
21
+ class TaskNode:
22
+ """Node in a workflow DAG.
23
+
24
+ Attributes:
25
+ name: Unique task name.
26
+ func: Callable function to execute.
27
+ depends_on: List of task names this task depends on.
28
+ result: Computed result (set after execution).
29
+ completed: Whether task has been executed.
30
+
31
+ Example:
32
+ >>> def compute_fft(state):
33
+ ... return {'fft': np.fft.fft(state['trace'])}
34
+ >>> node = TaskNode(name='fft', func=compute_fft, depends_on=['load'])
35
+
36
+ References:
37
+ API-013: DAG Execution
38
+ """
39
+
40
+ name: str
41
+ func: Callable[[dict[str, Any]], Any]
42
+ depends_on: list[str] = field(default_factory=list)
43
+ result: Any = None
44
+ completed: bool = False
45
+
46
+
47
+ class WorkflowDAG:
48
+ """Directed Acyclic Graph for workflow execution.
49
+
50
+ Manages task dependencies and executes tasks in topological order
51
+ with automatic parallelization of independent tasks.
52
+
53
+ Example:
54
+ >>> from oscura.workflow.dag import WorkflowDAG
55
+ >>> dag = WorkflowDAG()
56
+ >>> dag.add_task('load', load_trace, depends_on=[])
57
+ >>> dag.add_task('fft', compute_fft, depends_on=['load'])
58
+ >>> dag.add_task('rise_time', compute_rise_time, depends_on=['load'])
59
+ >>> dag.add_task('enob', compute_enob, depends_on=['fft', 'rise_time'])
60
+ >>> results = dag.execute()
61
+
62
+ References:
63
+ API-013: DAG Execution for Complex Workflows
64
+ """
65
+
66
+ def __init__(self) -> None:
67
+ """Initialize empty DAG."""
68
+ self.tasks: dict[str, TaskNode] = {}
69
+ self._adjacency: dict[str, list[str]] = defaultdict(list)
70
+
71
+ def add_task(
72
+ self,
73
+ name: str,
74
+ func: Callable[[dict[str, Any]], Any],
75
+ depends_on: list[str] | None = None,
76
+ ) -> None:
77
+ """Add a task to the DAG.
78
+
79
+ Args:
80
+ name: Unique name for the task.
81
+ func: Function to execute. Should accept state dict and return result.
82
+ depends_on: List of task names this task depends on.
83
+
84
+ Raises:
85
+ AnalysisError: If task name already exists or creates a cycle.
86
+
87
+ Example:
88
+ >>> dag.add_task('fft', compute_fft, depends_on=['load'])
89
+
90
+ References:
91
+ API-013: DAG Execution
92
+ """
93
+ if name in self.tasks:
94
+ raise AnalysisError(f"Task '{name}' already exists in DAG")
95
+
96
+ depends_on = depends_on or []
97
+
98
+ # Verify dependencies exist
99
+ for dep in depends_on:
100
+ if dep not in self.tasks:
101
+ raise AnalysisError(f"Dependency '{dep}' not found for task '{name}'")
102
+
103
+ # Create task node
104
+ task = TaskNode(name=name, func=func, depends_on=depends_on)
105
+ self.tasks[name] = task
106
+
107
+ # Update adjacency list
108
+ for dep in depends_on:
109
+ self._adjacency[dep].append(name)
110
+
111
+ # Check for cycles
112
+ if self._has_cycle():
113
+ # Rollback - remove task
114
+ del self.tasks[name]
115
+ for dep in depends_on:
116
+ self._adjacency[dep].remove(name)
117
+ raise AnalysisError(f"Adding task '{name}' would create a cycle in DAG")
118
+
119
+ def _has_cycle(self) -> bool:
120
+ """Check if DAG contains a cycle.
121
+
122
+ Returns:
123
+ True if cycle detected.
124
+ """
125
+ # Use DFS to detect cycles
126
+ visited: set[str] = set()
127
+ rec_stack: set[str] = set()
128
+
129
+ def dfs(node: str) -> bool:
130
+ visited.add(node)
131
+ rec_stack.add(node)
132
+
133
+ for neighbor in self._adjacency.get(node, []):
134
+ if neighbor not in visited:
135
+ if dfs(neighbor):
136
+ return True
137
+ elif neighbor in rec_stack:
138
+ return True
139
+
140
+ rec_stack.remove(node)
141
+ return False
142
+
143
+ return any(task_name not in visited and dfs(task_name) for task_name in self.tasks)
144
+
145
+ def _topological_sort(self) -> list[list[str]]:
146
+ """Compute topological sort grouped by execution level.
147
+
148
+ Tasks at the same level can be executed in parallel.
149
+
150
+ Returns:
151
+ List of levels, where each level is a list of task names.
152
+
153
+ Raises:
154
+ AnalysisError: If DAG contains a cycle or unreachable tasks.
155
+
156
+ Example:
157
+ >>> levels = dag._topological_sort()
158
+ >>> # [[load], [fft, rise_time], [enob]]
159
+ """
160
+ # Compute in-degree for each node
161
+ in_degree = {name: len(task.depends_on) for name, task in self.tasks.items()}
162
+
163
+ # Find nodes with no dependencies (level 0)
164
+ levels: list[list[str]] = []
165
+ queue = deque([name for name, degree in in_degree.items() if degree == 0])
166
+
167
+ while queue:
168
+ # All tasks at this level can run in parallel
169
+ current_level = list(queue)
170
+ levels.append(current_level)
171
+ queue.clear()
172
+
173
+ # Process current level
174
+ for task_name in current_level:
175
+ # Reduce in-degree of dependent tasks
176
+ for dependent in self._adjacency.get(task_name, []):
177
+ in_degree[dependent] -= 1
178
+ if in_degree[dependent] == 0:
179
+ queue.append(dependent)
180
+
181
+ # Verify all tasks were included
182
+ total_tasks = sum(len(level) for level in levels)
183
+ if total_tasks != len(self.tasks):
184
+ raise AnalysisError("DAG contains a cycle or unreachable tasks")
185
+
186
+ return levels
187
+
188
+ def execute(
189
+ self,
190
+ *,
191
+ initial_state: dict[str, Any] | None = None,
192
+ parallel: bool = True,
193
+ max_workers: int | None = None,
194
+ ) -> dict[str, Any]:
195
+ """Execute the workflow DAG.
196
+
197
+ Tasks are executed in topological order with automatic parallelization
198
+ of independent tasks at each level.
199
+
200
+ Args:
201
+ initial_state: Initial state dictionary passed to first tasks.
202
+ parallel: Enable parallel execution of independent tasks.
203
+ max_workers: Maximum number of parallel workers. None uses CPU count.
204
+
205
+ Returns:
206
+ Final state dictionary containing all task results.
207
+
208
+ Example:
209
+ >>> results = dag.execute(initial_state={'trace': trace_data})
210
+ >>> print(results['enob'])
211
+
212
+ References:
213
+ API-013: DAG Execution
214
+ """
215
+ if not self.tasks:
216
+ return initial_state or {}
217
+
218
+ state = initial_state or {}
219
+ levels = self._topological_sort()
220
+
221
+ for level in levels:
222
+ if parallel and len(level) > 1:
223
+ # Execute level in parallel
224
+ self._execute_level_parallel(level, state, max_workers)
225
+ else:
226
+ # Execute level sequentially
227
+ self._execute_level_sequential(level, state)
228
+
229
+ return state
230
+
231
+ def _execute_level_sequential(self, level: list[str], state: dict[str, Any]) -> None:
232
+ """Execute a level of tasks sequentially.
233
+
234
+ Args:
235
+ level: List of task names to execute.
236
+ state: Shared state dictionary.
237
+
238
+ Raises:
239
+ AnalysisError: If task execution fails.
240
+ """
241
+ for task_name in level:
242
+ task = self.tasks[task_name]
243
+ try:
244
+ result = task.func(state)
245
+ task.result = result
246
+ task.completed = True
247
+
248
+ # Update state with result
249
+ if isinstance(result, dict):
250
+ state.update(result)
251
+ else:
252
+ state[task_name] = result
253
+
254
+ except Exception as e:
255
+ raise AnalysisError(f"Task '{task_name}' failed: {e}") from e
256
+
257
+ def _execute_level_parallel(
258
+ self, level: list[str], state: dict[str, Any], max_workers: int | None
259
+ ) -> None:
260
+ """Execute a level of tasks in parallel.
261
+
262
+ Args:
263
+ level: List of task names to execute in parallel.
264
+ state: Shared state dictionary.
265
+ max_workers: Maximum number of workers.
266
+
267
+ Raises:
268
+ AnalysisError: If task execution fails.
269
+ """
270
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
271
+ # Submit all tasks
272
+ future_to_task = {executor.submit(self.tasks[name].func, state): name for name in level}
273
+
274
+ # Collect results
275
+ for future in as_completed(future_to_task):
276
+ task_name = future_to_task[future]
277
+ task = self.tasks[task_name]
278
+
279
+ try:
280
+ result = future.result()
281
+ task.result = result
282
+ task.completed = True
283
+
284
+ # Update state with result
285
+ if isinstance(result, dict):
286
+ state.update(result)
287
+ else:
288
+ state[task_name] = result
289
+
290
+ except Exception as e:
291
+ raise AnalysisError(f"Task '{task_name}' failed: {e}") from e
292
+
293
+ def get_result(self, task_name: str) -> Any:
294
+ """Get result from a completed task.
295
+
296
+ Args:
297
+ task_name: Name of the task.
298
+
299
+ Returns:
300
+ Task result.
301
+
302
+ Raises:
303
+ AnalysisError: If task doesn't exist or hasn't been executed.
304
+
305
+ Example:
306
+ >>> fft_result = dag.get_result('fft')
307
+ """
308
+ if task_name not in self.tasks:
309
+ raise AnalysisError(f"Task '{task_name}' not found in DAG")
310
+
311
+ task = self.tasks[task_name]
312
+ if not task.completed:
313
+ raise AnalysisError(f"Task '{task_name}' has not been executed yet")
314
+
315
+ return task.result
316
+
317
+ def reset(self) -> None:
318
+ """Reset all task completion states.
319
+
320
+ Allows re-execution of the DAG with different initial state.
321
+
322
+ Example:
323
+ >>> dag.reset()
324
+ >>> results = dag.execute(initial_state={'trace': new_trace})
325
+ """
326
+ for task in self.tasks.values():
327
+ task.completed = False
328
+ task.result = None
329
+
330
+ def to_graphviz(self) -> str:
331
+ """Generate Graphviz DOT representation of the DAG.
332
+
333
+ Returns:
334
+ DOT format string for visualization.
335
+
336
+ Example:
337
+ >>> dot = dag.to_graphviz()
338
+ >>> with open('workflow.dot', 'w') as f:
339
+ ... f.write(dot)
340
+ >>> # Then: dot -Tpng workflow.dot -o workflow.png
341
+
342
+ References:
343
+ API-013: DAG Execution
344
+ """
345
+ lines = ["digraph WorkflowDAG {", " rankdir=LR;", " node [shape=box];", ""]
346
+
347
+ # Add nodes
348
+ for task_name, task in self.tasks.items():
349
+ style = "filled,bold" if task.completed else "filled"
350
+ color = "lightgreen" if task.completed else "lightblue"
351
+ lines.append(f' "{task_name}" [style="{style}", fillcolor="{color}"];')
352
+
353
+ lines.append("")
354
+
355
+ # Add edges
356
+ for task_name, task in self.tasks.items():
357
+ for dep in task.depends_on:
358
+ lines.append(f' "{dep}" -> "{task_name}";')
359
+
360
+ lines.append("}")
361
+ return "\n".join(lines)
362
+
363
+ def __repr__(self) -> str:
364
+ """String representation of DAG."""
365
+ return f"WorkflowDAG(tasks={len(self.tasks)})"
366
+
367
+ def __str__(self) -> str:
368
+ """Detailed string representation."""
369
+ lines = [f"WorkflowDAG with {len(self.tasks)} tasks:"]
370
+ for task_name, task in self.tasks.items():
371
+ deps = ", ".join(task.depends_on) if task.depends_on else "none"
372
+ status = "✓" if task.completed else "○"
373
+ lines.append(f" {status} {task_name} (depends on: {deps})")
374
+ return "\n".join(lines)
375
+
376
+
377
+ __all__ = ["TaskNode", "WorkflowDAG"]
@@ -0,0 +1,58 @@
1
+ """High-level workflow presets for TraceKit.
2
+
3
+ This module provides one-call analysis workflows for common signal
4
+ characterization tasks.
5
+
6
+ Example:
7
+ >>> import oscura as tk
8
+ >>> # Reverse engineer unknown signal
9
+ >>> result = tk.workflows.reverse_engineer_signal(trace)
10
+ >>> print(result.protocol_spec)
11
+ >>>
12
+ >>> # EMC compliance testing
13
+ >>> results = tk.workflows.emc_compliance_test(trace)
14
+ >>>
15
+ >>> # Multi-trace analysis
16
+ >>> stats = tk.workflows.load_all(["trace1.wfm", "trace2.wfm"])
17
+ """
18
+
19
+ from oscura.workflows.compliance import emc_compliance_test
20
+ from oscura.workflows.digital import characterize_buffer
21
+ from oscura.workflows.multi_trace import (
22
+ AlignmentMethod,
23
+ MultiTraceResults,
24
+ MultiTraceWorkflow,
25
+ TraceStatistics,
26
+ load_all,
27
+ )
28
+ from oscura.workflows.power import power_analysis
29
+ from oscura.workflows.protocol import debug_protocol
30
+ from oscura.workflows.reverse_engineering import (
31
+ FieldSpec,
32
+ InferredFrame,
33
+ ProtocolSpec,
34
+ ReverseEngineeringResult,
35
+ reverse_engineer_signal,
36
+ )
37
+ from oscura.workflows.signal_integrity import signal_integrity_audit
38
+
39
+ __all__ = [
40
+ # Multi-trace
41
+ "AlignmentMethod",
42
+ # Reverse engineering
43
+ "FieldSpec",
44
+ "InferredFrame",
45
+ "MultiTraceResults",
46
+ "MultiTraceWorkflow",
47
+ "ProtocolSpec",
48
+ "ReverseEngineeringResult",
49
+ "TraceStatistics",
50
+ # Domain workflows
51
+ "characterize_buffer",
52
+ "debug_protocol",
53
+ "emc_compliance_test",
54
+ "load_all",
55
+ "power_analysis",
56
+ "reverse_engineer_signal",
57
+ "signal_integrity_audit",
58
+ ]