Skip to content

Commit 6ddc08f

Browse files
committed
Merge branch 'ChristianTremblay-issue-22'
2 parents dc65d0f + f8ad735 commit 6ddc08f

File tree

10 files changed

+216
-51
lines changed

10 files changed

+216
-51
lines changed

.github/workflows/ci.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,20 @@ jobs:
5959

6060
- name: Test Python package
6161
working-directory: python
62+
run: uv run --project . python -m unittest discover -s tests
63+
64+
- name: Build ontoenv wheel
65+
shell: bash
66+
run: uv run maturin build --release -m python/Cargo.toml
67+
68+
- name: Run pyontoenv unit tests
69+
working-directory: pyontoenv-shim
6270
run: uv run python -m unittest discover -s tests
71+
72+
- name: Build pyontoenv shim wheel
73+
shell: bash
74+
run: uv build --project pyontoenv-shim --wheel
75+
76+
- name: Test pyontoenv shim
77+
shell: bash
78+
run: uv run python scripts/test_pyontoenv.py

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ Project components:
1111
- Rust library: [`ontoenv`](https://docs.rs/ontoenv/latest/ontoenv/)
1212
- Python bindings: [`ontoenv`](https://pypi.org/project/ontoenv/)
1313

14+
## Building From Source
15+
16+
### Rust workspace
17+
- `cargo build --workspace --release` compiles every crate (`lib/`, `cli/`, `rdf5d/`) and produces optimized binaries in `target/release/`.
18+
- `cargo test --workspace` exercises all Rust tests; the convenience wrapper `./test` also drives the Python suites.
19+
20+
### Python package (`python/`)
21+
- `uv run --project python maturin develop` builds the extension module in editable mode against the local Rust library.
22+
- `uv run --project python python -m unittest discover -s tests` runs the Python unit tests.
23+
- Generated wheels land in `python/target/wheels/` when you run `uv run maturin build --release -m python/Cargo.toml`.
24+
25+
### Compatibility shim (`pyontoenv-shim/`)
26+
- `uv build --project pyontoenv-shim --wheel` produces the `pyontoenv` wheel that re-exports the bindings.
27+
- `uv run --project pyontoenv-shim python -m unittest discover` validates the shim and its aliasing behavior.
28+
- `uv run python scripts/test_pyontoenv.py` installs the freshly built wheels into a throwaway virtualenv and sanity-checks imports and the CLI.
29+
- The helper `./version <new-version>` bumps the workspace version and refreshes related manifests for both Rust and Python packages.
30+
1431
## Overview
1532

1633
Imagine you have an RDF graph which imports some ontologies in order to use those concepts.

pyontoenv-shim/pyproject.toml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
[project]
2+
name = "pyontoenv"
3+
version = "0.4.0a14"
4+
description = "Compatibility wrapper that installs the ontoenv package."
5+
readme = "README.md"
6+
requires-python = ">=3.9"
7+
license = { text = "BSD-3-Clause" }
8+
authors = [
9+
{ name = "Gabe Fierro", email = "[email protected]" },
10+
]
11+
dependencies = ["ontoenv"]
12+
13+
[project.urls]
14+
Homepage = "https://github.com/gtfierro/ontoenv-rs"
15+
Repository = "https://github.com/gtfierro/ontoenv-rs"
16+
Issues = "https://github.com/gtfierro/ontoenv-rs/issues"
17+
18+
[tool.uv.sources]
19+
ontoenv = { path = "../python", editable = true }
20+
121
[build-system]
2-
requires = ["setuptools>=68"]
3-
build-backend = "setuptools.build_meta"
22+
requires = ["uv-build>=0.5.0"]
23+
build-backend = "uv_build"

pyontoenv-shim/setup.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

pyontoenv-shim/src/pyontoenv/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Compatibility wrapper that proxies to the real ``ontoenv`` package."""
22

33
from importlib import import_module
4+
import sys as _sys
45

56
_ontoenv = import_module("ontoenv")
67

@@ -11,3 +12,10 @@
1112
__version__ = version if isinstance(version, str) else getattr(_ontoenv, "__version__", "0.0.0")
1213

1314
__all__ = getattr(_ontoenv, "__all__", [])
15+
16+
# Ensure version metadata is available via both imports.
17+
if not hasattr(_ontoenv, "__version__"):
18+
setattr(_ontoenv, "__version__", __version__)
19+
20+
# Ensure importing `pyontoenv` yields the same module object as `ontoenv`.
21+
_sys.modules[__name__] = _ontoenv
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import sys
2+
import unittest
3+
4+
5+
class PyOntoEnvImportTests(unittest.TestCase):
6+
def test_pyontoenv_aliases_ontoenv(self) -> None:
7+
import pyontoenv # noqa: F401
8+
import ontoenv
9+
10+
self.assertIs(sys.modules["pyontoenv"], ontoenv)
11+
self.assertTrue(hasattr(ontoenv, "OntoEnv"))
12+
self.assertIsInstance(getattr(ontoenv, "__version__", None), str)
13+
14+
15+
if __name__ == "__main__":
16+
unittest.main()

python/ontoenv/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""Python package shim for the ontoenv extension."""
22

33
# These symbols come from the Rust extension module built via maturin.
4-
from ._native import OntoEnv, Ontology, run_cli, version # type: ignore[attr-defined]
5-
from . import _native as _ext # type: ignore[attr-defined]
4+
from ontoenv._native import OntoEnv, Ontology, run_cli, version # type: ignore[attr-defined]
5+
from ontoenv import _native as _ext # type: ignore[attr-defined]
66

77
__doc__ = getattr(_ext, "__doc__", None) # type: ignore[assignment]
88

python/ontoenv/_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import sys
44

5-
from .ontoenv import run_cli as _run_cli
5+
from ontoenv import run_cli as _run_cli
66

77

88
def main(argv: list[str] | None = None) -> int:

test

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
export UV_CACHE_DIR="${UV_CACHE_DIR:-$ROOT/.uv-cache}"
6+
export UV_SYSTEM_RESOLVE="${UV_SYSTEM_RESOLVE:-0}"
7+
8+
echo "+ cargo test --workspace"
9+
cargo test --workspace
10+
11+
echo "+ uv run maturin develop (python/)"
12+
(
13+
cd "$ROOT/python"
14+
uv run maturin develop
15+
)
16+
17+
echo "+ uv run python -m unittest discover -s tests (python/)"
18+
(
19+
cd "$ROOT/python"
20+
uv run python -m unittest discover -s tests
21+
)
22+
23+
echo "+ uv run python -m unittest discover -s tests (pyontoenv-shim/)"
24+
(
25+
cd "$ROOT/pyontoenv-shim"
26+
uv run python -m unittest discover -s tests
27+
)
28+
29+
echo "+ uv run python -c 'import pyontoenv...' (pyontoenv-shim/)"
30+
(
31+
cd "$ROOT/pyontoenv-shim"
32+
uv run python -c "
33+
import pyontoenv, ontoenv
34+
from pyontoenv import OntoEnv
35+
assert callable(OntoEnv)
36+
print('pyontoenv version', pyontoenv.__version__)
37+
"
38+
)

version

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env python3
2+
"""Version management helper for ontoenv-rs.
3+
4+
- Without arguments: print the current workspace version.
5+
- With a version string: update all manifests and rebuild lockfiles.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
import argparse
11+
import os
12+
import subprocess
13+
import sys
14+
import re
15+
from pathlib import Path
16+
17+
ROOT = Path(__file__).resolve().parent
18+
CARGO_TOML = ROOT / "Cargo.toml"
19+
PYONTOENV_PYPROJECT = ROOT / "pyontoenv-shim" / "pyproject.toml"
20+
21+
22+
def read_current_version() -> str:
23+
text = (ROOT / "Cargo.toml").read_text(encoding="utf-8").splitlines()
24+
in_workspace = False
25+
for raw in text:
26+
line = raw.strip()
27+
if line.startswith("[") and line.endswith("]"):
28+
in_workspace = line == "[workspace.package]"
29+
continue
30+
if not in_workspace:
31+
continue
32+
if line.startswith("version"):
33+
match = re.search(r'version\s*=\s*"([^"]+)"', line)
34+
if match:
35+
return match.group(1)
36+
raise SystemExit("Unable to find workspace.package.version in Cargo.toml")
37+
38+
39+
def write_if_contains(path: Path, old: str, new: str) -> bool:
40+
text = path.read_text(encoding="utf-8")
41+
if old not in text:
42+
return False
43+
path.write_text(text.replace(old, new), encoding="utf-8")
44+
return True
45+
46+
47+
def update_versions(old: str, new: str) -> None:
48+
touched = []
49+
for path in (CARGO_TOML, PYONTOENV_PYPROJECT):
50+
if write_if_contains(path, old, new):
51+
touched.append(path)
52+
if not touched:
53+
print("warning: no files updated; version string may already be current", file=sys.stderr)
54+
55+
56+
def run_command(cmd: list[str], cwd: Path | None = None) -> None:
57+
display = " ".join(cmd)
58+
print(f"+ {display}", flush=True)
59+
env = os.environ.copy()
60+
env.setdefault("UV_CACHE_DIR", str(ROOT / ".uv-cache"))
61+
env.setdefault("UV_SYSTEM_RESOLVE", "0")
62+
try:
63+
subprocess.run(cmd, cwd=cwd, check=True, env=env)
64+
except subprocess.CalledProcessError as exc:
65+
raise SystemExit(f"{display} failed with exit code {exc.returncode}") from exc
66+
67+
68+
def rebuild() -> None:
69+
run_command(["cargo", "check"])
70+
run_command(["cargo", "build"])
71+
run_command(["uv", "lock"], cwd=ROOT / "python")
72+
run_command(["uv", "lock"], cwd=ROOT / "pyontoenv-shim")
73+
74+
75+
def main() -> None:
76+
parser = argparse.ArgumentParser(description="Manage workspace version.")
77+
parser.add_argument("version", nargs="?", help="New version string to apply.")
78+
args = parser.parse_args()
79+
80+
current = read_current_version()
81+
if not args.version:
82+
print(current)
83+
return
84+
85+
new = args.version
86+
if new == current:
87+
print(f"version already {current}")
88+
rebuild()
89+
return
90+
91+
update_versions(current, new)
92+
rebuild()
93+
94+
95+
if __name__ == "__main__":
96+
main()

0 commit comments

Comments
 (0)