diff --git a/bindings/src/error.rs b/bindings/src/error.rs new file mode 100644 index 0000000..2c9532f --- /dev/null +++ b/bindings/src/error.rs @@ -0,0 +1,16 @@ +pub use codecov_rs::error::CodecovError as RsCodecovError; +use pyo3::{exceptions::PyRuntimeError, prelude::*}; + +pub struct PyCodecovError(RsCodecovError); + +impl From for PyErr { + fn from(error: PyCodecovError) -> Self { + PyRuntimeError::new_err(error.0.to_string()) + } +} + +impl From for PyCodecovError { + fn from(other: RsCodecovError) -> Self { + Self(other) + } +} diff --git a/bindings/src/lib.rs b/bindings/src/lib.rs index 696a20b..6c8e4e4 100644 --- a/bindings/src/lib.rs +++ b/bindings/src/lib.rs @@ -1,18 +1,41 @@ +use std::{fs::File, path::PathBuf}; + +use codecov_rs::{parsers, report}; use pyo3::prelude::*; -// See if non-pyo3-annotated Rust lines are still instrumented -fn raw_rust_add(a: usize, b: usize) -> usize { - println!("hello"); - a + b -} +use crate::error::PyCodecovError; + +mod error; + +#[pyclass] +pub struct SqliteReportBuilder(report::SqliteReportBuilder); + +#[pymethods] +impl SqliteReportBuilder { + pub fn filepath(&self) -> PyResult<&PathBuf> { + Ok(&self.0.filename) + } + + #[staticmethod] + #[pyo3(signature = (report_json_filepath, chunks_filepath, out_path))] + pub fn from_pyreport( + report_json_filepath: &str, + chunks_filepath: &str, + out_path: &str, + ) -> PyResult { + let mut report_builder = + report::SqliteReportBuilder::open(out_path.into()).map_err(PyCodecovError::from)?; -#[pyfunction] -fn dummy_add(a: usize, b: usize) -> PyResult { - Ok(raw_rust_add(a, b)) + let report_json_file = File::open(report_json_filepath)?; + let chunks_file = File::open(chunks_filepath)?; + parsers::pyreport::parse_pyreport(&report_json_file, &chunks_file, &mut report_builder) + .map_err(PyCodecovError::from)?; + Ok(SqliteReportBuilder(report_builder)) + } } #[pymodule] fn _bindings(_py: Python, m: &Bound) -> PyResult<()> { - m.add_function(wrap_pyfunction!(dummy_add, m)?)?; + m.add_class::()?; Ok(()) } diff --git a/python/codecov_rs/dummy_add.py b/python/codecov_rs/dummy_add.py deleted file mode 100644 index 6801173..0000000 --- a/python/codecov_rs/dummy_add.py +++ /dev/null @@ -1,3 +0,0 @@ -from ._bindings import dummy_add - -dummy_add.__module__ = __name__ diff --git a/python/codecov_rs/dummy_add.pyi b/python/codecov_rs/dummy_add.pyi deleted file mode 100644 index 8d003c5..0000000 --- a/python/codecov_rs/dummy_add.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from pydantic.types import NonNegativeInt - -def dummy_add(a: NonNegativeInt, b: NonNegativeInt) -> NonNegativeInt: ... diff --git a/python/codecov_rs/report.py b/python/codecov_rs/report.py new file mode 100644 index 0000000..35d9089 --- /dev/null +++ b/python/codecov_rs/report.py @@ -0,0 +1,3 @@ +from ._bindings import SqliteReportBuilder + +SqliteReportBuilder.__module__ = __name__ diff --git a/python/codecov_rs/report.pyi b/python/codecov_rs/report.pyi new file mode 100644 index 0000000..363cd88 --- /dev/null +++ b/python/codecov_rs/report.pyi @@ -0,0 +1,6 @@ +class SqliteReportBuilder: + @staticmethod + def from_pyreport( + report_json_filepath: str, chunks_filepath: str, out_filepath: str | None = None + ) -> SqliteReportBuilder: ... + def filepath(self) -> str: ... diff --git a/python/tests/test_lib.py b/python/tests/test_lib.py index ec3a03f..4e53097 100644 --- a/python/tests/test_lib.py +++ b/python/tests/test_lib.py @@ -1,4 +1,26 @@ -def test_dummy_add(): - from codecov_rs.dummy_add import dummy_add +from pathlib import Path +from tempfile import NamedTemporaryFile - assert dummy_add(3, 4) == 7 +from codecov_rs.report import SqliteReportBuilder + +PROJECT_ROOT = Path(__file__).parent.parent.parent + + +def get_fixture_path(path_from_root: str) -> str: + return str(PROJECT_ROOT / path_from_root) + + +def test_from_pyreport(): + report_json_filepath = get_fixture_path( + "test_utils/fixtures/pyreport/codecov-rs-reports-json-d2a9ba1.txt" + ) + chunks_filepath = get_fixture_path( + "test_utils/fixtures/pyreport/codecov-rs-chunks-d2a9ba1.txt" + ) + + with NamedTemporaryFile() as out_file: + report_builder = SqliteReportBuilder.from_pyreport( + report_json_filepath, chunks_filepath, out_file.name + ) + print(report_builder.filepath()) + assert report_builder.filepath() is not None