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,535 @@
1
+ """Oscura exception hierarchy with helpful error messages.
2
+
3
+ This module provides custom exception classes that follow a consistent
4
+ template for error messages: WHAT, WHY, HOW TO FIX, DOCUMENTATION LINK.
5
+
6
+
7
+ Example:
8
+ >>> try:
9
+ ... raise UnsupportedFormatError(".xyz", ["wfm", "csv", "npz"])
10
+ ... except UnsupportedFormatError as e:
11
+ ... print(e)
12
+ Unsupported file format: .xyz
13
+ ...
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Any
19
+
20
+ # Documentation base URL
21
+ # Points to GitHub repository docs directory as primary documentation source.
22
+ # Update this when official documentation hosting is configured (e.g., ReadTheDocs).
23
+ #
24
+ # To verify/update this URL:
25
+ # 1. Check if https://oscura.readthedocs.io exists and is active
26
+ # 2. If not, use GitHub repository docs: https://github.com/lair-click-bats/oscura/tree/main/docs
27
+ # 3. Or local docs path for development: file:///path/to/docs/
28
+ DOCS_BASE_URL = "https://github.com/lair-click-bats/oscura/tree/main/docs"
29
+
30
+
31
+ class OscuraError(Exception):
32
+ """Base exception for all Oscura errors.
33
+
34
+ All Oscura exceptions inherit from this class, providing a
35
+ consistent interface for error handling.
36
+
37
+ Attributes:
38
+ message: Brief description of the error.
39
+ details: Additional context about the error.
40
+ fix_hint: Suggestion for how to fix the error.
41
+ docs_path: Path to relevant documentation.
42
+
43
+ Example:
44
+ >>> raise OscuraError("Something went wrong")
45
+ OscuraError: Something went wrong
46
+ """
47
+
48
+ docs_path: str = "errors"
49
+
50
+ def __init__(
51
+ self,
52
+ message: str,
53
+ *,
54
+ details: str | None = None,
55
+ fix_hint: str | None = None,
56
+ docs_path: str | None = None,
57
+ ) -> None:
58
+ """Initialize OscuraError.
59
+
60
+ Args:
61
+ message: Brief description of the error.
62
+ details: Additional context about what caused the error.
63
+ fix_hint: Suggestion for how to fix the error.
64
+ docs_path: Path to relevant documentation (appended to base URL).
65
+ """
66
+ self.message = message
67
+ self.details = details
68
+ self.fix_hint = fix_hint
69
+ if docs_path is not None:
70
+ self.docs_path = docs_path
71
+ super().__init__(self._format_message())
72
+
73
+ def _format_message(self) -> str:
74
+ """Format the full error message with template.
75
+
76
+ Returns:
77
+ Formatted error message with WHAT, WHY, HOW TO FIX, DOCS.
78
+ """
79
+ parts = [self.message]
80
+
81
+ if self.details:
82
+ parts.append(f"Details: {self.details}")
83
+
84
+ if self.fix_hint:
85
+ parts.append(f"Fix: {self.fix_hint}")
86
+
87
+ parts.append(f"Docs: {DOCS_BASE_URL}/{self.docs_path}")
88
+
89
+ return "\n".join(parts)
90
+
91
+
92
+ class LoaderError(OscuraError):
93
+ """Error loading trace data from file.
94
+
95
+ Raised when a file cannot be read, parsed, or converted to
96
+ a Oscura data structure.
97
+
98
+ Attributes:
99
+ file_path: Path to the file that failed to load.
100
+ """
101
+
102
+ docs_path: str = "errors#loader"
103
+
104
+ def __init__(
105
+ self,
106
+ message: str,
107
+ *,
108
+ file_path: str | None = None,
109
+ details: str | None = None,
110
+ fix_hint: str | None = None,
111
+ ) -> None:
112
+ """Initialize LoaderError.
113
+
114
+ Args:
115
+ message: Brief description of the error.
116
+ file_path: Path to the file that failed to load.
117
+ details: Additional context about the error.
118
+ fix_hint: Suggestion for how to fix the error.
119
+ """
120
+ self.file_path = file_path
121
+ if file_path and not details:
122
+ details = f"File: {file_path}"
123
+ elif file_path and details:
124
+ details = f"File: {file_path}. {details}"
125
+ super().__init__(
126
+ message,
127
+ details=details,
128
+ fix_hint=fix_hint,
129
+ docs_path=self.docs_path,
130
+ )
131
+
132
+
133
+ class UnsupportedFormatError(LoaderError):
134
+ """File format not recognized or unsupported.
135
+
136
+ Raised when attempting to load a file with an unsupported
137
+ extension or format.
138
+
139
+ Attributes:
140
+ format_ext: The unsupported format extension.
141
+ supported_formats: List of supported format extensions.
142
+ """
143
+
144
+ docs_path: str = "errors#unsupported-format"
145
+
146
+ def __init__(
147
+ self,
148
+ format_ext: str,
149
+ supported_formats: list[str] | None = None,
150
+ *,
151
+ file_path: str | None = None,
152
+ ) -> None:
153
+ """Initialize UnsupportedFormatError.
154
+
155
+ Args:
156
+ format_ext: The unsupported format extension (e.g., ".xyz").
157
+ supported_formats: List of supported format extensions.
158
+ file_path: Path to the file that failed to load.
159
+ """
160
+ self.format_ext = format_ext
161
+ self.supported_formats = supported_formats or []
162
+
163
+ message = f"Unsupported file format: {format_ext}"
164
+
165
+ if self.supported_formats:
166
+ formats_str = ", ".join(self.supported_formats)
167
+ details = f"Supported formats: {formats_str}"
168
+ else:
169
+ details = None
170
+
171
+ fix_hint = "Convert the file to a supported format or use a custom loader."
172
+
173
+ super().__init__(
174
+ message,
175
+ file_path=file_path,
176
+ details=details,
177
+ fix_hint=fix_hint,
178
+ )
179
+
180
+
181
+ class FormatError(LoaderError):
182
+ """File format is invalid or corrupted.
183
+
184
+ Raised when a file has the correct extension but invalid content.
185
+ """
186
+
187
+ docs_path: str = "errors#format-error"
188
+
189
+ def __init__(
190
+ self,
191
+ message: str,
192
+ *,
193
+ file_path: str | None = None,
194
+ expected: str | None = None,
195
+ got: str | None = None,
196
+ details: str | None = None,
197
+ fix_hint: str | None = None,
198
+ ) -> None:
199
+ """Initialize FormatError.
200
+
201
+ Args:
202
+ message: Brief description of the error.
203
+ file_path: Path to the file that failed to load.
204
+ expected: What was expected in the file.
205
+ got: What was actually found.
206
+ details: Additional context about the error (overrides expected/got).
207
+ fix_hint: Suggestion for how to fix the error.
208
+ """
209
+ # Build details from expected/got if not provided directly
210
+ if details is None:
211
+ if expected and got:
212
+ details = f"Expected: {expected}. Got: {got}"
213
+ elif expected:
214
+ details = f"Expected: {expected}"
215
+ elif got:
216
+ details = f"Found: {got}"
217
+
218
+ # Use default fix_hint if not provided
219
+ if fix_hint is None:
220
+ fix_hint = "Verify the file is not corrupted and matches the expected format."
221
+
222
+ super().__init__(
223
+ message,
224
+ file_path=file_path,
225
+ details=details,
226
+ fix_hint=fix_hint,
227
+ )
228
+
229
+
230
+ class AnalysisError(OscuraError):
231
+ """Error during signal analysis.
232
+
233
+ Raised when an analysis function encounters invalid data
234
+ or cannot compute a result.
235
+ """
236
+
237
+ docs_path: str = "errors#analysis"
238
+
239
+ def __init__(
240
+ self,
241
+ message: str,
242
+ *,
243
+ analysis_type: str | None = None,
244
+ details: str | None = None,
245
+ fix_hint: str | None = None,
246
+ ) -> None:
247
+ """Initialize AnalysisError.
248
+
249
+ Args:
250
+ message: Brief description of the error.
251
+ analysis_type: Type of analysis that failed (e.g., "rise_time").
252
+ details: Additional context about the error.
253
+ fix_hint: Suggestion for how to fix the error.
254
+ """
255
+ self.analysis_type = analysis_type
256
+ if analysis_type and not details:
257
+ details = f"Analysis: {analysis_type}"
258
+ elif analysis_type and details:
259
+ details = f"Analysis: {analysis_type}. {details}"
260
+ super().__init__(
261
+ message,
262
+ details=details,
263
+ fix_hint=fix_hint,
264
+ docs_path=self.docs_path,
265
+ )
266
+
267
+
268
+ class InsufficientDataError(AnalysisError):
269
+ """Not enough data points for the requested analysis.
270
+
271
+ Raised when a signal is too short or lacks sufficient
272
+ features (edges, periods, etc.) for analysis.
273
+
274
+ Attributes:
275
+ required: Minimum data points or features required.
276
+ available: Actual data points or features available.
277
+ """
278
+
279
+ docs_path: str = "errors#insufficient-data"
280
+
281
+ def __init__(
282
+ self,
283
+ message: str,
284
+ *,
285
+ required: int | None = None,
286
+ available: int | None = None,
287
+ analysis_type: str | None = None,
288
+ ) -> None:
289
+ """Initialize InsufficientDataError.
290
+
291
+ Args:
292
+ message: Brief description of the error.
293
+ required: Minimum number of samples or features required.
294
+ available: Actual number available.
295
+ analysis_type: Type of analysis that failed.
296
+ """
297
+ self.required = required
298
+ self.available = available
299
+
300
+ details = None
301
+ if required is not None and available is not None:
302
+ details = f"Required: {required}. Available: {available}"
303
+ elif required is not None:
304
+ details = f"Minimum required: {required}"
305
+
306
+ fix_hint = "Acquire more data or reduce analysis window."
307
+
308
+ super().__init__(
309
+ message,
310
+ analysis_type=analysis_type,
311
+ details=details,
312
+ fix_hint=fix_hint,
313
+ )
314
+
315
+
316
+ class SampleRateError(AnalysisError):
317
+ """Invalid or missing sample rate.
318
+
319
+ Raised when sample rate is invalid (zero, negative) or
320
+ insufficient for the requested analysis.
321
+
322
+ Attributes:
323
+ required_rate: Minimum sample rate required.
324
+ actual_rate: Actual sample rate provided.
325
+ """
326
+
327
+ docs_path: str = "errors#sample-rate"
328
+
329
+ def __init__(
330
+ self,
331
+ message: str,
332
+ *,
333
+ required_rate: float | None = None,
334
+ actual_rate: float | None = None,
335
+ ) -> None:
336
+ """Initialize SampleRateError.
337
+
338
+ Args:
339
+ message: Brief description of the error.
340
+ required_rate: Minimum sample rate required in Hz.
341
+ actual_rate: Actual sample rate in Hz.
342
+ """
343
+ self.required_rate = required_rate
344
+ self.actual_rate = actual_rate
345
+
346
+ details = None
347
+ if required_rate is not None and actual_rate is not None:
348
+ details = f"Required: {required_rate:.2e} Hz. Got: {actual_rate:.2e} Hz"
349
+ elif actual_rate is not None:
350
+ details = f"Got: {actual_rate:.2e} Hz"
351
+
352
+ fix_hint = "Ensure sample_rate is positive and sufficient for the analysis."
353
+
354
+ super().__init__(
355
+ message,
356
+ details=details,
357
+ fix_hint=fix_hint,
358
+ )
359
+
360
+
361
+ class ConfigurationError(OscuraError):
362
+ """Invalid configuration parameters.
363
+
364
+ Raised when configuration is invalid, missing required fields,
365
+ or contains invalid values.
366
+
367
+ Attributes:
368
+ config_key: The configuration key that is invalid.
369
+ expected_type: Expected type or format.
370
+ actual_value: The invalid value that was provided.
371
+ """
372
+
373
+ docs_path: str = "errors#configuration"
374
+
375
+ def __init__(
376
+ self,
377
+ message: str,
378
+ *,
379
+ config_key: str | None = None,
380
+ expected_type: str | None = None,
381
+ actual_value: Any = None,
382
+ details: str | None = None,
383
+ fix_hint: str | None = None,
384
+ ) -> None:
385
+ """Initialize ConfigurationError.
386
+
387
+ Args:
388
+ message: Brief description of the error.
389
+ config_key: The configuration key that is invalid.
390
+ expected_type: Expected type or format.
391
+ actual_value: The invalid value that was provided.
392
+ details: Additional context about the error.
393
+ fix_hint: Suggestion for how to fix the error.
394
+ """
395
+ self.config_key = config_key
396
+ self.expected_type = expected_type
397
+ self.actual_value = actual_value
398
+
399
+ # Build details from parts if not provided directly
400
+ if details is None:
401
+ details_parts = []
402
+ if config_key:
403
+ details_parts.append(f"Key: {config_key}")
404
+ if expected_type:
405
+ details_parts.append(f"Expected: {expected_type}")
406
+ if actual_value is not None:
407
+ details_parts.append(f"Got: {actual_value!r}")
408
+ details = ". ".join(details_parts) if details_parts else None
409
+
410
+ if fix_hint is None:
411
+ fix_hint = "Check configuration file and ensure all values are valid."
412
+
413
+ super().__init__(
414
+ message,
415
+ details=details,
416
+ fix_hint=fix_hint,
417
+ docs_path=self.docs_path,
418
+ )
419
+
420
+
421
+ class ValidationError(OscuraError):
422
+ """Data validation failed.
423
+
424
+ Raised when input data does not meet validation requirements.
425
+
426
+ Attributes:
427
+ field: The field that failed validation.
428
+ constraint: The constraint that was violated.
429
+ value: The value that failed validation.
430
+ """
431
+
432
+ docs_path: str = "errors#validation"
433
+
434
+ def __init__(
435
+ self,
436
+ message: str,
437
+ *,
438
+ field: str | None = None,
439
+ constraint: str | None = None,
440
+ value: Any = None,
441
+ ) -> None:
442
+ """Initialize ValidationError.
443
+
444
+ Args:
445
+ message: Brief description of the error.
446
+ field: The field that failed validation.
447
+ constraint: The constraint that was violated.
448
+ value: The value that failed validation.
449
+ """
450
+ self.field = field
451
+ self.constraint = constraint
452
+ self.value = value
453
+
454
+ details_parts = []
455
+ if field:
456
+ details_parts.append(f"Field: {field}")
457
+ if constraint:
458
+ details_parts.append(f"Constraint: {constraint}")
459
+ if value is not None:
460
+ details_parts.append(f"Value: {value!r}")
461
+
462
+ details = ". ".join(details_parts) if details_parts else None
463
+ fix_hint = "Ensure input data meets all validation requirements."
464
+
465
+ super().__init__(
466
+ message,
467
+ details=details,
468
+ fix_hint=fix_hint,
469
+ docs_path=self.docs_path,
470
+ )
471
+
472
+
473
+ class ExportError(OscuraError):
474
+ """Error exporting data.
475
+
476
+ Raised when data cannot be exported to the requested format.
477
+
478
+ Attributes:
479
+ export_format: The format that failed.
480
+ output_path: Path where export was attempted.
481
+ """
482
+
483
+ docs_path: str = "errors#export"
484
+
485
+ def __init__(
486
+ self,
487
+ message: str,
488
+ *,
489
+ export_format: str | None = None,
490
+ output_path: str | None = None,
491
+ details: str | None = None,
492
+ ) -> None:
493
+ """Initialize ExportError.
494
+
495
+ Args:
496
+ message: Brief description of the error.
497
+ export_format: The format that failed (e.g., "csv", "hdf5").
498
+ output_path: Path where export was attempted.
499
+ details: Additional context about the error.
500
+ """
501
+ self.export_format = export_format
502
+ self.output_path = output_path
503
+
504
+ details_parts = []
505
+ if export_format:
506
+ details_parts.append(f"Format: {export_format}")
507
+ if output_path:
508
+ details_parts.append(f"Path: {output_path}")
509
+ if details:
510
+ details_parts.append(details)
511
+
512
+ combined_details = ". ".join(details_parts) if details_parts else None
513
+ fix_hint = "Check output path is writable and data is valid for export."
514
+
515
+ super().__init__(
516
+ message,
517
+ details=combined_details,
518
+ fix_hint=fix_hint,
519
+ docs_path=self.docs_path,
520
+ )
521
+
522
+
523
+ __all__ = [
524
+ "DOCS_BASE_URL",
525
+ "AnalysisError",
526
+ "ConfigurationError",
527
+ "ExportError",
528
+ "FormatError",
529
+ "InsufficientDataError",
530
+ "LoaderError",
531
+ "OscuraError",
532
+ "SampleRateError",
533
+ "UnsupportedFormatError",
534
+ "ValidationError",
535
+ ]