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,453 @@
1
+ """Memory monitoring and OOM prevention for TraceKit.
2
+
3
+ This module provides runtime memory monitoring to prevent out-of-memory crashes
4
+ and gracefully handle memory exhaustion scenarios.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.core.memory_monitor import monitor_memory, MemoryMonitor
9
+ >>> with MemoryMonitor('spectrogram', max_memory="4GB") as monitor:
10
+ ... for i in range(1000):
11
+ ... # Perform work
12
+ ... monitor.check(i) # Check memory periodically
13
+ ... stats = monitor.get_stats()
14
+ >>> print(f"Peak memory: {stats['peak'] / 1e9:.2f} GB")
15
+
16
+ References:
17
+ psutil documentation for memory monitoring
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import time
23
+ from contextlib import contextmanager
24
+ from dataclasses import dataclass
25
+ from typing import TYPE_CHECKING, Any
26
+
27
+ from oscura.config.memory import get_memory_config
28
+ from oscura.utils.memory import get_available_memory, get_max_memory
29
+
30
+ if TYPE_CHECKING:
31
+ from collections.abc import Callable, Iterator
32
+
33
+
34
+ @dataclass
35
+ class MemorySnapshot:
36
+ """Snapshot of memory state at a point in time.
37
+
38
+ Attributes:
39
+ timestamp: Time of snapshot (seconds since epoch).
40
+ available: Available system memory (bytes).
41
+ process_rss: Process resident set size (bytes).
42
+ process_vms: Process virtual memory size (bytes).
43
+ pressure: Memory pressure (0.0-1.0).
44
+ """
45
+
46
+ timestamp: float
47
+ available: int
48
+ process_rss: int
49
+ process_vms: int
50
+ pressure: float
51
+
52
+
53
+ class MemoryMonitor:
54
+ """Context manager for monitoring memory usage during operations.
55
+
56
+
57
+ Monitors memory usage during long-running operations and aborts
58
+ before system crashes if memory pressure becomes critical.
59
+
60
+ Attributes:
61
+ operation: Name of the operation being monitored.
62
+ max_memory: Maximum allowed memory (None = use global config).
63
+ check_interval: How often to check memory (number of iterations).
64
+ abort_on_critical: Whether to abort when critical threshold reached.
65
+
66
+ Example:
67
+ >>> with MemoryMonitor('fft', max_memory="2GB") as monitor:
68
+ ... result = compute_fft(data)
69
+ ... stats = monitor.get_stats()
70
+ >>> print(f"Peak: {stats['peak'] / 1e6:.1f} MB")
71
+
72
+ Raises:
73
+ MemoryError: If memory usage approaches critical limit.
74
+ """
75
+
76
+ def __init__(
77
+ self,
78
+ operation: str,
79
+ *,
80
+ max_memory: int | str | None = None,
81
+ check_interval: int = 100,
82
+ abort_on_critical: bool = True,
83
+ ):
84
+ """Initialize memory monitor.
85
+
86
+ Args:
87
+ operation: Name of operation being monitored.
88
+ max_memory: Maximum memory limit (bytes, string like "4GB", or None for auto).
89
+ check_interval: Check memory every N iterations.
90
+ abort_on_critical: Abort operation if critical threshold reached.
91
+ """
92
+ self.operation = operation
93
+ self.check_interval = check_interval
94
+ self.abort_on_critical = abort_on_critical
95
+
96
+ # Parse max_memory
97
+ if max_memory is None:
98
+ self.max_memory = get_max_memory()
99
+ elif isinstance(max_memory, str):
100
+ from oscura.config.memory import _parse_memory_string
101
+
102
+ self.max_memory = _parse_memory_string(max_memory)
103
+ else:
104
+ self.max_memory = int(max_memory)
105
+
106
+ # State
107
+ self.start_memory = 0
108
+ self.peak_memory = 0
109
+ self.current_memory = 0
110
+ self._iteration = 0
111
+ self._snapshots: list[MemorySnapshot] = []
112
+ self._start_time = 0.0
113
+
114
+ def __enter__(self) -> MemoryMonitor:
115
+ """Enter context and record starting memory."""
116
+ self.start_memory = self._get_process_memory()
117
+ self.peak_memory = self.start_memory
118
+ self.current_memory = self.start_memory
119
+ self._start_time = time.time()
120
+
121
+ # Take initial snapshot
122
+ self._take_snapshot()
123
+
124
+ return self
125
+
126
+ def __exit__(
127
+ self,
128
+ exc_type: type[BaseException] | None,
129
+ exc_val: BaseException | None,
130
+ exc_tb: Any,
131
+ ) -> None:
132
+ """Exit context and finalize monitoring."""
133
+ # Note: exc_val and exc_tb intentionally unused but required for Python 3.11+ compatibility
134
+ # Take final snapshot
135
+ self._take_snapshot()
136
+
137
+ def check(self, iteration: int | None = None) -> None:
138
+ """Check memory usage and raise error if limit approached.
139
+
140
+
141
+ Args:
142
+ iteration: Current iteration number (for periodic checking).
143
+
144
+ Raises:
145
+ MemoryError: If memory usage exceeds critical threshold.
146
+
147
+ Example:
148
+ >>> with MemoryMonitor('operation') as monitor:
149
+ ... for i in range(10000):
150
+ ... # Do work
151
+ ... monitor.check(i) # Check every 100 iterations
152
+ """
153
+ self._iteration += 1
154
+
155
+ # Only check periodically to reduce overhead
156
+ if iteration is not None and iteration % self.check_interval != 0:
157
+ return
158
+
159
+ self.current_memory = self._get_process_memory()
160
+ self.peak_memory = max(self.peak_memory, self.current_memory)
161
+
162
+ # Check against available memory and thresholds
163
+ available = get_available_memory()
164
+ config = get_memory_config()
165
+
166
+ # Calculate pressure
167
+ pressure = 1.0 - (available / self.max_memory) if self.max_memory > 0 else 0.0
168
+
169
+ # Take snapshot if significant time passed
170
+ if self._snapshots and (time.time() - self._snapshots[-1].timestamp) > 1.0:
171
+ self._take_snapshot()
172
+
173
+ # Check critical threshold
174
+ if self.abort_on_critical and pressure >= config.critical_threshold:
175
+ raise MemoryError(
176
+ f"Critical memory pressure during {self.operation}. "
177
+ f"Available: {available / 1e9:.2f} GB, "
178
+ f"Pressure: {pressure * 100:.1f}%, "
179
+ f"Limit: {self.max_memory / 1e9:.2f} GB. "
180
+ f"Operation aborted to prevent system crash. "
181
+ f"Suggestion: Reduce dataset size, increase memory limit, "
182
+ f"or use chunked processing."
183
+ )
184
+
185
+ def get_stats(self) -> dict[str, int | float]:
186
+ """Get memory statistics for this monitoring session.
187
+
188
+ Returns:
189
+ Dictionary with memory statistics including:
190
+ - start: Starting memory (bytes)
191
+ - current: Current memory (bytes)
192
+ - peak: Peak memory usage (bytes)
193
+ - delta: Memory increase since start (bytes)
194
+ - duration: Monitoring duration (seconds)
195
+
196
+ Example:
197
+ >>> with MemoryMonitor('operation') as monitor:
198
+ ... # ... do work ...
199
+ ... stats = monitor.get_stats()
200
+ >>> print(f"Peak: {stats['peak'] / 1e6:.1f} MB")
201
+ """
202
+ duration = time.time() - self._start_time if self._start_time > 0 else 0.0
203
+
204
+ return {
205
+ "start": self.start_memory,
206
+ "current": self.current_memory,
207
+ "peak": self.peak_memory,
208
+ "delta": self.peak_memory - self.start_memory,
209
+ "duration": duration,
210
+ }
211
+
212
+ def get_snapshots(self) -> list[MemorySnapshot]:
213
+ """Get all memory snapshots taken during monitoring.
214
+
215
+ Returns:
216
+ List of MemorySnapshot objects.
217
+
218
+ Example:
219
+ >>> with MemoryMonitor('operation') as monitor:
220
+ ... # ... work ...
221
+ ... pass
222
+ >>> for snap in monitor.get_snapshots():
223
+ ... print(f"t={snap.timestamp:.1f}s: {snap.available/1e9:.2f} GB available")
224
+ """
225
+ return self._snapshots.copy()
226
+
227
+ def _get_process_memory(self) -> int:
228
+ """Get current process memory usage in bytes.
229
+
230
+ Returns:
231
+ Resident set size (RSS) in bytes.
232
+ """
233
+ try:
234
+ import psutil
235
+
236
+ process = psutil.Process()
237
+ return process.memory_info().rss # type: ignore[no-any-return]
238
+ except ImportError:
239
+ # Fallback: estimate from system memory
240
+ from oscura.utils.memory import get_total_memory
241
+
242
+ return get_total_memory() - get_available_memory()
243
+
244
+ def _take_snapshot(self) -> None:
245
+ """Take a snapshot of current memory state."""
246
+ try:
247
+ import psutil
248
+
249
+ process = psutil.Process()
250
+ mem_info = process.memory_info()
251
+ available = get_available_memory()
252
+
253
+ from oscura.utils.memory import get_memory_pressure
254
+
255
+ pressure = get_memory_pressure()
256
+
257
+ snapshot = MemorySnapshot(
258
+ timestamp=time.time(),
259
+ available=available,
260
+ process_rss=mem_info.rss,
261
+ process_vms=mem_info.vms,
262
+ pressure=pressure,
263
+ )
264
+ self._snapshots.append(snapshot)
265
+ except ImportError:
266
+ # Skip snapshots if psutil not available
267
+ pass
268
+
269
+
270
+ @contextmanager
271
+ def monitor_memory(
272
+ operation: str,
273
+ *,
274
+ max_memory: int | str | None = None,
275
+ check_interval: int = 100,
276
+ ) -> Iterator[MemoryMonitor]:
277
+ """Context manager for monitoring memory usage.
278
+
279
+
280
+ Convenience function that wraps MemoryMonitor.
281
+
282
+ Args:
283
+ operation: Name of operation being monitored.
284
+ max_memory: Maximum memory limit.
285
+ check_interval: Check memory every N iterations.
286
+
287
+ Yields:
288
+ MemoryMonitor instance.
289
+
290
+ Example:
291
+ >>> with monitor_memory('spectrogram', max_memory="4GB") as mon:
292
+ ... for i in range(1000):
293
+ ... # Work
294
+ ... mon.check(i)
295
+ """
296
+ monitor = MemoryMonitor(
297
+ operation,
298
+ max_memory=max_memory,
299
+ check_interval=check_interval,
300
+ )
301
+ with monitor:
302
+ yield monitor
303
+
304
+
305
+ @dataclass
306
+ class ProgressWithMemory:
307
+ """Progress information with memory metrics.
308
+
309
+
310
+ Attributes:
311
+ current: Current progress value.
312
+ total: Total progress value.
313
+ eta_seconds: Estimated time to completion (seconds).
314
+ memory_used: Current memory usage (bytes).
315
+ memory_peak: Peak memory usage (bytes).
316
+ memory_available: Available system memory (bytes).
317
+ operation: Name of operation.
318
+ """
319
+
320
+ current: int
321
+ total: int
322
+ eta_seconds: float
323
+ memory_used: int
324
+ memory_peak: int
325
+ memory_available: int
326
+ operation: str
327
+
328
+ @property
329
+ def percent(self) -> float:
330
+ """Progress percentage (0.0-100.0)."""
331
+ if self.total == 0:
332
+ return 100.0
333
+ return (self.current / self.total) * 100.0
334
+
335
+ @property
336
+ def memory_pressure(self) -> float:
337
+ """Memory pressure (0.0-1.0)."""
338
+ from oscura.utils.memory import get_memory_pressure
339
+
340
+ return get_memory_pressure()
341
+
342
+ def format_progress(self) -> str:
343
+ """Format progress as human-readable string.
344
+
345
+ Returns:
346
+ Formatted progress string with memory info.
347
+
348
+ Example:
349
+ >>> progress = ProgressWithMemory(42, 100, 5.0, 1.2e9, 2.1e9, 6e9, "fft")
350
+ >>> print(progress.format_progress())
351
+ 42.0% | 1.20 GB used | 2.10 GB peak | 6.00 GB avail | ETA 5s
352
+ """
353
+ return (
354
+ f"{self.percent:.1f}% | "
355
+ f"{self.memory_used / 1e9:.2f} GB used | "
356
+ f"{self.memory_peak / 1e9:.2f} GB peak | "
357
+ f"{self.memory_available / 1e9:.2f} GB avail | "
358
+ f"ETA {self.eta_seconds:.0f}s"
359
+ )
360
+
361
+
362
+ class ProgressMonitor:
363
+ """Combined progress and memory monitoring.
364
+
365
+
366
+ Tracks both operation progress and memory usage, providing
367
+ unified progress updates with memory metrics.
368
+
369
+ Example:
370
+ >>> monitor = ProgressMonitor('spectrogram', total=1000)
371
+ >>> for i in range(1000):
372
+ ... # Work
373
+ ... monitor.update(i)
374
+ ... if i % 100 == 0:
375
+ ... progress = monitor.get_progress()
376
+ ... print(progress.format_progress())
377
+ """
378
+
379
+ def __init__(
380
+ self,
381
+ operation: str,
382
+ total: int,
383
+ *,
384
+ callback: Callable[[ProgressWithMemory], None] | None = None,
385
+ update_interval: int = 1,
386
+ ):
387
+ """Initialize progress monitor.
388
+
389
+ Args:
390
+ operation: Name of operation.
391
+ total: Total number of items to process.
392
+ callback: Optional callback function called on each update.
393
+ update_interval: Call callback every N updates.
394
+ """
395
+ self.operation = operation
396
+ self.total = total
397
+ self.callback = callback
398
+ self.update_interval = update_interval
399
+ self.current = 0
400
+ self._start_time = time.time()
401
+ self._memory_monitor = MemoryMonitor(operation, check_interval=1)
402
+ self._update_count = 0
403
+
404
+ def update(self, current: int | None = None) -> None:
405
+ """Update progress.
406
+
407
+ Args:
408
+ current: Current progress value (if None, increments by 1).
409
+ """
410
+ if current is not None:
411
+ self.current = current
412
+ else:
413
+ self.current += 1
414
+
415
+ self._update_count += 1
416
+
417
+ # Check memory
418
+ self._memory_monitor.check(self._update_count)
419
+
420
+ # Call callback if interval reached
421
+ if self.callback and self._update_count % self.update_interval == 0:
422
+ progress = self.get_progress()
423
+ self.callback(progress)
424
+
425
+ def get_progress(self) -> ProgressWithMemory:
426
+ """Get current progress with memory metrics.
427
+
428
+ Returns:
429
+ ProgressWithMemory instance.
430
+ """
431
+ elapsed = time.time() - self._start_time
432
+ eta = elapsed / self.current * (self.total - self.current) if self.current > 0 else 0.0
433
+
434
+ stats = self._memory_monitor.get_stats()
435
+
436
+ return ProgressWithMemory(
437
+ current=self.current,
438
+ total=self.total,
439
+ eta_seconds=eta,
440
+ memory_used=stats["current"], # type: ignore[arg-type]
441
+ memory_peak=stats["peak"], # type: ignore[arg-type]
442
+ memory_available=get_available_memory(),
443
+ operation=self.operation,
444
+ )
445
+
446
+
447
+ __all__ = [
448
+ "MemoryMonitor",
449
+ "MemorySnapshot",
450
+ "ProgressMonitor",
451
+ "ProgressWithMemory",
452
+ "monitor_memory",
453
+ ]