oscura 0.0.1__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. oscura/__init__.py +813 -8
  2. oscura/__main__.py +392 -0
  3. oscura/analyzers/__init__.py +37 -0
  4. oscura/analyzers/digital/__init__.py +177 -0
  5. oscura/analyzers/digital/bus.py +691 -0
  6. oscura/analyzers/digital/clock.py +805 -0
  7. oscura/analyzers/digital/correlation.py +720 -0
  8. oscura/analyzers/digital/edges.py +632 -0
  9. oscura/analyzers/digital/extraction.py +413 -0
  10. oscura/analyzers/digital/quality.py +878 -0
  11. oscura/analyzers/digital/signal_quality.py +877 -0
  12. oscura/analyzers/digital/thresholds.py +708 -0
  13. oscura/analyzers/digital/timing.py +1104 -0
  14. oscura/analyzers/eye/__init__.py +46 -0
  15. oscura/analyzers/eye/diagram.py +434 -0
  16. oscura/analyzers/eye/metrics.py +555 -0
  17. oscura/analyzers/jitter/__init__.py +83 -0
  18. oscura/analyzers/jitter/ber.py +333 -0
  19. oscura/analyzers/jitter/decomposition.py +759 -0
  20. oscura/analyzers/jitter/measurements.py +413 -0
  21. oscura/analyzers/jitter/spectrum.py +220 -0
  22. oscura/analyzers/measurements.py +40 -0
  23. oscura/analyzers/packet/__init__.py +171 -0
  24. oscura/analyzers/packet/daq.py +1077 -0
  25. oscura/analyzers/packet/metrics.py +437 -0
  26. oscura/analyzers/packet/parser.py +327 -0
  27. oscura/analyzers/packet/payload.py +2156 -0
  28. oscura/analyzers/packet/payload_analysis.py +1312 -0
  29. oscura/analyzers/packet/payload_extraction.py +236 -0
  30. oscura/analyzers/packet/payload_patterns.py +670 -0
  31. oscura/analyzers/packet/stream.py +359 -0
  32. oscura/analyzers/patterns/__init__.py +266 -0
  33. oscura/analyzers/patterns/clustering.py +1036 -0
  34. oscura/analyzers/patterns/discovery.py +539 -0
  35. oscura/analyzers/patterns/learning.py +797 -0
  36. oscura/analyzers/patterns/matching.py +1091 -0
  37. oscura/analyzers/patterns/periodic.py +650 -0
  38. oscura/analyzers/patterns/sequences.py +767 -0
  39. oscura/analyzers/power/__init__.py +116 -0
  40. oscura/analyzers/power/ac_power.py +391 -0
  41. oscura/analyzers/power/basic.py +383 -0
  42. oscura/analyzers/power/conduction.py +314 -0
  43. oscura/analyzers/power/efficiency.py +297 -0
  44. oscura/analyzers/power/ripple.py +356 -0
  45. oscura/analyzers/power/soa.py +372 -0
  46. oscura/analyzers/power/switching.py +479 -0
  47. oscura/analyzers/protocol/__init__.py +150 -0
  48. oscura/analyzers/protocols/__init__.py +150 -0
  49. oscura/analyzers/protocols/base.py +500 -0
  50. oscura/analyzers/protocols/can.py +620 -0
  51. oscura/analyzers/protocols/can_fd.py +448 -0
  52. oscura/analyzers/protocols/flexray.py +405 -0
  53. oscura/analyzers/protocols/hdlc.py +399 -0
  54. oscura/analyzers/protocols/i2c.py +368 -0
  55. oscura/analyzers/protocols/i2s.py +296 -0
  56. oscura/analyzers/protocols/jtag.py +393 -0
  57. oscura/analyzers/protocols/lin.py +445 -0
  58. oscura/analyzers/protocols/manchester.py +333 -0
  59. oscura/analyzers/protocols/onewire.py +501 -0
  60. oscura/analyzers/protocols/spi.py +334 -0
  61. oscura/analyzers/protocols/swd.py +325 -0
  62. oscura/analyzers/protocols/uart.py +393 -0
  63. oscura/analyzers/protocols/usb.py +495 -0
  64. oscura/analyzers/signal_integrity/__init__.py +63 -0
  65. oscura/analyzers/signal_integrity/embedding.py +294 -0
  66. oscura/analyzers/signal_integrity/equalization.py +370 -0
  67. oscura/analyzers/signal_integrity/sparams.py +484 -0
  68. oscura/analyzers/spectral/__init__.py +53 -0
  69. oscura/analyzers/spectral/chunked.py +273 -0
  70. oscura/analyzers/spectral/chunked_fft.py +571 -0
  71. oscura/analyzers/spectral/chunked_wavelet.py +391 -0
  72. oscura/analyzers/spectral/fft.py +92 -0
  73. oscura/analyzers/statistical/__init__.py +250 -0
  74. oscura/analyzers/statistical/checksum.py +923 -0
  75. oscura/analyzers/statistical/chunked_corr.py +228 -0
  76. oscura/analyzers/statistical/classification.py +778 -0
  77. oscura/analyzers/statistical/entropy.py +1113 -0
  78. oscura/analyzers/statistical/ngrams.py +614 -0
  79. oscura/analyzers/statistics/__init__.py +119 -0
  80. oscura/analyzers/statistics/advanced.py +885 -0
  81. oscura/analyzers/statistics/basic.py +263 -0
  82. oscura/analyzers/statistics/correlation.py +630 -0
  83. oscura/analyzers/statistics/distribution.py +298 -0
  84. oscura/analyzers/statistics/outliers.py +463 -0
  85. oscura/analyzers/statistics/streaming.py +93 -0
  86. oscura/analyzers/statistics/trend.py +520 -0
  87. oscura/analyzers/validation.py +598 -0
  88. oscura/analyzers/waveform/__init__.py +36 -0
  89. oscura/analyzers/waveform/measurements.py +943 -0
  90. oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
  91. oscura/analyzers/waveform/spectral.py +1689 -0
  92. oscura/analyzers/waveform/wavelets.py +298 -0
  93. oscura/api/__init__.py +62 -0
  94. oscura/api/dsl.py +538 -0
  95. oscura/api/fluent.py +571 -0
  96. oscura/api/operators.py +498 -0
  97. oscura/api/optimization.py +392 -0
  98. oscura/api/profiling.py +396 -0
  99. oscura/automotive/__init__.py +73 -0
  100. oscura/automotive/can/__init__.py +52 -0
  101. oscura/automotive/can/analysis.py +356 -0
  102. oscura/automotive/can/checksum.py +250 -0
  103. oscura/automotive/can/correlation.py +212 -0
  104. oscura/automotive/can/discovery.py +355 -0
  105. oscura/automotive/can/message_wrapper.py +375 -0
  106. oscura/automotive/can/models.py +385 -0
  107. oscura/automotive/can/patterns.py +381 -0
  108. oscura/automotive/can/session.py +452 -0
  109. oscura/automotive/can/state_machine.py +300 -0
  110. oscura/automotive/can/stimulus_response.py +461 -0
  111. oscura/automotive/dbc/__init__.py +15 -0
  112. oscura/automotive/dbc/generator.py +156 -0
  113. oscura/automotive/dbc/parser.py +146 -0
  114. oscura/automotive/dtc/__init__.py +30 -0
  115. oscura/automotive/dtc/database.py +3036 -0
  116. oscura/automotive/j1939/__init__.py +14 -0
  117. oscura/automotive/j1939/decoder.py +745 -0
  118. oscura/automotive/loaders/__init__.py +35 -0
  119. oscura/automotive/loaders/asc.py +98 -0
  120. oscura/automotive/loaders/blf.py +77 -0
  121. oscura/automotive/loaders/csv_can.py +136 -0
  122. oscura/automotive/loaders/dispatcher.py +136 -0
  123. oscura/automotive/loaders/mdf.py +331 -0
  124. oscura/automotive/loaders/pcap.py +132 -0
  125. oscura/automotive/obd/__init__.py +14 -0
  126. oscura/automotive/obd/decoder.py +707 -0
  127. oscura/automotive/uds/__init__.py +48 -0
  128. oscura/automotive/uds/decoder.py +265 -0
  129. oscura/automotive/uds/models.py +64 -0
  130. oscura/automotive/visualization.py +369 -0
  131. oscura/batch/__init__.py +55 -0
  132. oscura/batch/advanced.py +627 -0
  133. oscura/batch/aggregate.py +300 -0
  134. oscura/batch/analyze.py +139 -0
  135. oscura/batch/logging.py +487 -0
  136. oscura/batch/metrics.py +556 -0
  137. oscura/builders/__init__.py +41 -0
  138. oscura/builders/signal_builder.py +1131 -0
  139. oscura/cli/__init__.py +14 -0
  140. oscura/cli/batch.py +339 -0
  141. oscura/cli/characterize.py +273 -0
  142. oscura/cli/compare.py +775 -0
  143. oscura/cli/decode.py +551 -0
  144. oscura/cli/main.py +247 -0
  145. oscura/cli/shell.py +350 -0
  146. oscura/comparison/__init__.py +66 -0
  147. oscura/comparison/compare.py +397 -0
  148. oscura/comparison/golden.py +487 -0
  149. oscura/comparison/limits.py +391 -0
  150. oscura/comparison/mask.py +434 -0
  151. oscura/comparison/trace_diff.py +30 -0
  152. oscura/comparison/visualization.py +481 -0
  153. oscura/compliance/__init__.py +70 -0
  154. oscura/compliance/advanced.py +756 -0
  155. oscura/compliance/masks.py +363 -0
  156. oscura/compliance/reporting.py +483 -0
  157. oscura/compliance/testing.py +298 -0
  158. oscura/component/__init__.py +38 -0
  159. oscura/component/impedance.py +365 -0
  160. oscura/component/reactive.py +598 -0
  161. oscura/component/transmission_line.py +312 -0
  162. oscura/config/__init__.py +191 -0
  163. oscura/config/defaults.py +254 -0
  164. oscura/config/loader.py +348 -0
  165. oscura/config/memory.py +271 -0
  166. oscura/config/migration.py +458 -0
  167. oscura/config/pipeline.py +1077 -0
  168. oscura/config/preferences.py +530 -0
  169. oscura/config/protocol.py +875 -0
  170. oscura/config/schema.py +713 -0
  171. oscura/config/settings.py +420 -0
  172. oscura/config/thresholds.py +599 -0
  173. oscura/convenience.py +457 -0
  174. oscura/core/__init__.py +299 -0
  175. oscura/core/audit.py +457 -0
  176. oscura/core/backend_selector.py +405 -0
  177. oscura/core/cache.py +590 -0
  178. oscura/core/cancellation.py +439 -0
  179. oscura/core/confidence.py +225 -0
  180. oscura/core/config.py +506 -0
  181. oscura/core/correlation.py +216 -0
  182. oscura/core/cross_domain.py +422 -0
  183. oscura/core/debug.py +301 -0
  184. oscura/core/edge_cases.py +541 -0
  185. oscura/core/exceptions.py +535 -0
  186. oscura/core/gpu_backend.py +523 -0
  187. oscura/core/lazy.py +832 -0
  188. oscura/core/log_query.py +540 -0
  189. oscura/core/logging.py +931 -0
  190. oscura/core/logging_advanced.py +952 -0
  191. oscura/core/memoize.py +171 -0
  192. oscura/core/memory_check.py +274 -0
  193. oscura/core/memory_guard.py +290 -0
  194. oscura/core/memory_limits.py +336 -0
  195. oscura/core/memory_monitor.py +453 -0
  196. oscura/core/memory_progress.py +465 -0
  197. oscura/core/memory_warnings.py +315 -0
  198. oscura/core/numba_backend.py +362 -0
  199. oscura/core/performance.py +352 -0
  200. oscura/core/progress.py +524 -0
  201. oscura/core/provenance.py +358 -0
  202. oscura/core/results.py +331 -0
  203. oscura/core/types.py +504 -0
  204. oscura/core/uncertainty.py +383 -0
  205. oscura/discovery/__init__.py +52 -0
  206. oscura/discovery/anomaly_detector.py +672 -0
  207. oscura/discovery/auto_decoder.py +415 -0
  208. oscura/discovery/comparison.py +497 -0
  209. oscura/discovery/quality_validator.py +528 -0
  210. oscura/discovery/signal_detector.py +769 -0
  211. oscura/dsl/__init__.py +73 -0
  212. oscura/dsl/commands.py +246 -0
  213. oscura/dsl/interpreter.py +455 -0
  214. oscura/dsl/parser.py +689 -0
  215. oscura/dsl/repl.py +172 -0
  216. oscura/exceptions.py +59 -0
  217. oscura/exploratory/__init__.py +111 -0
  218. oscura/exploratory/error_recovery.py +642 -0
  219. oscura/exploratory/fuzzy.py +513 -0
  220. oscura/exploratory/fuzzy_advanced.py +786 -0
  221. oscura/exploratory/legacy.py +831 -0
  222. oscura/exploratory/parse.py +358 -0
  223. oscura/exploratory/recovery.py +275 -0
  224. oscura/exploratory/sync.py +382 -0
  225. oscura/exploratory/unknown.py +707 -0
  226. oscura/export/__init__.py +25 -0
  227. oscura/export/wireshark/README.md +265 -0
  228. oscura/export/wireshark/__init__.py +47 -0
  229. oscura/export/wireshark/generator.py +312 -0
  230. oscura/export/wireshark/lua_builder.py +159 -0
  231. oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
  232. oscura/export/wireshark/type_mapping.py +165 -0
  233. oscura/export/wireshark/validator.py +105 -0
  234. oscura/exporters/__init__.py +94 -0
  235. oscura/exporters/csv.py +303 -0
  236. oscura/exporters/exporters.py +44 -0
  237. oscura/exporters/hdf5.py +219 -0
  238. oscura/exporters/html_export.py +701 -0
  239. oscura/exporters/json_export.py +291 -0
  240. oscura/exporters/markdown_export.py +367 -0
  241. oscura/exporters/matlab_export.py +354 -0
  242. oscura/exporters/npz_export.py +219 -0
  243. oscura/exporters/spice_export.py +210 -0
  244. oscura/extensibility/__init__.py +131 -0
  245. oscura/extensibility/docs.py +752 -0
  246. oscura/extensibility/extensions.py +1125 -0
  247. oscura/extensibility/logging.py +259 -0
  248. oscura/extensibility/measurements.py +485 -0
  249. oscura/extensibility/plugins.py +414 -0
  250. oscura/extensibility/registry.py +346 -0
  251. oscura/extensibility/templates.py +913 -0
  252. oscura/extensibility/validation.py +651 -0
  253. oscura/filtering/__init__.py +89 -0
  254. oscura/filtering/base.py +563 -0
  255. oscura/filtering/convenience.py +564 -0
  256. oscura/filtering/design.py +725 -0
  257. oscura/filtering/filters.py +32 -0
  258. oscura/filtering/introspection.py +605 -0
  259. oscura/guidance/__init__.py +24 -0
  260. oscura/guidance/recommender.py +429 -0
  261. oscura/guidance/wizard.py +518 -0
  262. oscura/inference/__init__.py +251 -0
  263. oscura/inference/active_learning/README.md +153 -0
  264. oscura/inference/active_learning/__init__.py +38 -0
  265. oscura/inference/active_learning/lstar.py +257 -0
  266. oscura/inference/active_learning/observation_table.py +230 -0
  267. oscura/inference/active_learning/oracle.py +78 -0
  268. oscura/inference/active_learning/teachers/__init__.py +15 -0
  269. oscura/inference/active_learning/teachers/simulator.py +192 -0
  270. oscura/inference/adaptive_tuning.py +453 -0
  271. oscura/inference/alignment.py +653 -0
  272. oscura/inference/bayesian.py +943 -0
  273. oscura/inference/binary.py +1016 -0
  274. oscura/inference/crc_reverse.py +711 -0
  275. oscura/inference/logic.py +288 -0
  276. oscura/inference/message_format.py +1305 -0
  277. oscura/inference/protocol.py +417 -0
  278. oscura/inference/protocol_dsl.py +1084 -0
  279. oscura/inference/protocol_library.py +1230 -0
  280. oscura/inference/sequences.py +809 -0
  281. oscura/inference/signal_intelligence.py +1509 -0
  282. oscura/inference/spectral.py +215 -0
  283. oscura/inference/state_machine.py +634 -0
  284. oscura/inference/stream.py +918 -0
  285. oscura/integrations/__init__.py +59 -0
  286. oscura/integrations/llm.py +1827 -0
  287. oscura/jupyter/__init__.py +32 -0
  288. oscura/jupyter/display.py +268 -0
  289. oscura/jupyter/magic.py +334 -0
  290. oscura/loaders/__init__.py +526 -0
  291. oscura/loaders/binary.py +69 -0
  292. oscura/loaders/configurable.py +1255 -0
  293. oscura/loaders/csv.py +26 -0
  294. oscura/loaders/csv_loader.py +473 -0
  295. oscura/loaders/hdf5.py +9 -0
  296. oscura/loaders/hdf5_loader.py +510 -0
  297. oscura/loaders/lazy.py +370 -0
  298. oscura/loaders/mmap_loader.py +583 -0
  299. oscura/loaders/numpy_loader.py +436 -0
  300. oscura/loaders/pcap.py +432 -0
  301. oscura/loaders/preprocessing.py +368 -0
  302. oscura/loaders/rigol.py +287 -0
  303. oscura/loaders/sigrok.py +321 -0
  304. oscura/loaders/tdms.py +367 -0
  305. oscura/loaders/tektronix.py +711 -0
  306. oscura/loaders/validation.py +584 -0
  307. oscura/loaders/vcd.py +464 -0
  308. oscura/loaders/wav.py +233 -0
  309. oscura/math/__init__.py +45 -0
  310. oscura/math/arithmetic.py +824 -0
  311. oscura/math/interpolation.py +413 -0
  312. oscura/onboarding/__init__.py +39 -0
  313. oscura/onboarding/help.py +498 -0
  314. oscura/onboarding/tutorials.py +405 -0
  315. oscura/onboarding/wizard.py +466 -0
  316. oscura/optimization/__init__.py +19 -0
  317. oscura/optimization/parallel.py +440 -0
  318. oscura/optimization/search.py +532 -0
  319. oscura/pipeline/__init__.py +43 -0
  320. oscura/pipeline/base.py +338 -0
  321. oscura/pipeline/composition.py +242 -0
  322. oscura/pipeline/parallel.py +448 -0
  323. oscura/pipeline/pipeline.py +375 -0
  324. oscura/pipeline/reverse_engineering.py +1119 -0
  325. oscura/plugins/__init__.py +122 -0
  326. oscura/plugins/base.py +272 -0
  327. oscura/plugins/cli.py +497 -0
  328. oscura/plugins/discovery.py +411 -0
  329. oscura/plugins/isolation.py +418 -0
  330. oscura/plugins/lifecycle.py +959 -0
  331. oscura/plugins/manager.py +493 -0
  332. oscura/plugins/registry.py +421 -0
  333. oscura/plugins/versioning.py +372 -0
  334. oscura/py.typed +0 -0
  335. oscura/quality/__init__.py +65 -0
  336. oscura/quality/ensemble.py +740 -0
  337. oscura/quality/explainer.py +338 -0
  338. oscura/quality/scoring.py +616 -0
  339. oscura/quality/warnings.py +456 -0
  340. oscura/reporting/__init__.py +248 -0
  341. oscura/reporting/advanced.py +1234 -0
  342. oscura/reporting/analyze.py +448 -0
  343. oscura/reporting/argument_preparer.py +596 -0
  344. oscura/reporting/auto_report.py +507 -0
  345. oscura/reporting/batch.py +615 -0
  346. oscura/reporting/chart_selection.py +223 -0
  347. oscura/reporting/comparison.py +330 -0
  348. oscura/reporting/config.py +615 -0
  349. oscura/reporting/content/__init__.py +39 -0
  350. oscura/reporting/content/executive.py +127 -0
  351. oscura/reporting/content/filtering.py +191 -0
  352. oscura/reporting/content/minimal.py +257 -0
  353. oscura/reporting/content/verbosity.py +162 -0
  354. oscura/reporting/core.py +508 -0
  355. oscura/reporting/core_formats/__init__.py +17 -0
  356. oscura/reporting/core_formats/multi_format.py +210 -0
  357. oscura/reporting/engine.py +836 -0
  358. oscura/reporting/export.py +366 -0
  359. oscura/reporting/formatting/__init__.py +129 -0
  360. oscura/reporting/formatting/emphasis.py +81 -0
  361. oscura/reporting/formatting/numbers.py +403 -0
  362. oscura/reporting/formatting/standards.py +55 -0
  363. oscura/reporting/formatting.py +466 -0
  364. oscura/reporting/html.py +578 -0
  365. oscura/reporting/index.py +590 -0
  366. oscura/reporting/multichannel.py +296 -0
  367. oscura/reporting/output.py +379 -0
  368. oscura/reporting/pdf.py +373 -0
  369. oscura/reporting/plots.py +731 -0
  370. oscura/reporting/pptx_export.py +360 -0
  371. oscura/reporting/renderers/__init__.py +11 -0
  372. oscura/reporting/renderers/pdf.py +94 -0
  373. oscura/reporting/sections.py +471 -0
  374. oscura/reporting/standards.py +680 -0
  375. oscura/reporting/summary_generator.py +368 -0
  376. oscura/reporting/tables.py +397 -0
  377. oscura/reporting/template_system.py +724 -0
  378. oscura/reporting/templates/__init__.py +15 -0
  379. oscura/reporting/templates/definition.py +205 -0
  380. oscura/reporting/templates/index.html +649 -0
  381. oscura/reporting/templates/index.md +173 -0
  382. oscura/schemas/__init__.py +158 -0
  383. oscura/schemas/bus_configuration.json +322 -0
  384. oscura/schemas/device_mapping.json +182 -0
  385. oscura/schemas/packet_format.json +418 -0
  386. oscura/schemas/protocol_definition.json +363 -0
  387. oscura/search/__init__.py +16 -0
  388. oscura/search/anomaly.py +292 -0
  389. oscura/search/context.py +149 -0
  390. oscura/search/pattern.py +160 -0
  391. oscura/session/__init__.py +34 -0
  392. oscura/session/annotations.py +289 -0
  393. oscura/session/history.py +313 -0
  394. oscura/session/session.py +445 -0
  395. oscura/streaming/__init__.py +43 -0
  396. oscura/streaming/chunked.py +611 -0
  397. oscura/streaming/progressive.py +393 -0
  398. oscura/streaming/realtime.py +622 -0
  399. oscura/testing/__init__.py +54 -0
  400. oscura/testing/synthetic.py +808 -0
  401. oscura/triggering/__init__.py +68 -0
  402. oscura/triggering/base.py +229 -0
  403. oscura/triggering/edge.py +353 -0
  404. oscura/triggering/pattern.py +344 -0
  405. oscura/triggering/pulse.py +581 -0
  406. oscura/triggering/window.py +453 -0
  407. oscura/ui/__init__.py +48 -0
  408. oscura/ui/formatters.py +526 -0
  409. oscura/ui/progressive_display.py +340 -0
  410. oscura/utils/__init__.py +99 -0
  411. oscura/utils/autodetect.py +338 -0
  412. oscura/utils/buffer.py +389 -0
  413. oscura/utils/lazy.py +407 -0
  414. oscura/utils/lazy_imports.py +147 -0
  415. oscura/utils/memory.py +836 -0
  416. oscura/utils/memory_advanced.py +1326 -0
  417. oscura/utils/memory_extensions.py +465 -0
  418. oscura/utils/progressive.py +352 -0
  419. oscura/utils/windowing.py +362 -0
  420. oscura/visualization/__init__.py +321 -0
  421. oscura/visualization/accessibility.py +526 -0
  422. oscura/visualization/annotations.py +374 -0
  423. oscura/visualization/axis_scaling.py +305 -0
  424. oscura/visualization/colors.py +453 -0
  425. oscura/visualization/digital.py +337 -0
  426. oscura/visualization/eye.py +420 -0
  427. oscura/visualization/histogram.py +281 -0
  428. oscura/visualization/interactive.py +858 -0
  429. oscura/visualization/jitter.py +702 -0
  430. oscura/visualization/keyboard.py +394 -0
  431. oscura/visualization/layout.py +365 -0
  432. oscura/visualization/optimization.py +1028 -0
  433. oscura/visualization/palettes.py +446 -0
  434. oscura/visualization/plot.py +92 -0
  435. oscura/visualization/power.py +290 -0
  436. oscura/visualization/power_extended.py +626 -0
  437. oscura/visualization/presets.py +467 -0
  438. oscura/visualization/protocols.py +932 -0
  439. oscura/visualization/render.py +207 -0
  440. oscura/visualization/rendering.py +444 -0
  441. oscura/visualization/reverse_engineering.py +791 -0
  442. oscura/visualization/signal_integrity.py +808 -0
  443. oscura/visualization/specialized.py +553 -0
  444. oscura/visualization/spectral.py +811 -0
  445. oscura/visualization/styles.py +381 -0
  446. oscura/visualization/thumbnails.py +311 -0
  447. oscura/visualization/time_axis.py +351 -0
  448. oscura/visualization/waveform.py +367 -0
  449. oscura/workflow/__init__.py +13 -0
  450. oscura/workflow/dag.py +377 -0
  451. oscura/workflows/__init__.py +58 -0
  452. oscura/workflows/compliance.py +280 -0
  453. oscura/workflows/digital.py +272 -0
  454. oscura/workflows/multi_trace.py +502 -0
  455. oscura/workflows/power.py +178 -0
  456. oscura/workflows/protocol.py +492 -0
  457. oscura/workflows/reverse_engineering.py +639 -0
  458. oscura/workflows/signal_integrity.py +227 -0
  459. oscura-0.1.0.dist-info/METADATA +300 -0
  460. oscura-0.1.0.dist-info/RECORD +463 -0
  461. oscura-0.1.0.dist-info/entry_points.txt +2 -0
  462. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/licenses/LICENSE +1 -1
  463. oscura-0.0.1.dist-info/METADATA +0 -63
  464. oscura-0.0.1.dist-info/RECORD +0 -5
  465. {oscura-0.0.1.dist-info → oscura-0.1.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,403 @@
1
+ """Number formatting utilities for signal analysis reports.
2
+
3
+ Provides comprehensive number formatting with SI prefixes, engineering notation,
4
+ locale support, and specification comparison capabilities.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ from datetime import datetime
11
+ from typing import ClassVar
12
+
13
+
14
+ class NumberFormatter:
15
+ """Comprehensive number formatting utility with SI prefix support.
16
+
17
+ Attributes:
18
+ sig_figs: Number of significant figures to display.
19
+ auto_scale: Whether to automatically scale to appropriate SI prefix.
20
+ engineering_notation: Use engineering notation (powers of 3).
21
+ unicode_prefixes: Use Unicode characters for prefixes (µ vs u).
22
+
23
+ Examples:
24
+ >>> fmt = NumberFormatter(sig_figs=3)
25
+ >>> fmt.format(2.3e-9, "s")
26
+ '2.30 ns'
27
+ >>> fmt.format(1.5e6, "Hz")
28
+ '1.50 MHz'
29
+ """
30
+
31
+ # SI prefixes (powers of 10)
32
+ # Unicode uses Greek Small Letter Mu (U+03BC), ASCII uses 'u'
33
+ SI_PREFIXES: ClassVar[dict[int, tuple[str, str]]] = {
34
+ -15: ("f", "f"), # femto
35
+ -12: ("p", "p"), # pico
36
+ -9: ("n", "n"), # nano
37
+ -6: ("\u03bc", "u"), # micro (Greek mu U+03BC, ascii 'u')
38
+ -3: ("m", "m"), # milli
39
+ 0: ("", ""), # base
40
+ 3: ("k", "k"), # kilo
41
+ 6: ("M", "M"), # mega
42
+ 9: ("G", "G"), # giga
43
+ 12: ("T", "T"), # tera
44
+ }
45
+
46
+ def __init__(
47
+ self,
48
+ sig_figs: int = 3,
49
+ auto_scale: bool = True,
50
+ engineering_notation: bool = True,
51
+ unicode_prefixes: bool = True,
52
+ precision: int | None = None,
53
+ use_si: bool | None = None,
54
+ ) -> None:
55
+ """Initialize formatter.
56
+
57
+ Args:
58
+ sig_figs: Number of significant figures (default 3).
59
+ auto_scale: Enable automatic SI prefix scaling (default True).
60
+ engineering_notation: Use engineering notation (default True).
61
+ unicode_prefixes: Use Unicode prefixes like µ (default True).
62
+ precision: Alias for sig_figs (backwards compatibility).
63
+ use_si: Alias for auto_scale (backwards compatibility).
64
+ """
65
+ # Handle backwards compatibility aliases
66
+ self.sig_figs = precision if precision is not None else sig_figs
67
+ self.auto_scale = use_si if use_si is not None else auto_scale
68
+ self.engineering_notation = engineering_notation
69
+ self.unicode_prefixes = unicode_prefixes
70
+
71
+ # Legacy attribute for backwards compatibility
72
+ self.precision = self.sig_figs
73
+ self.use_si = self.auto_scale
74
+
75
+ def format(
76
+ self,
77
+ value: float,
78
+ unit: str = "",
79
+ decimal_places: int | None = None,
80
+ ) -> str:
81
+ """Format a number with optional SI prefix.
82
+
83
+ Args:
84
+ value: Numeric value to format.
85
+ unit: Unit of measurement (e.g., "V", "Hz", "s").
86
+ decimal_places: Override number of decimal places.
87
+
88
+ Returns:
89
+ Formatted string with value, prefix, and unit.
90
+
91
+ Examples:
92
+ >>> fmt = NumberFormatter()
93
+ >>> fmt.format(2.3e-6, "s")
94
+ '2.300 µs'
95
+ >>> fmt.format(1500000, "Hz")
96
+ '1.500 MHz'
97
+ """
98
+ # Handle special float values
99
+ if math.isnan(value):
100
+ return f"NaN {unit}".strip()
101
+ if math.isinf(value):
102
+ sign = "-" if value < 0 else ""
103
+ return f"{sign}Inf {unit}".strip()
104
+
105
+ # Determine precision
106
+ places = decimal_places if decimal_places is not None else self.sig_figs
107
+
108
+ if not self.auto_scale:
109
+ # No scaling - show full value with appropriate precision
110
+ # Use more decimal places for small numbers to show actual value
111
+ if abs(value) != 0 and abs(value) < 1:
112
+ # Calculate needed decimal places to show significant figures
113
+ from math import floor, log10
114
+
115
+ order = floor(log10(abs(value)))
116
+ # For value like 0.0023, order=-3, need at least 4 decimals
117
+ decimal_places_needed = max(places, abs(order) + 1)
118
+ return f"{value:.{decimal_places_needed}f} {unit}".strip()
119
+ elif abs(value) >= 1e6:
120
+ return f"{value:.{places}e} {unit}".strip()
121
+ return f"{value:.{places}f} {unit}".strip()
122
+
123
+ # Find appropriate SI prefix
124
+ if value == 0:
125
+ return f"0.{'0' * places} {unit}".strip()
126
+
127
+ abs_val = abs(value)
128
+
129
+ # Determine the appropriate power of 10
130
+ if abs_val < 1e-15:
131
+ return f"{value:.{places}e} {unit}".strip()
132
+ elif abs_val < 1e-12:
133
+ scaled, exp = value * 1e15, -15
134
+ elif abs_val < 1e-9:
135
+ scaled, exp = value * 1e12, -12
136
+ elif abs_val < 1e-6:
137
+ scaled, exp = value * 1e9, -9
138
+ elif abs_val < 1e-3:
139
+ scaled, exp = value * 1e6, -6
140
+ elif abs_val < 1:
141
+ scaled, exp = value * 1e3, -3
142
+ elif abs_val < 1e3:
143
+ scaled, exp = value, 0
144
+ elif abs_val < 1e6:
145
+ scaled, exp = value / 1e3, 3
146
+ elif abs_val < 1e9:
147
+ scaled, exp = value / 1e6, 6
148
+ elif abs_val < 1e12:
149
+ scaled, exp = value / 1e9, 9
150
+ elif abs_val < 1e15:
151
+ scaled, exp = value / 1e12, 12
152
+ else:
153
+ return f"{value:.{places}e} {unit}".strip()
154
+
155
+ # Get prefix (unicode or ascii)
156
+ prefix_idx = 0 if self.unicode_prefixes else 1
157
+ prefix = self.SI_PREFIXES.get(exp, ("", ""))[prefix_idx]
158
+
159
+ return f"{scaled:.{places}f} {prefix}{unit}".strip()
160
+
161
+ def format_percentage(self, value: float, decimals: int = 1) -> str:
162
+ """Format a value as a percentage.
163
+
164
+ Args:
165
+ value: Value as decimal (0.543 = 54.3%) or already percentage.
166
+ decimals: Number of decimal places.
167
+
168
+ Returns:
169
+ Formatted percentage string.
170
+
171
+ Examples:
172
+ >>> fmt = NumberFormatter()
173
+ >>> fmt.format_percentage(0.543)
174
+ '54.3%'
175
+ """
176
+ # If value > 1, assume it's already a percentage
177
+ if abs(value) > 1:
178
+ return f"{value:.{decimals}f}%"
179
+ return f"{value * 100:.{decimals}f}%"
180
+
181
+ def format_range(
182
+ self,
183
+ min_val: float,
184
+ typ_val: float,
185
+ max_val: float,
186
+ unit: str = "",
187
+ ) -> str:
188
+ """Format min/typ/max range.
189
+
190
+ Args:
191
+ min_val: Minimum value.
192
+ typ_val: Typical value.
193
+ max_val: Maximum value.
194
+ unit: Unit of measurement.
195
+
196
+ Returns:
197
+ Formatted range string.
198
+
199
+ Examples:
200
+ >>> fmt = NumberFormatter()
201
+ >>> fmt.format_range(1e-6, 2e-6, 3e-6, "s")
202
+ 'min=1.000 µs typ=2.000 µs max=3.000 µs'
203
+ """
204
+ return (
205
+ f"min={self.format(min_val, unit)} "
206
+ f"typ={self.format(typ_val, unit)} "
207
+ f"max={self.format(max_val, unit)}"
208
+ )
209
+
210
+
211
+ def format_value(
212
+ value: float,
213
+ unit_or_precision: str | int = 3,
214
+ unit: str = "",
215
+ sig_figs: int | None = None,
216
+ ) -> str:
217
+ """Format a numeric value with SI prefix.
218
+
219
+ Args:
220
+ value: Value to format.
221
+ unit_or_precision: Either unit (str) or precision (int).
222
+ unit: Unit string (if precision specified first).
223
+ sig_figs: Number of significant figures (alternative to precision arg).
224
+
225
+ Returns:
226
+ Formatted value with appropriate SI prefix.
227
+
228
+ Examples:
229
+ >>> format_value(2.3e-9, "s")
230
+ '2.300 ns'
231
+ >>> format_value(1.5e6, 4, "Hz")
232
+ '1.5000 MHz'
233
+ """
234
+ # Handle flexible arguments
235
+ if isinstance(unit_or_precision, str):
236
+ precision = sig_figs if sig_figs is not None else 3
237
+ actual_unit = unit_or_precision
238
+ else:
239
+ precision = sig_figs if sig_figs is not None else unit_or_precision
240
+ actual_unit = unit
241
+
242
+ fmt = NumberFormatter(sig_figs=precision)
243
+ return fmt.format(value, actual_unit)
244
+
245
+
246
+ def format_with_units(value: float, unit: str, sig_figs: int = 3) -> str:
247
+ """Format value with units and SI prefix.
248
+
249
+ Args:
250
+ value: Numeric value.
251
+ unit: Unit of measurement.
252
+ sig_figs: Number of significant figures.
253
+
254
+ Returns:
255
+ Formatted string with value and unit.
256
+ """
257
+ fmt = NumberFormatter(sig_figs=sig_figs)
258
+ return fmt.format(value, unit)
259
+
260
+
261
+ def format_with_context(
262
+ value: float,
263
+ context: str = "",
264
+ spec: float | None = None,
265
+ unit: str = "",
266
+ spec_type: str = "max",
267
+ show_margin: bool = True,
268
+ ) -> str:
269
+ """Format value with context and specification comparison.
270
+
271
+ Args:
272
+ value: Value to format.
273
+ context: Context string for display.
274
+ spec: Specification limit for comparison.
275
+ unit: Unit of measurement.
276
+ spec_type: Type of specification ("max", "min", or "exact").
277
+ show_margin: Whether to show margin percentage.
278
+
279
+ Returns:
280
+ Formatted string with pass/fail indication if spec provided.
281
+
282
+ Examples:
283
+ >>> format_with_context(2.3e-9, spec=5e-9, unit="s", spec_type="max")
284
+ '2.300 ns ✓'
285
+ """
286
+ formatted = format_value(value, unit)
287
+
288
+ if spec is not None:
289
+ # Determine pass/fail
290
+ if spec_type == "max":
291
+ passed = value <= spec
292
+ margin = ((spec - value) / spec * 100) if spec != 0 else 0
293
+ elif spec_type == "min":
294
+ passed = value >= spec
295
+ margin = ((value - spec) / spec * 100) if spec != 0 else 0
296
+ else: # exact
297
+ tolerance = abs(spec * 0.01) # 1% tolerance
298
+ passed = abs(value - spec) <= tolerance
299
+ margin = 100 - abs((value - spec) / spec * 100) if spec != 0 else 100
300
+
301
+ # Unicode checkmark/cross
302
+ status = "\u2713" if passed else "\u2717"
303
+
304
+ if show_margin and passed:
305
+ return f"{formatted} {status} ({margin:.1f}% margin)"
306
+ return f"{formatted} {status}"
307
+
308
+ if context:
309
+ return f"{formatted} ({context})"
310
+ return formatted
311
+
312
+
313
+ def format_percentage(value: float, decimals: int = 1) -> str:
314
+ """Format as percentage.
315
+
316
+ Args:
317
+ value: Value as decimal (0.5 = 50%) or already percentage (>1).
318
+ decimals: Number of decimal places.
319
+
320
+ Returns:
321
+ Formatted percentage string.
322
+ """
323
+ if abs(value) > 1:
324
+ return f"{value:.{decimals}f}%"
325
+ return f"{value * 100:.{decimals}f}%"
326
+
327
+
328
+ def format_range(min_val: float, max_val: float, unit: str = "") -> str:
329
+ """Format a range of values.
330
+
331
+ Args:
332
+ min_val: Minimum value.
333
+ max_val: Maximum value.
334
+ unit: Unit of measurement.
335
+
336
+ Returns:
337
+ Formatted range string.
338
+ """
339
+ return f"{format_value(min_val, unit)} to {format_value(max_val, unit)}"
340
+
341
+
342
+ def format_with_locale(
343
+ value: float | None = None,
344
+ locale: str = "en_US",
345
+ date_value: float | None = None,
346
+ ) -> str:
347
+ """Format value with locale-specific formatting.
348
+
349
+ Args:
350
+ value: Numeric value to format.
351
+ locale: Locale string (e.g., 'en_US', 'de_DE', 'fr_FR').
352
+ date_value: Unix timestamp for date formatting.
353
+
354
+ Returns:
355
+ Formatted string with locale-specific separators.
356
+ Returns empty string if value is None and no date_value.
357
+
358
+ Examples:
359
+ >>> format_with_locale(1234.56, locale="en_US")
360
+ '1,234.56'
361
+ >>> format_with_locale(1234.56, locale="de_DE")
362
+ '1.234,56'
363
+ """
364
+ # Handle date formatting
365
+ if date_value is not None:
366
+ dt = datetime.fromtimestamp(date_value)
367
+ if locale.startswith("en"):
368
+ return dt.strftime("%m/%d/%Y")
369
+ elif locale.startswith("de"):
370
+ return dt.strftime("%d.%m.%Y")
371
+ elif locale.startswith("fr"):
372
+ return dt.strftime("%d/%m/%Y")
373
+ else:
374
+ return dt.strftime("%Y-%m-%d")
375
+
376
+ # Handle None value gracefully
377
+ if value is None:
378
+ return ""
379
+
380
+ # Handle numeric formatting by locale
381
+ if locale.startswith("en"):
382
+ return f"{value:,.2f}"
383
+ elif locale.startswith("de"):
384
+ # German: 1.234,56
385
+ formatted = f"{value:,.2f}"
386
+ return formatted.replace(",", "X").replace(".", ",").replace("X", ".")
387
+ elif locale.startswith("fr"):
388
+ # French: 1 234,56 (narrow no-break space for thousands)
389
+ formatted = f"{value:,.2f}"
390
+ return formatted.replace(",", " ").replace(".", ",")
391
+ else:
392
+ return f"{value:,.2f}"
393
+
394
+
395
+ __all__ = [
396
+ "NumberFormatter",
397
+ "format_percentage",
398
+ "format_range",
399
+ "format_value",
400
+ "format_with_context",
401
+ "format_with_locale",
402
+ "format_with_units",
403
+ ]
@@ -0,0 +1,55 @@
1
+ """Formatting standards."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from enum import Enum
5
+ from typing import Any
6
+
7
+
8
+ class Severity(Enum):
9
+ """Severity levels."""
10
+
11
+ INFO = "info"
12
+ WARNING = "warning"
13
+ ERROR = "error"
14
+ CRITICAL = "critical"
15
+ SUCCESS = "success"
16
+
17
+
18
+ @dataclass
19
+ class ColorScheme:
20
+ """Color scheme for reports."""
21
+
22
+ primary: str = "#007ACC"
23
+ secondary: str = "#6C757D"
24
+ success: str = "#28A745"
25
+ warning: str = "#FFC107"
26
+ error: str = "#DC3545"
27
+ info: str = "#17A2B8"
28
+
29
+
30
+ @dataclass
31
+ class FormatStandards:
32
+ """Formatting standards for reports."""
33
+
34
+ title_size: int = 18
35
+ heading_size: int = 14
36
+ body_size: int = 10
37
+ code_font: str = "Courier New"
38
+ body_font: str = "Arial"
39
+ colors: ColorScheme = field(default_factory=ColorScheme)
40
+
41
+
42
+ def apply_formatting_standards(content: Any, standards: FormatStandards | None = None) -> Any:
43
+ """Apply formatting standards to content."""
44
+ if standards is None:
45
+ standards = FormatStandards()
46
+ # Placeholder implementation
47
+ return content
48
+
49
+
50
+ __all__ = [
51
+ "ColorScheme",
52
+ "FormatStandards",
53
+ "Severity",
54
+ "apply_formatting_standards",
55
+ ]