1414
1515namespace duckdb {
1616
17- void TransformDuckToArrowChunk (py ::object pyarrow_schema, ArrowArray &data, py ::list &batches) {
17+ void TransformDuckToArrowChunk (nb ::object pyarrow_schema, ArrowArray &data, nb ::list &batches) {
1818 duckdb::PyUtil::GilAssert ();
19- auto pyarrow_lib_module = py ::module_::import_ (" pyarrow" ).attr (" lib" );
19+ auto pyarrow_lib_module = nb ::module_::import_ (" pyarrow" ).attr (" lib" );
2020 auto batch_import_func = pyarrow_lib_module.attr (" RecordBatch" ).attr (" _import_from_c" );
2121 batches.append (batch_import_func (reinterpret_cast <uint64_t >(&data), pyarrow_schema));
2222}
@@ -28,10 +28,10 @@ void VerifyArrowDatasetLoaded() {
2828 }
2929}
3030
31- py ::object PythonTableArrowArrayStreamFactory::ProduceScanner (py ::object &arrow_scanner, py ::handle &arrow_obj_handle,
31+ nb ::object PythonTableArrowArrayStreamFactory::ProduceScanner (nb ::object &arrow_scanner, nb ::handle &arrow_obj_handle,
3232 ArrowStreamParameters ¶meters,
3333 const ClientProperties &client_properties) {
34- D_ASSERT (!py ::isinstance<py ::capsule>(arrow_obj_handle));
34+ D_ASSERT (!nb ::isinstance<nb ::capsule>(arrow_obj_handle));
3535 ArrowSchemaWrapper schema;
3636 PythonTableArrowArrayStreamFactory::GetSchemaInternal (arrow_obj_handle, schema);
3737 ArrowTableSchema arrow_table;
@@ -41,18 +41,18 @@ py::object PythonTableArrowArrayStreamFactory::ProduceScanner(py::object &arrow_
4141 auto filters = parameters.filters ;
4242 auto &column_list = parameters.projected_columns .columns ;
4343 auto &filter_to_col = parameters.projected_columns .filter_to_col ;
44- py ::list projection_list (py ::cast (column_list));
44+ nb ::list projection_list (nb ::cast (column_list));
4545
4646 bool has_filter = filters && filters->HasFilters ();
47- py ::dict kwargs;
47+ nb ::dict kwargs;
4848 if (!column_list.empty ()) {
4949 kwargs[" columns" ] = projection_list;
5050 }
5151
5252 if (has_filter) {
5353 auto filter = PyArrowFilterPushdown::TransformFilter (*filters, parameters.projected_columns .projection_map ,
5454 filter_to_col, client_properties, arrow_table);
55- if (!filter.is (py ::none ())) {
55+ if (!filter.is (nb ::none ())) {
5656 kwargs[" filter" ] = filter;
5757 }
5858 }
@@ -61,20 +61,20 @@ py::object PythonTableArrowArrayStreamFactory::ProduceScanner(py::object &arrow_
6161
6262unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce (uintptr_t factory_ptr,
6363 ArrowStreamParameters ¶meters) {
64- py ::gil_scoped_acquire acquire;
64+ nb ::gil_scoped_acquire acquire;
6565 auto factory = static_cast <PythonTableArrowArrayStreamFactory *>(reinterpret_cast <void *>(factory_ptr)); // NOLINT
6666 D_ASSERT (factory->arrow_object );
67- py ::handle arrow_obj_handle (factory->arrow_object );
67+ nb ::handle arrow_obj_handle (factory->arrow_object );
6868 auto arrow_object_type = factory->cached_arrow_type ;
6969
7070 if (arrow_object_type == PyArrowObjectType::PolarsLazyFrame) {
71- py ::object lf = py ::borrow<py ::object>(arrow_obj_handle);
71+ nb ::object lf = nb ::borrow<nb ::object>(arrow_obj_handle);
7272
7373 auto filters = parameters.filters ;
7474 bool filters_pushed = false ;
7575
7676 // Translate DuckDB filters to Polars expressions and push into the lazy plan.
77- // The walker only fails (throws / returns py ::none()) for filters that are not
77+ // The walker only fails (throws / returns nb ::none()) for filters that are not
7878 // required for correctness — optional/runtime wrappers it skips, or shapes the
7979 // optimizer keeps above the scan. A throw here would mean the optimizer fully
8080 // pushed something we can't translate (a correctness bug), so we let it surface
@@ -84,15 +84,15 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
8484 auto filter_expr = PolarsFilterPushdown::TransformFilter (
8585 *filters, parameters.projected_columns .projection_map , parameters.projected_columns .filter_to_col ,
8686 factory->client_properties );
87- if (!filter_expr.is (py ::none ())) {
87+ if (!filter_expr.is (nb ::none ())) {
8888 lf = lf.attr (" filter" )(filter_expr);
8989 filters_pushed = true ;
9090 }
9191 }
9292
9393 // If no filters were pushed and we have a cached Arrow table, reuse it. This avoids re-reading from source and
9494 // re-converting on repeated unfiltered scans.
95- py ::object arrow_table;
95+ nb ::object arrow_table;
9696 if (!filters_pushed && factory->cached_arrow_table .ptr () != nullptr ) {
9797 arrow_table = factory->cached_arrow_table ;
9898 } else {
@@ -106,11 +106,11 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
106106 // Apply column projection
107107 auto &column_list = parameters.projected_columns .columns ;
108108 if (!column_list.empty ()) {
109- arrow_table = arrow_table.attr (" select" )(py ::cast (column_list));
109+ arrow_table = arrow_table.attr (" select" )(nb ::cast (column_list));
110110 }
111111
112112 auto capsule_obj = arrow_table.attr (" __arrow_c_stream__" )();
113- auto capsule = py ::borrow<py ::capsule>(capsule_obj);
113+ auto capsule = nb ::borrow<nb ::capsule>(capsule_obj);
114114 auto stream = reinterpret_cast <ArrowArrayStream *>(capsule.data ());
115115 auto res = make_uniq<ArrowArrayStreamWrapper>();
116116 res->arrow_array_stream = *stream;
@@ -119,8 +119,8 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
119119 }
120120
121121 if (arrow_object_type == PyArrowObjectType::PyCapsuleInterface || arrow_object_type == PyArrowObjectType::Table) {
122- py ::object capsule_obj = arrow_obj_handle.attr (" __arrow_c_stream__" )();
123- auto capsule = py ::borrow<py ::capsule>(capsule_obj);
122+ nb ::object capsule_obj = arrow_obj_handle.attr (" __arrow_c_stream__" )();
123+ auto capsule = nb ::borrow<nb ::capsule>(capsule_obj);
124124 auto stream = reinterpret_cast <ArrowArrayStream *>(capsule.data ());
125125 if (!stream->release ) {
126126 throw InvalidInputException (
@@ -133,14 +133,14 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
133133 if (import_cache_check.pyarrow .dataset ()) {
134134 // Tier A: full pushdown via pyarrow.dataset
135135 // Import as RecordBatchReader, feed through Scanner.from_batches for projection/filter pushdown.
136- auto pyarrow_lib_module = py ::module_::import_ (" pyarrow" ).attr (" lib" );
136+ auto pyarrow_lib_module = nb ::module_::import_ (" pyarrow" ).attr (" lib" );
137137 auto import_func = pyarrow_lib_module.attr (" RecordBatchReader" ).attr (" _import_from_c" );
138- py ::object reader = import_func (reinterpret_cast <uint64_t >(stream));
138+ nb ::object reader = import_func (reinterpret_cast <uint64_t >(stream));
139139 // _import_from_c takes ownership of the stream; null out to prevent capsule double-free
140140 stream->release = nullptr ;
141141 auto &import_cache = *DuckDBPyConnection::ImportCache ();
142- py ::object arrow_batch_scanner = import_cache.pyarrow .dataset .Scanner ().attr (" from_batches" );
143- py ::handle reader_handle = reader;
142+ nb ::object arrow_batch_scanner = import_cache.pyarrow .dataset .Scanner ().attr (" from_batches" );
143+ nb ::handle reader_handle = reader;
144144 auto scanner = ProduceScanner (arrow_batch_scanner, reader_handle, parameters, factory->client_properties );
145145 auto record_batches = scanner.attr (" to_reader" )();
146146 auto res = make_uniq<ArrowArrayStreamWrapper>();
@@ -159,7 +159,7 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
159159
160160 if (arrow_object_type == PyArrowObjectType::PyCapsule) {
161161 auto res = make_uniq<ArrowArrayStreamWrapper>();
162- auto capsule = py ::borrow<py ::capsule>(arrow_obj_handle);
162+ auto capsule = nb ::borrow<nb ::capsule>(arrow_obj_handle);
163163 auto stream = reinterpret_cast <ArrowArrayStream *>(capsule.data ());
164164 if (!stream->release ) {
165165 throw InvalidInputException (" This ArrowArrayStream has already been consumed and cannot be scanned again." );
@@ -172,8 +172,8 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
172172 // Scanner and Dataset: require pyarrow.dataset for pushdown
173173 VerifyArrowDatasetLoaded ();
174174 auto &import_cache = *DuckDBPyConnection::ImportCache ();
175- py ::object scanner;
176- py ::object arrow_batch_scanner = import_cache.pyarrow .dataset .Scanner ().attr (" from_batches" );
175+ nb ::object scanner;
176+ nb ::object arrow_batch_scanner = import_cache.pyarrow .dataset .Scanner ().attr (" from_batches" );
177177 switch (arrow_object_type) {
178178 case PyArrowObjectType::Scanner: {
179179 // If it's a scanner we have to turn it to a record batch reader, and then a scanner again since we can't stack
@@ -183,13 +183,13 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
183183 break ;
184184 }
185185 case PyArrowObjectType::Dataset: {
186- py ::object arrow_scanner = arrow_obj_handle.attr (" __class__" ).attr (" scanner" );
186+ nb ::object arrow_scanner = arrow_obj_handle.attr (" __class__" ).attr (" scanner" );
187187 scanner = ProduceScanner (arrow_scanner, arrow_obj_handle, parameters, factory->client_properties );
188188 break ;
189189 }
190190 default : {
191- // py ::object wrap: py ::str() of a bare .attr() accessor is an ambiguous overload on MSVC.
192- auto py_object_type = py ::cast<std::string>(py ::str (py ::object ((arrow_obj_handle).type ().attr (" __name__" ))));
191+ // nb ::object wrap: nb ::str() of a bare .attr() accessor is an ambiguous overload on MSVC.
192+ auto py_object_type = nb ::cast<std::string>(nb ::str (nb ::object ((arrow_obj_handle).type ().attr (" __name__" ))));
193193 throw InvalidInputException (" Object of type '%s' is not a recognized Arrow object" , py_object_type);
194194 }
195195 }
@@ -201,10 +201,10 @@ unique_ptr<ArrowArrayStreamWrapper> PythonTableArrowArrayStreamFactory::Produce(
201201 return res;
202202}
203203
204- void PythonTableArrowArrayStreamFactory::GetSchemaInternal (py ::handle arrow_obj_handle, ArrowSchemaWrapper &schema) {
204+ void PythonTableArrowArrayStreamFactory::GetSchemaInternal (nb ::handle arrow_obj_handle, ArrowSchemaWrapper &schema) {
205205 // PyCapsule (from bare capsule Produce path)
206- if (py ::isinstance<py ::capsule>(arrow_obj_handle)) {
207- auto capsule = py ::borrow<py ::capsule>(arrow_obj_handle);
206+ if (nb ::isinstance<nb ::capsule>(arrow_obj_handle)) {
207+ auto capsule = nb ::borrow<nb ::capsule>(arrow_obj_handle);
208208 auto stream = reinterpret_cast <ArrowArrayStream *>(capsule.data ());
209209 if (!stream->release ) {
210210 throw InvalidInputException (" This ArrowArrayStream has already been consumed and cannot be scanned again." );
@@ -238,17 +238,17 @@ void PythonTableArrowArrayStreamFactory::GetSchema(uintptr_t factory_ptr, ArrowS
238238 return ;
239239 }
240240
241- py ::gil_scoped_acquire acquire;
241+ nb ::gil_scoped_acquire acquire;
242242 D_ASSERT (factory->arrow_object );
243- py ::handle arrow_obj_handle (factory->arrow_object );
243+ nb ::handle arrow_obj_handle (factory->arrow_object );
244244
245245 auto type = factory->cached_arrow_type ;
246246 if (type == PyArrowObjectType::PolarsLazyFrame) {
247247 // head(0).collect().to_arrow() gives the Arrow-exported schema (e.g. large_string) without materializing data.
248248 // collect_schema() would give Polars-native types (e.g. string_view) that don't match the actual export.
249249 const auto empty_arrow = arrow_obj_handle.attr (" head" )(0 ).attr (" collect" )().attr (" to_arrow" )();
250250 const auto schema_capsule = empty_arrow.attr (" schema" ).attr (" __arrow_c_schema__" )();
251- const auto capsule = py ::borrow<py ::capsule>(schema_capsule);
251+ const auto capsule = nb ::borrow<nb ::capsule>(schema_capsule);
252252 const auto arrow_schema = reinterpret_cast <ArrowSchema *>(capsule.data ());
253253 factory->cached_schema = *arrow_schema;
254254 arrow_schema->release = nullptr ;
@@ -259,9 +259,9 @@ void PythonTableArrowArrayStreamFactory::GetSchema(uintptr_t factory_ptr, ArrowS
259259 }
260260 if (type == PyArrowObjectType::PyCapsuleInterface || type == PyArrowObjectType::Table) {
261261 // Get __arrow_c_schema__ if it exists
262- if (py ::hasattr (arrow_obj_handle, " __arrow_c_schema__" )) {
262+ if (nb ::hasattr (arrow_obj_handle, " __arrow_c_schema__" )) {
263263 auto schema_capsule = arrow_obj_handle.attr (" __arrow_c_schema__" )();
264- auto capsule = py ::borrow<py ::capsule>(schema_capsule);
264+ auto capsule = nb ::borrow<nb ::capsule>(schema_capsule);
265265 auto arrow_schema = reinterpret_cast <ArrowSchema *>(capsule.data ());
266266 factory->cached_schema = *arrow_schema; // factory takes ownership
267267 arrow_schema->release = nullptr ;
@@ -271,16 +271,16 @@ void PythonTableArrowArrayStreamFactory::GetSchema(uintptr_t factory_ptr, ArrowS
271271 return ;
272272 }
273273 // Otherwise try to use .schema with _export_to_c
274- if (py ::hasattr (arrow_obj_handle, " schema" )) {
274+ if (nb ::hasattr (arrow_obj_handle, " schema" )) {
275275 auto obj_schema = arrow_obj_handle.attr (" schema" );
276- if (py ::hasattr (obj_schema, " _export_to_c" )) {
276+ if (nb ::hasattr (obj_schema, " _export_to_c" )) {
277277 obj_schema.attr (" _export_to_c" )(reinterpret_cast <uint64_t >(&schema.arrow_schema ));
278278 return ;
279279 }
280280 }
281281 // Fallback: create a temporary stream just for the schema (consumes single-use streams!)
282282 auto stream_capsule = arrow_obj_handle.attr (" __arrow_c_stream__" )();
283- auto capsule = py ::borrow<py ::capsule>(stream_capsule);
283+ auto capsule = nb ::borrow<nb ::capsule>(stream_capsule);
284284 auto stream = reinterpret_cast <ArrowArrayStream *>(capsule.data ());
285285 if (stream->get_schema (stream, &schema.arrow_schema )) {
286286 throw InvalidInputException (" Failed to get Arrow schema from stream: %s" ,
0 commit comments