Changelog: tramaj-py
On Fri, 25 Sep 2026, by @lucasdicioccio, 683 words, 0 code snippets, 1 links, 0images.
Changelog: tramaj-py
Release history of tramaj-py, the Python implementation, standard library only. Releases happen when there are
major changes rather than on a schedule; each entry below is one version.
Every implementation has its own page like this one, and each page is
tagged so the site builds one Atom feed per implementation:
#changelog #python #tramaj-py
The 0.2.0 entry has breaking changes to numbers: Migrating to integers and floats says what to do about each.
tramaj-py 0.2.02026-10-09
Language v5: two number types, arithmetic, sorting and number formatting. On PyPI, as tramaj.
- changed Breaking: numbers are two types, an integer and a float (decisions section 18), and they are the two Python types: an `int` is an integer and a `float` a float, in the context and in the result. A literal and a JSON number are typed by their text: `3` is an integer, `3.0` and `3e0` are floats. Integers cover the signed 64-bit range; Python's own are unbounded, so one outside the range is refused and never rounded: a parse error as a literal, a `TypeMismatch` in the context, a `NotRepresentable` as a result.
- changed Breaking: a number keeps its type when written. `str(1.0)` is `1.0` where it was `1`, and `compact_json`, `pretty_json` and the CLI write a float with a fraction or an exponent. `node_from_json` rejects an integer outside the range and a float too large for a double.
- changed Breaking: `eq` never equates an integer with a float, and so neither does `json_equal`. `lt`/`lte`/`gt`/`gte` take two integers or two floats; a mixed pair is a `TypeMismatch`. An array index is an integer: `has` and `lookup` no longer take `1.0` for `1`.
- changed Breaking: `int` and `float` are type primitives and `number` is no longer one (v4-types section 1). `"$term"` is a reserved object key, next to `"$sym"` and `"$type"`. `normalize_number` and `MAX_SAFE_INTEGER` are gone from `jsonval`; `VNumber` is replaced by `VInt` and `VFloat`.
- added The arithmetic profile (reference section 11), ten builtins: `sum`, `product`, `negate`, `inverse`, `quotient`, `floor-quotient`, `modulo`, `floor`, `real` and `round`. It is an option of each evaluation, off by default: `run_program(..., arithmetic=True)`, and `--arithmetic` on the command line. Without it the ten names are unbound. `round` (decisions section 20) gives the nearest integer, ties away from zero, unlike Python's own.
- added Terms: over a symbol an arithmetic builtin builds `{"$term": op, "arguments": [...]}` with its operands as written (v3-symbols section 1.9), and a well-formed term can be seeded back in symbolic mode.
- added `arithmetic_ops` and `deep_arithmetic_ops`, the scope-aware analysis of which arithmetic names a program references free; `python -m tramaj analyze arithmetic` prints the deep one. `parse_json` reads JSON text with each number typed by its text. The `NotRepresentable` error kind.
- added The corpus runner declares `int-float`, `arithmetic`, `int64`, `sort`, `format-number` and `round`, and turns arithmetic on only for the cases that list it.
- added `sort-by(list, fn)` and `sort-by-descending(list, fn)` (decisions section 20): a stable sort by key, in every profile. The key function runs once per element, in index order; the keys of one call are all integers, all floats or all strings, and strings compare by code point.
- changed Breaking: `sort-by` and `sort-by-descending` are special-form names lowering to one new AST constructor, `ast.SortBy`. A program can no longer bind one and call it as an ordinary name, and a wrong argument count is a parse error.
- added `format-number(x, decimals, group)` (decisions section 20), an ordinary builtin of every profile: positional decimal text with 0 to 20 decimals and an optional group separator. It rounds the exact value of the number, ties away from zero, on `fractions.Fraction`, and never writes an exponent or a negative zero.
tramaj-py 0.1.02026-09-27
Python port: parser, evaluator (concrete and symbolic modes), Node JSON codec, static analyses and a python -m tramaj CLI. Standard library only, Python 3.9+.
- added Hand-written port checked against `corpus/cases` by `tests/test_corpus.py`: every case passes in both modes.
- added Object destructuring patterns in `@` bindings and lambda parameters (decisions section 17): a parser lowering to plain `Let`/`Lambda`, checked by shared corpus cases 100-118.