Skip to main content

polars_python/functions/
io.rs

1use std::io::BufReader;
2
3#[cfg(any(feature = "ipc", feature = "parquet"))]
4use polars::prelude::ArrowSchema;
5use polars::prelude::CloudScheme;
6use pyo3::prelude::*;
7use pyo3::types::PyDict;
8
9use crate::conversion::Wrap;
10use crate::error::PyPolarsErr;
11use crate::file::{EitherRustPythonFile, get_either_file};
12use crate::io::cloud_options::OptPyCloudOptions;
13
14#[cfg(feature = "ipc")]
15#[pyfunction]
16pub fn read_ipc_schema(py: Python<'_>, py_f: Py<PyAny>) -> PyResult<Bound<'_, PyDict>> {
17    use arrow::io::ipc::read::read_file_metadata;
18    let metadata = match get_either_file(py_f, false)? {
19        EitherRustPythonFile::Rust(r) => {
20            read_file_metadata(&mut BufReader::new(r)).map_err(PyPolarsErr::from)?
21        },
22        EitherRustPythonFile::Py(mut r) => read_file_metadata(&mut r).map_err(PyPolarsErr::from)?,
23    };
24
25    let dict = PyDict::new(py);
26    fields_to_pydict(&metadata.schema, &dict)?;
27    Ok(dict)
28}
29
30#[cfg(feature = "parquet")]
31#[pyfunction]
32pub fn read_parquet_metadata(
33    py: Python,
34    py_f: Py<PyAny>,
35    storage_options: OptPyCloudOptions,
36    credential_provider: Option<Py<PyAny>>,
37) -> PyResult<Py<PyDict>> {
38    use std::io::Cursor;
39
40    use polars_error::feature_gated;
41    use polars_io::pl_async::get_runtime;
42    use polars_parquet::read::read_metadata;
43    use polars_parquet::read::schema::read_custom_key_value_metadata;
44
45    use crate::file::{PythonScanSourceInput, get_python_scan_source_input};
46
47    let metadata = match get_python_scan_source_input(py_f, false)? {
48        PythonScanSourceInput::Buffer(buf) => {
49            read_metadata(&mut Cursor::new(buf)).map_err(PyPolarsErr::from)?
50        },
51        PythonScanSourceInput::Path(p) => {
52            let cloud_options = storage_options.extract_opt_cloud_options(
53                CloudScheme::from_path(p.as_str()),
54                credential_provider,
55            )?;
56
57            if p.has_scheme() {
58                feature_gated!("cloud", {
59                    use polars::prelude::ParquetObjectStore;
60                    use polars_error::PolarsResult;
61
62                    py.detach(|| {
63                        get_runtime().block_on(async {
64                            let mut reader =
65                                ParquetObjectStore::from_uri(p, cloud_options.as_ref(), None)
66                                    .await?;
67                            let result = reader.get_metadata().await?;
68                            PolarsResult::Ok((**result).clone())
69                        })
70                    })
71                })
72                .map_err(PyPolarsErr::from)?
73            } else {
74                let file = polars_utils::open_file(p.as_std_path()).map_err(PyPolarsErr::from)?;
75                read_metadata(&mut BufReader::new(file)).map_err(PyPolarsErr::from)?
76            }
77        },
78        PythonScanSourceInput::File(f) => {
79            read_metadata(&mut BufReader::new(f)).map_err(PyPolarsErr::from)?
80        },
81    };
82
83    let key_value_metadata = read_custom_key_value_metadata(metadata.key_value_metadata());
84    let dict = PyDict::new(py);
85    for (key, value) in key_value_metadata.into_iter() {
86        dict.set_item(key.as_str(), value.as_str())?;
87    }
88    Ok(dict.unbind())
89}
90
91#[cfg(any(feature = "ipc", feature = "parquet"))]
92fn fields_to_pydict(schema: &ArrowSchema, dict: &Bound<'_, PyDict>) -> PyResult<()> {
93    for field in schema.iter_values() {
94        let dt = Wrap(polars::prelude::DataType::from_arrow_field(field));
95        dict.set_item(field.name.as_str(), &dt)?;
96    }
97    Ok(())
98}
99
100#[cfg(feature = "clipboard")]
101#[pyfunction]
102pub fn read_clipboard_string() -> PyResult<String> {
103    use arboard;
104    let mut clipboard =
105        arboard::Clipboard::new().map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
106    let result = clipboard
107        .get_text()
108        .map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
109    Ok(result)
110}
111
112#[cfg(feature = "clipboard")]
113#[pyfunction]
114pub fn write_clipboard_string(s: &str) -> PyResult<()> {
115    use arboard;
116    let mut clipboard =
117        arboard::Clipboard::new().map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
118    clipboard
119        .set_text(s)
120        .map_err(|e| PyPolarsErr::Other(format!("{e}")))?;
121    Ok(())
122}