Skip to main content

as

One Python, three syntaxes. as converts Python source between the indentation skin you know and two it can wear: C-style braces and Lisp-style S-expressions. Same semantics, different look — hence the name: as lisp, as brace, as py.

def quicksort(items):                  def quicksort(items) {
    if len(items) <= 1:                    if len(items) <= 1 {
        return items                           return items;
    pivot, *rest = items;                }
    lo = [x for x in rest                pivot, *rest = items;
         if x < pivot]                   lo = [x for x in rest if x < pivot];
    hi = [x for x in rest                hi = [x for x in rest if x >= pivot];
         if x >= pivot]                  return quicksort(lo) + [pivot] + quicksort(hi);
    return quicksort(lo) + [pivot]    }
        + quicksort(hi)
(defn quicksort (items)
  (if (<= (len items) 1) (return items))
  (set! '(pivot (* rest)) items)
  (set! lo (list-comp x (for [x in rest]) (when (< x pivot))))
  (set! hi (list-comp x (for [x in rest]) (when (>= x pivot))))
  (return (+ (+ (quicksort lo) [pivot]) (quicksort hi))))

Why

"Braces or indentation" is one of the oldest holy wars in programming. as does not pick a side — it makes the question meaningless. Write in whichever skin you like, read in whichever skin you like, and argue about taste instead of syntax. The round trip is exact: converting py → skin → py yields an AST identical to the original (tested on the whole as codebase and 40 stdlib modules, see Tests).

Install & use

pip install as
as lisp foo.py            # Python → S-expressions (stdout)
as brace foo.py -o foo.cpy
as py foo.lpy             # S-expressions → Python
cat foo.py | as brace - --from py

Input style is detected from the extension: .py, .cpy (braces), .lpy (lisp). Use --from to override.

The importable package is aslang (from aslang import convert) because as is a Python keyword — the distribution and the CLI keep the two-letter name.

The three skins

skin extension blocks collections
py .py indentation (), [], {}, {k: v}
brace .cpy if cond { ... } unchanged (Python expressions)
lisp .lpy (if cond ...) [...] list, '(...) tuple, {(k v)} dict, #{...} set

The lisp skin is more than a re-bracketing: operators go prefix ((+ a (* b c))), methods become calls ((len items), (items.append x)), comprehensions get for/when clauses, match cases carry their patterns as data. The brace skin stays deliberately close to Python — only the block structure changes.

lpy form reference (selected)

(defn name (params...) [-> ret] body...)     (set! target value)
(for [x in iter] body... [(else ...)])       (while cond body...)
(if test then... [(elif ...)...] [(else ...)])
(with [(expr as name) ...] body...)
(try body... (except Type [as e] h...)...)
(match subject (case pattern [(when guard)] body...))
patterns: literal | name | _ | (as pat name) | (or p...) | [p *rest]
          {(key pat) ... (** rest)} | (Cls p... (kws (attr pat)...))
(list-comp elt (for [x in xs]) (when cond))
(fstr "x = " (fv value) "!")

Correctness

  • py ↔ brace converts text directly on the token stream: comments, formatting and even docstrings survive byte-for-byte outside the changed block lines.
  • anything ↔ lisp goes through the ast module: the reader builds a real AST, the printer walks it. Comments are preserved best-effort (dropped by the ast, re-attached by line numbers).
  • Round-trip proof: ast.dump(ast.parse(src)) == ast.dump(parse(convert( convert(src, py, skin), skin, py))) for every corpus file.

Compared

bython Hy Nim as
direction → py → py AST own lang any → any
braces skin
S-expression skin ✓ (own)
round-trip guaranteed ✓ (AST-equal)
Python semantics mostly no ✓ exactly

Limitations

  • match is supported in all skins; typing.TypeAlias statements and try*-era syntax are not yet in the lisp skin.
  • The lisp reader accepts a fixed set of special forms; arbitrary macro machinery is out of scope (this is a converter, not a language).
  • A case body that begins with a call to a function literally named when needs parentheses discipline (the (when ...) guard marker wins).

Note on the name

Yes, as shadows GNU as (the assembler) if ~/.local/bin precedes /usr/bin in your PATH. If you build C, keep your PATH straight or alias. The two-letter namespace was simply too good to leave unused — import json as j, as lisp foo.py.

Development

pip install -e .
pytest                  # 92 tests: unit + stdlib corpus + self-application

The tool digests its own source in the test suite: every module of aslang is converted to both skins, back, and the result must be AST-identical — and must still execute.

MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

like_a-0.1.0.tar.gz (27.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

like_a-0.1.0-py3-none-any.whl (24.9 kB view details)

Uploaded Python 3

File details

Details for the file like_a-0.1.0.tar.gz.

File metadata

  • Download URL: like_a-0.1.0.tar.gz
  • Upload date:
  • Size: 27.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for like_a-0.1.0.tar.gz
Algorithm Hash digest
SHA256 decddbeca3d5e4af775e4b92928d67220973281a42961fefd368953cc9218e94
MD5 6c4c79a2c788f4ab83e1abc979601873
BLAKE2b-256 b0e87e04f563e73b058ca16bc7eddb8e0272160f6279471f5a0f42e4406c76bb

See more details on using hashes here.

File details

Details for the file like_a-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: like_a-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for like_a-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cace60b5ffe9fdd1566ab774621883b57313cc6fa02d7de68cb1d0bc3676b98d
MD5 4dace51ab2a207a9d5bdc823b799ada2
BLAKE2b-256 9f1964cf4c5dfdce9a86750756b380f7f691314aefddd0d9d882da79c4efa89f

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page