oscura 0.5.1__py3-none-any.whl → 0.7.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 (497) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/edges.py +325 -65
  5. oscura/analyzers/digital/quality.py +293 -166
  6. oscura/analyzers/digital/timing.py +260 -115
  7. oscura/analyzers/digital/timing_numba.py +334 -0
  8. oscura/analyzers/entropy.py +605 -0
  9. oscura/analyzers/eye/diagram.py +176 -109
  10. oscura/analyzers/eye/metrics.py +5 -5
  11. oscura/analyzers/jitter/__init__.py +6 -4
  12. oscura/analyzers/jitter/ber.py +52 -52
  13. oscura/analyzers/jitter/classification.py +156 -0
  14. oscura/analyzers/jitter/decomposition.py +163 -113
  15. oscura/analyzers/jitter/spectrum.py +80 -64
  16. oscura/analyzers/ml/__init__.py +39 -0
  17. oscura/analyzers/ml/features.py +600 -0
  18. oscura/analyzers/ml/signal_classifier.py +604 -0
  19. oscura/analyzers/packet/daq.py +246 -158
  20. oscura/analyzers/packet/parser.py +12 -1
  21. oscura/analyzers/packet/payload.py +50 -2110
  22. oscura/analyzers/packet/payload_analysis.py +361 -181
  23. oscura/analyzers/packet/payload_patterns.py +133 -70
  24. oscura/analyzers/packet/stream.py +84 -23
  25. oscura/analyzers/patterns/__init__.py +26 -5
  26. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  27. oscura/analyzers/patterns/clustering.py +169 -108
  28. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  29. oscura/analyzers/patterns/discovery.py +1 -1
  30. oscura/analyzers/patterns/matching.py +581 -197
  31. oscura/analyzers/patterns/pattern_mining.py +778 -0
  32. oscura/analyzers/patterns/periodic.py +121 -38
  33. oscura/analyzers/patterns/sequences.py +175 -78
  34. oscura/analyzers/power/conduction.py +1 -1
  35. oscura/analyzers/power/soa.py +6 -6
  36. oscura/analyzers/power/switching.py +250 -110
  37. oscura/analyzers/protocol/__init__.py +17 -1
  38. oscura/analyzers/protocols/base.py +6 -6
  39. oscura/analyzers/protocols/ble/__init__.py +38 -0
  40. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  41. oscura/analyzers/protocols/ble/uuids.py +288 -0
  42. oscura/analyzers/protocols/can.py +257 -127
  43. oscura/analyzers/protocols/can_fd.py +107 -80
  44. oscura/analyzers/protocols/flexray.py +139 -80
  45. oscura/analyzers/protocols/hdlc.py +93 -58
  46. oscura/analyzers/protocols/i2c.py +247 -106
  47. oscura/analyzers/protocols/i2s.py +138 -86
  48. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  49. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  50. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  51. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  52. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  53. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  54. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  55. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  56. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  57. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  58. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  59. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  60. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  61. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  62. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  63. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  64. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  65. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  66. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  67. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  68. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  69. oscura/analyzers/protocols/jtag.py +180 -98
  70. oscura/analyzers/protocols/lin.py +219 -114
  71. oscura/analyzers/protocols/manchester.py +4 -4
  72. oscura/analyzers/protocols/onewire.py +253 -149
  73. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  74. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  75. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  76. oscura/analyzers/protocols/spi.py +192 -95
  77. oscura/analyzers/protocols/swd.py +321 -167
  78. oscura/analyzers/protocols/uart.py +267 -125
  79. oscura/analyzers/protocols/usb.py +235 -131
  80. oscura/analyzers/side_channel/power.py +17 -12
  81. oscura/analyzers/signal/__init__.py +15 -0
  82. oscura/analyzers/signal/timing_analysis.py +1086 -0
  83. oscura/analyzers/signal_integrity/__init__.py +4 -1
  84. oscura/analyzers/signal_integrity/sparams.py +2 -19
  85. oscura/analyzers/spectral/chunked.py +129 -60
  86. oscura/analyzers/spectral/chunked_fft.py +300 -94
  87. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  88. oscura/analyzers/statistical/checksum.py +376 -217
  89. oscura/analyzers/statistical/classification.py +229 -107
  90. oscura/analyzers/statistical/entropy.py +78 -53
  91. oscura/analyzers/statistics/correlation.py +407 -211
  92. oscura/analyzers/statistics/outliers.py +2 -2
  93. oscura/analyzers/statistics/streaming.py +30 -5
  94. oscura/analyzers/validation.py +216 -101
  95. oscura/analyzers/waveform/measurements.py +9 -0
  96. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  97. oscura/analyzers/waveform/spectral.py +500 -228
  98. oscura/api/__init__.py +31 -5
  99. oscura/api/dsl/__init__.py +582 -0
  100. oscura/{dsl → api/dsl}/commands.py +43 -76
  101. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  102. oscura/{dsl → api/dsl}/parser.py +107 -77
  103. oscura/{dsl → api/dsl}/repl.py +2 -2
  104. oscura/api/dsl.py +1 -1
  105. oscura/{integrations → api/integrations}/__init__.py +1 -1
  106. oscura/{integrations → api/integrations}/llm.py +201 -102
  107. oscura/api/operators.py +3 -3
  108. oscura/api/optimization.py +144 -30
  109. oscura/api/rest_server.py +921 -0
  110. oscura/api/server/__init__.py +17 -0
  111. oscura/api/server/dashboard.py +850 -0
  112. oscura/api/server/static/README.md +34 -0
  113. oscura/api/server/templates/base.html +181 -0
  114. oscura/api/server/templates/export.html +120 -0
  115. oscura/api/server/templates/home.html +284 -0
  116. oscura/api/server/templates/protocols.html +58 -0
  117. oscura/api/server/templates/reports.html +43 -0
  118. oscura/api/server/templates/session_detail.html +89 -0
  119. oscura/api/server/templates/sessions.html +83 -0
  120. oscura/api/server/templates/waveforms.html +73 -0
  121. oscura/automotive/__init__.py +8 -1
  122. oscura/automotive/can/__init__.py +10 -0
  123. oscura/automotive/can/checksum.py +3 -1
  124. oscura/automotive/can/dbc_generator.py +590 -0
  125. oscura/automotive/can/message_wrapper.py +121 -74
  126. oscura/automotive/can/patterns.py +98 -21
  127. oscura/automotive/can/session.py +292 -56
  128. oscura/automotive/can/state_machine.py +6 -3
  129. oscura/automotive/can/stimulus_response.py +97 -75
  130. oscura/automotive/dbc/__init__.py +10 -2
  131. oscura/automotive/dbc/generator.py +84 -56
  132. oscura/automotive/dbc/parser.py +6 -6
  133. oscura/automotive/dtc/data.json +17 -102
  134. oscura/automotive/dtc/database.py +2 -2
  135. oscura/automotive/flexray/__init__.py +31 -0
  136. oscura/automotive/flexray/analyzer.py +504 -0
  137. oscura/automotive/flexray/crc.py +185 -0
  138. oscura/automotive/flexray/fibex.py +449 -0
  139. oscura/automotive/j1939/__init__.py +45 -8
  140. oscura/automotive/j1939/analyzer.py +605 -0
  141. oscura/automotive/j1939/spns.py +326 -0
  142. oscura/automotive/j1939/transport.py +306 -0
  143. oscura/automotive/lin/__init__.py +47 -0
  144. oscura/automotive/lin/analyzer.py +612 -0
  145. oscura/automotive/loaders/blf.py +13 -2
  146. oscura/automotive/loaders/csv_can.py +143 -72
  147. oscura/automotive/loaders/dispatcher.py +50 -2
  148. oscura/automotive/loaders/mdf.py +86 -45
  149. oscura/automotive/loaders/pcap.py +111 -61
  150. oscura/automotive/uds/__init__.py +4 -0
  151. oscura/automotive/uds/analyzer.py +725 -0
  152. oscura/automotive/uds/decoder.py +140 -58
  153. oscura/automotive/uds/models.py +7 -1
  154. oscura/automotive/visualization.py +1 -1
  155. oscura/cli/analyze.py +348 -0
  156. oscura/cli/batch.py +142 -122
  157. oscura/cli/benchmark.py +275 -0
  158. oscura/cli/characterize.py +137 -82
  159. oscura/cli/compare.py +224 -131
  160. oscura/cli/completion.py +250 -0
  161. oscura/cli/config_cmd.py +361 -0
  162. oscura/cli/decode.py +164 -87
  163. oscura/cli/export.py +286 -0
  164. oscura/cli/main.py +115 -31
  165. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  166. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  167. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  168. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  169. oscura/cli/progress.py +147 -0
  170. oscura/cli/shell.py +157 -135
  171. oscura/cli/validate_cmd.py +204 -0
  172. oscura/cli/visualize.py +158 -0
  173. oscura/convenience.py +125 -79
  174. oscura/core/__init__.py +4 -2
  175. oscura/core/backend_selector.py +3 -3
  176. oscura/core/cache.py +126 -15
  177. oscura/core/cancellation.py +1 -1
  178. oscura/{config → core/config}/__init__.py +20 -11
  179. oscura/{config → core/config}/defaults.py +1 -1
  180. oscura/{config → core/config}/loader.py +7 -5
  181. oscura/{config → core/config}/memory.py +5 -5
  182. oscura/{config → core/config}/migration.py +1 -1
  183. oscura/{config → core/config}/pipeline.py +99 -23
  184. oscura/{config → core/config}/preferences.py +1 -1
  185. oscura/{config → core/config}/protocol.py +3 -3
  186. oscura/{config → core/config}/schema.py +426 -272
  187. oscura/{config → core/config}/settings.py +1 -1
  188. oscura/{config → core/config}/thresholds.py +195 -153
  189. oscura/core/correlation.py +5 -6
  190. oscura/core/cross_domain.py +0 -2
  191. oscura/core/debug.py +9 -5
  192. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  193. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  194. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  195. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  196. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  197. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  198. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  199. oscura/core/gpu_backend.py +11 -7
  200. oscura/core/log_query.py +101 -11
  201. oscura/core/logging.py +126 -54
  202. oscura/core/logging_advanced.py +5 -5
  203. oscura/core/memory_limits.py +108 -70
  204. oscura/core/memory_monitor.py +2 -2
  205. oscura/core/memory_progress.py +7 -7
  206. oscura/core/memory_warnings.py +1 -1
  207. oscura/core/numba_backend.py +13 -13
  208. oscura/{plugins → core/plugins}/__init__.py +9 -9
  209. oscura/{plugins → core/plugins}/base.py +7 -7
  210. oscura/{plugins → core/plugins}/cli.py +3 -3
  211. oscura/{plugins → core/plugins}/discovery.py +186 -106
  212. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  213. oscura/{plugins → core/plugins}/manager.py +7 -7
  214. oscura/{plugins → core/plugins}/registry.py +3 -3
  215. oscura/{plugins → core/plugins}/versioning.py +1 -1
  216. oscura/core/progress.py +16 -1
  217. oscura/core/provenance.py +8 -2
  218. oscura/{schemas → core/schemas}/__init__.py +2 -2
  219. oscura/{schemas → core/schemas}/device_mapping.json +2 -8
  220. oscura/{schemas → core/schemas}/packet_format.json +4 -24
  221. oscura/{schemas → core/schemas}/protocol_definition.json +2 -12
  222. oscura/core/types.py +4 -0
  223. oscura/core/uncertainty.py +3 -3
  224. oscura/correlation/__init__.py +52 -0
  225. oscura/correlation/multi_protocol.py +811 -0
  226. oscura/discovery/auto_decoder.py +117 -35
  227. oscura/discovery/comparison.py +191 -86
  228. oscura/discovery/quality_validator.py +155 -68
  229. oscura/discovery/signal_detector.py +196 -79
  230. oscura/export/__init__.py +18 -8
  231. oscura/export/kaitai_struct.py +513 -0
  232. oscura/export/scapy_layer.py +801 -0
  233. oscura/export/wireshark/generator.py +1 -1
  234. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  235. oscura/export/wireshark_dissector.py +746 -0
  236. oscura/guidance/wizard.py +207 -111
  237. oscura/hardware/__init__.py +19 -0
  238. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  239. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  240. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  241. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  242. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  243. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  244. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  245. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  246. oscura/hardware/firmware/__init__.py +29 -0
  247. oscura/hardware/firmware/pattern_recognition.py +874 -0
  248. oscura/hardware/hal_detector.py +736 -0
  249. oscura/hardware/security/__init__.py +37 -0
  250. oscura/hardware/security/side_channel_detector.py +1126 -0
  251. oscura/inference/__init__.py +4 -0
  252. oscura/inference/active_learning/observation_table.py +4 -1
  253. oscura/inference/alignment.py +216 -123
  254. oscura/inference/bayesian.py +113 -33
  255. oscura/inference/crc_reverse.py +101 -55
  256. oscura/inference/logic.py +6 -2
  257. oscura/inference/message_format.py +342 -183
  258. oscura/inference/protocol.py +95 -44
  259. oscura/inference/protocol_dsl.py +180 -82
  260. oscura/inference/signal_intelligence.py +1439 -706
  261. oscura/inference/spectral.py +99 -57
  262. oscura/inference/state_machine.py +810 -158
  263. oscura/inference/stream.py +270 -110
  264. oscura/iot/__init__.py +34 -0
  265. oscura/iot/coap/__init__.py +32 -0
  266. oscura/iot/coap/analyzer.py +668 -0
  267. oscura/iot/coap/options.py +212 -0
  268. oscura/iot/lorawan/__init__.py +21 -0
  269. oscura/iot/lorawan/crypto.py +206 -0
  270. oscura/iot/lorawan/decoder.py +801 -0
  271. oscura/iot/lorawan/mac_commands.py +341 -0
  272. oscura/iot/mqtt/__init__.py +27 -0
  273. oscura/iot/mqtt/analyzer.py +999 -0
  274. oscura/iot/mqtt/properties.py +315 -0
  275. oscura/iot/zigbee/__init__.py +31 -0
  276. oscura/iot/zigbee/analyzer.py +615 -0
  277. oscura/iot/zigbee/security.py +153 -0
  278. oscura/iot/zigbee/zcl.py +349 -0
  279. oscura/jupyter/display.py +125 -45
  280. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  281. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  282. oscura/jupyter/exploratory/fuzzy.py +746 -0
  283. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  284. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  285. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  286. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  287. oscura/jupyter/exploratory/sync.py +612 -0
  288. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  289. oscura/jupyter/magic.py +4 -4
  290. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  291. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  292. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  293. oscura/loaders/__init__.py +183 -67
  294. oscura/loaders/binary.py +88 -1
  295. oscura/loaders/chipwhisperer.py +153 -137
  296. oscura/loaders/configurable.py +208 -86
  297. oscura/loaders/csv_loader.py +458 -215
  298. oscura/loaders/hdf5_loader.py +278 -119
  299. oscura/loaders/lazy.py +87 -54
  300. oscura/loaders/mmap_loader.py +1 -1
  301. oscura/loaders/numpy_loader.py +253 -116
  302. oscura/loaders/pcap.py +226 -151
  303. oscura/loaders/rigol.py +110 -49
  304. oscura/loaders/sigrok.py +201 -78
  305. oscura/loaders/tdms.py +81 -58
  306. oscura/loaders/tektronix.py +291 -174
  307. oscura/loaders/touchstone.py +182 -87
  308. oscura/loaders/tss.py +456 -0
  309. oscura/loaders/vcd.py +215 -117
  310. oscura/loaders/wav.py +155 -68
  311. oscura/reporting/__init__.py +9 -0
  312. oscura/reporting/analyze.py +352 -146
  313. oscura/reporting/argument_preparer.py +69 -14
  314. oscura/reporting/auto_report.py +97 -61
  315. oscura/reporting/batch.py +131 -58
  316. oscura/reporting/chart_selection.py +57 -45
  317. oscura/reporting/comparison.py +63 -17
  318. oscura/reporting/content/executive.py +76 -24
  319. oscura/reporting/core_formats/multi_format.py +11 -8
  320. oscura/reporting/engine.py +312 -158
  321. oscura/reporting/enhanced_reports.py +949 -0
  322. oscura/reporting/export.py +86 -43
  323. oscura/reporting/formatting/numbers.py +69 -42
  324. oscura/reporting/html.py +139 -58
  325. oscura/reporting/index.py +137 -65
  326. oscura/reporting/output.py +158 -67
  327. oscura/reporting/pdf.py +67 -102
  328. oscura/reporting/plots.py +191 -112
  329. oscura/reporting/sections.py +88 -47
  330. oscura/reporting/standards.py +104 -61
  331. oscura/reporting/summary_generator.py +75 -55
  332. oscura/reporting/tables.py +138 -54
  333. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  334. oscura/sessions/__init__.py +14 -23
  335. oscura/sessions/base.py +3 -3
  336. oscura/sessions/blackbox.py +106 -10
  337. oscura/sessions/generic.py +2 -2
  338. oscura/sessions/legacy.py +783 -0
  339. oscura/side_channel/__init__.py +63 -0
  340. oscura/side_channel/dpa.py +1025 -0
  341. oscura/utils/__init__.py +15 -1
  342. oscura/utils/bitwise.py +118 -0
  343. oscura/{builders → utils/builders}/__init__.py +1 -1
  344. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  345. oscura/{comparison → utils/comparison}/compare.py +202 -101
  346. oscura/{comparison → utils/comparison}/golden.py +83 -63
  347. oscura/{comparison → utils/comparison}/limits.py +313 -89
  348. oscura/{comparison → utils/comparison}/mask.py +151 -45
  349. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  350. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  351. oscura/{component → utils/component}/__init__.py +3 -3
  352. oscura/{component → utils/component}/impedance.py +122 -58
  353. oscura/{component → utils/component}/reactive.py +165 -168
  354. oscura/{component → utils/component}/transmission_line.py +3 -3
  355. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  356. oscura/{filtering → utils/filtering}/base.py +1 -1
  357. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  358. oscura/{filtering → utils/filtering}/design.py +169 -93
  359. oscura/{filtering → utils/filtering}/filters.py +2 -2
  360. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  361. oscura/utils/geometry.py +31 -0
  362. oscura/utils/imports.py +184 -0
  363. oscura/utils/lazy.py +1 -1
  364. oscura/{math → utils/math}/__init__.py +2 -2
  365. oscura/{math → utils/math}/arithmetic.py +114 -48
  366. oscura/{math → utils/math}/interpolation.py +139 -106
  367. oscura/utils/memory.py +129 -66
  368. oscura/utils/memory_advanced.py +92 -9
  369. oscura/utils/memory_extensions.py +10 -8
  370. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  371. oscura/{optimization → utils/optimization}/search.py +2 -2
  372. oscura/utils/performance/__init__.py +58 -0
  373. oscura/utils/performance/caching.py +889 -0
  374. oscura/utils/performance/lsh_clustering.py +333 -0
  375. oscura/utils/performance/memory_optimizer.py +699 -0
  376. oscura/utils/performance/optimizations.py +675 -0
  377. oscura/utils/performance/parallel.py +654 -0
  378. oscura/utils/performance/profiling.py +661 -0
  379. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  380. oscura/{pipeline → utils/pipeline}/composition.py +1 -1
  381. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  382. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  383. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  384. oscura/{search → utils/search}/__init__.py +3 -3
  385. oscura/{search → utils/search}/anomaly.py +188 -58
  386. oscura/utils/search/context.py +294 -0
  387. oscura/{search → utils/search}/pattern.py +138 -10
  388. oscura/utils/serial.py +51 -0
  389. oscura/utils/storage/__init__.py +61 -0
  390. oscura/utils/storage/database.py +1166 -0
  391. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  392. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  393. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  394. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  395. oscura/{triggering → utils/triggering}/base.py +6 -6
  396. oscura/{triggering → utils/triggering}/edge.py +2 -2
  397. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  398. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  399. oscura/{triggering → utils/triggering}/window.py +2 -2
  400. oscura/utils/validation.py +32 -0
  401. oscura/validation/__init__.py +121 -0
  402. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  403. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  404. oscura/{compliance → validation/compliance}/masks.py +1 -1
  405. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  406. oscura/{compliance → validation/compliance}/testing.py +114 -52
  407. oscura/validation/compliance_tests.py +915 -0
  408. oscura/validation/fuzzer.py +990 -0
  409. oscura/validation/grammar_tests.py +596 -0
  410. oscura/validation/grammar_validator.py +904 -0
  411. oscura/validation/hil_testing.py +977 -0
  412. oscura/{quality → validation/quality}/__init__.py +4 -4
  413. oscura/{quality → validation/quality}/ensemble.py +251 -171
  414. oscura/{quality → validation/quality}/explainer.py +3 -3
  415. oscura/{quality → validation/quality}/scoring.py +1 -1
  416. oscura/{quality → validation/quality}/warnings.py +4 -4
  417. oscura/validation/regression_suite.py +808 -0
  418. oscura/validation/replay.py +788 -0
  419. oscura/{testing → validation/testing}/__init__.py +2 -2
  420. oscura/{testing → validation/testing}/synthetic.py +5 -5
  421. oscura/visualization/__init__.py +9 -0
  422. oscura/visualization/accessibility.py +1 -1
  423. oscura/visualization/annotations.py +64 -67
  424. oscura/visualization/colors.py +7 -7
  425. oscura/visualization/digital.py +180 -81
  426. oscura/visualization/eye.py +236 -85
  427. oscura/visualization/interactive.py +320 -143
  428. oscura/visualization/jitter.py +587 -247
  429. oscura/visualization/layout.py +169 -134
  430. oscura/visualization/optimization.py +103 -52
  431. oscura/visualization/palettes.py +1 -1
  432. oscura/visualization/power.py +427 -211
  433. oscura/visualization/power_extended.py +626 -297
  434. oscura/visualization/presets.py +2 -0
  435. oscura/visualization/protocols.py +495 -181
  436. oscura/visualization/render.py +79 -63
  437. oscura/visualization/reverse_engineering.py +171 -124
  438. oscura/visualization/signal_integrity.py +460 -279
  439. oscura/visualization/specialized.py +190 -100
  440. oscura/visualization/spectral.py +670 -255
  441. oscura/visualization/thumbnails.py +166 -137
  442. oscura/visualization/waveform.py +150 -63
  443. oscura/workflows/__init__.py +3 -0
  444. oscura/{batch → workflows/batch}/__init__.py +5 -5
  445. oscura/{batch → workflows/batch}/advanced.py +150 -75
  446. oscura/workflows/batch/aggregate.py +531 -0
  447. oscura/workflows/batch/analyze.py +236 -0
  448. oscura/{batch → workflows/batch}/logging.py +2 -2
  449. oscura/{batch → workflows/batch}/metrics.py +1 -1
  450. oscura/workflows/complete_re.py +1144 -0
  451. oscura/workflows/compliance.py +44 -54
  452. oscura/workflows/digital.py +197 -51
  453. oscura/workflows/legacy/__init__.py +12 -0
  454. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  455. oscura/workflows/multi_trace.py +9 -9
  456. oscura/workflows/power.py +42 -62
  457. oscura/workflows/protocol.py +82 -49
  458. oscura/workflows/reverse_engineering.py +351 -150
  459. oscura/workflows/signal_integrity.py +157 -82
  460. oscura-0.7.0.dist-info/METADATA +661 -0
  461. oscura-0.7.0.dist-info/RECORD +591 -0
  462. oscura/batch/aggregate.py +0 -300
  463. oscura/batch/analyze.py +0 -139
  464. oscura/dsl/__init__.py +0 -73
  465. oscura/exceptions.py +0 -59
  466. oscura/exploratory/fuzzy.py +0 -513
  467. oscura/exploratory/sync.py +0 -384
  468. oscura/exporters/__init__.py +0 -94
  469. oscura/exporters/csv.py +0 -303
  470. oscura/exporters/exporters.py +0 -44
  471. oscura/exporters/hdf5.py +0 -217
  472. oscura/exporters/html_export.py +0 -701
  473. oscura/exporters/json_export.py +0 -291
  474. oscura/exporters/markdown_export.py +0 -367
  475. oscura/exporters/matlab_export.py +0 -354
  476. oscura/exporters/npz_export.py +0 -219
  477. oscura/exporters/spice_export.py +0 -210
  478. oscura/search/context.py +0 -149
  479. oscura/session/__init__.py +0 -34
  480. oscura/session/annotations.py +0 -289
  481. oscura/session/history.py +0 -313
  482. oscura/session/session.py +0 -520
  483. oscura/workflow/__init__.py +0 -13
  484. oscura-0.5.1.dist-info/METADATA +0 -583
  485. oscura-0.5.1.dist-info/RECORD +0 -481
  486. /oscura/core/{config.py → config/legacy.py} +0 -0
  487. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  488. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  489. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  490. /oscura/{schemas → core/schemas}/bus_configuration.json +0 -0
  491. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  492. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  493. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  494. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  495. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/WHEEL +0 -0
  496. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/entry_points.txt +0 -0
  497. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,7 @@ threshold configurations.
6
6
 
7
7
 
8
8
  Example:
9
- >>> from oscura.config.schema import validate_against_schema
9
+ >>> from oscura.core.config.schema import validate_against_schema
10
10
  >>> config = {"name": "uart", "baud_rate": 115200}
11
11
  >>> validate_against_schema(config, "protocol")
12
12
  True
@@ -26,7 +26,7 @@ try:
26
26
  JSONSCHEMA_AVAILABLE = True
27
27
  except ImportError:
28
28
  JSONSCHEMA_AVAILABLE = False
29
- JsonSchemaError = Exception # type: ignore[ignore-without-code]
29
+ JsonSchemaError = Exception
30
30
 
31
31
  from oscura.core.exceptions import ConfigurationError
32
32
  from oscura.core.exceptions import ValidationError as OscuraValidationError
@@ -391,318 +391,472 @@ def _register_builtin_schemas(registry: SchemaRegistry) -> None:
391
391
  Args:
392
392
  registry: Registry to populate.
393
393
  """
394
- # Protocol definition schema
394
+ _register_protocol_schema(registry)
395
+ _register_pipeline_schema(registry)
396
+ _register_logic_family_schema(registry)
397
+ _register_threshold_profile_schema(registry)
398
+ _register_preferences_schema(registry)
399
+
400
+
401
+ def _register_protocol_schema(registry: SchemaRegistry) -> None:
402
+ """Register protocol definition schema.
403
+
404
+ Args:
405
+ registry: Schema registry to populate.
406
+ """
407
+ schema = _build_protocol_schema()
395
408
  registry.register(
396
409
  ConfigSchema(
397
410
  name="protocol",
398
411
  version="1.0.0",
399
412
  description="Protocol decoder configuration",
400
- schema={
401
- "$schema": "http://json-schema.org/draft-07/schema#",
402
- "type": "object",
403
- "required": ["name"],
404
- "properties": {
405
- "name": {
406
- "type": "string",
407
- "description": "Protocol identifier",
408
- "pattern": "^[a-z][a-z0-9_]*$",
409
- },
410
- "version": {
411
- "type": "string",
412
- "description": "Protocol version (semver)",
413
- "pattern": "^\\d+\\.\\d+\\.\\d+$",
414
- },
415
- "description": {
416
- "type": "string",
417
- },
418
- "author": {
419
- "type": "string",
420
- },
421
- "timing": {
422
- "type": "object",
423
- "properties": {
424
- "baud_rates": {
425
- "type": "array",
426
- "items": {"type": "integer", "minimum": 1},
427
- },
428
- "data_bits": {
429
- "type": "array",
430
- "items": {
431
- "type": "integer",
432
- "minimum": 1,
433
- "maximum": 32,
434
- },
435
- },
436
- "stop_bits": {
437
- "type": "array",
438
- "items": {
439
- "type": "number",
440
- "minimum": 0.5,
441
- "maximum": 2,
442
- },
443
- },
444
- "parity": {
445
- "type": "array",
446
- "items": {
447
- "type": "string",
448
- "enum": ["none", "even", "odd", "mark", "space"],
449
- },
450
- },
451
- },
452
- },
453
- "voltage_levels": {
454
- "type": "object",
455
- "properties": {
456
- "logic_family": {"type": "string"},
457
- "idle_state": {"type": "string", "enum": ["high", "low"]},
458
- "mark_voltage": {"type": "number"},
459
- "space_voltage": {"type": "number"},
460
- },
461
- },
462
- "state_machine": {
463
- "type": "object",
464
- "properties": {
465
- "states": {
466
- "type": "array",
467
- "items": {"type": "string"},
468
- },
469
- "initial_state": {"type": "string"},
470
- "transitions": {
471
- "type": "array",
472
- "items": {
473
- "type": "object",
474
- "required": ["from", "to", "condition"],
475
- "properties": {
476
- "from": {"type": "string"},
477
- "to": {"type": "string"},
478
- "condition": {"type": "string"},
479
- },
480
- },
481
- },
482
- },
413
+ schema=schema,
414
+ )
415
+ )
416
+
417
+
418
+ def _build_protocol_schema() -> dict[str, Any]:
419
+ """Build protocol schema definition.
420
+
421
+ Returns:
422
+ JSON Schema dictionary for protocol configuration.
423
+ """
424
+ return {
425
+ "$schema": "http://json-schema.org/draft-07/schema#",
426
+ "type": "object",
427
+ "required": ["name"],
428
+ "properties": {
429
+ "name": _build_protocol_name_property(),
430
+ "version": _build_semver_property(),
431
+ "description": {"type": "string"},
432
+ "author": {"type": "string"},
433
+ "timing": _build_timing_property(),
434
+ "voltage_levels": _build_voltage_levels_property(),
435
+ "state_machine": _build_state_machine_property(),
436
+ },
437
+ "additionalProperties": True,
438
+ }
439
+
440
+
441
+ def _build_protocol_name_property() -> dict[str, Any]:
442
+ """Build protocol name property definition.
443
+
444
+ Returns:
445
+ Property schema for protocol name.
446
+ """
447
+ return {
448
+ "type": "string",
449
+ "description": "Protocol identifier",
450
+ "pattern": "^[a-z][a-z0-9_]*$",
451
+ }
452
+
453
+
454
+ def _build_semver_property() -> dict[str, Any]:
455
+ """Build semantic version property definition.
456
+
457
+ Returns:
458
+ Property schema for semver strings.
459
+ """
460
+ return {
461
+ "type": "string",
462
+ "description": "Protocol version (semver)",
463
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
464
+ }
465
+
466
+
467
+ def _build_timing_property() -> dict[str, Any]:
468
+ """Build timing configuration property.
469
+
470
+ Returns:
471
+ Property schema for timing parameters.
472
+ """
473
+ return {
474
+ "type": "object",
475
+ "properties": {
476
+ "baud_rates": {
477
+ "type": "array",
478
+ "items": {"type": "integer", "minimum": 1},
479
+ },
480
+ "data_bits": {
481
+ "type": "array",
482
+ "items": {"type": "integer", "minimum": 1, "maximum": 32},
483
+ },
484
+ "stop_bits": {
485
+ "type": "array",
486
+ "items": {"type": "number", "minimum": 0.5, "maximum": 2},
487
+ },
488
+ "parity": {
489
+ "type": "array",
490
+ "items": {
491
+ "type": "string",
492
+ "enum": ["none", "even", "odd", "mark", "space"],
493
+ },
494
+ },
495
+ },
496
+ }
497
+
498
+
499
+ def _build_voltage_levels_property() -> dict[str, Any]:
500
+ """Build voltage levels property.
501
+
502
+ Returns:
503
+ Property schema for voltage level specifications.
504
+ """
505
+ return {
506
+ "type": "object",
507
+ "properties": {
508
+ "logic_family": {"type": "string"},
509
+ "idle_state": {"type": "string", "enum": ["high", "low"]},
510
+ "mark_voltage": {"type": "number"},
511
+ "space_voltage": {"type": "number"},
512
+ },
513
+ }
514
+
515
+
516
+ def _build_state_machine_property() -> dict[str, Any]:
517
+ """Build state machine property.
518
+
519
+ Returns:
520
+ Property schema for state machine definitions.
521
+ """
522
+ return {
523
+ "type": "object",
524
+ "properties": {
525
+ "states": {
526
+ "type": "array",
527
+ "items": {"type": "string"},
528
+ },
529
+ "initial_state": {"type": "string"},
530
+ "transitions": {
531
+ "type": "array",
532
+ "items": {
533
+ "type": "object",
534
+ "required": ["from", "to", "condition"],
535
+ "properties": {
536
+ "from": {"type": "string"},
537
+ "to": {"type": "string"},
538
+ "condition": {"type": "string"},
483
539
  },
484
540
  },
485
- "additionalProperties": True,
486
541
  },
487
- )
488
- )
542
+ },
543
+ }
544
+
545
+
546
+ def _register_pipeline_schema(registry: SchemaRegistry) -> None:
547
+ """Register pipeline definition schema.
489
548
 
490
- # Pipeline definition schema
549
+ Args:
550
+ registry: Schema registry to populate.
551
+ """
552
+ schema = _build_pipeline_schema()
491
553
  registry.register(
492
554
  ConfigSchema(
493
555
  name="pipeline",
494
556
  version="1.0.0",
495
557
  description="Analysis pipeline configuration",
496
- schema={
497
- "$schema": "http://json-schema.org/draft-07/schema#",
498
- "type": "object",
499
- "required": ["name", "steps"],
500
- "properties": {
501
- "name": {
502
- "type": "string",
503
- "description": "Pipeline identifier",
504
- },
505
- "version": {
506
- "type": "string",
507
- "pattern": "^\\d+\\.\\d+\\.\\d+$",
508
- },
509
- "description": {
510
- "type": "string",
511
- },
512
- "steps": {
513
- "type": "array",
514
- "minItems": 1,
515
- "items": {
516
- "type": "object",
517
- "required": ["name", "type"],
518
- "properties": {
519
- "name": {"type": "string"},
520
- "type": {"type": "string"},
521
- "params": {"type": "object"},
522
- "inputs": {"type": "object"},
523
- "outputs": {"type": "object"},
524
- },
525
- },
526
- },
527
- "parallel_groups": {
528
- "type": "array",
529
- "items": {
530
- "type": "array",
531
- "items": {"type": "string"},
532
- },
533
- },
534
- },
535
- },
558
+ schema=schema,
536
559
  )
537
560
  )
538
561
 
539
- # Logic family schema
562
+
563
+ def _build_pipeline_schema() -> dict[str, Any]:
564
+ """Build pipeline schema definition.
565
+
566
+ Returns:
567
+ JSON Schema dictionary for pipeline configuration.
568
+ """
569
+ return {
570
+ "$schema": "http://json-schema.org/draft-07/schema#",
571
+ "type": "object",
572
+ "required": ["name", "steps"],
573
+ "properties": {
574
+ "name": {"type": "string", "description": "Pipeline identifier"},
575
+ "version": _build_semver_property(),
576
+ "description": {"type": "string"},
577
+ "steps": _build_pipeline_steps_property(),
578
+ "parallel_groups": _build_parallel_groups_property(),
579
+ },
580
+ }
581
+
582
+
583
+ def _build_pipeline_steps_property() -> dict[str, Any]:
584
+ """Build pipeline steps property.
585
+
586
+ Returns:
587
+ Property schema for pipeline step definitions.
588
+ """
589
+ return {
590
+ "type": "array",
591
+ "minItems": 1,
592
+ "items": {
593
+ "type": "object",
594
+ "required": ["name", "type"],
595
+ "properties": {
596
+ "name": {"type": "string"},
597
+ "type": {"type": "string"},
598
+ "params": {"type": "object"},
599
+ "inputs": {"type": "object"},
600
+ "outputs": {"type": "object"},
601
+ },
602
+ },
603
+ }
604
+
605
+
606
+ def _build_parallel_groups_property() -> dict[str, Any]:
607
+ """Build parallel groups property.
608
+
609
+ Returns:
610
+ Property schema for parallel execution groups.
611
+ """
612
+ return {
613
+ "type": "array",
614
+ "items": {
615
+ "type": "array",
616
+ "items": {"type": "string"},
617
+ },
618
+ }
619
+
620
+
621
+ def _register_logic_family_schema(registry: SchemaRegistry) -> None:
622
+ """Register logic family voltage threshold schema.
623
+
624
+ Args:
625
+ registry: Schema registry to populate.
626
+ """
627
+ schema = _build_logic_family_schema()
540
628
  registry.register(
541
629
  ConfigSchema(
542
630
  name="logic_family",
543
631
  version="1.0.0",
544
632
  description="Logic family voltage thresholds",
545
- schema={
546
- "$schema": "http://json-schema.org/draft-07/schema#",
547
- "type": "object",
548
- "required": ["name", "VIH", "VIL", "VOH", "VOL"],
549
- "properties": {
550
- "name": {
551
- "type": "string",
552
- "description": "Logic family name",
553
- },
554
- "description": {
555
- "type": "string",
556
- },
557
- "VIH": {
558
- "type": "number",
559
- "description": "Input high voltage threshold (V)",
560
- "minimum": 0,
561
- "maximum": 10,
562
- },
563
- "VIL": {
564
- "type": "number",
565
- "description": "Input low voltage threshold (V)",
566
- "minimum": 0,
567
- "maximum": 10,
568
- },
569
- "VOH": {
570
- "type": "number",
571
- "description": "Output high voltage (V)",
572
- "minimum": 0,
573
- "maximum": 10,
574
- },
575
- "VOL": {
576
- "type": "number",
577
- "description": "Output low voltage (V)",
578
- "minimum": 0,
579
- "maximum": 10,
580
- },
581
- "VCC": {
582
- "type": "number",
583
- "description": "Supply voltage (V)",
584
- "minimum": 0,
585
- "maximum": 15,
586
- },
587
- "temperature_range": {
588
- "type": "object",
589
- "properties": {
590
- "min": {"type": "number"},
591
- "max": {"type": "number"},
592
- },
593
- },
594
- "noise_margin_high": {
595
- "type": "number",
596
- "description": "High state noise margin (V)",
597
- },
598
- "noise_margin_low": {
599
- "type": "number",
600
- "description": "Low state noise margin (V)",
601
- },
602
- },
603
- },
633
+ schema=schema,
604
634
  )
605
635
  )
606
636
 
607
- # Threshold profile schema
637
+
638
+ def _build_logic_family_schema() -> dict[str, Any]:
639
+ """Build logic family schema definition.
640
+
641
+ Returns:
642
+ JSON Schema dictionary for logic family voltage specifications.
643
+ """
644
+ return {
645
+ "$schema": "http://json-schema.org/draft-07/schema#",
646
+ "type": "object",
647
+ "required": ["name", "VIH", "VIL", "VOH", "VOL"],
648
+ "properties": {
649
+ "name": {"type": "string", "description": "Logic family name"},
650
+ "description": {"type": "string"},
651
+ "VIH": _build_voltage_property("Input high voltage threshold (V)"),
652
+ "VIL": _build_voltage_property("Input low voltage threshold (V)"),
653
+ "VOH": _build_voltage_property("Output high voltage (V)"),
654
+ "VOL": _build_voltage_property("Output low voltage (V)"),
655
+ "VCC": _build_supply_voltage_property(),
656
+ "temperature_range": _build_temperature_range_property(),
657
+ "noise_margin_high": {"type": "number", "description": "High state noise margin (V)"},
658
+ "noise_margin_low": {"type": "number", "description": "Low state noise margin (V)"},
659
+ },
660
+ }
661
+
662
+
663
+ def _build_voltage_property(description: str) -> dict[str, Any]:
664
+ """Build standard voltage property with 0-10V range.
665
+
666
+ Args:
667
+ description: Property description.
668
+
669
+ Returns:
670
+ Property schema for voltage value.
671
+ """
672
+ return {"type": "number", "description": description, "minimum": 0, "maximum": 10}
673
+
674
+
675
+ def _build_supply_voltage_property() -> dict[str, Any]:
676
+ """Build supply voltage property.
677
+
678
+ Returns:
679
+ Property schema for VCC with 0-15V range.
680
+ """
681
+ return {"type": "number", "description": "Supply voltage (V)", "minimum": 0, "maximum": 15}
682
+
683
+
684
+ def _build_temperature_range_property() -> dict[str, Any]:
685
+ """Build temperature range property.
686
+
687
+ Returns:
688
+ Property schema for temperature range.
689
+ """
690
+ return {
691
+ "type": "object",
692
+ "properties": {
693
+ "min": {"type": "number"},
694
+ "max": {"type": "number"},
695
+ },
696
+ }
697
+
698
+
699
+ def _register_threshold_profile_schema(registry: SchemaRegistry) -> None:
700
+ """Register threshold profile schema.
701
+
702
+ Args:
703
+ registry: Schema registry to populate.
704
+ """
705
+ schema = _build_threshold_profile_schema()
608
706
  registry.register(
609
707
  ConfigSchema(
610
708
  name="threshold_profile",
611
709
  version="1.0.0",
612
710
  description="Analysis threshold profile",
613
- schema={
614
- "$schema": "http://json-schema.org/draft-07/schema#",
615
- "type": "object",
616
- "required": ["name"],
617
- "properties": {
618
- "name": {
619
- "type": "string",
620
- },
621
- "description": {
622
- "type": "string",
623
- },
624
- "base_family": {
625
- "type": "string",
626
- "description": "Base logic family to extend",
627
- },
628
- "overrides": {
629
- "type": "object",
630
- "additionalProperties": {"type": "number"},
631
- },
632
- "tolerance": {
633
- "type": "number",
634
- "description": "Tolerance percentage (0-100)",
635
- "minimum": 0,
636
- "maximum": 100,
637
- "default": 0,
638
- },
639
- },
640
- },
711
+ schema=schema,
641
712
  )
642
713
  )
643
714
 
644
- # Preferences schema
715
+
716
+ def _build_threshold_profile_schema() -> dict[str, Any]:
717
+ """Build threshold profile schema definition.
718
+
719
+ Returns:
720
+ JSON Schema dictionary for threshold profile configuration.
721
+ """
722
+ return {
723
+ "$schema": "http://json-schema.org/draft-07/schema#",
724
+ "type": "object",
725
+ "required": ["name"],
726
+ "properties": {
727
+ "name": {"type": "string"},
728
+ "description": {"type": "string"},
729
+ "base_family": {"type": "string", "description": "Base logic family to extend"},
730
+ "overrides": {"type": "object", "additionalProperties": {"type": "number"}},
731
+ "tolerance": _build_tolerance_property(),
732
+ },
733
+ }
734
+
735
+
736
+ def _build_tolerance_property() -> dict[str, Any]:
737
+ """Build tolerance property.
738
+
739
+ Returns:
740
+ Property schema for tolerance percentage (0-100).
741
+ """
742
+ return {
743
+ "type": "number",
744
+ "description": "Tolerance percentage (0-100)",
745
+ "minimum": 0,
746
+ "maximum": 100,
747
+ "default": 0,
748
+ }
749
+
750
+
751
+ def _register_preferences_schema(registry: SchemaRegistry) -> None:
752
+ """Register user preferences schema.
753
+
754
+ Args:
755
+ registry: Schema registry to populate.
756
+ """
757
+ schema = _build_preferences_schema()
645
758
  registry.register(
646
759
  ConfigSchema(
647
760
  name="preferences",
648
761
  version="1.0.0",
649
762
  description="User preferences",
650
- schema={
651
- "$schema": "http://json-schema.org/draft-07/schema#",
652
- "type": "object",
653
- "properties": {
654
- "defaults": {
655
- "type": "object",
656
- "properties": {
657
- "sample_rate": {"type": "number", "minimum": 0},
658
- "window_function": {"type": "string"},
659
- "fft_size": {"type": "integer", "minimum": 1},
660
- },
661
- },
662
- "visualization": {
663
- "type": "object",
664
- "properties": {
665
- "style": {"type": "string"},
666
- "figure_size": {
667
- "type": "array",
668
- "items": {"type": "number"},
669
- "minItems": 2,
670
- "maxItems": 2,
671
- },
672
- "dpi": {"type": "integer", "minimum": 50, "maximum": 600},
673
- "colormap": {"type": "string"},
674
- },
675
- },
676
- "export": {
677
- "type": "object",
678
- "properties": {
679
- "default_format": {
680
- "type": "string",
681
- "enum": ["csv", "hdf5", "npz", "json"],
682
- },
683
- "precision": {
684
- "type": "integer",
685
- "minimum": 1,
686
- "maximum": 15,
687
- },
688
- },
689
- },
690
- "logging": {
691
- "type": "object",
692
- "properties": {
693
- "level": {
694
- "type": "string",
695
- "enum": ["DEBUG", "INFO", "WARNING", "ERROR"],
696
- },
697
- "file": {"type": "string"},
698
- },
699
- },
700
- },
701
- },
763
+ schema=schema,
702
764
  )
703
765
  )
704
766
 
705
767
 
768
+ def _build_preferences_schema() -> dict[str, Any]:
769
+ """Build preferences schema definition.
770
+
771
+ Returns:
772
+ JSON Schema dictionary for user preferences.
773
+ """
774
+ return {
775
+ "$schema": "http://json-schema.org/draft-07/schema#",
776
+ "type": "object",
777
+ "properties": {
778
+ "defaults": _build_defaults_property(),
779
+ "visualization": _build_visualization_property(),
780
+ "export": _build_export_property(),
781
+ "logging": _build_logging_property(),
782
+ },
783
+ }
784
+
785
+
786
+ def _build_defaults_property() -> dict[str, Any]:
787
+ """Build defaults property for preferences.
788
+
789
+ Returns:
790
+ Property schema for default settings.
791
+ """
792
+ return {
793
+ "type": "object",
794
+ "properties": {
795
+ "sample_rate": {"type": "number", "minimum": 0},
796
+ "window_function": {"type": "string"},
797
+ "fft_size": {"type": "integer", "minimum": 1},
798
+ },
799
+ }
800
+
801
+
802
+ def _build_visualization_property() -> dict[str, Any]:
803
+ """Build visualization property for preferences.
804
+
805
+ Returns:
806
+ Property schema for visualization settings.
807
+ """
808
+ return {
809
+ "type": "object",
810
+ "properties": {
811
+ "style": {"type": "string"},
812
+ "figure_size": {
813
+ "type": "array",
814
+ "items": {"type": "number"},
815
+ "minItems": 2,
816
+ "maxItems": 2,
817
+ },
818
+ "dpi": {"type": "integer", "minimum": 50, "maximum": 600},
819
+ "colormap": {"type": "string"},
820
+ },
821
+ }
822
+
823
+
824
+ def _build_export_property() -> dict[str, Any]:
825
+ """Build export property for preferences.
826
+
827
+ Returns:
828
+ Property schema for export settings.
829
+ """
830
+ return {
831
+ "type": "object",
832
+ "properties": {
833
+ "default_format": {
834
+ "type": "string",
835
+ "enum": ["csv", "hdf5", "npz", "json"],
836
+ },
837
+ "precision": {"type": "integer", "minimum": 1, "maximum": 15},
838
+ },
839
+ }
840
+
841
+
842
+ def _build_logging_property() -> dict[str, Any]:
843
+ """Build logging property for preferences.
844
+
845
+ Returns:
846
+ Property schema for logging settings.
847
+ """
848
+ return {
849
+ "type": "object",
850
+ "properties": {
851
+ "level": {
852
+ "type": "string",
853
+ "enum": ["DEBUG", "INFO", "WARNING", "ERROR"],
854
+ },
855
+ "file": {"type": "string"},
856
+ },
857
+ }
858
+
859
+
706
860
  __all__ = [
707
861
  "ConfigSchema",
708
862
  "SchemaRegistry",