33 * @brief C++ helper library for Polars integration tests.
44 *
55 * This library provides C functions that can be called from Python via ctypes
6- * to test the bidirectional data exchange between Polars and sparrow.
6+ * to test the bidirectional data exchange between Polars and sparrow using
7+ * the sparrow::pycapsule interface.
78 */
89
910#include " test_polars_helper.hpp"
1213#include < iostream>
1314#include < vector>
1415
15- #include < Python.h>
16- #include < sparrow-pycapsule/config/config.hpp>
17- #include < sparrow-pycapsule/pycapsule.hpp>
18-
1916#include < sparrow/array.hpp>
2017#include < sparrow/primitive_array.hpp>
2118#include < sparrow/utils/nullable.hpp>
2219
23- // Export C API functions for ctypes
20+ #include < sparrow-pycapsule/pycapsule.hpp>
21+
2422extern " C"
2523{
26- /* *
27- * @brief Initialize Python interpreter if not already initialized.
28- *
29- * Note: When called from Python (via ctypes), Python is already initialized.
30- * This function only initializes if called from pure C++ context.
31- */
32- void init_python ()
33- {
34- // When called from Python via ctypes, Python is already initialized
35- // So this check should always be true, and we do nothing
36- if (Py_IsInitialized ())
37- {
38- // Python already initialized - this is the normal case when called from Python
39- return ;
40- }
41-
42- // Only initialize if we're being called from C++ without Python
43- Py_Initialize ();
44- }
45-
46- /* *
47- * @brief Create a simple test array and return raw Arrow C pointers.
48- *
49- * Instead of creating PyCapsules in C++, we return raw pointers that Python
50- * will wrap in PyCapsules. This avoids Python C API calls from ctypes libraries.
51- *
52- * @param schema_ptr_out Output parameter for ArrowSchema pointer
53- * @param array_ptr_out Output parameter for ArrowArray pointer
54- * @return 0 on success, -1 on error
55- */
56- int create_test_array_as_pointers (void ** schema_ptr_out, void ** array_ptr_out)
24+ int create_test_array_capsules (PyObject** schema_capsule_out, PyObject** array_capsule_out)
5725 {
5826 try
5927 {
60- // Create a test array with nullable integers
6128 std::vector<sparrow::nullable<int32_t >> values = {
6229 sparrow::make_nullable<int32_t >(10 , true ),
6330 sparrow::make_nullable<int32_t >(20 , true ),
@@ -69,120 +36,101 @@ extern "C"
6936 sparrow::primitive_array<int32_t > prim_array (std::move (values));
7037 sparrow::array arr (std::move (prim_array));
7138
72- // Extract Arrow C structures
73- auto [arrow_array, arrow_schema] = sparrow::extract_arrow_structures (std::move (arr));
39+ auto [schema_capsule, array_capsule] = sparrow::pycapsule::export_array_to_capsules (arr);
7440
75- // Allocate on heap and transfer ownership to Python
76- ArrowSchema* schema_ptr = new ArrowSchema (std::move (arrow_schema));
77- ArrowArray* array_ptr = new ArrowArray (std::move (arrow_array));
41+ if (schema_capsule == nullptr || array_capsule == nullptr )
42+ {
43+ std::cerr << " Failed to create PyCapsules\n " ;
44+ Py_XDECREF (schema_capsule);
45+ Py_XDECREF (array_capsule);
46+ return -1 ;
47+ }
7848
79- *schema_ptr_out = schema_ptr ;
80- *array_ptr_out = array_ptr ;
49+ *schema_capsule_out = schema_capsule ;
50+ *array_capsule_out = array_capsule ;
8151
8252 return 0 ;
8353 }
8454 catch (const std::exception& e)
8555 {
86- std::cerr << " Exception in create_test_array_as_pointers : " << e.what () << std::endl ;
56+ std::cerr << " Exception in create_test_array_capsules : " << e.what () << ' \n ' ;
8757 return -1 ;
8858 }
8959 }
9060
91- /* *
92- * @brief Import array from raw Arrow C pointers and return new pointers.
93- *
94- * @param schema_ptr_in Input ArrowSchema pointer
95- * @param array_ptr_in Input ArrowArray pointer
96- * @param schema_ptr_out Output ArrowSchema pointer
97- * @param array_ptr_out Output ArrowArray pointer
98- * @return 0 on success, -1 on error
99- */
100- int
101- roundtrip_array_pointers (void * schema_ptr_in, void * array_ptr_in, void ** schema_ptr_out, void ** array_ptr_out)
61+ int roundtrip_array_capsules (
62+ PyObject* schema_capsule_in,
63+ PyObject* array_capsule_in,
64+ PyObject** schema_capsule_out,
65+ PyObject** array_capsule_out
66+ )
10267 {
10368 try
10469 {
105- if (schema_ptr_in == nullptr || array_ptr_in == nullptr )
70+ if (schema_capsule_in == nullptr || array_capsule_in == nullptr )
10671 {
107- std::cerr << " Null input pointers " << std::endl ;
72+ std::cerr << " Null input capsules \n " ;
10873 return -1 ;
10974 }
11075
111- ArrowSchema* schema_in = static_cast <ArrowSchema*>(schema_ptr_in);
112- ArrowArray* array_in = static_cast <ArrowArray*>(array_ptr_in);
113-
114- // Move the data (mark originals as released to prevent double-free)
115- ArrowSchema schema_moved = *schema_in;
116- ArrowArray array_moved = *array_in;
117- schema_in->release = nullptr ;
118- array_in->release = nullptr ;
119-
120- // Import into sparrow
121- sparrow::array arr (std::move (array_moved), std::move (schema_moved));
76+ sparrow::array arr = sparrow::pycapsule::import_array_from_capsules (
77+ schema_capsule_in,
78+ array_capsule_in
79+ );
12280
123- std::cout << " Roundtrip array size: " << arr.size () << std::endl ;
81+ std::cout << " Roundtrip array size: " << arr.size () << ' \n ' ;
12482
125- // Export back out
126- auto [arrow_array_out, arrow_schema_out] = sparrow::extract_arrow_structures (std::move (arr));
83+ auto [schema_capsule, array_capsule] = sparrow::pycapsule::export_array_to_capsules (arr);
12784
128- ArrowSchema* schema_out = new ArrowSchema (std::move (arrow_schema_out));
129- ArrowArray* array_out = new ArrowArray (std::move (arrow_array_out));
85+ if (schema_capsule == nullptr || array_capsule == nullptr )
86+ {
87+ std::cerr << " Failed to create output PyCapsules\n " ;
88+ Py_XDECREF (schema_capsule);
89+ Py_XDECREF (array_capsule);
90+ return -1 ;
91+ }
13092
131- *schema_ptr_out = schema_out ;
132- *array_ptr_out = array_out ;
93+ *schema_capsule_out = schema_capsule ;
94+ *array_capsule_out = array_capsule ;
13395
13496 return 0 ;
13597 }
13698 catch (const std::exception& e)
13799 {
138- std::cerr << " Exception in roundtrip_array_pointers : " << e.what () << std::endl ;
100+ std::cerr << " Exception in roundtrip_array_capsules : " << e.what () << ' \n ' ;
139101 return -1 ;
140102 }
141103 }
142104
143- /* *
144- * @brief Verify that Arrow C structures have the expected size.
145- *
146- * @param schema_ptr ArrowSchema pointer
147- * @param array_ptr ArrowArray pointer
148- * @param expected_size Expected array size
149- * @return 0 if size matches, -1 otherwise
150- */
151- int verify_array_size_from_pointers (void * schema_ptr, void * array_ptr, size_t expected_size)
105+ int verify_array_size_from_capsules (PyObject* schema_capsule, PyObject* array_capsule, size_t expected_size)
152106 {
153107 try
154108 {
155- if (schema_ptr == nullptr || array_ptr == nullptr )
109+ if (schema_capsule == nullptr || array_capsule == nullptr )
156110 {
157- std::cerr << " Null pointers provided" << std::endl ;
111+ std::cerr << " Null capsules provided\n " ;
158112 return -1 ;
159113 }
160114
161- ArrowSchema* schema = static_cast <ArrowSchema*>(schema_ptr);
162- ArrowArray* array = static_cast <ArrowArray*>(array_ptr);
163-
164- // Move the data (mark originals as released)
165- ArrowSchema schema_moved = *schema;
166- ArrowArray array_moved = *array;
167- schema->release = nullptr ;
168- array->release = nullptr ;
169-
170- sparrow::array arr (std::move (array_moved), std::move (schema_moved));
115+ sparrow::array arr = sparrow::pycapsule::import_array_from_capsules (
116+ schema_capsule,
117+ array_capsule
118+ );
171119
172120 if (arr.size () == expected_size)
173121 {
174- std::cout << " Array size verified: " << arr.size () << std::endl ;
122+ std::cout << " Array size verified: " << arr.size () << ' \n ' ;
175123 return 0 ;
176124 }
177125 else
178126 {
179- std::cerr << " Size mismatch: expected " << expected_size << " , got " << arr.size () << std::endl ;
127+ std::cerr << " Size mismatch: expected " << expected_size << " , got " << arr.size () << ' \n ' ;
180128 return -1 ;
181129 }
182130 }
183131 catch (const std::exception& e)
184132 {
185- std::cerr << " Exception in verify_array_size_from_pointers : " << e.what () << std::endl ;
133+ std::cerr << " Exception in verify_array_size_from_capsules : " << e.what () << ' \n ' ;
186134 return -1 ;
187135 }
188136 }
0 commit comments