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.
- oscura/__init__.py +813 -8
- oscura/__main__.py +392 -0
- oscura/analyzers/__init__.py +37 -0
- oscura/analyzers/digital/__init__.py +177 -0
- oscura/analyzers/digital/bus.py +691 -0
- oscura/analyzers/digital/clock.py +805 -0
- oscura/analyzers/digital/correlation.py +720 -0
- oscura/analyzers/digital/edges.py +632 -0
- oscura/analyzers/digital/extraction.py +413 -0
- oscura/analyzers/digital/quality.py +878 -0
- oscura/analyzers/digital/signal_quality.py +877 -0
- oscura/analyzers/digital/thresholds.py +708 -0
- oscura/analyzers/digital/timing.py +1104 -0
- oscura/analyzers/eye/__init__.py +46 -0
- oscura/analyzers/eye/diagram.py +434 -0
- oscura/analyzers/eye/metrics.py +555 -0
- oscura/analyzers/jitter/__init__.py +83 -0
- oscura/analyzers/jitter/ber.py +333 -0
- oscura/analyzers/jitter/decomposition.py +759 -0
- oscura/analyzers/jitter/measurements.py +413 -0
- oscura/analyzers/jitter/spectrum.py +220 -0
- oscura/analyzers/measurements.py +40 -0
- oscura/analyzers/packet/__init__.py +171 -0
- oscura/analyzers/packet/daq.py +1077 -0
- oscura/analyzers/packet/metrics.py +437 -0
- oscura/analyzers/packet/parser.py +327 -0
- oscura/analyzers/packet/payload.py +2156 -0
- oscura/analyzers/packet/payload_analysis.py +1312 -0
- oscura/analyzers/packet/payload_extraction.py +236 -0
- oscura/analyzers/packet/payload_patterns.py +670 -0
- oscura/analyzers/packet/stream.py +359 -0
- oscura/analyzers/patterns/__init__.py +266 -0
- oscura/analyzers/patterns/clustering.py +1036 -0
- oscura/analyzers/patterns/discovery.py +539 -0
- oscura/analyzers/patterns/learning.py +797 -0
- oscura/analyzers/patterns/matching.py +1091 -0
- oscura/analyzers/patterns/periodic.py +650 -0
- oscura/analyzers/patterns/sequences.py +767 -0
- oscura/analyzers/power/__init__.py +116 -0
- oscura/analyzers/power/ac_power.py +391 -0
- oscura/analyzers/power/basic.py +383 -0
- oscura/analyzers/power/conduction.py +314 -0
- oscura/analyzers/power/efficiency.py +297 -0
- oscura/analyzers/power/ripple.py +356 -0
- oscura/analyzers/power/soa.py +372 -0
- oscura/analyzers/power/switching.py +479 -0
- oscura/analyzers/protocol/__init__.py +150 -0
- oscura/analyzers/protocols/__init__.py +150 -0
- oscura/analyzers/protocols/base.py +500 -0
- oscura/analyzers/protocols/can.py +620 -0
- oscura/analyzers/protocols/can_fd.py +448 -0
- oscura/analyzers/protocols/flexray.py +405 -0
- oscura/analyzers/protocols/hdlc.py +399 -0
- oscura/analyzers/protocols/i2c.py +368 -0
- oscura/analyzers/protocols/i2s.py +296 -0
- oscura/analyzers/protocols/jtag.py +393 -0
- oscura/analyzers/protocols/lin.py +445 -0
- oscura/analyzers/protocols/manchester.py +333 -0
- oscura/analyzers/protocols/onewire.py +501 -0
- oscura/analyzers/protocols/spi.py +334 -0
- oscura/analyzers/protocols/swd.py +325 -0
- oscura/analyzers/protocols/uart.py +393 -0
- oscura/analyzers/protocols/usb.py +495 -0
- oscura/analyzers/signal_integrity/__init__.py +63 -0
- oscura/analyzers/signal_integrity/embedding.py +294 -0
- oscura/analyzers/signal_integrity/equalization.py +370 -0
- oscura/analyzers/signal_integrity/sparams.py +484 -0
- oscura/analyzers/spectral/__init__.py +53 -0
- oscura/analyzers/spectral/chunked.py +273 -0
- oscura/analyzers/spectral/chunked_fft.py +571 -0
- oscura/analyzers/spectral/chunked_wavelet.py +391 -0
- oscura/analyzers/spectral/fft.py +92 -0
- oscura/analyzers/statistical/__init__.py +250 -0
- oscura/analyzers/statistical/checksum.py +923 -0
- oscura/analyzers/statistical/chunked_corr.py +228 -0
- oscura/analyzers/statistical/classification.py +778 -0
- oscura/analyzers/statistical/entropy.py +1113 -0
- oscura/analyzers/statistical/ngrams.py +614 -0
- oscura/analyzers/statistics/__init__.py +119 -0
- oscura/analyzers/statistics/advanced.py +885 -0
- oscura/analyzers/statistics/basic.py +263 -0
- oscura/analyzers/statistics/correlation.py +630 -0
- oscura/analyzers/statistics/distribution.py +298 -0
- oscura/analyzers/statistics/outliers.py +463 -0
- oscura/analyzers/statistics/streaming.py +93 -0
- oscura/analyzers/statistics/trend.py +520 -0
- oscura/analyzers/validation.py +598 -0
- oscura/analyzers/waveform/__init__.py +36 -0
- oscura/analyzers/waveform/measurements.py +943 -0
- oscura/analyzers/waveform/measurements_with_uncertainty.py +371 -0
- oscura/analyzers/waveform/spectral.py +1689 -0
- oscura/analyzers/waveform/wavelets.py +298 -0
- oscura/api/__init__.py +62 -0
- oscura/api/dsl.py +538 -0
- oscura/api/fluent.py +571 -0
- oscura/api/operators.py +498 -0
- oscura/api/optimization.py +392 -0
- oscura/api/profiling.py +396 -0
- oscura/automotive/__init__.py +73 -0
- oscura/automotive/can/__init__.py +52 -0
- oscura/automotive/can/analysis.py +356 -0
- oscura/automotive/can/checksum.py +250 -0
- oscura/automotive/can/correlation.py +212 -0
- oscura/automotive/can/discovery.py +355 -0
- oscura/automotive/can/message_wrapper.py +375 -0
- oscura/automotive/can/models.py +385 -0
- oscura/automotive/can/patterns.py +381 -0
- oscura/automotive/can/session.py +452 -0
- oscura/automotive/can/state_machine.py +300 -0
- oscura/automotive/can/stimulus_response.py +461 -0
- oscura/automotive/dbc/__init__.py +15 -0
- oscura/automotive/dbc/generator.py +156 -0
- oscura/automotive/dbc/parser.py +146 -0
- oscura/automotive/dtc/__init__.py +30 -0
- oscura/automotive/dtc/database.py +3036 -0
- oscura/automotive/j1939/__init__.py +14 -0
- oscura/automotive/j1939/decoder.py +745 -0
- oscura/automotive/loaders/__init__.py +35 -0
- oscura/automotive/loaders/asc.py +98 -0
- oscura/automotive/loaders/blf.py +77 -0
- oscura/automotive/loaders/csv_can.py +136 -0
- oscura/automotive/loaders/dispatcher.py +136 -0
- oscura/automotive/loaders/mdf.py +331 -0
- oscura/automotive/loaders/pcap.py +132 -0
- oscura/automotive/obd/__init__.py +14 -0
- oscura/automotive/obd/decoder.py +707 -0
- oscura/automotive/uds/__init__.py +48 -0
- oscura/automotive/uds/decoder.py +265 -0
- oscura/automotive/uds/models.py +64 -0
- oscura/automotive/visualization.py +369 -0
- oscura/batch/__init__.py +55 -0
- oscura/batch/advanced.py +627 -0
- oscura/batch/aggregate.py +300 -0
- oscura/batch/analyze.py +139 -0
- oscura/batch/logging.py +487 -0
- oscura/batch/metrics.py +556 -0
- oscura/builders/__init__.py +41 -0
- oscura/builders/signal_builder.py +1131 -0
- oscura/cli/__init__.py +14 -0
- oscura/cli/batch.py +339 -0
- oscura/cli/characterize.py +273 -0
- oscura/cli/compare.py +775 -0
- oscura/cli/decode.py +551 -0
- oscura/cli/main.py +247 -0
- oscura/cli/shell.py +350 -0
- oscura/comparison/__init__.py +66 -0
- oscura/comparison/compare.py +397 -0
- oscura/comparison/golden.py +487 -0
- oscura/comparison/limits.py +391 -0
- oscura/comparison/mask.py +434 -0
- oscura/comparison/trace_diff.py +30 -0
- oscura/comparison/visualization.py +481 -0
- oscura/compliance/__init__.py +70 -0
- oscura/compliance/advanced.py +756 -0
- oscura/compliance/masks.py +363 -0
- oscura/compliance/reporting.py +483 -0
- oscura/compliance/testing.py +298 -0
- oscura/component/__init__.py +38 -0
- oscura/component/impedance.py +365 -0
- oscura/component/reactive.py +598 -0
- oscura/component/transmission_line.py +312 -0
- oscura/config/__init__.py +191 -0
- oscura/config/defaults.py +254 -0
- oscura/config/loader.py +348 -0
- oscura/config/memory.py +271 -0
- oscura/config/migration.py +458 -0
- oscura/config/pipeline.py +1077 -0
- oscura/config/preferences.py +530 -0
- oscura/config/protocol.py +875 -0
- oscura/config/schema.py +713 -0
- oscura/config/settings.py +420 -0
- oscura/config/thresholds.py +599 -0
- oscura/convenience.py +457 -0
- oscura/core/__init__.py +299 -0
- oscura/core/audit.py +457 -0
- oscura/core/backend_selector.py +405 -0
- oscura/core/cache.py +590 -0
- oscura/core/cancellation.py +439 -0
- oscura/core/confidence.py +225 -0
- oscura/core/config.py +506 -0
- oscura/core/correlation.py +216 -0
- oscura/core/cross_domain.py +422 -0
- oscura/core/debug.py +301 -0
- oscura/core/edge_cases.py +541 -0
- oscura/core/exceptions.py +535 -0
- oscura/core/gpu_backend.py +523 -0
- oscura/core/lazy.py +832 -0
- oscura/core/log_query.py +540 -0
- oscura/core/logging.py +931 -0
- oscura/core/logging_advanced.py +952 -0
- oscura/core/memoize.py +171 -0
- oscura/core/memory_check.py +274 -0
- oscura/core/memory_guard.py +290 -0
- oscura/core/memory_limits.py +336 -0
- oscura/core/memory_monitor.py +453 -0
- oscura/core/memory_progress.py +465 -0
- oscura/core/memory_warnings.py +315 -0
- oscura/core/numba_backend.py +362 -0
- oscura/core/performance.py +352 -0
- oscura/core/progress.py +524 -0
- oscura/core/provenance.py +358 -0
- oscura/core/results.py +331 -0
- oscura/core/types.py +504 -0
- oscura/core/uncertainty.py +383 -0
- oscura/discovery/__init__.py +52 -0
- oscura/discovery/anomaly_detector.py +672 -0
- oscura/discovery/auto_decoder.py +415 -0
- oscura/discovery/comparison.py +497 -0
- oscura/discovery/quality_validator.py +528 -0
- oscura/discovery/signal_detector.py +769 -0
- oscura/dsl/__init__.py +73 -0
- oscura/dsl/commands.py +246 -0
- oscura/dsl/interpreter.py +455 -0
- oscura/dsl/parser.py +689 -0
- oscura/dsl/repl.py +172 -0
- oscura/exceptions.py +59 -0
- oscura/exploratory/__init__.py +111 -0
- oscura/exploratory/error_recovery.py +642 -0
- oscura/exploratory/fuzzy.py +513 -0
- oscura/exploratory/fuzzy_advanced.py +786 -0
- oscura/exploratory/legacy.py +831 -0
- oscura/exploratory/parse.py +358 -0
- oscura/exploratory/recovery.py +275 -0
- oscura/exploratory/sync.py +382 -0
- oscura/exploratory/unknown.py +707 -0
- oscura/export/__init__.py +25 -0
- oscura/export/wireshark/README.md +265 -0
- oscura/export/wireshark/__init__.py +47 -0
- oscura/export/wireshark/generator.py +312 -0
- oscura/export/wireshark/lua_builder.py +159 -0
- oscura/export/wireshark/templates/dissector.lua.j2 +92 -0
- oscura/export/wireshark/type_mapping.py +165 -0
- oscura/export/wireshark/validator.py +105 -0
- oscura/exporters/__init__.py +94 -0
- oscura/exporters/csv.py +303 -0
- oscura/exporters/exporters.py +44 -0
- oscura/exporters/hdf5.py +219 -0
- oscura/exporters/html_export.py +701 -0
- oscura/exporters/json_export.py +291 -0
- oscura/exporters/markdown_export.py +367 -0
- oscura/exporters/matlab_export.py +354 -0
- oscura/exporters/npz_export.py +219 -0
- oscura/exporters/spice_export.py +210 -0
- oscura/extensibility/__init__.py +131 -0
- oscura/extensibility/docs.py +752 -0
- oscura/extensibility/extensions.py +1125 -0
- oscura/extensibility/logging.py +259 -0
- oscura/extensibility/measurements.py +485 -0
- oscura/extensibility/plugins.py +414 -0
- oscura/extensibility/registry.py +346 -0
- oscura/extensibility/templates.py +913 -0
- oscura/extensibility/validation.py +651 -0
- oscura/filtering/__init__.py +89 -0
- oscura/filtering/base.py +563 -0
- oscura/filtering/convenience.py +564 -0
- oscura/filtering/design.py +725 -0
- oscura/filtering/filters.py +32 -0
- oscura/filtering/introspection.py +605 -0
- oscura/guidance/__init__.py +24 -0
- oscura/guidance/recommender.py +429 -0
- oscura/guidance/wizard.py +518 -0
- oscura/inference/__init__.py +251 -0
- oscura/inference/active_learning/README.md +153 -0
- oscura/inference/active_learning/__init__.py +38 -0
- oscura/inference/active_learning/lstar.py +257 -0
- oscura/inference/active_learning/observation_table.py +230 -0
- oscura/inference/active_learning/oracle.py +78 -0
- oscura/inference/active_learning/teachers/__init__.py +15 -0
- oscura/inference/active_learning/teachers/simulator.py +192 -0
- oscura/inference/adaptive_tuning.py +453 -0
- oscura/inference/alignment.py +653 -0
- oscura/inference/bayesian.py +943 -0
- oscura/inference/binary.py +1016 -0
- oscura/inference/crc_reverse.py +711 -0
- oscura/inference/logic.py +288 -0
- oscura/inference/message_format.py +1305 -0
- oscura/inference/protocol.py +417 -0
- oscura/inference/protocol_dsl.py +1084 -0
- oscura/inference/protocol_library.py +1230 -0
- oscura/inference/sequences.py +809 -0
- oscura/inference/signal_intelligence.py +1509 -0
- oscura/inference/spectral.py +215 -0
- oscura/inference/state_machine.py +634 -0
- oscura/inference/stream.py +918 -0
- oscura/integrations/__init__.py +59 -0
- oscura/integrations/llm.py +1827 -0
- oscura/jupyter/__init__.py +32 -0
- oscura/jupyter/display.py +268 -0
- oscura/jupyter/magic.py +334 -0
- oscura/loaders/__init__.py +526 -0
- oscura/loaders/binary.py +69 -0
- oscura/loaders/configurable.py +1255 -0
- oscura/loaders/csv.py +26 -0
- oscura/loaders/csv_loader.py +473 -0
- oscura/loaders/hdf5.py +9 -0
- oscura/loaders/hdf5_loader.py +510 -0
- oscura/loaders/lazy.py +370 -0
- oscura/loaders/mmap_loader.py +583 -0
- oscura/loaders/numpy_loader.py +436 -0
- oscura/loaders/pcap.py +432 -0
- oscura/loaders/preprocessing.py +368 -0
- oscura/loaders/rigol.py +287 -0
- oscura/loaders/sigrok.py +321 -0
- oscura/loaders/tdms.py +367 -0
- oscura/loaders/tektronix.py +711 -0
- oscura/loaders/validation.py +584 -0
- oscura/loaders/vcd.py +464 -0
- oscura/loaders/wav.py +233 -0
- oscura/math/__init__.py +45 -0
- oscura/math/arithmetic.py +824 -0
- oscura/math/interpolation.py +413 -0
- oscura/onboarding/__init__.py +39 -0
- oscura/onboarding/help.py +498 -0
- oscura/onboarding/tutorials.py +405 -0
- oscura/onboarding/wizard.py +466 -0
- oscura/optimization/__init__.py +19 -0
- oscura/optimization/parallel.py +440 -0
- oscura/optimization/search.py +532 -0
- oscura/pipeline/__init__.py +43 -0
- oscura/pipeline/base.py +338 -0
- oscura/pipeline/composition.py +242 -0
- oscura/pipeline/parallel.py +448 -0
- oscura/pipeline/pipeline.py +375 -0
- oscura/pipeline/reverse_engineering.py +1119 -0
- oscura/plugins/__init__.py +122 -0
- oscura/plugins/base.py +272 -0
- oscura/plugins/cli.py +497 -0
- oscura/plugins/discovery.py +411 -0
- oscura/plugins/isolation.py +418 -0
- oscura/plugins/lifecycle.py +959 -0
- oscura/plugins/manager.py +493 -0
- oscura/plugins/registry.py +421 -0
- oscura/plugins/versioning.py +372 -0
- oscura/py.typed +0 -0
- oscura/quality/__init__.py +65 -0
- oscura/quality/ensemble.py +740 -0
- oscura/quality/explainer.py +338 -0
- oscura/quality/scoring.py +616 -0
- oscura/quality/warnings.py +456 -0
- oscura/reporting/__init__.py +248 -0
- oscura/reporting/advanced.py +1234 -0
- oscura/reporting/analyze.py +448 -0
- oscura/reporting/argument_preparer.py +596 -0
- oscura/reporting/auto_report.py +507 -0
- oscura/reporting/batch.py +615 -0
- oscura/reporting/chart_selection.py +223 -0
- oscura/reporting/comparison.py +330 -0
- oscura/reporting/config.py +615 -0
- oscura/reporting/content/__init__.py +39 -0
- oscura/reporting/content/executive.py +127 -0
- oscura/reporting/content/filtering.py +191 -0
- oscura/reporting/content/minimal.py +257 -0
- oscura/reporting/content/verbosity.py +162 -0
- oscura/reporting/core.py +508 -0
- oscura/reporting/core_formats/__init__.py +17 -0
- oscura/reporting/core_formats/multi_format.py +210 -0
- oscura/reporting/engine.py +836 -0
- oscura/reporting/export.py +366 -0
- oscura/reporting/formatting/__init__.py +129 -0
- oscura/reporting/formatting/emphasis.py +81 -0
- oscura/reporting/formatting/numbers.py +403 -0
- oscura/reporting/formatting/standards.py +55 -0
- oscura/reporting/formatting.py +466 -0
- oscura/reporting/html.py +578 -0
- oscura/reporting/index.py +590 -0
- oscura/reporting/multichannel.py +296 -0
- oscura/reporting/output.py +379 -0
- oscura/reporting/pdf.py +373 -0
- oscura/reporting/plots.py +731 -0
- oscura/reporting/pptx_export.py +360 -0
- oscura/reporting/renderers/__init__.py +11 -0
- oscura/reporting/renderers/pdf.py +94 -0
- oscura/reporting/sections.py +471 -0
- oscura/reporting/standards.py +680 -0
- oscura/reporting/summary_generator.py +368 -0
- oscura/reporting/tables.py +397 -0
- oscura/reporting/template_system.py +724 -0
- oscura/reporting/templates/__init__.py +15 -0
- oscura/reporting/templates/definition.py +205 -0
- oscura/reporting/templates/index.html +649 -0
- oscura/reporting/templates/index.md +173 -0
- oscura/schemas/__init__.py +158 -0
- oscura/schemas/bus_configuration.json +322 -0
- oscura/schemas/device_mapping.json +182 -0
- oscura/schemas/packet_format.json +418 -0
- oscura/schemas/protocol_definition.json +363 -0
- oscura/search/__init__.py +16 -0
- oscura/search/anomaly.py +292 -0
- oscura/search/context.py +149 -0
- oscura/search/pattern.py +160 -0
- oscura/session/__init__.py +34 -0
- oscura/session/annotations.py +289 -0
- oscura/session/history.py +313 -0
- oscura/session/session.py +445 -0
- oscura/streaming/__init__.py +43 -0
- oscura/streaming/chunked.py +611 -0
- oscura/streaming/progressive.py +393 -0
- oscura/streaming/realtime.py +622 -0
- oscura/testing/__init__.py +54 -0
- oscura/testing/synthetic.py +808 -0
- oscura/triggering/__init__.py +68 -0
- oscura/triggering/base.py +229 -0
- oscura/triggering/edge.py +353 -0
- oscura/triggering/pattern.py +344 -0
- oscura/triggering/pulse.py +581 -0
- oscura/triggering/window.py +453 -0
- oscura/ui/__init__.py +48 -0
- oscura/ui/formatters.py +526 -0
- oscura/ui/progressive_display.py +340 -0
- oscura/utils/__init__.py +99 -0
- oscura/utils/autodetect.py +338 -0
- oscura/utils/buffer.py +389 -0
- oscura/utils/lazy.py +407 -0
- oscura/utils/lazy_imports.py +147 -0
- oscura/utils/memory.py +836 -0
- oscura/utils/memory_advanced.py +1326 -0
- oscura/utils/memory_extensions.py +465 -0
- oscura/utils/progressive.py +352 -0
- oscura/utils/windowing.py +362 -0
- oscura/visualization/__init__.py +321 -0
- oscura/visualization/accessibility.py +526 -0
- oscura/visualization/annotations.py +374 -0
- oscura/visualization/axis_scaling.py +305 -0
- oscura/visualization/colors.py +453 -0
- oscura/visualization/digital.py +337 -0
- oscura/visualization/eye.py +420 -0
- oscura/visualization/histogram.py +281 -0
- oscura/visualization/interactive.py +858 -0
- oscura/visualization/jitter.py +702 -0
- oscura/visualization/keyboard.py +394 -0
- oscura/visualization/layout.py +365 -0
- oscura/visualization/optimization.py +1028 -0
- oscura/visualization/palettes.py +446 -0
- oscura/visualization/plot.py +92 -0
- oscura/visualization/power.py +290 -0
- oscura/visualization/power_extended.py +626 -0
- oscura/visualization/presets.py +467 -0
- oscura/visualization/protocols.py +932 -0
- oscura/visualization/render.py +207 -0
- oscura/visualization/rendering.py +444 -0
- oscura/visualization/reverse_engineering.py +791 -0
- oscura/visualization/signal_integrity.py +808 -0
- oscura/visualization/specialized.py +553 -0
- oscura/visualization/spectral.py +811 -0
- oscura/visualization/styles.py +381 -0
- oscura/visualization/thumbnails.py +311 -0
- oscura/visualization/time_axis.py +351 -0
- oscura/visualization/waveform.py +367 -0
- oscura/workflow/__init__.py +13 -0
- oscura/workflow/dag.py +377 -0
- oscura/workflows/__init__.py +58 -0
- oscura/workflows/compliance.py +280 -0
- oscura/workflows/digital.py +272 -0
- oscura/workflows/multi_trace.py +502 -0
- oscura/workflows/power.py +178 -0
- oscura/workflows/protocol.py +492 -0
- oscura/workflows/reverse_engineering.py +639 -0
- oscura/workflows/signal_integrity.py +227 -0
- oscura-0.1.1.dist-info/METADATA +300 -0
- oscura-0.1.1.dist-info/RECORD +463 -0
- oscura-0.1.1.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/licenses/LICENSE +1 -1
- oscura-0.0.1.dist-info/METADATA +0 -63
- oscura-0.0.1.dist-info/RECORD +0 -5
- {oscura-0.0.1.dist-info → oscura-0.1.1.dist-info}/WHEEL +0 -0
oscura/config/schema.py
ADDED
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
"""JSON Schema validation system for Oscura configuration.
|
|
2
|
+
|
|
3
|
+
This module provides a flexible schema validation system using JSON Schema
|
|
4
|
+
for validating configuration files including protocols, pipelines, and
|
|
5
|
+
threshold configurations.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from oscura.config.schema import validate_against_schema
|
|
10
|
+
>>> config = {"name": "uart", "baud_rate": 115200}
|
|
11
|
+
>>> validate_against_schema(config, "protocol")
|
|
12
|
+
True
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
# Try to import jsonschema for full validation
|
|
21
|
+
try:
|
|
22
|
+
import jsonschema # noqa: F401
|
|
23
|
+
from jsonschema import Draft7Validator
|
|
24
|
+
from jsonschema import ValidationError as JsonSchemaError
|
|
25
|
+
|
|
26
|
+
JSONSCHEMA_AVAILABLE = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
JSONSCHEMA_AVAILABLE = False
|
|
29
|
+
JsonSchemaError = Exception # type: ignore[ignore-without-code]
|
|
30
|
+
|
|
31
|
+
from oscura.core.exceptions import ConfigurationError
|
|
32
|
+
from oscura.core.exceptions import ValidationError as OscuraValidationError
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ValidationError(OscuraValidationError):
|
|
36
|
+
"""Schema validation error with detailed location information.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
path: JSON path to the invalid field.
|
|
40
|
+
line: Line number in source file (if available).
|
|
41
|
+
column: Column number in source file (if available).
|
|
42
|
+
schema_path: Path in schema where validation failed.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
message: str,
|
|
48
|
+
*,
|
|
49
|
+
path: str | None = None,
|
|
50
|
+
line: int | None = None,
|
|
51
|
+
column: int | None = None,
|
|
52
|
+
schema_path: str | None = None,
|
|
53
|
+
expected: Any = None,
|
|
54
|
+
actual: Any = None,
|
|
55
|
+
suggestion: str | None = None,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Initialize ValidationError.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
message: Description of the validation failure.
|
|
61
|
+
path: JSON path to invalid field (e.g., "protocol.timing.baud_rate").
|
|
62
|
+
line: Line number in source file.
|
|
63
|
+
column: Column number in source file.
|
|
64
|
+
schema_path: Path in schema where validation failed.
|
|
65
|
+
expected: Expected value or type.
|
|
66
|
+
actual: Actual value found.
|
|
67
|
+
suggestion: Suggested fix.
|
|
68
|
+
"""
|
|
69
|
+
self.path = path
|
|
70
|
+
self.line = line
|
|
71
|
+
self.column = column
|
|
72
|
+
self.schema_path = schema_path
|
|
73
|
+
self.expected = expected
|
|
74
|
+
self.actual = actual
|
|
75
|
+
self.suggestion = suggestion
|
|
76
|
+
|
|
77
|
+
# Build detailed message
|
|
78
|
+
details_parts = []
|
|
79
|
+
if path:
|
|
80
|
+
details_parts.append(f"Path: {path}")
|
|
81
|
+
if line is not None:
|
|
82
|
+
location = f"Line {line}"
|
|
83
|
+
if column is not None:
|
|
84
|
+
location += f", column {column}"
|
|
85
|
+
details_parts.append(location)
|
|
86
|
+
if expected is not None:
|
|
87
|
+
details_parts.append(f"Expected: {expected}")
|
|
88
|
+
if actual is not None:
|
|
89
|
+
details_parts.append(f"Got: {actual}")
|
|
90
|
+
|
|
91
|
+
super().__init__(
|
|
92
|
+
message,
|
|
93
|
+
field=path,
|
|
94
|
+
constraint=schema_path,
|
|
95
|
+
value=actual,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class ConfigSchema:
|
|
101
|
+
"""Schema definition with metadata.
|
|
102
|
+
|
|
103
|
+
Attributes:
|
|
104
|
+
name: Schema identifier (e.g., "protocol", "pipeline").
|
|
105
|
+
version: Schema version (semver format).
|
|
106
|
+
schema: JSON Schema dictionary.
|
|
107
|
+
description: Human-readable description.
|
|
108
|
+
uri: Optional URI for schema reference.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
name: str
|
|
112
|
+
version: str
|
|
113
|
+
schema: dict[str, Any]
|
|
114
|
+
description: str = ""
|
|
115
|
+
uri: str | None = None
|
|
116
|
+
|
|
117
|
+
def __post_init__(self) -> None:
|
|
118
|
+
"""Validate schema after initialization."""
|
|
119
|
+
if not self.name:
|
|
120
|
+
raise ValueError("Schema name cannot be empty")
|
|
121
|
+
if not self.version:
|
|
122
|
+
raise ValueError("Schema version cannot be empty")
|
|
123
|
+
if not self.schema:
|
|
124
|
+
raise ValueError("Schema cannot be empty")
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def full_uri(self) -> str:
|
|
128
|
+
"""Get full schema URI.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
URI for schema reference, or generated local path if not provided.
|
|
132
|
+
"""
|
|
133
|
+
if self.uri:
|
|
134
|
+
return self.uri
|
|
135
|
+
return f"urn:oscura:schemas:{self.name}:v{self.version}"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class SchemaRegistry:
|
|
139
|
+
"""Central registry for all configuration schemas.
|
|
140
|
+
|
|
141
|
+
Provides O(1) lookup of schemas by name and version.
|
|
142
|
+
|
|
143
|
+
Example:
|
|
144
|
+
>>> registry = SchemaRegistry()
|
|
145
|
+
>>> registry.register(protocol_schema)
|
|
146
|
+
>>> schema = registry.get("protocol")
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def __init__(self) -> None:
|
|
150
|
+
"""Initialize empty schema registry."""
|
|
151
|
+
self._schemas: dict[str, dict[str, ConfigSchema]] = {}
|
|
152
|
+
self._default_versions: dict[str, str] = {}
|
|
153
|
+
|
|
154
|
+
def register(
|
|
155
|
+
self,
|
|
156
|
+
schema: ConfigSchema,
|
|
157
|
+
*,
|
|
158
|
+
set_default: bool = True,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""Register a schema with the registry.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
schema: Schema to register.
|
|
164
|
+
set_default: If True, set as default version for this schema name.
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
ValueError: If schema with same name and version already exists.
|
|
168
|
+
"""
|
|
169
|
+
if schema.name not in self._schemas:
|
|
170
|
+
self._schemas[schema.name] = {}
|
|
171
|
+
|
|
172
|
+
if schema.version in self._schemas[schema.name]:
|
|
173
|
+
self._schemas[schema.name][schema.version]
|
|
174
|
+
raise ValueError(f"Schema '{schema.name}' v{schema.version} already registered")
|
|
175
|
+
|
|
176
|
+
self._schemas[schema.name][schema.version] = schema
|
|
177
|
+
|
|
178
|
+
if set_default:
|
|
179
|
+
self._default_versions[schema.name] = schema.version
|
|
180
|
+
|
|
181
|
+
def get(
|
|
182
|
+
self,
|
|
183
|
+
name: str,
|
|
184
|
+
version: str | None = None,
|
|
185
|
+
) -> ConfigSchema | None:
|
|
186
|
+
"""Get schema by name and optional version.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
name: Schema name (e.g., "protocol").
|
|
190
|
+
version: Specific version or None for default.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
ConfigSchema if found, None otherwise.
|
|
194
|
+
"""
|
|
195
|
+
if name not in self._schemas:
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
if version is None:
|
|
199
|
+
version = self._default_versions.get(name)
|
|
200
|
+
if version is None:
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
return self._schemas[name].get(version)
|
|
204
|
+
|
|
205
|
+
def list_schemas(self) -> list[str]:
|
|
206
|
+
"""List all registered schema names.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
List of schema names.
|
|
210
|
+
"""
|
|
211
|
+
return list(self._schemas.keys())
|
|
212
|
+
|
|
213
|
+
def list_versions(self, name: str) -> list[str]:
|
|
214
|
+
"""List all versions of a schema.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
name: Schema name.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
List of version strings.
|
|
221
|
+
"""
|
|
222
|
+
if name not in self._schemas:
|
|
223
|
+
return []
|
|
224
|
+
return list(self._schemas[name].keys())
|
|
225
|
+
|
|
226
|
+
def has_schema(self, name: str, version: str | None = None) -> bool:
|
|
227
|
+
"""Check if schema exists.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
name: Schema name.
|
|
231
|
+
version: Specific version or None for any.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
True if schema exists.
|
|
235
|
+
"""
|
|
236
|
+
if name not in self._schemas:
|
|
237
|
+
return False
|
|
238
|
+
if version is None:
|
|
239
|
+
return True
|
|
240
|
+
return version in self._schemas[name]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# Global schema registry
|
|
244
|
+
_global_registry: SchemaRegistry | None = None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def get_schema_registry() -> SchemaRegistry:
|
|
248
|
+
"""Get the global schema registry.
|
|
249
|
+
|
|
250
|
+
Initializes with built-in schemas on first call.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
Global SchemaRegistry instance.
|
|
254
|
+
"""
|
|
255
|
+
global _global_registry
|
|
256
|
+
|
|
257
|
+
if _global_registry is None:
|
|
258
|
+
_global_registry = SchemaRegistry()
|
|
259
|
+
_register_builtin_schemas(_global_registry)
|
|
260
|
+
|
|
261
|
+
return _global_registry
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def register_schema(
|
|
265
|
+
schema: ConfigSchema,
|
|
266
|
+
*,
|
|
267
|
+
set_default: bool = True,
|
|
268
|
+
) -> None:
|
|
269
|
+
"""Register a schema with the global registry.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
schema: Schema to register.
|
|
273
|
+
set_default: If True, set as default version.
|
|
274
|
+
"""
|
|
275
|
+
get_schema_registry().register(schema, set_default=set_default)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def validate_against_schema(
|
|
279
|
+
config: dict[str, Any],
|
|
280
|
+
schema_name: str,
|
|
281
|
+
*,
|
|
282
|
+
version: str | None = None,
|
|
283
|
+
strict: bool = False,
|
|
284
|
+
) -> bool:
|
|
285
|
+
"""Validate configuration against a registered schema.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
config: Configuration dictionary to validate.
|
|
289
|
+
schema_name: Name of schema to validate against.
|
|
290
|
+
version: Specific schema version or None for default.
|
|
291
|
+
strict: If True, fail on additional properties.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
True if validation passes.
|
|
295
|
+
|
|
296
|
+
Raises:
|
|
297
|
+
ValidationError: If validation fails with detailed error info.
|
|
298
|
+
ConfigurationError: If schema not found or jsonschema not available.
|
|
299
|
+
"""
|
|
300
|
+
if not JSONSCHEMA_AVAILABLE:
|
|
301
|
+
raise ConfigurationError(
|
|
302
|
+
"JSON Schema validation not available",
|
|
303
|
+
fix_hint="Install jsonschema: pip install jsonschema",
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
registry = get_schema_registry()
|
|
307
|
+
schema_obj = registry.get(schema_name, version)
|
|
308
|
+
|
|
309
|
+
if schema_obj is None:
|
|
310
|
+
available = registry.list_schemas()
|
|
311
|
+
raise ConfigurationError(
|
|
312
|
+
f"Schema '{schema_name}' not found",
|
|
313
|
+
details=f"Available schemas: {available}",
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
schema = schema_obj.schema.copy()
|
|
317
|
+
|
|
318
|
+
# Add strict mode
|
|
319
|
+
if strict and "additionalProperties" not in schema:
|
|
320
|
+
schema["additionalProperties"] = False
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
validator = Draft7Validator(schema)
|
|
324
|
+
errors = list(validator.iter_errors(config))
|
|
325
|
+
|
|
326
|
+
if errors:
|
|
327
|
+
# Get first error for main message
|
|
328
|
+
error = errors[0]
|
|
329
|
+
path = ".".join(str(p) for p in error.absolute_path) or "(root)"
|
|
330
|
+
|
|
331
|
+
# Try to provide helpful suggestion
|
|
332
|
+
suggestion = _get_error_suggestion(error)
|
|
333
|
+
|
|
334
|
+
raise ValidationError(
|
|
335
|
+
str(error.message),
|
|
336
|
+
path=path,
|
|
337
|
+
schema_path=".".join(str(p) for p in error.absolute_schema_path),
|
|
338
|
+
expected=error.schema.get("type") or error.schema.get("enum"),
|
|
339
|
+
actual=error.instance,
|
|
340
|
+
suggestion=suggestion,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
return True
|
|
344
|
+
|
|
345
|
+
except JsonSchemaError as e:
|
|
346
|
+
path = ".".join(str(p) for p in e.absolute_path) if e.absolute_path else None # type: ignore[assignment]
|
|
347
|
+
raise ValidationError(
|
|
348
|
+
str(e.message),
|
|
349
|
+
path=path,
|
|
350
|
+
schema_path=".".join(str(p) for p in e.absolute_schema_path)
|
|
351
|
+
if e.absolute_schema_path
|
|
352
|
+
else None,
|
|
353
|
+
) from e
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _get_error_suggestion(error: Any) -> str | None:
|
|
357
|
+
"""Generate suggestion for common validation errors.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
error: jsonschema ValidationError.
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Suggestion string or None.
|
|
364
|
+
"""
|
|
365
|
+
msg = error.message.lower()
|
|
366
|
+
|
|
367
|
+
if "is not of type" in msg:
|
|
368
|
+
expected_type = error.schema.get("type", "unknown")
|
|
369
|
+
return f"Convert value to {expected_type}"
|
|
370
|
+
|
|
371
|
+
if "is not valid under any of the given schemas" in msg:
|
|
372
|
+
return "Check value matches one of the allowed formats"
|
|
373
|
+
|
|
374
|
+
if "is a required property" in msg:
|
|
375
|
+
return "Add the missing required field"
|
|
376
|
+
|
|
377
|
+
if "additional properties" in msg:
|
|
378
|
+
return "Remove unrecognized fields or use additionalProperties: true"
|
|
379
|
+
|
|
380
|
+
if "does not match" in msg:
|
|
381
|
+
pattern = error.schema.get("pattern")
|
|
382
|
+
if pattern:
|
|
383
|
+
return f"Value must match pattern: {pattern}"
|
|
384
|
+
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _register_builtin_schemas(registry: SchemaRegistry) -> None:
|
|
389
|
+
"""Register all built-in schemas.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
registry: Registry to populate.
|
|
393
|
+
"""
|
|
394
|
+
# Protocol definition schema
|
|
395
|
+
registry.register(
|
|
396
|
+
ConfigSchema(
|
|
397
|
+
name="protocol",
|
|
398
|
+
version="1.0.0",
|
|
399
|
+
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
|
+
},
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
"additionalProperties": True,
|
|
486
|
+
},
|
|
487
|
+
)
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
# Pipeline definition schema
|
|
491
|
+
registry.register(
|
|
492
|
+
ConfigSchema(
|
|
493
|
+
name="pipeline",
|
|
494
|
+
version="1.0.0",
|
|
495
|
+
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
|
+
},
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
# Logic family schema
|
|
540
|
+
registry.register(
|
|
541
|
+
ConfigSchema(
|
|
542
|
+
name="logic_family",
|
|
543
|
+
version="1.0.0",
|
|
544
|
+
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
|
+
},
|
|
604
|
+
)
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
# Threshold profile schema
|
|
608
|
+
registry.register(
|
|
609
|
+
ConfigSchema(
|
|
610
|
+
name="threshold_profile",
|
|
611
|
+
version="1.0.0",
|
|
612
|
+
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
|
+
},
|
|
641
|
+
)
|
|
642
|
+
)
|
|
643
|
+
|
|
644
|
+
# Preferences schema
|
|
645
|
+
registry.register(
|
|
646
|
+
ConfigSchema(
|
|
647
|
+
name="preferences",
|
|
648
|
+
version="1.0.0",
|
|
649
|
+
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
|
+
},
|
|
702
|
+
)
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
__all__ = [
|
|
707
|
+
"ConfigSchema",
|
|
708
|
+
"SchemaRegistry",
|
|
709
|
+
"ValidationError",
|
|
710
|
+
"get_schema_registry",
|
|
711
|
+
"register_schema",
|
|
712
|
+
"validate_against_schema",
|
|
713
|
+
]
|