oscura 0.1.2__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. oscura/__init__.py +1 -1
  2. oscura/analyzers/packet/payload_extraction.py +2 -4
  3. oscura/analyzers/packet/stream.py +5 -5
  4. oscura/analyzers/patterns/__init__.py +4 -3
  5. oscura/analyzers/patterns/clustering.py +3 -1
  6. oscura/analyzers/power/ac_power.py +0 -2
  7. oscura/analyzers/power/basic.py +0 -2
  8. oscura/analyzers/power/ripple.py +0 -2
  9. oscura/analyzers/signal_integrity/embedding.py +0 -2
  10. oscura/analyzers/signal_integrity/sparams.py +28 -206
  11. oscura/analyzers/spectral/fft.py +0 -2
  12. oscura/analyzers/statistical/__init__.py +3 -3
  13. oscura/analyzers/statistical/checksum.py +2 -0
  14. oscura/analyzers/statistical/classification.py +2 -0
  15. oscura/analyzers/statistical/entropy.py +11 -9
  16. oscura/analyzers/statistical/ngrams.py +4 -2
  17. oscura/api/fluent.py +2 -2
  18. oscura/automotive/__init__.py +1 -3
  19. oscura/automotive/can/__init__.py +0 -2
  20. oscura/automotive/dbc/__init__.py +0 -2
  21. oscura/automotive/dtc/__init__.py +0 -2
  22. oscura/automotive/dtc/data.json +2763 -0
  23. oscura/automotive/dtc/database.py +37 -2769
  24. oscura/automotive/j1939/__init__.py +0 -2
  25. oscura/automotive/loaders/__init__.py +0 -2
  26. oscura/automotive/loaders/asc.py +0 -2
  27. oscura/automotive/loaders/blf.py +0 -2
  28. oscura/automotive/loaders/csv_can.py +0 -2
  29. oscura/automotive/obd/__init__.py +0 -2
  30. oscura/automotive/uds/__init__.py +0 -2
  31. oscura/automotive/uds/models.py +0 -2
  32. oscura/cli/main.py +0 -2
  33. oscura/cli/shell.py +0 -2
  34. oscura/config/loader.py +0 -2
  35. oscura/core/backend_selector.py +1 -1
  36. oscura/core/correlation.py +0 -2
  37. oscura/core/exceptions.py +56 -2
  38. oscura/core/lazy.py +5 -3
  39. oscura/core/memory_limits.py +0 -2
  40. oscura/core/numba_backend.py +5 -7
  41. oscura/core/uncertainty.py +3 -3
  42. oscura/dsl/interpreter.py +2 -0
  43. oscura/dsl/parser.py +8 -6
  44. oscura/exploratory/error_recovery.py +3 -3
  45. oscura/exploratory/parse.py +2 -0
  46. oscura/exploratory/recovery.py +2 -0
  47. oscura/exploratory/sync.py +2 -0
  48. oscura/export/wireshark/generator.py +1 -1
  49. oscura/export/wireshark/type_mapping.py +2 -0
  50. oscura/exporters/hdf5.py +1 -3
  51. oscura/extensibility/templates.py +0 -8
  52. oscura/inference/active_learning/lstar.py +2 -4
  53. oscura/inference/active_learning/observation_table.py +0 -2
  54. oscura/inference/active_learning/oracle.py +3 -1
  55. oscura/inference/active_learning/teachers/simulator.py +1 -3
  56. oscura/inference/alignment.py +2 -0
  57. oscura/inference/message_format.py +2 -0
  58. oscura/inference/protocol_dsl.py +7 -5
  59. oscura/inference/sequences.py +12 -14
  60. oscura/inference/state_machine.py +2 -0
  61. oscura/integrations/llm.py +3 -1
  62. oscura/jupyter/display.py +0 -2
  63. oscura/loaders/__init__.py +67 -51
  64. oscura/loaders/pcap.py +1 -1
  65. oscura/loaders/touchstone.py +221 -0
  66. oscura/math/arithmetic.py +0 -2
  67. oscura/optimization/parallel.py +9 -6
  68. oscura/pipeline/composition.py +0 -2
  69. oscura/plugins/cli.py +0 -2
  70. oscura/reporting/comparison.py +0 -2
  71. oscura/reporting/config.py +1 -1
  72. oscura/reporting/formatting/emphasis.py +2 -0
  73. oscura/reporting/formatting/numbers.py +0 -2
  74. oscura/reporting/output.py +1 -3
  75. oscura/reporting/sections.py +0 -2
  76. oscura/search/anomaly.py +2 -0
  77. oscura/session/session.py +80 -13
  78. oscura/testing/synthetic.py +2 -0
  79. oscura/ui/formatters.py +4 -2
  80. oscura/utils/buffer.py +2 -2
  81. oscura/utils/lazy.py +5 -5
  82. oscura/utils/memory_advanced.py +2 -2
  83. oscura/utils/memory_extensions.py +2 -2
  84. oscura/visualization/colors.py +0 -2
  85. oscura/visualization/power.py +2 -0
  86. oscura/workflows/multi_trace.py +2 -0
  87. {oscura-0.1.2.dist-info → oscura-0.3.0.dist-info}/METADATA +37 -16
  88. {oscura-0.1.2.dist-info → oscura-0.3.0.dist-info}/RECORD +91 -89
  89. {oscura-0.1.2.dist-info → oscura-0.3.0.dist-info}/WHEEL +0 -0
  90. {oscura-0.1.2.dist-info → oscura-0.3.0.dist-info}/entry_points.txt +0 -0
  91. {oscura-0.1.2.dist-info → oscura-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -4,8 +4,6 @@ This module provides J1939 protocol decoding for heavy-duty vehicles
4
4
  (trucks, buses, agriculture, marine).
5
5
  """
6
6
 
7
- from __future__ import annotations
8
-
9
7
  __all__ = ["J1939Decoder", "J1939Message", "extract_pgn"]
10
8
 
11
9
  try:
@@ -8,8 +8,6 @@ This module provides loaders for common automotive logging file formats:
8
8
  - PCAP (Packet Capture - SocketCAN)
9
9
  """
10
10
 
11
- from __future__ import annotations
12
-
13
11
  __all__ = [
14
12
  "detect_format",
15
13
  "load_asc",
@@ -9,8 +9,6 @@ ASC format example:
9
9
  0.010000 1 280 Rx d 8 0A 0B 0C 0D 0E 0F 10 11
10
10
  """
11
11
 
12
- from __future__ import annotations
13
-
14
12
  import re
15
13
  from pathlib import Path
16
14
 
@@ -5,8 +5,6 @@ BLF is a proprietary binary format used by Vector tools (CANoe, CANalyzer, etc.)
5
5
  for logging CAN bus data.
6
6
  """
7
7
 
8
- from __future__ import annotations
9
-
10
8
  from pathlib import Path
11
9
 
12
10
  from oscura.automotive.can.models import CANMessage, CANMessageList
@@ -9,8 +9,6 @@ Common CSV format:
9
9
  0.010000,0x280,0A0B0C0D0E0F1011
10
10
  """
11
11
 
12
- from __future__ import annotations
13
-
14
12
  import csv
15
13
  from pathlib import Path
16
14
 
@@ -4,8 +4,6 @@ This module provides OBD-II (On-Board Diagnostics) protocol decoding
4
4
  for standard vehicle diagnostics.
5
5
  """
6
6
 
7
- from __future__ import annotations
8
-
9
7
  __all__ = ["PID", "OBD2Decoder", "OBD2Response"]
10
8
 
11
9
  try:
@@ -36,8 +36,6 @@ Example:
36
36
  UDSService(0x10 DiagnosticSessionControl [Request], sub=0x01)
37
37
  """
38
38
 
39
- from __future__ import annotations
40
-
41
39
  __all__ = [
42
40
  "UDSDecoder",
43
41
  "UDSNegativeResponse",
@@ -3,8 +3,6 @@
3
3
  This module defines the core data structures for UDS protocol analysis.
4
4
  """
5
5
 
6
- from __future__ import annotations
7
-
8
6
  from dataclasses import dataclass
9
7
 
10
8
  __all__ = [
oscura/cli/main.py CHANGED
@@ -11,8 +11,6 @@ Example:
11
11
  $ oscura shell # Interactive REPL
12
12
  """
13
13
 
14
- from __future__ import annotations
15
-
16
14
  import json
17
15
  import logging
18
16
  import sys
oscura/cli/shell.py CHANGED
@@ -23,8 +23,6 @@ References:
23
23
  - IPython-style interaction patterns
24
24
  """
25
25
 
26
- from __future__ import annotations
27
-
28
26
  import atexit
29
27
  import code
30
28
  import contextlib
oscura/config/loader.py CHANGED
@@ -9,8 +9,6 @@ Example:
9
9
  >>> config = load_config_file("pipeline.yaml", schema="pipeline")
10
10
  """
11
11
 
12
- from __future__ import annotations
13
-
14
12
  import json
15
13
  from pathlib import Path
16
14
  from typing import Any
@@ -43,7 +43,7 @@ except (ImportError, AttributeError):
43
43
  HAS_GPU = False
44
44
 
45
45
  try:
46
- import numba # type: ignore[import-untyped]
46
+ import numba # type: ignore[import-not-found]
47
47
 
48
48
  HAS_NUMBA = True
49
49
  del numba
@@ -16,8 +16,6 @@ References:
16
16
  - Thread-local and async-safe context management
17
17
  """
18
18
 
19
- from __future__ import annotations
20
-
21
19
  import asyncio
22
20
  import contextvars
23
21
  import functools
oscura/core/exceptions.py CHANGED
@@ -13,8 +13,6 @@ Example:
13
13
  ...
14
14
  """
15
15
 
16
- from __future__ import annotations
17
-
18
16
  from typing import Any
19
17
 
20
18
  # Documentation base URL
@@ -520,6 +518,61 @@ class ExportError(OscuraError):
520
518
  )
521
519
 
522
520
 
521
+ class SecurityError(OscuraError):
522
+ """Security validation failed.
523
+
524
+ Raised when security checks fail, such as signature verification
525
+ or file integrity validation.
526
+
527
+ Attributes:
528
+ file_path: Path to the file that failed security checks.
529
+ check_type: Type of security check that failed.
530
+ """
531
+
532
+ docs_path: str = "errors#security"
533
+
534
+ def __init__(
535
+ self,
536
+ message: str,
537
+ *,
538
+ file_path: str | None = None,
539
+ check_type: str | None = None,
540
+ details: str | None = None,
541
+ fix_hint: str | None = None,
542
+ ) -> None:
543
+ """Initialize SecurityError.
544
+
545
+ Args:
546
+ message: Brief description of the error.
547
+ file_path: Path to the file that failed security checks.
548
+ check_type: Type of security check that failed.
549
+ details: Additional context about the error.
550
+ fix_hint: Suggestion for how to fix the error.
551
+ """
552
+ self.file_path = file_path
553
+ self.check_type = check_type
554
+
555
+ details_parts = []
556
+ if file_path:
557
+ details_parts.append(f"File: {file_path}")
558
+ if check_type:
559
+ details_parts.append(f"Check: {check_type}")
560
+ if details:
561
+ details_parts.append(details)
562
+
563
+ combined_details = ". ".join(details_parts) if details_parts else None
564
+
565
+ if fix_hint is None:
566
+ fix_hint = "Only load files from trusted sources. File may be corrupted or tampered."
567
+
568
+ super().__init__(
569
+ message,
570
+ details=combined_details,
571
+ fix_hint=fix_hint,
572
+ docs_path=self.docs_path,
573
+ )
574
+
575
+
523
576
  __all__ = [
524
577
  "DOCS_BASE_URL",
525
578
  "AnalysisError",
@@ -530,6 +583,7 @@ __all__ = [
530
583
  "LoaderError",
531
584
  "OscuraError",
532
585
  "SampleRateError",
586
+ "SecurityError",
533
587
  "UnsupportedFormatError",
534
588
  "ValidationError",
535
589
  ]
oscura/core/lazy.py CHANGED
@@ -49,7 +49,9 @@ from __future__ import annotations
49
49
  import functools
50
50
  import threading
51
51
  from dataclasses import dataclass
52
- from typing import TYPE_CHECKING, Any
52
+ from typing import TYPE_CHECKING, Any, Generic, TypeVar
53
+
54
+ T = TypeVar("T")
53
55
 
54
56
  if TYPE_CHECKING:
55
57
  from collections.abc import Callable
@@ -149,7 +151,7 @@ def reset_lazy_stats() -> None:
149
151
  _global_stats = LazyComputeStats()
150
152
 
151
153
 
152
- class LazyResult[T]:
154
+ class LazyResult(Generic[T]):
153
155
  """Deferred computation wrapper with thread-safe compute-once semantics.
154
156
 
155
157
  Wraps a computation function that will be called only when the result is
@@ -557,7 +559,7 @@ class LazyDict(dict[str, Any]):
557
559
  ]
558
560
 
559
561
 
560
- def lazy[T](fn: Callable[..., T]) -> Callable[..., LazyResult[T]]:
562
+ def lazy(fn: Callable[..., T]) -> Callable[..., LazyResult[T]]:
561
563
  """Decorator to make a function return a LazyResult.
562
564
 
563
565
  Wraps a function so it returns a LazyResult instead of computing
@@ -13,8 +13,6 @@ References:
13
13
  See oscura.config.memory for global memory configuration.
14
14
  """
15
15
 
16
- from __future__ import annotations
17
-
18
16
  import warnings
19
17
  from typing import Any
20
18
 
@@ -35,8 +35,6 @@ Example:
35
35
  >>> result = sum_of_squares(data) # Fast on second call
36
36
  """
37
37
 
38
- from __future__ import annotations
39
-
40
38
  import functools
41
39
  from collections.abc import Callable
42
40
  from typing import Any, TypeVar
@@ -45,11 +43,11 @@ import numpy as np
45
43
 
46
44
  # Try to import Numba
47
45
  try:
48
- from numba import guvectorize as _numba_guvectorize # type: ignore[import-untyped]
49
- from numba import jit as _numba_jit # type: ignore[import-untyped]
50
- from numba import njit as _numba_njit # type: ignore[import-untyped]
51
- from numba import prange as _numba_prange # type: ignore[import-untyped]
52
- from numba import vectorize as _numba_vectorize # type: ignore[import-untyped]
46
+ from numba import guvectorize as _numba_guvectorize # type: ignore[import-not-found]
47
+ from numba import jit as _numba_jit # type: ignore[import-not-found]
48
+ from numba import njit as _numba_njit # type: ignore[import-not-found]
49
+ from numba import prange as _numba_prange # type: ignore[import-not-found]
50
+ from numba import vectorize as _numba_vectorize # type: ignore[import-not-found]
53
51
 
54
52
  HAS_NUMBA = True
55
53
  except ImportError:
@@ -108,7 +108,7 @@ class MeasurementWithUncertainty:
108
108
  JCGM 100:2008 Section 5.1.6
109
109
  """
110
110
  if self.value == 0:
111
- return np.inf
111
+ return float(np.inf) # type: ignore[no-any-return]
112
112
  return abs(self.uncertainty / self.value)
113
113
 
114
114
  @property
@@ -173,7 +173,7 @@ class UncertaintyEstimator:
173
173
  JCGM 100:2008 Section 4.2 (Type A evaluation)
174
174
  """
175
175
  if len(data) < 2:
176
- return np.nan
176
+ return float(np.nan) # type: ignore[no-any-return]
177
177
  return float(np.std(data, ddof=1)) # Sample std (Bessel correction)
178
178
 
179
179
  @staticmethod
@@ -190,7 +190,7 @@ class UncertaintyEstimator:
190
190
  JCGM 100:2008 Section 4.2.3
191
191
  """
192
192
  if len(data) < 2:
193
- return np.nan
193
+ return float(np.nan) # type: ignore[no-any-return]
194
194
  return float(np.std(data, ddof=1) / np.sqrt(len(data)))
195
195
 
196
196
  @staticmethod
oscura/dsl/interpreter.py CHANGED
@@ -3,6 +3,8 @@
3
3
  Executes parsed DSL programs.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  from collections.abc import Callable
7
9
  from pathlib import Path
8
10
  from typing import Any
oscura/dsl/parser.py CHANGED
@@ -3,6 +3,8 @@
3
3
  Implements simple domain-specific language for trace analysis workflows.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  from dataclasses import dataclass
7
9
  from enum import Enum, auto
8
10
  from typing import Any, Union
@@ -352,14 +354,14 @@ class Assignment(ASTNode):
352
354
  """Variable assignment: $var = expr."""
353
355
 
354
356
  variable: str
355
- expression: "Expression"
357
+ expression: Expression
356
358
 
357
359
 
358
360
  @dataclass
359
361
  class Pipeline(ASTNode):
360
362
  """Pipeline expression: expr | command | command."""
361
363
 
362
- stages: list["Expression"]
364
+ stages: list[Expression]
363
365
 
364
366
 
365
367
  @dataclass
@@ -367,7 +369,7 @@ class Command(ASTNode):
367
369
  """Command invocation: command arg1 arg2."""
368
370
 
369
371
  name: str
370
- args: list["Expression"]
372
+ args: list[Expression]
371
373
 
372
374
 
373
375
  @dataclass
@@ -375,7 +377,7 @@ class FunctionCall(ASTNode):
375
377
  """Function call: func(arg1, arg2)."""
376
378
 
377
379
  name: str
378
- args: list["Expression"]
380
+ args: list[Expression]
379
381
 
380
382
 
381
383
  @dataclass
@@ -397,8 +399,8 @@ class ForLoop(ASTNode):
397
399
  """For loop: for $var in expr: body."""
398
400
 
399
401
  variable: str
400
- iterable: "Expression"
401
- body: list["Statement"]
402
+ iterable: Expression
403
+ body: list[Statement]
402
404
 
403
405
 
404
406
  # Type aliases
@@ -20,6 +20,8 @@ import numpy as np
20
20
 
21
21
  from oscura.core.types import WaveformTrace
22
22
 
23
+ T = TypeVar("T")
24
+
23
25
  logger = logging.getLogger(__name__)
24
26
 
25
27
  if TYPE_CHECKING:
@@ -27,8 +29,6 @@ if TYPE_CHECKING:
27
29
 
28
30
  from numpy.typing import NDArray
29
31
 
30
- T = TypeVar("T")
31
-
32
32
 
33
33
  @dataclass
34
34
  class RecoveryStats:
@@ -547,7 +547,7 @@ class RetryResult:
547
547
  adjustments_made: list[str]
548
548
 
549
549
 
550
- def retry_with_adjustment[T](
550
+ def retry_with_adjustment(
551
551
  func: Callable[..., T],
552
552
  trace: WaveformTrace,
553
553
  initial_params: dict[str, Any],
@@ -5,6 +5,8 @@ This module provides robust protocol decoding that continues after errors
5
5
  and timestamp correction for jittery captures.
6
6
  """
7
7
 
8
+ from __future__ import annotations
9
+
8
10
  from dataclasses import dataclass
9
11
  from enum import Enum
10
12
  from typing import Any, Literal
@@ -5,6 +5,8 @@ This module characterizes bit error patterns to diagnose capture quality
5
5
  issues (EMI, USB problems, clock jitter) and suggests likely causes.
6
6
  """
7
7
 
8
+ from __future__ import annotations
9
+
8
10
  from dataclasses import dataclass
9
11
  from enum import Enum
10
12
 
@@ -6,6 +6,8 @@ in noisy or corrupted logic analyzer captures, with configurable bit error
6
6
  tolerance using Hamming distance.
7
7
  """
8
8
 
9
+ from __future__ import annotations
10
+
9
11
  from dataclasses import dataclass
10
12
  from enum import Enum
11
13
  from typing import Literal
@@ -106,7 +106,7 @@ class WiresharkDissectorGenerator:
106
106
 
107
107
  # Render template
108
108
  template = self.env.get_template("dissector.lua.j2")
109
- return template.render(**context)
109
+ return str(template.render(**context)) # type: ignore[no-any-return]
110
110
 
111
111
  def _build_template_context(self, protocol: ProtocolDefinition) -> dict[str, Any]:
112
112
  """Build context dictionary for template rendering.
@@ -7,6 +7,8 @@ References:
7
7
  https://wiki.wireshark.org/LuaAPI/Proto
8
8
  """
9
9
 
10
+ from __future__ import annotations
11
+
10
12
  from typing import Literal
11
13
 
12
14
  # Map Oscura field types to Wireshark ProtoField types
oscura/exporters/hdf5.py CHANGED
@@ -11,8 +11,6 @@ References:
11
11
  HDF5 specification (https://www.hdfgroup.org/)
12
12
  """
13
13
 
14
- from __future__ import annotations
15
-
16
14
  from datetime import datetime
17
15
  from pathlib import Path
18
16
  from typing import Any
@@ -81,7 +79,7 @@ def export_hdf5(
81
79
 
82
80
 
83
81
  def _write_trace_dataset(
84
- f: h5py.File,
82
+ f: "h5py.File",
85
83
  name: str,
86
84
  trace: WaveformTrace | DigitalTrace,
87
85
  compression: str | None,
@@ -622,8 +622,6 @@ def _generate_analyzer_stub(template: PluginTemplate, class_name: str) -> str:
622
622
  References:
623
623
  PLUG-008: Plugin Template Generator
624
624
  """
625
- from __future__ import annotations
626
-
627
625
  import numpy as np
628
626
  from numpy.typing import NDArray
629
627
 
@@ -697,8 +695,6 @@ def _generate_loader_stub(template: PluginTemplate, class_name: str) -> str:
697
695
  References:
698
696
  PLUG-008: Plugin Template Generator
699
697
  """
700
- from __future__ import annotations
701
-
702
698
  import numpy as np
703
699
  from numpy.typing import NDArray
704
700
  from pathlib import Path
@@ -782,8 +778,6 @@ def _generate_exporter_stub(template: PluginTemplate, class_name: str) -> str:
782
778
  References:
783
779
  PLUG-008: Plugin Template Generator
784
780
  """
785
- from __future__ import annotations
786
-
787
781
  import numpy as np
788
782
  from numpy.typing import NDArray
789
783
  from pathlib import Path
@@ -871,8 +865,6 @@ def _generate_generic_stub(template: PluginTemplate, class_name: str) -> str:
871
865
  References:
872
866
  PLUG-008: Plugin Template Generator
873
867
  """
874
- from __future__ import annotations
875
-
876
868
 
877
869
  class {class_name}:
878
870
  """Generic plugin implementation.
@@ -26,11 +26,9 @@ Complexity:
26
26
  - Produces minimal DFA (fewest states)
27
27
  """
28
28
 
29
- from __future__ import annotations
30
-
31
29
  from oscura.inference.active_learning.observation_table import ObservationTable
32
- from oscura.inference.active_learning.oracle import Oracle # noqa: TC001
33
- from oscura.inference.state_machine import FiniteAutomaton # noqa: TC001
30
+ from oscura.inference.active_learning.oracle import Oracle
31
+ from oscura.inference.state_machine import FiniteAutomaton
34
32
 
35
33
 
36
34
  class LStarLearner:
@@ -8,8 +8,6 @@ References:
8
8
  Information and Computation, 75(2), 87-106.
9
9
  """
10
10
 
11
- from __future__ import annotations
12
-
13
11
  from dataclasses import dataclass, field
14
12
 
15
13
  from oscura.inference.state_machine import FiniteAutomaton, State, Transition
@@ -11,8 +11,10 @@ References:
11
11
  from __future__ import annotations
12
12
 
13
13
  from abc import ABC, abstractmethod
14
+ from typing import TYPE_CHECKING
14
15
 
15
- from oscura.inference.state_machine import FiniteAutomaton # noqa: TC001
16
+ if TYPE_CHECKING:
17
+ from oscura.inference.state_machine import FiniteAutomaton
16
18
 
17
19
 
18
20
  class Oracle(ABC):
@@ -7,10 +7,8 @@ requiring a live system.
7
7
  The simulator teacher treats traces as examples of valid protocol sequences.
8
8
  """
9
9
 
10
- from __future__ import annotations
11
-
12
10
  from oscura.inference.active_learning.oracle import Oracle
13
- from oscura.inference.state_machine import FiniteAutomaton # noqa: TC001
11
+ from oscura.inference.state_machine import FiniteAutomaton
14
12
 
15
13
 
16
14
  class SimulatorTeacher(Oracle):
@@ -12,6 +12,8 @@ Key capabilities:
12
12
  - Conserved/variable region detection
13
13
  """
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  from dataclasses import dataclass
16
18
  from typing import Any, Literal
17
19
 
@@ -18,6 +18,8 @@ References:
18
18
  Discoverer: Automatic Protocol Reverse Engineering. USENIX Security 2007.
19
19
  """
20
20
 
21
+ from __future__ import annotations
22
+
21
23
  from dataclasses import dataclass
22
24
  from dataclasses import field as dataclass_field
23
25
  from typing import Any, Literal
@@ -13,6 +13,8 @@ Key capabilities:
13
13
  - Comprehensive error reporting
14
14
  """
15
15
 
16
+ from __future__ import annotations
17
+
16
18
  import ast
17
19
  import operator
18
20
  import struct
@@ -68,7 +70,7 @@ class FieldDefinition:
68
70
  element: dict[str, Any] | None = None # Element definition for arrays
69
71
  count_field: str | None = None # Field containing array count
70
72
  count: int | None = None # Fixed array count
71
- fields: list["FieldDefinition"] | None = None # Nested fields for struct type
73
+ fields: list[FieldDefinition] | None = None # Nested fields for struct type
72
74
 
73
75
  def __post_init__(self) -> None:
74
76
  """Handle size_ref as alias for size."""
@@ -117,7 +119,7 @@ class ProtocolDefinition:
117
119
  encoding: dict[str, Any] = field(default_factory=dict)
118
120
 
119
121
  @classmethod
120
- def from_yaml(cls, path: str | Path) -> "ProtocolDefinition":
122
+ def from_yaml(cls, path: str | Path) -> ProtocolDefinition:
121
123
  """Load protocol definition from YAML file.
122
124
 
123
125
  : YAML parsing.
@@ -134,7 +136,7 @@ class ProtocolDefinition:
134
136
  return cls.from_dict(config)
135
137
 
136
138
  @classmethod
137
- def from_dict(cls, config: dict[str, Any]) -> "ProtocolDefinition":
139
+ def from_dict(cls, config: dict[str, Any]) -> ProtocolDefinition:
138
140
  """Create from dictionary.
139
141
 
140
142
  : Configuration parsing.
@@ -168,7 +170,7 @@ class ProtocolDefinition:
168
170
  @classmethod
169
171
  def _parse_field_definition(
170
172
  cls, field_dict: dict[str, Any], default_endian: str
171
- ) -> "FieldDefinition":
173
+ ) -> FieldDefinition:
172
174
  """Parse a single field definition from dictionary.
173
175
 
174
176
  Args:
@@ -365,7 +367,7 @@ class ProtocolDecoder:
365
367
  self._endian_map: dict[str, str] = {"big": ">", "little": "<"}
366
368
 
367
369
  @classmethod
368
- def load(cls, path: str | Path) -> "ProtocolDecoder":
370
+ def load(cls, path: str | Path) -> ProtocolDecoder:
369
371
  """Load decoder from YAML protocol definition.
370
372
 
371
373
  : Load decoder from file.