""" Conversion context data structure. This module defines the ConversionContext dataclass that holds all state and intermediate results throughout the conversion pipeline. """ from dataclasses import dataclass, field from typing import Optional, List, Dict, Any @dataclass class ConversionContext: """ Shared state for the conversion pipeline. This context object flows through all pipeline stages, accumulating intermediate results and maintaining conversion state. Attributes: input_type: Type of input ('docx', 'omml', 'mathml', 'stdin') subject_mode: Subject area hint ('math', 'chemistry', 'physics', 'statistics', 'auto') wrap_identifiers: Whether to wrap identifiers in \\mathrm{} (default: True) prefer_xlongequal: Use \\xlongequal for overset equals (default: True) # Intermediate results omml: OMML XML string (if applicable) mathml: MathML XML string latex: Generated LaTeX string # Validation state validation_errors: List of validation error messages validation_warnings: List of validation warning messages is_valid: Whether MathML passed validation # Color optimization state uniform_equation_color: Hex color if entire equation uses same color, else empty suppress_leaf_colors: Flag to suppress individual element colors when uniform color detected # Metadata equation_count: Number of equations processed current_equation_index: Index of current equation being processed context_hints: Additional context information # Performance metrics stage_timings: Dict mapping stage name to execution time (seconds) total_time: Total processing time (seconds) """ # Configuration input_type: str subject_mode: str = "math" wrap_identifiers: bool = True prefer_xlongequal: bool = True # Intermediate results omml: Optional[str] = None mathml: Optional[str] = None latex: Optional[str] = None # Validation results validation_errors: List[str] = field(default_factory=list) validation_warnings: List[str] = field(default_factory=list) is_valid: bool = True # Color optimization state uniform_equation_color: str = "" suppress_leaf_colors: bool = False # Script context tracking (for fraction sizing) script_context_stack: List[str] = field(default_factory=list) display_style_context: bool = False # Set theory mode (for unclosed set notation) set_theory_mode: bool = False # Chemistry equation detection (cached) is_chemistry_equation: Optional[bool] = None # Metadata equation_count: int = 0 current_equation_index: int = 0 context_hints: Dict[str, Any] = field(default_factory=dict) # Performance metrics stage_timings: Dict[str, float] = field(default_factory=dict) total_time: float = 0.0 def add_error(self, error: str) -> None: """Add a validation error.""" self.validation_errors.append(error) self.is_valid = False def add_warning(self, warning: str) -> None: """Add a validation warning.""" self.validation_warnings.append(warning) def record_stage_time(self, stage_name: str, time_seconds: float) -> None: """Record execution time for a stage.""" self.stage_timings[stage_name] = time_seconds def has_errors(self) -> bool: """Check if any errors were recorded.""" return len(self.validation_errors) > 0 def has_warnings(self) -> bool: """Check if any warnings were recorded.""" return len(self.validation_warnings) > 0 def clear_validation_state(self) -> None: """Clear validation errors and warnings.""" self.validation_errors.clear() self.validation_warnings.clear() self.is_valid = True def push_script_context(self, element_type: str) -> None: """ Push a script context (msup/msub/msubsup) onto the stack. Args: element_type: The element type entering script context """ self.script_context_stack.append(element_type) def pop_script_context(self) -> Optional[str]: """ Pop a script context from the stack. Returns: The popped element type, or None if stack was empty """ return self.script_context_stack.pop() if self.script_context_stack else None def in_script_context(self) -> bool: """Check if currently inside a script context (superscript/subscript).""" return len(self.script_context_stack) > 0 def __str__(self) -> str: """String representation for debugging.""" status = "valid" if self.is_valid else "invalid" return ( f"ConversionContext(" f"input_type={self.input_type}, " f"subject_mode={self.subject_mode}, " f"status={status}, " f"equations={self.equation_count})" ) def __repr__(self) -> str: """Detailed representation for debugging.""" return ( f"ConversionContext(\n" f" input_type={self.input_type!r},\n" f" subject_mode={self.subject_mode!r},\n" f" wrap_identifiers={self.wrap_identifiers},\n" f" prefer_xlongequal={self.prefer_xlongequal},\n" f" is_valid={self.is_valid},\n" f" equation_count={self.equation_count},\n" f" errors={len(self.validation_errors)},\n" f" warnings={len(self.validation_warnings)},\n" f" total_time={self.total_time:.4f}s\n" f")" )