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]