Skip to main content

spasmlang

PyPI - Version PyPI - Python Version

Synopsis

spasmlang is a simple Python assembly language. It lets you generate CPython bytecode from a simple assembly-like syntax, and assembles it with a bundled C++ extension rather than a pure-Python bytecode library.

Supports CPython 3.10 through 3.14, and has no runtime dependencies.


Table of Contents

Installation

pip install spasmlang

Wheels are published for CPython 3.10–3.14 on Linux, macOS and Windows. Installing from source needs a C++17 compiler.

Usage

The spasmlang package provides a class, Assembly, that allows you to generate bytecode from a simple assembly-like syntax. See the examples below for a taste of its API. Where source-level assembly isn't practical, the low-level API lets you string instruction objects together directly.

You can also use the spasm command-line utility to compile assembly files directly to Python bytecode:

spasm example.pya  # generates example.pyc

Examples

This is how the classic "Hello, World!" program looks like, targeting the CPython 3.12 bytecode:

from spasm import Assembly

asm = Assembly()
asm.parse(
    r"""
    push_null
    load_const          print
    load_const          "Hello, World!"
    call                1
    return_value
    """
)
exec(asm.compile())

This is how you can compile the file example.pya to example.pyc to create a "Hello, World!" module, again targeting CPython 3.11:

# example.pya
    resume      0
    push_null
    load_name   $print
    load_const  "Hello, spasm!"
    precall     1
    call        1
    pop_top
    load_const  None
    return_value

Compile the assembly code with (assuming that you have installed spasmlang with CPython 3.11)

spasm example.pya

and then execute the generated module with e.g.

python3.11 -m example

This example shows how to create a module that exports a greet function that takes one argument, targeting CPython 3.11:

# greet.pya

code greet(who)
    resume                      0
    load_global                 (True, "print")
    load_const                  "Hello, "
    load_fast                   $who
    format_value                0
    build_string                2
    precall                     1
    call                        1
    return_value
end

    resume 0
    load_const                  .greet
    make_function               0
    store_name                  $greet
    load_const                  None
    return_value

Again, compile the assembly code with

spasm greet.pya

and test it with

$ python3.11 -c "from greet import greet; greet('spasmlang')"
Hello, spasmlang

Code blocks nest, and a block header can declare the variables the block shares with the one around it, which is what a closure needs:

code NAME(arguments)[cells]<frees>

The two trailing groups are optional and independent, so code f(x)<n> declares a free variable and no cells. Cells are this block's locals that a nested block captures; frees are the ones it captures from its own enclosing block. They have to be written down because nothing in the instruction stream tells the two apart — LOAD_DEREF $n looks the same either way.

This is lambda n: lambda: n in assembly, targeting CPython 3.12:

# adder.pya

code outer(n)[n]
    make_cell                   $n
    resume                      0

    code inner()<n>
        copy_free_vars          1
        resume                  0
        load_deref              $n
        return_value
    end

    load_closure                $n
    build_tuple                 1
    load_const                  .inner
    make_function               8
    return_value
end

    resume                      0
    load_const                  .outer
    make_function               0
    store_name                  $outer
    load_const                  None
    return_value
$ spasm adder.pya && python3.12 -c "from adder import outer; print(outer(42)())"
42

Note that n appears both as an argument of outer and in its cell list: from CPython 3.11 a captured parameter occupies a single frame slot that is at once a local and a cell, and MAKE_CELL is what turns it into one. inner is reachable only from outer, since a nested block is a constant of the block it is written in and not of the module.

Low-level API

Writing a snippet of assembly is the shortest way to get bytecode, but it is not always the right shape for the job. When the instruction stream is being computed rather than written — you are transforming an existing code object, generating a sequence whose length depends on runtime data, or injecting instrumentation into somebody else's function — you want to string instructions together as objects. That is what spasm.bytecode exposes, and it is the same layer the assembler itself is built on.

from spasm.bytecode import Bytecode, ExcEntry, Instr, Label

The data model

A Bytecode is a mutable, decoded code object. Bytecode.from_code(co) builds one from an existing code object and bc.to_code() encodes it back; the round trip is lossless, so decoding and re-encoding an untouched function gives back byte-identical co_code, line table and exception table.

Attribute Meaning
instrs The instruction list. Holds Instr objects and nothing else — no labels, no pseudo-entries.
end_labels Labels for the position one past the last instruction.
exc_entries The ExcEntry list making up the exception table (3.11+).
consts, names, varnames, freevars, cellvars The code object's tables, as plain lists.
argcount, flags, firstlineno, filename, name, qualname The remaining code object fields.

An Instr carries op (settable as an opname string or as an int), arg, and the position attributes lineno, col_offset, end_lineno and end_col.

There is no stacksize: co_stacksize is always computed from the instruction stream by to_code(), and is neither stored nor settable.

Bytecode() with no arguments is an empty template — no instructions, empty tables, argcount 0, flags 0, firstlineno 1, filename <string>, name and qualname <bytecode> — so building from scratch is a matter of filling in the fields you care about. Bytecode(instrs) seeds the instruction list in one go; either way bc.instrs is a live list you can mutate in place.

import sys
import types

from spasm.bytecode import Bytecode, Instr, infer_flags

bc = Bytecode()
if sys.version_info >= (3, 11):
    bc.instrs.append(Instr("RESUME", 0))
bc.instrs += [
    Instr("LOAD_FAST", "x"),
    Instr("LOAD_FAST", "y"),
    Instr("BINARY_OP" if sys.version_info >= (3, 11) else "BINARY_ADD", 0),
    Instr("RETURN_VALUE"),
]
bc.name = bc.qualname = "add"
bc.argcount = 2
bc.varnames = ["x", "y"]
bc.flags = infer_flags(bc, is_function=True)

add = types.FunctionType(bc.to_code(), {})
assert add(1, 2) == 3

infer_flags derives the co_flags a code object being built from scratch needs, as far as that can be done from the code alone: it cannot see *args/**kwargs or lexical nesting, so CO_VARARGS, CO_VARKEYWORDS and CO_NESTED are left to the caller.

Instruction arguments

Arguments that name a table entry are given as the value, not as the index, and the entry is created if it isn't there already:

Argument kind What to pass
co_consts (LOAD_CONST, …) The constant itself.
co_varnames (LOAD_FAST, STORE_FAST, …) The variable name, as a string.
free/cell variables (LOAD_DEREF, …) The variable name, as a string.
Jump targets A Label.
co_names (LOAD_GLOBAL, LOAD_ATTR, STORE_NAME, …) An int, from encode_name_arg().
Everything else The raw int oparg.

Name arguments are the one exception, because they are not just an index: from 3.11 LOAD_GLOBAL and from 3.12 LOAD_ATTR pack a flag bit alongside it. encode_name_arg(bc, opname, name, flag=False) interns the name and returns the oparg, shifting the index where the version calls for it.

Two more helpers cover opargs that are conceptually symbolic: compare_oparg(Compare.LT) for COMPARE_OP, whose encoding moved twice between 3.10 and 3.13, and the BinaryOp enum for BINARY_OP on 3.11+, whose members are used as the oparg directly.

If you would rather work with indices, add_const(), add_name() and add_varname() intern a value and hand back its index.

The superinstructions that pack two variable indices into a single oparg — LOAD_FAST_LOAD_FAST and friends — take a plain int, since a single name cannot express what they encode.

Jumps and labels

Jump targets are Label objects rather than offsets, which is what makes an instruction list editable: inserting or removing instructions shifts every offset in the code object, but a label stays attached to the instruction it points at.

Make one with bc.new_label(), append it to the labels list of the instruction it should land on, and pass it as the argument of the jump. For a target one past the end of the code, append it to bc.end_labels instead. bc.label_positions() maps every label to the index in instrs it currently resolves to.

bc = Bytecode()
falsy = bc.new_label()

instrs = [Instr("LOAD_FAST", "x")]
if sys.version_info >= (3, 13):
    instrs.append(Instr("TO_BOOL"))  # 3.13+ POP_JUMP_IF_* only accepts a bool
instrs += [
    Instr("POP_JUMP_IF_FALSE", falsy),
    Instr("LOAD_CONST", "truthy"),
    Instr("RETURN_VALUE"),
    Instr("LOAD_CONST", "falsy"),
    Instr("RETURN_VALUE"),
]
instrs[-2].labels.append(falsy)
bc.instrs += instrs

Nothing here needs to know how far the jump reaches: the encoder picks the relative or absolute form the opcode wants, and grows EXTENDED_ARG prefixes to a fixed point when an oparg does not fit in a byte — which it has to iterate, since growing one prefix moves every target after it.

Transforming an existing code object

Instrumentation is the case the API is really shaped for: decode, splice, and encode back.

import sys

from spasm.bytecode import Bytecode, Instr, encode_name_arg

PY311 = sys.version_info >= (3, 11)


def f(a, b):
    return a * b


bc = Bytecode.from_code(f.__code__)

# The flag bit makes LOAD_GLOBAL push the NULL that the call sequence wants,
# in whichever order this version expects it; before 3.11 there is no NULL.
flag = {"flag": True} if PY311 else {}
trace = [
    Instr("LOAD_GLOBAL", encode_name_arg(bc, "LOAD_GLOBAL", "print", **flag)),
    Instr("LOAD_CONST", "called!"),
    Instr("CALL" if PY311 else "CALL_FUNCTION", 1),
    Instr("POP_TOP"),
]

# RESUME has to stay the first instruction of a 3.11+ code object.
at = 1 if PY311 else 0
for instr in trace:
    instr.lineno = bc.instrs[at].lineno
bc.instrs[at:at] = trace

f.__code__ = bc.to_code()
f(3, 4)  # prints "called!" and returns 12

Give inserted instructions a lineno explicitly. Nothing forces you to, but the line table is what tracebacks and debuggers read, and an instrumented function whose lines have drifted is unpleasant to debug.

Exception table entries

From 3.11 on, exception handling is table-driven rather than done with block instructions, and bc.exc_entries is that table. An ExcEntry is three labels — the protected region's start and (exclusive) stop, and the handler — plus the stack depth the handler is entered at and whether the interpreter should push lasti before the exception.

from spasm.bytecode import Bytecode, ExcEntry, Instr


def risky(x):
    return 1 / x


bc = Bytecode.from_code(risky.__code__)

start = bc.new_label()
handler = bc.new_label()
bc.instrs[1].labels.append(start)  # everything after RESUME is protected

recover = [
    Instr("POP_TOP"),  # the exception the interpreter pushed for us
    Instr("LOAD_CONST", None),
    Instr("RETURN_VALUE"),
]
recover[0].labels.append(handler)
for instr in recover:
    instr.lineno = bc.instrs[-1].lineno
bc.instrs += recover

# stop is exclusive, so the handler's own label doubles as the end of the
# region it handles.
bc.exc_entries.append(ExcEntry(start, handler, handler))

risky.__code__ = bc.to_code()
assert risky(0) is None

depth defaults to being inferred, which works whenever the depth at the start of the protected region follows from normal control flow. Where it does not — a handler reachable only through another handler's cleanup path, say — to_code() raises instead of guessing, and you pass the depth yourself.

What is checked, and what is not

to_code() computes co_stacksize, resolves labels, encodes the line and exception tables and rejects opcodes the interpreter reserves for itself: the INSTRUMENTED_* family, ENTER_EXECUTOR, CACHE and the pseudo-opcodes. That last check exists because handing some of them to PyCode_New does not raise, it crashes.

Beyond that, this is an assembly language: it will faithfully encode a stack effect that does not balance, a LOAD_FAST reading a variable that was never stored, or a jump into the middle of an instruction's inline caches, and the interpreter will fault on it. Bytecode that is valid runs; bytecode that merely assembles need not.

Finally, opcodes and calling conventions move between releases — RESUME and BINARY_OP arrived in 3.11, POP_JUMP_IF_FALSE wants a real bool on the stack from 3.13, the NULL a call needs is pushed in a different order in 3.13 than in 3.12 — so code written against this API targets an interpreter version in a way that source-level spasm snippets partly hide. The dis module for the version you are targeting is the reference.

Architecture

spasmlang is two layers.

spasm._core is a C++ extension implementing the bytecode data model — Bytecode, Instr, Label, ExcEntry — along with code object decoding and encoding, line table and exception table handling, and stack depth computation. It carries opcode tables generated at build time for the exact interpreter it is compiled against (see setup.py), which is why there is one wheel per Python minor version rather than a single abi3 wheel.

spasm.bytecode is a thin Python layer over it holding the parts that are version-dependent bookkeeping rather than data structure: the Compare and BinaryOp symbolic opargs and their per-version encodings, name-argument packing for LOAD_GLOBAL/LOAD_ATTR, and co_flags inference. spasm.asm builds on both and stays concerned with parsing and assembly.

Stack depth (co_stacksize) is computed for you. Exception table entry depths are inferred too, but only where that can be done exactly — see the note in spasm/bytecode.py and src/stackdepth.cpp; to_code() raises rather than emit a depth it cannot derive correctly.

This code was previously developed as a separate bytecode-native package and has since been absorbed here.

License

spasmlang is distributed under the terms of the 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

spasmlang-0.3.0.tar.gz (94.6 kB view details)

Uploaded Source

Built Distributions

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

spasmlang-0.3.0-cp313-cp313-win_amd64.whl (72.2 kB view details)

Uploaded CPython 3.13Windows x86-64

spasmlang-0.3.0-cp313-cp313-win32.whl (61.7 kB view details)

Uploaded CPython 3.13Windows x86

spasmlang-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.13musllinux: musl 1.2+ x86-64

spasmlang-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (801.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

spasmlang-0.3.0-cp313-cp313-macosx_11_0_arm64.whl (68.0 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

spasmlang-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl (70.4 kB view details)

Uploaded CPython 3.13macOS 10.13+ x86-64

spasmlang-0.3.0-cp312-cp312-win_amd64.whl (71.8 kB view details)

Uploaded CPython 3.12Windows x86-64

spasmlang-0.3.0-cp312-cp312-win32.whl (61.3 kB view details)

Uploaded CPython 3.12Windows x86

spasmlang-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

spasmlang-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (800.3 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

spasmlang-0.3.0-cp312-cp312-macosx_11_0_arm64.whl (68.0 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

spasmlang-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl (70.4 kB view details)

Uploaded CPython 3.12macOS 10.13+ x86-64

spasmlang-0.3.0-cp311-cp311-win_amd64.whl (70.7 kB view details)

Uploaded CPython 3.11Windows x86-64

spasmlang-0.3.0-cp311-cp311-win32.whl (59.6 kB view details)

Uploaded CPython 3.11Windows x86

spasmlang-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl (1.7 MB view details)

Uploaded CPython 3.11musllinux: musl 1.2+ x86-64

spasmlang-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (791.6 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

spasmlang-0.3.0-cp311-cp311-macosx_11_0_arm64.whl (66.9 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

spasmlang-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl (69.4 kB view details)

Uploaded CPython 3.11macOS 10.9+ x86-64

spasmlang-0.3.0-cp310-cp310-win_amd64.whl (60.4 kB view details)

Uploaded CPython 3.10Windows x86-64

spasmlang-0.3.0-cp310-cp310-win32.whl (53.1 kB view details)

Uploaded CPython 3.10Windows x86

spasmlang-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.10musllinux: musl 1.2+ x86-64

spasmlang-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (653.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

spasmlang-0.3.0-cp310-cp310-macosx_11_0_arm64.whl (57.9 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

spasmlang-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl (59.0 kB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

File details

Details for the file spasmlang-0.3.0.tar.gz.

File metadata

  • Download URL: spasmlang-0.3.0.tar.gz
  • Upload date:
  • Size: 94.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0.tar.gz
Algorithm Hash digest
SHA256 5a049c129b52600236b275e1b1561c0d8d3a887479b477a256bcf5360fecab90
MD5 4149c8f7fdb3983a48c44c1dfab16a9a
BLAKE2b-256 e1c0434c4d784381299d7c9da9c4078521cd96400054a76b53f0ca6569e92eed

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 72.2 kB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 450efe1acc5c19da42557e1ca481b3956e03001deb0175b1df040e897a5a0312
MD5 fc606e39b56033ea69669ba58b4da1fb
BLAKE2b-256 88b74d832f75776f5ce3f938136c207195e995864a49bd615711825d330616a4

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-win32.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp313-cp313-win32.whl
  • Upload date:
  • Size: 61.7 kB
  • Tags: CPython 3.13, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-win32.whl
Algorithm Hash digest
SHA256 d96a327d6102ff4850b952f06b0b8d044b4ea5da9d06b16943bd5865832baeca
MD5 f81257c58df1fb35af9bd1872bfde9e7
BLAKE2b-256 b1fb9d93ab94031995ff586f28557d65c54c696d65007237ae48275a97549874

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 d3d6eb8a9aaf438ae7f719cd8155c47e898e374e1aff7eb35de5f57c746beaf2
MD5 48e354aca12f7790af3da6176ec8eddf
BLAKE2b-256 3218a336153896e78ca48d2978ad24c1394a49355679d80eb4be03d2bb791265

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d2e68bf22736a10c3c2ed71464cee3939772025486e4613a2a41dcffbd472124
MD5 ec24312d338c522c8142046e14844088
BLAKE2b-256 08e1ac84b2dbceb060a4cdb49c7ae5f09b4a92387bb04455cd201bf656c9cd18

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1d1a20977b6c29a20b559f2b0f1c98265c598a1078d17d6359e14642324377cb
MD5 f013607ebc5d24ea23e8cb80d49ea0a7
BLAKE2b-256 dc861fcee234d81fd7a1bc47908666345a139f614c7267da1ea361c3bee52cca

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 1e9f189346433fb9788242e6a0d4d60e0d18b14ca1eae4962aa01dc925dbdfc4
MD5 4cc3abbc75d286e5a6927a8169242551
BLAKE2b-256 0a298a0da5b2be5532742abe8332f7e9be3a042a31aa5bdb58a5232b85513d8a

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 71.8 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 4ec8c6e898e7f54be9a30424dada6adcb1e5f98c74d6ed02ecd6bb5d48eab471
MD5 1557713a457f9635bdf205f5bbbd5137
BLAKE2b-256 e7bb56c961f9dcb071bcdac4142fcaa0a2d2b03d8f68da7ffc951758661d0e77

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-win32.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp312-cp312-win32.whl
  • Upload date:
  • Size: 61.3 kB
  • Tags: CPython 3.12, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-win32.whl
Algorithm Hash digest
SHA256 18c78e7ffecb7126b4018881a88e1bf78850230478ee8ad2a9fe16979f9cebb4
MD5 7b331c5b6977352a34d740ddf1138257
BLAKE2b-256 ddea685253d525bf4de5eb90c06edf322b76234936fd27123d2acb30670297a3

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9e8d01c7fc110a3320c1cb70154716bc576a4a59b3a5f58230e52c73d890fc29
MD5 2737436483ac2f8c114ec10ba7471c10
BLAKE2b-256 07865de7b1f43aa35632094e40c15dfb4bd14e5131e432487c4581afba9f830e

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a03389dd61275fcb8e215c4896b8d6753289cc8ab5a5ef8a4353b56de516803b
MD5 5ef8a67129f0ec67662945d39c9b88ff
BLAKE2b-256 534c07ef59f27fb4d162ed9787b49f847103fcad274bbc528f169f2398c9065c

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d995a9fdd4ec066b6a353174abbe488d9ca22f5cc966dca61689451eda6b7813
MD5 662c8260ca4544307a98f36083b03a40
BLAKE2b-256 dbeeb33d4204f34a02db6f8b6e04d795fa512c25046f0eeb5eb8186383577253

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 2e48afc91fe3fc14b469c831afeff794d6b848d655dd545d9838821159ea2211
MD5 6166cc06d9835ab164feb5e3269dde38
BLAKE2b-256 a684478954e9c4290a17aecb6b8620152ad99214847b5a0d367637b38a2127eb

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 70.7 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 a16a68480e76454de539de0d9d12e1fb9f04223a4017f820efb47f242ee74c93
MD5 307c357b843bd7f5e2e83a5757fca94e
BLAKE2b-256 50e693df269a396d2021fc6fa9a5fe88ae3b5ae5cb62cd1dd745426ce0ac691a

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-win32.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp311-cp311-win32.whl
  • Upload date:
  • Size: 59.6 kB
  • Tags: CPython 3.11, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-win32.whl
Algorithm Hash digest
SHA256 78b95906ff470a48cf87e8c23f3f6821eecb4a009b0dc5905d61abca95d1e157
MD5 6403a1cef42076ba802bd2e5ad51ded2
BLAKE2b-256 ccbc5b6ecdbc369464f6fc576d53af6b302e26f970d7985cf4607d4a24919380

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 35a9f6b05c25627f5fd34e92128bc3f1dc717f83d638e15420e70b7a0d217b12
MD5 6f874757484cabe553a6f927b12eb4a2
BLAKE2b-256 07086b50cc4e4d1b37e1f83a07f46bfb6af3ad166b81fd671201e8b6a7742fa1

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 918f5880c6ea2e0e4fa4625b07f90ef93f09796f559236bfafccabb9edac6888
MD5 ff72565c87093076764a999c4a68efb8
BLAKE2b-256 15337c285f8629e0fbb9a7ae263611393cb1fd66cb80f3da9b0aec69b71808a5

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1af10438075f9324810cacc4f0a02f9970c9f88423b0b40eb17cf2c3d854935a
MD5 2799edc78084ca9a923d54bfa4c9d96a
BLAKE2b-256 79cccc31dc3a9c30de1b4975fa6a04b72e0c71164a257c9b33c640118ae93f51

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 17c670bed981e0a0c311a3f2ec1b0b02bd352fd88c02a39a07d59d24194daec7
MD5 07d87c2453616e91728406e1a6b4e7db
BLAKE2b-256 022b7f62f509a43636ef4c581cc9bd29fa4efbbc425aaabb80f4723e4f126449

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 60.4 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 96ad2f577a7cbd1246b97c71d8eebb5c427ad97ff77f17ab0a3440642a1a5c58
MD5 9ede295470326c42ca4111b5f7693f05
BLAKE2b-256 c3c991c5999d472c4ed95e252a3250b71130cf04b158b530f5a1b7daea4e46af

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-win32.whl.

File metadata

  • Download URL: spasmlang-0.3.0-cp310-cp310-win32.whl
  • Upload date:
  • Size: 53.1 kB
  • Tags: CPython 3.10, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-win32.whl
Algorithm Hash digest
SHA256 41b405df281355161c1f7b87bbdc5324df4f4feef56f937d658b3e7ab108dc48
MD5 276b064e8c826bae9beab70912eba105
BLAKE2b-256 a2135b992170da9675e2a0f567be2854308a89808c70fde63c96e73be11d35e2

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 f77e90630da7da2aadc05922be12e6ed232dd07c37e7475f1f5fad5df8257247
MD5 da3c9baf0f23b670c8176bd6cb554e0d
BLAKE2b-256 6870b34d523a8629f04b59a8c42deb73f49e3528a23f55cab717fcda975153ea

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 934b62ead54d224c0dc4cf80b8c9f39a4c415578380a2f4381f6dc8bdf164d6d
MD5 56804ed1f593d8d38d8d2644ed76b804
BLAKE2b-256 99fe43d521d569973bf85e321cbbae2b445f0070f77ee3cf3ca4d5f4c2c30283

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0ad3156932da000c4c8fbc2361dc780a741292dd6459cffb80db833a824afc5e
MD5 e33a43a6668016be97dff9ad9260fd94
BLAKE2b-256 93ab266c071f930d08fbadbd3385f371fe01b1f860c8f89da374ebbc7aaa5648

See more details on using hashes here.

File details

Details for the file spasmlang-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for spasmlang-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 fad3ca8d986ddcaa33d6374e70ed9b4275001d46476b78555e0a155590a8b6e5
MD5 c82eacb6f60c54f7d09b7298d9156768
BLAKE2b-256 d39b0c4887d97ed1dcccddc76a12092ec451116dec09007ae40e69a16f445e56

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

25 files

0.2.1

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

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