hypergraphz 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ /zig-*
2
+ /.zig-*
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.so
8
+ *.dylib
9
+ *.dll
10
+ /dist/
11
+ /wheelhouse/
12
+ /.venv/
13
+ *.egg-info/
@@ -0,0 +1,19 @@
1
+ Copyright (c) Davy Duperron
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: hypergraphz
3
+ Version: 0.1.5
4
+ Summary: Python bindings for the HypergraphZ hypergraph library
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+
10
+ # HypergraphZ - A Hypergraph Implementation in Zig
11
+
12
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/yamafaktory/hypergraphz/ci.yml?branch=main&style=flat-square)
13
+
14
+ HypergraphZ is a directed hypergraph implementation in Zig (https://en.wikipedia.org/wiki/Hypergraph):
15
+
16
+ - Each hyperedge can contain zero, one (unary) or multiple vertices.
17
+ - Each hyperedge can contain vertices directed to themselves one or more times.
18
+
19
+ ---
20
+
21
+ ## For Python users
22
+
23
+ ### Installation
24
+
25
+ ```sh
26
+ pip install hypergraphz
27
+ # or with uv
28
+ uv add hypergraphz
29
+ ```
30
+
31
+ Pre-built wheels are available for Linux (x86\_64, aarch64), macOS (x86\_64, arm64), and Windows (x86\_64).
32
+
33
+ ### Quick start
34
+
35
+ ```python
36
+ from hypergraphz import Hypergraph
37
+
38
+ g = Hypergraph()
39
+
40
+ # Add vertices and hyperedges
41
+ alice = g.add_vertex({"name": "alice", "age": 30})
42
+ bob = g.add_vertex({"name": "bob", "age": 25})
43
+ carol = g.add_vertex({"name": "carol", "age": 35})
44
+
45
+ collab = g.add_hyperedge({"type": "project"})
46
+ g.connect(collab, [alice, bob, carol])
47
+
48
+ # Build the reverse index before querying
49
+ g.build()
50
+
51
+ # Shortest path
52
+ path = g.shortest_path(alice, carol)
53
+
54
+ # Fluent query builders
55
+ active = (
56
+ g.vertices()
57
+ .where(lambda d: d["age"] > 28)
58
+ .data()
59
+ )
60
+
61
+ # Structural algorithms
62
+ scores, _, _ = g.page_rank()
63
+ centrality = g.centrality()
64
+ components = g.connected_components()
65
+
66
+ # Sub-graph operations return independent Hypergraph objects
67
+ sub = g.vertex_induced_subgraph([alice, bob])
68
+ dual = g.dual()
69
+ ```
70
+
71
+ ### API summary
72
+
73
+ | Category | Methods |
74
+ |---|---|
75
+ | Lifecycle | `build()`, `clear()`, `save()`, `load()`, `clone()` |
76
+ | Vertices | `add_vertex()`, `get_vertex()`, `update_vertex()`, `delete_vertex()`, `vertex_count()`, `all_vertex_ids()` |
77
+ | Hyperedges | `add_hyperedge()`, `get_hyperedge()`, `update_hyperedge()`, `delete_hyperedge()`, `hyperedge_count()`, `all_hyperedge_ids()` |
78
+ | Relations | `connect()`, `prepend()`, `insert_vertex()`, `insert_many()`, `disconnect()`, `disconnect_at()` |
79
+ | Degree | `vertex_indegree()`, `vertex_outdegree()` |
80
+ | Queries | `hyperedge_vertices()`, `vertex_hyperedges()`, `neighborhood()`, `intersections()`, `hyperedges_connecting()`, `endpoints()`, `orphan_vertices()`, `orphan_hyperedges()` |
81
+ | Boolean | `is_connected()`, `is_reachable()`, `has_cycle()`, `is_k_uniform()` |
82
+ | Traversal | `shortest_path()`, `all_paths()`, `bfs()`, `dfs()`, `random_walk()` |
83
+ | Algorithms | `connected_components()`, `topological_sort()`, `cut_vertices()`, `centrality()`, `page_rank()`, `inclusions()`, `nestedness_profile()` |
84
+ | Matrices | `incidence_matrix()`, `incidence_matrix_coo()`, `laplacian()` |
85
+ | Sub-graphs | `dual()`, `k_skeleton()`, `vertex_induced_subgraph()`, `edge_induced_subgraph()`, `core()`, `expand_to_graph()`, `expand_to_star()`, `line_graph()`, `transitive_closure()` |
86
+ | Fluent builders | `vertices()` → `VertexQuery`, `hyperedges()` → `HyperedgeQuery` |
87
+
88
+ ### Exceptions
89
+
90
+ All errors map to typed exceptions from `hypergraphz`:
91
+
92
+ | Exception | When raised |
93
+ |---|---|
94
+ | `NotBuiltError` | Query requires `build()` first |
95
+ | `VertexNotFoundError` | Vertex ID does not exist |
96
+ | `HyperedgeNotFoundError` | Hyperedge ID does not exist |
97
+ | `CycleDetectedError` | Operation requires a DAG |
98
+ | `NoPathError` | No directed path exists |
99
+ | `IndexOutOfBoundsError` | Insertion index out of range |
100
+ | `NotEnoughVerticesError` | Operation needs more vertices |
101
+
102
+ ---
103
+
104
+ ## For Zig users
105
+
106
+ ### Zig version
107
+
108
+ HypergraphZ currently requires **Zig 0.17.0-dev.242+5d55999d2**.
109
+
110
+ ### Usage
111
+
112
+ Add `hypergraphz` as a dependency to your `build.zig.zon`:
113
+
114
+ ```sh
115
+ zig fetch --save https://github.com/yamafaktory/hypergraphz/archive/v0.1.0.tar.gz
116
+ ```
117
+
118
+ Add `hypergraphz` as a dependency to your `build.zig`:
119
+
120
+ ```zig
121
+ const hypergraphz = b.dependency("hypergraphz", .{
122
+ .target = target,
123
+ .optimize = optimize,
124
+ });
125
+ exe.root_module.addImport("hypergraphz", hypergraphz.module("hypergraphz"));
126
+ ```
127
+
128
+ ### Example
129
+
130
+ `examples/coauthorship.zig` models a small research community as a directed hypergraph
131
+ where vertices are researchers and hyperedges are papers. The first listed author is
132
+ treated as the corresponding author, giving each hyperedge a natural direction.
133
+
134
+ ```
135
+ zig build example
136
+ ```
137
+
138
+ It walks through seventeen features of the library in sequence:
139
+
140
+ | Section | API | What it shows |
141
+ | ------------------------ | ------------------------ | ------------------------------------------------------------ |
142
+ | Papers per researcher | `getVertexHyperedges` | reverse-index query |
143
+ | Research communities | `getConnectedComponents` | two isolated groups with no cross-group papers |
144
+ | Betweenness centrality | `computeCentrality` | which researchers bridge the most collaboration paths |
145
+ | Degrees of separation | `findShortestPath` | 1–3 hops within a community; unreachable across communities |
146
+ | Dual: paper-centric view | `getDual` | swap vertices ↔ hyperedges to see each researcher's papers |
147
+ | Shared authorship | `getIntersections` | researchers present on every paper in a given set |
148
+ | Seniority ordering | `topologicalSort` | hierarchy implied by the authorship direction |
149
+ | Pairwise expansion | `expandToGraph` | 6 papers encode 11 directed pairs in a regular graph |
150
+ | Spectral view | `toLaplacian` | normalized Laplacian; block-diagonal under disjoint groups |
151
+ | PageRank | `computePageRank` | citation-weighted stationary distribution; sums to 1 |
152
+ | Random walk | `randomWalk` | seeded weighted walk; stays inside the start's component |
153
+ | Star expansion | `expandToStar` | bipartite (researcher ↔ paper) projection; 2-uniform |
154
+ | Line graph | `getLineGraph` | papers as vertices, linked when they share an author |
155
+ | K-core decomposition | `getCore` | (s, t)-core peeling; trims the lone-paper researcher |
156
+ | Nestedness | `getInclusions` | strict-subset pairs across hyperedges; sized profile |
157
+ | Co-author neighborhoods | `getVertexNeighborhood` | undirected co-occurrence neighbors across all hyperedges |
158
+
159
+ ---
160
+
161
+ ## Documentation
162
+
163
+ The latest online documentation can be found [here](https://yamafaktory.github.io/hypergraphz/).
@@ -0,0 +1,154 @@
1
+ # HypergraphZ - A Hypergraph Implementation in Zig
2
+
3
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/yamafaktory/hypergraphz/ci.yml?branch=main&style=flat-square)
4
+
5
+ HypergraphZ is a directed hypergraph implementation in Zig (https://en.wikipedia.org/wiki/Hypergraph):
6
+
7
+ - Each hyperedge can contain zero, one (unary) or multiple vertices.
8
+ - Each hyperedge can contain vertices directed to themselves one or more times.
9
+
10
+ ---
11
+
12
+ ## For Python users
13
+
14
+ ### Installation
15
+
16
+ ```sh
17
+ pip install hypergraphz
18
+ # or with uv
19
+ uv add hypergraphz
20
+ ```
21
+
22
+ Pre-built wheels are available for Linux (x86\_64, aarch64), macOS (x86\_64, arm64), and Windows (x86\_64).
23
+
24
+ ### Quick start
25
+
26
+ ```python
27
+ from hypergraphz import Hypergraph
28
+
29
+ g = Hypergraph()
30
+
31
+ # Add vertices and hyperedges
32
+ alice = g.add_vertex({"name": "alice", "age": 30})
33
+ bob = g.add_vertex({"name": "bob", "age": 25})
34
+ carol = g.add_vertex({"name": "carol", "age": 35})
35
+
36
+ collab = g.add_hyperedge({"type": "project"})
37
+ g.connect(collab, [alice, bob, carol])
38
+
39
+ # Build the reverse index before querying
40
+ g.build()
41
+
42
+ # Shortest path
43
+ path = g.shortest_path(alice, carol)
44
+
45
+ # Fluent query builders
46
+ active = (
47
+ g.vertices()
48
+ .where(lambda d: d["age"] > 28)
49
+ .data()
50
+ )
51
+
52
+ # Structural algorithms
53
+ scores, _, _ = g.page_rank()
54
+ centrality = g.centrality()
55
+ components = g.connected_components()
56
+
57
+ # Sub-graph operations return independent Hypergraph objects
58
+ sub = g.vertex_induced_subgraph([alice, bob])
59
+ dual = g.dual()
60
+ ```
61
+
62
+ ### API summary
63
+
64
+ | Category | Methods |
65
+ |---|---|
66
+ | Lifecycle | `build()`, `clear()`, `save()`, `load()`, `clone()` |
67
+ | Vertices | `add_vertex()`, `get_vertex()`, `update_vertex()`, `delete_vertex()`, `vertex_count()`, `all_vertex_ids()` |
68
+ | Hyperedges | `add_hyperedge()`, `get_hyperedge()`, `update_hyperedge()`, `delete_hyperedge()`, `hyperedge_count()`, `all_hyperedge_ids()` |
69
+ | Relations | `connect()`, `prepend()`, `insert_vertex()`, `insert_many()`, `disconnect()`, `disconnect_at()` |
70
+ | Degree | `vertex_indegree()`, `vertex_outdegree()` |
71
+ | Queries | `hyperedge_vertices()`, `vertex_hyperedges()`, `neighborhood()`, `intersections()`, `hyperedges_connecting()`, `endpoints()`, `orphan_vertices()`, `orphan_hyperedges()` |
72
+ | Boolean | `is_connected()`, `is_reachable()`, `has_cycle()`, `is_k_uniform()` |
73
+ | Traversal | `shortest_path()`, `all_paths()`, `bfs()`, `dfs()`, `random_walk()` |
74
+ | Algorithms | `connected_components()`, `topological_sort()`, `cut_vertices()`, `centrality()`, `page_rank()`, `inclusions()`, `nestedness_profile()` |
75
+ | Matrices | `incidence_matrix()`, `incidence_matrix_coo()`, `laplacian()` |
76
+ | Sub-graphs | `dual()`, `k_skeleton()`, `vertex_induced_subgraph()`, `edge_induced_subgraph()`, `core()`, `expand_to_graph()`, `expand_to_star()`, `line_graph()`, `transitive_closure()` |
77
+ | Fluent builders | `vertices()` → `VertexQuery`, `hyperedges()` → `HyperedgeQuery` |
78
+
79
+ ### Exceptions
80
+
81
+ All errors map to typed exceptions from `hypergraphz`:
82
+
83
+ | Exception | When raised |
84
+ |---|---|
85
+ | `NotBuiltError` | Query requires `build()` first |
86
+ | `VertexNotFoundError` | Vertex ID does not exist |
87
+ | `HyperedgeNotFoundError` | Hyperedge ID does not exist |
88
+ | `CycleDetectedError` | Operation requires a DAG |
89
+ | `NoPathError` | No directed path exists |
90
+ | `IndexOutOfBoundsError` | Insertion index out of range |
91
+ | `NotEnoughVerticesError` | Operation needs more vertices |
92
+
93
+ ---
94
+
95
+ ## For Zig users
96
+
97
+ ### Zig version
98
+
99
+ HypergraphZ currently requires **Zig 0.17.0-dev.242+5d55999d2**.
100
+
101
+ ### Usage
102
+
103
+ Add `hypergraphz` as a dependency to your `build.zig.zon`:
104
+
105
+ ```sh
106
+ zig fetch --save https://github.com/yamafaktory/hypergraphz/archive/v0.1.0.tar.gz
107
+ ```
108
+
109
+ Add `hypergraphz` as a dependency to your `build.zig`:
110
+
111
+ ```zig
112
+ const hypergraphz = b.dependency("hypergraphz", .{
113
+ .target = target,
114
+ .optimize = optimize,
115
+ });
116
+ exe.root_module.addImport("hypergraphz", hypergraphz.module("hypergraphz"));
117
+ ```
118
+
119
+ ### Example
120
+
121
+ `examples/coauthorship.zig` models a small research community as a directed hypergraph
122
+ where vertices are researchers and hyperedges are papers. The first listed author is
123
+ treated as the corresponding author, giving each hyperedge a natural direction.
124
+
125
+ ```
126
+ zig build example
127
+ ```
128
+
129
+ It walks through seventeen features of the library in sequence:
130
+
131
+ | Section | API | What it shows |
132
+ | ------------------------ | ------------------------ | ------------------------------------------------------------ |
133
+ | Papers per researcher | `getVertexHyperedges` | reverse-index query |
134
+ | Research communities | `getConnectedComponents` | two isolated groups with no cross-group papers |
135
+ | Betweenness centrality | `computeCentrality` | which researchers bridge the most collaboration paths |
136
+ | Degrees of separation | `findShortestPath` | 1–3 hops within a community; unreachable across communities |
137
+ | Dual: paper-centric view | `getDual` | swap vertices ↔ hyperedges to see each researcher's papers |
138
+ | Shared authorship | `getIntersections` | researchers present on every paper in a given set |
139
+ | Seniority ordering | `topologicalSort` | hierarchy implied by the authorship direction |
140
+ | Pairwise expansion | `expandToGraph` | 6 papers encode 11 directed pairs in a regular graph |
141
+ | Spectral view | `toLaplacian` | normalized Laplacian; block-diagonal under disjoint groups |
142
+ | PageRank | `computePageRank` | citation-weighted stationary distribution; sums to 1 |
143
+ | Random walk | `randomWalk` | seeded weighted walk; stays inside the start's component |
144
+ | Star expansion | `expandToStar` | bipartite (researcher ↔ paper) projection; 2-uniform |
145
+ | Line graph | `getLineGraph` | papers as vertices, linked when they share an author |
146
+ | K-core decomposition | `getCore` | (s, t)-core peeling; trims the lone-paper researcher |
147
+ | Nestedness | `getInclusions` | strict-subset pairs across hyperedges; sized profile |
148
+ | Co-author neighborhoods | `getVertexNeighborhood` | undirected co-occurrence neighbors across all hyperedges |
149
+
150
+ ---
151
+
152
+ ## Documentation
153
+
154
+ The latest online documentation can be found [here](https://yamafaktory.github.io/hypergraphz/).
@@ -0,0 +1,134 @@
1
+ const std = @import("std");
2
+ const HypergraphZPath = "src/hypergraphz.zig";
3
+ const BenchPath = "bench/main.zig";
4
+ const TestRootPath = "tests/root.zig";
5
+ const CAbiPath = "src/hgz_c_api.zig";
6
+
7
+ pub fn build(b: *std.Build) void {
8
+ const target = b.standardTargetOptions(.{});
9
+ const optimize = b.standardOptimizeOption(.{});
10
+ const root_source_file = b.path(HypergraphZPath);
11
+
12
+ const root_module = b.addModule("hypergraphz", .{
13
+ .root_source_file = root_source_file,
14
+ .target = target,
15
+ .optimize = optimize,
16
+ });
17
+
18
+ const test_module = b.createModule(.{
19
+ .root_source_file = b.path(TestRootPath),
20
+ .imports = &.{.{ .name = "hypergraphz", .module = root_module }},
21
+ .target = target,
22
+ .optimize = optimize,
23
+ });
24
+
25
+ // Creates a step for unit testing. This only builds the test executable
26
+ // but does not run it.
27
+ const unit_tests = b.addTest(.{
28
+ .root_module = test_module,
29
+ });
30
+
31
+ const run_lib_unit_tests = b.addRunArtifact(unit_tests);
32
+
33
+ // Disable cache for unit tests to get logs.
34
+ // https://ziggit.dev/t/how-to-enable-more-logging-and-disable-caching-with-zig-build-test/2654/11
35
+ run_lib_unit_tests.has_side_effects = true;
36
+
37
+ // Similar to creating the run step earlier, this exposes a `test` step to
38
+ // the `zig build --help` menu, providing a way for the user to request
39
+ // running the unit tests.
40
+ // Notes:
41
+ // - `zig build test -Doptimize=ReleaseFast` to run the unit tests in release-fast mode.
42
+ const test_step = b.step("test", "Run unit tests");
43
+ test_step.dependOn(&run_lib_unit_tests.step);
44
+
45
+ // Generate docs step.
46
+ const docs_step = b.step("docs", "Build the HypergraphZ docs");
47
+ const docs_obj = b.addObject(.{
48
+ .name = "HypergraphZ",
49
+ .root_module = b.createModule(.{
50
+ .root_source_file = root_source_file,
51
+ .target = target,
52
+ .optimize = optimize,
53
+ }),
54
+ });
55
+ const docs = docs_obj.getEmittedDocs();
56
+ docs_step.dependOn(&b.addInstallDirectory(.{
57
+ .source_dir = docs,
58
+ .install_dir = .prefix,
59
+ .install_subdir = "docs",
60
+ }).step);
61
+
62
+ // Format step.
63
+ const fmt_step = b.step("fmt", "Format all source files");
64
+ const fmt = b.addFmt(.{
65
+ .paths = &.{ HypergraphZPath, "bench", "build.zig", "tests", "examples" },
66
+ });
67
+ fmt_step.dependOn(&fmt.step);
68
+
69
+ // Check step used by the zls configuration.
70
+ const check_step = b.step("check", "Check if HypergraphZ compiles");
71
+ const check = b.addTest(.{
72
+ .root_module = test_module,
73
+ });
74
+ check_step.dependOn(&check.step);
75
+ const bench_check = b.addExecutable(.{
76
+ .name = "bench",
77
+ .root_module = b.createModule(.{
78
+ .root_source_file = b.path(BenchPath),
79
+ .target = target,
80
+ .optimize = optimize,
81
+ .imports = &.{.{ .name = "hypergraphz", .module = root_module }},
82
+ }),
83
+ });
84
+ check_step.dependOn(&bench_check.step);
85
+
86
+ // Example step.
87
+ const example_step = b.step("example", "Run the co-authorship network example");
88
+ const example_exe = b.addExecutable(.{
89
+ .name = "coauthorship",
90
+ .root_module = b.createModule(.{
91
+ .root_source_file = b.path("examples/coauthorship.zig"),
92
+ .imports = &.{.{ .name = "hypergraphz", .module = root_module }},
93
+ .target = target,
94
+ .optimize = optimize,
95
+ }),
96
+ });
97
+ example_step.dependOn(&b.addRunArtifact(example_exe).step);
98
+ check_step.dependOn(&example_exe.step);
99
+
100
+ // Shared library step (C ABI for Python bindings).
101
+ const lib_step = b.step("lib", "Build the HypergraphZ shared library (C ABI)");
102
+ const lib = b.addLibrary(.{
103
+ .name = "hypergraphz",
104
+ .linkage = .dynamic,
105
+ .root_module = b.createModule(.{
106
+ .root_source_file = b.path(CAbiPath),
107
+ .target = target,
108
+ .optimize = optimize,
109
+ .link_libc = true,
110
+ .imports = &.{.{ .name = "hypergraphz", .module = root_module }},
111
+ }),
112
+ });
113
+ lib_step.dependOn(&b.addInstallArtifact(lib, .{}).step);
114
+
115
+ // Bench step.
116
+ const bench_source_file = b.path(BenchPath);
117
+ const bench_module = b.addModule("bench", .{
118
+ .root_source_file = bench_source_file,
119
+ .target = target,
120
+ .optimize = .ReleaseFast,
121
+ .imports = &.{.{ .name = "hypergraphz", .module = root_module }},
122
+ });
123
+
124
+ const bench_step = b.step("bench", "Run benchmarks");
125
+ const bench_exe = b.addExecutable(.{
126
+ .name = "bench",
127
+ .root_module = bench_module,
128
+ });
129
+ const bench_run = b.addRunArtifact(bench_exe);
130
+ if (b.args) |args| {
131
+ bench_run.addArgs(args);
132
+ }
133
+ bench_step.dependOn(&bench_run.step);
134
+ }
@@ -0,0 +1,14 @@
1
+ .{
2
+ .name = .hypergraphz,
3
+ .fingerprint = 0xc4efc93d2a1d228a,
4
+ .version = "0.1.5",
5
+ .minimum_zig_version = "0.17.0-dev.242+5d55999d2",
6
+ .paths = .{
7
+ "LICENSE",
8
+ "README.md",
9
+ "build.zig",
10
+ "build.zig.zon",
11
+ "src",
12
+ "tests",
13
+ },
14
+ }
@@ -0,0 +1,45 @@
1
+ """Custom hatch build hook: compiles the Zig shared library during wheel packaging."""
2
+
3
+ import shutil
4
+ import subprocess
5
+ import sys
6
+ import sysconfig
7
+ from pathlib import Path
8
+
9
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
10
+
11
+ ROOT = Path(__file__).parent
12
+ PKG_DIR = ROOT / "python" / "hypergraphz"
13
+ PATTERNS = ("libhypergraphz.so", "libhypergraphz.dylib", "hypergraphz.dll")
14
+
15
+
16
+ def _wheel_tag() -> str:
17
+ python_tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
18
+ plat = sysconfig.get_platform().replace("-", "_").replace(".", "_")
19
+ return f"{python_tag}-{python_tag}-{plat}"
20
+
21
+
22
+ class CustomBuildHook(BuildHookInterface):
23
+ def initialize(self, version, build_data):
24
+ if self.target_name == "sdist":
25
+ return
26
+
27
+ # CI pre-copies the library before invoking cibuildwheel — nothing to build.
28
+ # Local development: build and copy if missing.
29
+ if not any(PKG_DIR.glob(p) for p in PATTERNS):
30
+ lib_dir = ROOT / "zig-out" / "lib"
31
+ subprocess.run(["zig", "build", "lib", "-Doptimize=ReleaseFast"], check=True, cwd=ROOT)
32
+
33
+ copied = False
34
+ for pattern in PATTERNS:
35
+ for lib in lib_dir.glob(pattern):
36
+ shutil.copy2(lib, PKG_DIR / lib.name)
37
+ copied = True
38
+
39
+ if not copied:
40
+ raise RuntimeError(f"No shared library found in {lib_dir}")
41
+
42
+ # Tell hatchling this is a platform wheel. Setting both keys because
43
+ # different hatchling versions look at one or the other.
44
+ build_data["pure_python"] = False
45
+ build_data["tag"] = _wheel_tag()
@@ -0,0 +1,69 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hypergraphz"
7
+ dynamic = ["version"]
8
+ description = "Python bindings for the HypergraphZ hypergraph library"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT" }
12
+
13
+ [dependency-groups]
14
+ dev = [
15
+ "pytest>=8.0",
16
+ "ruff>=0.4",
17
+ "hatch-vcs>=0.4",
18
+ "cibuildwheel>=2.20",
19
+ "wheel>=0.45",
20
+ ]
21
+
22
+ [tool.hatch.version]
23
+ source = "vcs"
24
+
25
+ [tool.hatch.build.targets.wheel]
26
+ packages = ["python/hypergraphz"]
27
+ # Override .gitignore exclusions — hatchling respects gitignore by default
28
+ artifacts = [
29
+ "python/hypergraphz/libhypergraphz.so",
30
+ "python/hypergraphz/libhypergraphz.dylib",
31
+ "python/hypergraphz/hypergraphz.dll",
32
+ ]
33
+
34
+ [tool.hatch.build.hooks.custom]
35
+ path = "hatch_build.py"
36
+
37
+ [tool.hatch.build.targets.sdist]
38
+ include = [
39
+ "python/",
40
+ "src/",
41
+ "build.zig",
42
+ "build.zig.zon",
43
+ "hatch_build.py",
44
+ ]
45
+
46
+ [tool.cibuildwheel]
47
+ build = "cp311-*"
48
+ skip = "pp*"
49
+
50
+
51
+ [tool.cibuildwheel.macos]
52
+ environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" }
53
+
54
+ [tool.cibuildwheel.windows]
55
+ archs = ["AMD64"]
56
+
57
+ [tool.ruff]
58
+ src = ["python"]
59
+ line-length = 100
60
+
61
+ [tool.ruff.lint]
62
+ select = ["E", "F", "I", "UP", "B", "SIM"]
63
+ ignore = ["E501"]
64
+
65
+ [tool.ruff.lint.isort]
66
+ known-first-party = ["hypergraphz"]
67
+
68
+ [tool.pytest.ini_options]
69
+ testpaths = ["tests-python"]
@@ -0,0 +1,28 @@
1
+ """HypergraphZ — Python bindings for the HypergraphZ Zig library."""
2
+
3
+ from ._errors import (
4
+ CycleDetectedError,
5
+ HyperedgeNotFoundError,
6
+ HypergraphZError,
7
+ IndexOutOfBoundsError,
8
+ NoPathError,
9
+ NotBuiltError,
10
+ NotEnoughVerticesError,
11
+ VertexNotFoundError,
12
+ )
13
+ from ._graph import Hypergraph
14
+ from ._query import HyperedgeQuery, VertexQuery
15
+
16
+ __all__ = [
17
+ "Hypergraph",
18
+ "HyperedgeQuery",
19
+ "VertexQuery",
20
+ "HypergraphZError",
21
+ "NotBuiltError",
22
+ "VertexNotFoundError",
23
+ "HyperedgeNotFoundError",
24
+ "CycleDetectedError",
25
+ "NoPathError",
26
+ "IndexOutOfBoundsError",
27
+ "NotEnoughVerticesError",
28
+ ]