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,455 @@
1
+ """Oscura DSL Interpreter.
2
+
3
+ Executes parsed DSL programs.
4
+ """
5
+
6
+ from collections.abc import Callable
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from oscura.dsl.parser import (
11
+ Assignment,
12
+ Command,
13
+ Expression,
14
+ ForLoop,
15
+ FunctionCall,
16
+ Literal,
17
+ Pipeline,
18
+ Statement,
19
+ Variable,
20
+ parse_dsl,
21
+ )
22
+
23
+
24
+ class InterpreterError(Exception):
25
+ """DSL interpreter error.
26
+
27
+ Raised when the interpreter encounters an error during execution,
28
+ such as undefined variables, unknown commands, or invalid operations.
29
+ """
30
+
31
+
32
+ class Interpreter:
33
+ """DSL interpreter for Oscura commands.
34
+
35
+ Executes parsed AST with Python implementations of DSL commands.
36
+ """
37
+
38
+ def __init__(self) -> None:
39
+ """Initialize interpreter with empty environment."""
40
+ self.variables: dict[str, Any] = {}
41
+ self.commands: dict[str, Any] = {}
42
+ self._register_builtin_commands()
43
+
44
+ def _register_builtin_commands(self) -> None:
45
+ """Register built-in DSL commands."""
46
+ # Import oscura functions lazily to avoid circular imports
47
+ self.commands["load"] = self._cmd_load
48
+ self.commands["filter"] = self._cmd_filter
49
+ self.commands["measure"] = self._cmd_measure
50
+ self.commands["plot"] = self._cmd_plot
51
+ self.commands["export"] = self._cmd_export
52
+ self.commands["glob"] = self._cmd_glob
53
+
54
+ def _cmd_load(self, *args: Any) -> Any:
55
+ """Load command: load "filename"."""
56
+ if len(args) != 1:
57
+ raise InterpreterError("load requires exactly 1 argument: filename")
58
+
59
+ filename = args[0]
60
+ if not isinstance(filename, str):
61
+ raise InterpreterError("load filename must be a string")
62
+
63
+ # Lazy import to avoid circular dependency
64
+ try:
65
+ from oscura.loaders import load
66
+
67
+ # Try to determine loader from extension
68
+ path = Path(filename)
69
+ if not path.exists():
70
+ raise InterpreterError(f"File not found: {filename}")
71
+
72
+ # Load the file using Oscura's loader
73
+ return load(str(path))
74
+
75
+ except ImportError as e:
76
+ raise InterpreterError(f"oscura.loaders not available: {e}") # noqa: B904
77
+ except Exception as e:
78
+ raise InterpreterError(f"Failed to load {filename}: {e}") # noqa: B904
79
+
80
+ def _cmd_filter(self, trace: Any, *args: Any) -> Any:
81
+ """Filter command: filter lowpass 1000."""
82
+ if len(args) < 1:
83
+ raise InterpreterError("filter requires filter type argument")
84
+
85
+ filter_type = args[0]
86
+ if not isinstance(filter_type, str):
87
+ raise InterpreterError("filter type must be a string")
88
+
89
+ # Import filter functions
90
+ try:
91
+ from oscura import filtering
92
+
93
+ # Note: bandpass and bandstop have different signatures (low, high)
94
+ # but we treat them as Any -> Any for DSL simplicity
95
+ filter_map: dict[str, Callable[..., Any]] = {
96
+ "lowpass": filtering.low_pass,
97
+ "highpass": filtering.high_pass,
98
+ "bandpass": filtering.band_pass,
99
+ "bandstop": filtering.band_stop,
100
+ }
101
+
102
+ if filter_type not in filter_map:
103
+ raise InterpreterError(
104
+ f"Unknown filter type: {filter_type}. Available: {', '.join(filter_map.keys())}"
105
+ )
106
+
107
+ # Get cutoff frequency (required for all filters)
108
+ if len(args) < 2:
109
+ raise InterpreterError(f"{filter_type} filter requires cutoff frequency")
110
+
111
+ cutoff = args[1]
112
+ if not isinstance(cutoff, (int, float)):
113
+ raise InterpreterError("cutoff frequency must be a number")
114
+
115
+ # Apply filter
116
+ filter_func: Callable[..., Any] = filter_map[filter_type]
117
+ return filter_func(trace, cutoff)
118
+
119
+ except ImportError as e:
120
+ raise InterpreterError(f"oscura.filtering not available: {e}") # noqa: B904
121
+ except Exception as e:
122
+ raise InterpreterError(f"Filter failed: {e}") # noqa: B904
123
+
124
+ def _cmd_measure(self, trace: Any, *args: Any) -> Any:
125
+ """Measure command: measure rise_time."""
126
+ if len(args) < 1:
127
+ raise InterpreterError("measure requires measurement name")
128
+
129
+ measurement = args[0]
130
+ if not isinstance(measurement, str):
131
+ raise InterpreterError("measurement name must be a string")
132
+
133
+ # Import measurement functions
134
+ try:
135
+ import oscura
136
+
137
+ # Map measurement names to functions - access via getattr
138
+ measure_map: dict[str, str] = {
139
+ "frequency": "frequency",
140
+ "period": "period",
141
+ "duty_cycle": "duty_cycle",
142
+ "rise_time": "rise_time",
143
+ "fall_time": "fall_time",
144
+ "amplitude": "amplitude",
145
+ "rms": "rms",
146
+ "mean": "mean",
147
+ "peak_to_peak": "vpp",
148
+ }
149
+
150
+ if measurement not in measure_map:
151
+ raise InterpreterError(
152
+ f"Unknown measurement: {measurement}. "
153
+ f"Available: {', '.join(measure_map.keys())}"
154
+ )
155
+
156
+ # Apply measurement - use getattr to access the function
157
+ func_name = measure_map[measurement]
158
+ measure_func = getattr(oscura, func_name)
159
+ return measure_func(trace)
160
+
161
+ except ImportError as e:
162
+ raise InterpreterError(f"oscura measurements not available: {e}") # noqa: B904
163
+ except AttributeError as e:
164
+ raise InterpreterError(f"Measurement function not found: {e}") # noqa: B904
165
+ except Exception as e:
166
+ raise InterpreterError(f"Measurement failed: {e}") # noqa: B904
167
+
168
+ def _cmd_plot(self, trace: Any, *args: Any) -> Any:
169
+ """Plot command: plot."""
170
+ # Import visualization functions
171
+ try:
172
+ from oscura import visualization
173
+
174
+ # Optional plot type (default: waveform)
175
+ plot_type = "waveform"
176
+ if len(args) > 0:
177
+ plot_type = args[0]
178
+ if not isinstance(plot_type, str):
179
+ raise InterpreterError("plot type must be a string")
180
+
181
+ # Plot based on type - use getattr to access the plot function
182
+ if plot_type == "waveform":
183
+ plot_func = getattr(visualization, "plot", None)
184
+ if plot_func is None:
185
+ raise InterpreterError("visualization.plot not available")
186
+ plot_func(trace)
187
+ return trace # Return trace for chaining
188
+ else:
189
+ raise InterpreterError(f"Unknown plot type: {plot_type}. Available: waveform")
190
+
191
+ except ImportError as e:
192
+ raise InterpreterError(f"oscura.visualization not available: {e}") # noqa: B904
193
+ except Exception as e:
194
+ raise InterpreterError(f"Plot failed: {e}") # noqa: B904
195
+
196
+ def _cmd_export(self, data: Any, *args: Any) -> Any:
197
+ """Export command: export json "output.json"."""
198
+ if len(args) < 1:
199
+ raise InterpreterError("export requires format argument")
200
+
201
+ format_type = args[0]
202
+ if not isinstance(format_type, str):
203
+ raise InterpreterError("export format must be a string")
204
+
205
+ # Get optional filename
206
+ filename = None
207
+ if len(args) > 1:
208
+ filename = args[1]
209
+ if not isinstance(filename, str):
210
+ raise InterpreterError("export filename must be a string")
211
+
212
+ # Import export functions
213
+ try:
214
+ from oscura.exporters import csv as csv_exporter
215
+ from oscura.exporters import json_export
216
+
217
+ export_map: dict[str, Any] = {
218
+ "csv": csv_exporter.export_csv,
219
+ "json": json_export.export_json,
220
+ }
221
+
222
+ if format_type not in export_map:
223
+ raise InterpreterError(
224
+ f"Unknown export format: {format_type}. "
225
+ f"Available: {', '.join(export_map.keys())}"
226
+ )
227
+
228
+ # Export data
229
+ export_func = export_map[format_type]
230
+ if filename:
231
+ export_func(data, filename)
232
+ return filename
233
+ else:
234
+ # Generate default filename
235
+ default_name = f"export.{format_type}"
236
+ export_func(data, default_name)
237
+ return default_name
238
+
239
+ except ImportError as e:
240
+ raise InterpreterError(f"oscura.export not available: {e}") # noqa: B904
241
+ except Exception as e:
242
+ raise InterpreterError(f"Export failed: {e}") # noqa: B904
243
+
244
+ def _cmd_glob(self, pattern: str) -> list[str]:
245
+ """Glob command: glob("*.csv")."""
246
+ if not isinstance(pattern, str):
247
+ raise InterpreterError("glob pattern must be a string")
248
+
249
+ from glob import glob as glob_func
250
+
251
+ return list(glob_func(pattern)) # noqa: PTH207
252
+
253
+ def eval_expression(self, expr: Expression) -> Any:
254
+ """Evaluate an expression.
255
+
256
+ Args:
257
+ expr: Expression AST node
258
+
259
+ Returns:
260
+ Evaluated result
261
+
262
+ Raises:
263
+ InterpreterError: On evaluation errors
264
+ """
265
+ # Literal value
266
+ if isinstance(expr, Literal):
267
+ return expr.value
268
+
269
+ # Variable reference
270
+ if isinstance(expr, Variable):
271
+ if expr.name not in self.variables:
272
+ raise InterpreterError(f"Undefined variable: {expr.name} at line {expr.line}")
273
+ return self.variables[expr.name]
274
+
275
+ # Function call
276
+ if isinstance(expr, FunctionCall):
277
+ return self.eval_function_call(expr)
278
+
279
+ # Command
280
+ if isinstance(expr, Command):
281
+ return self.eval_command(expr, None)
282
+
283
+ # Pipeline
284
+ if isinstance(expr, Pipeline):
285
+ return self.eval_pipeline(expr)
286
+
287
+ raise InterpreterError(f"Unknown expression type: {type(expr).__name__}")
288
+
289
+ def eval_function_call(self, func: FunctionCall) -> Any:
290
+ """Evaluate function call."""
291
+ if func.name not in self.commands:
292
+ raise InterpreterError(f"Unknown function: {func.name} at line {func.line}")
293
+
294
+ # Evaluate arguments
295
+ args = [self.eval_expression(arg) for arg in func.args]
296
+
297
+ # Call command function
298
+ return self.commands[func.name](*args)
299
+
300
+ def eval_command(self, cmd: Command, input_data: Any | None) -> Any:
301
+ """Evaluate command with optional piped input.
302
+
303
+ Args:
304
+ cmd: Command AST node
305
+ input_data: Input from previous pipeline stage (or None)
306
+
307
+ Returns:
308
+ Command result
309
+
310
+ Raises:
311
+ InterpreterError: If command is unknown
312
+ """
313
+ if cmd.name not in self.commands:
314
+ raise InterpreterError(f"Unknown command: {cmd.name} at line {cmd.line}")
315
+
316
+ # Evaluate arguments
317
+ args = [self.eval_expression(arg) for arg in cmd.args]
318
+
319
+ # If there's input data, prepend it as first argument
320
+ if input_data is not None:
321
+ args = [input_data, *args]
322
+
323
+ # Call command function
324
+ return self.commands[cmd.name](*args)
325
+
326
+ def eval_pipeline(self, pipeline: Pipeline) -> Any:
327
+ """Evaluate pipeline of commands.
328
+
329
+ Args:
330
+ pipeline: Pipeline AST node
331
+
332
+ Returns:
333
+ Final pipeline result
334
+
335
+ Raises:
336
+ InterpreterError: If pipeline stage is invalid
337
+ """
338
+ result = None
339
+
340
+ for i, stage in enumerate(pipeline.stages):
341
+ if i == 0:
342
+ # First stage - no input
343
+ if isinstance(stage, Command):
344
+ result = self.eval_command(stage, None)
345
+ else:
346
+ result = self.eval_expression(stage)
347
+ # Subsequent stages - pipe input from previous
348
+ elif isinstance(stage, Command):
349
+ result = self.eval_command(stage, result)
350
+ else:
351
+ raise InterpreterError(
352
+ f"Pipeline stage {i + 1} must be a command, got {type(stage).__name__}"
353
+ )
354
+
355
+ return result
356
+
357
+ def eval_statement(self, stmt: Statement) -> None:
358
+ """Execute a statement.
359
+
360
+ Args:
361
+ stmt: Statement AST node
362
+
363
+ Raises:
364
+ InterpreterError: On execution errors
365
+ """
366
+ # Assignment
367
+ if isinstance(stmt, Assignment):
368
+ value = self.eval_expression(stmt.expression)
369
+ self.variables[stmt.variable] = value
370
+ return
371
+
372
+ # For loop
373
+ if isinstance(stmt, ForLoop):
374
+ self.eval_for_loop(stmt)
375
+ return
376
+
377
+ # Expression statement (pipeline)
378
+ if isinstance(stmt, Pipeline):
379
+ self.eval_pipeline(stmt)
380
+ return
381
+
382
+ # Function call as statement (e.g., in for loop body: process($f))
383
+ if isinstance(stmt, FunctionCall):
384
+ self.eval_function_call(stmt)
385
+ return
386
+
387
+ # All Statement types covered above (Assignment, ForLoop, Pipeline, FunctionCall)
388
+ # This line is unreachable if type system is correct, but kept for runtime safety
389
+ raise InterpreterError(f"Unknown statement type: {type(stmt).__name__}") # type: ignore[unreachable]
390
+
391
+ def eval_for_loop(self, loop: ForLoop) -> None:
392
+ """Execute for loop.
393
+
394
+ Args:
395
+ loop: ForLoop AST node
396
+
397
+ Raises:
398
+ InterpreterError: If iterable is not iterable
399
+ """
400
+ # Evaluate iterable
401
+ iterable = self.eval_expression(loop.iterable)
402
+
403
+ if not hasattr(iterable, "__iter__"):
404
+ raise InterpreterError(
405
+ f"For loop iterable is not iterable: {type(iterable).__name__} at line {loop.line}"
406
+ )
407
+
408
+ # Execute body for each item
409
+ for item in iterable:
410
+ # Set loop variable
411
+ self.variables[loop.variable] = item
412
+
413
+ # Execute body statements
414
+ for stmt in loop.body:
415
+ self.eval_statement(stmt)
416
+
417
+ def execute(self, statements: list[Statement]) -> None:
418
+ """Execute a program (list of statements).
419
+
420
+ Args:
421
+ statements: AST (list of statements)
422
+ """
423
+ for stmt in statements:
424
+ self.eval_statement(stmt)
425
+
426
+ def execute_source(self, source: str) -> None:
427
+ """Parse and execute DSL source code.
428
+
429
+ Args:
430
+ source: DSL source code
431
+ """
432
+ ast = parse_dsl(source)
433
+ self.execute(ast)
434
+
435
+
436
+ def execute_dsl(source: str, variables: dict[str, Any] | None = None) -> dict[str, Any]:
437
+ """Execute Oscura DSL source code.
438
+
439
+ Args:
440
+ source: DSL source code
441
+ variables: Optional initial variables
442
+
443
+ Returns:
444
+ Final variable environment after execution
445
+ """
446
+ interpreter = Interpreter()
447
+
448
+ # Set initial variables
449
+ if variables:
450
+ interpreter.variables.update(variables)
451
+
452
+ # Execute
453
+ interpreter.execute_source(source)
454
+
455
+ return interpreter.variables