1mod data;
2mod error;
3mod types;
4mod utils;
5
6use std::fmt::Display;
7
8#[cfg(feature = "python")]
9use error::py_errors;
10#[cfg(feature = "python")]
11use pyo3::prelude::*;
12#[cfg(feature = "python")]
13use types::excelsheet::{CellError, CellErrors};
14
15pub use data::{FastExcelColumn, FastExcelSeries};
16use error::ErrorContext;
17pub use error::{FastExcelError, FastExcelErrorKind, FastExcelResult};
18pub use types::{
19 ColumnInfo, ColumnNameFrom, DType, DTypeCoercion, DTypeFrom, DTypes, DefinedName, ExcelReader,
20 ExcelSheet, ExcelTable, IdxOrName, LoadSheetOrTableOptions, SelectedColumns, SheetVisible,
21 SkipRows,
22};
23
24pub fn read_excel<S: AsRef<str> + Display>(path: S) -> FastExcelResult<ExcelReader> {
27 ExcelReader::try_from_path(path.as_ref())
28 .with_context(|| format!("could not load excel file at {path}"))
29}
30
31#[cfg(feature = "python")]
32#[pyfunction(name = "read_excel")]
34fn py_read_excel<'py>(source: &Bound<'_, PyAny>, py: Python<'py>) -> PyResult<ExcelReader> {
35 use py_errors::IntoPyResult;
36
37 if let Ok(path) = source.extract::<String>() {
38 py.detach(|| ExcelReader::try_from_path(&path))
39 .with_context(|| format!("could not load excel file at {path}"))
40 .into_pyresult()
41 } else if let Ok(bytes) = source.extract::<&[u8]>() {
42 py.detach(|| ExcelReader::try_from(bytes))
43 .with_context(|| "could not load excel file for those bytes")
44 .into_pyresult()
45 } else {
46 Err(py_errors::InvalidParametersError::new_err(
47 "source must be a string or bytes",
48 ))
49 }
50}
51
52#[cfg(feature = "python")]
55fn get_python_version() -> String {
56 let version = env!("CARGO_PKG_VERSION").to_string();
57 version.replace("-alpha", "a").replace("-beta", "b")
63}
64
65#[cfg(feature = "python")]
66#[pymodule(gil_used = false)]
67fn _fastexcel(m: &Bound<'_, PyModule>) -> PyResult<()> {
68 use crate::types::excelsheet::column_info::{ColumnInfo, ColumnInfoNoDtype};
69
70 pyo3_log::init();
71
72 let py = m.py();
73 m.add_function(wrap_pyfunction!(py_read_excel, m)?)?;
74 m.add_class::<ColumnInfo>()?;
75 m.add_class::<ColumnInfoNoDtype>()?;
76 m.add_class::<DefinedName>()?;
77 m.add_class::<CellError>()?;
78 m.add_class::<CellErrors>()?;
79 m.add_class::<ExcelSheet>()?;
80 m.add_class::<ExcelReader>()?;
81 m.add_class::<ExcelTable>()?;
82 m.add("__version__", get_python_version())?;
83
84 [
86 ("FastExcelError", py.get_type::<py_errors::FastExcelError>()),
87 (
88 "UnsupportedColumnTypeCombinationError",
89 py.get_type::<py_errors::UnsupportedColumnTypeCombinationError>(),
90 ),
91 (
92 "CannotRetrieveCellDataError",
93 py.get_type::<py_errors::CannotRetrieveCellDataError>(),
94 ),
95 (
96 "CalamineCellError",
97 py.get_type::<py_errors::CalamineCellError>(),
98 ),
99 ("CalamineError", py.get_type::<py_errors::CalamineError>()),
100 (
101 "SheetNotFoundError",
102 py.get_type::<py_errors::SheetNotFoundError>(),
103 ),
104 (
105 "ColumnNotFoundError",
106 py.get_type::<py_errors::ColumnNotFoundError>(),
107 ),
108 ("ArrowError", py.get_type::<py_errors::ArrowError>()),
109 (
110 "InvalidParametersError",
111 py.get_type::<py_errors::InvalidParametersError>(),
112 ),
113 ]
114 .into_iter()
115 .try_for_each(|(exc_name, exc_type)| m.add(exc_name, exc_type))
116}