3838 PYTHON_ARG =
3939endif
4040
41+ # Extras that lack free-threaded (PEP 703) wheels
42+ FREE_THREADED_INCOMPATIBLE_EXTRAS = bodo ray sql-postgres hive-kerberos datafusion
43+
44+ # Detect free-threaded Python (e.g. PYTHON=3.14t) and exclude incompatible extras
45+ ifneq ($(findstring t,$(PYTHON ) ) ,)
46+ EXTRAS_ARG = --all-extras $(foreach extra,$(FREE_THREADED_INCOMPATIBLE_EXTRAS ) ,--no-extra $(extra ) )
47+ # Ignore test files that import excluded extras at module level
48+ FREE_THREADED_PYTEST_IGNORES = --ignore=tests/table/test_datafusion.py --ignore=tests/table/test_upsert.py -k "not kerberos"
49+ else
50+ EXTRAS_ARG = --all-extras
51+ FREE_THREADED_PYTEST_IGNORES =
52+ endif
53+
4154ifeq ($(COVERAGE ) ,1)
4255 TEST_RUNNER = uv run $(PYTHON_ARG ) python -m coverage run --parallel-mode --source=pyiceberg -m
4356else
@@ -74,11 +87,11 @@ install-uv: ## Ensure uv is installed
7487 fi
7588
7689install : install-uv # # Install uv, dependencies, and pre-commit hooks
77- uv sync $(PYTHON_ARG ) --all-extras
90+ uv sync $(PYTHON_ARG ) $( EXTRAS_ARG )
7891 @# Reinstall pyiceberg if Cython extensions (.so) are missing after `make clean` (see #2869)
7992 @if ! find pyiceberg -name " *.so" 2> /dev/null | grep -q . ; then \
8093 echo " Cython extensions not found, reinstalling pyiceberg..." ; \
81- uv sync $(PYTHON_ARG ) --all-extras --reinstall-package pyiceberg; \
94+ uv sync $(PYTHON_ARG ) $( EXTRAS_ARG ) --reinstall-package pyiceberg; \
8295 fi
8396 @# Install pre-commit hooks (skipped outside git repo, e.g. release tarballs)
8497 @if [ -d .git ]; then \
@@ -104,7 +117,7 @@ lint: ## Run code linters via prek (pre-commit hooks)
104117# #@ Testing
105118
106119test : # # Run all unit tests (excluding integration)
107- $(TEST_RUNNER ) pytest tests/ -m " (unmarked or parametrize) and not integration" $(PYTEST_ARGS )
120+ $(TEST_RUNNER ) pytest tests/ -m " (unmarked or parametrize) and not integration" $(FREE_THREADED_PYTEST_IGNORES ) $( PYTEST_ARGS )
108121
109122test-integration : test-integration-setup test-integration-exec test-integration-cleanup # # Run integration tests
110123
@@ -115,7 +128,7 @@ test-integration-setup: install ## Start Docker services for integration tests
115128 uv run $(PYTHON_ARG ) python dev/provision.py
116129
117130test-integration-exec : # # Run integration tests (excluding provision)
118- $(TEST_RUNNER ) pytest tests/ -m integration $(PYTEST_ARGS )
131+ $(TEST_RUNNER ) pytest tests/ -m integration $(FREE_THREADED_PYTEST_IGNORES ) $( PYTEST_ARGS )
119132
120133test-integration-cleanup : # # Clean up integration test environment
121134 @if [ " ${KEEP_COMPOSE} " != " 1" ]; then \
0 commit comments