Skip to content

Commit ad77fe6

Browse files
committed
Added bundling logic for wheels
1 parent efdd3b6 commit ad77fe6

File tree

5 files changed

+74
-2
lines changed

5 files changed

+74
-2
lines changed

.github/workflows/publish-pypi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- os: ubuntu-latest
2424
binary_name: stagehand-linux-x64
2525
output_path: src/stagehand/_sea/stagehand-linux-x64
26-
wheel_platform_tag: linux_x86_64
26+
wheel_platform_tag: manylinux2014_x86_64
2727
- os: macos-latest
2828
binary_name: stagehand-darwin-arm64
2929
output_path: src/stagehand/_sea/stagehand-darwin-arm64

hatch_build.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from __future__ import annotations
2+
3+
import os
4+
from pathlib import Path
5+
6+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
7+
8+
9+
def _infer_platform_tag() -> str:
10+
from packaging.tags import sys_tags
11+
12+
# Linux tag is after many/musl; skip those to get the generic platform tag.
13+
tag = next(iter(t for t in sys_tags() if "manylinux" not in t.platform and "musllinux" not in t.platform))
14+
return tag.platform
15+
16+
17+
def _has_embedded_sea_binaries() -> bool:
18+
sea_dir = Path(__file__).resolve().parent / "src" / "stagehand" / "_sea"
19+
if not sea_dir.exists():
20+
return False
21+
22+
for path in sea_dir.iterdir():
23+
if not path.is_file():
24+
continue
25+
if path.name in {".keep"}:
26+
continue
27+
if path.name.startswith("."):
28+
continue
29+
return True
30+
31+
return False
32+
33+
34+
class CustomBuildHook(BuildHookInterface):
35+
def initialize(self, _version: str, build_data: dict) -> None:
36+
if not _has_embedded_sea_binaries():
37+
return
38+
39+
# We are bundling a platform-specific executable, so this must not be a
40+
# "pure python" wheel.
41+
build_data["pure_python"] = False
42+
43+
# CI sets this so we get deterministic wheel tags that match the SEA
44+
# artifact we're embedding (e.g. "py3-none-macosx_11_0_arm64").
45+
wheel_tag = os.environ.get("STAGEHAND_WHEEL_TAG", "").strip()
46+
if wheel_tag:
47+
if wheel_tag.count("-") != 2:
48+
raise ValueError(
49+
"Invalid STAGEHAND_WHEEL_TAG. Expected a full wheel tag like 'py3-none-macosx_11_0_arm64'."
50+
)
51+
build_data["tag"] = wheel_tag
52+
build_data["infer_tag"] = False
53+
else:
54+
# For local builds, infer just the platform portion so the wheel
55+
# remains Python-version agnostic (our embedded server binary is not
56+
# tied to a specific Python ABI).
57+
build_data["tag"] = f"py3-none-{_infer_platform_tag()}"
58+
build_data["infer_tag"] = False

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,17 @@ pydantic-v2 = [
7777
]
7878

7979
[build-system]
80-
requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"]
80+
requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme", "packaging"]
8181
build-backend = "hatchling.build"
8282

8383
[tool.hatch.build]
8484
include = [
8585
"src/*"
8686
]
8787

88+
[tool.hatch.build.hooks.custom]
89+
path = "hatch_build.py"
90+
8891
[tool.hatch.build.targets.wheel]
8992
packages = ["src/stagehand"]
9093

src/stagehand/_sea/.keep

Whitespace-only changes.

src/stagehand/lib/sea_binary.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,16 @@ def resolve_binary_path(
106106
here = Path(__file__).resolve()
107107
repo_root = here.parents[3] # stagehand-python/
108108
candidate = repo_root / "bin" / "sea" / filename
109+
110+
if not candidate.exists():
111+
raise FileNotFoundError(
112+
f"Stagehand SEA binary not found at {candidate}.\n"
113+
f"For local development, download the binary using:\n"
114+
f" uv run python scripts/download-binary.py\n"
115+
f"Or set the STAGEHAND_SEA_BINARY environment variable to point to your binary.\n"
116+
f"For production use, install a platform-specific wheel from PyPI.\n"
117+
f"See: https://github.com/browserbase/stagehand-python#local-development"
118+
)
119+
109120
_ensure_executable(candidate)
110121
return candidate

0 commit comments

Comments
 (0)