use crate::cleaner::clean;
use crate::unicode::{CleanOpts, InspectOpts, clean_text, inspect_text};
use pyo3::prelude::*;
use pyo3::types::PyBytes;
#[pyclass(name = "CleanTextResult")]
pub struct PyCleanTextResult {
#[pyo3(get)]
pub cleaned: String,
#[pyo3(get)]
pub removed_count: usize,
#[pyo3(get)]
pub replaced_count: usize,
#[pyo3(get)]
pub summary: Vec<String>,
}
#[pyclass(name = "CharHit", skip_from_py_object)]
#[derive(Clone)]
pub struct PyCharHit {
#[pyo3(get)]
pub codepoint: u32,
#[pyo3(get)]
pub character: String,
#[pyo3(get)]
pub label: String,
#[pyo3(get)]
pub count: usize,
#[pyo3(get)]
pub kind: String,
#[pyo3(get)]
pub confidence: String,
#[pyo3(get)]
pub sample_offsets: Vec<usize>,
}
#[pyclass(name = "TextInspectReport")]
pub struct PyTextInspectReport {
#[pyo3(get)]
pub length: usize,
#[pyo3(get)]
pub suspicious_total: usize,
#[pyo3(get)]
pub hits: Vec<PyCharHit>,
#[pyo3(get)]
pub notes: Vec<String>,
}
#[pyfunction(name = "clean_text")]
pub fn clean_text_py(text: &str) -> PyResult<PyCleanTextResult> {
let opts = CleanOpts::safe();
let (cleaned, stats) = clean_text(text, &opts)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
Ok(PyCleanTextResult {
cleaned,
removed_count: stats.removed_count,
replaced_count: stats.replaced_count,
summary: stats.summary,
})
}
#[pyfunction(name = "inspect_text")]
pub fn inspect_text_py(text: &str) -> PyResult<PyTextInspectReport> {
let opts = InspectOpts::default();
let report = inspect_text(text, &opts)
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
let hits = report
.hits
.into_iter()
.map(|h| PyCharHit {
codepoint: h.codepoint,
character: h.character,
label: h.label,
count: h.count,
kind: h.kind.as_str().to_string(),
confidence: h.confidence.as_str().to_string(),
sample_offsets: h.sample_offsets,
})
.collect();
Ok(PyTextInspectReport {
length: report.length,
suspicious_total: report.suspicious_total,
hits,
notes: report.notes,
})
}
#[pyfunction(name = "clean_bytes")]
pub fn clean_bytes_py<'py>(py: Python<'py>, data: &[u8]) -> PyResult<Bound<'py, PyBytes>> {
let out =
clean(data, None).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
Ok(PyBytes::new(py, &out.bytes))
}
pub fn register_python_module(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(clean_text_py, m)?)?;
m.add_function(wrap_pyfunction!(inspect_text_py, m)?)?;
m.add_function(wrap_pyfunction!(clean_bytes_py, m)?)?;
m.add_class::<PyCleanTextResult>()?;
m.add_class::<PyTextInspectReport>()?;
m.add_class::<PyCharHit>()?;
Ok(())
}