Metadata-Version: 2.4
Name: expr2katex
Version: 0.1.0
Summary: Convert a Python expression string to a KaTeX string
Project-URL: Homepage, https://github.com/YOUR_USERNAME/expr2katex
Project-URL: Repository, https://github.com/YOUR_USERNAME/expr2katex
Project-URL: Issues, https://github.com/YOUR_USERNAME/expr2katex/issues
License: MIT
License-File: LICENSE
Keywords: ast,expression,katex,latex,math
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup :: LaTeX
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# expr2katex

Convert a Python expression string to a [KaTeX](https://katex.org/) string.

```python
from expr2katex import expr2katex

katex, err = expr2katex("sin(a) + (c + 3) * b")
# katex → \sin\left(a\right)+\left(c+3\right)\times b
# err   → None
```

## Features

- **Zero dependencies** — built on Python's standard `ast` module only
- **Precedence-aware parenthesisation** — reconstructs grouping from the AST structure, so `(a + b) * c` renders correctly without any string heuristics
- **KaTeX-native functions** — `sin`, `cos`, `sqrt`, `log`, etc. render with their native KaTeX commands (`\sin`, `\sqrt{x}`, …)
- **Unknown functions** fall back to `\operatorname{foo}` automatically
- **Configurable division style** — `\frac{a}{b}` or `a \div b`
- **Symbol style overrides** — control how variables and function names are rendered per symbol
- **SyntaxError highlighting** — invalid expressions return a KaTeX string with the offending token highlighted in red, designed for real-time UI previews

## Installation

```bash
pip install expr2katex
```

## Usage

### Basic

```python
from expr2katex import expr2katex

katex, err = expr2katex("sin(a) + b * c")
# \sin\left(a\right)+b\times c
```

### Division style

```python
expr2katex("a / b")                      # \frac{a}{b}  (default)
expr2katex("a / b", div_style="div")     # a \div b
```

### Power and roots

```python
expr2katex("a ** 2")          # a^{2}
expr2katex("sqrt(x)")         # \sqrt{x}
expr2katex("sqrt(x, 3)")      # \sqrt[3]{x}   (n-th root)
```

### Symbol style overrides

```python
from expr2katex import expr2katex, SymbolStyle

expr2katex("foo(x)", symbol_styles={
    "foo": SymbolStyle.TEXT,       # \text{foo}\left(x\right)
    "x":   SymbolStyle.BOLD,       # \boldsymbol{x}
})
```

| `SymbolStyle`   | Output                  | Default for  |
|-----------------|-------------------------|--------------|
| `ITALIC`        | `x`                     | variables    |
| `OPERATORNAME`  | `\operatorname{foo}`    | functions    |
| `TEXT`          | `\text{foo}`            |              |
| `BOLD`          | `\boldsymbol{x}`        |              |

### SyntaxError highlighting

When the expression is invalid, `expr2katex` returns a KaTeX string with the offending token highlighted in red — useful for real-time formula editors.

```python
katex, err = expr2katex("sin(a + (b * c")
# katex → \text{sin(a + }\textcolor{red}{\underbrace{\text{(}}}\text{b * c}
# err   → '(' was never closed
```

Choose between `underbrace` (default) and `underline`:

```python
expr2katex("sin(a + (b * c", error_style="underline")
```

### Raising on error

```python
# SyntaxError is re-raised instead of being returned
expr2katex("sin(a + (b * c", raise_on_error=True)
# SyntaxError: '(' was never closed

# All non-SyntaxError exceptions are always raised regardless of raise_on_error.
```

## API reference

```python
def expr2katex(
    expr: str,
    raise_on_error: bool = False,
    div_style: Literal["frac", "div"] = "frac",
    symbol_styles: dict[str, SymbolStyle] | None = None,
    error_style: Literal["underbrace", "underline"] = "underbrace",
) -> tuple[str, str | None]: ...
```

| Parameter       | Type                              | Default       | Description |
|-----------------|-----------------------------------|---------------|-------------|
| `expr`          | `str`                             | —             | Python expression string to convert |
| `raise_on_error`| `bool`                            | `False`       | Re-raise `SyntaxError` instead of returning highlighted KaTeX |
| `div_style`     | `"frac"` \| `"div"`              | `"frac"`      | Division rendering style |
| `symbol_styles` | `dict[str, SymbolStyle] \| None` | `None`        | Per-symbol style overrides |
| `error_style`   | `"underbrace"` \| `"underline"`  | `"underbrace"`| Error highlight decoration |

**Returns** `(katex: str, err: str | None)` — `err` is `None` on success, or `SyntaxError.msg` on failure.

## Supported operators

| Python  | KaTeX output          |
|---------|-----------------------|
| `+`     | `a+b`                 |
| `-`     | `a-b`                 |
| `*`     | `a\times b`           |
| `/`     | `\frac{a}{b}`         |
| `//`    | `\lfloor\frac{a}{b}\rfloor` |
| `%`     | `a\bmod b`            |
| `**`    | `a^{b}`               |
| `-x`    | `-x`                  |
| `+x`    | `x` (omitted)         |

## KaTeX-native functions

The following function names are rendered with their native KaTeX command (`\sin`, `\cos`, …). All other names fall back to `\operatorname{name}`.

`sin` `cos` `tan` `arcsin` `arccos` `arctan` `sinh` `cosh` `tanh` `log` `ln` `exp` `min` `max` `gcd` `lcm` `det` `dim` `sqrt`

`sqrt` uses the dedicated `\sqrt{x}` template. Pass a second argument for n-th roots: `sqrt(x, n)` → `\sqrt[n]{x}`.

## License

MIT