Skip to content

Commit f3bee82

Browse files
prefer bound Python token over Python::with_gil
When available, using an already bound python token is zero-cost. Python::with_gil carries a runtime check. Ref: PyO3/pyo3#4274
1 parent a326fab commit f3bee82

File tree

2 files changed

+24
-35
lines changed

2 files changed

+24
-35
lines changed

src/dataframe.rs

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -423,17 +423,15 @@ impl PyDataFrame {
423423

424424
/// Convert to Arrow Table
425425
/// Collect the batches and pass to Arrow Table
426-
fn to_arrow_table(&self, py: Python) -> PyResult<PyObject> {
426+
fn to_arrow_table(&self, py: Python<'_>) -> PyResult<PyObject> {
427427
let batches = self.collect(py)?.to_object(py);
428428
let schema: PyObject = self.schema().into_py(py);
429429

430-
Python::with_gil(|py| {
431-
// Instantiate pyarrow Table object and use its from_batches method
432-
let table_class = py.import_bound("pyarrow")?.getattr("Table")?;
433-
let args = PyTuple::new_bound(py, &[batches, schema]);
434-
let table: PyObject = table_class.call_method1("from_batches", args)?.into();
435-
Ok(table)
436-
})
430+
// Instantiate pyarrow Table object and use its from_batches method
431+
let table_class = py.import_bound("pyarrow")?.getattr("Table")?;
432+
let args = PyTuple::new_bound(py, &[batches, schema]);
433+
let table: PyObject = table_class.call_method1("from_batches", args)?.into();
434+
Ok(table)
437435
}
438436

439437
fn execute_stream(&self, py: Python) -> PyResult<PyRecordBatchStream> {
@@ -464,51 +462,42 @@ impl PyDataFrame {
464462

465463
/// Convert to pandas dataframe with pyarrow
466464
/// Collect the batches, pass to Arrow Table & then convert to Pandas DataFrame
467-
fn to_pandas(&self, py: Python) -> PyResult<PyObject> {
465+
fn to_pandas(&self, py: Python<'_>) -> PyResult<PyObject> {
468466
let table = self.to_arrow_table(py)?;
469467

470-
Python::with_gil(|py| {
471-
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pandas
472-
let result = table.call_method0(py, "to_pandas")?;
473-
Ok(result)
474-
})
468+
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pandas
469+
let result = table.call_method0(py, "to_pandas")?;
470+
Ok(result)
475471
}
476472

477473
/// Convert to Python list using pyarrow
478474
/// Each list item represents one row encoded as dictionary
479-
fn to_pylist(&self, py: Python) -> PyResult<PyObject> {
475+
fn to_pylist(&self, py: Python<'_>) -> PyResult<PyObject> {
480476
let table = self.to_arrow_table(py)?;
481477

482-
Python::with_gil(|py| {
483-
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pylist
484-
let result = table.call_method0(py, "to_pylist")?;
485-
Ok(result)
486-
})
478+
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pylist
479+
let result = table.call_method0(py, "to_pylist")?;
480+
Ok(result)
487481
}
488482

489483
/// Convert to Python dictionary using pyarrow
490484
/// Each dictionary key is a column and the dictionary value represents the column values
491485
fn to_pydict(&self, py: Python) -> PyResult<PyObject> {
492486
let table = self.to_arrow_table(py)?;
493487

494-
Python::with_gil(|py| {
495-
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pydict
496-
let result = table.call_method0(py, "to_pydict")?;
497-
Ok(result)
498-
})
488+
// See also: https://arrow.apache.org/docs/python/generated/pyarrow.Table.html#pyarrow.Table.to_pydict
489+
let result = table.call_method0(py, "to_pydict")?;
490+
Ok(result)
499491
}
500492

501493
/// Convert to polars dataframe with pyarrow
502494
/// Collect the batches, pass to Arrow Table & then convert to polars DataFrame
503-
fn to_polars(&self, py: Python) -> PyResult<PyObject> {
495+
fn to_polars(&self, py: Python<'_>) -> PyResult<PyObject> {
504496
let table = self.to_arrow_table(py)?;
505-
506-
Python::with_gil(|py| {
507-
let dataframe = py.import_bound("polars")?.getattr("DataFrame")?;
508-
let args = PyTuple::new_bound(py, &[table]);
509-
let result: PyObject = dataframe.call1(args)?.into();
510-
Ok(result)
511-
})
497+
let dataframe = py.import_bound("polars")?.getattr("DataFrame")?;
498+
let args = PyTuple::new_bound(py, &[table]);
499+
let result: PyObject = dataframe.call1(args)?.into();
500+
Ok(result)
512501
}
513502

514503
// Executes this DataFrame to get the total number of rows.

src/sql/logical.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl PyLogicalPlan {
6363
impl PyLogicalPlan {
6464
/// Return the specific logical operator
6565
pub fn to_variant(&self, py: Python) -> PyResult<PyObject> {
66-
Python::with_gil(|_| match self.plan.as_ref() {
66+
match self.plan.as_ref() {
6767
LogicalPlan::Aggregate(plan) => PyAggregate::from(plan.clone()).to_variant(py),
6868
LogicalPlan::Analyze(plan) => PyAnalyze::from(plan.clone()).to_variant(py),
6969
LogicalPlan::CrossJoin(plan) => PyCrossJoin::from(plan.clone()).to_variant(py),
@@ -85,7 +85,7 @@ impl PyLogicalPlan {
8585
"Cannot convert this plan to a LogicalNode: {:?}",
8686
other
8787
))),
88-
})
88+
}
8989
}
9090

9191
/// Get the inputs to this plan

0 commit comments

Comments
 (0)