Skip to content

Commit 92349ff

Browse files
committed
hatch
1 parent 7d384f0 commit 92349ff

2 files changed

Lines changed: 54 additions & 63 deletions

File tree

pywry/hatch_build.py

Lines changed: 50 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
This hook downloads and embeds the pytauri-wheel native extension for the
44
target platform, making pywry fully self-contained without requiring users
55
to download pytauri-wheel separately.
6+
7+
It also sets the wheel tags to make this a platform-specific wheel,
8+
which is required since we bundle native binaries.
69
"""
710

811
# pylint: disable=too-many-locals
@@ -11,31 +14,32 @@
1114

1215
import os
1316
import platform
14-
import subprocess
17+
import shutil
1518
import sys
16-
import tempfile
17-
import zipfile
1819

1920
from pathlib import Path
2021
from typing import Any
2122

2223
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
2324

2425

25-
def get_platform_tag() -> str:
26-
"""Get the platform tag for the current build target."""
26+
def get_wheel_platform_tag() -> str:
27+
"""Get the platform tag for the output wheel.
28+
29+
This is the tag that will be used in the wheel filename.
30+
We use manylinux_2_28 for Linux for broad compatibility.
31+
"""
2732
system = platform.system().lower()
2833
machine = platform.machine().lower()
2934

3035
if system == "darwin":
31-
# Use tags that match what pytauri-wheel publishes on PyPI
3236
if machine == "arm64":
3337
return "macosx_14_0_arm64"
3438
return "macosx_13_0_x86_64"
3539
if system == "linux":
3640
if machine == "aarch64":
37-
return "manylinux_2_35_aarch64"
38-
return "manylinux_2_35_x86_64"
41+
return "manylinux_2_28_aarch64"
42+
return "manylinux_2_28_x86_64"
3943
if system == "windows":
4044
if machine == "arm64":
4145
return "win_arm64"
@@ -62,72 +66,54 @@ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
6266

6367
# Skip for editable installs
6468
if version == "editable":
65-
self.app.display_info("Skipping pytauri-wheel bundling for editable install")
69+
self.app.display_info(
70+
"Skipping pytauri-wheel bundling for editable install"
71+
)
6672
return
6773

74+
python_tag = get_python_tag()
75+
wheel_platform_tag = get_wheel_platform_tag()
76+
# Set wheel tags to make this a platform-specific wheel
77+
# This is critical - without this, hatch generates a pure Python wheel
78+
build_data["tag"] = f"{python_tag}-{python_tag}-{wheel_platform_tag}"
79+
build_data["pure_python"] = False
80+
6881
# Check if bundling is enabled (can be disabled for development)
6982
if os.environ.get("PYWRY_SKIP_BUNDLE", "").lower() in ("1", "true", "yes"):
70-
self.app.display_info("Skipping pytauri-wheel bundling (PYWRY_SKIP_BUNDLE=1)")
83+
self.app.display_info(
84+
"Skipping pytauri-wheel bundling (PYWRY_SKIP_BUNDLE=1)"
85+
)
7186
return
7287

73-
pytauri_version = os.environ.get("PYTAURI_WHEEL_VERSION", "0.8.0")
74-
python_tag = get_python_tag()
75-
platform_tag = get_platform_tag()
76-
7788
self.app.display_info(
78-
f"Bundling pytauri-wheel {pytauri_version} for {python_tag}-{platform_tag}"
89+
f"Bundling pytauri-wheel for {python_tag}-{wheel_platform_tag}"
7990
)
8091

8192
# Create vendor directory in the package
8293
vendor_dir = Path(self.root) / "pywry" / "_vendor" / "pytauri_wheel"
8394
vendor_dir.mkdir(parents=True, exist_ok=True)
8495

85-
with tempfile.TemporaryDirectory() as tmpdir:
86-
tmppath = Path(tmpdir)
87-
88-
try:
89-
subprocess.run( # noqa: S603
90-
[
91-
sys.executable,
92-
"-m",
93-
"pip",
94-
"download",
95-
"--no-deps",
96-
"--only-binary=:all:",
97-
f"--dest={tmppath}",
98-
f"--platform={platform_tag}",
99-
f"--python-version={sys.version_info.major}.{sys.version_info.minor}",
100-
f"--abi={python_tag}",
101-
f"pytauri-wheel=={pytauri_version}",
102-
],
103-
check=True,
104-
capture_output=True,
105-
text=True,
106-
)
107-
except subprocess.CalledProcessError as e:
108-
self.app.display_error(f"Failed to download pytauri-wheel: {e.stderr}")
109-
raise
110-
111-
# Find the downloaded wheel
112-
wheels = list(tmppath.glob("pytauri_wheel*.whl"))
113-
if not wheels:
114-
raise RuntimeError(f"No pytauri-wheel found in {tmppath}")
115-
116-
wheel_path = wheels[0]
117-
self.app.display_info(f"Downloaded: {wheel_path.name}")
118-
119-
# Extract the wheel (it's a zip file)
120-
with zipfile.ZipFile(wheel_path, "r") as whl:
121-
# Extract only the pytauri_wheel package contents
122-
for member in whl.namelist():
123-
if member.startswith("pytauri_wheel/") and not member.endswith("/"):
124-
# Get the relative path within pytauri_wheel/
125-
rel_path = member[len("pytauri_wheel/") :]
126-
if rel_path:
127-
dest = vendor_dir / rel_path
128-
dest.parent.mkdir(parents=True, exist_ok=True)
129-
with whl.open(member) as src, dest.open("wb") as dst:
130-
dst.write(src.read())
96+
# Find the installed pytauri_wheel package location
97+
import importlib.util
98+
99+
spec = importlib.util.find_spec("pytauri_wheel")
100+
if spec is None or spec.origin is None:
101+
raise RuntimeError(
102+
"pytauri_wheel is not installed. Install it with: pip install pytauri-wheel"
103+
)
104+
105+
pytauri_wheel_dir = Path(spec.origin).parent
106+
self.app.display_info(f"Found pytauri_wheel at: {pytauri_wheel_dir}")
107+
108+
# Copy the entire pytauri_wheel package to vendor directory
109+
for item in pytauri_wheel_dir.iterdir():
110+
dest = vendor_dir / item.name
111+
if item.is_dir():
112+
if dest.exists():
113+
shutil.rmtree(dest)
114+
shutil.copytree(item, dest)
115+
else:
116+
shutil.copy2(item, dest)
131117

132118
# Create __init__.py that re-exports from vendor location
133119
init_content = '''"""Vendored pytauri_wheel package."""
@@ -140,4 +126,6 @@ def initialize(self, version: str, build_data: dict[str, Any]) -> None:
140126
# Add vendor directory to wheel
141127
build_data["force_include"][str(vendor_dir)] = "pywry/_vendor/pytauri_wheel"
142128

143-
self.app.display_success("Bundled pytauri-wheel into pywry/_vendor/pytauri_wheel")
129+
self.app.display_success(
130+
"Bundled pytauri-wheel into pywry/_vendor/pytauri_wheel"
131+
)

pywry/pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,14 @@ Repository = "https://github.com/deeleeramone/PyWry"
7575
Documentation = "https://github.com/deeleeramone/PyWry/pywry#readme"
7676

7777
[build-system]
78-
requires = ["hatchling>=1.21.0", "pip"]
78+
requires = ["hatchling>=1.21.0", "pip", "pytauri-wheel>=0.8.0"]
7979
build-backend = "hatchling.build"
8080

8181
[tool.hatch.build.targets.wheel]
8282
packages = ["pywry"]
83+
# Force platform-specific wheel since we bundle native pytauri binaries
84+
# Setting this to false tells hatch this is NOT a pure Python package
85+
strict-naming = false
8386

8487
[tool.hatch.build.targets.wheel.hooks.custom]
8588
path = "hatch_build.py"

0 commit comments

Comments
 (0)