This is an automated email from the ASF dual-hosted git repository.
raulcd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new e1c6fd5304 GH-42137 [CI][Python] Add Python Windows GitHub Action and
remove AppVeyor (#47567)
e1c6fd5304 is described below
commit e1c6fd53048553deb61e69e53581fcf9d59e4f55
Author: Raúl Cumplido <[email protected]>
AuthorDate: Wed Sep 17 09:48:52 2025 +0000
GH-42137 [CI][Python] Add Python Windows GitHub Action and remove AppVeyor
(#47567)
### Rationale for this change
There is currently a single CI job on AppVeyor. This is the only job on
Windows for Python and it usually fails due to CI issues rather than Python
real issues. We have more experience with GitHub actions and debugging AppVeyor
is usually challenging.
### What changes are included in this PR?
Create a Python Windows job that runs on GitHub actions. The job builds
Arrow CPP and PyArrow and it tests PyArrow.
Also removes the CI related files for AppVeyor
### Are these changes tested?
Yes, via CI.
### Are there any user-facing changes?
No
* GitHub Issue: #42137
Lead-authored-by: Raúl Cumplido <[email protected]>
Co-authored-by: Sutou Kouhei <[email protected]>
Signed-off-by: Raúl Cumplido <[email protected]>
---
.github/workflows/python.yml | 57 +++++++++++++++
appveyor.yml | 63 -----------------
ci/appveyor-cpp-build.bat | 163 -------------------------------------------
ci/appveyor-cpp-setup.bat | 102 ---------------------------
ci/scripts/python_build.bat | 139 ++++++++++++++++++++++++++++++++++++
ci/scripts/python_test.bat | 41 +++++++++++
6 files changed, 237 insertions(+), 328 deletions(-)
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 581d479da9..0d12accda4 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -239,3 +239,60 @@ jobs:
- name: Test
shell: bash
run: ci/scripts/python_test.sh $(pwd) $(pwd)/build
+
+ windows:
+ name: AMD64 Windows 2022 Python 3.13
+ runs-on: windows-2022
+ if: ${{ !contains(github.event.pull_request.title, 'WIP') }}
+ timeout-minutes: 60
+ env:
+ PYTHON_CMD: "py -3.13"
+ steps:
+ - name: Disable Crash Dialogs
+ run: |
+ reg add `
+ "HKCU\SOFTWARE\Microsoft\Windows\Windows Error Reporting" `
+ /v DontShowUI `
+ /t REG_DWORD `
+ /d 1 `
+ /f
+ - name: Checkout Arrow
+ uses: actions/checkout@v5
+ with:
+ fetch-depth: 0
+ submodules: recursive
+ - name: Setup Python
+ uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c #
v6.0.0
+ with:
+ python-version: 3.13
+ - name: Install ccache
+ shell: bash
+ run: |
+ ci/scripts/install_ccache.sh 4.6.3 /usr
+ - name: Setup ccache
+ shell: bash
+ run: |
+ ci/scripts/ccache_setup.sh
+ - name: Generate path variables
+ id: path-info
+ shell: bash
+ run: |
+ echo "CCACHE_DIR=$(ccache --get-config cache_dir)" >> $GITHUB_ENV
+ echo "usr-windows-dir="$(cygpath --absolute --windows /usr)"" >>
$GITHUB_OUTPUT
+ - name: Cache ccache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.CCACHE_DIR }}
+ key: python-ccache-windows-${{ env.CACHE_VERSION }}-${{
hashFiles('cpp/**') }}
+ restore-keys: python-ccache-windows-${{ env.CACHE_VERSION }}-
+ env:
+ # We can invalidate the current cache by updating this.
+ CACHE_VERSION: "2025-09-16.1"
+ - name: Build Arrow C++ and PyArrow
+ shell: cmd
+ run: |
+ call "ci\scripts\python_build.bat" %cd% "${{
steps.path-info.outputs.usr-windows-dir }}"
+ - name: Test PyArrow
+ shell: cmd
+ run: |
+ call "ci\scripts\python_test.bat" %cd%
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 9e4582f1d8..0000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-# Operating system (build VM template)
-os: Visual Studio 2019
-
-only_commits:
- # Skip commits not related to Python or C++
- files:
- - appveyor.yml
- - ci/appveyor*
- - ci/conda*
- - ci/scripts/*.bat
- - cpp/
- - format/
- - python/
-
-cache:
- - C:\Users\appveyor\AppData\Local\ccache
-
-matrix:
- fast_finish: true
-
-environment:
- global:
- APPVEYOR_SAVE_CACHE_ON_ERROR: true
- MSVC_DEFAULT_OPTIONS: ON
-
- ARCH: "64"
- ARROW_BUILD_FLIGHT: "ON"
- ARROW_BUILD_FLIGHT_SQL: "ON"
- ARROW_BUILD_GANDIVA: "ON"
- ARROW_GCS: "ON"
- ARROW_ORC: "ON"
- ARROW_S3: "ON"
- GENERATOR: Ninja
- PYTHON: "3.10"
-
-before_build:
- - call ci\appveyor-cpp-setup.bat
-
-build_script:
- - call ci\appveyor-cpp-build.bat
-
-# Disable test discovery
-test: off
-
-after_build:
- - ccache -sv
diff --git a/ci/appveyor-cpp-build.bat b/ci/appveyor-cpp-build.bat
deleted file mode 100644
index eb6a2cb720..0000000000
--- a/ci/appveyor-cpp-build.bat
+++ /dev/null
@@ -1,163 +0,0 @@
-@rem Licensed to the Apache Software Foundation (ASF) under one
-@rem or more contributor license agreements. See the NOTICE file
-@rem distributed with this work for additional information
-@rem regarding copyright ownership. The ASF licenses this file
-@rem to you under the Apache License, Version 2.0 (the
-@rem "License"); you may not use this file except in compliance
-@rem with the License. You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing,
-@rem software distributed under the License is distributed on an
-@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@rem KIND, either express or implied. See the License for the
-@rem specific language governing permissions and limitations
-@rem under the License.
-
-@echo on
-
-git config core.symlinks true
-git reset --hard
-
-@rem Retrieve git submodules, configure env var for Parquet unit tests
-git submodule update --init || exit /B
-
-set ARROW_TEST_DATA=%CD%\testing\data
-set PARQUET_TEST_DATA=%CD%\cpp\submodules\parquet-testing\data
-
-@rem Enable memory debug checks if the env is not set already
-IF "%ARROW_DEBUG_MEMORY_POOL%"=="" (
- set ARROW_DEBUG_MEMORY_POOL=trap
-)
-
-set CMAKE_BUILD_PARALLEL_LEVEL=%NUMBER_OF_PROCESSORS%
-set CTEST_PARALLEL_LEVEL=%NUMBER_OF_PROCESSORS%
-
-call activate arrow
-
-@rem The "main" C++ build script for Windows CI
-@rem (i.e. for usual configurations)
-
-set ARROW_CMAKE_ARGS=-DARROW_DEPENDENCY_SOURCE=CONDA -DARROW_WITH_BZ2=ON
-
-@rem Enable warnings-as-errors
-set ARROW_CXXFLAGS=/WX /MP
-
-@rem Install GCS testbench
-set PIPX_BIN_DIR=C:\Windows\
-call %CD%\ci\scripts\install_gcs_testbench.bat
-storage-testbench -h || exit /B
-
-@rem
-@rem Build and test Arrow C++ libraries (including Parquet)
-@rem
-
-mkdir cpp\build
-pushd cpp\build
-
-@rem XXX Without forcing CMAKE_CXX_COMPILER, CMake can re-run itself and
-@rem unfortunately switch from Release to Debug mode...
-@rem
-@rem In release mode, disable optimizations (/Od) for faster compiling
-@rem and enable runtime assertions.
-
-cmake -G "%GENERATOR%" %ARROW_CMAKE_ARGS% ^
- -DARROW_ACERO=ON ^
- -DARROW_BOOST_USE_SHARED=ON ^
- -DARROW_BUILD_EXAMPLES=ON ^
- -DARROW_BUILD_STATIC=OFF ^
- -DARROW_BUILD_TESTS=ON ^
- -DARROW_COMPUTE=ON ^
- -DARROW_CSV=ON ^
- -DARROW_CXXFLAGS="%ARROW_CXXFLAGS%" ^
- -DARROW_DATASET=ON ^
- -DARROW_ENABLE_TIMING_TESTS=OFF ^
- -DARROW_FILESYSTEM=ON ^
- -DARROW_FLIGHT=%ARROW_BUILD_FLIGHT% ^
- -DARROW_FLIGHT_SQL=%ARROW_BUILD_FLIGHT_SQL% ^
- -DARROW_GANDIVA=%ARROW_BUILD_GANDIVA% ^
- -DARROW_GCS=%ARROW_GCS% ^
- -DARROW_HDFS=ON ^
- -DARROW_JSON=ON ^
- -DARROW_MIMALLOC=ON ^
- -DARROW_ORC=%ARROW_ORC% ^
- -DARROW_PARQUET=ON ^
- -DARROW_S3=%ARROW_S3% ^
- -DARROW_SUBSTRAIT=ON ^
- -DARROW_VERBOSE_THIRDPARTY_BUILD=OFF ^
- -DARROW_WITH_BROTLI=ON ^
- -DARROW_WITH_LZ4=ON ^
- -DARROW_WITH_SNAPPY=ON ^
- -DARROW_WITH_ZLIB=ON ^
- -DARROW_WITH_ZSTD=ON ^
- -DCMAKE_BUILD_TYPE="Release" ^
- -DCMAKE_CXX_FLAGS_RELEASE="/MD /Od /UNDEBUG" ^
- -DCMAKE_CXX_STANDARD=17 ^
- -DCMAKE_INSTALL_PREFIX=%CONDA_PREFIX%\Library ^
- -DCMAKE_UNITY_BUILD=ON ^
- -DCMAKE_VERBOSE_MAKEFILE=OFF ^
- -DPARQUET_BUILD_EXECUTABLES=ON ^
- -DPARQUET_REQUIRE_ENCRYPTION=ON ^
- .. || exit /B
-cmake --build . --target install --config Release || exit /B
-
-@rem For ORC C++
-set TZDIR=%CONDA_PREFIX%\share\zoneinfo
-
-@rem For finding Python executable for GCS tests
-set PYTHON=python
-
-ctest --output-on-failure || exit /B
-
-popd
-
-pushd python
-
-@rem
-@rem Build and install pyarrow
-@rem
-
-set PYARROW_CMAKE_GENERATOR=%GENERATOR%
-set PYARROW_CXXFLAGS=%ARROW_CXXFLAGS%
-set PYARROW_PARALLEL=2
-set PYARROW_WITH_ACERO=ON
-set PYARROW_WITH_DATASET=ON
-set PYARROW_WITH_FLIGHT=%ARROW_BUILD_FLIGHT%
-set PYARROW_WITH_GANDIVA=%ARROW_BUILD_GANDIVA%
-set PYARROW_WITH_GCS=%ARROW_GCS%
-set PYARROW_WITH_ORC=%ARROW_ORC%
-set PYARROW_WITH_PARQUET=ON
-set PYARROW_WITH_PARQUET_ENCRYPTION=ON
-set PYARROW_WITH_S3=%ARROW_S3%
-set PYARROW_WITH_SUBSTRAIT=ON
-
-set ARROW_HOME=%CONDA_PREFIX%\Library
-@rem ARROW-3075; pkgconfig is broken for Parquet for now
-set PARQUET_HOME=%CONDA_PREFIX%\Library
-
-pip install --no-deps --no-build-isolation -vv --editable .
-
-@rem
-@rem Run pyarrow tests
-@rem
-
-@rem Download IANA Timezone Database to a non-standard location to
-@rem test the configurability of the timezone database path
-curl https://data.iana.org/time-zones/releases/tzdata2024b.tar.gz --output
tzdata.tar.gz || exit /B
-mkdir %USERPROFILE%\Downloads\test\tzdata
-tar --extract --file tzdata.tar.gz --directory
%USERPROFILE%\Downloads\test\tzdata
-curl
https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
^
- --output %USERPROFILE%\Downloads\test\tzdata\windowsZones.xml || exit /B
-@rem Remove the database from the default location
-rmdir /s /q %USERPROFILE%\Downloads\tzdata
-@rem Set the env var for the non-standard location of the database
-@rem (only needed for testing purposes)
-set PYARROW_TZDATA_PATH=%USERPROFILE%\Downloads\test\tzdata
-
-set AWS_EC2_METADATA_DISABLED=true
-set PYTHONDEVMODE=1
-
-popd
-
-python -m pytest -r sxX --durations=15 --pyargs pyarrow || exit /B
diff --git a/ci/appveyor-cpp-setup.bat b/ci/appveyor-cpp-setup.bat
deleted file mode 100644
index ff159bd0b4..0000000000
--- a/ci/appveyor-cpp-setup.bat
+++ /dev/null
@@ -1,102 +0,0 @@
-@rem Licensed to the Apache Software Foundation (ASF) under one
-@rem or more contributor license agreements. See the NOTICE file
-@rem distributed with this work for additional information
-@rem regarding copyright ownership. The ASF licenses this file
-@rem to you under the Apache License, Version 2.0 (the
-@rem "License"); you may not use this file except in compliance
-@rem with the License. You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing,
-@rem software distributed under the License is distributed on an
-@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-@rem KIND, either express or implied. See the License for the
-@rem specific language governing permissions and limitations
-@rem under the License.
-
-@echo on
-
-@rem
-@rem The miniconda install on AppVeyor is very outdated, use Mambaforge instead
-@rem
-
-appveyor DownloadFile
https://github.com/conda-forge/miniforge/releases/download/24.9.2-0/Mambaforge-Windows-x86_64.exe
|| exit /B
-start /wait "" Mambaforge-Windows-x86_64.exe /InstallationType=JustMe
/RegisterPython=0 /S /D=C:\Mambaforge
-set "PATH=C:\Mambaforge\scripts;C:\Mambaforge\condabin;%PATH%"
-
-@rem
-@rem Avoid picking up AppVeyor-installed OpenSSL (linker errors with gRPC)
-@rem XXX Perhaps there is a smarter way of solving this issue?
-@rem
-rd /s /q C:\OpenSSL-Win32
-rd /s /q C:\OpenSSL-Win64
-rd /s /q C:\OpenSSL-v11-Win32
-rd /s /q C:\OpenSSL-v11-Win64
-rd /s /q C:\OpenSSL-v111-Win32
-rd /s /q C:\OpenSSL-v111-Win64
-rd /s /q C:\OpenSSL-v30-Win32
-rd /s /q C:\OpenSSL-v30-Win64
-
-@rem
-@rem Configure conda
-@rem
-conda config --set auto_update_conda false
-conda config --set show_channel_urls true
-conda config --set always_yes true
-@rem Help with SSL timeouts to S3
-conda config --set remote_connect_timeout_secs 12
-
-conda info -a || exit /B
-
-@rem
-@rem Create conda environment
-@rem
-
-set CONDA_PACKAGES=
-
-if "%ARROW_BUILD_GANDIVA%" == "ON" (
- @rem Install llvmdev in the toolchain if building gandiva.dll
- set CONDA_PACKAGES=%CONDA_PACKAGES% --file=ci\conda_env_gandiva_win.txt
-)
-@rem Install pre-built "toolchain" packages for faster builds
-set CONDA_PACKAGES=%CONDA_PACKAGES% --file=ci\conda_env_cpp.txt
-@rem Arrow conda environment
-conda create -n arrow ^
- --file=ci\conda_env_python.txt ^
- %CONDA_PACKAGES% ^
- "ccache" ^
- "cmake" ^
- "ninja" ^
- "nomkl" ^
- "pandas" ^
- "python=%PYTHON%" ^
- || exit /B
-conda list -n arrow
-
-@rem
-@rem Configure compiler
-@rem
-call "C:\Program Files (x86)\Microsoft Visual
Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
-set CC=cl.exe
-set CXX=cl.exe
-
-@rem
-@rem Download Minio somewhere on PATH, for unit tests
-@rem
-if "%ARROW_S3%" == "ON" (
- appveyor DownloadFile
https://dl.min.io/server/minio/release/windows-amd64/archive/minio.RELEASE.2025-01-20T14-49-07Z
-FileName C:\Windows\Minio.exe || exit /B
-)
-
-@rem
-@rem Download IANA Timezone Database for unit tests
-@rem
-@rem (Doc section: Download timezone database)
-curl https://data.iana.org/time-zones/releases/tzdata2021e.tar.gz --output
tzdata.tar.gz
-mkdir tzdata
-tar --extract --file tzdata.tar.gz --directory tzdata
-move tzdata %USERPROFILE%\Downloads\tzdata
-@rem Also need Windows timezone mapping
-curl
https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
^
- --output %USERPROFILE%\Downloads\tzdata\windowsZones.xml
-@rem (Doc section: Download timezone database)
diff --git a/ci/scripts/python_build.bat b/ci/scripts/python_build.bat
new file mode 100644
index 0000000000..417cc0d5dd
--- /dev/null
+++ b/ci/scripts/python_build.bat
@@ -0,0 +1,139 @@
+@rem Licensed to the Apache Software Foundation (ASF) under one
+@rem or more contributor license agreements. See the NOTICE file
+@rem distributed with this work for additional information
+@rem regarding copyright ownership. The ASF licenses this file
+@rem to you under the Apache License, Version 2.0 (the
+@rem "License"); you may not use this file except in compliance
+@rem with the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing,
+@rem software distributed under the License is distributed on an
+@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem KIND, either express or implied. See the License for the
+@rem specific language governing permissions and limitations
+@rem under the License.
+
+@echo on
+
+set SOURCE_DIR=%1
+set CMAKE_INSTALL_PREFIX=%2
+set CPP_SOURCE_DIR=%SOURCE_DIR%\cpp
+set CPP_BUILD_DIR=%SOURCE_DIR%\build
+echo C++ source dir is %CPP_SOURCE_DIR%
+
+echo Building for Windows ...
+
+@REM List installed Pythons
+py -0p
+
+%PYTHON_CMD% -m sysconfig || exit /B 1
+
+@REM Setup MSVC environment
+
+call "C:\Program Files\Microsoft Visual
Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
+@echo on
+
+echo "=== CCACHE Stats before build ==="
+ccache -sv
+
+echo "=== Building Arrow C++ libraries ==="
+set ARROW_ACERO=ON
+set ARROW_DATASET=ON
+set ARROW_FLIGHT=OFF
+set ARROW_GANDIVA=OFF
+set ARROW_GCS=OFF
+set ARROW_HDFS=ON
+set ARROW_MIMALLOC=ON
+set ARROW_ORC=OFF
+set ARROW_PARQUET=ON
+set PARQUET_REQUIRE_ENCRYPTION=ON
+set ARROW_SUBSTRAIT=ON
+set ARROW_S3=ON
+set ARROW_TENSORFLOW=ON
+set ARROW_WITH_BROTLI=ON
+set ARROW_WITH_BZ2=OFF
+set ARROW_WITH_LZ4=ON
+set ARROW_WITH_SNAPPY=ON
+set ARROW_WITH_ZLIB=ON
+set ARROW_WITH_ZSTD=ON
+set CMAKE_BUILD_TYPE=Release
+set CMAKE_GENERATOR=Ninja
+set CMAKE_UNITY_BUILD=ON
+
+mkdir %CPP_BUILD_DIR%
+pushd %CPP_BUILD_DIR%
+
+cmake ^
+ -DARROW_ACERO=%ARROW_ACERO% ^
+ -DARROW_BUILD_SHARED=ON ^
+ -DARROW_BUILD_STATIC=OFF ^
+ -DARROW_BUILD_TESTS=OFF ^
+ -DARROW_COMPUTE=ON ^
+ -DARROW_CSV=ON ^
+ -DARROW_CXXFLAGS="/MP" ^
+ -DARROW_DATASET=%ARROW_DATASET% ^
+ -DARROW_DEPENDENCY_USE_SHARED=OFF ^
+ -DARROW_FILESYSTEM=ON ^
+ -DARROW_FLIGHT=%ARROW_FLIGHT% ^
+ -DARROW_GANDIVA=%ARROW_GANDIVA% ^
+ -DARROW_GCS=%ARROW_GCS% ^
+ -DARROW_HDFS=%ARROW_HDFS% ^
+ -DARROW_JSON=ON ^
+ -DARROW_MIMALLOC=%ARROW_MIMALLOC% ^
+ -DARROW_ORC=%ARROW_ORC% ^
+ -DARROW_PARQUET=%ARROW_PARQUET% ^
+ -DARROW_S3=%ARROW_S3% ^
+ -DARROW_SUBSTRAIT=%ARROW_SUBSTRAIT% ^
+ -DARROW_TENSORFLOW=%ARROW_TENSORFLOW% ^
+ -DARROW_USE_CCACHE=ON ^
+ -DARROW_WITH_BROTLI=%ARROW_WITH_BROTLI% ^
+ -DARROW_WITH_BZ2=%ARROW_WITH_BZ2% ^
+ -DARROW_WITH_LZ4=%ARROW_WITH_LZ4% ^
+ -DARROW_WITH_SNAPPY=%ARROW_WITH_SNAPPY% ^
+ -DARROW_WITH_ZLIB=%ARROW_WITH_ZLIB% ^
+ -DARROW_WITH_ZSTD=%ARROW_WITH_ZSTD% ^
+ -DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE% ^
+ -DCMAKE_INSTALL_PREFIX=%CMAKE_INSTALL_PREFIX% ^
+ -DCMAKE_UNITY_BUILD=%CMAKE_UNITY_BUILD% ^
+ -DMSVC_LINK_VERBOSE=ON ^
+ -DPARQUET_REQUIRE_ENCRYPTION=%PARQUET_REQUIRE_ENCRYPTION% ^
+ -Dxsimd_SOURCE=BUNDLED ^
+ -G "%CMAKE_GENERATOR%" ^
+ %CPP_SOURCE_DIR% || exit /B 1
+cmake --build . --config %CMAKE_BUILD_TYPE% --target install || exit /B 1
+popd
+
+echo "=== CCACHE Stats after build ==="
+ccache -sv
+
+echo "=== Building Python ==="
+set PYARROW_BUILD_TYPE=%CMAKE_BUILD_TYPE%
+set PYARROW_BUILD_VERBOSE=1
+set PYARROW_BUNDLE_ARROW_CPP=ON
+set PYARROW_CMAKE_GENERATOR=%CMAKE_GENERATOR%
+set PYARROW_WITH_ACERO=%ARROW_ACERO%
+set PYARROW_WITH_DATASET=%ARROW_DATASET%
+set PYARROW_WITH_FLIGHT=%ARROW_FLIGHT%
+set PYARROW_WITH_GANDIVA=%ARROW_GANDIVA%
+set PYARROW_WITH_GCS=%ARROW_GCS%
+set PYARROW_WITH_HDFS=%ARROW_HDFS%
+set PYARROW_WITH_ORC=%ARROW_ORC%
+set PYARROW_WITH_PARQUET=%ARROW_PARQUET%
+set PYARROW_WITH_PARQUET_ENCRYPTION=%PARQUET_REQUIRE_ENCRYPTION%
+set PYARROW_WITH_SUBSTRAIT=%ARROW_SUBSTRAIT%
+set PYARROW_WITH_S3=%ARROW_S3%
+set ARROW_HOME=%CMAKE_INSTALL_PREFIX%
+set CMAKE_PREFIX_PATH=%CMAKE_INSTALL_PREFIX%
+
+pushd %SOURCE_DIR%\python
+
+@REM Install Python build dependencies
+%PYTHON_CMD% -m pip install --upgrade pip || exit /B 1
+%PYTHON_CMD% -m pip install -r requirements-build.txt || exit /B 1
+
+@REM Build PyArrow
+%PYTHON_CMD% -m pip install --no-deps --no-build-isolation -vv . || exit /B 1
+
+popd
diff --git a/ci/scripts/python_test.bat b/ci/scripts/python_test.bat
new file mode 100644
index 0000000000..f9088c7f3d
--- /dev/null
+++ b/ci/scripts/python_test.bat
@@ -0,0 +1,41 @@
+@rem Licensed to the Apache Software Foundation (ASF) under one
+@rem or more contributor license agreements. See the NOTICE file
+@rem distributed with this work for additional information
+@rem regarding copyright ownership. The ASF licenses this file
+@rem to you under the Apache License, Version 2.0 (the
+@rem "License"); you may not use this file except in compliance
+@rem with the License. You may obtain a copy of the License at
+@rem
+@rem http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing,
+@rem software distributed under the License is distributed on an
+@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem KIND, either express or implied. See the License for the
+@rem specific language governing permissions and limitations
+@rem under the License.
+
+@echo on
+
+set SOURCE_DIR=%1
+
+set ARROW_TEST_DATA=%SOURCE_DIR%\testing\data
+set PARQUET_TEST_DATA=%SOURCE_DIR%\cpp\submodules\parquet-testing\data
+
+echo Testing on Windows ...
+
+@REM List installed Pythons
+py -0p
+
+%PYTHON_CMD% -m sysconfig || exit /B 1
+
+pushd %SOURCE_DIR%\python
+
+@REM Install Python test dependencies
+%PYTHON_CMD% -m pip install -r requirements-test.txt || exit /B 1
+
+popd
+
+@REM Run Python tests
+%PYTHON_CMD% -c "import pyarrow" || exit /B 1
+%PYTHON_CMD% -m pytest -r s --pyargs pyarrow || exit /B 1