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,724 @@
1
+ """Template system for TraceKit reports.
2
+
3
+ This module provides template loading, management, inheritance, and built-in
4
+ report templates.
5
+
6
+
7
+ Example:
8
+ >>> from oscura.reporting.template_system import load_template, register_template
9
+ >>> template = load_template("compliance")
10
+ >>> # Create custom template extending compliance
11
+ >>> custom = load_template("compliance")
12
+ >>> register_template("my_compliance", custom)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import copy
18
+ from dataclasses import dataclass, field
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ import yaml
23
+
24
+
25
+ @dataclass
26
+ class TemplateSection:
27
+ """A section definition in a template.
28
+
29
+ Attributes:
30
+ title: Section title.
31
+ content_type: Type of content (text, table, figure, measurement).
32
+ condition: Conditional expression for inclusion.
33
+ template: Jinja2 template for content.
34
+ subsections: Child sections.
35
+ order: Section order (for sorting during inheritance merge).
36
+ override: If True, replaces parent section with same title.
37
+
38
+ References:
39
+ REPORT-007: Template Definition Format
40
+ """
41
+
42
+ title: str
43
+ content_type: str = "text"
44
+ condition: str | None = None
45
+ template: str = ""
46
+ subsections: list[TemplateSection] = field(default_factory=list)
47
+ order: int = 0
48
+ override: bool = False
49
+
50
+
51
+ @dataclass
52
+ class ReportTemplate:
53
+ """A report template definition.
54
+
55
+ Attributes:
56
+ name: Template name.
57
+ version: Template version.
58
+ description: Template description.
59
+ author: Template author.
60
+ extends: Parent template name for inheritance (REPORT-005).
61
+ sections: Template sections.
62
+ styles: Style definitions.
63
+ metadata: Additional metadata.
64
+ overrides: Section-specific overrides (REPORT-008).
65
+
66
+ References:
67
+ REPORT-005: Template Inheritance
68
+ REPORT-007: Template Definition Format
69
+ REPORT-008: Template Overrides
70
+ """
71
+
72
+ name: str
73
+ version: str = "1.0"
74
+ description: str = ""
75
+ author: str = ""
76
+ extends: str | None = None
77
+ sections: list[TemplateSection] = field(default_factory=list)
78
+ styles: dict[str, Any] = field(default_factory=dict)
79
+ metadata: dict[str, Any] = field(default_factory=dict)
80
+ overrides: dict[str, dict[str, Any]] = field(default_factory=dict)
81
+
82
+
83
+ # Built-in templates
84
+ BUILTIN_TEMPLATES: dict[str, ReportTemplate] = {
85
+ "default": ReportTemplate(
86
+ name="Default Report",
87
+ version="1.0",
88
+ description="Standard analysis report template",
89
+ sections=[
90
+ TemplateSection(
91
+ title="Executive Summary",
92
+ content_type="text",
93
+ template="{{ summary }}",
94
+ order=0,
95
+ ),
96
+ TemplateSection(
97
+ title="Test Results",
98
+ content_type="table",
99
+ template="{{ results_table }}",
100
+ order=10,
101
+ ),
102
+ TemplateSection(
103
+ title="Methodology",
104
+ content_type="text",
105
+ condition="verbosity != 'executive'",
106
+ order=20,
107
+ ),
108
+ ],
109
+ ),
110
+ "compliance": ReportTemplate(
111
+ name="Compliance Report",
112
+ version="1.0",
113
+ description="Regulatory compliance testing report",
114
+ extends="default",
115
+ sections=[
116
+ TemplateSection(
117
+ title="Executive Summary",
118
+ content_type="text",
119
+ template="{{ compliance_summary }}",
120
+ override=True,
121
+ order=0,
122
+ ),
123
+ TemplateSection(
124
+ title="Test Standards",
125
+ content_type="text",
126
+ template="Standards tested: {{ standards }}",
127
+ order=5,
128
+ ),
129
+ TemplateSection(
130
+ title="Violations",
131
+ content_type="table",
132
+ condition="has_violations",
133
+ order=15,
134
+ ),
135
+ TemplateSection(
136
+ title="Certificate",
137
+ content_type="text",
138
+ order=30,
139
+ ),
140
+ ],
141
+ ),
142
+ "characterization": ReportTemplate(
143
+ name="Characterization Report",
144
+ version="1.0",
145
+ description="Device characterization report",
146
+ sections=[
147
+ TemplateSection(
148
+ title="Summary",
149
+ content_type="text",
150
+ order=0,
151
+ ),
152
+ TemplateSection(
153
+ title="Timing Parameters",
154
+ content_type="table",
155
+ order=10,
156
+ ),
157
+ TemplateSection(
158
+ title="Signal Quality",
159
+ content_type="table",
160
+ order=20,
161
+ ),
162
+ TemplateSection(
163
+ title="Margin Analysis",
164
+ content_type="table",
165
+ order=30,
166
+ ),
167
+ TemplateSection(
168
+ title="Waveform Plots",
169
+ content_type="figure",
170
+ order=40,
171
+ ),
172
+ ],
173
+ ),
174
+ "debug": ReportTemplate(
175
+ name="Debug Report",
176
+ version="1.0",
177
+ description="Detailed debug report with full data",
178
+ sections=[
179
+ TemplateSection(
180
+ title="Summary",
181
+ content_type="text",
182
+ order=0,
183
+ ),
184
+ TemplateSection(
185
+ title="Error Analysis",
186
+ content_type="text",
187
+ order=10,
188
+ ),
189
+ TemplateSection(
190
+ title="Protocol Decode",
191
+ content_type="table",
192
+ order=20,
193
+ ),
194
+ TemplateSection(
195
+ title="Timing Diagram",
196
+ content_type="figure",
197
+ order=30,
198
+ ),
199
+ TemplateSection(
200
+ title="Raw Data",
201
+ content_type="text",
202
+ order=40,
203
+ ),
204
+ TemplateSection(
205
+ title="Provenance",
206
+ content_type="text",
207
+ order=50,
208
+ ),
209
+ ],
210
+ ),
211
+ "production": ReportTemplate(
212
+ name="Production Report",
213
+ version="1.0",
214
+ description="Production test report with pass/fail and yield",
215
+ sections=[
216
+ TemplateSection(
217
+ title="Test Summary",
218
+ content_type="text",
219
+ template="Tested: {{ total }} | Passed: {{ passed }} | Failed: {{ failed }}",
220
+ order=0,
221
+ ),
222
+ TemplateSection(
223
+ title="Results",
224
+ content_type="table",
225
+ order=10,
226
+ ),
227
+ TemplateSection(
228
+ title="Yield Analysis",
229
+ content_type="table",
230
+ order=20,
231
+ ),
232
+ ],
233
+ ),
234
+ "comparison": ReportTemplate(
235
+ name="Comparison Report",
236
+ version="1.0",
237
+ description="Before/after comparison report",
238
+ sections=[
239
+ TemplateSection(
240
+ title="Summary",
241
+ content_type="text",
242
+ order=0,
243
+ ),
244
+ TemplateSection(
245
+ title="Differences",
246
+ content_type="table",
247
+ order=10,
248
+ ),
249
+ TemplateSection(
250
+ title="Side-by-Side Comparison",
251
+ content_type="figure",
252
+ order=20,
253
+ ),
254
+ ],
255
+ ),
256
+ }
257
+
258
+ # User-registered templates (REPORT-006)
259
+ _USER_TEMPLATES: dict[str, ReportTemplate] = {}
260
+
261
+
262
+ def register_template(
263
+ name: str,
264
+ template: ReportTemplate,
265
+ *,
266
+ overwrite: bool = False,
267
+ ) -> None:
268
+ """Register a user template.
269
+
270
+ Allows users to define custom templates or extend built-in ones.
271
+
272
+ Args:
273
+ name: Template name for registration.
274
+ template: Template definition.
275
+ overwrite: If True, allows overwriting existing templates.
276
+
277
+ Raises:
278
+ ValueError: If name exists and overwrite=False.
279
+
280
+ Example:
281
+ >>> from oscura.reporting.template_system import (
282
+ ... register_template, ReportTemplate, TemplateSection
283
+ ... )
284
+ >>> my_template = ReportTemplate(
285
+ ... name="Custom Report",
286
+ ... sections=[TemplateSection(title="My Section")]
287
+ ... )
288
+ >>> register_template("custom", my_template)
289
+
290
+ References:
291
+ REPORT-006: User Template Registration
292
+ """
293
+ if name in _USER_TEMPLATES and not overwrite:
294
+ raise ValueError(f"Template '{name}' already registered. Use overwrite=True to replace.")
295
+
296
+ if name in BUILTIN_TEMPLATES and not overwrite:
297
+ raise ValueError(f"Cannot overwrite built-in template '{name}'. Use overwrite=True.")
298
+
299
+ _USER_TEMPLATES[name] = template
300
+
301
+
302
+ def unregister_template(name: str) -> bool:
303
+ """Unregister a user template.
304
+
305
+ Args:
306
+ name: Template name.
307
+
308
+ Returns:
309
+ True if template was removed, False if not found.
310
+
311
+ References:
312
+ REPORT-006: User Template Registration
313
+ """
314
+ if name in _USER_TEMPLATES:
315
+ del _USER_TEMPLATES[name]
316
+ return True
317
+ return False
318
+
319
+
320
+ def extend_template(
321
+ base_name: str,
322
+ *,
323
+ name: str | None = None,
324
+ description: str | None = None,
325
+ add_sections: list[TemplateSection] | None = None,
326
+ remove_sections: list[str] | None = None,
327
+ section_overrides: dict[str, dict[str, Any]] | None = None,
328
+ style_overrides: dict[str, Any] | None = None,
329
+ ) -> ReportTemplate:
330
+ """Create a new template by extending an existing one.
331
+
332
+ Implements template inheritance with section merging and overrides.
333
+
334
+ Args:
335
+ base_name: Name of template to extend.
336
+ name: Name for new template.
337
+ description: Description for new template.
338
+ add_sections: New sections to add.
339
+ remove_sections: Section titles to remove.
340
+ section_overrides: Dict of section title -> field overrides.
341
+ style_overrides: Style fields to override.
342
+
343
+ Returns:
344
+ New ReportTemplate with inherited and modified sections.
345
+
346
+ Example:
347
+ >>> # Create custom compliance template
348
+ >>> custom = extend_template(
349
+ ... "compliance",
350
+ ... name="FDA Compliance",
351
+ ... add_sections=[TemplateSection(title="FDA Requirements")],
352
+ ... section_overrides={
353
+ ... "Certificate": {"template": "FDA Certificate: {{ cert_id }}"}
354
+ ... }
355
+ ... )
356
+
357
+ References:
358
+ REPORT-005: Template Inheritance
359
+ REPORT-008: Template Overrides
360
+ """
361
+ # Load base template (resolving inheritance chain)
362
+ base = load_template(base_name)
363
+
364
+ # Deep copy to avoid modifying original
365
+ new_template = copy.deepcopy(base)
366
+
367
+ # Update metadata
368
+ if name:
369
+ new_template.name = name
370
+ if description:
371
+ new_template.description = description
372
+ new_template.extends = base_name
373
+
374
+ # Apply section removals
375
+ if remove_sections:
376
+ new_template.sections = [
377
+ sec for sec in new_template.sections if sec.title not in remove_sections
378
+ ]
379
+
380
+ # Apply section overrides
381
+ if section_overrides:
382
+ for sec in new_template.sections:
383
+ if sec.title in section_overrides:
384
+ overrides = section_overrides[sec.title]
385
+ for field_name, value in overrides.items():
386
+ if hasattr(sec, field_name):
387
+ setattr(sec, field_name, value)
388
+
389
+ # Add new sections
390
+ if add_sections:
391
+ new_template.sections.extend(add_sections)
392
+
393
+ # Sort sections by order
394
+ new_template.sections.sort(key=lambda s: s.order)
395
+
396
+ # Apply style overrides
397
+ if style_overrides:
398
+ new_template.styles.update(style_overrides)
399
+
400
+ return new_template
401
+
402
+
403
+ def _resolve_inheritance(
404
+ template: ReportTemplate, visited: set[str] | None = None
405
+ ) -> ReportTemplate:
406
+ """Resolve template inheritance chain.
407
+
408
+ Args:
409
+ template: Template to resolve.
410
+ visited: Set of already visited template names (for cycle detection).
411
+
412
+ Returns:
413
+ Template with all inherited sections merged.
414
+
415
+ Raises:
416
+ ValueError: If circular inheritance detected.
417
+
418
+ References:
419
+ REPORT-005: Template Inheritance
420
+ """
421
+ if visited is None:
422
+ visited = set()
423
+
424
+ if template.name in visited:
425
+ raise ValueError(f"Circular template inheritance detected: {template.name}")
426
+
427
+ if not template.extends:
428
+ return template
429
+
430
+ visited.add(template.name)
431
+
432
+ # Get parent template
433
+ parent_name = template.extends
434
+ if parent_name in _USER_TEMPLATES:
435
+ parent = copy.deepcopy(_USER_TEMPLATES[parent_name])
436
+ elif parent_name in BUILTIN_TEMPLATES:
437
+ parent = copy.deepcopy(BUILTIN_TEMPLATES[parent_name])
438
+ else:
439
+ raise ValueError(f"Parent template not found: {parent_name}")
440
+
441
+ # Recursively resolve parent inheritance
442
+ parent = _resolve_inheritance(parent, visited)
443
+
444
+ # Merge sections
445
+ # Child sections with override=True replace parent sections with same title
446
+ parent_sections = {sec.title: sec for sec in parent.sections}
447
+
448
+ for child_sec in template.sections:
449
+ if child_sec.override or child_sec.title in parent_sections:
450
+ # Override or replace parent section
451
+ parent_sections[child_sec.title] = child_sec
452
+ else:
453
+ # Add new section
454
+ parent_sections[child_sec.title] = child_sec
455
+
456
+ # Sort by order
457
+ merged_sections = sorted(parent_sections.values(), key=lambda s: s.order)
458
+
459
+ # Merge styles (child overrides parent)
460
+ merged_styles = {**parent.styles, **template.styles}
461
+
462
+ # Merge metadata
463
+ merged_metadata = {**parent.metadata, **template.metadata}
464
+
465
+ return ReportTemplate(
466
+ name=template.name,
467
+ version=template.version,
468
+ description=template.description or parent.description,
469
+ author=template.author or parent.author,
470
+ extends=template.extends,
471
+ sections=merged_sections,
472
+ styles=merged_styles,
473
+ metadata=merged_metadata,
474
+ overrides=template.overrides,
475
+ )
476
+
477
+
478
+ def load_template(name_or_path: str, *, resolve_inheritance: bool = True) -> ReportTemplate:
479
+ """Load a report template.
480
+
481
+ Args:
482
+ name_or_path: Template name (builtin or registered) or path to YAML file.
483
+ resolve_inheritance: If True, resolve template inheritance chain.
484
+
485
+ Returns:
486
+ ReportTemplate instance.
487
+
488
+ Raises:
489
+ ValueError: If template not found.
490
+
491
+ Example:
492
+ >>> template = load_template("compliance")
493
+ >>> template = load_template("custom_template.yaml")
494
+
495
+ References:
496
+ REPORT-005: Template Inheritance
497
+ REPORT-006: User Template Registration
498
+ """
499
+ template = None
500
+
501
+ # Check user-registered templates first (REPORT-006)
502
+ if name_or_path in _USER_TEMPLATES:
503
+ template = copy.deepcopy(_USER_TEMPLATES[name_or_path])
504
+ # Then check builtin templates
505
+ elif name_or_path in BUILTIN_TEMPLATES:
506
+ template = copy.deepcopy(BUILTIN_TEMPLATES[name_or_path])
507
+ else:
508
+ # Try loading from file
509
+ path = Path(name_or_path)
510
+ if path.exists():
511
+ template = _load_template_file(path)
512
+ else:
513
+ # Try adding .yaml extension
514
+ yaml_path = Path(f"{name_or_path}.yaml")
515
+ if yaml_path.exists():
516
+ template = _load_template_file(yaml_path)
517
+
518
+ if template is None:
519
+ raise ValueError(f"Template not found: {name_or_path}")
520
+
521
+ # Resolve inheritance if requested (REPORT-005)
522
+ if resolve_inheritance and template.extends:
523
+ template = _resolve_inheritance(template)
524
+
525
+ return template
526
+
527
+
528
+ def _load_template_file(path: Path) -> ReportTemplate:
529
+ """Load template from YAML file.
530
+
531
+ Args:
532
+ path: Path to template YAML file.
533
+
534
+ Returns:
535
+ ReportTemplate instance loaded from file.
536
+
537
+ References:
538
+ REPORT-007: Template Definition Format
539
+ """
540
+ with open(path) as f:
541
+ data = yaml.safe_load(f)
542
+
543
+ template_data = data.get("template", data)
544
+
545
+ sections = []
546
+ for idx, sec_data in enumerate(template_data.get("sections", [])):
547
+ section = TemplateSection(
548
+ title=sec_data.get("title", ""),
549
+ content_type=sec_data.get("content_type", "text"),
550
+ condition=sec_data.get("condition"),
551
+ template=sec_data.get("template", sec_data.get("content", "")),
552
+ order=sec_data.get("order", idx * 10),
553
+ override=sec_data.get("override", False),
554
+ )
555
+ sections.append(section)
556
+
557
+ return ReportTemplate(
558
+ name=template_data.get("name", path.stem),
559
+ version=template_data.get("version", "1.0"),
560
+ description=template_data.get("description", ""),
561
+ author=template_data.get("author", ""),
562
+ extends=template_data.get("extends"),
563
+ sections=sections,
564
+ styles=template_data.get("styles", {}),
565
+ metadata=template_data.get("metadata", {}),
566
+ overrides=template_data.get("overrides", {}),
567
+ )
568
+
569
+
570
+ def list_templates(*, include_user: bool = True) -> list[str]:
571
+ """List available template names.
572
+
573
+ Args:
574
+ include_user: Include user-registered templates.
575
+
576
+ Returns:
577
+ List of template names.
578
+
579
+ References:
580
+ REPORT-006: User Template Registration
581
+ """
582
+ names = list(BUILTIN_TEMPLATES.keys())
583
+ if include_user:
584
+ names.extend(_USER_TEMPLATES.keys())
585
+ return sorted(set(names))
586
+
587
+
588
+ def get_template_info(name: str) -> dict[str, Any]:
589
+ """Get information about a template.
590
+
591
+ Args:
592
+ name: Template name.
593
+
594
+ Returns:
595
+ Dictionary with template info.
596
+
597
+ Raises:
598
+ ValueError: If template name unknown.
599
+
600
+ References:
601
+ REPORT-005: Template Inheritance
602
+ REPORT-006: User Template Registration
603
+ """
604
+ if name in _USER_TEMPLATES:
605
+ template = _USER_TEMPLATES[name]
606
+ source = "user"
607
+ elif name in BUILTIN_TEMPLATES:
608
+ template = BUILTIN_TEMPLATES[name]
609
+ source = "builtin"
610
+ else:
611
+ raise ValueError(f"Unknown template: {name}")
612
+
613
+ return {
614
+ "name": template.name,
615
+ "version": template.version,
616
+ "description": template.description,
617
+ "author": template.author,
618
+ "extends": template.extends,
619
+ "num_sections": len(template.sections),
620
+ "section_titles": [sec.title for sec in template.sections],
621
+ "source": source,
622
+ }
623
+
624
+
625
+ def save_template(template: ReportTemplate, path: str | Path) -> None:
626
+ """Save template to YAML file.
627
+
628
+ Args:
629
+ template: Template to save.
630
+ path: Output file path.
631
+
632
+ References:
633
+ REPORT-007: Template Definition Format
634
+ """
635
+ path = Path(path)
636
+
637
+ data = {
638
+ "template": {
639
+ "name": template.name,
640
+ "version": template.version,
641
+ "description": template.description,
642
+ "author": template.author,
643
+ "extends": template.extends,
644
+ "sections": [
645
+ {
646
+ "title": sec.title,
647
+ "content_type": sec.content_type,
648
+ "condition": sec.condition,
649
+ "template": sec.template,
650
+ "order": sec.order,
651
+ "override": sec.override,
652
+ }
653
+ for sec in template.sections
654
+ ],
655
+ "styles": template.styles,
656
+ "metadata": template.metadata,
657
+ "overrides": template.overrides,
658
+ }
659
+ }
660
+
661
+ with open(path, "w") as f:
662
+ yaml.dump(data, f, default_flow_style=False, sort_keys=False)
663
+
664
+
665
+ def create_template(
666
+ name: str,
667
+ sections: list[TemplateSection],
668
+ *,
669
+ extends: str | None = None,
670
+ description: str = "",
671
+ author: str = "",
672
+ styles: dict[str, Any] | None = None,
673
+ ) -> ReportTemplate:
674
+ """Create a new template.
675
+
676
+ Convenience function for creating templates programmatically.
677
+
678
+ Args:
679
+ name: Template name.
680
+ sections: List of sections.
681
+ extends: Parent template name for inheritance.
682
+ description: Template description.
683
+ author: Template author.
684
+ styles: Style definitions.
685
+
686
+ Returns:
687
+ New ReportTemplate.
688
+
689
+ Example:
690
+ >>> template = create_template(
691
+ ... "quick_report",
692
+ ... sections=[
693
+ ... TemplateSection(title="Summary", template="{{ summary }}"),
694
+ ... TemplateSection(title="Results", content_type="table"),
695
+ ... ],
696
+ ... description="Quick summary report"
697
+ ... )
698
+
699
+ References:
700
+ REPORT-007: Template Definition Format
701
+ """
702
+ return ReportTemplate(
703
+ name=name,
704
+ description=description,
705
+ author=author,
706
+ extends=extends,
707
+ sections=sections,
708
+ styles=styles or {},
709
+ )
710
+
711
+
712
+ __all__ = [
713
+ "BUILTIN_TEMPLATES",
714
+ "ReportTemplate",
715
+ "TemplateSection",
716
+ "create_template",
717
+ "extend_template",
718
+ "get_template_info",
719
+ "list_templates",
720
+ "load_template",
721
+ "register_template",
722
+ "save_template",
723
+ "unregister_template",
724
+ ]