Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
Expand Down Expand Up @@ -39,7 +38,12 @@ jobs:
- name: Test source distribution build
run: |
uv run python -m build --sdist


- name: Build manylinux wheel and test prebuilt install
run: bash scripts/verify_wheel_install.sh
env:
CIBW_BUILD: cp311-manylinux_x86_64

- name: Test installation from source
run: |
# Test that the source distribution can be installed
Expand Down
62 changes: 53 additions & 9 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.11"

Expand All @@ -32,25 +32,69 @@ jobs:

- uses: actions/upload-artifact@v4
with:
name: python-package-distributions
name: cibw-sdist
path: dist/*.tar.gz

build_wheels:
name: Build wheels (${{ matrix.os }})
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
- os: linux
runs-on: ubuntu-latest
- os: windows
runs-on: windows-latest
- os: macos-intel
runs-on: macos-15-intel
- os: macos-arm
runs-on: macos-latest

steps:
- uses: actions/checkout@v4

- name: Build wheels
uses: pypa/cibuildwheel@v3.4.1

- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}
path: ./wheelhouse/*.whl

verify_wheel_install:
name: Verify Linux wheel before PyPI
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Build manylinux wheel and test prebuilt install
run: bash scripts/verify_wheel_install.sh
env:
CIBW_BUILD: cp311-manylinux_x86_64

upload_pypi:
needs: [build_sdist]
needs: [build_sdist, build_wheels, verify_wheel_install]
runs-on: ubuntu-latest
if: github.event_name == 'release' && github.event.action == 'published'
environment:
name: pypi
url: https://pypi.org/p/python-uuidv47

steps:
- name: Download all artifacts
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
pattern: cibw-*
path: dist
merge-multiple: true

- name: Publish distribution 📦 to PyPI
- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
password: ${{ secrets.PYPI_API_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ parts/
sdist/
var/
wheels/
wheelhouse/
share/python-wheels/
*.egg-info/
.installed.cfg
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,7 @@ strict = true
warn_return_any = true
warn_unused_configs = true

[tool.cibuildwheel]
# Match Trove classifiers (CPython 3.9–3.12 only)
build = "cp39-* cp310-* cp311-* cp312-*"

22 changes: 22 additions & 0 deletions scripts/verify_wheel_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Build one manylinux wheel (selector via CIBW_BUILD) and run tests against a clean venv.
# Used on PR CI and in the release workflow before PyPI upload.
set -euxo pipefail

: "${CIBW_BUILD:=cp311-manylinux_x86_64}"

python -m pip install --upgrade pip
pip install cibuildwheel
cibuildwheel --platform linux --output-dir wheelhouse .

WHEEL="$(ls wheelhouse/python_uuidv47-*.whl | head -n1)"
test -n "${WHEEL}"

python -m venv .venv-wheeltest
.venv-wheeltest/bin/pip install --upgrade pip
.venv-wheeltest/bin/pip install pytest "${WHEEL}"
.venv-wheeltest/bin/python -m pytest \
tests/test_wheel_package.py \
tests/test_uuidv47.py \
tests/test_error_handling.py \
-v --tb=short
55 changes: 55 additions & 0 deletions tests/test_wheel_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Assertions for installs that ship a precompiled extension (wheels / binary installs).

These tests pass for a normal editable or ``pip install -e .`` build as long as the
Cython extension is compiled to a native module. They fail loudly if the accelerator
is missing or only source artifacts are visible at import time.
"""

from __future__ import annotations

from pathlib import Path

import python_uuidv47._uuidv47 as _uuidv47

import python_uuidv47
from python_uuidv47 import decode, encode, has_keys, set_keys, uuid_parse


def _extension_file() -> str | None:
return getattr(_uuidv47, "__file__", None)


def _is_native_extension_file(path: str) -> bool:
"""True if ``path`` looks like a loaded binary extension module."""
if not path:
return False
p = Path(path)
if p.suffix.lower() == ".pyd":
return True
# Linux/macOS: ``*.cpython-XY-…so`` or ``*.so``
return p.suffix.lower() == ".so"


def test_native_extension_module_file_points_to_binary() -> None:
path = _extension_file()
assert path is not None, "_uuidv47 should define __file__"
assert _is_native_extension_file(path), (
"Expected compiled extension (.so / .pyd); "
f"got __file__={path!r}. Is the Cython module built?"
)
assert not path.endswith(".pyx"), "Wheel/runtime should not import .pyx directly"


def test_package_version_matches_metadata() -> None:
assert isinstance(python_uuidv47.__version__, str)
assert len(python_uuidv47.__version__.split(".")) >= 2


def test_public_api_roundtrip_on_installed_package() -> None:
set_keys(111, 222)
assert has_keys() is True
u = "550e8400-e29b-71d4-a716-446655440000"
assert uuid_parse(u) is True
facade = encode(u)
assert uuid_parse(facade) is True
assert decode(facade) == u
Loading