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
71 changes: 54 additions & 17 deletions .github/workflows/test-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
# This workflow never publishes: it has no id-token permission and no environment.
#
# Beside the full parity runs, the `pyver` job installs the already built linux-x86_64 wheel (py3-none: no rebuild) into the Pythons the full
# runs of the event leave out (a pull request: 3.11, 3.13, 3.14; main, nightly, dispatch: 3.11, 3.13; a release: none) and into the free-threaded
# 3.14t, and runs a small subset of the tests there (about 20 s of tests per Python). It is informational: release-native.yml does not need it.
# runs of the event leave out (a pull request: 3.11, 3.13, 3.14; main, nightly, dispatch: 3.11, 3.13; a release: none), into 3.15 (always: the full suite
# needs jpype1 and ladybug, which have no cp315 wheel yet, so 3.15 runs without the test files that need jpype1) and into the free-threaded 3.14t, and runs a small subset of the tests there (about 20 s of tests per Python). It is informational: release-native.yml does not need it.
# scripts/select_native_matrix.py decides its legs.
#
# One wheel per platform, py3-none-<platform tag>:
# linux-x86_64 manylinux_2_34 container manylinux_2_34_x86_64 libarcadedb.so + libjvector-x86_64.so
# linux-aarch64 manylinux_2_34 aarch64 container manylinux_2_34_aarch64 libarcadedb.so
# linux-x86_64 manylinux_2_28 container manylinux_2_28_x86_64 libarcadedb.so + libjvector-x86_64.so
# linux-aarch64 manylinux_2_28 aarch64 container manylinux_2_28_aarch64 libarcadedb.so
# macos-arm64 native, heap and threads capped macosx_<minos>_arm64 libarcadedb.dylib
# windows-x64 native, MSVC environment loaded win_amd64 libarcadedb.dll
# Only free GitHub-hosted standard runners. GraalVM Community Edition only (pinned by sha256 per platform), never Oracle GraalVM.
Expand Down Expand Up @@ -278,9 +278,9 @@ jobs:
mv /usr/bin/link.exe /usr/bin/link-gnu.exe || true
echo "link is now: $(command -v link || echo none)"

# -march=compatibility, -J-Xmx12g, -H:-VectorAPISupport, fastops.mode 1, inside the manylinux_2_34 container (glibc 2.34) so the
# -march=compatibility, -J-Xmx12g, -H:-VectorAPISupport, fastops.mode 1, inside the manylinux_2_28 container (glibc 2.28) so the
# glibc floor of libarcadedb.so is a guarantee, not a property of the runner.
- name: Build the native image in manylinux_2_34
- name: Build the native image in manylinux_2_28
if: ${{ matrix.kind == 'linux' }}
env:
ENGINE: ${{ needs.plan.outputs.engine }}
Expand All @@ -296,11 +296,14 @@ jobs:
"$MANYLINUX_IMAGE" bash -euo pipefail -c '
ldd --version | sed -n 1p # not `head -1`: under pipefail its early exit can SIGPIPE ldd
uname -m
# zlib-devel, unzip and which are in the base repositories; EPEL is not needed and its mirrors fail now and then
for i in 1 2 3 4 5; do
dnf install -y --disablerepo="epel*" --setopt=install_weak_deps=False zlib-devel unzip which >/dev/null && break
[ "$i" -lt 5 ] && { echo "dnf failed, retry $i in $((i * 20))s" >&2; sleep $((i * 20)); } || exit 1
done
# zlib-devel, unzip and which are in the manylinux_2_28 image already; dnf runs only for a missing one (the AlmaLinux 8 mirror
# metadata fails now and then). EPEL is not needed and its mirrors fail too.
if ! rpm -q zlib-devel unzip which >/dev/null; then
for i in 1 2 3 4 5; do
dnf install -y --disablerepo="epel*" --setopt=install_weak_deps=False zlib-devel unzip which >/dev/null && break
[ "$i" -lt 5 ] && { echo "dnf failed, retry $i in $((i * 20))s" >&2; sleep $((i * 20)); } || exit 1
done
fi
cd /work
bash native/scripts/build-image.sh /out
' || { tail -n 80 "$T/lib/build.log" || true; exit 1; }
Expand Down Expand Up @@ -334,7 +337,7 @@ jobs:
for so in "$T"/lib/*.so; do
top="$(objdump -T "$so" | grep -Eo 'GLIBC_[0-9]+\.[0-9]+(\.[0-9]+)?' | sort -uV | tail -n 1)"
echo "$(basename "$so"): highest $top"
[ "$(printf '%s\nGLIBC_2.34\n' "$top" | sort -V | tail -n 1)" = "GLIBC_2.34" ] || { echo "$so needs $top, above the manylinux_2_34 floor" >&2; exit 1; }
[ "$(printf '%s\nGLIBC_2.28\n' "$top" | sort -V | tail -n 1)" = "GLIBC_2.28" ] || { echo "$so needs $top, above the manylinux_2_28 floor" >&2; exit 1; }
done

- name: Build the wheel
Expand Down Expand Up @@ -369,12 +372,34 @@ jobs:
# auditwheel wraps its report to the terminal width, so match on one line with the whitespace collapsed
tr -s '[:space:]' ' ' < "$T/auditwheel.txt" > "$T/auditwheel.flat"
grep -F 'consistent with the following platform tag' "$T/auditwheel.flat"
grep -F "\"$PLAT\"" "$T/auditwheel.flat"
# auditwheel names the LOWEST tag the wheel is consistent with. The wheel carries the tag of its build container (build_wheel.py
# --glibc-policy); the library may need less (its glibc symbols stop at 2.17, jvector's libstdc++ asks for more than manylinux2014),
# never more.
granted="$(grep -Eo 'consistent with the following platform tag: "manylinux_[0-9]+_[0-9]+' "$T/auditwheel.flat" | grep -Eo 'manylinux_[0-9]+_[0-9]+' || true)"
want="$(printf '%s' "$PLAT" | grep -Eo 'manylinux_[0-9]+_[0-9]+')"
echo "auditwheel grants ${granted:-an older policy}; the wheel is tagged $want"
[ "$(printf '%s\n%s\n' "${granted:-manylinux_2_5}" "$want" | sort -V | tail -n 1)" = "$want" ] || { echo "auditwheel needs a tag above $want" >&2; exit 1; }
if grep -Eiq 'instruction set|x86_64_v[0-9]' "$T/auditwheel.flat"; then
echo "auditwheel reports an ISA warning: the image is not baseline x86-64" >&2
exit 1
fi

# The tests run on the runner (glibc 2.39). This step runs the wheel where its tag says it must work: in the manylinux_2_28 container
# (glibc 2.28), on that image's Python 3.12, with nothing but the wheel installed.
- name: "Gate: the wheel installs and opens a database on glibc 2.28"
if: ${{ matrix.kind == 'linux' }}
env:
MANYLINUX_IMAGE: ${{ matrix.container }}
run: |
set -euo pipefail
docker run --rm -v "$T/wheel/dist:/wheel:ro" -v "$GITHUB_WORKSPACE/scripts/smoke_wheel.py:/smoke_wheel.py:ro" "$MANYLINUX_IMAGE" bash -euo pipefail -c '
ldd --version | sed -n 1p
/opt/python/cp312-cp312/bin/python -m venv /tmp/venv
/tmp/venv/bin/python -m pip install --no-index /wheel/*.whl
cd /tmp
/tmp/venv/bin/python /smoke_wheel.py
'

- name: "Gate: the macOS library links system libraries only"
if: ${{ matrix.kind == 'macos' }}
run: |
Expand Down Expand Up @@ -597,6 +622,7 @@ jobs:
KEY: linux-x86_64
PY: ${{ matrix.python }}
WITH_POLARS: ${{ matrix.polars }}
WITH_JPYPE: ${{ matrix.jpype }}
FREE_THREADED: ${{ matrix.freethreaded }}
# The subset: ctypes layer and database lifecycle (test_core, test_native_udf), queries and results (test_resultset), parameters
# (test_parameter_binding), type conversion (test_type_conversion), transactions (test_transaction_config), async (test_async_executor),
Expand Down Expand Up @@ -635,10 +661,17 @@ jobs:
files="$files,test_dataframe_ingest.py"
with_polars=(--with polars)
fi
# No jpype1 wheel for this Python (3.15): leave out test_parameter_binding.py (it imports jpype at module level) and test_vector.py
# (four tests build Java arrays with it). Everything else of the subset needs no JVM bridge.
with_jpype=(--with jpype1)
if [ "$WITH_JPYPE" != true ]; then
files="$(printf '%s' "$files" | tr ',' '\n' | grep -v -x -F -e test_parameter_binding.py -e test_vector.py | paste -sd, -)"
with_jpype=()
fi
echo "python $PY, files: $files"
cores="$(nproc)"
uv run --no-project --python "$PY" --with "$w" --with pytest --with numpy --with requests --with jpype1 --with pyarrow \
--with pandas ${with_polars[@]+"${with_polars[@]}"} \
uv run --no-project --python "$PY" --with "$w" --with pytest --with numpy --with requests --with pyarrow \
--with pandas ${with_polars[@]+"${with_polars[@]}"} ${with_jpype[@]+"${with_jpype[@]}"} \
python native/wheel/parity_wheel.py --repo "$GITHUB_WORKSPACE" --files "$files" \
--out "$T/parity/parity-wheel.tsv" --cores "0-$((cores - 1))" | tee "$T/parity/parity-wheel.run.log"

Expand All @@ -647,16 +680,20 @@ jobs:
run: |
set -euo pipefail
w="$(ls "$T"/wheel/*.whl)"
uv run --no-project --python "$PY" --with "$w" --with numpy --with pandas --with pyarrow --with jpype1 python - <<'PY' | tee -a "$GITHUB_STEP_SUMMARY"
with_jpype=(--with jpype1)
if [ "$WITH_JPYPE" != true ]; then with_jpype=(); fi
uv run --no-project --python "$PY" --with "$w" --with numpy --with pandas --with pyarrow ${with_jpype[@]+"${with_jpype[@]}"} python - <<'PY' | tee -a "$GITHUB_STEP_SUMMARY"
import os
import sys

import arcadedb # noqa: F401
import jpype # noqa: F401
import numpy # noqa: F401
import pandas # noqa: F401
import pyarrow # noqa: F401

if os.environ["WITH_JPYPE"] == "true":
import jpype # noqa: F401

gil = sys._is_gil_enabled() if hasattr(sys, "_is_gil_enabled") else True
print(f"python {sys.version.split()[0]}, GIL enabled after loading the wheel and its dependencies: {gil}")
if os.environ["FREE_THREADED"] == "true" and gil:
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/development/ci.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The workflow `test-native.yml` builds the native image of the `arcadedb` package

* A pull request runs it only when native paths change: `native/**`, `src/arcadedb/_native/**`, the native tests, or `test-native.yml` itself. It then runs on `linux-x86_64` with Python 3.12 only.
* A push to `main`, the nightly run, a manual run (dispatch) run all four platforms: `linux-x86_64`, `linux-aarch64`, `macos-arm64` and `windows-x64` (Python 3.12 and 3.14). A release (`release-native.yml` calls the workflow with `release: true`) runs the same four platforms on all four Python versions, 16 legs.
* The `pyver` job installs the already built `linux-x86_64` wheel (no rebuild) into the Pythons that the full parity runs of the event leave out (3.11, 3.13 and 3.14 on a pull request; 3.11 and 3.13 on a push to `main`, the nightly run and a dispatch; none on a release) and into the free-threaded 3.14t, and runs 13 test files there (14 where polars installs), about 20 seconds of tests per Python. It is informational: `release-native.yml` reads only the `native-passed-*` markers and the `native-wheel-*` wheels, so a red `pyver` leg never blocks a release. The 3.14t leg has no polars (no free-threaded wheel exists), so it skips `test_dataframe_ingest.py`. `scripts/select_native_matrix.py` decides its legs.
* The `pyver` job installs the already built `linux-x86_64` wheel (no rebuild) into the Pythons that the full parity runs of the event leave out (3.11, 3.13 and 3.14 on a pull request; 3.11 and 3.13 on a push to `main`, the nightly run and a dispatch; none on a release) into 3.15 and into the free-threaded 3.14t, and runs 13 test files there (14 where polars installs; 3.15 has no jpype1 wheel, so it leaves out the two files that need jpype1), about 20 seconds of tests per Python. It is informational: `release-native.yml` reads only the `native-passed-*` markers and the `native-wheel-*` wheels, so a red `pyver` leg never blocks a release. The 3.14t leg has no polars (no free-threaded wheel exists), so it skips `test_dataframe_ingest.py`. `scripts/select_native_matrix.py` decides its legs.
* A native image build takes about 1 to 2.5 hours for each platform. The organisation shares one runner limit with upstream ArcadeDB, so do not add runs lightly. Change the paths or the matrix of `test-native.yml` only for a reason that you can write down.

== Change the selection
Expand Down
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ Check which one you have with `python -c "import arcadedb; print(arcadedb.__back

== Requirements

* Python 3.11 to 3.14. The wheels' CI runs all four versions on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* Linux (x86_64 and ARM64), macOS on Apple Silicon, or Windows (x86_64). The Windows wheel of the native build is the newest.
* Python 3.11 to 3.14, and 3.15 for `{native-pkg-name}`. The wheels' CI runs all four versions on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* Linux (x86_64 and ARM64, glibc: no Alpine), macOS on Apple Silicon (no Intel Mac), or Windows (x86_64). The Windows wheel of the native build is the newest. The glibc floors and the other platforms that are not built are in xref:installation.adoc#requirements[Requirements].
* No Java installation, for either package.

== Links
Expand Down
24 changes: 18 additions & 6 deletions docs/modules/ROOT/pages/installation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,42 @@ NOTE: *Old names.* The JVM package was formerly `arcadedb-embedded`. It is now `

The JVM package is self-contained. It carries a Java 25 runtime for its platform, so you do not install Java. Its only Python dependency is `JPype1` 1.5.0 or later (the Java-Python bridge), which pip installs for you. The native package needs no Java and no JPype. Optional extras install the columnar helpers of the native package: `[numpy]`, `[arrow]`, `[pandas]` and `[polars]`.

[[requirements]]
== Requirements

* Python 3.11 to 3.14. The wheels' CI runs all four versions on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* One of the four platforms below. The Windows wheel of the native build is the newest, and its test run is the least proven of the four.
* Python 3.11 to 3.14 for both packages. The native package also supports Python 3.15: it is one `py3-none` wheel that loads its library with `ctypes`, and the CI runs a subset of the tests on 3.15. `{jvm-pkg-name}` does not install on 3.15 yet, because its dependency JPype has no 3.15 wheel. The CI runs all four versions 3.11 to 3.14 on every supported platform for `main`, the nightly run and each release. A pull request runs a smaller selection (xref:development/ci.adoc[Continuous integration]).
* One of the four platforms below. The Windows wheel of the native build is the newest, and its test run is the least proven of the four. It needs the Microsoft Visual C++ runtime (`VCRUNTIME140.dll`), which every CPython for Windows already brings.

Every wheel is platform-specific and built on a native runner of its platform, so pip needs no hint to pick the right one. The JVM wheel also carries a JRE for its platform. The native wheel is one file for each platform, and it serves every Python version because it loads its library with `ctypes`.

[cols="2,3"]
[cols="2,3,3"]
|===
| Platform | Wheel tag (JVM wheel, Python 3.12)
| Platform | Wheel tag, `{native-pkg-name}` | Wheel tag, `{jvm-pkg-name}` (Python 3.12)

| Linux x86_64
| `manylinux_2_34_x86_64`
| `manylinux_2_28_x86_64`: glibc 2.28 or later (RHEL 8 and Rocky 8, Debian 10, Ubuntu 20.04 and newer)
| `manylinux_2_34_x86_64`: glibc 2.34 or later (RHEL 9, Debian 12, Ubuntu 22.04 and newer)

| Linux ARM64
| `manylinux_2_34_aarch64`
| `manylinux_2_28_aarch64`: glibc 2.28 or later
| `manylinux_2_34_aarch64`: glibc 2.34 or later

| macOS Apple Silicon
| `macosx_11_0_arm64`
| `macosx_11_0_arm64`

| Windows x86_64
| `win_amd64`
| `win_amd64`
|===

Each native wheel is about 38 MB. These platforms are not built, and pip finds no wheel for them:

* *Intel Macs* (macOS x86_64). Apple has sold only Apple Silicon Macs since 2023, and macOS 26 is the last release for Intel Macs. On an Intel Mac, run the Linux wheel in Docker or in a Linux virtual machine.
* *Alpine Linux and other musl-based distributions.* The Linux wheels are for glibc. pip then says `No matching distribution found` (for a wheel file you downloaded: `is not a supported wheel on this platform`). Use a glibc image, for example `python:3.12-slim`.
* *Windows on ARM.*
* *Linux with an older glibc than the table*, for example Amazon Linux 2 and CentOS 7.

[[what-is-included]]
== What is included

Expand Down
8 changes: 4 additions & 4 deletions docs/modules/ROOT/pages/which-package.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ The API is the same. The runtime is not. These are the differences you can plan
| Larger. It carries a Java 25 runtime for its platform.

| Python versions
| 3.11 to 3.14
| 3.11 to 3.14
| 3.11 to 3.15. On 3.15 the CI runs a subset of the tests.
| 3.11 to 3.14. JPype has no 3.15 wheel yet.

| Platforms
| Linux x86_64 (glibc 2.34 or later), Linux aarch64, macOS arm64, Windows x64. The Windows wheel is the newest: it is built in CI, and its test run is the least proven of the four.
| Linux x86_64 (glibc 2.34 or later), Linux aarch64, macOS arm64, Windows x64.
| Linux x86_64 and aarch64 (glibc 2.28 or later), macOS arm64, Windows x64. The Windows wheel is the newest: it is built in CI, and its test run is the least proven of the four. Not built: Intel Mac, Alpine (musl), Windows on ARM. See xref:installation.adoc#requirements[Requirements].
| Linux x86_64 and aarch64 (glibc 2.34 or later), macOS arm64, Windows x64. Not built: Intel Mac, Alpine (musl), Windows on ARM.

| Java-object APIs (`get_java_database`, `get_java_document`, `get_java_*`)
| Not available. They raise `NotOnNativeYet`.
Expand Down
Loading
Loading