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,418 @@
1
+ """Plugin isolation and sandboxing.
2
+
3
+ This module provides resource limits, permission models, and sandboxing
4
+ for plugins to prevent interference and ensure security.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ import resource
11
+ import threading
12
+ from contextlib import contextmanager, suppress
13
+ from dataclasses import dataclass, field
14
+ from enum import Enum, auto
15
+ from typing import TYPE_CHECKING
16
+
17
+ if TYPE_CHECKING:
18
+ from collections.abc import Generator
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class Permission(Enum):
24
+ """Plugin permission types.
25
+
26
+ References:
27
+ PLUG-004: Plugin Isolation - permission model
28
+ """
29
+
30
+ READ_CONFIG = auto()
31
+ """Read configuration files"""
32
+ WRITE_CONFIG = auto()
33
+ """Write configuration files"""
34
+ READ_DATA = auto()
35
+ """Read data files"""
36
+ WRITE_DATA = auto()
37
+ """Write data files"""
38
+ NETWORK_ACCESS = auto()
39
+ """Access network"""
40
+ SUBPROCESS = auto()
41
+ """Spawn subprocesses"""
42
+ NATIVE_CODE = auto()
43
+ """Execute native code"""
44
+ SYSTEM_INFO = auto()
45
+ """Access system information"""
46
+
47
+
48
+ @dataclass
49
+ class ResourceLimits:
50
+ """Resource limits for plugin execution.
51
+
52
+ Attributes:
53
+ max_memory_mb: Maximum memory in MB (None for unlimited)
54
+ max_cpu_time_sec: Maximum CPU time in seconds (None for unlimited)
55
+ max_wall_time_sec: Maximum wall time in seconds (None for unlimited)
56
+ max_file_size_mb: Maximum file size in MB (None for unlimited)
57
+ max_open_files: Maximum open file descriptors (None for unlimited)
58
+
59
+ References:
60
+ PLUG-004: Plugin Isolation - resource limits
61
+ """
62
+
63
+ max_memory_mb: int | None = None
64
+ max_cpu_time_sec: float | None = None
65
+ max_wall_time_sec: float | None = None
66
+ max_file_size_mb: int | None = None
67
+ max_open_files: int | None = None
68
+
69
+ def to_rlimit_dict(self) -> dict[int, tuple[int, int]]:
70
+ """Convert to resource.setrlimit compatible dict.
71
+
72
+ Returns:
73
+ Dictionary of resource limits
74
+
75
+ References:
76
+ PLUG-004: Plugin Isolation - resource limits
77
+ """
78
+ limits = {}
79
+
80
+ if self.max_memory_mb is not None:
81
+ # RLIMIT_AS - address space limit
82
+ limit_bytes = self.max_memory_mb * 1024 * 1024
83
+ limits[resource.RLIMIT_AS] = (limit_bytes, limit_bytes)
84
+
85
+ if self.max_cpu_time_sec is not None:
86
+ # RLIMIT_CPU - CPU time limit
87
+ limit_sec = int(self.max_cpu_time_sec)
88
+ limits[resource.RLIMIT_CPU] = (limit_sec, limit_sec)
89
+
90
+ if self.max_file_size_mb is not None:
91
+ # RLIMIT_FSIZE - file size limit
92
+ limit_bytes = self.max_file_size_mb * 1024 * 1024
93
+ limits[resource.RLIMIT_FSIZE] = (limit_bytes, limit_bytes)
94
+
95
+ if self.max_open_files is not None:
96
+ # RLIMIT_NOFILE - number of open files
97
+ limits[resource.RLIMIT_NOFILE] = (
98
+ self.max_open_files,
99
+ self.max_open_files,
100
+ )
101
+
102
+ return limits
103
+
104
+
105
+ @dataclass
106
+ class PermissionSet:
107
+ """Set of permissions granted to a plugin.
108
+
109
+ Attributes:
110
+ allowed: Set of allowed permissions
111
+ denied: Set of explicitly denied permissions
112
+
113
+ References:
114
+ PLUG-004: Plugin Isolation - permission model
115
+ """
116
+
117
+ allowed: set[Permission] = field(default_factory=set)
118
+ denied: set[Permission] = field(default_factory=set)
119
+
120
+ def grant(self, permission: Permission) -> None:
121
+ """Grant a permission.
122
+
123
+ Args:
124
+ permission: Permission to grant
125
+
126
+ References:
127
+ PLUG-004: Plugin Isolation - permission model
128
+ """
129
+ self.allowed.add(permission)
130
+ if permission in self.denied:
131
+ self.denied.remove(permission)
132
+
133
+ def deny(self, permission: Permission) -> None:
134
+ """Deny a permission.
135
+
136
+ Args:
137
+ permission: Permission to deny
138
+
139
+ References:
140
+ PLUG-004: Plugin Isolation - permission model
141
+ """
142
+ self.denied.add(permission)
143
+ if permission in self.allowed:
144
+ self.allowed.remove(permission)
145
+
146
+ def has_permission(self, permission: Permission) -> bool:
147
+ """Check if permission is granted.
148
+
149
+ Args:
150
+ permission: Permission to check
151
+
152
+ Returns:
153
+ True if permission is granted
154
+
155
+ References:
156
+ PLUG-004: Plugin Isolation - permission model
157
+ """
158
+ if permission in self.denied:
159
+ return False
160
+ return permission in self.allowed
161
+
162
+ def check(self, permission: Permission) -> None:
163
+ """Check permission and raise if not granted.
164
+
165
+ Args:
166
+ permission: Permission to check
167
+
168
+ Raises:
169
+ PermissionError: If permission not granted
170
+
171
+ References:
172
+ PLUG-004: Plugin Isolation - permission model
173
+ """
174
+ if not self.has_permission(permission):
175
+ raise PermissionError(f"Plugin does not have {permission.name} permission")
176
+
177
+
178
+ class TimeoutError(Exception):
179
+ """Exception raised when execution timeout is exceeded."""
180
+
181
+
182
+ class ResourceExceededError(Exception):
183
+ """Exception raised when resource limit is exceeded."""
184
+
185
+
186
+ class PluginSandbox:
187
+ """Sandbox for isolated plugin execution.
188
+
189
+ Provides resource limits, timeout enforcement, and permission checking.
190
+
191
+ References:
192
+ PLUG-004: Plugin Isolation - resource limits, permission model
193
+ """
194
+
195
+ def __init__(
196
+ self,
197
+ permissions: PermissionSet | None = None,
198
+ limits: ResourceLimits | None = None,
199
+ ) -> None:
200
+ """Initialize sandbox.
201
+
202
+ Args:
203
+ permissions: Permission set for plugin
204
+ limits: Resource limits for plugin
205
+
206
+ References:
207
+ PLUG-004: Plugin Isolation
208
+ """
209
+ self.permissions = permissions or PermissionSet()
210
+ self.limits = limits or ResourceLimits()
211
+ self._original_limits: dict[int, tuple[int, int]] = {}
212
+
213
+ @contextmanager
214
+ def execute(
215
+ self,
216
+ timeout: float | None = None,
217
+ ) -> Generator[None, None, None]:
218
+ """Execute code in sandbox with resource limits.
219
+
220
+ Args:
221
+ timeout: Execution timeout in seconds
222
+
223
+ Yields:
224
+ None
225
+
226
+ Raises:
227
+ ResourceExceededError: If resource limit exceeded
228
+
229
+ Note:
230
+ Timeout handling is logged but does not raise TimeoutError.
231
+ Future versions will add proper timeout interruption.
232
+
233
+ References:
234
+ PLUG-004: Plugin Isolation - resource limits
235
+
236
+ Example:
237
+ >>> sandbox = PluginSandbox(limits=ResourceLimits(max_memory_mb=100))
238
+ >>> with sandbox.execute(timeout=5.0):
239
+ ... # Plugin code runs here with limits
240
+ ... result = plugin.process_data(data)
241
+ """
242
+ # Apply resource limits
243
+ self._apply_limits()
244
+
245
+ # Setup timeout if specified
246
+ timer = None
247
+ if timeout is not None:
248
+ try:
249
+ timer = threading.Timer(timeout, self._timeout_handler)
250
+ timer.start()
251
+ except RuntimeError:
252
+ # Thread limit reached, skip timeout
253
+ logger.warning("Could not create timeout timer (thread limit reached)")
254
+ timer = None
255
+
256
+ try:
257
+ yield
258
+
259
+ except MemoryError as e:
260
+ raise ResourceExceededError("Memory limit exceeded") from e
261
+
262
+ finally:
263
+ # Cancel timeout timer
264
+ if timer is not None:
265
+ with suppress(Exception):
266
+ timer.cancel()
267
+
268
+ # Restore original limits
269
+ self._restore_limits()
270
+
271
+ def _apply_limits(self) -> None:
272
+ """Apply resource limits.
273
+
274
+ References:
275
+ PLUG-004: Plugin Isolation - resource limits
276
+ """
277
+ rlimits = self.limits.to_rlimit_dict()
278
+
279
+ for resource_type, limit in rlimits.items():
280
+ try:
281
+ # Save original limit
282
+ self._original_limits[resource_type] = resource.getrlimit(resource_type)
283
+ # Apply new limit
284
+ resource.setrlimit(resource_type, limit)
285
+ logger.debug(f"Applied resource limit: {resource_type} = {limit}")
286
+
287
+ except (OSError, ValueError) as e:
288
+ logger.warning(f"Failed to set resource limit {resource_type}: {e}")
289
+
290
+ def _restore_limits(self) -> None:
291
+ """Restore original resource limits.
292
+
293
+ References:
294
+ PLUG-004: Plugin Isolation - resource limits
295
+ """
296
+ for resource_type, limit in self._original_limits.items():
297
+ try:
298
+ resource.setrlimit(resource_type, limit)
299
+ except (OSError, ValueError) as e:
300
+ logger.warning(f"Failed to restore resource limit {resource_type}: {e}")
301
+
302
+ self._original_limits.clear()
303
+
304
+ def _timeout_handler(self) -> None:
305
+ """Handle execution timeout.
306
+
307
+ References:
308
+ PLUG-004: Plugin Isolation - CPU time limit
309
+ """
310
+ logger.error("Plugin execution timeout exceeded")
311
+ # In a real implementation, this would interrupt the thread
312
+ # For now, we just log the error
313
+
314
+ def check_permission(self, permission: Permission) -> None:
315
+ """Check if plugin has permission.
316
+
317
+ Args:
318
+ permission: Permission to check
319
+
320
+ References:
321
+ PLUG-004: Plugin Isolation - permission model
322
+ """
323
+ self.permissions.check(permission)
324
+
325
+
326
+ class IsolationManager:
327
+ """Manager for plugin isolation and sandboxing.
328
+
329
+ Tracks sandboxes for all plugins and enforces isolation policies.
330
+
331
+ References:
332
+ PLUG-004: Plugin Isolation
333
+ """
334
+
335
+ def __init__(self) -> None:
336
+ """Initialize isolation manager."""
337
+ self._sandboxes: dict[str, PluginSandbox] = {}
338
+ self._default_limits = ResourceLimits(
339
+ max_memory_mb=512, # 512 MB default
340
+ max_cpu_time_sec=30.0, # 30 seconds default
341
+ )
342
+
343
+ def create_sandbox(
344
+ self,
345
+ plugin_name: str,
346
+ permissions: PermissionSet | None = None,
347
+ limits: ResourceLimits | None = None,
348
+ ) -> PluginSandbox:
349
+ """Create sandbox for a plugin.
350
+
351
+ Args:
352
+ plugin_name: Plugin name
353
+ permissions: Permission set (None for default)
354
+ limits: Resource limits (None for default)
355
+
356
+ Returns:
357
+ Plugin sandbox
358
+
359
+ References:
360
+ PLUG-004: Plugin Isolation
361
+ """
362
+ if limits is None:
363
+ limits = self._default_limits
364
+
365
+ sandbox = PluginSandbox(permissions=permissions, limits=limits)
366
+ self._sandboxes[plugin_name] = sandbox
367
+
368
+ logger.info(f"Created sandbox for plugin '{plugin_name}'")
369
+ return sandbox
370
+
371
+ def get_sandbox(self, plugin_name: str) -> PluginSandbox | None:
372
+ """Get sandbox for a plugin.
373
+
374
+ Args:
375
+ plugin_name: Plugin name
376
+
377
+ Returns:
378
+ Plugin sandbox or None
379
+ """
380
+ return self._sandboxes.get(plugin_name)
381
+
382
+ def remove_sandbox(self, plugin_name: str) -> None:
383
+ """Remove sandbox for a plugin.
384
+
385
+ Args:
386
+ plugin_name: Plugin name
387
+ """
388
+ if plugin_name in self._sandboxes:
389
+ del self._sandboxes[plugin_name]
390
+ logger.info(f"Removed sandbox for plugin '{plugin_name}'")
391
+
392
+
393
+ # Global isolation manager
394
+ _isolation_manager: IsolationManager | None = None
395
+
396
+
397
+ def get_isolation_manager() -> IsolationManager:
398
+ """Get global isolation manager.
399
+
400
+ Returns:
401
+ Global IsolationManager instance
402
+ """
403
+ global _isolation_manager
404
+ if _isolation_manager is None:
405
+ _isolation_manager = IsolationManager()
406
+ return _isolation_manager
407
+
408
+
409
+ __all__ = [
410
+ "IsolationManager",
411
+ "Permission",
412
+ "PermissionSet",
413
+ "PluginSandbox",
414
+ "ResourceExceededError",
415
+ "ResourceLimits",
416
+ "TimeoutError",
417
+ "get_isolation_manager",
418
+ ]