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,526 @@
1
+ """UI-specific formatting utilities for Oscura displays.
2
+
3
+ This module provides formatting functions tailored for user interface display,
4
+ including text alignment, truncation, color codes, and structured output.
5
+
6
+ - UI formatting for terminal and web outputs
7
+
8
+ Example:
9
+ >>> from oscura.ui.formatters import format_text, truncate, colorize
10
+ >>> format_text("Status", "active", align="left", width=20)
11
+ ' Status: active'
12
+ >>> truncate("Very long text here", max_length=10)
13
+ 'Very lon...'
14
+ >>> colorize("Success", color="green")
15
+ '\x1b[32mSuccess\x1b[0m'
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ from dataclasses import dataclass
21
+ from enum import Enum
22
+ from typing import Any, Literal
23
+
24
+ # Type alias for color names accepted by colorize()
25
+ type ColorName = Literal["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"]
26
+
27
+
28
+ class Color(Enum):
29
+ """ANSI color codes for terminal output."""
30
+
31
+ BLACK = "\033[30m"
32
+ RED = "\033[31m"
33
+ GREEN = "\033[32m"
34
+ YELLOW = "\033[33m"
35
+ BLUE = "\033[34m"
36
+ MAGENTA = "\033[35m"
37
+ CYAN = "\033[36m"
38
+ WHITE = "\033[37m"
39
+ RESET = "\033[0m"
40
+
41
+
42
+ class TextAlignment(Enum):
43
+ """Text alignment options."""
44
+
45
+ LEFT = "left"
46
+ CENTER = "center"
47
+ RIGHT = "right"
48
+
49
+
50
+ @dataclass
51
+ class FormattedText:
52
+ """Container for formatted text output.
53
+
54
+ Attributes:
55
+ content: The formatted text content.
56
+ color: Optional color code.
57
+ bold: Whether text should be bold.
58
+ width: Display width of the text.
59
+ """
60
+
61
+ content: str
62
+ color: Color | None = None
63
+ bold: bool = False
64
+ width: int = 0
65
+
66
+ def __str__(self) -> str:
67
+ """Get string representation with ANSI codes."""
68
+ result = self.content
69
+ if self.bold:
70
+ result = f"\033[1m{result}\033[0m"
71
+ if self.color and self.color != Color.RESET:
72
+ result = f"{self.color.value}{result}{Color.RESET.value}"
73
+ return result
74
+
75
+
76
+ def colorize(
77
+ text: str,
78
+ color: ColorName = "white",
79
+ bold: bool = False,
80
+ ) -> str:
81
+ """Apply ANSI color codes to text.
82
+
83
+ Args:
84
+ text: Text to colorize.
85
+ color: Color name (black, red, green, yellow, blue, magenta, cyan, white).
86
+ bold: Apply bold formatting.
87
+
88
+ Returns:
89
+ Text with ANSI color codes.
90
+
91
+ Example:
92
+ >>> colorize("Error", color="red")
93
+ '\x1b[31mError\x1b[0m'
94
+ """
95
+ try:
96
+ color_enum = Color[color.upper()]
97
+ except KeyError:
98
+ color_enum = Color.WHITE
99
+
100
+ result = text
101
+ if bold:
102
+ result = f"\033[1m{result}\033[0m"
103
+ result = f"{color_enum.value}{result}{Color.RESET.value}"
104
+ return result
105
+
106
+
107
+ def truncate(
108
+ text: str,
109
+ max_length: int,
110
+ suffix: str = "...",
111
+ ) -> str:
112
+ """Truncate text to maximum length with suffix.
113
+
114
+ Args:
115
+ text: Text to truncate.
116
+ max_length: Maximum length including suffix.
117
+ suffix: Suffix to append if truncated (default "...").
118
+
119
+ Returns:
120
+ Truncated text.
121
+
122
+ Example:
123
+ >>> truncate("Very long text here", max_length=10)
124
+ 'Very lon...'
125
+ """
126
+ if len(text) <= max_length:
127
+ return text
128
+
129
+ # Account for suffix length
130
+ truncate_at = max(0, max_length - len(suffix))
131
+ return text[:truncate_at] + suffix
132
+
133
+
134
+ def align_text(
135
+ text: str,
136
+ width: int,
137
+ alignment: Literal["left", "center", "right"] = "left",
138
+ fill_char: str = " ",
139
+ ) -> str:
140
+ """Align text within a given width.
141
+
142
+ Args:
143
+ text: Text to align.
144
+ width: Target width.
145
+ alignment: How to align (left, center, right).
146
+ fill_char: Character to use for padding.
147
+
148
+ Returns:
149
+ Aligned text.
150
+
151
+ Example:
152
+ >>> align_text("Hello", 10, "center")
153
+ ' Hello '
154
+ """
155
+ if len(text) >= width:
156
+ return text
157
+
158
+ if alignment == "center":
159
+ return text.center(width, fill_char)
160
+ elif alignment == "right":
161
+ return text.rjust(width, fill_char)
162
+ else: # left
163
+ return text.ljust(width, fill_char)
164
+
165
+
166
+ def format_text(
167
+ label: str,
168
+ value: Any,
169
+ align: Literal["left", "center", "right"] = "left",
170
+ width: int | None = None,
171
+ separator: str = ": ",
172
+ color: ColorName | None = None,
173
+ ) -> str:
174
+ """Format a label-value pair for display.
175
+
176
+ Args:
177
+ label: Label/key.
178
+ value: Value to display.
179
+ align: Text alignment.
180
+ width: Total width for alignment (including label, separator, value).
181
+ separator: Separator between label and value.
182
+ color: Optional color for the value.
183
+
184
+ Returns:
185
+ Formatted text.
186
+
187
+ Example:
188
+ >>> format_text("Status", "active", align="left", width=20)
189
+ ' Status: active'
190
+ """
191
+ result = f"{label}{separator}{value}"
192
+
193
+ if color:
194
+ result = f"{label}{separator}{colorize(str(value), color=color)}"
195
+
196
+ if width:
197
+ result = align_text(result, width, alignment=align)
198
+
199
+ return result
200
+
201
+
202
+ def format_table(
203
+ data: list[list[Any]],
204
+ headers: list[str] | None = None,
205
+ column_widths: list[int] | None = None,
206
+ align_columns: list[Literal["left", "center", "right"]] | None = None,
207
+ ) -> str:
208
+ """Format data as a simple table.
209
+
210
+ Args:
211
+ data: List of rows (each row is a list of values).
212
+ headers: Optional header row.
213
+ column_widths: Optional column widths (auto-calculated if not provided).
214
+ align_columns: Alignment for each column.
215
+
216
+ Returns:
217
+ Formatted table as string.
218
+
219
+ Example:
220
+ >>> data = [["Alice", 85], ["Bob", 92]]
221
+ >>> format_table(data, headers=["Name", "Score"])
222
+ """
223
+ if not data:
224
+ return ""
225
+
226
+ # Calculate column widths
227
+ num_cols = len(data[0]) if data else 0
228
+ if headers:
229
+ num_cols = len(headers)
230
+
231
+ if column_widths is None:
232
+ column_widths = []
233
+ for col_idx in range(num_cols):
234
+ max_width = 0
235
+ if headers and col_idx < len(headers):
236
+ max_width = len(str(headers[col_idx]))
237
+ for row in data:
238
+ if col_idx < len(row):
239
+ max_width = max(max_width, len(str(row[col_idx])))
240
+ column_widths.append(max_width + 2)
241
+
242
+ # Default alignment
243
+ if align_columns is None:
244
+ align_columns = ["left"] * num_cols
245
+
246
+ output_lines = []
247
+
248
+ # Add headers if provided
249
+ if headers:
250
+ header_cells = []
251
+ for col_idx, header in enumerate(headers):
252
+ width = column_widths[col_idx] if col_idx < len(column_widths) else 10
253
+ aligned = align_text(str(header), width, align_columns[col_idx])
254
+ header_cells.append(aligned)
255
+ output_lines.append(" ".join(header_cells))
256
+ # Add separator
257
+ separator = "-" * sum(column_widths) + ("-" * (num_cols - 1))
258
+ output_lines.append(separator)
259
+
260
+ # Add data rows
261
+ for row in data:
262
+ row_cells = []
263
+ for col_idx, cell in enumerate(row):
264
+ width = column_widths[col_idx] if col_idx < len(column_widths) else 10
265
+ aligned = align_text(str(cell), width, align_columns[col_idx])
266
+ row_cells.append(aligned)
267
+ output_lines.append(" ".join(row_cells))
268
+
269
+ return "\n".join(output_lines)
270
+
271
+
272
+ def format_status(
273
+ status: Literal["pass", "fail", "warning", "info", "pending"],
274
+ message: str = "",
275
+ use_symbols: bool = True,
276
+ ) -> str:
277
+ """Format a status message with optional symbol.
278
+
279
+ Args:
280
+ status: Status type (pass, fail, warning, info, pending).
281
+ message: Optional message text.
282
+ use_symbols: Use Unicode symbols or text.
283
+
284
+ Returns:
285
+ Formatted status string.
286
+
287
+ Example:
288
+ >>> format_status("pass", "All tests passed")
289
+ '✓ All tests passed'
290
+ """
291
+ symbols = {
292
+ "pass": "✓",
293
+ "fail": "✗",
294
+ "warning": "⚠",
295
+ "info": "ℹ", # noqa: RUF001 - intentional unicode info symbol
296
+ "pending": "⏳",
297
+ }
298
+
299
+ colors: dict[str, ColorName] = {
300
+ "pass": "green",
301
+ "fail": "red",
302
+ "warning": "yellow",
303
+ "info": "blue",
304
+ "pending": "cyan",
305
+ }
306
+
307
+ # Get color with default, cast needed because dict.get default is str
308
+ status_color: ColorName = colors.get(status, "white") # type: ignore[assignment]
309
+
310
+ if use_symbols:
311
+ symbol = symbols.get(status, "•")
312
+ colored_symbol = colorize(symbol, color=status_color)
313
+ return f"{colored_symbol} {message}" if message else colored_symbol
314
+ else:
315
+ text = status.upper()
316
+ return (
317
+ colorize(f"{text}: {message}", color=status_color)
318
+ if message
319
+ else colorize(text, color=status_color)
320
+ )
321
+
322
+
323
+ def format_percentage(
324
+ value: float,
325
+ decimals: int = 1,
326
+ show_bar: bool = False,
327
+ bar_width: int = 10,
328
+ ) -> str:
329
+ """Format a percentage with optional progress bar.
330
+
331
+ Args:
332
+ value: Percentage value (0-100 or 0-1).
333
+ decimals: Decimal places.
334
+ show_bar: Include ASCII progress bar.
335
+ bar_width: Width of progress bar.
336
+
337
+ Returns:
338
+ Formatted percentage string.
339
+
340
+ Example:
341
+ >>> format_percentage(0.75, show_bar=True)
342
+ '75.0% [████████ ]'
343
+ """
344
+ # Normalize to 0-100 range
345
+ if value <= 1:
346
+ pct = value * 100
347
+ else:
348
+ pct = value
349
+
350
+ result = f"{pct:.{decimals}f}%"
351
+
352
+ if show_bar and 0 <= pct <= 100:
353
+ filled = int((pct / 100) * bar_width)
354
+ bar = "[" + "█" * filled + "░" * (bar_width - filled) + "]"
355
+ result = f"{result} {bar}"
356
+
357
+ return result
358
+
359
+
360
+ def format_duration(seconds: float) -> str:
361
+ """Format duration in seconds as human-readable string.
362
+
363
+ Args:
364
+ seconds: Duration in seconds.
365
+
366
+ Returns:
367
+ Human-readable duration (e.g., "1h 23m 45s").
368
+
369
+ Example:
370
+ >>> format_duration(5025)
371
+ '1h 23m 45s'
372
+ """
373
+ if seconds < 0:
374
+ return "invalid"
375
+
376
+ hours = int(seconds // 3600)
377
+ minutes = int((seconds % 3600) // 60)
378
+ secs = int(seconds % 60)
379
+ millis = int((seconds % 1) * 1000)
380
+
381
+ if hours > 0:
382
+ return f"{hours}h {minutes}m {secs}s"
383
+ elif minutes > 0:
384
+ return f"{minutes}m {secs}s"
385
+ elif secs > 0:
386
+ return f"{secs}s"
387
+ else:
388
+ return f"{millis}ms"
389
+
390
+
391
+ def format_size(bytes_value: int, precision: int = 2) -> str:
392
+ """Format byte size as human-readable string.
393
+
394
+ Args:
395
+ bytes_value: Size in bytes.
396
+ precision: Decimal precision.
397
+
398
+ Returns:
399
+ Human-readable size (e.g., "1.23 MB").
400
+
401
+ Example:
402
+ >>> format_size(1234567)
403
+ '1.18 MB'
404
+ """
405
+ units = ["B", "KB", "MB", "GB", "TB"]
406
+ size = float(bytes_value)
407
+
408
+ for unit in units:
409
+ if size < 1024:
410
+ return f"{size:.{precision}f} {unit}"
411
+ size /= 1024
412
+
413
+ return f"{size:.{precision}f} PB"
414
+
415
+
416
+ def format_list(
417
+ items: list[str],
418
+ style: Literal["bullet", "numbered", "comma", "newline"] = "bullet",
419
+ prefix: str = "",
420
+ ) -> str:
421
+ """Format a list of items with various styles.
422
+
423
+ Args:
424
+ items: List of items to format.
425
+ style: Formatting style (bullet, numbered, comma, newline).
426
+ prefix: Prefix for each item.
427
+
428
+ Returns:
429
+ Formatted list as string.
430
+
431
+ Example:
432
+ >>> format_list(["a", "b", "c"], style="bullet")
433
+ ' • a\\n • b\\n • c'
434
+ """
435
+ if not items:
436
+ return ""
437
+
438
+ if style == "bullet":
439
+ return "\n".join(f"{prefix}• {item}" for item in items)
440
+ elif style == "numbered":
441
+ return "\n".join(f"{prefix}{i}. {item}" for i, item in enumerate(items, 1))
442
+ elif style == "comma":
443
+ return ", ".join(items)
444
+ else: # newline
445
+ return "\n".join(items)
446
+
447
+
448
+ def format_key_value_pairs(
449
+ pairs: dict[str, Any],
450
+ indent: int = 2,
451
+ separator: str = ": ",
452
+ ) -> str:
453
+ """Format key-value pairs with indentation.
454
+
455
+ Args:
456
+ pairs: Dictionary of key-value pairs.
457
+ indent: Indentation level (spaces).
458
+ separator: Separator between key and value.
459
+
460
+ Returns:
461
+ Formatted key-value pairs as string.
462
+
463
+ Example:
464
+ >>> format_key_value_pairs({"name": "Alice", "age": 30})
465
+ ' name: Alice\\n age: 30'
466
+ """
467
+ if not pairs:
468
+ return ""
469
+
470
+ indent_str = " " * indent
471
+ lines = []
472
+ for key, value in pairs.items():
473
+ lines.append(f"{indent_str}{key}{separator}{value}")
474
+ return "\n".join(lines)
475
+
476
+
477
+ def format_code_block(
478
+ code: str,
479
+ line_numbers: bool = False,
480
+ indent: int = 0,
481
+ language: str | None = None,
482
+ ) -> str:
483
+ """Format code with optional line numbers and indentation.
484
+
485
+ Args:
486
+ code: Code content.
487
+ line_numbers: Include line numbers.
488
+ indent: Indentation level.
489
+ language: Programming language for syntax highlighting (currently unused).
490
+
491
+ Returns:
492
+ Formatted code block.
493
+
494
+ Example:
495
+ >>> format_code_block("x = 1\\nprint(x)", line_numbers=True)
496
+ """
497
+ indent_str = " " * indent
498
+ lines = code.split("\n")
499
+
500
+ if line_numbers:
501
+ max_num_width = len(str(len(lines)))
502
+ formatted_lines = []
503
+ for num, line in enumerate(lines, 1):
504
+ formatted_lines.append(f"{indent_str}{num:>{max_num_width}} | {line}")
505
+ return "\n".join(formatted_lines)
506
+ else:
507
+ return "\n".join(f"{indent_str}{line}" for line in lines)
508
+
509
+
510
+ __all__ = [
511
+ "Color",
512
+ "FormattedText",
513
+ "TextAlignment",
514
+ "align_text",
515
+ "colorize",
516
+ "format_code_block",
517
+ "format_duration",
518
+ "format_key_value_pairs",
519
+ "format_list",
520
+ "format_percentage",
521
+ "format_size",
522
+ "format_status",
523
+ "format_table",
524
+ "format_text",
525
+ "truncate",
526
+ ]