Below is a complete example script that defines both parse_math_expression and a spell_out_sympy_expression function. The latter traverses the resulting SymPy expression tree and produces a human‑readable string. All functions are defined in the same block so you won’t encounter the NameError you saw previously.


import logging
from latex2sympy import latex2sympy
from sympy import (Add, Mul, Pow, Symbol, Number, Rational, Expr, Function,
                   sin, cos, tan, exp, log)

# Configure logging if desired (optional)
if not logging.getLogger().handlers:
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s - %(levelname)s - %(message)s')

def parse_math_expression(latex_math_string):
    """
    Parses a LaTeX mathematical string into a SymPy expression.
    Returns a SymPy expression object or None if parsing fails.
    """
    if not isinstance(latex_math_string, str) or not latex_math_string.strip():
        logging.warning("Received invalid or empty input for parsing.")
        return None
    try:
        sympy_expr = latex2sympy(latex_math_string)
        return sympy_expr
    except Exception as e:
        logging.error(f"Error during parsing: {e}")
        return None

def spell_out_sympy_expression(expr: Expr) -> str:
    """
    Recursively converts a SymPy expression into a spelled‑out string.
    Handles basic arithmetic operations, powers, functions, symbols, and numbers.
    """
    # Numbers and rationals
    if isinstance(expr, Number):
        return str(expr)
    if isinstance(expr, Rational):
        return f"{expr.p}/{expr.q}"

    # Variables / symbols
    if isinstance(expr, Symbol):
        return str(expr)

    # Addition
    if isinstance(expr, Add):
        parts = [spell_out_sympy_expression(arg) for arg in expr.args]
        return " plus ".join(parts)

    # Multiplication
    if isinstance(expr, Mul):
        # separate negative sign if present
        sign = ""
        if expr.as_coeff_Mul()[0] == -1:
            sign = "negative "
            args = expr.as_coeff_Mul()[1].args
        else:
            args = expr.args
        parts = [spell_out_sympy_expression(arg) for arg in args]
        return sign + " times ".join(parts)

    # Powers
    if isinstance(expr, Pow):
        base, exponent = expr.as_base_exp()
        return f"{spell_out_sympy_expression(base)} to the power of {spell_out_sympy_expression(exponent)}"

    # Basic functions (extend as needed)
    if isinstance(expr, Function):
        if expr.func == sin:
            return f"sine of {spell_out_sympy_expression(expr.args[0])}"
        if expr.func == cos:
            return f"cosine of {spell_out_sympy_expression(expr.args[0])}"
        if expr.func == tan:
            return f"tangent of {spell_out_sympy_expression(expr.args[0])}"
        if expr.func == exp:
            return f"exponential of {spell_out_sympy_expression(expr.args[0])}"
        if expr.func == log:
            return f"logarithm of {spell_out_sympy_expression(expr.args[0])}"
        # generic fall‑back
        return f"{expr.func.__name__} of {', '.join(spell_out_sympy_expression(a) for a in expr.args)}"

    # Fallback for unhandled expression types
    return str(expr)

# --- Demonstration ---

examples = [
    r"E = mc^2",
    r"\int_{0}^{\infty} e^{-x^2}\,dx",
    r"\frac{-b \pm \sqrt{b^2-4ac}}{2a}",
    r"a^2 + b^2",       # simple polynomial
    r"-3xy^2",          # negative coefficient and product
    r"\sin(\theta) + \cos(\theta)"  # trigonometric functions
]

for i, latex_input in enumerate(examples, start=1):
    sympy_expr = parse_math_expression(latex_input)
    if sympy_expr is not None:
        print(f"\nExample {i}: {latex_input}")
        print("SymPy expression:", sympy_expr)
        spelled = spell_out_sympy_expression(sympy_expr)
        print("Spelled out:", spelled)
    else:
        print(f"\nExample {i}: {latex_input}")
        print("Parsing failed.")

This script does the following:

  1. Defines parse_math_expression – converts a LaTeX string into a SymPy expression using latex2sympy.
  2. Defines spell_out_sympy_expression – traverses the SymPy expression tree and converts it into a plain‑language string, handling numbers, symbols, sums, products, powers, and some common functions (sine, cosine, etc.).
  3. Provides demonstration examples showing how the parser and spelling functions work together.

You can run this script as is to see the output for various LaTeX expressions and how they are spelled out in English. It also highlights how to extend the spell_out_sympy_expression function for additional operations or functions as needed.