This is an automated email from the ASF dual-hosted git repository.

apitrou 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 866502e6d6 GH-45867: [Python] Fix `SetuptoolsDeprecationWarning` 
(#47141)
866502e6d6 is described below

commit 866502e6d64e1e2422bbe7978c7bc3a5617431df
Author: Patrick J. Roddy <[email protected]>
AuthorDate: Thu Dec 18 12:11:45 2025 +0000

    GH-45867: [Python] Fix `SetuptoolsDeprecationWarning` (#47141)
    
    ### Rationale for this change
    When building locally, I get many errors along the lines of
    
    ```
    Please ensure the files specified are contained by the root
    of the Python package (normally marked by `pyproject.toml`).
    
    By 2026-Mar-20, you need to update your project and remove deprecated calls
    or your builds will no longer be supported.
    
    See https://packaging.python.org/en/latest/specifications/glob-patterns/ 
for details.
    ```
    
    <img width="958" height="755" alt="terminal demo" 
src="https://github.com/user-attachments/assets/67f0e261-c4d2-403c-b004-688dfaaccda6";
 />
    
    ### What changes are included in this PR?
    - Make the licence [SPDX compliant](https://spdx.org/licenses)
    - Remove the licence classifier
    - Move the licence files from `setup.cfg` to `pyproject.toml`
    - Fix the [disallowed glob 
patterns](https://packaging.python.org/en/latest/specifications/glob-patterns) 
via symlinks
    - Bumped the minimum version of `setuptools` due to macOS CI failures 
(don't know why this happened, caching maybe?)
    
    I appreciate the symlink change might prove controversial. See discussions 
in https://github.com/apache/arrow/issues/45867, fixes 
https://github.com/apache/arrow/issues/45867.
    
    ### Are these changes tested?
    When I rebuild locally, I get no errors any more.
    
    ### Are there any user-facing changes?
    Yes. The minimum required version of `setuptools` is now `77`. However, 
this is available on `>=3.9` so won't affect anyone really.
    
    * GitHub Issue: #45867
    
    Authored-by: Patrick J. Roddy <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 ci/conda_env_python.txt       |  2 +-
 python/.gitignore             |  5 +++++
 python/pyproject.toml         |  9 ++++++---
 python/requirements-build.txt |  2 +-
 python/setup.cfg              |  5 -----
 python/setup.py               | 34 +++++++++++++++++++++++++++++++++-
 6 files changed, 46 insertions(+), 11 deletions(-)

diff --git a/ci/conda_env_python.txt b/ci/conda_env_python.txt
index 4e3fd9f2de..eddba95a11 100644
--- a/ci/conda_env_python.txt
+++ b/ci/conda_env_python.txt
@@ -28,5 +28,5 @@ numpy>=1.16.6
 pytest
 pytest-faulthandler
 s3fs>=2023.10.0
-setuptools>=64
+setuptools>=77
 setuptools_scm>=8
diff --git a/python/.gitignore b/python/.gitignore
index fbc3b19243..dec4ffc1c9 100644
--- a/python/.gitignore
+++ b/python/.gitignore
@@ -45,3 +45,8 @@ pyarrow/_table_api.h
 manylinux1/arrow
 nm_arrow.log
 visible_symbols.log
+
+# the purpose of the custom SDist class in setup.py is to include these files
+# in the sdist tarball, but we don't want to track duplicates
+LICENSE.txt
+NOTICE.txt
diff --git a/python/pyproject.toml b/python/pyproject.toml
index fe812227eb..0a730fd4f7 100644
--- a/python/pyproject.toml
+++ b/python/pyproject.toml
@@ -22,7 +22,7 @@ requires = [
     # configuring setuptools_scm in pyproject.toml requires
     # versions released after 2022
     "setuptools_scm[toml]>=8",
-    "setuptools>=64",
+    "setuptools>=77",
 ]
 build-backend = "setuptools.build_meta"
 
@@ -32,9 +32,12 @@ dynamic = ["version"]
 requires-python = ">=3.10"
 description = "Python library for Apache Arrow"
 readme = {file = "README.md", content-type = "text/markdown"}
-license = {text = "Apache Software License"}
+license = "Apache-2.0"
+license-files = [
+    "LICENSE.txt",
+    "NOTICE.txt",
+]
 classifiers  = [
-    'License :: OSI Approved :: Apache Software License',
     'Programming Language :: Python :: 3.10',
     'Programming Language :: Python :: 3.11',
     'Programming Language :: Python :: 3.12',
diff --git a/python/requirements-build.txt b/python/requirements-build.txt
index e3fb5bc000..9e03e04ade 100644
--- a/python/requirements-build.txt
+++ b/python/requirements-build.txt
@@ -1,4 +1,4 @@
 cython>=3.1
 numpy>=1.25
 setuptools_scm>=8
-setuptools>=64
+setuptools>=77
diff --git a/python/setup.cfg b/python/setup.cfg
index 3df4ff27ef..b0c3edfa8b 100644
--- a/python/setup.cfg
+++ b/python/setup.cfg
@@ -15,11 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-[metadata]
-license_files =
-  ../LICENSE.txt
-  ../NOTICE.txt
-
 [build_sphinx]
 source-dir = doc/
 build-dir  = doc/_build
diff --git a/python/setup.py b/python/setup.py
index b6fea83eb0..a27bd3baef 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -23,6 +23,7 @@ import os.path
 from os.path import join as pjoin
 import re
 import shlex
+import shutil
 import sys
 import warnings
 
@@ -33,6 +34,7 @@ else:
     from distutils import sysconfig
 
 from setuptools import setup, Extension, Distribution
+from setuptools.command.sdist import sdist
 
 from Cython.Distutils import build_ext as _build_ext
 import Cython
@@ -395,11 +397,41 @@ class BinaryDistribution(Distribution):
         return True
 
 
+class CopyLicenseSdist(sdist):
+    """Custom sdist command that copies license files from parent directory."""
+
+    def make_release_tree(self, base_dir, files):
+        # Call parent to do the normal work
+        super().make_release_tree(base_dir, files)
+
+        # Define source (parent dir) and destination (sdist root) for license 
files
+        license_files = [
+            ("LICENSE.txt", "../LICENSE.txt"),
+            ("NOTICE.txt", "../NOTICE.txt"),
+        ]
+
+        for dest_name, src_path in license_files:
+            src_full = os.path.join(os.path.dirname(__file__), src_path)
+            dest_full = os.path.join(base_dir, dest_name)
+
+            # Remove any existing file/symlink at destination
+            if os.path.exists(dest_full) or os.path.islink(dest_full):
+                os.unlink(dest_full)
+
+            if not os.path.exists(src_full):
+                msg = f"Required license file not found: {src_full}"
+                raise FileNotFoundError(msg)
+
+            shutil.copy2(src_full, dest_full)
+            print(f"Copied {src_path} to {dest_name} in sdist")
+
+
 setup(
     distclass=BinaryDistribution,
     # Dummy extension to trigger build_ext
     ext_modules=[Extension('__dummy__', sources=[])],
     cmdclass={
-        'build_ext': build_ext
+        'build_ext': build_ext,
+        'sdist': CopyLicenseSdist,
     },
 )

Reply via email to