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,713 @@
1
+ """JSON Schema validation system for TraceKit configuration.
2
+
3
+ This module provides a flexible schema validation system using JSON Schema
4
+ for validating configuration files including protocols, pipelines, and
5
+ threshold configurations.
6
+
7
+
8
+ Example:
9
+ >>> from oscura.config.schema import validate_against_schema
10
+ >>> config = {"name": "uart", "baud_rate": 115200}
11
+ >>> validate_against_schema(config, "protocol")
12
+ True
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from dataclasses import dataclass
18
+ from typing import Any
19
+
20
+ # Try to import jsonschema for full validation
21
+ try:
22
+ import jsonschema # noqa: F401
23
+ from jsonschema import Draft7Validator
24
+ from jsonschema import ValidationError as JsonSchemaError
25
+
26
+ JSONSCHEMA_AVAILABLE = True
27
+ except ImportError:
28
+ JSONSCHEMA_AVAILABLE = False
29
+ JsonSchemaError = Exception # type: ignore[ignore-without-code]
30
+
31
+ from oscura.core.exceptions import ConfigurationError
32
+ from oscura.core.exceptions import ValidationError as TraceKitValidationError
33
+
34
+
35
+ class ValidationError(TraceKitValidationError):
36
+ """Schema validation error with detailed location information.
37
+
38
+ Attributes:
39
+ path: JSON path to the invalid field.
40
+ line: Line number in source file (if available).
41
+ column: Column number in source file (if available).
42
+ schema_path: Path in schema where validation failed.
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ message: str,
48
+ *,
49
+ path: str | None = None,
50
+ line: int | None = None,
51
+ column: int | None = None,
52
+ schema_path: str | None = None,
53
+ expected: Any = None,
54
+ actual: Any = None,
55
+ suggestion: str | None = None,
56
+ ) -> None:
57
+ """Initialize ValidationError.
58
+
59
+ Args:
60
+ message: Description of the validation failure.
61
+ path: JSON path to invalid field (e.g., "protocol.timing.baud_rate").
62
+ line: Line number in source file.
63
+ column: Column number in source file.
64
+ schema_path: Path in schema where validation failed.
65
+ expected: Expected value or type.
66
+ actual: Actual value found.
67
+ suggestion: Suggested fix.
68
+ """
69
+ self.path = path
70
+ self.line = line
71
+ self.column = column
72
+ self.schema_path = schema_path
73
+ self.expected = expected
74
+ self.actual = actual
75
+ self.suggestion = suggestion
76
+
77
+ # Build detailed message
78
+ details_parts = []
79
+ if path:
80
+ details_parts.append(f"Path: {path}")
81
+ if line is not None:
82
+ location = f"Line {line}"
83
+ if column is not None:
84
+ location += f", column {column}"
85
+ details_parts.append(location)
86
+ if expected is not None:
87
+ details_parts.append(f"Expected: {expected}")
88
+ if actual is not None:
89
+ details_parts.append(f"Got: {actual}")
90
+
91
+ super().__init__(
92
+ message,
93
+ field=path,
94
+ constraint=schema_path,
95
+ value=actual,
96
+ )
97
+
98
+
99
+ @dataclass
100
+ class ConfigSchema:
101
+ """Schema definition with metadata.
102
+
103
+ Attributes:
104
+ name: Schema identifier (e.g., "protocol", "pipeline").
105
+ version: Schema version (semver format).
106
+ schema: JSON Schema dictionary.
107
+ description: Human-readable description.
108
+ uri: Optional URI for schema reference.
109
+ """
110
+
111
+ name: str
112
+ version: str
113
+ schema: dict[str, Any]
114
+ description: str = ""
115
+ uri: str | None = None
116
+
117
+ def __post_init__(self) -> None:
118
+ """Validate schema after initialization."""
119
+ if not self.name:
120
+ raise ValueError("Schema name cannot be empty")
121
+ if not self.version:
122
+ raise ValueError("Schema version cannot be empty")
123
+ if not self.schema:
124
+ raise ValueError("Schema cannot be empty")
125
+
126
+ @property
127
+ def full_uri(self) -> str:
128
+ """Get full schema URI.
129
+
130
+ Returns:
131
+ URI for schema reference, or generated local path if not provided.
132
+ """
133
+ if self.uri:
134
+ return self.uri
135
+ return f"urn:oscura:schemas:{self.name}:v{self.version}"
136
+
137
+
138
+ class SchemaRegistry:
139
+ """Central registry for all configuration schemas.
140
+
141
+ Provides O(1) lookup of schemas by name and version.
142
+
143
+ Example:
144
+ >>> registry = SchemaRegistry()
145
+ >>> registry.register(protocol_schema)
146
+ >>> schema = registry.get("protocol")
147
+ """
148
+
149
+ def __init__(self) -> None:
150
+ """Initialize empty schema registry."""
151
+ self._schemas: dict[str, dict[str, ConfigSchema]] = {}
152
+ self._default_versions: dict[str, str] = {}
153
+
154
+ def register(
155
+ self,
156
+ schema: ConfigSchema,
157
+ *,
158
+ set_default: bool = True,
159
+ ) -> None:
160
+ """Register a schema with the registry.
161
+
162
+ Args:
163
+ schema: Schema to register.
164
+ set_default: If True, set as default version for this schema name.
165
+
166
+ Raises:
167
+ ValueError: If schema with same name and version already exists.
168
+ """
169
+ if schema.name not in self._schemas:
170
+ self._schemas[schema.name] = {}
171
+
172
+ if schema.version in self._schemas[schema.name]:
173
+ self._schemas[schema.name][schema.version]
174
+ raise ValueError(f"Schema '{schema.name}' v{schema.version} already registered")
175
+
176
+ self._schemas[schema.name][schema.version] = schema
177
+
178
+ if set_default:
179
+ self._default_versions[schema.name] = schema.version
180
+
181
+ def get(
182
+ self,
183
+ name: str,
184
+ version: str | None = None,
185
+ ) -> ConfigSchema | None:
186
+ """Get schema by name and optional version.
187
+
188
+ Args:
189
+ name: Schema name (e.g., "protocol").
190
+ version: Specific version or None for default.
191
+
192
+ Returns:
193
+ ConfigSchema if found, None otherwise.
194
+ """
195
+ if name not in self._schemas:
196
+ return None
197
+
198
+ if version is None:
199
+ version = self._default_versions.get(name)
200
+ if version is None:
201
+ return None
202
+
203
+ return self._schemas[name].get(version)
204
+
205
+ def list_schemas(self) -> list[str]:
206
+ """List all registered schema names.
207
+
208
+ Returns:
209
+ List of schema names.
210
+ """
211
+ return list(self._schemas.keys())
212
+
213
+ def list_versions(self, name: str) -> list[str]:
214
+ """List all versions of a schema.
215
+
216
+ Args:
217
+ name: Schema name.
218
+
219
+ Returns:
220
+ List of version strings.
221
+ """
222
+ if name not in self._schemas:
223
+ return []
224
+ return list(self._schemas[name].keys())
225
+
226
+ def has_schema(self, name: str, version: str | None = None) -> bool:
227
+ """Check if schema exists.
228
+
229
+ Args:
230
+ name: Schema name.
231
+ version: Specific version or None for any.
232
+
233
+ Returns:
234
+ True if schema exists.
235
+ """
236
+ if name not in self._schemas:
237
+ return False
238
+ if version is None:
239
+ return True
240
+ return version in self._schemas[name]
241
+
242
+
243
+ # Global schema registry
244
+ _global_registry: SchemaRegistry | None = None
245
+
246
+
247
+ def get_schema_registry() -> SchemaRegistry:
248
+ """Get the global schema registry.
249
+
250
+ Initializes with built-in schemas on first call.
251
+
252
+ Returns:
253
+ Global SchemaRegistry instance.
254
+ """
255
+ global _global_registry
256
+
257
+ if _global_registry is None:
258
+ _global_registry = SchemaRegistry()
259
+ _register_builtin_schemas(_global_registry)
260
+
261
+ return _global_registry
262
+
263
+
264
+ def register_schema(
265
+ schema: ConfigSchema,
266
+ *,
267
+ set_default: bool = True,
268
+ ) -> None:
269
+ """Register a schema with the global registry.
270
+
271
+ Args:
272
+ schema: Schema to register.
273
+ set_default: If True, set as default version.
274
+ """
275
+ get_schema_registry().register(schema, set_default=set_default)
276
+
277
+
278
+ def validate_against_schema(
279
+ config: dict[str, Any],
280
+ schema_name: str,
281
+ *,
282
+ version: str | None = None,
283
+ strict: bool = False,
284
+ ) -> bool:
285
+ """Validate configuration against a registered schema.
286
+
287
+ Args:
288
+ config: Configuration dictionary to validate.
289
+ schema_name: Name of schema to validate against.
290
+ version: Specific schema version or None for default.
291
+ strict: If True, fail on additional properties.
292
+
293
+ Returns:
294
+ True if validation passes.
295
+
296
+ Raises:
297
+ ValidationError: If validation fails with detailed error info.
298
+ ConfigurationError: If schema not found or jsonschema not available.
299
+ """
300
+ if not JSONSCHEMA_AVAILABLE:
301
+ raise ConfigurationError(
302
+ "JSON Schema validation not available",
303
+ fix_hint="Install jsonschema: pip install jsonschema",
304
+ )
305
+
306
+ registry = get_schema_registry()
307
+ schema_obj = registry.get(schema_name, version)
308
+
309
+ if schema_obj is None:
310
+ available = registry.list_schemas()
311
+ raise ConfigurationError(
312
+ f"Schema '{schema_name}' not found",
313
+ details=f"Available schemas: {available}",
314
+ )
315
+
316
+ schema = schema_obj.schema.copy()
317
+
318
+ # Add strict mode
319
+ if strict and "additionalProperties" not in schema:
320
+ schema["additionalProperties"] = False
321
+
322
+ try:
323
+ validator = Draft7Validator(schema)
324
+ errors = list(validator.iter_errors(config))
325
+
326
+ if errors:
327
+ # Get first error for main message
328
+ error = errors[0]
329
+ path = ".".join(str(p) for p in error.absolute_path) or "(root)"
330
+
331
+ # Try to provide helpful suggestion
332
+ suggestion = _get_error_suggestion(error)
333
+
334
+ raise ValidationError(
335
+ str(error.message),
336
+ path=path,
337
+ schema_path=".".join(str(p) for p in error.absolute_schema_path),
338
+ expected=error.schema.get("type") or error.schema.get("enum"),
339
+ actual=error.instance,
340
+ suggestion=suggestion,
341
+ )
342
+
343
+ return True
344
+
345
+ except JsonSchemaError as e:
346
+ path = ".".join(str(p) for p in e.absolute_path) if e.absolute_path else None # type: ignore[assignment]
347
+ raise ValidationError(
348
+ str(e.message),
349
+ path=path,
350
+ schema_path=".".join(str(p) for p in e.absolute_schema_path)
351
+ if e.absolute_schema_path
352
+ else None,
353
+ ) from e
354
+
355
+
356
+ def _get_error_suggestion(error: Any) -> str | None:
357
+ """Generate suggestion for common validation errors.
358
+
359
+ Args:
360
+ error: jsonschema ValidationError.
361
+
362
+ Returns:
363
+ Suggestion string or None.
364
+ """
365
+ msg = error.message.lower()
366
+
367
+ if "is not of type" in msg:
368
+ expected_type = error.schema.get("type", "unknown")
369
+ return f"Convert value to {expected_type}"
370
+
371
+ if "is not valid under any of the given schemas" in msg:
372
+ return "Check value matches one of the allowed formats"
373
+
374
+ if "is a required property" in msg:
375
+ return "Add the missing required field"
376
+
377
+ if "additional properties" in msg:
378
+ return "Remove unrecognized fields or use additionalProperties: true"
379
+
380
+ if "does not match" in msg:
381
+ pattern = error.schema.get("pattern")
382
+ if pattern:
383
+ return f"Value must match pattern: {pattern}"
384
+
385
+ return None
386
+
387
+
388
+ def _register_builtin_schemas(registry: SchemaRegistry) -> None:
389
+ """Register all built-in schemas.
390
+
391
+ Args:
392
+ registry: Registry to populate.
393
+ """
394
+ # Protocol definition schema
395
+ registry.register(
396
+ ConfigSchema(
397
+ name="protocol",
398
+ version="1.0.0",
399
+ description="Protocol decoder configuration",
400
+ schema={
401
+ "$schema": "http://json-schema.org/draft-07/schema#",
402
+ "type": "object",
403
+ "required": ["name"],
404
+ "properties": {
405
+ "name": {
406
+ "type": "string",
407
+ "description": "Protocol identifier",
408
+ "pattern": "^[a-z][a-z0-9_]*$",
409
+ },
410
+ "version": {
411
+ "type": "string",
412
+ "description": "Protocol version (semver)",
413
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
414
+ },
415
+ "description": {
416
+ "type": "string",
417
+ },
418
+ "author": {
419
+ "type": "string",
420
+ },
421
+ "timing": {
422
+ "type": "object",
423
+ "properties": {
424
+ "baud_rates": {
425
+ "type": "array",
426
+ "items": {"type": "integer", "minimum": 1},
427
+ },
428
+ "data_bits": {
429
+ "type": "array",
430
+ "items": {
431
+ "type": "integer",
432
+ "minimum": 1,
433
+ "maximum": 32,
434
+ },
435
+ },
436
+ "stop_bits": {
437
+ "type": "array",
438
+ "items": {
439
+ "type": "number",
440
+ "minimum": 0.5,
441
+ "maximum": 2,
442
+ },
443
+ },
444
+ "parity": {
445
+ "type": "array",
446
+ "items": {
447
+ "type": "string",
448
+ "enum": ["none", "even", "odd", "mark", "space"],
449
+ },
450
+ },
451
+ },
452
+ },
453
+ "voltage_levels": {
454
+ "type": "object",
455
+ "properties": {
456
+ "logic_family": {"type": "string"},
457
+ "idle_state": {"type": "string", "enum": ["high", "low"]},
458
+ "mark_voltage": {"type": "number"},
459
+ "space_voltage": {"type": "number"},
460
+ },
461
+ },
462
+ "state_machine": {
463
+ "type": "object",
464
+ "properties": {
465
+ "states": {
466
+ "type": "array",
467
+ "items": {"type": "string"},
468
+ },
469
+ "initial_state": {"type": "string"},
470
+ "transitions": {
471
+ "type": "array",
472
+ "items": {
473
+ "type": "object",
474
+ "required": ["from", "to", "condition"],
475
+ "properties": {
476
+ "from": {"type": "string"},
477
+ "to": {"type": "string"},
478
+ "condition": {"type": "string"},
479
+ },
480
+ },
481
+ },
482
+ },
483
+ },
484
+ },
485
+ "additionalProperties": True,
486
+ },
487
+ )
488
+ )
489
+
490
+ # Pipeline definition schema
491
+ registry.register(
492
+ ConfigSchema(
493
+ name="pipeline",
494
+ version="1.0.0",
495
+ description="Analysis pipeline configuration",
496
+ schema={
497
+ "$schema": "http://json-schema.org/draft-07/schema#",
498
+ "type": "object",
499
+ "required": ["name", "steps"],
500
+ "properties": {
501
+ "name": {
502
+ "type": "string",
503
+ "description": "Pipeline identifier",
504
+ },
505
+ "version": {
506
+ "type": "string",
507
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
508
+ },
509
+ "description": {
510
+ "type": "string",
511
+ },
512
+ "steps": {
513
+ "type": "array",
514
+ "minItems": 1,
515
+ "items": {
516
+ "type": "object",
517
+ "required": ["name", "type"],
518
+ "properties": {
519
+ "name": {"type": "string"},
520
+ "type": {"type": "string"},
521
+ "params": {"type": "object"},
522
+ "inputs": {"type": "object"},
523
+ "outputs": {"type": "object"},
524
+ },
525
+ },
526
+ },
527
+ "parallel_groups": {
528
+ "type": "array",
529
+ "items": {
530
+ "type": "array",
531
+ "items": {"type": "string"},
532
+ },
533
+ },
534
+ },
535
+ },
536
+ )
537
+ )
538
+
539
+ # Logic family schema
540
+ registry.register(
541
+ ConfigSchema(
542
+ name="logic_family",
543
+ version="1.0.0",
544
+ description="Logic family voltage thresholds",
545
+ schema={
546
+ "$schema": "http://json-schema.org/draft-07/schema#",
547
+ "type": "object",
548
+ "required": ["name", "VIH", "VIL", "VOH", "VOL"],
549
+ "properties": {
550
+ "name": {
551
+ "type": "string",
552
+ "description": "Logic family name",
553
+ },
554
+ "description": {
555
+ "type": "string",
556
+ },
557
+ "VIH": {
558
+ "type": "number",
559
+ "description": "Input high voltage threshold (V)",
560
+ "minimum": 0,
561
+ "maximum": 10,
562
+ },
563
+ "VIL": {
564
+ "type": "number",
565
+ "description": "Input low voltage threshold (V)",
566
+ "minimum": 0,
567
+ "maximum": 10,
568
+ },
569
+ "VOH": {
570
+ "type": "number",
571
+ "description": "Output high voltage (V)",
572
+ "minimum": 0,
573
+ "maximum": 10,
574
+ },
575
+ "VOL": {
576
+ "type": "number",
577
+ "description": "Output low voltage (V)",
578
+ "minimum": 0,
579
+ "maximum": 10,
580
+ },
581
+ "VCC": {
582
+ "type": "number",
583
+ "description": "Supply voltage (V)",
584
+ "minimum": 0,
585
+ "maximum": 15,
586
+ },
587
+ "temperature_range": {
588
+ "type": "object",
589
+ "properties": {
590
+ "min": {"type": "number"},
591
+ "max": {"type": "number"},
592
+ },
593
+ },
594
+ "noise_margin_high": {
595
+ "type": "number",
596
+ "description": "High state noise margin (V)",
597
+ },
598
+ "noise_margin_low": {
599
+ "type": "number",
600
+ "description": "Low state noise margin (V)",
601
+ },
602
+ },
603
+ },
604
+ )
605
+ )
606
+
607
+ # Threshold profile schema
608
+ registry.register(
609
+ ConfigSchema(
610
+ name="threshold_profile",
611
+ version="1.0.0",
612
+ description="Analysis threshold profile",
613
+ schema={
614
+ "$schema": "http://json-schema.org/draft-07/schema#",
615
+ "type": "object",
616
+ "required": ["name"],
617
+ "properties": {
618
+ "name": {
619
+ "type": "string",
620
+ },
621
+ "description": {
622
+ "type": "string",
623
+ },
624
+ "base_family": {
625
+ "type": "string",
626
+ "description": "Base logic family to extend",
627
+ },
628
+ "overrides": {
629
+ "type": "object",
630
+ "additionalProperties": {"type": "number"},
631
+ },
632
+ "tolerance": {
633
+ "type": "number",
634
+ "description": "Tolerance percentage (0-100)",
635
+ "minimum": 0,
636
+ "maximum": 100,
637
+ "default": 0,
638
+ },
639
+ },
640
+ },
641
+ )
642
+ )
643
+
644
+ # Preferences schema
645
+ registry.register(
646
+ ConfigSchema(
647
+ name="preferences",
648
+ version="1.0.0",
649
+ description="User preferences",
650
+ schema={
651
+ "$schema": "http://json-schema.org/draft-07/schema#",
652
+ "type": "object",
653
+ "properties": {
654
+ "defaults": {
655
+ "type": "object",
656
+ "properties": {
657
+ "sample_rate": {"type": "number", "minimum": 0},
658
+ "window_function": {"type": "string"},
659
+ "fft_size": {"type": "integer", "minimum": 1},
660
+ },
661
+ },
662
+ "visualization": {
663
+ "type": "object",
664
+ "properties": {
665
+ "style": {"type": "string"},
666
+ "figure_size": {
667
+ "type": "array",
668
+ "items": {"type": "number"},
669
+ "minItems": 2,
670
+ "maxItems": 2,
671
+ },
672
+ "dpi": {"type": "integer", "minimum": 50, "maximum": 600},
673
+ "colormap": {"type": "string"},
674
+ },
675
+ },
676
+ "export": {
677
+ "type": "object",
678
+ "properties": {
679
+ "default_format": {
680
+ "type": "string",
681
+ "enum": ["csv", "hdf5", "npz", "json"],
682
+ },
683
+ "precision": {
684
+ "type": "integer",
685
+ "minimum": 1,
686
+ "maximum": 15,
687
+ },
688
+ },
689
+ },
690
+ "logging": {
691
+ "type": "object",
692
+ "properties": {
693
+ "level": {
694
+ "type": "string",
695
+ "enum": ["DEBUG", "INFO", "WARNING", "ERROR"],
696
+ },
697
+ "file": {"type": "string"},
698
+ },
699
+ },
700
+ },
701
+ },
702
+ )
703
+ )
704
+
705
+
706
+ __all__ = [
707
+ "ConfigSchema",
708
+ "SchemaRegistry",
709
+ "ValidationError",
710
+ "get_schema_registry",
711
+ "register_schema",
712
+ "validate_against_schema",
713
+ ]