Declarative runtime Python code generation: hygienic AST stitching with automatic hole/binding wiring
Project description
astichi
A declarative, runtime code generator for Python.
Astichi stitches small, marker-bearing Python snippets into specialized code at runtime — for example, inside a class decorator that assembles a tailored implementation each time it is applied — and emits plain, inspectable Python that then runs with no per-call dispatch overhead. An optional native Rust engine keeps that runtime generation fast enough to sit on the decoration / import path.
The point is to make AST stitching declarative: you say what fills which hole and what satisfies which injection point — even partially — and astichi connects the dots for you. It matches snippets to compatible holes, values to their binding slots, and identifiers to their demands (with a real compatibility check, not string-matching), wires them across nested layers, and keeps every scope hygienic. You describe the graph; you don't hand-walk and mutate an AST.
It is a focused, hygienic AST stitcher — it composes generator-authored fragments; it is not a generic codemod or refactoring framework for existing source.
pip install astichi
Release wheels for Linux, macOS, and Windows (CPython 3.12–3.15) bundle an optional native Rust acceleration engine; installs without a matching wheel fall back to pure Python. See the native fast path.
Quick start
You author Python with markers in it, compile each snippet into a
Composable, wire them together with a builder, then materialize and
emit real Python.
import astichi
root = astichi.compile("""
items = []
astichi_hole(body) # a named insertion site
result = tuple(items)
""")
step = astichi.compile("""
astichi_pass(items, outer_bind=True).append("x") # explicitly reuse outer `items`
""")
builder = astichi.build()
builder.add.Root(root)
builder.add.Step(step)
builder.Root.body.add.Step(order=0) # stitch `step` into the `body` hole
print(builder.build().materialize().emit(provenance=False))
Emitted Python:
items = []
items.append("x")
result = tuple(items)
Without astichi_pass(items, outer_bind=True), the inner snippet would not
silently reuse items just because the spelling matches. Astichi defaults to
isolated scopes and only crosses them when the source says so — that is the
hygiene guarantee that makes large stitched programs predictable.
For the full compile → bind → build → describe → materialize → emit walkthrough, see the Using the API guide.
What you get
- Connect-the-dots wiring. Hand astichi a snippet, a value, or an identifier plus a partial description of where it goes, and it finds the compatible hole / binding slot / demand and attaches it — checking structural compatibility, not just names. You under-specify; it resolves the match (and refuses ambiguous ones with a diagnostic). This is the declarative core; see the assembler.
- Multi-layer composition. Composables compose into composables: build one, reuse it as a piece of the next, nest child scopes, and wire identifiers across layers — with hygiene preserved at every boundary.
- Valid ASTs, not string fragments. Compose typed AST nodes with deterministic insertion order instead of concatenating text.
- Hygiene by default. Each inserted snippet lives in its own scope. Names
cross boundaries only through explicit
keep/pass/import/export, so stitched fragments never collide by accident. - Generation-time specialization. Bake values into the source and unroll
astichi_for(...)loops into straight-line Python as you generate — so the emitted function carries no dispatch layer to pay for on every call. - Managed imports. Snippets declare the imports they need with
astichi_pyimport(...); astichi collects, dedupes, collision-checks, and inserts them at materialize time. - Inspectable output. Emitted source can be diffed, tested, and round-tripped, optionally with a provenance tail for AST/source-location restoration.
- Descriptor-driven composition.
describe()exposes holes, binds, ports, and target addresses so tools can wire fragments from data instead of hand-written attribute chains.
The marker model
These are not functions you import or call.
astichi_hole,astichi_keep,astichi_pass, and the rest are markers — sentinel names recognized in the Python source text you hand toastichi.compile(...). There is nofrom astichi import astichi_hole; you write the marker inside the snippet string and astichi recognizes it by name and AST position (not by string matching alone). The only names you actually import fromastichiarecompile,build,Composable, and a few helpers.
The core markers are:
astichi_hole(name)-> insertion siteastichi_keep(name)-> hygiene-preserved name in expression / statement sourcename__astichi_keep__-> hygiene-preserved name in identifier positionname__astichi_arg__-> identifier demandname__astichi_param_hole__-> function-parameter insertion targetastichi_funcargs(...)-> call-argument payloadastichi_for(...)-> build-time loop unrollingastichi_bind_external(name)-> external/literal value slotastichi_ref(path)-> compile-time reducible identifier / attribute pathastichi_pyimport(module=..., names=(...))-> managed Python importastichi_comment("...")-> final-output source commentastichi_pass(name, outer_bind=True)-> explicit same-name boundary readastichi_import(name)-> explicit whole-scope boundary importastichi_export(name)-> explicit outward supplyastichi_insert(...)-> internal emitted metadata, not general authored API
Comment marker note:
astichi_comment("...")is statement-only. Ordinarymaterialize()strips it for executable output;emit_commented()renders it as real#comments.- Multi-line payloads keep the marker statement's indentation, and only exact
{__file__}/{__line__}substrings are expanded.
Value-form target note:
astichi_ref(...)andastichi_pass(...)are ordinary value-form surfaces in expressions.- If the marker result itself must occupy an
Assign/AugAssign/Deletetarget position, append._or.astichi_v:astichi_ref("self.f0")._ = 1,astichi_pass(counter).astichi_v = 1. - If you immediately continue to a real attribute, plain Python target syntax
already works:
astichi_pass(obj).field = 1.
The one rule that matters most is scope:
astichi_insertis the basic Astichi boundary.- Each inserted composable lives in its own Astichi scope.
- There is no implicit capture across that boundary.
- If a name crosses the boundary, make it explicit with
keep,pass,import, orexport. - Function parameters are the pinned exception: parameter names and uses in the function scope stay attached to that parameter binding.
The full marker reference, edge cases, and value-form target rules live in the marker docs and scoping & hygiene reference.
Declarative wiring: the assembler connects the dots
This is the part that makes astichi feel low-fuss. The hardest, most
error-prone part of stitching code by hand is the bookkeeping: which snippet
is allowed in which hole, which value feeds which injection point, which
identifier answers which demand — and keeping all of that straight as the
graph grows across layers. astichi.assembler.AssemblyScope does that matching
for you.
The plain fluent builder makes you name the exact target up front
(builder.Root.body.add.Step()). The assembler inverts it: you hand it a
resource plus a partial description of where it belongs, and it
finds the site that resource can legally satisfy — a block hole, an
identifier demand, an external-value slot — using a structural compatibility
check against the target's descriptor, not string-matching. Under-specify and
it resolves the match; if more than one site fits, it refuses with a diagnostic
rather than guessing. That is the "connect the dots" behavior: you declare
intent, astichi does the wiring.
It is built from three small, composable pieces:
- Pluggable resources — what to attach:
as_composable(...)(a fragment),as_external_value(...)(a compile-time value),as_identifier(...)(an identifier spelling). - Partial selectors — where it may attach, as much or as little as you
know:
name,build_match, andowner_match(the last two are path patterns with./?/*/+wildcards). - One-call resolution —
wire(resource, ...)runsfind_candidates(...)→require_one(...)→apply(...)for you and returns the resolved candidate. (The three steps stay public if you want them separately, andapply_batch(...)takes an ordered stream.)wireraises a diagnostic naming the build path, owner, and source location when the selector matches nothing or more than one site.
import astichi
from astichi.assembler import AssemblyScope, as_composable, as_external_value
root = astichi.compile("""
out = []
astichi_hole(body)
result = tuple(out)
""")
body = astichi.compile("""
astichi_pass(out, outer_bind=True).append(astichi_bind_external(label))
""")
scope = AssemblyScope(astichi.build())
scope.add("Root", root)
# One call each, minimal selector — just the demand NAME. No exact target path.
scope.wire(as_composable(body, build_name="Body"), name="body")
scope.wire(as_external_value("done"), name="label")
print(scope.build().materialize().emit(provenance=False))
Emitted Python:
out = []
out.append('done')
result = tuple(out)
You named the demand (body, label) and nothing else — no
builder.Root.body.add(...), no exact address. The scope found the compatible
hole and the compatible external slot and wired them.
When you do need precision — disambiguating among many sites, indexed
instances, ordering — tighten the same call with build_match / owner_match
path patterns (. / ? / * / + wildcards), build_index, and order. That
is also what lets you compose along two axes at once: place the same
template in many spots (structure), and specialize each placement
differently (substitution). One template becomes many polymorphic concrete
forms:
import astichi
from astichi.assembler import (
AssemblyScope, as_composable, as_external_value, as_identifier,
)
shell = astichi.compile("""
class Accessors:
def __init__(self, data):
self._data = data
astichi_hole(methods)
""")
# One polymorphic template: the method name is an identifier demand,
# the lookup key is an external-value slot.
getter = astichi.compile("""
def method_name__astichi_arg__(self):
return self._data[astichi_bind_external(key)]
""")
scope = AssemblyScope(astichi.build())
scope.add("Shell", shell)
for i, (method, key) in enumerate(
[("get_name", "name"), ("get_email", "email"), ("get_age", "age")], start=1
):
inst = f"Getter[{i}]"
# axis 1 — structure: place the SAME template into `methods`, repeatedly
scope.wire(as_composable(getter, build_name="Getter", build_index=i, order=i), name="methods")
# axis 2 — specialization: bind THIS instance's name + key differently
scope.wire(as_identifier(method), name="method_name", build_match=("Shell", inst))
scope.wire(as_external_value(key), name="key", build_match=("Shell", inst))
print(scope.build().materialize().emit(provenance=False))
Emitted Python — three specialized methods from one template:
class Accessors:
def __init__(self, data):
self._data = data
def get_name(self):
return self._data['name']
def get_email(self):
return self._data['email']
def get_age(self):
return self._data['age']
That is the polymorphic core: a single template, matched into a hole three
times and specialized per instance — and as_composable, as_identifier, and
as_external_value resources all attached by the same one-call wire(...). YIDL
pushes this to production scale (see Maturity).
Least-surprise means it never guesses. If a resource fits more than one site,
wire refuses (via require_one) with a diagnostic that names every candidate's
build path, owner, demand name, kind, and source location, so you know exactly
how to narrow the selector:
ValueError: expected exactly one candidate, found 2
candidate 1:
demand: build_path=Root owner=. name=first kind=hole.block location=<astichi>:3 locator=body[1]/value
resource: composable build_name=Frag
production: name=__block__ kind=production.block location=<astichi>:1 locator=.
candidate 2:
demand: build_path=Root owner=. name=second kind=hole.block location=<astichi>:4 locator=body[2]/value
resource: composable build_name=Frag
production: name=__block__ kind=production.block location=<astichi>:1 locator=.
The same matching works across layers. A composable you already built can be registered as a piece of a larger assembly, child scopes resolve before their parents, and an identifier supplied in one layer can answer a demand in another — so you compose composables, and astichi keeps the wiring and the hygiene consistent the whole way up the tree.
Composables carrying astichi_pyimport(...) markers also have their imports
auto-linked and deduped at materialize, and the materialization plan tracks both
boundary hygiene and managed-import hygiene so independently authored fragments
never silently collide. Full reference:
Assembler Scope.
Native Rust fast path
The target workload is runtime code generation — e.g. a class decorator that
assembles a tailored implementation every time it is applied, across many classes
at import time. Pure-Python AST assembly is too slow to sit on that per-use path,
so astichi ships an optional native engine (_astichi_native_engine, built with
PyO3) that drives the hot generation path in Rust.
When it is present, lower-engine selection defaults to auto and prefers
native Rust for the assembler's batch resolve/apply, keeping occurrence/edge
state in the native engine. When the extension is absent, the exact same API runs
on pure Python — native is an accelerator, never a requirement.
- Release wheels bundle the extension;
pip installfrom sdist compiles it when no matching wheel exists. SetASTICHI_SKIP_NATIVE_BUILD=1for a Python-only install. - Build locally from the repo root with
uv run python native_engine/build.py. engine=pythonremains the differential oracle that the native path is tested against.
See native_engine/README.md
and the perf-refactor notes in
dev-docs/ for the
self-native production boundary.
Maturity
Astichi is a 1.x release backed by a suite of 2,250+ tests — golden
source/plan fixtures, structural snapshots, and integration coverage — run across
CPython 3.12–3.15 and against both the Python and native lower engines, with
engine=python serving as a differential oracle for the Rust path. Behavior is
anchored by those golden and differential tests; the core
compile → build → materialize → emit pipeline is stable, and new surface lands
behind the same test discipline.
In the wild. Astichi is the code-generation engine behind YIDL lifecycle:
~6,400 lines of declarative .yidl across 8 layered concepts compile to 118
reusable templates and 310 match/contribution rules, which the assembler
weaves into ~4,800 lines of generated lifecycle code — all on both axes (one
template, many specialized placements) plus a concept-inheritance layer on top,
driven through AssemblyScope, not by hand. That is the polymorphic, declarative
model above at production scale.
Documentation
| Topic | Doc |
|---|---|
| Docs home | docs/README.md |
| End-to-end guide (compile → emit) | guide/using-the-api.md |
| Reference index | reference/README.md |
| Glossary | reference/glossary.md |
| Public API & submodules | reference/public-api.md |
compile(...) |
reference/compile-api.md |
Composable, emit, materialize |
reference/composable-api.md |
| Builder (fluent + data-driven) | reference/builder-api.md |
Descriptors (describe()) |
reference/descriptor-api.md |
| Markers | reference/marker-overview.md |
| Scoping & hygiene | reference/scoping-hygiene.md |
| Managed imports | reference/marker-pyimport.md |
| Materialize & emit | reference/materialize-and-emit.md |
| Assembler scope (auto-attach) | reference/assembler-scope.md |
| Implementation snapshot & open gaps | dev-docs/AstichiSingleSourceSummary.md |
When astichi is not the right tool
- You want to refactor or rewrite an existing user codebase — astichi composes
generator-authored fragments, it is not a generic
ast.NodeTransformer-style codemod or refactoring framework. - You need a one-off source transform — astichi earns its keep when the same generator runs repeatedly (e.g. a decorator applied across many classes) and ordering, scope, hygiene, and speed all matter at once.
- A plain string template is genuinely enough and none of those concerns are fighting you — you may not need astichi.
Development
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest
Or with uv:
uv run --with pytest pytest -q
Build the native extension (optional): uv run python native_engine/build.py.
License
LGPL-2.1-or-later. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file astichi-1.1.0.tar.gz.
File metadata
- Download URL: astichi-1.1.0.tar.gz
- Upload date:
- Size: 960.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e068c4fe38c52cace183191554bcd51d151916094b4708b305d4dd5dd4828d94
|
|
| MD5 |
c717ae8219723a4d52e875601cd7118c
|
|
| BLAKE2b-256 |
3fe2b884a922a7b26646187d5aa777225ea6db7d088912138e2e71463b65b573
|
Provenance
The following attestation bundles were made for astichi-1.1.0.tar.gz:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0.tar.gz -
Subject digest:
e068c4fe38c52cace183191554bcd51d151916094b4708b305d4dd5dd4828d94 - Sigstore transparency entry: 2007259137
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: astichi-1.1.0-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 5.6 MB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffa9777c473c4ddb231c4bece4ba6efefc84154617b2a89f21f26857e1413483
|
|
| MD5 |
c3857468b9b64d74ec7b322bad240702
|
|
| BLAKE2b-256 |
040a2bdaf9df19560101cf123edf6133cb78c6ab1396e15428f83a50f0775be1
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp314-cp314-win_amd64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp314-cp314-win_amd64.whl -
Subject digest:
ffa9777c473c4ddb231c4bece4ba6efefc84154617b2a89f21f26857e1413483 - Sigstore transparency entry: 2007259473
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: astichi-1.1.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 3.6 MB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0ec189ba2f48e074ce64e9cceb31714b3fd86afd62ea31f2b747dab86d0945e
|
|
| MD5 |
1af388d44e56cea06454210a175ee325
|
|
| BLAKE2b-256 |
7d423057d361f777a401b8e395109b436e9126e82b183dc096d7ef8fbd0c48b4
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp313-cp313-win_amd64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp313-cp313-win_amd64.whl -
Subject digest:
f0ec189ba2f48e074ce64e9cceb31714b3fd86afd62ea31f2b747dab86d0945e - Sigstore transparency entry: 2007259770
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: astichi-1.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e975ab63221844ad6fcdcc5591dbf930351ae9139f2aed60fcd50a4bda56e8b6
|
|
| MD5 |
56dccd2860a3a0498bfe83af9a0b1277
|
|
| BLAKE2b-256 |
5a3d1201a86ce7444eefd19d1b023238c71c8bd177cd3505748bbc424125f095
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp312-cp312-win_amd64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp312-cp312-win_amd64.whl -
Subject digest:
e975ab63221844ad6fcdcc5591dbf930351ae9139f2aed60fcd50a4bda56e8b6 - Sigstore transparency entry: 2007259340
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp312-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: astichi-1.1.0-cp312-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae993384b3a1f72b1e9d2034d897ae04850f20c88d3a3287f7792fea0700ee67
|
|
| MD5 |
73459f70c8d2f459084639c8a8f25a31
|
|
| BLAKE2b-256 |
8056dc9da7a6aa18a7517821b662a8d94a05df4b1715fa4a66be3d6ff000371c
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp312-abi3-manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp312-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
ae993384b3a1f72b1e9d2034d897ae04850f20c88d3a3287f7792fea0700ee67 - Sigstore transparency entry: 2007259229
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp312-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: astichi-1.1.0-cp312-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
052d5dcfe84cc735db0183d7a44c097b4e532b7534b89b6d0804d19416a0385f
|
|
| MD5 |
39de32a0a309300bab09ece1d3134bf3
|
|
| BLAKE2b-256 |
fec434020347b124a2b8caa767c45df6c3dabeb178e36817e001edfdd3a53a9b
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp312-abi3-manylinux_2_28_aarch64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp312-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
052d5dcfe84cc735db0183d7a44c097b4e532b7534b89b6d0804d19416a0385f - Sigstore transparency entry: 2007259574
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: astichi-1.1.0-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
286d0243721c9b60658957402b382b88b5104c8302fd5f208c7b5fec7af706e7
|
|
| MD5 |
eb156706b8e349045b846109c91c3c28
|
|
| BLAKE2b-256 |
d7e99218ee44756b06db3fd761af4b5629e687067c5583786d74d841e7e0268f
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp312-abi3-macosx_11_0_arm64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp312-abi3-macosx_11_0_arm64.whl -
Subject digest:
286d0243721c9b60658957402b382b88b5104c8302fd5f208c7b5fec7af706e7 - Sigstore transparency entry: 2007259678
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type:
File details
Details for the file astichi-1.1.0-cp312-abi3-macosx_10_13_x86_64.whl.
File metadata
- Download URL: astichi-1.1.0-cp312-abi3-macosx_10_13_x86_64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12+, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
742fc8e76d278eaf260a65fc8a57f562f22da69af15052e0e7e0033aac8a87ca
|
|
| MD5 |
9dd571b4c0e0ef3c74c70ab0d55730a7
|
|
| BLAKE2b-256 |
1265bfca90471cf76f5dc9f2ab7603a58b44b731a08360b11d428cb55c61b77a
|
Provenance
The following attestation bundles were made for astichi-1.1.0-cp312-abi3-macosx_10_13_x86_64.whl:
Publisher:
publish.yml on owebeeone/astichi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
astichi-1.1.0-cp312-abi3-macosx_10_13_x86_64.whl -
Subject digest:
742fc8e76d278eaf260a65fc8a57f562f22da69af15052e0e7e0033aac8a87ca - Sigstore transparency entry: 2007259863
- Sigstore integration time:
-
Permalink:
owebeeone/astichi@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/owebeeone
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13518261fd6738fda9d8f02b44721a504e0e5ecf -
Trigger Event:
release
-
Statement type: