Skip to content

unpythonic 2.2.0 — "Hail Eris"

Latest

Choose a tag to compare

@Technologicat Technologicat released this 12 May 13:47
· 1 commit to master since this release

Two new dialects, esoteric and qualitatively different.

The dialects

  • unpythonic.dialects.bf — Brainfuck as a dialect. Source-to-source transpiler with legible Python output (bf.compile(src) returns the generated code as a string for inspection). 8-bit wrapping tape via defaultdict[int, int]; bf source comments preserved as Python comments; reset line clears the tape between programs.
  • unpythonic.dialects.befunge — Befunge-93 as a dialect. Runtime interpreter for a strict 80×25 toroidal playfield with byte cells and an unbounded-int stack. All Befunge-93 commands supported, including ? (random direction; seedable via run(src, *, seed=...) for tests), p/g (self-modifying code), and &/~ (integer/character input). The bf/befunge pair demonstrates mcpyrate's Dialect.transform_source hook in two qualitatively different modes: dialect-as-transpiler (bf) and dialect-as-reader (befunge — Befunge's 2D self-modifying control flow has no statically-soundable structure).

Other new

  • expect[] — new expr macro for declaring the tested expression inside with test:. Replaces return expr, which still works but emits a DeprecationWarning and will be un-hijacked in 3.0.0 so return regains its standard Python meaning inside with test:.
  • unpythonic.excutil.withfwith as a function. Expression form completing the raisef/tryf/withf suite. Single CM or tuple; body arity auto-detected.
  • @multishot, myield, myield_from, MultishotIterator — multi-shot generators. A @multishot function is generator-shaped but every myield captures the execution state as a continuation, so it can be resumed from any earlier myield arbitrarily many times. MultishotIterator exposes a subset of the standard generator protocol plus copy.copy(mi) forking. Only meaningful inside with continuations:. Closes #80.
  • Values unpacking in unpythonic.funutil.call and callwith. Each Values in positional args expands in place (left-to-right), splicing rets into positional args and merging kwrets into kwargs. Mirrors Python's [*a, *b, c] / {**a, **b} semantics.
  • FrozenAttributeError — compatibility shim multiply inheriting from TypeError (legacy) and dataclasses.FrozenInstanceError (stdlib convention). Raised by cons on attribute write/delete. The TypeError base will be dropped in 3.0.0.
  • redirect_stdin — context manager feeding sys.stdin from a stream. The third sibling of contextlib.redirect_stdout/stderr, which the stdlib never shipped.

Fixed

  • unpythonic.misc.callsite_filename now uses sys._getframe instead of inspect.stack(). Latent PyPy-3.11 / macOS / Windows bug: inspect.stack() raised TypeError when any frame in the walk reported f_lineno = None.
  • unpythonic.llist.cons.__delattr__ now raises FrozenAttributeError. Latent bug: del c.car previously corrupted the cell.
  • unpythonic.assignonce now forbids del e.foo on a defined name. Latent bug: the assign-once contract could be bypassed via del; rebind.

Changed

  • lispython, listhell, pytkell dialects propagate the Python 3.8+ source-location fields end_lineno / end_col_offset through splice_dialect alongside lineno / col_offset. Tooling that consumes precise source ranges (debuggers, PEP 657 traceback formatters) gets richer information. Closes #83.
  • Requires mcpyrate >= 4.2.0.

Docs

  • doc/macros.md: new "Topology of continuations" and "Scoping of locals in continuations" subsections. Closes #82.

Milestone 2.2.0 complete. Closes #35, #76, #80, #82, #83, #85 (step 1; step 2 milestoned to 3.0.0), #86.