Skip to content

Commit 22e488f

Browse files
committed
Boring fixes for frozen
1 parent 0dd3225 commit 22e488f

File tree

2 files changed

+23
-21
lines changed

2 files changed

+23
-21
lines changed

src/config.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,39 @@
1818
use pyo3::prelude::*;
1919
use pyo3::types::*;
2020

21+
use std::sync::{Arc, Mutex};
22+
2123
use datafusion::config::ConfigOptions;
2224

2325
use crate::errors::PyDataFusionResult;
2426
use crate::utils::py_obj_to_scalar_value;
2527

26-
// TODO: Not frozen because set needs access
27-
#[pyclass(name = "Config", module = "datafusion", subclass)]
28+
#[pyclass(frozen, name = "Config", module = "datafusion", subclass)]
2829
#[derive(Clone)]
2930
pub(crate) struct PyConfig {
30-
config: ConfigOptions,
31+
config: Arc<Mutex<ConfigOptions>>,
3132
}
3233

3334
#[pymethods]
3435
impl PyConfig {
3536
#[new]
3637
fn py_new() -> Self {
3738
Self {
38-
config: ConfigOptions::new(),
39+
config: Arc::new(Mutex::new(ConfigOptions::new())),
3940
}
4041
}
4142

4243
/// Get configurations from environment variables
4344
#[staticmethod]
4445
pub fn from_env() -> PyDataFusionResult<Self> {
4546
Ok(Self {
46-
config: ConfigOptions::from_env()?,
47+
config: Arc::new(Mutex::new(ConfigOptions::from_env()?)),
4748
})
4849
}
4950

5051
/// Get a configuration option
5152
pub fn get<'py>(&self, key: &str, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
52-
let options = self.config.to_owned();
53+
let options = self.config.lock().unwrap();
5354
for entry in options.entries() {
5455
if entry.key == key {
5556
return Ok(entry.value.into_pyobject(py)?);
@@ -59,16 +60,17 @@ impl PyConfig {
5960
}
6061

6162
/// Set a configuration option
62-
pub fn set(&mut self, key: &str, value: PyObject, py: Python) -> PyDataFusionResult<()> {
63+
pub fn set(&self, key: &str, value: PyObject, py: Python) -> PyDataFusionResult<()> {
6364
let scalar_value = py_obj_to_scalar_value(py, value)?;
64-
self.config.set(key, scalar_value.to_string().as_str())?;
65+
let mut config = self.config.lock().unwrap();
66+
config.set(key, scalar_value.to_string().as_str())?;
6567
Ok(())
6668
}
6769

6870
/// Get all configuration options
6971
pub fn get_all(&self, py: Python) -> PyResult<PyObject> {
7072
let dict = PyDict::new(py);
71-
let options = self.config.to_owned();
73+
let options = self.config.lock().unwrap();
7274
for entry in options.entries() {
7375
dict.set_item(entry.key, entry.value.clone().into_pyobject(py)?)?;
7476
}

src/dataframe.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
use std::collections::HashMap;
1919
use std::ffi::CString;
20-
use std::sync::Arc;
20+
use std::sync::{Arc, Mutex};
2121

2222
use arrow::array::{new_null_array, RecordBatch, RecordBatchIterator, RecordBatchReader};
2323
use arrow::compute::can_cast_types;
@@ -284,31 +284,31 @@ impl PyParquetColumnOptions {
284284
/// A PyDataFrame is a representation of a logical plan and an API to compose statements.
285285
/// Use it to build a plan and `.collect()` to execute the plan and collect the result.
286286
/// The actual execution of a plan runs natively on Rust and Arrow on a multi-threaded environment.
287-
// TODO: Not frozen because batches don't currently handle interior mutability
288-
#[pyclass(name = "DataFrame", module = "datafusion", subclass)]
287+
#[pyclass(frozen, name = "DataFrame", module = "datafusion", subclass)]
289288
#[derive(Clone)]
290289
pub struct PyDataFrame {
291290
df: Arc<DataFrame>,
292291

293292
// In IPython environment cache batches between __repr__ and _repr_html_ calls.
294-
batches: Option<(Vec<RecordBatch>, bool)>,
293+
#[allow(clippy::type_complexity)] // Currently only used once
294+
batches: Arc<Mutex<Option<(Vec<RecordBatch>, bool)>>>,
295295
}
296296

297297
impl PyDataFrame {
298298
/// creates a new PyDataFrame
299299
pub fn new(df: DataFrame) -> Self {
300300
Self {
301301
df: Arc::new(df),
302-
batches: None,
302+
batches: Arc::new(Mutex::new(None)),
303303
}
304304
}
305305

306-
fn prepare_repr_string(&mut self, py: Python, as_html: bool) -> PyDataFusionResult<String> {
306+
fn prepare_repr_string(&self, py: Python, as_html: bool) -> PyDataFusionResult<String> {
307307
// Get the Python formatter and config
308308
let PythonFormatter { formatter, config } = get_python_formatter_with_config(py)?;
309309

310-
let should_cache = *is_ipython_env(py) && self.batches.is_none();
311-
let (batches, has_more) = match self.batches.take() {
310+
let should_cache = *is_ipython_env(py) && self.batches.lock().unwrap().is_none();
311+
let (batches, has_more) = match self.batches.lock().unwrap().take() {
312312
Some(b) => b,
313313
None => wait_for_future(
314314
py,
@@ -347,7 +347,7 @@ impl PyDataFrame {
347347
let html_str: String = html_result.extract()?;
348348

349349
if should_cache {
350-
self.batches = Some((batches, has_more));
350+
*self.batches.lock().unwrap() = Some((batches, has_more));
351351
}
352352

353353
Ok(html_str)
@@ -377,7 +377,7 @@ impl PyDataFrame {
377377
}
378378
}
379379

380-
fn __repr__(&mut self, py: Python) -> PyDataFusionResult<String> {
380+
fn __repr__(&self, py: Python) -> PyDataFusionResult<String> {
381381
self.prepare_repr_string(py, false)
382382
}
383383

@@ -412,7 +412,7 @@ impl PyDataFrame {
412412
Ok(format!("DataFrame()\n{batches_as_displ}{additional_str}"))
413413
}
414414

415-
fn _repr_html_(&mut self, py: Python) -> PyDataFusionResult<String> {
415+
fn _repr_html_(&self, py: Python) -> PyDataFusionResult<String> {
416416
self.prepare_repr_string(py, true)
417417
}
418418

@@ -875,7 +875,7 @@ impl PyDataFrame {
875875

876876
#[pyo3(signature = (requested_schema=None))]
877877
fn __arrow_c_stream__<'py>(
878-
&'py mut self,
878+
&'py self,
879879
py: Python<'py>,
880880
requested_schema: Option<Bound<'py, PyCapsule>>,
881881
) -> PyDataFusionResult<Bound<'py, PyCapsule>> {

0 commit comments

Comments
 (0)