]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
pybind/rados,rgw: replace Tempita errno checks with C preprocessor
authorKefu Chai <k.chai@proxmox.com>
Fri, 30 Jan 2026 08:57:34 +0000 (16:57 +0800)
committerKefu Chai <k.chai@proxmox.com>
Mon, 2 Feb 2026 03:14:44 +0000 (11:14 +0800)
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 <k.chai@proxmox.com>
src/pybind/rados/rados.pyx
src/pybind/rados/setup.py
src/pybind/rgw/rgw.pyx
src/pybind/rgw/setup.py

index 508206244f4db354f201b49f82fff74cafea7c28..68b5626b18c2fe1de015533da98748f0c2063b86 100644 (file)
@@ -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 <errno.h>
+    #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):
index ec345f9718cf402569d02fe70393447b599952dc..27570bf9d524f51790b9bfbe3e4a4c9f57d148f6 100755 (executable)
@@ -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),
     ),
index bec58b0ef0e2b6624388ed18c651667050199f75..434504a06e8b2e61fdff4eb43860f1588d6184b6 100644 (file)
@@ -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 <errno.h>
+    #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):
index 374167cbbca4978ac31d1fbb682620ecc29512c8..224342a10e5f142b5c32e546c0a0c41119ee32a5 100755 (executable)
@@ -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
     ),