Skip to main content

metal-graph

CI

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 with output="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_iter is 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_iter is a budget: scores are returned even when it is exhausted; inspect last_run_info() for the stopping reason.
  • ppr_topk normalizes seed weights, combines duplicate seeds, returns deterministic top-k ordering, and pads with id=-1, score=0 when k > 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_hop returns ascending vertex indices and original input edge IDs. max_vertices and max_edges bound result size, not worst-case runtime, scanned edges, or scratch memory. Use as_graph=True to 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 capped k_hop run 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_hop filters are reserved for a future release; edge_types= and time_range= currently raise NotImplementedError.

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

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)

Table of built distributions (wheels) for metal-graph 0.1.2
File Actions
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 log

Release 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 log

Release 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 log

Release 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 log

Release 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 log

Security 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.

Select from 5 files

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 log

A 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.

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