metal-graph
Fast graph analytics for Apple Silicon.
metal-graph is a Python and C library for ranking, searching, and exploring graphs on a Mac. Build a graph once from NumPy arrays, then run PageRank, HITS hub/authority scoring, batched personalized PageRank, breadth-first search, neighborhood extraction, and connected-components analysis through one consistent API.
The library uses the Metal GPU for work that benefits from it and a threaded CPU path for smaller jobs. That choice is automatic by default, so using metal-graph does not require Metal knowledge or device-management code.
It is particularly useful for:
- knowledge-graph and retrieval pipelines;
- entity ranking, recommendations, and repo maps;
- graph-backed agent memory and neighborhood lookup;
- local analysis of large graphs on Apple Silicon.
Why use metal-graph?
- A small, practical API. Inputs and outputs are NumPy arrays, and integer or string IDs are supported.
- Useful graph operations included. PageRank, HITS, batched PPR with top-k, BFS, sparse BFS, bounded k-hop extraction, and weakly connected components are available today.
- Good performance across different query sizes. Large traversals can use the GPU, while tiny reachable components can stay on the CPU and avoid GPU launch overhead.
- Transparent execution.
mg.last_run_info()reports what ran, where it ran, and how long the engine took. - Tested against established libraries. More than 1,000 Python cases cover correctness, properties, and integration behavior. CI also checks the C API, wheels, and GPU-required jobs.
The main interface is Python (metal_graph, with NumPy input and output).
A stable C API is available in
include/mg.h,
but it is not
bundled into the Python wheel; install it separately from source with CMake.
Requirements
- macOS 14 or newer
- Apple Silicon with an M1 or newer
- CPython 3.10–3.14
Installing a prebuilt wheel does not require a compiler. Building from source, including installing the C API, additionally requires CMake 3.24 or newer and Xcode with the Metal compiler.
Install
Install the prebuilt wheel from PyPI:
python3 -m pip install metal-graph
python3 -c "import metal_graph as mg; print(mg.__version__, mg.has_gpu())"
No compiler or Metal setup is needed for the wheel. Source builds, development setup, native tests, wheel validation, and C API installation are covered in CONTRIBUTING.md.
Quick start
import numpy as np
import metal_graph as mg
# Build an immutable directed graph.
src = np.array([0, 0, 1, 2], dtype=np.uint32)
dst = np.array([1, 2, 2, 3], dtype=np.uint32)
G = mg.Graph.from_edges(
src,
dst,
directed=True,
num_vertices=4,
)
# Rank every vertex.
rank = mg.pagerank(G)
hubs, authorities = mg.hits(G)
# Explore from vertex 0.
dist, parent = mg.bfs(G, sources=[0], direction="out")
vertices, sparse_dist, sparse_parent = mg.bfs(
G,
sources=[0],
direction="out",
output="sparse",
)
neighbors, edge_ids = mg.k_hop(
G,
seeds=[0],
k=2,
direction="both",
)
# Find weakly connected components.
components = mg.experimental.wcc(G)
For a batch of personalized ranking queries, pack the seeds using offsets:
seeds = np.array([0, 2], dtype=np.uint32)
seed_weights = np.ones(2, dtype=np.float32)
seed_offsets = np.array([0, 1, 2], dtype=np.uint64)
ids, scores = mg.ppr_topk(
G,
seeds,
seed_weights,
seed_offsets,
k=4,
)
# ids and scores both have shape (number_of_queries, k)
By default, metal-graph chooses the execution path for each call:
mg.set_execution("auto") # "auto", "gpu", or "cpu"
mg.last_run_info() # op, path, iterations, engine time, HITS status
The
notebooks/
directory contains complete examples for the
core API, batched PPR retrieval, and low-latency BFS.
Available operations
Graph.from_edges(...)builds an immutable weighted or unweighted graph.pagerank(...)returns a score for every vertex.hits(...)returns L1-normalized hub and authority scores.ppr_topk(...)answers a batch of personalized PageRank queries and returns only the highest-scoring vertices.bfs(...)returns dense distances and parents, or compact results withoutput="sparse".k_hop(...)finds a bounded neighborhood and its induced input edges.experimental.wcc(...)labels weakly connected components.
Performance
Unless stated otherwise, the results below were measured on an Apple M4 Max running macOS 26.2. Timings cover the Python call through the returned result, so they include normal API overhead. Lower is better.
Most cells come from source commit a4a8bc; the HippoRAG PPR cell marked ²
comes from the isolated artifact at source commit 7afb4b2. metal-graph
cells are medians of 20 warm calls. External baselines generally use four
timed calls after one warm-up, with additional samples for sub-2 ms BFS
measurements. The full
benchmark report
contains p95 values, package versions, and methodology.
metal-graph latency
| Dataset | PageRank / iteration | ppr_topk B=16, k=64 |
BFS source 0 | WCC |
|---|---|---|---|---|
| RMAT-18 (V=262k, E=4.2M) | 0.35 ms | 10.2 ms | 1.5 ms | 3.8 ms |
| HippoRAG-shape KG (V=100k, E=2M, weighted) | 0.21 ms | 10.707 ms² | 0.012 ms¹ | 4.1 ms |
| RMAT-22 (V=4.2M, E=67M) | 3.4 ms | 122 ms | 13.9 ms | 32.4 ms |
| RMAT-24 (V=16.8M, E=268M) | 14.7 ms | 556 ms | 46.1 ms | 119.8 ms |
| soc-LiveJournal1 (V=4.8M, E=69M) | 4.0 ms | 174 ms | 13.4 ms | 24.9 ms |
| com-orkut (V=3.1M, E=117M) | 7.9 ms | 257 ms | 8.3 ms | 55.9 ms |
HITS on Apple Metal
The focused HITS run used the same Apple M4 Max on macOS 26.6.2, with an
absolute L1 convergence target of 1e-5 and 20 warm calls per implementation.
Every baseline shown below passed a score-agreement check against the fp64
reference. The complete
HITS benchmark report
includes p95 and cold timings, setup costs, package versions, methodology, and
source provenance.
| Dataset | Metal HITS | Matching fp64 CPU | Prebuilt SciPy recurrence | rustworkx public HITS API |
|---|---|---|---|---|
| RMAT-18 (V=262k, E=4.2M) | 2.650 ms | 19.443 ms (7.34×) | 34.881 ms (13.16×) | rustworkx 537.627 ms (202.88×) |
| HippoRAG-shape KG (V=100k, E=2M) | 1.470 ms | 10.376 ms (7.06×) | 3.927 ms (2.67×) | rustworkx 54.275 ms (36.93×) |
SciPy's matrix coalesces the KG's 2.0M repeated input links into 305,667 weighted nonzero positions, while metal-graph retains every parallel link. This gives SciPy a substantial workload advantage on that row and makes its 2.67× result the most conservative comparison.
Comparison with CPU graph libraries
Each cell shows metal-graph vs external median (speedup). These are
end-to-end API comparisons, not claims that every library performs identical
internal work.
The rustworkx BFS adapter returns the same dense dist + parent shape as
metal-graph. PageRank uses the faster completed igraph or rustworkx call for
each dataset, but solver and iteration behavior are not fully normalized.
WCC compares the corresponding operation, although the external libraries
return their native component representation. Treat the PageRank and WCC
ratios as practical API-level context. The recorded versions were rustworkx
0.18.0 and igraph 1.0.0.
| Dataset | PageRank full run | BFS source 0 | WCC |
|---|---|---|---|
| RMAT-18 | 1.759 vs 306.411 ms, rustworkx (174.2×) | 1.538 vs 1,030.735 ms, rustworkx (670.2×) | 3.819 vs 125.525 ms, igraph (32.9×) |
| HippoRAG KG | 3.074 vs 35.893 ms, igraph (11.7×) | 0.012 vs 0.057 ms, rustworkx (4.8×)¹ | 4.090 vs 13.136 ms, igraph (3.2×) |
| RMAT-22 | 16.892 vs 6,346.648 ms, rustworkx (375.7×) | 13.920 vs 17,600.397 ms, rustworkx (1,264.4×) | 32.362 vs 2,173.854 ms, igraph (67.2×) |
| RMAT-24 | 73.464 vs 30,765.861 ms, rustworkx (418.8×) | 46.096 vs 79,206.021 ms, rustworkx (1,718.3×) | 119.823 vs 9,058.173 ms, igraph (75.6×) |
| LiveJournal | 19.773 vs 6,803.438 ms, rustworkx (344.1×) | 13.398 vs 9,417.407 ms, rustworkx (702.9×) | 24.932 vs 1,652.573 ms, igraph (66.3×) |
| Orkut | 39.501 vs 24,247.799 ms, igraph (613.9×) | 8.290 vs 41,158.931 ms, rustworkx (4,965.2×) | 55.942 vs 67.772 ms, igraph (1.21×; below the 2× target) |
Performance varies with the graph and operation. For example, HippoRAG WCC and source-0 BFS measured 3.2× and 4.8× faster, while Orkut WCC measured 1.21×. Using the benchmark's historical gate definitions, 17 of 18 full-run PageRank, high-degree BFS, and WCC cells exceeded the documented 2× target. The source-0 BFS column above is not that exact gate matrix.
Contextual personalized PageRank comparison
The igraph query loop uses PRPACK and cannot be pinned to metal-graph's iteration count. This table is useful end-to-end context, not an identical-work comparison.
| Dataset | metal-graph B=16, k=64 | igraph 16-query loop | Contextual speedup |
|---|---|---|---|
| RMAT-18 | 10.202 ms | 5,972.022 ms | 585.4× |
| HippoRAG KG | 10.707 ms² | 611.357 ms | 57.1× |
| RMAT-22 | 121.993 ms | 106,395.181 ms | 872.1× |
| RMAT-24 | 555.634 ms | 588,510.973 ms | 1,059.2× |
| LiveJournal | 173.635 ms | did not complete after more than six hours | not comparable |
| Orkut | 257.417 ms | skipped after the LiveJournal overrun | not comparable |
Notes for the marked benchmark cells
¹ Tiny-component BFS. Reachable components that fit the serial-path caps
use a bounded serial CPU path. By default the caps are 8,192 vertices and
524,288 scanned edges when the full traversal would otherwise run on the
GPU, and 1,024 vertices and 8,192 edges when it would run on the threaded
CPU. The tiny source-0 component shown here is assessed against a 50 µs
absolute-latency objective rather than a ratio alone; larger traversals that
still fit the caps take longer than that and are not held to it. Dense result
initialization dominates at this scale.
output="sparse" avoids that cost when the traversal fits the configured
caps. Overflow or forced-GPU execution remains exact but materializes dense
state before compaction. The bounded collector still reserves a lazily zeroed
V-byte visited map, so sparse output is not an unconditional
O(|reached|)-memory guarantee. The benchmark records whether the objective
passed but does not fail the command when it is missed.
For the HippoRAG high-degree source, metal-graph measured 1.905 ms on the
GPU versus rustworkx at 50.058 ms (26.3×), under the earlier 1,024-vertex and
8,192-edge serial caps. That source reaches 4,737 vertices through 437,592
scanned edges, which fits the current GPU-fallback defaults, so auto mode
now answers it on the serial CPU path; that has not yet been re-measured with
the benchmark harness. mg.set_execution("gpu") still exercises the GPU.
² Isolated HippoRAG PPR measurement. The displayed values come from a clean-process, 20-run artifact: JSON · rendered report. It measured 10.707 ms per batch (p95 10.922), or 0.669 ms/query. That meets the 0.7 ms/query objective and misses the 10 ms batch objective by 7%.
This measurement supersedes the interrupted full-suite run's anomalous
15.116 ms reading, which carried a 3.3 ms python_boundary residue unique to
that collection window. The same artifact measured high-degree BFS at
1.857 ms versus igraph at 2.321 ms (1.25×) and rustworkx at 49.334 ms
(26.6×), using the corrected equivalent-output adapter. That GPU-path
reading also predates the current serial BFS caps (see note ¹).
Benchmark provenance and comparison caveats
The run's original igraph BFS rows predate the corrected dense-output adapter and are excluded as non-equivalent. The current harness contains the corrected adapter but needs a new physical rerun. SciPy and NetworkX comparisons remain in the full artifacts and benchmark report.
The Orkut results have a strict checked-in JSON and rendered report pair. Completed rows for RMAT-18 through LiveJournal were reconstructed from the preserved run log and remain provisional. The original run was interrupted before its final JSON was written; LiveJournal's contextual PPR comparison did not complete.
These are workload-specific measurements from one machine, not a blanket GPU-speedup claim. Orkut's rustworkx PageRank call failed on the undirected graph, leaving igraph as its completed comparator.
How execution is chosen
mode="auto" is intended for normal use. The planner starts with the GPU
when a Metal device is available and the graph has at least a per-operation
number of stored edges: one million for pagerank (including personalized
PageRank), hits, ppr_topk, bfs, and wcc;
otherwise it starts with the CPU. By default, k_hop starts with the CPU at
every size; MG_E_GPU_MIN_KHOP or MG_E_GPU_MIN can override that default.
Its induced-edge extraction runs on the host on either path. Individual
algorithms can override the planner's candidate when another path is more
appropriate.
PageRank and HITS retain their original fp64 CPU arithmetic below one million stored edges. Lowering their GPU thresholds explicitly opts into fp32 GPU arithmetic, changing the precision of the computation.
BFS, for example, first tries a bounded serial traversal. If the reachable component fits within its vertex and scanned-edge caps, the CPU answers the query directly. If it does not fit, the partial attempt is discarded and the regular CPU or GPU path runs instead. Each reached vertex's adjacency is charged against the edge cap when the vertex is discovered, so an attempt that cannot fit is usually abandoned early. The caps are larger when the fallback is the GPU than when it is the threaded CPU path.
ppr_topk applies the same idea per query. When the vertices reachable
from a query's seeds along outgoing edges fit within the vertex and
scanned-edge caps, every other vertex has an exact score of zero, so the CPU
solves that query exactly in fp64 on the reachable set alone, with the same
summation order (including the fixed 16,384-edge tiles of rows with that many
incoming edges), audit rule, and tie order as the full CPU path. Dropping the
unreachable zero-contribution edges therefore preserves the dense result
exactly. To locate those tiles, the first auto- or CPU-mode ppr_topk
call on a directed graph builds a small cached index of the large rows'
tile boundaries (up to three parallel passes over the edges). Queries that
do not fit run on the planned CPU or GPU path; in a mixed batch only those
rows go to the GPU, so their scores carry the usual GPU float32 tolerance
while the others are fp64. last_run_info() reports path="cpu" when every
query in the batch was answered this way, and the planned path otherwise.
Forced GPU mode skips the attempt.
You can override the planner when testing or profiling:
mg.set_execution("gpu") # require the GPU path
mg.set_execution("cpu") # require the CPU path
mg.set_execution("auto") # restore automatic selection
mg.last_run_info() returns a snapshot of the last recorded algorithm run
on the calling thread, including its chosen path, iteration count,
and engine time. After HITS, it also distinguishes convergence from exhaustion
of the iteration budget:
hubs, authorities = mg.hits(G, tol=1e-5, max_iter=100)
info = mg.last_run_info() # Read before running another algorithm.
if info["stop_reason"] == "max_iter":
print("Iteration budget reached; scores may need more iterations.")
print(info["converged"], info["stop_reason"], info["final_delta_l1"])
converged is a boolean for HITS, stop_reason is "converged",
"max_iter", or "empty_graph", and final_delta_l1 is the last measured
L1 change in the hub vector. Other operations, and the initial state before
an operation, report None, "not_applicable", and None respectively;
these fields do not report PageRank or PPR convergence. A later recorded
run replaces the current metadata, but a previously returned dictionary
remains unchanged. The C API exposes the same status through
mg_last_run_convergence(); see the
C example.
Forced GPU mode raises an error if no device is available.
Advanced environment settings
GPU BFS batches increasing numbers of levels (8, 8, 16, 32, then 64) to keep shallow traversals responsive while reducing host round-trips on deep graphs.
| Variable | Default | Meaning |
|---|---|---|
MG_E_GPU_MIN |
unset (per-op defaults) | auto-planner GPU threshold (stored edges); when set, applies to every operation |
MG_E_GPU_MIN_<OP> |
PAGERANK/HITS/PPR/BFS/WCC 1000000; KHOP never |
per-operation threshold; takes precedence over MG_E_GPU_MIN; lowering numeric-operation thresholds opts into fp32 GPU arithmetic |
MG_PR_AUDIT_INTERVAL |
5 | iterations per GPU command batch / fp64 audit |
MG_HITS_AUDIT_INTERVAL |
5 | HITS iterations per GPU command batch / fp64 audit |
MG_BFS_LEVELS_PER_BATCH |
adaptive 8,8,16,32,64… | BFS levels per command buffer; an integer pins a fixed size (clamped 1–256) |
MG_BFS_SPARSE_MAX_VERTICES |
8192 if the fallback is the GPU, else 1024 | auto/CPU BFS latency-path vertex cap (0 disables) |
MG_BFS_SPARSE_MAX_EDGES |
524288 if the fallback is the GPU, else 8192 | auto/CPU BFS latency-path scanned-edge cap (0 disables) |
MG_PPR_SPARSE_MAX_VERTICES |
1024 | auto/CPU ppr_topk per-query reachable-set vertex cap (0 disables) |
MG_PPR_SPARSE_MAX_EDGES |
8192 | auto/CPU ppr_topk per-query scanned-edge cap (0 disables) |
MG_WCC_ROUNDS_PER_BATCH |
— | ignored: GPU WCC runs one fixed sequence of union-find passes (sample, snapshot, link, compress) in a single command buffer |
MG_WCC_CPU_PAR_MIN_EDGES |
65536 | CPU WCC uses the threaded union-find at or above this many stored edges (serial below it, or when MG_THREADS=1) |
MG_GPU_TOPK |
1 | GPU radix-select for ppr_topk (0 = CPU oracle) |
MG_BFS_BOTTOMUP |
1 | direction-optimizing bottom-up switch |
MG_BFS_HIGH_SPLIT_MAX |
64 | GPU BFS: max threadgroups per high-degree frontier vertex (1 = unsplit; clamped 1–1024) |
MG_REQUIRE_GPU |
0 | hard-fail when no Metal device |
MG_FORCE_CPU |
0 | disable the GPU entirely |
MG_THREADS |
all cores | CPU-path thread count (the caller plus persistent pool workers; values above 257 use 256 workers) |
MG_METALLIB |
embedded | override path to a .metallib (dev loop) |
MG_DEBUG_POISON_SCRATCH |
0 | debug: fill uninitialized GPU scratch buffers with 0xFF bytes (NaN) so reads of unwritten elements surface |
Graph IDs and result behavior
External integer or string IDs are mapped to dense user indices in
np.unique order. Algorithm inputs and outputs use those user indices.
Use G.index_of(ids) to map external IDs to indices and
G.external_ids[index] to map back. G.external_ids returns a detached,
read-only NumPy snapshot, so changing a caller-owned copy cannot alter the
graph's ID mapping.
Graphs are immutable after construction. Duplicate edges and self-loops are
kept, and PageRank counts them. Non-finite or negative weights are rejected.
Undirected graphs are symmetrized internally, while G.num_edges continues
to report the number of input edges.
The most important result conventions are:
- PageRank follows NetworkX-compatible weighted normalization and dangling
mass handling.
max_iteris a budget: metal-graph returns the current result when it is reached, while NetworkX raises. - HITS returns
(hubs, authorities)with separate L1-normalized float32 vectors. It ignores edge weights, counts parallel edges separately, and returns zeros for edgeless graphs.max_iteris a budget: scores are returned even when it is exhausted; inspectlast_run_info()for the stopping reason. ppr_topknormalizes seed weights, combines duplicate seeds, returns deterministic top-k ordering, and pads withid=-1, score=0whenk > V.- BFS supports
direction="out","in", or"both". Unreachable distances and missing parents are-1. Parent choice can vary when several same-depth parents are valid on a parallel path. - Sparse BFS returns aligned
(vertices, dist, parent)arrays in ascending user-index order. k_hopreturns ascending vertex indices and original input edge IDs.max_verticesandmax_edgesbound result size, not worst-case runtime, scanned edges, or scratch memory. Useas_graph=Trueto materialize the returned neighborhood as a new graph.- WCC treats directed edges as undirected and numbers components by their first appearance in user-index order.
Version 0.1.2 changes CPU floating-point summation: PageRank and PPR scores can differ from 0.1.1 in the last float32 bit, and PPR near-ties can change order. Large adjacency rows can also change HITS scores through tiled fp64 summation. These ranking results remain deterministic across CPU thread counts; see the 0.1.2 release notes for details.
Exact PageRank convergence behavior
Convergence is L1(r_new - r_old) < V * tol, audited in fp64 every
MG_PR_AUDIT_INTERVAL iterations. Iteration counts therefore land on audit
boundaries. Batched PPR queries converge independently and freeze at those
boundaries. Top-k ties are resolved by ascending user index.
Exact HITS convergence behavior
Starting from uniform hubs, HITS alternates authority = A.T @ hubs and
hubs = A @ authority, L1-normalizing after each multiplication. Convergence
is L1(hubs_new - hubs_old) < V * tol, audited every
MG_HITS_AUDIT_INTERVAL iterations (default 5) and on the final allowed
iteration. final_delta_l1 reports this hub change, not a spectral residual.
Convergence on the final allowed iteration is reported as "converged",
even when iterations == max_iter; otherwise exhausting the budget reports
converged=False and stop_reason="max_iter".
For empty or edgeless graphs, HITS returns zero scores with converged=True,
stop_reason="empty_graph", final_delta_l1=0.0, and zero iterations. This
is a convention for the trivial result rather than an iterative convergence
test.
Current limits
- The library currently supports
V, E < 2^31; graph values are fp32 and graph IDs are int32 internally. - Graphs are immutable snapshots rather than streaming or mutable graphs.
- HITS materializes and caches the reverse CSR for directed graphs, so its first call adds a second adjacency-sized structure to the graph snapshot.
direction="both"BFS on directed graphs and cappedk_hoprun on the deterministic CPU path.- Batched GPU PPR keeps the CSR plus an eight-query tile in memory. The
dominant tile state uses roughly 100 bytes per vertex. Oversized workloads
raise a descriptive working-set error;
mode="cpu"avoids that GPU limit. - GPU top-k selection uses its bit-identical CPU fallback for tiny graphs
(
V < 4096),k >= V,k > 4096, and degenerate tie floods. - Typed and temporal
k_hopfilters are reserved for a future release;edge_types=andtime_range=currently raiseNotImplementedError.
Benchmarks and reproducibility
bench/run.py --suite v01 runs the full matrix against igraph, rustworkx,
SciPy, and NetworkX. It uses synthetic RMAT and knowledge-graph-shaped data
plus SHA-pinned SNAP datasets, which are downloaded only with --fetch.
See the
benchmark guide
for commands and artifact format.
New published performance claims require a matched, checked-in JSON and rendered-report pair from a physical run. The disclosed exception is the reconstructed RMAT-18 through LiveJournal data described above; only Orkut has a matched pair for the later full-suite values.
Project resources
- Example notebooks
- Benchmark guide
- Contribution and development guide
- C API
- v0.1 implementation and design rationale
Roadmap
Possible future additions include label propagation, core number, similarity top-k, typed and temporal neighborhood filters, MLX device-resident results, and a NetworkX backend preview. Louvain and Leiden community detection are longer-term candidates.
License
Apache-2.0 (LICENSE). The vendored metal-cpp library is Apache-2.0, © Apple Inc.; see THIRD_PARTY_NOTICES.md.
Metadata
Release files for metal-graph 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| metal_graph-0.1.2-cp314-cp314-macosx_14_0_arm64.whl | CPython 3.14 | CPython 3.14 | macOS 14.0+ ARM64 | Details for metal_graph-0.1.2-cp314-cp314-macosx_14_0_arm64.whl |
| metal_graph-0.1.2-cp313-cp313-macosx_14_0_arm64.whl | CPython 3.13 | CPython 3.13 | macOS 14.0+ ARM64 | Details for metal_graph-0.1.2-cp313-cp313-macosx_14_0_arm64.whl |
| metal_graph-0.1.2-cp312-cp312-macosx_14_0_arm64.whl | CPython 3.12 | CPython 3.12 | macOS 14.0+ ARM64 | Details for metal_graph-0.1.2-cp312-cp312-macosx_14_0_arm64.whl |
| metal_graph-0.1.2-cp311-cp311-macosx_14_0_arm64.whl | CPython 3.11 | CPython 3.11 | macOS 14.0+ ARM64 | Details for metal_graph-0.1.2-cp311-cp311-macosx_14_0_arm64.whl |
| metal_graph-0.1.2-cp310-cp310-macosx_14_0_arm64.whl | CPython 3.10 | CPython 3.10 | macOS 14.0+ ARM64 | Details for metal_graph-0.1.2-cp310-cp310-macosx_14_0_arm64.whl |
Total release size: 1.5 MB
Release files / metal_graph-0.1.2-cp314-cp314-macosx_14_0_arm64.whl
| Download URL | metal_graph-0.1.2-cp314-cp314-macosx_14_0_arm64.whl |
|---|---|
| Size | 298.5 kB |
| Tags | CPython 3.14 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
cc7c46dd80004e2bffc218971d5e8e56cce628a2cb6bbae085e77f57bcb1f51b
|
|
BLAKE2b-256 checksum How to use checksums |
65b4af84edf2465cf28c5429b76b3435bebd134c316b11fbd5012d20719603bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / metal_graph-0.1.2-cp313-cp313-macosx_14_0_arm64.whl
| Download URL | metal_graph-0.1.2-cp313-cp313-macosx_14_0_arm64.whl |
|---|---|
| Size | 298.4 kB |
| Tags | CPython 3.13 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
4f07795a3203d0e2342450c72a059f6621b769f774b1fdc6c2ed8a3bea4e0f8a
|
|
BLAKE2b-256 checksum How to use checksums |
76db16311fc8dffb99dea322d218b3a6c61bff5a61e61a5232dbbcb1018fadee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / metal_graph-0.1.2-cp312-cp312-macosx_14_0_arm64.whl
| Download URL | metal_graph-0.1.2-cp312-cp312-macosx_14_0_arm64.whl |
|---|---|
| Size | 298.5 kB |
| Tags | CPython 3.12 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
8dd17efdda6204ad54d98c302f48453d0f6e7c52c16f2f47ef58e8be20a17bea
|
|
BLAKE2b-256 checksum How to use checksums |
7b287f89a7c672707b366fa49d8c2f4bfc3e808f041a98ffc9e3b89df1df115b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / metal_graph-0.1.2-cp311-cp311-macosx_14_0_arm64.whl
| Download URL | metal_graph-0.1.2-cp311-cp311-macosx_14_0_arm64.whl |
|---|---|
| Size | 299.5 kB |
| Tags | CPython 3.11 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b02320186ef4a9cbf2f6285cee962bcf16e89f46043b854c9f39e7c0fe5a9447
|
|
BLAKE2b-256 checksum How to use checksums |
30adceba7f45946011c445b4b9dca41c19d5865422311743aedbe4615188609e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / metal_graph-0.1.2-cp310-cp310-macosx_14_0_arm64.whl
| Download URL | metal_graph-0.1.2-cp310-cp310-macosx_14_0_arm64.whl |
|---|---|
| Size | 299.8 kB |
| Tags | CPython 3.10 macOS 14.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
fe054247ec0ed395047da48ef25d7fe2db9c21adb4873dfaea5ccf38964044df
|
|
BLAKE2b-256 checksum How to use checksums |
941a41b9be58b870c582f46cf4e91207f73a867b16d834199021653e2af34f26
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for metal-graph 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 5 files in this release have been uploaded with provenance metadata.
Attestation for metal_graph-0.1.2-cp314-cp314-macosx_14_0_arm64.whl
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.