This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-nanoarrow.git
The following commit(s) were added to refs/heads/main by this push:
new b3c952a3 chore(ci): Integrate Python into more CI workflows (#359)
b3c952a3 is described below
commit b3c952a3e21c2b47df85dbede3444f852614a3e2
Author: Dewey Dunnington <[email protected]>
AuthorDate: Wed Jan 17 09:32:49 2024 -0400
chore(ci): Integrate Python into more CI workflows (#359)
This PR adds Python to the coverage and verify workflows (except on
centos7, where the image isn't set up for a supported version of Python
yet). There were also some housekeeping issues identified by various
logs that I noticed in the process (e.g., fixing the Python dev version
format, ensuring that CMAKE_BIN is respected in bootstrap.py).
---
.github/workflows/coverage.yaml | 4 +--
.github/workflows/python.yaml | 25 ++------------
.github/workflows/verify.yaml | 4 ++-
ci/scripts/coverage.sh | 38 +++++++++++++++++++++
dev/release/verify-release-candidate.sh | 58 +++++++++++++++++++++++++++++++++
python/bootstrap.py | 9 +++--
python/pyproject.toml | 8 +++--
python/setup.py | 3 +-
python/src/nanoarrow/_lib.pyx | 2 +-
python/src/nanoarrow/_static_version.py | 2 +-
python/tests/test_version.py | 2 +-
11 files changed, 119 insertions(+), 36 deletions(-)
diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml
index 25dd1cf4..74876381 100644
--- a/.github/workflows/coverage.yaml
+++ b/.github/workflows/coverage.yaml
@@ -55,6 +55,6 @@ jobs:
path: _coverage
- name: Upload coverage to codecov
- uses: codecov/codecov-action@v2
+ uses: codecov/codecov-action@v3
with:
- files: '_coverage/coverage.info,_coverage/r_coverage.json'
+ files:
'_coverage/coverage.info,_coverage/r_coverage.json,_coverage/python_coverage.xml'
diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml
index 85f12c2e..c60f2290 100644
--- a/.github/workflows/python.yaml
+++ b/.github/workflows/python.yaml
@@ -36,7 +36,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
- python-version: ['3.10']
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
steps:
- uses: actions/checkout@v3
@@ -59,27 +59,6 @@ jobs:
pytest python/tests -v -s
- name: Run doctests
- if: success() && matrix.python-version == '3.10'
+ if: success() && matrix.python-version == '3.12'
run: |
pytest --pyargs nanoarrow --doctest-modules
-
- - name: Coverage
- if: success() && matrix.python-version == '3.10'
- run: |
- pip uninstall --yes nanoarrow
- pip install pytest-cov Cython
- pushd python
-
- # Build with Cython + gcc coverage options
- pip install -e .
- NANOARROW_PYTHON_COVERAGE=1 python setup.py build_ext --inplace
-
- # Run tests + coverage.py (generates .coverage + coverage.xml files)
- python -m pytest --cov ./src/nanoarrow
- python -m coverage xml
-
- - name: Upload coverage to codecov
- if: success() && matrix.python-version == '3.10'
- uses: codecov/codecov-action@v2
- with:
- files: 'python/coverage.xml'
diff --git a/.github/workflows/verify.yaml b/.github/workflows/verify.yaml
index c5d12360..b0943905 100644
--- a/.github/workflows/verify.yaml
+++ b/.github/workflows/verify.yaml
@@ -138,7 +138,9 @@ jobs:
- {
platform: "centos7",
arch: "amd64",
- compose_args: "-e NANOARROW_ACCEPT_IMPORT_GPG_KEYS_ERROR=1"
+ # Currently the Python on the centos7 image is 3.6, which does
not support
+ # new enough setuptools to build the Python package.
+ compose_args: "-e NANOARROW_ACCEPT_IMPORT_GPG_KEYS_ERROR=1 -e
TEST_PYTHON=0"
}
- {
platform: "ubuntu",
diff --git a/ci/scripts/coverage.sh b/ci/scripts/coverage.sh
index ad7374ab..8c866bb9 100755
--- a/ci/scripts/coverage.sh
+++ b/ci/scripts/coverage.sh
@@ -52,7 +52,15 @@ case $# in
;;
esac
+maybe_activate_venv() {
+ if [ ! -z "${NANOARROW_PYTHON_VENV}" ]; then
+ source "${NANOARROW_PYTHON_VENV}/bin/activate"
+ fi
+}
+
function main() {
+ maybe_activate_venv
+
SANDBOX_DIR="${TARGET_NANOARROW_DIR}/_coverage"
if [ -d "${SANDBOX_DIR}" ]; then
rm -rf "${SANDBOX_DIR}"
@@ -107,6 +115,7 @@ function main() {
--exclude "*/gtest/*" \
--exclude "*/flatcc/*" \
--exclude "*_generated.h" \
+ --exclude "*nanoarrow/_deps/*" \
--output-file coverage.info
# Generate the html coverage while we're here
@@ -137,6 +146,35 @@ function main() {
show_header "R package coverage summary"
Rscript -e 'library(covr); print(readRDS("r_coverage.rds"))'
popd
+
+ # Build + test Python package with cython/gcc coverage options
+ show_header "Build + test Python package"
+ pushd "${SANDBOX_DIR}"
+ TARGET_NANOARROW_PYTHON_DIR="${TARGET_NANOARROW_DIR}/python"
+
+ pushd "${TARGET_NANOARROW_PYTHON_DIR}"
+ NANOARROW_PYTHON_COVERAGE=1 python -m pip install -e .
+
+ # Run tests + coverage.py (generates .coverage with absolute file paths)
+ python -m pytest --cov ./src/nanoarrow
+
+ # Generate HTML report (file paths not important since it's just for
viewing)
+ python -m coverage html
+ mv htmlcov "${SANDBOX_DIR}/python_htmlcov"
+
+ # Move .coverage to the root directory and generate coverage.xml
+ # (generates relative file paths from the root of the repo)
+ mv .coverage ..
+ cp .coveragerc ..
+ pushd ..
+ python -m coverage xml
+ mv coverage.xml "${SANDBOX_DIR}/python_coverage.xml"
+ mv .coverage "${SANDBOX_DIR}/python_coverage.db"
+ rm .coveragerc
+ popd
+
+ popd
+ popd
}
main
diff --git a/dev/release/verify-release-candidate.sh
b/dev/release/verify-release-candidate.sh
index 250bbe64..84013602 100755
--- a/dev/release/verify-release-candidate.sh
+++ b/dev/release/verify-release-candidate.sh
@@ -297,6 +297,59 @@ test_r() {
popd
}
+activate_or_create_venv() {
+ if [ ! -z "${NANOARROW_PYTHON_VENV}" ]; then
+ show_info "Activating virtual environment at ${NANOARROW_PYTHON_VENV}"
+ # bash on Windows needs venv/Scripts/activate instead of venv/bin/activate
+ source "${NANOARROW_PYTHON_VENV}/bin/activate" || source
"${NANOARROW_PYTHON_VENV}/Scripts/activate"
+ else
+ # Try python3 first, then try regular python (e.g., Windows)
+ if [ -z "${PYTHON_BIN}" ] && python3 --version >/dev/null; then
+ PYTHON_BIN=python3
+ elif [ -z "${PYTHON_BIN}" ]; then
+ PYTHON_BIN=python
+ fi
+
+ show_info "Creating temporary virtual environment using ${PYTHON_BIN}..."
+ "${PYTHON_BIN}" -m venv "${NANOARROW_TMPDIR}/venv"
+ # bash on Windows needs venv/Scripts/activate instead of venv/bin/activate
+ source "${NANOARROW_TMPDIR}/venv/bin/activate" || source
"${NANOARROW_TMPDIR}/venv/Scripts/activate"
+ python -m pip install --upgrade pip
+ fi
+}
+
+test_python() {
+ show_header "Build and test Python package"
+ activate_or_create_venv
+
+ show_info "Installing build utilities"
+ python -m pip install --upgrade build
+
+ pushd "${NANOARROW_SOURCE_DIR}/python"
+
+ show_info "Building Python package"
+ rm -rf "${NANOARROW_TMPDIR}/python"
+ python -m build --wheel --outdir "${NANOARROW_TMPDIR}/python"
+ PYTHON_WHEEL_NAME=$(ls "${NANOARROW_TMPDIR}/python" | grep -e ".whl")
+
+ # On Windows bash, pip install needs a Windows-style path
+ if uname | grep -e "_NT-" >/dev/null; then
+ pushd "${NANOARROW_TMPDIR}"
+ PYTHON_WHEEL_PATH="$(pwd -W)/python/${PYTHON_WHEEL_NAME}"
+ popd
+ else
+ PYTHON_WHEEL_PATH="${NANOARROW_TMPDIR}/python/${PYTHON_WHEEL_NAME}"
+ fi
+
+ show_info "Installing Python package"
+ python -m pip install --force-reinstall "${PYTHON_WHEEL_PATH}[verify]"
+
+ show_info "Testing wheel"
+ python -m pytest -vv
+
+ popd
+}
+
ensure_source_directory() {
show_header "Ensuring source directory"
@@ -346,6 +399,10 @@ test_source_distribution() {
test_r
fi
+ if [ ${TEST_PYTHON} -gt 0 ]; then
+ test_python
+ fi
+
popd
}
@@ -359,6 +416,7 @@ test_source_distribution() {
: ${TEST_C:=${TEST_SOURCE}}
: ${TEST_C_BUNDLED:=${TEST_C}}
: ${TEST_R:=${TEST_SOURCE}}
+: ${TEST_PYTHON:=${TEST_SOURCE}}
TEST_SUCCESS=no
diff --git a/python/bootstrap.py b/python/bootstrap.py
index b540058a..4fb2b0e9 100644
--- a/python/bootstrap.py
+++ b/python/bootstrap.py
@@ -186,7 +186,10 @@ def copy_or_generate_nanoarrow_c():
is_in_nanoarrow_repo = "nanoarrow.h" in os.listdir(
os.path.join(source_dir, "src", "nanoarrow")
)
- has_cmake = os.system("cmake --version") == 0
+ cmake_bin = os.getenv("CMAKE_BIN")
+ if not cmake_bin:
+ cmake_bin = "cmake"
+ has_cmake = os.system(f"{cmake_bin} --version") == 0
with tempfile.TemporaryDirectory() as build_dir:
if is_in_nanoarrow_repo:
@@ -206,7 +209,7 @@ def copy_or_generate_nanoarrow_c():
try:
subprocess.run(
[
- "cmake",
+ cmake_bin,
"-B",
build_dir,
"-S",
@@ -217,7 +220,7 @@ def copy_or_generate_nanoarrow_c():
)
subprocess.run(
[
- "cmake",
+ cmake_bin,
"--install",
build_dir,
"--prefix",
diff --git a/python/pyproject.toml b/python/pyproject.toml
index 7850a09f..e176be26 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -22,15 +22,19 @@ dynamic = ["version"]
readme = "README.md"
description = "Python bindings to the nanoarrow C library"
authors = [{name = "Apache Arrow Developers", email = "[email protected]"}]
+maintainers = [{name = "Apache Arrow Developers", email =
"[email protected]"}]
license = {text = "Apache-2.0"}
requires-python = ">=3.8"
[project.optional-dependencies]
test = ["pyarrow", "pytest", "numpy"]
+verify = ["pytest", "numpy"]
[project.urls]
-homepage = "https://arrow.apache.org"
-repository = "https://github.com/apache/arrow-nanoarrow"
+Homepage = "https://arrow.apache.org"
+Repository = "https://github.com/apache/arrow-nanoarrow"
+Issues = "https://github.com/apache/arrow-nanoarrow/issues"
+Changelog = "https://github.com/apache/arrow-nanoarrow/blob/main/CHANGELOG.md"
[build-system]
requires = [
diff --git a/python/setup.py b/python/setup.py
index 92f8abc9..cdffda2b 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -52,7 +52,7 @@ if os.path.exists(bootstrap_py):
# Set some extra flags for compiling with coverage support
-if os.getenv("NANOARROW_COVERAGE") == "1":
+if os.getenv("NANOARROW_PYTHON_COVERAGE") == "1":
extra_compile_args = ["--coverage"]
extra_link_args = ["--coverage"]
extra_define_macros = [("CYTHON_TRACE", 1)]
@@ -65,7 +65,6 @@ else:
extra_link_args = []
extra_define_macros = []
-
setup(
ext_modules=[
Extension(
diff --git a/python/src/nanoarrow/_lib.pyx b/python/src/nanoarrow/_lib.pyx
index f77067c9..54d7bbdc 100644
--- a/python/src/nanoarrow/_lib.pyx
+++ b/python/src/nanoarrow/_lib.pyx
@@ -915,7 +915,7 @@ cdef class CBufferView:
if format_const != NULL:
snprintf(self._format, sizeof(self._format), "%s", format_const)
else:
- snprintf(self._format, sizeof(self._format), "%ds",
self._element_size_bits // 8)
+ snprintf(self._format, sizeof(self._format), "%ds",
<int>(self._element_size_bits // 8))
def __getbuffer__(self, Py_buffer *buffer, int flags):
if self._device.device_type != ARROW_DEVICE_CPU:
diff --git a/python/src/nanoarrow/_static_version.py
b/python/src/nanoarrow/_static_version.py
index 53569eff..33ecbc5c 100644
--- a/python/src/nanoarrow/_static_version.py
+++ b/python/src/nanoarrow/_static_version.py
@@ -18,7 +18,7 @@
# This file is part of 'miniver': https://github.com/jbweston/miniver
# Replaced by version-bumping scripts at release time
-version = "0.4.0dev0"
+version = "0.4.0.dev0"
# These values are only set if the distribution was created with 'git archive'
refnames = "$Format:%D$"
diff --git a/python/tests/test_version.py b/python/tests/test_version.py
index 2b080d64..701019cc 100644
--- a/python/tests/test_version.py
+++ b/python/tests/test_version.py
@@ -21,7 +21,7 @@ import nanoarrow as na
def test_version():
- re_py_version = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(dev[0-9+])?$")
+ re_py_version = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(\.dev[0-9+])?$")
assert re_py_version.match(na.__version__) is not None