asciimath2
AsciiMath2 is asciimath.org's grammar extended with everything
asciimath-parser already
implements (matrices, aligned multi-line equations, colors, fonts, accents,
...), plus two more contributions on top of that:
render-time configurability
and a symbol-table isolation contract.
The full grammar is written down in SPEC.md — read that first.
This directory is the standard plus one from-scratch implementation of one direction through it:
LaTeX --[this package]--> AsciiMath2 --[asciimath-parser]--> LaTeX
asciimath-parser already goes AsciiMath2 → LaTeX. This package goes the
other way, which nothing implemented before. Together they round-trip.
Install & use
uv sync # or: pip install -e .
uv run asciimath2 '\frac{1}{2} + \sqrt{x^2+1}'
# 1/2 + sqrt(x^2 + 1)
from asciimath2 import convert, Config, UnsupportedLatexError
convert(r"\sum_{i=1}^n i^2")
# 'sum_(i = 1)^n i^2'
convert(r"\begin{pmatrix} a & b \\ c & d \end{pmatrix}")
# '(a, b; c, d)'
try:
convert(r"\begin{tikzpicture}...\end{tikzpicture}")
except UnsupportedLatexError:
... # fall back to keeping the original LaTeX -- see "On failure" below
Config mirrors the three render options from PR #22
(multiline_env, single_newline_break, bar_as_mid — see SPEC.md §2.2);
only single_newline_break changes what this package emits.
How it works
src/asciimath2/:
latex_context.py— extendspylatexenc's macro database with argument specs for macros it doesn't know the arity of (\binom,\overset,\operatorname, ...), so pylatexenc attaches their{...}groups as real arguments instead of leaving them as unrelated sibling nodes.symbols.py— the LaTeX-command → AsciiMath2-token tables. Ground truth isasciimath-parser's ownSYMBOLMAP(packages/core/src/symbols.ts), read directly from source, not paraphrased from docs.render.py— flattens a pylatexenc node tree into a linear token stream, then does a single left-to-right pass building AsciiMath2 text.^/_bind to exactly the token before/after them; any compound expression used as a required single argument gets wrapped in(...), which AsciiMath2's own grammar strips invisibly in exactly those positions — so this converter never has to reimplement LaTeX operator precedence itself.cli.py—asciimath2 '<latex>'/ reads stdin.
Scope, honestly
This is a broad, tested common subset of LaTeX math — not a general LaTeX
interpreter (that's not a well-defined target; LaTeX can define arbitrary
macros). What's covered: arithmetic, fractions/roots, sub/superscripts,
\left/\right delimiters (all standard pairs), big operators with limits,
trig/log/etc. functions, Greek letters, relations/logic/arrows, fonts and
accents, \text, \binom/\operatorname/\pmod/\color, and matrix-like
and aligned-like environments (pmatrix/bmatrix/vmatrix/Vmatrix/
matrix/array/cases, aligned/align/gather/split/...).
Two deliberate choices about what happens outside that:
tex(...)escape hatch — an unrecognized bare macro with no arguments (e.g.\digamma) degrades totex(\digamma), AsciiMath2's own raw-LaTeX passthrough (SPEC.md §2.4), rather than failing the whole expression.- On failure, raise, don't guess — anything else unsupported (an unknown
macro that's ambiguous about whether it takes arguments, an unrecognized
environment, a
\leftwith no matching\right, ...) raisesUnsupportedLatexErrorfor the whole expression rather than silently emitting something plausible-looking but wrong. This is the same contract mark-vector's currentbackend/app/latex_to_asciimath.pyalready expects frompy-asciimath(None/exception on failure → keep the original LaTeX visible via\(...\)/\[...\]), so this package is a drop-in candidate for that integration point if/when it's wired in — see "Not yet done" below.
Integration status
Both follow-ups from the initial version of this package are now done:
- Wired into mark-vector's backend.
backend/app/latex_to_asciimath.pyuses this package (added as a local editable dependency inbackend/pyproject.toml) instead ofpy-asciimath— which is the whole reason this package exists (py-asciimathcouldn't do matrices,\\, and other constructs this package handles). Multi-row output (aligned systems, etc.) is preserved as blank-line-separated rows inside the$$...$$block it writes back to the document, rather than being collapsed to one line, so the row structure survives to the frontend. - Frontend renders AsciiMath2's extensions.
frontend/static/js/markdown.jsimportsasciimath-parserdirectly as an ES module from jsDelivr (https://cdn.jsdelivr.net/npm/asciimath-parser@<version>/dist/index.js— it ships no browser-global/UMD build, unlike theasciimath2texpackage it replaced) instead ofasciimath2tex, which only implemented the base asciimath.org grammar. For the AsciiMath dialect, a full$$...$$block is now handed to the parser in one call rather than being split line-by-line, soasciimath-parser's own row/&-alignment handling (SPEC.md §2.2) does the work instead of the frontend approximating it with agatheredenvironment. The LaTeX dialect's per-linegatheredstacking is unchanged, since LaTeX has no equivalent convention.
Verified end to end (asciimath2.convert() output fed through the actual
published asciimath-parser@0.6.11 and, in a real browser via Playwright,
through KaTeX) for derivatives/limits, matrix multiplication, aligned
systems of equations, piecewise cases, and norms — no parse errors,
correct LaTeX, correct rendering.
Metadata
Release files for asciimath2 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| asciimath2-0.1.1.tar.gz | 18.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| asciimath2-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.2 kB
Release files / asciimath2-0.1.1.tar.gz
| Download URL | asciimath2-0.1.1.tar.gz |
|---|---|
| Size | 18.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
27d451c79c9b14ae4e1bd2f90c4bb7c8638beace4b8c5de33091461c059f2ceb
|
|
BLAKE2b-256 checksum How to use checksums |
06ae70abffad42d6995010c263071f2f71fdd9f30b7caacf89f41a64d6d04e33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / asciimath2-0.1.1-py3-none-any.whl
| Download URL | asciimath2-0.1.1-py3-none-any.whl |
|---|---|
| Size | 21.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
968578340e3a96e775e78acf73bd9b129eb41e8ed04c28c9a6e4d3d72e9392cb
|
|
BLAKE2b-256 checksum How to use checksums |
a248273f21aebd202a6889f62705cfab56e8ece32488bd7b09043b3c0a47936a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for asciimath2 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.