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,439 @@
1
+ """Enhanced cancellation support for TraceKit operations.
2
+
3
+ This module provides advanced cancellation features including signal handling,
4
+ cleanup routines, and resume support for long-running operations.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.core.cancellation import CancellationManager
9
+ >>> manager = CancellationManager()
10
+ >>> with manager.cancellable_operation("Loading data"):
11
+ ... # ... long operation ...
12
+ ... manager.check_cancelled()
13
+
14
+ References:
15
+ - Python threading best practices
16
+ - Signal handling patterns
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import atexit
22
+ import signal
23
+ import threading
24
+ import time
25
+ from contextlib import contextmanager
26
+ from typing import TYPE_CHECKING, Any
27
+
28
+ if TYPE_CHECKING:
29
+ from collections.abc import Callable, Generator
30
+
31
+
32
+ class CancellationManager:
33
+ """Manager for cancellable operations with cleanup support.
34
+
35
+ : Ctrl+C handling, cleanup, and resume support.
36
+ Provides graceful cancellation with automatic cleanup and signal handling.
37
+
38
+ Args:
39
+ cleanup_callback: Optional callback for cleanup on cancellation
40
+ auto_cleanup: Automatically cleanup on exit (default: True)
41
+
42
+ Example:
43
+ >>> from oscura.core.cancellation import CancellationManager
44
+ >>> def cleanup():
45
+ ... print("Cleaning up...")
46
+ >>> manager = CancellationManager(cleanup_callback=cleanup)
47
+ >>> manager.register_signal_handlers()
48
+ >>> # Press Ctrl+C to trigger cancellation
49
+
50
+ References:
51
+ PROG-002: Cancellation Support
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ *,
57
+ cleanup_callback: Callable[[], None] | None = None,
58
+ auto_cleanup: bool = True,
59
+ ) -> None:
60
+ """Initialize cancellation manager.
61
+
62
+ Args:
63
+ cleanup_callback: Function to call on cancellation
64
+ auto_cleanup: Register cleanup at exit
65
+ """
66
+ self._cancelled = threading.Event()
67
+ self._cleanup_callback = cleanup_callback
68
+ self._cleanup_functions: list[Callable[[], None]] = []
69
+ self._partial_results: dict[str, Any] = {}
70
+ self._operation_name = ""
71
+ self._start_time = 0.0
72
+ self._signal_handlers_registered = False
73
+
74
+ if auto_cleanup:
75
+ atexit.register(self._cleanup)
76
+
77
+ def register_signal_handlers(self) -> None:
78
+ """Register signal handlers for Ctrl+C and SIGTERM.
79
+
80
+ : Ctrl+C handling - graceful cancellation.
81
+ Catches interrupt signals and triggers cancellation.
82
+
83
+ Example:
84
+ >>> manager.register_signal_handlers()
85
+ >>> # Now Ctrl+C will trigger cancellation
86
+
87
+ References:
88
+ PROG-002: Ctrl+C handling
89
+ """
90
+ if self._signal_handlers_registered:
91
+ return
92
+
93
+ def signal_handler(signum: int, frame: Any) -> None:
94
+ self.cancel(f"Received signal {signum}")
95
+
96
+ signal.signal(signal.SIGINT, signal_handler)
97
+ signal.signal(signal.SIGTERM, signal_handler)
98
+ self._signal_handlers_registered = True
99
+
100
+ def cancel(self, reason: str = "Operation cancelled") -> None:
101
+ """Request cancellation of the operation.
102
+
103
+ : cancel() method on operation handles.
104
+
105
+ Args:
106
+ reason: Reason for cancellation
107
+
108
+ Example:
109
+ >>> manager.cancel("User requested stop")
110
+
111
+ References:
112
+ PROG-002: cancel() method on operation handles
113
+ """
114
+ self._cancelled.set()
115
+ self._operation_name = reason
116
+
117
+ def is_cancelled(self) -> bool:
118
+ """Check if cancellation has been requested.
119
+
120
+ Returns:
121
+ True if operation should be cancelled
122
+
123
+ Example:
124
+ >>> if manager.is_cancelled():
125
+ ... return # Exit early
126
+
127
+ References:
128
+ PROG-002: Cancellation Support
129
+ """
130
+ return self._cancelled.is_set()
131
+
132
+ def check_cancelled(self) -> None:
133
+ """Check cancellation status and raise if cancelled.
134
+
135
+ : Graceful cancellation with partial results.
136
+
137
+ Raises:
138
+ CancelledException: If cancellation has been requested
139
+
140
+ Example:
141
+ >>> manager.check_cancelled() # Raises if cancelled
142
+
143
+ References:
144
+ PROG-002: Cancellation Support
145
+ """
146
+ if self._cancelled.is_set():
147
+ self._cleanup()
148
+ elapsed = time.time() - self._start_time if self._start_time > 0 else 0
149
+ raise CancelledException(
150
+ self._operation_name,
151
+ partial_results=self._partial_results,
152
+ elapsed_time=elapsed,
153
+ )
154
+
155
+ def add_cleanup(self, cleanup_fn: Callable[[], None]) -> None:
156
+ """Add a cleanup function to be called on cancellation.
157
+
158
+ : Cleanup on cancellation - no partial files.
159
+
160
+ Args:
161
+ cleanup_fn: Function to call for cleanup
162
+
163
+ Example:
164
+ >>> def cleanup_temp_files():
165
+ ... os.remove("temp.dat")
166
+ >>> manager.add_cleanup(cleanup_temp_files)
167
+
168
+ References:
169
+ PROG-002: Cleanup on cancellation
170
+ """
171
+ self._cleanup_functions.append(cleanup_fn)
172
+
173
+ def store_partial_result(self, key: str, value: Any) -> None:
174
+ """Store partial result for retrieval after cancellation.
175
+
176
+ : Partial results available after cancellation.
177
+
178
+ Args:
179
+ key: Result identifier
180
+ value: Partial result value
181
+
182
+ Example:
183
+ >>> manager.store_partial_result("samples_processed", 1000)
184
+
185
+ References:
186
+ PROG-002: Partial results available after cancellation
187
+ """
188
+ self._partial_results[key] = value
189
+
190
+ def get_partial_results(self) -> dict[str, Any]:
191
+ """Get partial results collected before cancellation.
192
+
193
+ Returns:
194
+ Dictionary of partial results
195
+
196
+ Example:
197
+ >>> try:
198
+ ... # ... operation ...
199
+ ... except CancelledException as e:
200
+ ... results = manager.get_partial_results()
201
+
202
+ References:
203
+ PROG-002: Partial results available after cancellation
204
+ """
205
+ return self._partial_results.copy()
206
+
207
+ def _cleanup(self) -> None:
208
+ """Execute all registered cleanup functions.
209
+
210
+ References:
211
+ PROG-002: Cleanup on cancellation
212
+ """
213
+ # Call user-provided cleanup
214
+ if self._cleanup_callback is not None:
215
+ try:
216
+ self._cleanup_callback()
217
+ except Exception:
218
+ pass # Ignore cleanup errors
219
+
220
+ # Call registered cleanup functions
221
+ for cleanup_fn in self._cleanup_functions:
222
+ try:
223
+ cleanup_fn()
224
+ except Exception:
225
+ pass # Ignore cleanup errors
226
+
227
+ @contextmanager
228
+ def cancellable_operation(
229
+ self,
230
+ name: str = "Operation",
231
+ ) -> Generator[CancellationManager, None, None]:
232
+ """Context manager for cancellable operations.
233
+
234
+ : Graceful cancellation with cleanup.
235
+
236
+ Args:
237
+ name: Operation name for logging
238
+
239
+ Yields:
240
+ CancellationManager instance
241
+
242
+ Raises:
243
+ CancelledException: If operation is cancelled or interrupted.
244
+
245
+ Example:
246
+ >>> with manager.cancellable_operation("Loading data") as ctx:
247
+ ... for i in range(1000):
248
+ ... ctx.check_cancelled()
249
+ ... # ... process ...
250
+
251
+ References:
252
+ PROG-002: Cancellation Support
253
+ """
254
+ self._operation_name = name
255
+ self._start_time = time.time()
256
+ try:
257
+ yield self
258
+ except CancelledException:
259
+ raise
260
+ except KeyboardInterrupt:
261
+ self.cancel("Interrupted by user (Ctrl+C)")
262
+ self._cleanup()
263
+ raise CancelledException( # noqa: B904
264
+ f"{name} interrupted by user",
265
+ partial_results=self._partial_results,
266
+ elapsed_time=time.time() - self._start_time,
267
+ )
268
+ finally:
269
+ if self._cancelled.is_set():
270
+ self._cleanup()
271
+
272
+
273
+ class CancelledException(Exception):
274
+ """Exception raised when operation is cancelled.
275
+
276
+ : Partial results available after cancellation.
277
+
278
+ Attributes:
279
+ message: Cancellation message
280
+ partial_results: Results collected before cancellation
281
+ elapsed_time: Time elapsed before cancellation
282
+
283
+ Example:
284
+ >>> try:
285
+ ... manager.check_cancelled()
286
+ ... except CancelledException as e:
287
+ ... print(f"Cancelled after {e.elapsed_time:.1f}s")
288
+ ... print(f"Partial results: {e.partial_results}")
289
+
290
+ References:
291
+ PROG-002: Partial results available after cancellation
292
+ """
293
+
294
+ def __init__(
295
+ self,
296
+ message: str,
297
+ *,
298
+ partial_results: dict[str, Any] | None = None,
299
+ elapsed_time: float = 0.0,
300
+ ) -> None:
301
+ """Initialize CancelledException.
302
+
303
+ Args:
304
+ message: Cancellation message
305
+ partial_results: Partial results dictionary
306
+ elapsed_time: Elapsed time in seconds
307
+ """
308
+ self.message = message
309
+ self.partial_results = partial_results or {}
310
+ self.elapsed_time = elapsed_time
311
+ super().__init__(
312
+ f"{message} (elapsed: {elapsed_time:.1f}s, "
313
+ f"partial results: {len(self.partial_results)} items)"
314
+ )
315
+
316
+
317
+ class ResumableOperation:
318
+ """Support for resumable operations after cancellation.
319
+
320
+ : Resume support where possible.
321
+
322
+ Args:
323
+ checkpoint_callback: Function to save checkpoint state
324
+ restore_callback: Function to restore from checkpoint
325
+
326
+ Example:
327
+ >>> def save_state(state):
328
+ ... with open("checkpoint.json", "w") as f:
329
+ ... json.dump(state, f)
330
+ >>> def load_state():
331
+ ... with open("checkpoint.json") as f:
332
+ ... return json.load(f)
333
+ >>> op = ResumableOperation(save_state, load_state)
334
+
335
+ References:
336
+ PROG-002: Resume support where possible
337
+ """
338
+
339
+ def __init__(
340
+ self,
341
+ checkpoint_callback: Callable[[dict], None], # type: ignore[type-arg]
342
+ restore_callback: Callable[[], dict], # type: ignore[type-arg]
343
+ ) -> None:
344
+ """Initialize resumable operation.
345
+
346
+ Args:
347
+ checkpoint_callback: Function to save state
348
+ restore_callback: Function to restore state
349
+ """
350
+ self._checkpoint_callback = checkpoint_callback
351
+ self._restore_callback = restore_callback
352
+ self._state: dict[str, Any] = {}
353
+
354
+ def checkpoint(self, state: dict[str, Any]) -> None:
355
+ """Save operation state for resume.
356
+
357
+ Args:
358
+ state: Current operation state
359
+
360
+ Example:
361
+ >>> op.checkpoint({"processed": 500, "total": 1000})
362
+
363
+ References:
364
+ PROG-002: Resume support
365
+ """
366
+ self._state = state
367
+ self._checkpoint_callback(state)
368
+
369
+ def restore(self) -> dict[str, Any]:
370
+ """Restore operation state from checkpoint.
371
+
372
+ Returns:
373
+ Restored state dictionary
374
+
375
+ Example:
376
+ >>> state = op.restore()
377
+ >>> start_index = state.get("processed", 0)
378
+
379
+ References:
380
+ PROG-002: Resume support
381
+ """
382
+ self._state = self._restore_callback()
383
+ return self._state
384
+
385
+ def has_checkpoint(self) -> bool:
386
+ """Check if checkpoint exists.
387
+
388
+ Returns:
389
+ True if checkpoint is available
390
+
391
+ References:
392
+ PROG-002: Resume support
393
+ """
394
+ try:
395
+ self._restore_callback()
396
+ return True
397
+ except Exception:
398
+ return False
399
+
400
+
401
+ def confirm_cancellation(
402
+ operation_name: str = "operation",
403
+ *,
404
+ destructive: bool = False,
405
+ ) -> bool:
406
+ """Confirm cancellation for destructive operations.
407
+
408
+ : Cancel confirmation for destructive operations.
409
+
410
+ Args:
411
+ operation_name: Name of operation to cancel
412
+ destructive: Whether operation is destructive
413
+
414
+ Returns:
415
+ True if user confirms cancellation
416
+
417
+ Example:
418
+ >>> if confirm_cancellation("Delete files", destructive=True):
419
+ ... # Proceed with cancellation
420
+
421
+ References:
422
+ PROG-002: Cancel confirmation for destructive operations
423
+ """
424
+ if not destructive:
425
+ return True
426
+
427
+ try:
428
+ response = input(f"Cancel {operation_name}? This may lose data. [y/N]: ").strip().lower()
429
+ return response in ("y", "yes")
430
+ except (EOFError, KeyboardInterrupt):
431
+ return True # Assume yes on Ctrl+C during prompt
432
+
433
+
434
+ __all__ = [
435
+ "CancellationManager",
436
+ "CancelledException",
437
+ "ResumableOperation",
438
+ "confirm_cancellation",
439
+ ]
@@ -0,0 +1,225 @@
1
+ """Universal confidence scoring for auto-detection.
2
+
3
+ This module provides confidence scoring infrastructure used across
4
+ all auto-discovery and analysis functions.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.core.confidence import ConfidenceScore
9
+ >>> score = ConfidenceScore(value=0.85, factors={'signal_quality': 0.9, 'pattern_match': 0.8})
10
+ >>> print(f"Confidence: {score.value:.2f} ({score.interpretation})")
11
+ Confidence: 0.85 (likely)
12
+
13
+ References:
14
+ TraceKit Auto-Discovery Specification
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from dataclasses import dataclass, field
20
+ from typing import Any
21
+
22
+
23
+ @dataclass
24
+ class ConfidenceScore:
25
+ """Confidence score for auto-detection results.
26
+
27
+ Represents reliability of automated analysis results with
28
+ standardized 0.0-1.0 scale and human-readable interpretation.
29
+
30
+ Confidence scale:
31
+ - 0.9-1.0: High - "almost certain", trust the result
32
+ - 0.7-0.9: Medium - "likely", verify if critical
33
+ - 0.5-0.7: Low - "possible", check alternatives
34
+ - 0.0-0.5: Unreliable - "uncertain", manual analysis recommended
35
+
36
+ Attributes:
37
+ value: Confidence value (0.0-1.0, 2 decimal precision).
38
+ factors: Dictionary of contributing factors and their scores.
39
+ explanation: Optional explanation of confidence calculation.
40
+
41
+ Example:
42
+ >>> score = ConfidenceScore(0.92, factors={'snr': 0.95, 'timing': 0.89})
43
+ >>> print(f"{score.value:.2f} - {score.interpretation}")
44
+ 0.92 - almost certain
45
+ """
46
+
47
+ value: float
48
+ factors: dict[str, float] = field(default_factory=dict)
49
+ explanation: str | None = None
50
+
51
+ def __post_init__(self) -> None:
52
+ """Validate confidence score after initialization."""
53
+ if not 0.0 <= self.value <= 1.0:
54
+ raise ValueError(f"Confidence value must be in [0.0, 1.0], got {self.value}")
55
+ # Round to 2 decimal places
56
+ self.value = round(self.value, 2)
57
+
58
+ # Validate factors
59
+ for name, factor_value in self.factors.items():
60
+ if not 0.0 <= factor_value <= 1.0:
61
+ raise ValueError(f"Factor '{name}' must be in [0.0, 1.0], got {factor_value}")
62
+
63
+ @property
64
+ def level(self) -> str:
65
+ """Confidence level classification.
66
+
67
+ Returns:
68
+ str: One of "high", "medium", "low", "unreliable".
69
+ """
70
+ if self.value >= 0.9:
71
+ return "high"
72
+ elif self.value >= 0.7:
73
+ return "medium"
74
+ elif self.value >= 0.5:
75
+ return "low"
76
+ else:
77
+ return "unreliable"
78
+
79
+ @property
80
+ def interpretation(self) -> str:
81
+ """Human-readable interpretation.
82
+
83
+ Returns:
84
+ Descriptive interpretation string.
85
+ """
86
+ if self.value >= 0.95:
87
+ return "almost certain"
88
+ elif self.value >= 0.85:
89
+ return "likely"
90
+ elif self.value >= 0.75:
91
+ return "possible"
92
+ elif self.value >= 0.55:
93
+ return "uncertain"
94
+ else:
95
+ return "unlikely"
96
+
97
+ @staticmethod
98
+ def combine(
99
+ scores: list[float],
100
+ weights: list[float] | None = None,
101
+ ) -> float:
102
+ """Combine multiple confidence scores into one.
103
+
104
+ Uses weighted average to combine scores. Equal weights if not specified.
105
+
106
+ Args:
107
+ scores: List of confidence values (0.0-1.0).
108
+ weights: Optional weight for each score (must sum to 1.0).
109
+
110
+ Returns:
111
+ Combined confidence score (0.0-1.0).
112
+
113
+ Raises:
114
+ ValueError: If scores/weights are invalid or don't match.
115
+
116
+ Example:
117
+ >>> scores = [0.9, 0.8, 0.7]
118
+ >>> combined = ConfidenceScore.combine(scores, weights=[0.5, 0.3, 0.2])
119
+ >>> print(f"{combined:.2f}")
120
+ 0.83
121
+ """
122
+ if not scores:
123
+ raise ValueError("Cannot combine empty score list")
124
+
125
+ for score in scores:
126
+ if not 0.0 <= score <= 1.0:
127
+ raise ValueError(f"Score must be in [0.0, 1.0], got {score}")
128
+
129
+ if weights is None:
130
+ # Equal weights
131
+ weights = [1.0 / len(scores)] * len(scores)
132
+
133
+ if len(scores) != len(weights):
134
+ raise ValueError(f"Scores ({len(scores)}) and weights ({len(weights)}) length mismatch")
135
+
136
+ # Normalize weights to sum to 1.0
137
+ weight_sum = sum(weights)
138
+ if weight_sum == 0:
139
+ raise ValueError("Weights must sum to non-zero value")
140
+
141
+ normalized_weights = [w / weight_sum for w in weights]
142
+
143
+ # Weighted average
144
+ combined = sum(s * w for s, w in zip(scores, normalized_weights, strict=False))
145
+ return round(combined, 2)
146
+
147
+ def to_dict(self) -> dict[str, Any]:
148
+ """Convert to dictionary representation.
149
+
150
+ Returns:
151
+ Dictionary with confidence details.
152
+ """
153
+ return {
154
+ "value": self.value,
155
+ "level": self.level,
156
+ "interpretation": self.interpretation,
157
+ "factors": self.factors,
158
+ "explanation": self.explanation,
159
+ }
160
+
161
+ def __repr__(self) -> str:
162
+ """String representation."""
163
+ return f"ConfidenceScore({self.value:.2f}, level='{self.level}')"
164
+
165
+ def __float__(self) -> float:
166
+ """Convert to float (returns value)."""
167
+ return self.value
168
+
169
+
170
+ def calculate_confidence(
171
+ factors: dict[str, float],
172
+ weights: dict[str, float] | None = None,
173
+ *,
174
+ explanation: str | None = None,
175
+ ) -> ConfidenceScore:
176
+ """Calculate confidence score from multiple factors.
177
+
178
+ Args:
179
+ factors: Dictionary of factor names to values (0.0-1.0).
180
+ weights: Optional weights for each factor (must sum to 1.0).
181
+ explanation: Optional explanation of calculation.
182
+
183
+ Returns:
184
+ ConfidenceScore object with combined value.
185
+
186
+ Raises:
187
+ ValueError: If factors is empty or missing weight for a factor.
188
+
189
+ Example:
190
+ >>> factors = {'signal_quality': 0.9, 'pattern_match': 0.85, 'timing': 0.8}
191
+ >>> weights = {'signal_quality': 0.4, 'pattern_match': 0.4, 'timing': 0.2}
192
+ >>> score = calculate_confidence(factors, weights)
193
+ >>> print(f"Confidence: {score.value:.2f}")
194
+ Confidence: 0.86
195
+ """
196
+ if not factors:
197
+ raise ValueError("Cannot calculate confidence from empty factors")
198
+
199
+ if weights is None:
200
+ # Equal weights
201
+ score_values = list(factors.values())
202
+ weight_values = None
203
+ else:
204
+ # Use provided weights
205
+ score_values = []
206
+ weight_values = []
207
+ for name, value in factors.items():
208
+ score_values.append(value)
209
+ if name not in weights:
210
+ raise ValueError(f"Missing weight for factor '{name}'")
211
+ weight_values.append(weights[name])
212
+
213
+ combined_value = ConfidenceScore.combine(score_values, weight_values)
214
+
215
+ return ConfidenceScore(
216
+ value=combined_value,
217
+ factors=factors,
218
+ explanation=explanation,
219
+ )
220
+
221
+
222
+ __all__ = [
223
+ "ConfidenceScore",
224
+ "calculate_confidence",
225
+ ]