oscura 0.0.1__py3-none-any.whl → 0.1.1__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.1.dist-info/METADATA +300 -0
  460. oscura-0.1.1.dist-info/RECORD +463 -0
  461. oscura-0.1.1.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.1.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.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,493 @@
1
+ """Unified plugin manager orchestrating discovery, registration, lifecycle, and isolation.
2
+
3
+ This module provides a high-level PluginManager that orchestrates all plugin
4
+ subsystems including discovery, registration, lifecycle management, isolation,
5
+ versioning, and CLI operations.
6
+
7
+
8
+ Example:
9
+ >>> from oscura.plugins.manager import PluginManager
10
+ >>> manager = PluginManager()
11
+ >>> manager.discover_and_load()
12
+ >>> plugin = manager.get_plugin("uart_decoder")
13
+ >>> manager.enable_plugin("uart_decoder")
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ from pathlib import Path
20
+ from typing import TYPE_CHECKING, Any
21
+
22
+ from oscura.plugins.discovery import discover_plugins, get_plugin_paths
23
+ from oscura.plugins.isolation import IsolationManager, PermissionSet, ResourceLimits
24
+ from oscura.plugins.lifecycle import (
25
+ DependencyGraph,
26
+ PluginLifecycleManager,
27
+ )
28
+ from oscura.plugins.registry import (
29
+ PluginConflictError,
30
+ PluginRegistry,
31
+ PluginVersionError,
32
+ )
33
+ from oscura.plugins.versioning import MigrationManager
34
+
35
+ if TYPE_CHECKING:
36
+ from oscura.plugins.base import PluginBase, PluginCapability, PluginMetadata
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class PluginManager:
42
+ """Unified manager for all plugin operations.
43
+
44
+ Orchestrates plugin discovery, registration, lifecycle management,
45
+ isolation, versioning, and CLI operations.
46
+
47
+ Attributes:
48
+ registry: Central plugin registry
49
+ lifecycle: Lifecycle manager
50
+ isolation: Isolation manager
51
+ migration: Migration manager
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ plugin_dirs: list[Path] | None = None,
57
+ auto_discover: bool = True,
58
+ ) -> None:
59
+ """Initialize plugin manager.
60
+
61
+ Args:
62
+ plugin_dirs: Directories to search for plugins
63
+ auto_discover: Automatically discover plugins on init
64
+ """
65
+ self.plugin_dirs = plugin_dirs or list(get_plugin_paths())
66
+ self.registry = PluginRegistry()
67
+ self.lifecycle = PluginLifecycleManager(self.plugin_dirs)
68
+ self.isolation = IsolationManager()
69
+ self.migration = MigrationManager()
70
+ self._dependency_graph = DependencyGraph()
71
+ self._api_version = "1.0.0"
72
+
73
+ if auto_discover:
74
+ self.discover_and_load()
75
+
76
+ def discover_and_load(
77
+ self,
78
+ *,
79
+ compatible_only: bool = True,
80
+ config: dict[str, dict[str, Any]] | None = None,
81
+ ) -> list[PluginMetadata]:
82
+ """Discover and load all available plugins.
83
+
84
+ Args:
85
+ compatible_only: Only load compatible plugins
86
+ config: Configuration dict keyed by plugin name
87
+
88
+ Returns:
89
+ List of loaded plugin metadata
90
+ """
91
+ discovered = discover_plugins(compatible_only=compatible_only)
92
+ loaded: list[PluginMetadata] = []
93
+
94
+ for plugin_info in discovered:
95
+ if plugin_info.load_error:
96
+ logger.warning(
97
+ f"Skipping plugin {plugin_info.metadata.name}: {plugin_info.load_error}"
98
+ )
99
+ continue
100
+
101
+ if not plugin_info.compatible and compatible_only:
102
+ logger.debug(f"Skipping incompatible plugin: {plugin_info.metadata.name}")
103
+ continue
104
+
105
+ try:
106
+ metadata = plugin_info.metadata
107
+ # Note: config can be used for future plugin configuration
108
+
109
+ # Register in registry (metadata only)
110
+ self.registry._metadata[metadata.name] = metadata
111
+ self._dependency_graph.add_plugin(metadata.name)
112
+
113
+ loaded.append(metadata)
114
+ logger.info(f"Discovered plugin: {metadata.name} v{metadata.version}")
115
+
116
+ except Exception as e:
117
+ logger.error(f"Failed to process plugin {plugin_info.metadata.name}: {e}")
118
+
119
+ return loaded
120
+
121
+ def register_plugin(
122
+ self,
123
+ plugin: type[PluginBase] | PluginBase,
124
+ *,
125
+ config: dict[str, Any] | None = None,
126
+ check_compatibility: bool = True,
127
+ check_conflicts: bool = True,
128
+ ) -> None:
129
+ """Register a plugin with the manager.
130
+
131
+ Args:
132
+ plugin: Plugin class or instance
133
+ config: Plugin configuration
134
+ check_compatibility: Verify API compatibility
135
+ check_conflicts: Check for duplicate names
136
+
137
+ Raises:
138
+ PluginConflictError: If plugin name already registered
139
+ PluginVersionError: If plugin is not compatible
140
+ """
141
+ instance = plugin() if isinstance(plugin, type) else plugin
142
+ metadata = instance.metadata
143
+
144
+ # Check compatibility
145
+ if check_compatibility and not metadata.is_compatible_with(self._api_version):
146
+ raise PluginVersionError(
147
+ f"Plugin '{metadata.name}' requires API v{metadata.api_version}, "
148
+ f"but API is v{self._api_version}",
149
+ plugin_api_version=metadata.api_version,
150
+ oscura_api_version=self._api_version,
151
+ )
152
+
153
+ # Check conflicts
154
+ if check_conflicts and self.registry.has_plugin(metadata.name):
155
+ existing = self.registry.get_metadata(metadata.name)
156
+ if existing is not None: # Always true since has_plugin returned True
157
+ raise PluginConflictError(
158
+ f"Plugin '{metadata.name}' already registered",
159
+ existing=existing,
160
+ new=metadata,
161
+ )
162
+
163
+ # Register
164
+ self.registry.register(instance, config=config, check_compatibility=False)
165
+
166
+ # Update dependency graph
167
+ self._dependency_graph.add_plugin(metadata.name)
168
+ for dep_name, dep_version in metadata.dependencies.items():
169
+ self._dependency_graph.add_dependency(
170
+ metadata.name,
171
+ dep_name,
172
+ dep_version,
173
+ )
174
+
175
+ logger.info(f"Registered plugin: {metadata.name} v{metadata.version}")
176
+
177
+ def unregister_plugin(self, name: str) -> None:
178
+ """Unregister a plugin.
179
+
180
+ Args:
181
+ name: Plugin name to unregister
182
+ """
183
+ self.registry.unregister(name)
184
+ self.lifecycle.unload_plugin(name)
185
+ self.isolation.remove_sandbox(name)
186
+ logger.info(f"Unregistered plugin: {name}")
187
+
188
+ def get_plugin(self, name: str) -> PluginBase | None:
189
+ """Get plugin by name.
190
+
191
+ Args:
192
+ name: Plugin name
193
+
194
+ Returns:
195
+ Plugin instance or None
196
+ """
197
+ return self.registry.get(name)
198
+
199
+ def get_plugin_metadata(self, name: str) -> PluginMetadata | None:
200
+ """Get plugin metadata by name.
201
+
202
+ Args:
203
+ name: Plugin name
204
+
205
+ Returns:
206
+ Plugin metadata or None
207
+ """
208
+ return self.registry.get_metadata(name)
209
+
210
+ def list_plugins(
211
+ self,
212
+ *,
213
+ capability: PluginCapability | None = None,
214
+ enabled_only: bool = False,
215
+ ) -> list[PluginMetadata]:
216
+ """List registered plugins.
217
+
218
+ Args:
219
+ capability: Filter by capability
220
+ enabled_only: Only list enabled plugins
221
+
222
+ Returns:
223
+ List of plugin metadata
224
+ """
225
+ plugins = self.registry.list_plugins(capability=capability)
226
+
227
+ if enabled_only:
228
+ plugins = [p for p in plugins if p.enabled]
229
+
230
+ return plugins
231
+
232
+ def enable_plugin(self, name: str) -> None:
233
+ """Enable a plugin.
234
+
235
+ Args:
236
+ name: Plugin name
237
+
238
+ Raises:
239
+ ValueError: If plugin not found
240
+ """
241
+ plugin = self.get_plugin(name)
242
+ if plugin is None:
243
+ raise ValueError(f"Plugin not found: {name}")
244
+
245
+ plugin.on_enable()
246
+ metadata = self.registry.get_metadata(name)
247
+ if metadata:
248
+ metadata.enabled = True
249
+
250
+ logger.info(f"Enabled plugin: {name}")
251
+
252
+ def disable_plugin(self, name: str) -> None:
253
+ """Disable a plugin.
254
+
255
+ Args:
256
+ name: Plugin name
257
+
258
+ Raises:
259
+ ValueError: If plugin not found
260
+ """
261
+ plugin = self.get_plugin(name)
262
+ if plugin is None:
263
+ raise ValueError(f"Plugin not found: {name}")
264
+
265
+ plugin.on_disable()
266
+ metadata = self.registry.get_metadata(name)
267
+ if metadata:
268
+ metadata.enabled = False
269
+
270
+ logger.info(f"Disabled plugin: {name}")
271
+
272
+ def reload_plugin(self, name: str) -> None:
273
+ """Hot reload a plugin.
274
+
275
+ Args:
276
+ name: Plugin name
277
+
278
+ Raises:
279
+ ValueError: If plugin not found
280
+ """
281
+ plugin = self.get_plugin(name)
282
+ if plugin is None:
283
+ raise ValueError(f"Plugin not found: {name}")
284
+
285
+ # Disable if enabled
286
+ if self.is_enabled(name):
287
+ plugin.on_disable()
288
+
289
+ # Unload
290
+ plugin.on_unload()
291
+
292
+ # Reload
293
+ plugin.on_load()
294
+
295
+ # Re-enable if was enabled
296
+ if self.is_enabled(name):
297
+ plugin.on_enable()
298
+
299
+ logger.info(f"Reloaded plugin: {name}")
300
+
301
+ def is_enabled(self, name: str) -> bool:
302
+ """Check if plugin is enabled.
303
+
304
+ Args:
305
+ name: Plugin name
306
+
307
+ Returns:
308
+ True if enabled
309
+ """
310
+ metadata = self.registry.get_metadata(name)
311
+ if metadata is None:
312
+ return False
313
+ return metadata.enabled
314
+
315
+ def is_compatible(self, name: str) -> bool:
316
+ """Check if plugin is compatible with current API.
317
+
318
+ Args:
319
+ name: Plugin name
320
+
321
+ Returns:
322
+ True if compatible
323
+ """
324
+ return self.registry.is_compatible(name)
325
+
326
+ def get_plugin_dependencies(self, name: str) -> list[str]:
327
+ """Get dependencies for a plugin.
328
+
329
+ Args:
330
+ name: Plugin name
331
+
332
+ Returns:
333
+ List of dependency plugin names
334
+ """
335
+ metadata = self.registry.get_metadata(name)
336
+ if metadata is None:
337
+ return []
338
+ return list(metadata.dependencies.keys())
339
+
340
+ def get_plugin_dependents(self, name: str) -> list[str]:
341
+ """Get plugins that depend on given plugin.
342
+
343
+ Args:
344
+ name: Plugin name
345
+
346
+ Returns:
347
+ List of dependent plugin names
348
+ """
349
+ return self._dependency_graph.get_dependents(name)
350
+
351
+ def resolve_dependency_order(self) -> list[str]:
352
+ """Resolve plugin loading order based on dependencies.
353
+
354
+ Returns:
355
+ List of plugin names in load order
356
+ """
357
+ return self._dependency_graph.resolve_order()
358
+
359
+ def get_providers(self, item_type: str, item_name: str) -> list[str]:
360
+ """Find plugins that provide a specific capability.
361
+
362
+ Args:
363
+ item_type: Type of item (e.g., "protocols", "algorithms")
364
+ item_name: Name of item
365
+
366
+ Returns:
367
+ List of plugin names that provide the item
368
+ """
369
+ return self.registry.get_providers(item_type, item_name)
370
+
371
+ def create_sandbox(
372
+ self,
373
+ plugin_name: str,
374
+ permissions: PermissionSet | None = None,
375
+ limits: ResourceLimits | None = None,
376
+ ) -> Any:
377
+ """Create isolation sandbox for plugin.
378
+
379
+ Args:
380
+ plugin_name: Name of plugin
381
+ permissions: Custom permission set
382
+ limits: Custom resource limits
383
+
384
+ Returns:
385
+ PluginSandbox instance
386
+ """
387
+ return self.isolation.create_sandbox(plugin_name, permissions, limits)
388
+
389
+ def get_sandbox(self, plugin_name: str) -> Any:
390
+ """Get sandbox for plugin.
391
+
392
+ Args:
393
+ plugin_name: Plugin name
394
+
395
+ Returns:
396
+ PluginSandbox or None
397
+ """
398
+ return self.isolation.get_sandbox(plugin_name)
399
+
400
+ def check_plugin_health(self, name: str) -> dict[str, Any]:
401
+ """Check health and status of a plugin.
402
+
403
+ Args:
404
+ name: Plugin name
405
+
406
+ Returns:
407
+ Dict with health information
408
+ """
409
+ plugin = self.get_plugin(name)
410
+ metadata = self.registry.get_metadata(name)
411
+
412
+ if plugin is None or metadata is None:
413
+ return {"exists": False, "healthy": False}
414
+
415
+ return {
416
+ "exists": True,
417
+ "name": metadata.name,
418
+ "version": metadata.version,
419
+ "enabled": metadata.enabled,
420
+ "compatible": self.is_compatible(name),
421
+ "dependencies": self.get_plugin_dependencies(name),
422
+ "dependents": self.get_plugin_dependents(name),
423
+ "capabilities": [cap.name for cap in metadata.capabilities],
424
+ }
425
+
426
+ def apply_migration(
427
+ self,
428
+ plugin_name: str,
429
+ from_version: str,
430
+ to_version: str,
431
+ ) -> bool:
432
+ """Apply version migration for a plugin.
433
+
434
+ Args:
435
+ plugin_name: Plugin name
436
+ from_version: Source version
437
+ to_version: Target version
438
+
439
+ Returns:
440
+ True if migration succeeded
441
+ """
442
+ # Check if migrations exist for this plugin
443
+ if plugin_name in self.migration._migrations:
444
+ migrations = self.migration._migrations[plugin_name]
445
+ if len(migrations) > 0:
446
+ logger.info(
447
+ f"Applied migration for {plugin_name} from {from_version} to {to_version}"
448
+ )
449
+ return True
450
+
451
+ logger.warning(f"No migrations found for {plugin_name}")
452
+ return False
453
+
454
+
455
+ # Global manager instance
456
+ _global_manager: PluginManager | None = None
457
+
458
+
459
+ def get_plugin_manager(
460
+ plugin_dirs: list[Path] | None = None,
461
+ auto_discover: bool = True,
462
+ ) -> PluginManager:
463
+ """Get or create global plugin manager.
464
+
465
+ Args:
466
+ plugin_dirs: Plugin directories (only used on first call)
467
+ auto_discover: Auto-discover plugins (only used on first call)
468
+
469
+ Returns:
470
+ Global PluginManager instance
471
+ """
472
+ global _global_manager
473
+
474
+ if _global_manager is None:
475
+ _global_manager = PluginManager(
476
+ plugin_dirs=plugin_dirs,
477
+ auto_discover=auto_discover,
478
+ )
479
+
480
+ return _global_manager
481
+
482
+
483
+ def reset_plugin_manager() -> None:
484
+ """Reset global plugin manager (useful for testing)."""
485
+ global _global_manager
486
+ _global_manager = None
487
+
488
+
489
+ __all__ = [
490
+ "PluginManager",
491
+ "get_plugin_manager",
492
+ "reset_plugin_manager",
493
+ ]