From d02c518eb3d9ecd1ae51a456a823eacc91c625d7 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Fri, 30 Jan 2026 16:57:34 +0800 Subject: [PATCH] pybind/rados,rgw: replace Tempita errno checks with C preprocessor MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Replace Tempita-based platform-specific errno handling with C preprocessor conditionals for the rados and rgw Python bindings, aligning with the approach already used in cephfs. Previously, rados and rgw used Tempita to generate platform-specific errno_to_exception dictionaries, duplicating ~40 lines of code to choose between ENOATTR (FreeBSD) and ENODATA (Linux) for the NoData exception. This created an inconsistency with cephfs, which uses C preprocessor conditionals for similar platform compatibility needs. This commit introduces a CEPH_ENODATA macro that resolves to the appropriate errno value at compile time: - ENOATTR on FreeBSD/Darwin - ENODATA on Linux Changes: - Add CEPH_ENODATA macro using #ifdef preprocessor conditionals - Use single errno_to_exception dictionary with CEPH_ENODATA (~20 lines) - Remove UNAME_SYSNAME variable and platform import from setup.py - Retain Tempita processing for BUILD_DOC (still required) Benefits: - Eliminates runtime platform detection in setup.py - Reduces code duplication (40 lines → 20 lines) - Provides consistency across all pybind modules (rados, rgw, cephfs) Follows the same pattern as DIRENT_D_OFF in cephfs bindings. Signed-off-by: Kefu Chai --- src/pybind/rados/rados.pyx | 41 ++++++++++++++++---------------------- src/pybind/rados/setup.py | 7 ++++--- src/pybind/rgw/rgw.pyx | 35 ++++++++++++++++---------------- src/pybind/rgw/setup.py | 6 +++--- 4 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/pybind/rados/rados.pyx b/src/pybind/rados/rados.pyx index 508206244f4..68b5626b18c 100644 --- a/src/pybind/rados/rados.pyx +++ b/src/pybind/rados/rados.pyx @@ -20,6 +20,20 @@ from libc cimport errno from libc.stdint cimport * from libc.stdlib cimport malloc, realloc, free +# Platform-specific errno handling using C preprocessor +cdef extern from *: + """ + #include + #if defined(__FreeBSD__) || defined(__APPLE__) + // FreeBSD/Darwin use ENOATTR for "no data" + #define CEPH_ENODATA ENOATTR + #else + // Linux uses ENODATA + #define CEPH_ENODATA ENODATA + #endif + """ + int CEPH_ENODATA + {{if BUILD_DOC}} include "mock_rados.pxi" {{else}} @@ -233,28 +247,8 @@ class ConnectionShutdown(OSError): super(ConnectionShutdown, self).__init__( "RADOS connection was shutdown (%s)" % message, errno) - -# Build errno mapping based on platform -# FreeBSD uses ENOATTR while Linux uses ENODATA -{{if UNAME_SYSNAME == "FreeBSD"}} -cdef errno_to_exception = { - errno.EPERM : PermissionError, - errno.ENOENT : ObjectNotFound, - errno.EIO : IOError, - errno.ENOSPC : NoSpace, - errno.EEXIST : ObjectExists, - errno.EBUSY : ObjectBusy, - errno.ENOATTR : NoData, - errno.EINTR : InterruptedOrTimeoutError, - errno.ETIMEDOUT : TimedOut, - errno.EACCES : PermissionDeniedError, - errno.EINPROGRESS : InProgress, - errno.EISCONN : IsConnected, - errno.EINVAL : InvalidArgumentError, - errno.ENOTCONN : NotConnected, - errno.ESHUTDOWN : ConnectionShutdown, -} -{{else}} +# Build errno mapping +# Use CEPH_ENODATA which resolves to ENOATTR on FreeBSD or ENODATA on Linux cdef errno_to_exception = { errno.EPERM : PermissionError, errno.ENOENT : ObjectNotFound, @@ -262,7 +256,7 @@ cdef errno_to_exception = { errno.ENOSPC : NoSpace, errno.EEXIST : ObjectExists, errno.EBUSY : ObjectBusy, - errno.ENODATA : NoData, + CEPH_ENODATA : NoData, errno.EINTR : InterruptedOrTimeoutError, errno.ETIMEDOUT : TimedOut, errno.EACCES : PermissionDeniedError, @@ -272,7 +266,6 @@ cdef errno_to_exception = { errno.ENOTCONN : NotConnected, errno.ESHUTDOWN : ConnectionShutdown, } -{{endif}} cdef make_ex(ret: int, msg: str): diff --git a/src/pybind/rados/setup.py b/src/pybind/rados/setup.py index ec345f9718c..27570bf9d52 100755 --- a/src/pybind/rados/setup.py +++ b/src/pybind/rados/setup.py @@ -11,7 +11,6 @@ from distutils.ccompiler import new_compiler from itertools import filterfalse, takewhile import os -import platform import shutil import sys import tempfile @@ -140,10 +139,10 @@ def check_sanity(): if 'BUILD_DOC' in os.environ or 'READTHEDOCS' in os.environ: ext_args = dict(extra_compile_args=['-DBUILD_DOC']) - cython_constants = dict(BUILD_DOC=True, UNAME_SYSNAME=platform.system()) + cython_constants = dict(BUILD_DOC=True) elif check_sanity(): ext_args = get_python_flags(['rados']) - cython_constants = dict(BUILD_DOC=False, UNAME_SYSNAME=platform.system()) + cython_constants = dict(BUILD_DOC=False) else: sys.exit(1) @@ -217,6 +216,8 @@ setup( **ext_args ) ], + # use "3str" when Cython 3.0 is available + compiler_directives={'language_level': sys.version_info.major}, compile_time_env=cython_constants, build_dir=os.environ.get("CYTHON_BUILD_DIR", None), ), diff --git a/src/pybind/rgw/rgw.pyx b/src/pybind/rgw/rgw.pyx index bec58b0ef0e..434504a06e8 100644 --- a/src/pybind/rgw/rgw.pyx +++ b/src/pybind/rgw/rgw.pyx @@ -10,6 +10,20 @@ from libc.stdlib cimport malloc, realloc, free from cstat cimport stat cimport libcpp +# Platform-specific errno handling using C preprocessor +cdef extern from *: + """ + #include + #if defined(__FreeBSD__) || defined(__APPLE__) + // FreeBSD/Darwin use ENOATTR for "no data" + #define CEPH_ENODATA ENOATTR + #else + // Linux uses ENODATA + #define CEPH_ENODATA ENODATA + #endif + """ + int CEPH_ENODATA + {{if BUILD_DOC}} include "mock_rgw.pxi" {{else}} @@ -92,35 +106,20 @@ class OutOfRange(Error): pass -# Build errno mapping based on platform -# FreeBSD uses ENOATTR while Linux uses ENODATA -{{if UNAME_SYSNAME == "FreeBSD"}} -cdef errno_to_exception = { - errno.EPERM : PermissionError, - errno.ENOENT : ObjectNotFound, - errno.EIO : IOError, - errno.ENOSPC : NoSpace, - errno.EEXIST : ObjectExists, - errno.ENOATTR : NoData, - errno.EINVAL : InvalidValue, - errno.EOPNOTSUPP : OperationNotSupported, - errno.ERANGE : OutOfRange, - errno.EWOULDBLOCK: WouldBlock, -} -{{else}} +# Build errno mapping +# Use CEPH_ENODATA which resolves to ENOATTR on FreeBSD or ENODATA on Linux cdef errno_to_exception = { errno.EPERM : PermissionError, errno.ENOENT : ObjectNotFound, errno.EIO : IOError, errno.ENOSPC : NoSpace, errno.EEXIST : ObjectExists, - errno.ENODATA : NoData, + CEPH_ENODATA : NoData, errno.EINVAL : InvalidValue, errno.EOPNOTSUPP : OperationNotSupported, errno.ERANGE : OutOfRange, errno.EWOULDBLOCK: WouldBlock, } -{{endif}} cdef class FileHandle(object): diff --git a/src/pybind/rgw/setup.py b/src/pybind/rgw/setup.py index 374167cbbca..224342a10e5 100755 --- a/src/pybind/rgw/setup.py +++ b/src/pybind/rgw/setup.py @@ -141,15 +141,14 @@ def check_sanity(): shutil.rmtree(tmp_dir) -import platform if 'BUILD_DOC' in os.environ or 'READTHEDOCS' in os.environ: ext_args = {} - cython_constants = dict(BUILD_DOC=True, UNAME_SYSNAME=platform.system()) + cython_constants = dict(BUILD_DOC=True) cythonize_args = dict(compile_time_env=cython_constants) elif check_sanity(): ext_args = get_python_flags(['rados', 'rgw']) - cython_constants = dict(BUILD_DOC=False, UNAME_SYSNAME=platform.system()) + cython_constants = dict(BUILD_DOC=False) include_path = [os.path.join(os.path.dirname(__file__), "..", "rados")] cythonize_args = dict(compile_time_env=cython_constants, include_path=include_path) @@ -226,6 +225,7 @@ setup( **ext_args ) ], + compiler_directives={'language_level': sys.version_info.major}, build_dir=os.environ.get("CYTHON_BUILD_DIR", None), **cythonize_args ), -- 2.47.3