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,421 @@
1
+ """Plugin registry and management.
2
+
3
+ This module provides the central plugin registry for loading,
4
+ registering, and accessing plugins.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.plugins.registry import register_plugin, get_plugin
9
+ >>> register_plugin(MyDecoder)
10
+ >>> decoder = get_plugin("my_decoder")
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ from typing import TYPE_CHECKING, Any
17
+
18
+ from oscura.plugins.discovery import (
19
+ OSCURA_API_VERSION,
20
+ DiscoveredPlugin,
21
+ discover_plugins,
22
+ )
23
+
24
+ if TYPE_CHECKING:
25
+ from oscura.plugins.base import PluginBase, PluginCapability, PluginMetadata
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class PluginConflictError(Exception):
31
+ """Plugin registration conflict.
32
+
33
+ Raised when registering a plugin with a name that already exists.
34
+
35
+ Attributes:
36
+ existing: Metadata of existing plugin.
37
+ new: Metadata of new plugin.
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ message: str,
43
+ existing: PluginMetadata,
44
+ new: PluginMetadata,
45
+ ) -> None:
46
+ super().__init__(message)
47
+ self.existing = existing
48
+ self.new = new
49
+
50
+
51
+ class PluginVersionError(Exception):
52
+ """Plugin version incompatibility.
53
+
54
+ Raised when a plugin is not compatible with the current API.
55
+
56
+ Attributes:
57
+ plugin_api_version: Plugin's required API version.
58
+ oscura_api_version: Current Oscura API version.
59
+ """
60
+
61
+ def __init__(
62
+ self,
63
+ message: str,
64
+ plugin_api_version: str,
65
+ oscura_api_version: str,
66
+ ) -> None:
67
+ super().__init__(message)
68
+ self.plugin_api_version = plugin_api_version
69
+ self.oscura_api_version = oscura_api_version
70
+
71
+
72
+ class PluginDependencyError(Exception):
73
+ """Plugin dependency not satisfied.
74
+
75
+ Attributes:
76
+ plugin: Plugin name that has unmet dependency.
77
+ dependency: Missing dependency name.
78
+ required_version: Required dependency version.
79
+ """
80
+
81
+ def __init__(
82
+ self,
83
+ message: str,
84
+ plugin: str,
85
+ dependency: str,
86
+ required_version: str,
87
+ ) -> None:
88
+ super().__init__(message)
89
+ self.plugin = plugin
90
+ self.dependency = dependency
91
+ self.required_version = required_version
92
+
93
+
94
+ class PluginRegistry:
95
+ """Central registry for plugins.
96
+
97
+ Manages plugin registration, loading, and lookup.
98
+
99
+ Example:
100
+ >>> registry = PluginRegistry()
101
+ >>> registry.register(MyDecoder)
102
+ >>> plugin = registry.get("my_decoder")
103
+ """
104
+
105
+ def __init__(self) -> None:
106
+ """Initialize empty registry."""
107
+ self._plugins: dict[str, PluginBase] = {}
108
+ self._metadata: dict[str, PluginMetadata] = {}
109
+ self._by_capability: dict[PluginCapability, list[str]] = {}
110
+ self._discovered: list[DiscoveredPlugin] = []
111
+
112
+ def register(
113
+ self,
114
+ plugin: type[PluginBase] | PluginBase,
115
+ *,
116
+ check_compatibility: bool = True,
117
+ check_conflicts: bool = True,
118
+ config: dict[str, Any] | None = None,
119
+ ) -> None:
120
+ """Register a plugin with the registry.
121
+
122
+ Args:
123
+ plugin: Plugin class or instance to register.
124
+ check_compatibility: Verify API compatibility.
125
+ check_conflicts: Check for duplicate names.
126
+ config: Optional plugin configuration.
127
+
128
+ Raises:
129
+ PluginConflictError: If plugin name already registered.
130
+ PluginVersionError: If plugin is not compatible.
131
+ """
132
+ # Get or create instance
133
+ instance = plugin() if isinstance(plugin, type) else plugin
134
+
135
+ metadata = instance.metadata
136
+
137
+ # Check compatibility
138
+ if check_compatibility and not metadata.is_compatible_with(OSCURA_API_VERSION):
139
+ raise PluginVersionError(
140
+ f"Plugin '{metadata.name}' requires API v{metadata.api_version}, "
141
+ f"but Oscura API is v{OSCURA_API_VERSION}",
142
+ plugin_api_version=metadata.api_version,
143
+ oscura_api_version=OSCURA_API_VERSION,
144
+ )
145
+
146
+ # Check conflicts (PLUG-002: conflict detection for duplicate plugins)
147
+ if check_conflicts and metadata.name in self._plugins:
148
+ existing = self._metadata[metadata.name]
149
+
150
+ # Provide detailed conflict information
151
+ conflict_msg = (
152
+ f"Plugin '{metadata.name}' already registered:\n"
153
+ f" Existing: v{existing.version} at {existing.path}\n"
154
+ f" New: v{metadata.version}"
155
+ )
156
+
157
+ # Check if same version
158
+ if existing.version == metadata.version:
159
+ conflict_msg += " (same version)"
160
+
161
+ raise PluginConflictError(
162
+ conflict_msg,
163
+ existing=existing,
164
+ new=metadata,
165
+ )
166
+
167
+ # Register
168
+ self._plugins[metadata.name] = instance
169
+ self._metadata[metadata.name] = metadata
170
+
171
+ # Index by capability
172
+ for cap in metadata.capabilities:
173
+ if cap not in self._by_capability:
174
+ self._by_capability[cap] = []
175
+ self._by_capability[cap].append(metadata.name)
176
+
177
+ # Configure and load
178
+ if config:
179
+ instance.on_configure(config)
180
+
181
+ instance.on_load()
182
+
183
+ logger.info(f"Registered plugin: {metadata.name} v{metadata.version}")
184
+
185
+ def unregister(self, name: str) -> None:
186
+ """Unregister a plugin.
187
+
188
+ Args:
189
+ name: Plugin name to unregister.
190
+ """
191
+ if name not in self._plugins:
192
+ return
193
+
194
+ instance = self._plugins[name]
195
+ metadata = self._metadata[name]
196
+
197
+ # Call unload hook
198
+ instance.on_unload()
199
+
200
+ # Remove from capability index
201
+ for cap in metadata.capabilities:
202
+ if cap in self._by_capability and name in self._by_capability[cap]:
203
+ self._by_capability[cap].remove(name)
204
+
205
+ # Remove from registry
206
+ del self._plugins[name]
207
+ del self._metadata[name]
208
+
209
+ logger.info(f"Unregistered plugin: {name}")
210
+
211
+ def get(self, name: str) -> PluginBase | None:
212
+ """Get plugin by name.
213
+
214
+ Args:
215
+ name: Plugin name.
216
+
217
+ Returns:
218
+ Plugin instance or None.
219
+ """
220
+ return self._plugins.get(name)
221
+
222
+ def get_metadata(self, name: str) -> PluginMetadata | None:
223
+ """Get plugin metadata by name.
224
+
225
+ Args:
226
+ name: Plugin name.
227
+
228
+ Returns:
229
+ Plugin metadata or None.
230
+ """
231
+ return self._metadata.get(name)
232
+
233
+ def list_plugins(
234
+ self,
235
+ *,
236
+ capability: PluginCapability | None = None,
237
+ ) -> list[PluginMetadata]:
238
+ """List registered plugins.
239
+
240
+ Args:
241
+ capability: Filter by capability.
242
+
243
+ Returns:
244
+ List of plugin metadata.
245
+ """
246
+ if capability is not None:
247
+ names = self._by_capability.get(capability, [])
248
+ return [self._metadata[name] for name in names]
249
+
250
+ return list(self._metadata.values())
251
+
252
+ def has_plugin(self, name: str) -> bool:
253
+ """Check if plugin is registered.
254
+
255
+ Args:
256
+ name: Plugin name.
257
+
258
+ Returns:
259
+ True if registered.
260
+ """
261
+ return name in self._plugins
262
+
263
+ def is_compatible(self, name: str) -> bool:
264
+ """Check if plugin is compatible with current API.
265
+
266
+ Args:
267
+ name: Plugin name.
268
+
269
+ Returns:
270
+ True if compatible.
271
+ """
272
+ metadata = self._metadata.get(name)
273
+ if metadata is None:
274
+ return False
275
+ return metadata.is_compatible_with(OSCURA_API_VERSION)
276
+
277
+ def discover_and_load(
278
+ self,
279
+ *,
280
+ compatible_only: bool = True,
281
+ config: dict[str, dict[str, Any]] | None = None,
282
+ ) -> list[PluginMetadata]:
283
+ """Discover and load all available plugins.
284
+
285
+ Args:
286
+ compatible_only: Only load compatible plugins.
287
+ config: Configuration dict keyed by plugin name.
288
+
289
+ Returns:
290
+ List of loaded plugin metadata.
291
+ """
292
+ self._discovered = discover_plugins(compatible_only=compatible_only)
293
+ loaded: list[PluginMetadata] = []
294
+
295
+ for discovered in self._discovered:
296
+ if discovered.load_error:
297
+ logger.warning(
298
+ f"Skipping plugin {discovered.metadata.name}: {discovered.load_error}"
299
+ )
300
+ continue
301
+
302
+ if not discovered.compatible and compatible_only:
303
+ logger.debug(f"Skipping incompatible plugin: {discovered.metadata.name}")
304
+ continue
305
+
306
+ try:
307
+ if config and discovered.metadata.name in config:
308
+ config[discovered.metadata.name]
309
+
310
+ # For now, just store the metadata
311
+ # Full loading requires importing the plugin module
312
+ self._metadata[discovered.metadata.name] = discovered.metadata
313
+ loaded.append(discovered.metadata)
314
+
315
+ except Exception as e:
316
+ logger.error(f"Failed to load plugin {discovered.metadata.name}: {e}")
317
+
318
+ return loaded
319
+
320
+ def get_providers(self, item_type: str, item_name: str) -> list[str]:
321
+ """Find plugins that provide a specific capability.
322
+
323
+ Args:
324
+ item_type: Type of item (e.g., "protocols", "algorithms").
325
+ item_name: Name of item.
326
+
327
+ Returns:
328
+ List of plugin names that provide the item.
329
+ """
330
+ providers: list[str] = []
331
+
332
+ for name, metadata in self._metadata.items():
333
+ if item_type in metadata.provides:
334
+ if item_name in metadata.provides[item_type]:
335
+ providers.append(name)
336
+
337
+ return providers
338
+
339
+
340
+ # Global registry instance
341
+ _global_registry: PluginRegistry | None = None
342
+
343
+
344
+ def get_plugin_registry() -> PluginRegistry:
345
+ """Get the global plugin registry.
346
+
347
+ Returns:
348
+ Global PluginRegistry instance.
349
+ """
350
+ global _global_registry
351
+
352
+ if _global_registry is None:
353
+ _global_registry = PluginRegistry()
354
+
355
+ return _global_registry
356
+
357
+
358
+ def register_plugin(
359
+ plugin: type[PluginBase] | PluginBase,
360
+ *,
361
+ config: dict[str, Any] | None = None,
362
+ ) -> None:
363
+ """Register plugin with global registry.
364
+
365
+ Args:
366
+ plugin: Plugin class or instance.
367
+ config: Plugin configuration.
368
+ """
369
+ get_plugin_registry().register(plugin, config=config)
370
+
371
+
372
+ def get_plugin(name: str) -> PluginBase | None:
373
+ """Get plugin from global registry.
374
+
375
+ Args:
376
+ name: Plugin name.
377
+
378
+ Returns:
379
+ Plugin instance or None.
380
+ """
381
+ return get_plugin_registry().get(name)
382
+
383
+
384
+ def list_plugins(
385
+ *,
386
+ capability: PluginCapability | None = None,
387
+ ) -> list[PluginMetadata]:
388
+ """List plugins from global registry.
389
+
390
+ Args:
391
+ capability: Filter by capability.
392
+
393
+ Returns:
394
+ List of plugin metadata.
395
+ """
396
+ return get_plugin_registry().list_plugins(capability=capability)
397
+
398
+
399
+ def is_compatible(name: str) -> bool:
400
+ """Check plugin compatibility.
401
+
402
+ Args:
403
+ name: Plugin name.
404
+
405
+ Returns:
406
+ True if compatible.
407
+ """
408
+ return get_plugin_registry().is_compatible(name)
409
+
410
+
411
+ __all__ = [
412
+ "PluginConflictError",
413
+ "PluginDependencyError",
414
+ "PluginRegistry",
415
+ "PluginVersionError",
416
+ "get_plugin",
417
+ "get_plugin_registry",
418
+ "is_compatible",
419
+ "list_plugins",
420
+ "register_plugin",
421
+ ]