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
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"""Plugin versioning and migration support.
|
|
2
|
+
|
|
3
|
+
This module provides version compatibility checking, migration support
|
|
4
|
+
between plugin versions, and multi-version compatibility layers.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Callable
|
|
15
|
+
|
|
16
|
+
from oscura.plugins.base import PluginBase
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class VersionRange:
|
|
23
|
+
"""Version range specification.
|
|
24
|
+
|
|
25
|
+
Supports version range syntax:
|
|
26
|
+
- "1.0.0" - exact version
|
|
27
|
+
- ">=1.0.0" - greater than or equal
|
|
28
|
+
- "<2.0.0" - less than
|
|
29
|
+
- "^1.5.0" - compatible with (same major)
|
|
30
|
+
- "~1.5.0" - approximately (same major.minor)
|
|
31
|
+
- "*" - any version
|
|
32
|
+
|
|
33
|
+
References:
|
|
34
|
+
PLUG-005: Plugin Dependencies - version range support
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
spec: str
|
|
38
|
+
|
|
39
|
+
def matches(self, version: str) -> bool:
|
|
40
|
+
"""Check if version matches this range.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
version: Version string to check (semver format)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
True if version matches range
|
|
47
|
+
|
|
48
|
+
References:
|
|
49
|
+
PLUG-005: Plugin Dependencies - version range support
|
|
50
|
+
"""
|
|
51
|
+
if self.spec == "*":
|
|
52
|
+
return True
|
|
53
|
+
|
|
54
|
+
# Parse version
|
|
55
|
+
try:
|
|
56
|
+
v_major, v_minor, v_patch = self._parse_version(version)
|
|
57
|
+
except ValueError:
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
# Handle different operators
|
|
61
|
+
if self.spec.startswith(">="):
|
|
62
|
+
target = self.spec[2:].strip()
|
|
63
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
64
|
+
return (v_major, v_minor, v_patch) >= (t_major, t_minor, t_patch)
|
|
65
|
+
|
|
66
|
+
elif self.spec.startswith("<="):
|
|
67
|
+
target = self.spec[2:].strip()
|
|
68
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
69
|
+
return (v_major, v_minor, v_patch) <= (t_major, t_minor, t_patch)
|
|
70
|
+
|
|
71
|
+
elif self.spec.startswith(">"):
|
|
72
|
+
target = self.spec[1:].strip()
|
|
73
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
74
|
+
return (v_major, v_minor, v_patch) > (t_major, t_minor, t_patch)
|
|
75
|
+
|
|
76
|
+
elif self.spec.startswith("<"):
|
|
77
|
+
target = self.spec[1:].strip()
|
|
78
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
79
|
+
return (v_major, v_minor, v_patch) < (t_major, t_minor, t_patch)
|
|
80
|
+
|
|
81
|
+
elif self.spec.startswith("^"):
|
|
82
|
+
# Compatible: same major version
|
|
83
|
+
target = self.spec[1:].strip()
|
|
84
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
85
|
+
return v_major == t_major and (v_minor, v_patch) >= (t_minor, t_patch)
|
|
86
|
+
|
|
87
|
+
elif self.spec.startswith("~"):
|
|
88
|
+
# Approximately: same major.minor version
|
|
89
|
+
target = self.spec[1:].strip()
|
|
90
|
+
t_major, t_minor, t_patch = self._parse_version(target)
|
|
91
|
+
return v_major == t_major and v_minor == t_minor and v_patch >= t_patch
|
|
92
|
+
|
|
93
|
+
else:
|
|
94
|
+
# Exact match
|
|
95
|
+
return version == self.spec
|
|
96
|
+
|
|
97
|
+
def _parse_version(self, version: str) -> tuple[int, int, int]:
|
|
98
|
+
"""Parse semver version string.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
version: Version string (e.g., "1.2.3")
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Tuple of (major, minor, patch)
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
ValueError: If version format is invalid
|
|
108
|
+
"""
|
|
109
|
+
# Handle version with metadata (e.g., "1.2.3-beta+build")
|
|
110
|
+
version = version.split("-")[0].split("+")[0]
|
|
111
|
+
|
|
112
|
+
parts = version.split(".")
|
|
113
|
+
if len(parts) != 3:
|
|
114
|
+
raise ValueError(f"Invalid version format: {version}")
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
major = int(parts[0])
|
|
118
|
+
minor = int(parts[1])
|
|
119
|
+
patch = int(parts[2])
|
|
120
|
+
return (major, minor, patch)
|
|
121
|
+
except ValueError as e:
|
|
122
|
+
raise ValueError(f"Invalid version format: {version}") from e
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass
|
|
126
|
+
class Migration:
|
|
127
|
+
"""Plugin migration definition.
|
|
128
|
+
|
|
129
|
+
Defines migration path from one version to another.
|
|
130
|
+
|
|
131
|
+
Attributes:
|
|
132
|
+
from_version: Source version
|
|
133
|
+
to_version: Target version
|
|
134
|
+
migrate_func: Migration function
|
|
135
|
+
description: Migration description
|
|
136
|
+
|
|
137
|
+
References:
|
|
138
|
+
PLUG-003: Plugin Versioning - migration support
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
from_version: str
|
|
142
|
+
to_version: str
|
|
143
|
+
migrate_func: Callable[[dict[str, Any]], dict[str, Any]]
|
|
144
|
+
description: str = ""
|
|
145
|
+
|
|
146
|
+
def apply(self, config: dict[str, Any]) -> dict[str, Any]:
|
|
147
|
+
"""Apply migration to configuration.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
config: Plugin configuration
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Migrated configuration
|
|
154
|
+
|
|
155
|
+
References:
|
|
156
|
+
PLUG-003: Plugin Versioning - migration support
|
|
157
|
+
"""
|
|
158
|
+
logger.info(f"Migrating plugin config from v{self.from_version} to v{self.to_version}")
|
|
159
|
+
return self.migrate_func(config)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class VersionCompatibilityLayer:
|
|
163
|
+
"""Multi-version compatibility layer for plugins.
|
|
164
|
+
|
|
165
|
+
Allows plugins to support multiple API versions by adapting
|
|
166
|
+
the interface based on the current Oscura API version.
|
|
167
|
+
|
|
168
|
+
References:
|
|
169
|
+
PLUG-003: Plugin Versioning - multi-version compatibility layer
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
def __init__(self, plugin: PluginBase) -> None:
|
|
173
|
+
"""Initialize compatibility layer.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
plugin: Plugin instance to wrap
|
|
177
|
+
"""
|
|
178
|
+
self._plugin = plugin
|
|
179
|
+
self._api_version = "1.0.0" # Default
|
|
180
|
+
self._adapters: dict[str, Callable] = {} # type: ignore[type-arg]
|
|
181
|
+
|
|
182
|
+
def set_api_version(self, api_version: str) -> None:
|
|
183
|
+
"""Set target API version.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
api_version: Oscura API version
|
|
187
|
+
|
|
188
|
+
References:
|
|
189
|
+
PLUG-003: Plugin Versioning - multi-version compatibility
|
|
190
|
+
"""
|
|
191
|
+
self._api_version = api_version
|
|
192
|
+
logger.debug(f"Set API version to {api_version} for plugin {self._plugin.name}")
|
|
193
|
+
|
|
194
|
+
def register_adapter(
|
|
195
|
+
self,
|
|
196
|
+
api_version: str,
|
|
197
|
+
method_name: str,
|
|
198
|
+
adapter: Callable, # type: ignore[type-arg]
|
|
199
|
+
) -> None:
|
|
200
|
+
"""Register method adapter for specific API version.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
api_version: API version this adapter is for
|
|
204
|
+
method_name: Method name to adapt
|
|
205
|
+
adapter: Adapter function
|
|
206
|
+
|
|
207
|
+
References:
|
|
208
|
+
PLUG-003: Plugin Versioning - multi-version compatibility
|
|
209
|
+
"""
|
|
210
|
+
key = f"{api_version}:{method_name}"
|
|
211
|
+
self._adapters[key] = adapter
|
|
212
|
+
|
|
213
|
+
def call_adapted(self, method_name: str, *args: Any, **kwargs: Any) -> Any:
|
|
214
|
+
"""Call plugin method with version adaptation.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
method_name: Method to call
|
|
218
|
+
*args: Positional arguments
|
|
219
|
+
**kwargs: Keyword arguments
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
Method result
|
|
223
|
+
|
|
224
|
+
References:
|
|
225
|
+
PLUG-003: Plugin Versioning - multi-version compatibility
|
|
226
|
+
"""
|
|
227
|
+
key = f"{self._api_version}:{method_name}"
|
|
228
|
+
|
|
229
|
+
if key in self._adapters:
|
|
230
|
+
# Use adapter
|
|
231
|
+
adapter = self._adapters[key]
|
|
232
|
+
return adapter(self._plugin, *args, **kwargs)
|
|
233
|
+
else:
|
|
234
|
+
# Call directly
|
|
235
|
+
method = getattr(self._plugin, method_name)
|
|
236
|
+
return method(*args, **kwargs)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class MigrationManager:
|
|
240
|
+
"""Manager for plugin configuration migrations.
|
|
241
|
+
|
|
242
|
+
Tracks and applies migrations between plugin versions.
|
|
243
|
+
|
|
244
|
+
References:
|
|
245
|
+
PLUG-003: Plugin Versioning - migration support
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
def __init__(self) -> None:
|
|
249
|
+
"""Initialize migration manager."""
|
|
250
|
+
self._migrations: dict[str, list[Migration]] = {}
|
|
251
|
+
|
|
252
|
+
def register_migration(self, plugin_name: str, migration: Migration) -> None:
|
|
253
|
+
"""Register a migration for a plugin.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
plugin_name: Plugin name
|
|
257
|
+
migration: Migration definition
|
|
258
|
+
|
|
259
|
+
References:
|
|
260
|
+
PLUG-003: Plugin Versioning - migration support
|
|
261
|
+
"""
|
|
262
|
+
if plugin_name not in self._migrations:
|
|
263
|
+
self._migrations[plugin_name] = []
|
|
264
|
+
|
|
265
|
+
self._migrations[plugin_name].append(migration)
|
|
266
|
+
logger.debug(
|
|
267
|
+
f"Registered migration for {plugin_name}: "
|
|
268
|
+
f"v{migration.from_version} -> v{migration.to_version}"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
def get_migration_path(
|
|
272
|
+
self,
|
|
273
|
+
plugin_name: str,
|
|
274
|
+
from_version: str,
|
|
275
|
+
to_version: str,
|
|
276
|
+
) -> list[Migration]:
|
|
277
|
+
"""Get migration path between versions.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
plugin_name: Plugin name
|
|
281
|
+
from_version: Source version
|
|
282
|
+
to_version: Target version
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
List of migrations in order
|
|
286
|
+
|
|
287
|
+
Raises:
|
|
288
|
+
ValueError: If no migration path exists
|
|
289
|
+
|
|
290
|
+
References:
|
|
291
|
+
PLUG-003: Plugin Versioning - migration support
|
|
292
|
+
"""
|
|
293
|
+
if plugin_name not in self._migrations:
|
|
294
|
+
return []
|
|
295
|
+
|
|
296
|
+
# Simple linear path (could be enhanced with graph search)
|
|
297
|
+
migrations = self._migrations[plugin_name]
|
|
298
|
+
path: list[Migration] = []
|
|
299
|
+
|
|
300
|
+
current = from_version
|
|
301
|
+
while current != to_version:
|
|
302
|
+
# Find next migration
|
|
303
|
+
next_migration = None
|
|
304
|
+
for migration in migrations:
|
|
305
|
+
if migration.from_version == current:
|
|
306
|
+
next_migration = migration
|
|
307
|
+
break
|
|
308
|
+
|
|
309
|
+
if next_migration is None:
|
|
310
|
+
raise ValueError(f"No migration path from v{from_version} to v{to_version}")
|
|
311
|
+
|
|
312
|
+
path.append(next_migration)
|
|
313
|
+
current = next_migration.to_version
|
|
314
|
+
|
|
315
|
+
return path
|
|
316
|
+
|
|
317
|
+
def migrate(
|
|
318
|
+
self,
|
|
319
|
+
plugin_name: str,
|
|
320
|
+
config: dict[str, Any],
|
|
321
|
+
from_version: str,
|
|
322
|
+
to_version: str,
|
|
323
|
+
) -> dict[str, Any]:
|
|
324
|
+
"""Migrate configuration between versions.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
plugin_name: Plugin name
|
|
328
|
+
config: Current configuration
|
|
329
|
+
from_version: Source version
|
|
330
|
+
to_version: Target version
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Migrated configuration
|
|
334
|
+
|
|
335
|
+
References:
|
|
336
|
+
PLUG-003: Plugin Versioning - migration support
|
|
337
|
+
"""
|
|
338
|
+
if from_version == to_version:
|
|
339
|
+
return config
|
|
340
|
+
|
|
341
|
+
path = self.get_migration_path(plugin_name, from_version, to_version)
|
|
342
|
+
|
|
343
|
+
result = config
|
|
344
|
+
for migration in path:
|
|
345
|
+
result = migration.apply(result)
|
|
346
|
+
|
|
347
|
+
return result
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# Global migration manager
|
|
351
|
+
_migration_manager: MigrationManager | None = None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def get_migration_manager() -> MigrationManager:
|
|
355
|
+
"""Get global migration manager.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Global MigrationManager instance
|
|
359
|
+
"""
|
|
360
|
+
global _migration_manager
|
|
361
|
+
if _migration_manager is None:
|
|
362
|
+
_migration_manager = MigrationManager()
|
|
363
|
+
return _migration_manager
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
__all__ = [
|
|
367
|
+
"Migration",
|
|
368
|
+
"MigrationManager",
|
|
369
|
+
"VersionCompatibilityLayer",
|
|
370
|
+
"VersionRange",
|
|
371
|
+
"get_migration_manager",
|
|
372
|
+
]
|
oscura/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Signal quality analysis module for Oscura."""
|
|
2
|
+
|
|
3
|
+
from oscura.quality.ensemble import (
|
|
4
|
+
AMPLITUDE_ENSEMBLE,
|
|
5
|
+
EDGE_DETECTION_ENSEMBLE,
|
|
6
|
+
FREQUENCY_ENSEMBLE,
|
|
7
|
+
AggregationMethod,
|
|
8
|
+
EnsembleAggregator,
|
|
9
|
+
EnsembleResult,
|
|
10
|
+
create_edge_ensemble,
|
|
11
|
+
create_frequency_ensemble,
|
|
12
|
+
)
|
|
13
|
+
from oscura.quality.explainer import (
|
|
14
|
+
ResultExplainer,
|
|
15
|
+
ResultExplanation,
|
|
16
|
+
explain_result,
|
|
17
|
+
)
|
|
18
|
+
from oscura.quality.scoring import (
|
|
19
|
+
AnalysisQualityScore,
|
|
20
|
+
DataQualityMetrics,
|
|
21
|
+
ReliabilityCategory,
|
|
22
|
+
assess_data_quality,
|
|
23
|
+
calculate_quality_score,
|
|
24
|
+
combine_quality_scores,
|
|
25
|
+
score_analysis_result,
|
|
26
|
+
)
|
|
27
|
+
from oscura.quality.warnings import (
|
|
28
|
+
QualityWarning,
|
|
29
|
+
SignalQualityAnalyzer,
|
|
30
|
+
check_clipping,
|
|
31
|
+
check_noise,
|
|
32
|
+
check_saturation,
|
|
33
|
+
check_undersampling,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
# Ensemble methods
|
|
38
|
+
"AMPLITUDE_ENSEMBLE",
|
|
39
|
+
"EDGE_DETECTION_ENSEMBLE",
|
|
40
|
+
"FREQUENCY_ENSEMBLE",
|
|
41
|
+
"AggregationMethod",
|
|
42
|
+
# Scoring
|
|
43
|
+
"AnalysisQualityScore",
|
|
44
|
+
"DataQualityMetrics",
|
|
45
|
+
"EnsembleAggregator",
|
|
46
|
+
"EnsembleResult",
|
|
47
|
+
# Warnings
|
|
48
|
+
"QualityWarning",
|
|
49
|
+
"ReliabilityCategory",
|
|
50
|
+
"ResultExplainer",
|
|
51
|
+
# Explainability
|
|
52
|
+
"ResultExplanation",
|
|
53
|
+
"SignalQualityAnalyzer",
|
|
54
|
+
"assess_data_quality",
|
|
55
|
+
"calculate_quality_score",
|
|
56
|
+
"check_clipping",
|
|
57
|
+
"check_noise",
|
|
58
|
+
"check_saturation",
|
|
59
|
+
"check_undersampling",
|
|
60
|
+
"combine_quality_scores",
|
|
61
|
+
"create_edge_ensemble",
|
|
62
|
+
"create_frequency_ensemble",
|
|
63
|
+
"explain_result",
|
|
64
|
+
"score_analysis_result",
|
|
65
|
+
]
|