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

absurdfarce pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-python-driver.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 3c13176b CASSPYTHON-3 Introduce pyproject.toml to explicitly declare 
build dependencies
3c13176b is described below

commit 3c13176bcbf4d4cb6dd7b3d24bc71c67fc90be32
Author: absurdfarce <[email protected]>
AuthorDate: Mon Dec 22 15:51:09 2025 -0600

    CASSPYTHON-3 Introduce pyproject.toml to explicitly declare build 
dependencies
    
    patch by Bret McGuire; reviewed by Bret McGuire and Brad Schoening
    reference: https://github.com/apache/cassandra-python-driver/pull/1264
---
 cassandra/__init__.py |   6 +-
 pyproject.toml        |  56 +++++++
 setup.py              | 437 +++++++-------------------------------------------
 3 files changed, 117 insertions(+), 382 deletions(-)

diff --git a/cassandra/__init__.py b/cassandra/__init__.py
index 6d0744aa..c7327086 100644
--- a/cassandra/__init__.py
+++ b/cassandra/__init__.py
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 import logging
-
+import importlib.metadata
 
 class NullHandler(logging.Handler):
 
@@ -24,9 +24,7 @@ class NullHandler(logging.Handler):
 
 logging.getLogger('cassandra').addHandler(NullHandler())
 
-__version_info__ = (3, 29, 3)
-__version__ = '.'.join(map(str, __version_info__))
-
+__version__ = importlib.metadata.version('cassandra-driver')
 
 class ConsistencyLevel(object):
     """
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..170d96df
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,56 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = ["setuptools", "Cython>=3.0", "tomli"]
+
+[project]
+name = "cassandra-driver"
+description = "Apache Cassandra Python Driver"
+version = "3.30.0"
+dependencies = ['geomet>=1.1']
+readme = "README.rst"
+authors = [{name = "DataStax"}]
+license = "Apache-2.0"
+license-files = ["LICENSE"]
+requires-python = ">= 3.10"
+keywords = ["cassandra","cql","orm","dse","graph"]
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "Natural Language :: English",
+    "Operating System :: OS Independent",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
+    "Programming Language :: Python :: Implementation :: CPython",
+    "Programming Language :: Python :: Implementation :: PyPy",
+    "Topic :: Software Development :: Libraries :: Python Modules"
+]
+
+[project.optional-dependencies]
+graph = ["gremlinpython==3.4.6"]
+cle = ["cryptography>=42.0"]
+test = ["pytest", "PyYAML", "pytz"]
+
+[project.urls]
+homepage = "https://github.com/apache/cassandra-python-driver/";
+documentation = "https://docs.datastax.com/en/developer/python-driver/latest/";
+source = "https://github.com/apache/cassandra-python-driver/";
+issues = 
"https://issues.apache.org/jira/issues/?jql=project%20%3D%20CASSPYTHON%20ORDER%20BY%20key%20DESC";
+changelog = 
"https://github.com/apache/cassandra-python-driver/blob/trunk/CHANGELOG.rst";
+
+[tool.setuptools.packages.find]
+include = ['cassandra', 'cassandra.io', 'cassandra.cqlengine', 
'cassandra.graph',
+'cassandra.datastax', 'cassandra.datastax.insights', 
'cassandra.datastax.graph',
+'cassandra.datastax.graph.fluent', 'cassandra.datastax.cloud',
+"cassandra.column_encryption"]
+
+[tool.cassandra-driver]
+build-murmur3-extension = true
+build-libev-extension = true
+build-cython-extensions = true
+libev-includes = []
+libev-libs = []
+build-concurrency = 0
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 5144e905..a3f067c8 100644
--- a/setup.py
+++ b/setup.py
@@ -16,132 +16,22 @@
 
 import os
 import sys
-import warnings
-
-import ez_setup
-ez_setup.use_setuptools()
-
-from setuptools import setup
-from distutils.command.build_ext import build_ext
-from distutils.core import Extension
-from distutils.errors import (CCompilerError, DistutilsPlatformError,
-                              DistutilsExecError)
-from distutils.cmd import Command
 
+from pathlib import Path
+from setuptools import setup, Extension
 try:
-    import subprocess
-    has_subprocess = True
+    import tomllib as toml
 except ImportError:
-    has_subprocess = False
-
-from cassandra import __version__
-
-long_description = ""
-with open("README.rst") as f:
-    long_description = f.read()
-
-has_cqlengine = False
-if __name__ == '__main__' and sys.argv[1] == "install":
-    try:
-        import cqlengine
-        has_cqlengine = True
-    except ImportError:
-        pass
-
-PROFILING = False
-
-
-class DocCommand(Command):
-
-    description = "generate or test documentation"
-
-    user_options = [("test", "t",
-                     "run doctests instead of generating documentation")]
-
-    boolean_options = ["test"]
-
-    def initialize_options(self):
-        self.test = False
-
-    def finalize_options(self):
-        pass
-
-    def run(self):
-        if self.test:
-            path = "docs/_build/doctest"
-            mode = "doctest"
-        else:
-            path = "docs/_build/%s" % __version__
-            mode = "html"
-
-            try:
-                os.makedirs(path)
-            except OSError:
-                pass
-
-        if has_subprocess:
-            # Prevent run with in-place extensions because cython-generated 
objects do not carry docstrings
-            # 
http://docs.cython.org/src/userguide/special_methods.html#docstrings
-            import glob
-            for f in glob.glob("cassandra/*.so"):
-                print("Removing '%s' to allow docs to run on pure python 
modules." % (f,))
-                os.unlink(f)
-
-            # Build io extension to make import and docstrings work
-            try:
-                output = subprocess.check_output(
-                    ["python", "setup.py", "build_ext", "--inplace", 
"--force", "--no-murmur3", "--no-cython"],
-                    stderr=subprocess.STDOUT)
-            except subprocess.CalledProcessError as exc:
-                raise RuntimeError("Documentation step '%s' failed: %s: %s" % 
("build_ext", exc, exc.output))
-            else:
-                print(output)
-
-            try:
-                output = subprocess.check_output(
-                    ["sphinx-build", "-b", mode, "docs", path],
-                    stderr=subprocess.STDOUT)
-            except subprocess.CalledProcessError as exc:
-                raise RuntimeError("Documentation step '%s' failed: %s: %s" % 
(mode, exc, exc.output))
-            else:
-                print(output)
-
-            print("")
-            print("Documentation step '%s' performed, results here:" % mode)
-            print("   file://%s/%s/index.html" % 
(os.path.dirname(os.path.realpath(__file__)), path))
-
-
-class BuildFailed(Exception):
-
-    def __init__(self, ext):
-        self.ext = ext
-
+    import tomli as toml
 
+# ========================== General purpose vals to describe our current 
platform ==========================
 is_windows = sys.platform.startswith('win32')
 is_macos = sys.platform.startswith('darwin')
+is_pypy = "PyPy" in sys.version
+is_supported_platform = sys.platform != "cli" and not 
sys.platform.startswith("java")
+is_supported_arch = sys.byteorder != "big"
 
-murmur3_ext = Extension('cassandra.cmurmur3',
-                        sources=['cassandra/cmurmur3.c'])
-
-
-def eval_env_var_as_array(varname):
-    val = os.environ.get(varname)
-    return None if not val else [v.strip() for v in val.split(',')]
-
-
-DEFAULT_LIBEV_INCLUDES = ['/usr/include/libev', '/usr/local/include', 
'/opt/local/include', '/usr/include']
-DEFAULT_LIBEV_LIBDIRS = ['/usr/local/lib', '/opt/local/lib', '/usr/lib64']
-libev_includes = eval_env_var_as_array('CASS_DRIVER_LIBEV_INCLUDES') or 
DEFAULT_LIBEV_INCLUDES
-libev_libdirs = eval_env_var_as_array('CASS_DRIVER_LIBEV_LIBS') or 
DEFAULT_LIBEV_LIBDIRS
-if is_macos:
-    libev_includes.extend(['/opt/homebrew/include', 
os.path.expanduser('~/homebrew/include')])
-    libev_libdirs.extend(['/opt/homebrew/lib'])
-libev_ext = Extension('cassandra.io.libevwrapper',
-                      sources=['cassandra/io/libevwrapper.c'],
-                      include_dirs=libev_includes,
-                      libraries=['ev'],
-                      library_dirs=libev_libdirs)
-
+# ========================== A few upfront checks ==========================
 platform_unsupported_msg = \
 """
 ===============================================================================
@@ -163,284 +53,75 @@ Some optional C extensions are not supported in PyPy. 
Only murmur3 will be built
 
=================================================================================
 """
 
-is_pypy = "PyPy" in sys.version
 if is_pypy:
     sys.stderr.write(pypy_unsupported_msg)
-
-is_supported_platform = sys.platform != "cli" and not 
sys.platform.startswith("java")
-is_supported_arch = sys.byteorder != "big"
 if not is_supported_platform:
     sys.stderr.write(platform_unsupported_msg)
 elif not is_supported_arch:
     sys.stderr.write(arch_unsupported_msg)
 
-try_extensions = "--no-extensions" not in sys.argv and is_supported_platform 
and is_supported_arch and not os.environ.get('CASS_DRIVER_NO_EXTENSIONS')
-try_murmur3 = try_extensions and "--no-murmur3" not in sys.argv
-try_libev = try_extensions and "--no-libev" not in sys.argv and not is_pypy 
and not os.environ.get('CASS_DRIVER_NO_LIBEV')
-try_cython = try_extensions and "--no-cython" not in sys.argv and not is_pypy 
and not os.environ.get('CASS_DRIVER_NO_CYTHON')
-try_cython &= 'egg_info' not in sys.argv  # bypass setup_requires for pip 
egg_info calls, which will never have --install-option"--no-cython" coming fomr 
pip
-
-sys.argv = [a for a in sys.argv if a not in ("--no-murmur3", "--no-libev", 
"--no-cython", "--no-extensions")]
-
-build_concurrency = int(os.environ.get('CASS_DRIVER_BUILD_CONCURRENCY', '0'))
-
-
-class NoPatchExtension(Extension):
-
-    # Older versions of setuptools.extension has a static flag which is set 
False before our
-    # setup_requires lands Cython. It causes our *.pyx sources to be renamed 
to *.c in
-    # the initializer.
-    # The other workaround would be to manually generate sources, but that 
bypasses a lot
-    # of the niceness cythonize embodies (setup build dir, conditional build, 
etc).
-    # Newer setuptools does not have this problem because it checks for cython 
dynamically.
-    # 
https://bitbucket.org/pypa/setuptools/commits/714c3144e08fd01a9f61d1c88411e76d2538b2e4
-
-    def __init__(self, *args, **kwargs):
-        # bypass the patched init if possible
-        if Extension.__bases__:
-            base, = Extension.__bases__
-            base.__init__(self, *args, **kwargs)
-        else:
-            Extension.__init__(self, *args, **kwargs)
-
-
-class build_extensions(build_ext):
-
-    error_message = """
-===============================================================================
-WARNING: could not compile %s.
+# ========================== Extensions ==========================
+pyproject_toml = Path(__file__).parent / "pyproject.toml"
+with open(pyproject_toml,"rb") as f:
+    pyproject_data = toml.load(f)
+driver_project_data = pyproject_data["tool"]["cassandra-driver"]
 
-The C extensions are not required for the driver to run, but they add support
-for token-aware routing with the Murmur3Partitioner.
+murmur3_ext = Extension('cassandra.cmurmur3', sources=['cassandra/cmurmur3.c'])
 
-On Windows, make sure Visual Studio or an SDK is installed, and your 
environment
-is configured to build for the appropriate architecture (matching your Python 
runtime).
-This is often a matter of using vcvarsall.bat from your install directory, or 
running
-from a command prompt in the Visual Studio Tools Start Menu.
-===============================================================================
-""" if is_windows else """
-===============================================================================
-WARNING: could not compile %s.
-
-The C extensions are not required for the driver to run, but they add support
-for libev and token-aware routing with the Murmur3Partitioner.
-
-Linux users should ensure that GCC and the Python headers are available.
-
-On Ubuntu and Debian, this can be accomplished by running:
-
-    $ sudo apt-get install build-essential python-dev
-
-On RedHat and RedHat-based systems like CentOS and Fedora:
-
-    $ sudo yum install gcc python-devel
-
-On OSX, homebrew installations of Python should provide the necessary headers.
-
-libev Support
--------------
-For libev support, you will also need to install libev and its headers.
-
-On Debian/Ubuntu:
-
-    $ sudo apt-get install libev4 libev-dev
-
-On RHEL/CentOS/Fedora:
-
-    $ sudo yum install libev libev-devel
+DEFAULT_LIBEV_INCLUDES = ['/usr/include/libev', '/usr/local/include', 
'/opt/local/include', '/usr/include']
+DEFAULT_LIBEV_LIBS = ['/usr/local/lib', '/opt/local/lib', '/usr/lib64']
+libev_includes = driver_project_data["libev-includes"] or 
DEFAULT_LIBEV_INCLUDES
+libev_libs = driver_project_data["libev-libs"] or DEFAULT_LIBEV_LIBS
+if is_macos:
+    libev_includes.extend(['/opt/homebrew/include', 
os.path.expanduser('~/homebrew/include')])
+    libev_libs.extend(['/opt/homebrew/lib'])
+libev_ext = Extension('cassandra.io.libevwrapper',
+                      sources=['cassandra/io/libevwrapper.c'],
+                      include_dirs=libev_includes,
+                      libraries=['ev'],
+                      library_dirs=libev_libs)
 
-On OSX, via homebrew:
+try_murmur3 = driver_project_data["build-murmur3-extension"] and 
is_supported_platform and is_supported_arch
+try_libev = driver_project_data["build-libev-extension"] and 
is_supported_platform and is_supported_arch
+try_cython = driver_project_data["build-cython-extensions"] and 
is_supported_platform and is_supported_arch and not is_pypy
 
-    $ brew install libev
+build_concurrency = driver_project_data["build-concurrency"]
 
-===============================================================================
-    """
+def build_extension_list():
 
-    def run(self):
-        try:
-            self._setup_extensions()
-            build_ext.run(self)
-        except DistutilsPlatformError as exc:
-            sys.stderr.write('%s\n' % str(exc))
-            warnings.warn(self.error_message % "C extensions.")
+    rv = []
 
-    def build_extensions(self):
-        if build_concurrency > 1:
-            self.check_extensions_list(self.extensions)
+    if try_murmur3:
+        sys.stderr.write("Appending murmur extension %s\n" % murmur3_ext)
+        rv.append(murmur3_ext)
 
-            import multiprocessing.pool
-            
multiprocessing.pool.ThreadPool(processes=build_concurrency).map(self.build_extension,
 self.extensions)
-        else:
-            build_ext.build_extensions(self)
+    if try_libev:
+        sys.stderr.write("Appending libev extension %s\n" % libev_ext)
+        rv.append(libev_ext)
 
-    def build_extension(self, ext):
+    if try_cython:
+        sys.stderr.write("Trying Cython builds in order to append Cython 
extensions\n")
         try:
-            build_ext.build_extension(self, ext)
-        except (CCompilerError, DistutilsExecError,
-                DistutilsPlatformError, IOError) as exc:
-            sys.stderr.write('%s\n' % str(exc))
-            name = "The %s extension" % (ext.name,)
-            warnings.warn(self.error_message % (name,))
-
-    def _setup_extensions(self):
-        # We defer extension setup until this command to leveraage 
'setup_requires' pulling in Cython before we
-        # attempt to import anything
-        self.extensions = []
-
-        if try_murmur3:
-            self.extensions.append(murmur3_ext)
-
-        if try_libev:
-            sys.stderr.write("Appending libev extension %s" % libev_ext)
-            self.extensions.append(libev_ext)
-
-        if try_cython:
-            try:
-                from Cython.Build import cythonize
-                cython_candidates = ['cluster', 'concurrent', 'connection', 
'cqltypes', 'metadata',
-                                     'pool', 'protocol', 'query', 'util']
-                compile_args = [] if is_windows else ['-Wno-unused-function']
-                self.extensions.extend(cythonize(
+            from Cython.Build import cythonize
+            cython_candidates = ['cluster', 'concurrent', 'connection', 
'cqltypes', 'metadata',
+                                 'pool', 'protocol', 'query', 'util']
+            compile_args = [] if is_windows else ['-Wno-unused-function']
+            rv.extend(cythonize(
                     [Extension('cassandra.%s' % m, ['cassandra/%s.py' % m],
-                               extra_compile_args=compile_args)
+                                extra_compile_args=compile_args)
                         for m in cython_candidates],
                     nthreads=build_concurrency,
                     exclude_failures=True))
 
-                self.extensions.extend(cythonize(NoPatchExtension("*", 
["cassandra/*.pyx"], extra_compile_args=compile_args),
-                                                 nthreads=build_concurrency))
-            except Exception:
-                sys.stderr.write("Failed to cythonize one or more modules. 
These will not be compiled as extensions (optional).\n")
-
-
-def pre_build_check():
-    """
-    Try to verify build tools
-    """
-    if os.environ.get('CASS_DRIVER_NO_PRE_BUILD_CHECK'):
-        return True
-
-    try:
-        from distutils.ccompiler import new_compiler
-        from distutils.sysconfig import customize_compiler
-        from distutils.dist import Distribution
-
-        # base build_ext just to emulate compiler option setup
-        be = build_ext(Distribution())
-        be.initialize_options()
-        be.finalize_options()
-
-        # First, make sure we have a Python include directory
-        have_python_include = any(os.path.isfile(os.path.join(p, 'Python.h')) 
for p in be.include_dirs)
-        if not have_python_include:
-            sys.stderr.write("Did not find 'Python.h' in %s.\n" % 
(be.include_dirs,))
-            return False
-
-        compiler = new_compiler(compiler=be.compiler)
-        customize_compiler(compiler)
-
-        try:
-            # We must be able to initialize the compiler if it has that method
-            if hasattr(compiler, "initialize"):
-                compiler.initialize()
-        except OSError:
-            return False
-
-        executables = []
-        if compiler.compiler_type in ('unix', 'cygwin'):
-            executables = [compiler.executables[exe][0] for exe in 
('compiler_so', 'linker_so')]
-        elif compiler.compiler_type == 'nt':
-            executables = [getattr(compiler, exe) for exe in ('cc', 'linker')]
-
-        if executables:
-            from distutils.spawn import find_executable
-            for exe in executables:
-                if not find_executable(exe):
-                    sys.stderr.write("Failed to find %s for compiler type 
%s.\n" % (exe, compiler.compiler_type))
-                    return False
-
-    except Exception as exc:
-        sys.stderr.write('%s\n' % str(exc))
-        sys.stderr.write("Failed pre-build check. Attempting anyway.\n")
-
-    # if we are unable to positively id the compiler type, or one of these 
assumptions fails,
-    # just proceed as we would have without the check
-    return True
-
-
-def run_setup(extensions):
-
-    kw = {'cmdclass': {'doc': DocCommand}}
-    kw['cmdclass']['build_ext'] = build_extensions
-    kw['ext_modules'] = [Extension('DUMMY', [])]  # dummy extension makes sure 
build_ext is called for install
-
-    if try_cython:
-        # precheck compiler before adding to setup_requires
-        # we don't actually negate try_cython because:
-        # 1.) build_ext eats errors at compile time, letting the install 
complete while producing useful feedback
-        # 2.) there could be a case where the python environment has cython 
installed but the system doesn't have build tools
-        if pre_build_check():
-            cython_dep = 'Cython>=3.0'
-            user_specified_cython_version = 
os.environ.get('CASS_DRIVER_ALLOWED_CYTHON_VERSION')
-            if user_specified_cython_version is not None:
-                cython_dep = 'Cython==%s' % (user_specified_cython_version,)
-            kw['setup_requires'] = [cython_dep]
-        else:
-            sys.stderr.write("Bypassing Cython setup requirement\n")
-
-    dependencies = ['geomet>=1.1']
-
-    _EXTRAS_REQUIRE = {
-        'graph': ['gremlinpython==3.4.6'],
-        'cle': ['cryptography>=42.0']
-    }
-
-    setup(
-        name='cassandra-driver',
-        version=__version__,
-        description='Apache Cassandra Python Driver',
-        long_description=long_description,
-        long_description_content_type='text/x-rst',
-        url='http://github.com/datastax/python-driver',
-        project_urls={
-            'Documentation': 
'https://docs.datastax.com/en/developer/python-driver/latest/',
-            'Source': 'https://github.com/datastax/python-driver/',
-            'Issues': 'https://datastax-oss.atlassian.net/browse/PYTHON',
-        },
-        author='DataStax',
-        packages=[
-            'cassandra', 'cassandra.io', 'cassandra.cqlengine', 
'cassandra.graph',
-            'cassandra.datastax', 'cassandra.datastax.insights', 
'cassandra.datastax.graph',
-            'cassandra.datastax.graph.fluent', 'cassandra.datastax.cloud',
-            "cassandra.column_encryption"
-        ],
-        keywords='cassandra,cql,orm,dse,graph',
-        include_package_data=True,
-        install_requires=dependencies,
-        extras_require=_EXTRAS_REQUIRE,
-        tests_require=['pytest', 'PyYAML', 'pytz'],
-        classifiers=[
-            'Development Status :: 5 - Production/Stable',
-            'Intended Audience :: Developers',
-            'License :: OSI Approved :: Apache Software License',
-            'Natural Language :: English',
-            'Operating System :: OS Independent',
-            'Programming Language :: Python',
-            'Programming Language :: Python :: 3.9',
-            'Programming Language :: Python :: 3.10',
-            'Programming Language :: Python :: 3.11',
-            'Programming Language :: Python :: 3.12',
-            'Programming Language :: Python :: 3.13',
-            'Programming Language :: Python :: Implementation :: CPython',
-            'Programming Language :: Python :: Implementation :: PyPy',
-            'Topic :: Software Development :: Libraries :: Python Modules'
-        ],
-        **kw)
-
-
-run_setup(None)
-
-if has_cqlengine:
-    warnings.warn("\n#######\n'cqlengine' package is present on path: %s\n"
-                  "cqlengine is now an integrated sub-package of this 
driver.\n"
-                  "It is recommended to remove this package to reduce the 
chance for conflicting usage" % cqlengine.__file__)
+            rv.extend(cythonize(Extension("*", ["cassandra/*.pyx"], 
extra_compile_args=compile_args),
+                                          nthreads=build_concurrency))
+        except Exception as exc:
+            sys.stderr.write("Failed to cythonize one or more modules. These 
will not be compiled as extensions (optional).\n")
+            sys.stderr.write("Cython error: %s\n" % exc)
+    
+    return rv
+
+# ========================== And finally setup() itself 
==========================
+setup(
+    ext_modules = build_extension_list()
+)
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to