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,524 @@
1
+ """Progress tracking and cancellation support for TraceKit operations.
2
+
3
+ This module provides progress callbacks, cancellation tokens, and memory warnings
4
+ for long-running operations.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.core.progress import ProgressCallback, CancellationToken
9
+ >>> token = CancellationToken()
10
+ >>> def progress_fn(current, total, message):
11
+ ... print(f"{current}/{total}: {message}")
12
+ >>> # Use in analysis functions
13
+ >>> result = analyze(data, progress_callback=progress_fn, cancel_token=token)
14
+
15
+ References:
16
+ - WCAG 2.1 progress indication guidelines
17
+ - Python threading and multiprocessing best practices
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import time
23
+ import warnings
24
+ from typing import TYPE_CHECKING, Protocol
25
+
26
+ import psutil
27
+
28
+ if TYPE_CHECKING:
29
+ from collections.abc import Callable
30
+
31
+
32
+ class ProgressCallback(Protocol):
33
+ """Protocol for progress callback functions.
34
+
35
+ : Progress callback parameter on all analysis functions.
36
+ Callback receives (current, total, message) for progress reporting.
37
+
38
+ Args:
39
+ current: Current progress value (e.g., samples processed)
40
+ total: Total expected value (e.g., total samples)
41
+ message: Descriptive message about current operation
42
+
43
+ Example:
44
+ >>> def my_progress(current: int, total: int, message: str) -> None:
45
+ ... percent = 100 * current / total
46
+ ... print(f"{percent:.1f}%: {message}")
47
+
48
+ References:
49
+ PROG-001: Progress Indication for Long Operations
50
+ """
51
+
52
+ def __call__(self, current: int, total: int, message: str) -> None:
53
+ """Progress callback signature.
54
+
55
+ Args:
56
+ current: Current progress (completed items)
57
+ total: Total items to process
58
+ message: Status message
59
+ """
60
+ ...
61
+
62
+
63
+ class CancellationToken:
64
+ """Token for cancelling long-running operations.
65
+
66
+ : Cancellation Support - cancel() method on operation handles.
67
+ Allows graceful cancellation of operations with Ctrl+C support.
68
+
69
+ Attributes:
70
+ cancelled: Whether cancellation has been requested
71
+ message: Optional cancellation message
72
+
73
+ Example:
74
+ >>> from oscura.core.progress import CancellationToken, CancelledError
75
+ >>> token = CancellationToken()
76
+ >>> # In analysis function:
77
+ >>> for i in range(n_samples):
78
+ ... if token.is_cancelled():
79
+ ... raise CancelledError("Analysis cancelled by user")
80
+ ... # ... process sample ...
81
+
82
+ References:
83
+ PROG-002: Cancellation Support
84
+ """
85
+
86
+ def __init__(self) -> None:
87
+ """Initialize cancellation token."""
88
+ self._cancelled: bool = False
89
+ self._message: str = ""
90
+ self._cancelled_at: float | None = None
91
+
92
+ def cancel(self, message: str = "Operation cancelled") -> None:
93
+ """Request cancellation of the operation.
94
+
95
+ Args:
96
+ message: Reason for cancellation (default: "Operation cancelled")
97
+
98
+ Example:
99
+ >>> token = CancellationToken()
100
+ >>> token.cancel("User requested stop")
101
+ >>> assert token.is_cancelled()
102
+
103
+ References:
104
+ PROG-002: Cancellation Support
105
+ """
106
+ self._cancelled = True
107
+ self._message = message
108
+ self._cancelled_at = time.time()
109
+
110
+ def is_cancelled(self) -> bool:
111
+ """Check if cancellation has been requested.
112
+
113
+ Returns:
114
+ True if operation should be cancelled
115
+
116
+ Example:
117
+ >>> token = CancellationToken()
118
+ >>> if token.is_cancelled():
119
+ ... return # Exit early
120
+
121
+ References:
122
+ PROG-002: Cancellation Support
123
+ """
124
+ return self._cancelled
125
+
126
+ def check(self) -> None:
127
+ """Check cancellation status and raise if cancelled.
128
+
129
+ Raises:
130
+ CancelledError: If cancellation has been requested
131
+
132
+ Example:
133
+ >>> token = CancellationToken()
134
+ >>> token.cancel()
135
+ >>> token.check() # Raises CancelledError
136
+
137
+ References:
138
+ PROG-002: Cancellation Support
139
+ """
140
+ if self._cancelled:
141
+ raise CancelledError(self._message)
142
+
143
+ @property
144
+ def message(self) -> str:
145
+ """Get cancellation message.
146
+
147
+ Returns:
148
+ Cancellation message
149
+
150
+ References:
151
+ PROG-002: Cancellation Support
152
+ """
153
+ return self._message
154
+
155
+ @property
156
+ def cancelled_at(self) -> float | None:
157
+ """Get timestamp when cancellation was requested.
158
+
159
+ Returns:
160
+ Timestamp in seconds since epoch, or None if not cancelled
161
+
162
+ References:
163
+ PROG-002: Cancellation Support
164
+ """
165
+ return self._cancelled_at
166
+
167
+
168
+ class CancelledError(Exception):
169
+ """Exception raised when operation is cancelled.
170
+
171
+ : Partial results available after cancellation.
172
+ Operations can catch this to save partial results before exiting.
173
+
174
+ Attributes:
175
+ message: Reason for cancellation
176
+ progress: Progress percentage at cancellation (0-100)
177
+
178
+ Example:
179
+ >>> from oscura.core.progress import CancelledError
180
+ >>> try:
181
+ ... # ... long operation ...
182
+ ... raise CancelledError("User cancelled", progress=45.5)
183
+ ... except CancelledError as e:
184
+ ... print(f"Cancelled at {e.progress}%: {e.message}")
185
+
186
+ References:
187
+ PROG-002: Cancellation Support
188
+ """
189
+
190
+ def __init__(self, message: str, *, progress: float = 0.0) -> None:
191
+ """Initialize CancelledError.
192
+
193
+ Args:
194
+ message: Reason for cancellation
195
+ progress: Progress percentage at cancellation (default: 0.0)
196
+ """
197
+ self.message = message
198
+ self.progress = progress
199
+ super().__init__(f"{message} ({progress:.1f}% complete)")
200
+
201
+
202
+ def create_progress_tracker(
203
+ total: int,
204
+ *,
205
+ callback: Callable[[int, int, str], None] | None = None,
206
+ update_interval: float = 0.1,
207
+ ) -> ProgressTracker:
208
+ """Create a progress tracker for an operation.
209
+
210
+ : Progress callback receives (current, total, eta_seconds).
211
+ Automatically calculates ETA and throttles updates.
212
+
213
+ Args:
214
+ total: Total number of items to process
215
+ callback: Optional progress callback function
216
+ update_interval: Minimum time between updates in seconds (default: 0.1)
217
+
218
+ Returns:
219
+ ProgressTracker instance
220
+
221
+ Example:
222
+ >>> from oscura.core.progress import create_progress_tracker
223
+ >>> tracker = create_progress_tracker(1000, callback=my_progress)
224
+ >>> for i in range(1000):
225
+ ... tracker.update(i + 1, "Processing item")
226
+
227
+ References:
228
+ PROG-001: Progress Indication for Long Operations
229
+ """
230
+ return ProgressTracker(total, callback=callback, update_interval=update_interval)
231
+
232
+
233
+ class ProgressTracker:
234
+ """Progress tracker with ETA calculation and throttling.
235
+
236
+ : Callback receives (current, total, eta_seconds).
237
+ Tracks progress and calculates estimated time to completion.
238
+
239
+ Args:
240
+ total: Total number of items
241
+ callback: Optional progress callback
242
+ update_interval: Minimum seconds between updates
243
+
244
+ Example:
245
+ >>> from oscura.core.progress import ProgressTracker
246
+ >>> tracker = ProgressTracker(1000)
247
+ >>> for i in range(1000):
248
+ ... tracker.update(i + 1, "Processing")
249
+ >>> tracker.finish("Complete")
250
+
251
+ References:
252
+ PROG-001: Progress Indication for Long Operations
253
+ """
254
+
255
+ def __init__(
256
+ self,
257
+ total: int,
258
+ *,
259
+ callback: Callable[[int, int, str], None] | None = None,
260
+ update_interval: float = 0.1,
261
+ ) -> None:
262
+ """Initialize progress tracker.
263
+
264
+ Args:
265
+ total: Total items to process
266
+ callback: Progress callback function
267
+ update_interval: Minimum seconds between updates
268
+ """
269
+ self.total = total
270
+ self.current = 0
271
+ self.callback = callback
272
+ self.update_interval = update_interval
273
+
274
+ self._start_time = time.time()
275
+ self._last_update_time = 0.0
276
+ self._finished = False
277
+
278
+ def update(self, current: int, message: str = "") -> None:
279
+ """Update progress.
280
+
281
+ Args:
282
+ current: Current progress value
283
+ message: Status message
284
+
285
+ Example:
286
+ >>> tracker.update(500, "Halfway done")
287
+
288
+ References:
289
+ PROG-001: Progress Indication for Long Operations
290
+ """
291
+ self.current = current
292
+
293
+ # Throttle updates
294
+ now = time.time()
295
+ if now - self._last_update_time < self.update_interval:
296
+ return
297
+
298
+ self._last_update_time = now
299
+
300
+ if self.callback:
301
+ self.callback(current, self.total, message)
302
+
303
+ def get_eta(self) -> float:
304
+ """Calculate estimated time to completion.
305
+
306
+ Returns:
307
+ Estimated seconds remaining
308
+
309
+ Example:
310
+ >>> tracker.update(500, "Processing")
311
+ >>> eta = tracker.get_eta()
312
+ >>> print(f"ETA: {eta:.1f} seconds")
313
+
314
+ References:
315
+ PROG-001: Progress Indication for Long Operations
316
+ """
317
+ if self.current == 0:
318
+ return 0.0
319
+
320
+ elapsed = time.time() - self._start_time
321
+ rate = self.current / elapsed
322
+ remaining = self.total - self.current
323
+
324
+ if rate > 0:
325
+ return remaining / rate
326
+ else:
327
+ return 0.0
328
+
329
+ def get_progress_percent(self) -> float:
330
+ """Get progress as percentage.
331
+
332
+ Returns:
333
+ Progress percentage (0-100)
334
+
335
+ Example:
336
+ >>> tracker.update(250, "Processing")
337
+ >>> print(f"Progress: {tracker.get_progress_percent():.1f}%")
338
+
339
+ References:
340
+ PROG-001: Progress Indication for Long Operations
341
+ """
342
+ if self.total == 0:
343
+ return 100.0
344
+ return 100.0 * self.current / self.total
345
+
346
+ def finish(self, message: str = "Complete") -> None:
347
+ """Mark operation as finished.
348
+
349
+ Args:
350
+ message: Completion message (default: "Complete")
351
+
352
+ Example:
353
+ >>> tracker.finish("Analysis complete")
354
+
355
+ References:
356
+ PROG-001: Progress Indication for Long Operations
357
+ """
358
+ self._finished = True
359
+ self.current = self.total
360
+
361
+ if self.callback:
362
+ self.callback(self.total, self.total, message)
363
+
364
+
365
+ def estimate_memory_usage(
366
+ n_samples: int,
367
+ dtype_bytes: int = 8,
368
+ *,
369
+ n_channels: int = 1,
370
+ scratch_multiplier: float = 2.0,
371
+ ) -> int:
372
+ """Estimate memory usage for an operation.
373
+
374
+ : Estimate memory before large FFT/spectrograms.
375
+ Calculates expected memory consumption including scratch space.
376
+
377
+ Args:
378
+ n_samples: Number of samples
379
+ dtype_bytes: Bytes per sample (default: 8 for float64)
380
+ n_channels: Number of channels (default: 1)
381
+ scratch_multiplier: Multiplier for temporary arrays (default: 2.0)
382
+
383
+ Returns:
384
+ Estimated memory usage in bytes
385
+
386
+ Example:
387
+ >>> from oscura.core.progress import estimate_memory_usage
388
+ >>> memory_bytes = estimate_memory_usage(1_000_000, dtype_bytes=8)
389
+ >>> memory_mb = memory_bytes / (1024 ** 2)
390
+ >>> print(f"Estimated: {memory_mb:.1f} MB")
391
+
392
+ References:
393
+ PROG-003: Memory Usage Warnings
394
+ """
395
+ # Base array size
396
+ base_size = n_samples * dtype_bytes * n_channels
397
+
398
+ # Include scratch space for operations (e.g., FFT)
399
+ total_size = int(base_size * scratch_multiplier)
400
+
401
+ return total_size
402
+
403
+
404
+ def check_memory_available(required_bytes: int, *, threshold: float = 0.8) -> bool:
405
+ """Check if sufficient memory is available.
406
+
407
+ : Warn if estimated > 80% of available RAM.
408
+ Checks system memory availability before large operations.
409
+
410
+ Args:
411
+ required_bytes: Required memory in bytes
412
+ threshold: Maximum fraction of available RAM to use (default: 0.8)
413
+
414
+ Returns:
415
+ True if sufficient memory is available
416
+
417
+ Example:
418
+ >>> from oscura.core.progress import check_memory_available
419
+ >>> required = 1024 * 1024 * 1024 # 1 GB
420
+ >>> if not check_memory_available(required):
421
+ ... print("Warning: Insufficient memory")
422
+
423
+ References:
424
+ PROG-003: Memory Usage Warnings
425
+ """
426
+ memory = psutil.virtual_memory()
427
+ available_bytes = memory.available
428
+ threshold_bytes = available_bytes * threshold
429
+
430
+ return required_bytes <= threshold_bytes # type: ignore[no-any-return]
431
+
432
+
433
+ def warn_memory_usage(
434
+ required_bytes: int,
435
+ *,
436
+ threshold: float = 0.8,
437
+ suggest_chunked: bool = True,
438
+ ) -> None:
439
+ """Warn if operation may exceed available memory.
440
+
441
+ : Warn before operations that may exceed available memory.
442
+ Issues warning and suggests chunked processing if needed.
443
+
444
+ Args:
445
+ required_bytes: Required memory in bytes
446
+ threshold: Maximum fraction of available RAM (default: 0.8)
447
+ suggest_chunked: Suggest chunked processing (default: True)
448
+
449
+ Example:
450
+ >>> from oscura.core.progress import warn_memory_usage
451
+ >>> required = estimate_memory_usage(10_000_000)
452
+ >>> warn_memory_usage(required)
453
+
454
+ References:
455
+ PROG-003: Memory Usage Warnings
456
+ """
457
+ memory = psutil.virtual_memory()
458
+ available_bytes = memory.available
459
+ threshold_bytes = available_bytes * threshold
460
+
461
+ required_mb = required_bytes / (1024**2)
462
+ available_mb = available_bytes / (1024**2)
463
+ threshold_mb = threshold_bytes / (1024**2)
464
+
465
+ if required_bytes > threshold_bytes:
466
+ message = (
467
+ f"Warning: Operation may require {required_mb:.1f} MB of memory, "
468
+ f"but only {available_mb:.1f} MB is available "
469
+ f"(threshold: {threshold_mb:.1f} MB)."
470
+ )
471
+
472
+ if suggest_chunked:
473
+ message += " Consider using chunked processing or reducing the data size."
474
+
475
+ warnings.warn(message, ResourceWarning, stacklevel=2)
476
+
477
+
478
+ def create_simple_progress(
479
+ message_prefix: str = "Progress",
480
+ ) -> Callable[[int, int, str], None]:
481
+ """Create a simple text-based progress callback.
482
+
483
+ : CLI shows progress bar for long operations.
484
+ Returns a callback that prints progress to stdout.
485
+
486
+ Args:
487
+ message_prefix: Prefix for progress messages (default: "Progress")
488
+
489
+ Returns:
490
+ Progress callback function
491
+
492
+ Example:
493
+ >>> from oscura.core.progress import create_simple_progress
494
+ >>> callback = create_simple_progress("Loading")
495
+ >>> for i in range(100):
496
+ ... callback(i + 1, 100, "Processing")
497
+
498
+ References:
499
+ PROG-001: Progress Indication for Long Operations
500
+ """
501
+
502
+ def callback(current: int, total: int, message: str) -> None:
503
+ percent = 100 * current / total if total > 0 else 0
504
+ status = f"{message_prefix}: {percent:.1f}% ({current}/{total})"
505
+ if message:
506
+ status += f" - {message}"
507
+ print(f"\r{status}", end="", flush=True)
508
+ if current >= total:
509
+ print() # New line when complete
510
+
511
+ return callback
512
+
513
+
514
+ __all__ = [
515
+ "CancellationToken",
516
+ "CancelledError",
517
+ "ProgressCallback",
518
+ "ProgressTracker",
519
+ "check_memory_available",
520
+ "create_progress_tracker",
521
+ "create_simple_progress",
522
+ "estimate_memory_usage",
523
+ "warn_memory_usage",
524
+ ]