oscura 0.0.1__py3-none-any.whl → 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.0.dist-info/METADATA +300 -0
- oscura-0.1.0.dist-info/RECORD +463 -0
- oscura-0.1.0.dist-info/entry_points.txt +2 -0
- {oscura-0.0.1.dist-info → oscura-0.1.0.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.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Lua code builder for programmatic dissector generation.
|
|
2
|
+
|
|
3
|
+
This module provides a builder class for constructing Lua code with
|
|
4
|
+
proper indentation and structure.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LuaCodeBuilder:
|
|
9
|
+
"""Build Lua dissector code programmatically.
|
|
10
|
+
|
|
11
|
+
This class helps construct well-formatted Lua code with proper
|
|
12
|
+
indentation and structure management.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
>>> builder = LuaCodeBuilder()
|
|
16
|
+
>>> builder.add_comment("Initialize protocol")
|
|
17
|
+
>>> builder.add_variable("proto", 'Proto("myproto", "My Protocol")')
|
|
18
|
+
>>> builder.begin_function("dissector", ["buffer", "pinfo", "tree"])
|
|
19
|
+
>>> builder.add_line("pinfo.cols.protocol = proto.name")
|
|
20
|
+
>>> builder.end_function()
|
|
21
|
+
>>> print(builder.to_string())
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, indent_size: int = 4) -> None:
|
|
25
|
+
"""Initialize the builder.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
indent_size: Number of spaces per indentation level
|
|
29
|
+
"""
|
|
30
|
+
self.lines: list[str] = []
|
|
31
|
+
self.indent_level = 0
|
|
32
|
+
self.indent_size = indent_size
|
|
33
|
+
|
|
34
|
+
def add_line(self, line: str) -> None:
|
|
35
|
+
"""Add a line with current indentation.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
line: Line content (without indentation)
|
|
39
|
+
"""
|
|
40
|
+
if line.strip(): # Don't indent empty lines
|
|
41
|
+
indent = " " * (self.indent_level * self.indent_size)
|
|
42
|
+
self.lines.append(f"{indent}{line}")
|
|
43
|
+
else:
|
|
44
|
+
self.lines.append("")
|
|
45
|
+
|
|
46
|
+
def add_blank_line(self) -> None:
|
|
47
|
+
"""Add a blank line."""
|
|
48
|
+
self.lines.append("")
|
|
49
|
+
|
|
50
|
+
def add_comment(self, comment: str, prefix: str = "--") -> None:
|
|
51
|
+
"""Add a Lua comment.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
comment: Comment text
|
|
55
|
+
prefix: Comment prefix (default: "--")
|
|
56
|
+
"""
|
|
57
|
+
self.add_line(f"{prefix} {comment}")
|
|
58
|
+
|
|
59
|
+
def begin_function(self, name: str, params: list[str]) -> None:
|
|
60
|
+
"""Start a function definition.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
name: Function name
|
|
64
|
+
params: List of parameter names
|
|
65
|
+
"""
|
|
66
|
+
param_list = ", ".join(params)
|
|
67
|
+
self.add_line(f"function {name}({param_list})")
|
|
68
|
+
self.indent_level += 1
|
|
69
|
+
|
|
70
|
+
def end_function(self) -> None:
|
|
71
|
+
"""End a function definition."""
|
|
72
|
+
self.indent_level -= 1
|
|
73
|
+
self.add_line("end")
|
|
74
|
+
|
|
75
|
+
def begin_if(self, condition: str) -> None:
|
|
76
|
+
"""Start an if statement.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
condition: If condition
|
|
80
|
+
"""
|
|
81
|
+
self.add_line(f"if {condition} then")
|
|
82
|
+
self.indent_level += 1
|
|
83
|
+
|
|
84
|
+
def add_else(self) -> None:
|
|
85
|
+
"""Add else clause."""
|
|
86
|
+
self.indent_level -= 1
|
|
87
|
+
self.add_line("else")
|
|
88
|
+
self.indent_level += 1
|
|
89
|
+
|
|
90
|
+
def add_elseif(self, condition: str) -> None:
|
|
91
|
+
"""Add elseif clause.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
condition: Elseif condition
|
|
95
|
+
"""
|
|
96
|
+
self.indent_level -= 1
|
|
97
|
+
self.add_line(f"elseif {condition} then")
|
|
98
|
+
self.indent_level += 1
|
|
99
|
+
|
|
100
|
+
def end_if(self) -> None:
|
|
101
|
+
"""End an if statement."""
|
|
102
|
+
self.indent_level -= 1
|
|
103
|
+
self.add_line("end")
|
|
104
|
+
|
|
105
|
+
def begin_for(self, loop_var: str, start: str, end: str) -> None:
|
|
106
|
+
"""Start a for loop.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
loop_var: Loop variable name
|
|
110
|
+
start: Start value
|
|
111
|
+
end: End value
|
|
112
|
+
"""
|
|
113
|
+
self.add_line(f"for {loop_var} = {start}, {end} do")
|
|
114
|
+
self.indent_level += 1
|
|
115
|
+
|
|
116
|
+
def end_for(self) -> None:
|
|
117
|
+
"""End a for loop."""
|
|
118
|
+
self.indent_level -= 1
|
|
119
|
+
self.add_line("end")
|
|
120
|
+
|
|
121
|
+
def add_variable(self, name: str, value: str, local: bool = True) -> None:
|
|
122
|
+
"""Add a variable declaration.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
name: Variable name
|
|
126
|
+
value: Variable value
|
|
127
|
+
local: Whether to use 'local' keyword
|
|
128
|
+
"""
|
|
129
|
+
prefix = "local " if local else ""
|
|
130
|
+
self.add_line(f"{prefix}{name} = {value}")
|
|
131
|
+
|
|
132
|
+
def add_return(self, value: str) -> None:
|
|
133
|
+
"""Add a return statement.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
value: Return value
|
|
137
|
+
"""
|
|
138
|
+
self.add_line(f"return {value}")
|
|
139
|
+
|
|
140
|
+
def indent(self) -> None:
|
|
141
|
+
"""Increase indentation level."""
|
|
142
|
+
self.indent_level += 1
|
|
143
|
+
|
|
144
|
+
def dedent(self) -> None:
|
|
145
|
+
"""Decrease indentation level."""
|
|
146
|
+
if self.indent_level > 0:
|
|
147
|
+
self.indent_level -= 1
|
|
148
|
+
|
|
149
|
+
def to_string(self) -> str:
|
|
150
|
+
"""Generate final Lua code.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Complete Lua code as a string
|
|
154
|
+
"""
|
|
155
|
+
return "\n".join(self.lines)
|
|
156
|
+
|
|
157
|
+
def __str__(self) -> str:
|
|
158
|
+
"""String representation."""
|
|
159
|
+
return self.to_string()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
-- {{ protocol.name }}.lua
|
|
2
|
+
-- Generated by TraceKit on {{ timestamp }}
|
|
3
|
+
--
|
|
4
|
+
-- Protocol: {{ protocol.description }}
|
|
5
|
+
-- Version: {{ protocol.version }}
|
|
6
|
+
{% if protocol.endian %}-- Endianness: {{ protocol.endian }}
|
|
7
|
+
{% endif %}
|
|
8
|
+
|
|
9
|
+
-- Protocol declaration
|
|
10
|
+
local {{ proto_var }} = Proto("{{ protocol.name }}", "{{ protocol.description }}")
|
|
11
|
+
|
|
12
|
+
-- Field declarations
|
|
13
|
+
{% for field in fields %}
|
|
14
|
+
local f_{{ field.name }} = {{ field.protofield_type }}(
|
|
15
|
+
"{{ protocol.name }}.{{ field.name }}",
|
|
16
|
+
"{{ field.display_name }}",
|
|
17
|
+
{{ field.display_base }}
|
|
18
|
+
{%- if field.value_string %}, {{ field.value_string }}{% endif %}
|
|
19
|
+
)
|
|
20
|
+
{% endfor %}
|
|
21
|
+
|
|
22
|
+
-- Register fields
|
|
23
|
+
{{ proto_var }}.fields = { {% for field in fields %}f_{{ field.name }}{% if not loop.last %}, {% endif %}{% endfor %} }
|
|
24
|
+
|
|
25
|
+
-- Dissector function
|
|
26
|
+
function {{ proto_var }}.dissector(buffer, pinfo, tree)
|
|
27
|
+
local pktlen = buffer:len()
|
|
28
|
+
|
|
29
|
+
-- Check minimum length
|
|
30
|
+
if pktlen < {{ min_length }} then
|
|
31
|
+
return 0 -- Not enough data
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
-- Set protocol column
|
|
35
|
+
pinfo.cols.protocol = {{ proto_var }}.name
|
|
36
|
+
|
|
37
|
+
-- Create protocol subtree
|
|
38
|
+
local subtree = tree:add({{ proto_var }}, buffer(), "{{ protocol.description }}")
|
|
39
|
+
local offset = 0
|
|
40
|
+
|
|
41
|
+
-- Decode fields
|
|
42
|
+
{% for field in fields %}
|
|
43
|
+
{% if field.condition %}
|
|
44
|
+
-- Conditional field: {{ field.name }} ({{ field.condition }})
|
|
45
|
+
-- TODO: Implement condition evaluation
|
|
46
|
+
{% endif %}
|
|
47
|
+
{% if field.is_variable_length %}
|
|
48
|
+
-- Variable-length field: {{ field.name }}
|
|
49
|
+
{% if field.size_field %}
|
|
50
|
+
local {{ field.name }}_len = buffer({{ field.size_offset }}, {{ field.size_field_size }}):{{ field.size_reader }}()
|
|
51
|
+
if offset + {{ field.name }}_len > pktlen then
|
|
52
|
+
subtree:add_expert_info(PI_MALFORMED, PI_ERROR, "Truncated {{ field.name }}")
|
|
53
|
+
return pktlen
|
|
54
|
+
end
|
|
55
|
+
subtree:add(f_{{ field.name }}, buffer(offset, {{ field.name }}_len))
|
|
56
|
+
offset = offset + {{ field.name }}_len
|
|
57
|
+
{% else %}
|
|
58
|
+
-- Use remaining data for {{ field.name }}
|
|
59
|
+
local {{ field.name }}_len = pktlen - offset
|
|
60
|
+
subtree:add(f_{{ field.name }}, buffer(offset, {{ field.name }}_len))
|
|
61
|
+
offset = offset + {{ field.name }}_len
|
|
62
|
+
{% endif %}
|
|
63
|
+
{% else %}
|
|
64
|
+
-- Fixed-length field: {{ field.name }} ({{ field.size }} bytes)
|
|
65
|
+
if offset + {{ field.size }} > pktlen then
|
|
66
|
+
subtree:add_expert_info(PI_MALFORMED, PI_ERROR, "Truncated {{ field.name }}")
|
|
67
|
+
return pktlen
|
|
68
|
+
end
|
|
69
|
+
subtree:add(f_{{ field.name }}, buffer(offset, {{ field.size }}))
|
|
70
|
+
offset = offset + {{ field.size }}
|
|
71
|
+
{% endif %}
|
|
72
|
+
|
|
73
|
+
{% endfor %}
|
|
74
|
+
return offset
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
-- Protocol registration
|
|
78
|
+
{% if transport == "tcp" %}
|
|
79
|
+
-- Register on TCP port {{ port }}
|
|
80
|
+
local tcp_table = DissectorTable.get("tcp.port")
|
|
81
|
+
tcp_table:add({{ port }}, {{ proto_var }})
|
|
82
|
+
{% elif transport == "udp" %}
|
|
83
|
+
-- Register on UDP port {{ port }}
|
|
84
|
+
local udp_table = DissectorTable.get("udp.port")
|
|
85
|
+
udp_table:add({{ port }}, {{ proto_var }})
|
|
86
|
+
{% elif pattern %}
|
|
87
|
+
-- Register on pattern match
|
|
88
|
+
-- TODO: Implement heuristic dissector for pattern "{{ pattern }}"
|
|
89
|
+
{% else %}
|
|
90
|
+
-- No automatic registration - manually register as needed
|
|
91
|
+
-- Example: DissectorTable.get("tcp.port"):add(PORT, {{ proto_var }})
|
|
92
|
+
{% endif %}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Type mapping between TraceKit field types and Wireshark ProtoField types.
|
|
2
|
+
|
|
3
|
+
This module provides mappings from TraceKit protocol field types to their
|
|
4
|
+
corresponding Wireshark Lua ProtoField types and display bases.
|
|
5
|
+
|
|
6
|
+
References:
|
|
7
|
+
https://wiki.wireshark.org/LuaAPI/Proto
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
# Map TraceKit field types to Wireshark ProtoField types
|
|
13
|
+
FIELD_TYPE_MAPPING: dict[str, str] = {
|
|
14
|
+
"uint8": "ProtoField.uint8",
|
|
15
|
+
"uint16": "ProtoField.uint16",
|
|
16
|
+
"uint32": "ProtoField.uint32",
|
|
17
|
+
"uint64": "ProtoField.uint64",
|
|
18
|
+
"int8": "ProtoField.int8",
|
|
19
|
+
"int16": "ProtoField.int16",
|
|
20
|
+
"int32": "ProtoField.int32",
|
|
21
|
+
"int64": "ProtoField.int64",
|
|
22
|
+
"bytes": "ProtoField.bytes",
|
|
23
|
+
"string": "ProtoField.string",
|
|
24
|
+
"bool": "ProtoField.bool",
|
|
25
|
+
"float32": "ProtoField.float",
|
|
26
|
+
"float64": "ProtoField.double",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Map display base names to Wireshark base constants
|
|
30
|
+
BASE_MAPPING: dict[str, str] = {
|
|
31
|
+
"dec": "base.DEC",
|
|
32
|
+
"hex": "base.HEX",
|
|
33
|
+
"oct": "base.OCT",
|
|
34
|
+
"bin": "base.BIN",
|
|
35
|
+
"none": "base.NONE",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Default display base for each field type
|
|
39
|
+
DEFAULT_BASE: dict[str, str] = {
|
|
40
|
+
"uint8": "hex",
|
|
41
|
+
"uint16": "hex",
|
|
42
|
+
"uint32": "hex",
|
|
43
|
+
"uint64": "hex",
|
|
44
|
+
"int8": "dec",
|
|
45
|
+
"int16": "dec",
|
|
46
|
+
"int32": "dec",
|
|
47
|
+
"int64": "dec",
|
|
48
|
+
"bytes": "none",
|
|
49
|
+
"string": "none",
|
|
50
|
+
"bool": "none",
|
|
51
|
+
"float32": "none",
|
|
52
|
+
"float64": "none",
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def get_protofield_type(field_type: str, display_base: str | None = None) -> tuple[str, str]:
|
|
57
|
+
"""Map TraceKit field type to Wireshark ProtoField and display base.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
field_type: TraceKit field type (uint8, uint16, string, etc.)
|
|
61
|
+
display_base: Optional display base (dec, hex, oct, bin, none)
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Tuple of (protofield_type, base_constant)
|
|
65
|
+
Example: ("ProtoField.uint16", "base.HEX")
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
ValueError: If field type is unknown
|
|
69
|
+
"""
|
|
70
|
+
if field_type not in FIELD_TYPE_MAPPING:
|
|
71
|
+
raise ValueError(f"Unknown field type: {field_type}")
|
|
72
|
+
|
|
73
|
+
protofield = FIELD_TYPE_MAPPING[field_type]
|
|
74
|
+
|
|
75
|
+
# Determine display base
|
|
76
|
+
if display_base is None:
|
|
77
|
+
display_base = DEFAULT_BASE[field_type]
|
|
78
|
+
|
|
79
|
+
if display_base not in BASE_MAPPING:
|
|
80
|
+
raise ValueError(f"Unknown display base: {display_base}")
|
|
81
|
+
|
|
82
|
+
base_constant = BASE_MAPPING[display_base]
|
|
83
|
+
|
|
84
|
+
return protofield, base_constant
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_field_size(field_type: str) -> int | None:
|
|
88
|
+
"""Get the fixed size in bytes for a field type.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
field_type: TraceKit field type
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Field size in bytes, or None for variable-length types
|
|
95
|
+
"""
|
|
96
|
+
size_map: dict[str, int | None] = {
|
|
97
|
+
"uint8": 1,
|
|
98
|
+
"int8": 1,
|
|
99
|
+
"uint16": 2,
|
|
100
|
+
"int16": 2,
|
|
101
|
+
"uint32": 4,
|
|
102
|
+
"int32": 4,
|
|
103
|
+
"uint64": 8,
|
|
104
|
+
"int64": 8,
|
|
105
|
+
"float32": 4,
|
|
106
|
+
"float64": 8,
|
|
107
|
+
"bool": 1,
|
|
108
|
+
"bytes": None, # Variable length
|
|
109
|
+
"string": None, # Variable length
|
|
110
|
+
}
|
|
111
|
+
return size_map.get(field_type)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def is_variable_length(field_type: str) -> bool:
|
|
115
|
+
"""Check if a field type is variable length.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
field_type: TraceKit field type
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
True if field is variable length
|
|
122
|
+
"""
|
|
123
|
+
return get_field_size(field_type) is None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_lua_reader_function(field_type: str, endian: Literal["big", "little"] = "big") -> str:
|
|
127
|
+
"""Get the Lua buffer reader function for a field type.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
field_type: TraceKit field type
|
|
131
|
+
endian: Byte order (big or little endian)
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Lua function name (e.g., "uint16", "le_uint16")
|
|
135
|
+
|
|
136
|
+
Raises:
|
|
137
|
+
ValueError: If field type is unknown
|
|
138
|
+
"""
|
|
139
|
+
if field_type not in FIELD_TYPE_MAPPING:
|
|
140
|
+
raise ValueError(f"Unknown field type: {field_type}")
|
|
141
|
+
|
|
142
|
+
# Map field types to Lua buffer reader methods
|
|
143
|
+
reader_map: dict[str, str] = {
|
|
144
|
+
"uint8": "uint",
|
|
145
|
+
"int8": "int",
|
|
146
|
+
"uint16": "uint16",
|
|
147
|
+
"int16": "int16",
|
|
148
|
+
"uint32": "uint32",
|
|
149
|
+
"int32": "int32",
|
|
150
|
+
"uint64": "uint64",
|
|
151
|
+
"int64": "int64",
|
|
152
|
+
"float32": "float",
|
|
153
|
+
"float64": "double",
|
|
154
|
+
"bool": "uint",
|
|
155
|
+
"bytes": "bytes",
|
|
156
|
+
"string": "string",
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
reader = reader_map[field_type]
|
|
160
|
+
|
|
161
|
+
# Add little-endian prefix if needed
|
|
162
|
+
if endian == "little" and field_type not in ["uint8", "int8", "bool", "bytes", "string"]:
|
|
163
|
+
return f"le_{reader}"
|
|
164
|
+
|
|
165
|
+
return reader
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Lua syntax validator using luac compiler.
|
|
2
|
+
|
|
3
|
+
This module validates generated Lua code syntax using the luac compiler
|
|
4
|
+
if available on the system.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import subprocess
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def validate_lua_syntax(lua_code: str) -> tuple[bool, str]:
|
|
12
|
+
"""Validate Lua syntax using luac compiler.
|
|
13
|
+
|
|
14
|
+
This function attempts to validate Lua code by passing it through
|
|
15
|
+
the luac compiler. If luac is not available, validation is skipped.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
lua_code: Lua code to validate
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Tuple of (is_valid, error_message)
|
|
22
|
+
- is_valid: True if syntax is valid or validation skipped
|
|
23
|
+
- error_message: Empty string if valid, error details if invalid,
|
|
24
|
+
or skip message if luac not available
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
>>> valid, error = validate_lua_syntax("local x = 1")
|
|
28
|
+
>>> if not valid:
|
|
29
|
+
... print(f"Syntax error: {error}")
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
# Try to validate using luac
|
|
33
|
+
result = subprocess.run(
|
|
34
|
+
["luac", "-p", "-"],
|
|
35
|
+
input=lua_code.encode(),
|
|
36
|
+
capture_output=True,
|
|
37
|
+
timeout=5,
|
|
38
|
+
check=False,
|
|
39
|
+
)
|
|
40
|
+
if result.returncode == 0:
|
|
41
|
+
return True, ""
|
|
42
|
+
return False, result.stderr.decode()
|
|
43
|
+
except FileNotFoundError:
|
|
44
|
+
# luac not available, skip validation
|
|
45
|
+
return True, "luac not found, syntax validation skipped"
|
|
46
|
+
except subprocess.TimeoutExpired:
|
|
47
|
+
return False, "Validation timeout"
|
|
48
|
+
except Exception as e:
|
|
49
|
+
# Other errors - treat as unable to validate
|
|
50
|
+
return True, f"Validation skipped: {e!s}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def validate_lua_file(lua_path: Path) -> tuple[bool, str]:
|
|
54
|
+
"""Validate a Lua file using luac compiler.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
lua_path: Path to Lua file
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Tuple of (is_valid, error_message)
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
FileNotFoundError: If the file does not exist
|
|
64
|
+
"""
|
|
65
|
+
if not lua_path.exists():
|
|
66
|
+
raise FileNotFoundError(f"Lua file not found: {lua_path}")
|
|
67
|
+
|
|
68
|
+
lua_code = lua_path.read_text()
|
|
69
|
+
return validate_lua_syntax(lua_code)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def check_luac_available() -> bool:
|
|
73
|
+
"""Check if luac compiler is available on the system.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
True if luac is available, False otherwise
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
result = subprocess.run(
|
|
80
|
+
["luac", "-v"],
|
|
81
|
+
capture_output=True,
|
|
82
|
+
timeout=2,
|
|
83
|
+
check=False,
|
|
84
|
+
)
|
|
85
|
+
return result.returncode == 0
|
|
86
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def save_and_validate(lua_code: str, output_path: Path) -> tuple[bool, str]:
|
|
91
|
+
"""Save Lua code to file and validate it.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
lua_code: Lua code to save
|
|
95
|
+
output_path: Where to save the file
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Tuple of (is_valid, error_message)
|
|
99
|
+
"""
|
|
100
|
+
# Save the file first
|
|
101
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
102
|
+
output_path.write_text(lua_code)
|
|
103
|
+
|
|
104
|
+
# Validate
|
|
105
|
+
return validate_lua_file(output_path)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Data export module for TraceKit.
|
|
2
|
+
|
|
3
|
+
Provides export functionality to various file formats including CSV, HDF5,
|
|
4
|
+
JSON, MATLAB, Markdown, HTML, NumPy NPZ, and SPICE PWL.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.exporters import export_csv, export_hdf5, export_json, export_mat
|
|
9
|
+
>>> export_csv(trace, "waveform.csv")
|
|
10
|
+
>>> export_hdf5(trace, "waveform.h5")
|
|
11
|
+
>>> export_json(trace, "waveform.json")
|
|
12
|
+
>>> export_mat(trace, "waveform.mat")
|
|
13
|
+
>>> export_markdown(data, "report.md")
|
|
14
|
+
>>> export_html(data, "report.html")
|
|
15
|
+
>>> export_npz(trace, "waveform.npz")
|
|
16
|
+
>>> export_pwl(trace, "stimulus.pwl")
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# Import exporters module as namespace for DSL compatibility
|
|
20
|
+
from oscura.exporters import exporters
|
|
21
|
+
from oscura.exporters.csv import (
|
|
22
|
+
export_csv,
|
|
23
|
+
export_multi_trace_csv,
|
|
24
|
+
)
|
|
25
|
+
from oscura.exporters.hdf5 import (
|
|
26
|
+
append_trace,
|
|
27
|
+
export_hdf5,
|
|
28
|
+
export_measurement_results,
|
|
29
|
+
)
|
|
30
|
+
from oscura.exporters.html_export import (
|
|
31
|
+
export_html,
|
|
32
|
+
generate_html_report,
|
|
33
|
+
)
|
|
34
|
+
from oscura.exporters.json_export import (
|
|
35
|
+
TraceKitJSONEncoder,
|
|
36
|
+
export_json,
|
|
37
|
+
export_measurements,
|
|
38
|
+
export_protocol_decode,
|
|
39
|
+
load_json,
|
|
40
|
+
)
|
|
41
|
+
from oscura.exporters.markdown_export import (
|
|
42
|
+
export_markdown,
|
|
43
|
+
generate_markdown_report,
|
|
44
|
+
)
|
|
45
|
+
from oscura.exporters.matlab_export import (
|
|
46
|
+
export_mat,
|
|
47
|
+
export_multi_trace_mat,
|
|
48
|
+
)
|
|
49
|
+
from oscura.exporters.npz_export import (
|
|
50
|
+
export_npz,
|
|
51
|
+
load_npz,
|
|
52
|
+
)
|
|
53
|
+
from oscura.exporters.spice_export import (
|
|
54
|
+
export_pwl,
|
|
55
|
+
export_pwl_multi,
|
|
56
|
+
generate_spice_source,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"TraceKitJSONEncoder",
|
|
61
|
+
"append_trace",
|
|
62
|
+
# CSV export (EXP-001)
|
|
63
|
+
"export_csv",
|
|
64
|
+
# HDF5 export (EXP-002)
|
|
65
|
+
"export_hdf5",
|
|
66
|
+
# HTML export (EXP-007)
|
|
67
|
+
"export_html",
|
|
68
|
+
# JSON export (EXP-003)
|
|
69
|
+
"export_json",
|
|
70
|
+
# Markdown export (EXP-006)
|
|
71
|
+
"export_markdown",
|
|
72
|
+
# MATLAB export (EXP-008)
|
|
73
|
+
"export_mat",
|
|
74
|
+
"export_measurement_results",
|
|
75
|
+
"export_measurements",
|
|
76
|
+
"export_multi_trace_csv",
|
|
77
|
+
"export_multi_trace_mat",
|
|
78
|
+
# NPZ export (EXP-004)
|
|
79
|
+
"export_npz",
|
|
80
|
+
"export_protocol_decode",
|
|
81
|
+
# SPICE PWL export (EXP-005)
|
|
82
|
+
"export_pwl",
|
|
83
|
+
"export_pwl_multi",
|
|
84
|
+
"exporters",
|
|
85
|
+
# HTML report generation
|
|
86
|
+
"generate_html_report",
|
|
87
|
+
# Markdown report generation
|
|
88
|
+
"generate_markdown_report",
|
|
89
|
+
# SPICE source generation
|
|
90
|
+
"generate_spice_source",
|
|
91
|
+
"load_json",
|
|
92
|
+
# NPZ loading
|
|
93
|
+
"load_npz",
|
|
94
|
+
]
|