diff --git a/Cargo.lock b/Cargo.lock index b20c4c0..147670d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "autosar-data" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92741401526284907ea6ae04ca7ef3c0a198a093c3b5cc058374167053fe83d" +checksum = "628b53c54a58c8ad7b98436386c05aa96fe520f9c697d5d77e329cd59f40386d" dependencies = [ "autosar-data-specification", "parking_lot", @@ -23,9 +23,9 @@ dependencies = [ [[package]] name = "autosar-data-specification" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86920f753cf0228cf7dbfc7d5d92c0fbf0bfec65f6e8df3a922a09185e98ecb4" +checksum = "56b54d8a6e90455250b3a5fad3bea181d76c9ba22e32edf475728ccaafecae7f" dependencies = [ "num-derive", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 5a5e2f2..9b0adc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,6 @@ name = "autosar_data" crate-type = ["cdylib"] [dependencies] -autosar-data = {version = "0.10"} -autosar-data-specification = {version = "0.10"} +autosar-data = {version = "0.11"} +autosar-data-specification = {version = "0.11"} pyo3 = "0.19.2" diff --git a/autosar_data.pyi b/autosar_data.pyi index 1240639..c774cb4 100644 --- a/autosar_data.pyi +++ b/autosar_data.pyi @@ -400,6 +400,13 @@ class CharacterDataTypeUnsignedInt: def __repr__(self) -> str: ... def __str__(self) -> str: ... +def check_file(filename: str): + """Check if the file contains arxml data. Returns true if an arxml file header is found and does not parse anything after it.""" + ... + +def check_buffer(filename: bytes): + """Check if the buffer contains arxml data. Returns true if an arxml file header is found and does not parse anything after it.""" + ... __version__: str """ diff --git a/src/lib.rs b/src/lib.rs index 9d4ba51..01a7c01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ use autosar_data_rs::CharacterData; use autosar_data_specification::expand_version_mask; use autosar_data_specification::CharacterDataSpec; use pyo3::create_exception; +use pyo3::exceptions::{PyTypeError, PyValueError}; use pyo3::intern; use pyo3::prelude::*; use pyo3::types::*; @@ -371,6 +372,28 @@ impl ValidSubElementInfo { } } +#[pyfunction] +fn check_file(filename: &str) -> bool { + autosar_data_rs::check_file(filename) +} + +#[pyfunction] +fn check_buffer(object: PyObject) -> PyResult { + Python::with_gil(|py| { + if let Ok(bytebuffer) = object.extract::<&[u8]>(py) { + Ok(autosar_data_rs::check_buffer(bytebuffer)) + } else if let Ok(stringbuffer) = object.extract::<&str>(py) { + Ok(autosar_data_rs::check_buffer(stringbuffer.as_bytes())) + } else { + let any = object.as_ref(py); + Err(PyTypeError::new_err(format!( + "'{}' cannot be converted to 'bytes'", + any.get_type() + ))) + } + }) +} + /// Provides functionality to read, modify and write Autosar arxml files, /// both separately and in projects consisting of multiple files. /// @@ -383,6 +406,11 @@ impl ValidSubElementInfo { /// - ElementType /// - ValidSubElementInfo /// +/// Functions: +/// +/// - check_file +/// - check_buffwe +/// /// Variables: /// /// - __version__ @@ -410,6 +438,8 @@ fn autosar_data(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_function(wrap_pyfunction!(check_file, m)?)?; + m.add_function(wrap_pyfunction!(check_buffer, m)?)?; m.add("AutosarDataError", py.get_type::())?; m.add("__version__", intern!(m.py(), env!("CARGO_PKG_VERSION")))?; Ok(()) @@ -427,12 +457,12 @@ fn extract_character_data( if let Ok(enumitem) = autosar_data_rs::EnumItem::from_str(&strval) { Ok(CharacterData::Enum(enumitem)) } else { - Err(pyo3::exceptions::PyValueError::new_err(format!( + Err(PyValueError::new_err(format!( "string value '{strval}' cannot be converted to 'EnumItem'" ))) } } else { - Err(pyo3::exceptions::PyTypeError::new_err(format!( + Err(PyTypeError::new_err(format!( "'{}' cannot be converted to 'EnumItem'", any.get_type() ))) @@ -446,7 +476,7 @@ fn extract_character_data( } else if let Ok(floatval) = any.extract::() { Ok(CharacterData::String(floatval.to_string())) } else { - Err(pyo3::exceptions::PyTypeError::new_err(format!( + Err(PyTypeError::new_err(format!( "'{}' cannot be converted to 'str'", any.get_type() ))) @@ -457,14 +487,14 @@ fn extract_character_data( if let Ok(intval) = strval.parse() { Ok(CharacterData::UnsignedInteger(intval)) } else { - Err(pyo3::exceptions::PyValueError::new_err(format!( + Err(PyValueError::new_err(format!( "invalid literal '{strval}' for conversion to int" ))) } } else if let Ok(intval) = any.extract::() { Ok(CharacterData::UnsignedInteger(intval)) } else { - Err(pyo3::exceptions::PyTypeError::new_err(format!( + Err(PyTypeError::new_err(format!( "'{}' cannot be converted to 'int'", any.get_type() ))) @@ -475,7 +505,7 @@ fn extract_character_data( if let Ok(floatval) = strval.parse() { Ok(CharacterData::Double(floatval)) } else { - Err(pyo3::exceptions::PyValueError::new_err(format!( + Err(PyValueError::new_err(format!( "invalid literal '{strval}' for conversion to float" ))) } @@ -484,7 +514,7 @@ fn extract_character_data( } else if let Ok(floatval) = any.extract::() { Ok(CharacterData::Double(floatval)) } else { - Err(pyo3::exceptions::PyTypeError::new_err(format!( + Err(PyTypeError::new_err(format!( "'{}' cannot be converted to 'float'", any.get_type() ))) @@ -537,7 +567,7 @@ fn version_mask_from_any(version_obj: PyObject) -> PyResult { Ok(ver as u32) } else { let any = version_obj.as_ref(py); - Err(pyo3::exceptions::PyTypeError::new_err(format!( + Err(PyTypeError::new_err(format!( "'{}' cannot be converted to 'VersionSpecification'", any.get_type() ))) diff --git a/test/element_test.py b/test/element_test.py index 016c9ca..6fc995d 100644 --- a/test/element_test.py +++ b/test/element_test.py @@ -296,6 +296,17 @@ def test_character_data_5() -> None: el_ar_packages.remove_character_content_item(0) +def test_character_data_6() -> None: + # reading and writing character data on an element with content_type == Mixed + # this should work as long as there are 0 or 1 content items in the mixed content + model = AutosarModel() + model.create_file("file") + el_l2 = model.root_element.create_sub_element("AR-PACKAGES") \ + .create_named_sub_element("AR-PACKAGE", "Pkg1") \ + .create_sub_element("DESC") \ + .create_sub_element("L-2") + el_l2.character_data = "text" + assert el_l2.character_data == "text" def test_element_creation() -> None: model = AutosarModel() diff --git a/test/test.py b/test/test.py index 850699e..e7a0468 100644 --- a/test/test.py +++ b/test/test.py @@ -1,5 +1,6 @@ from autosar_data import * import pytest +import os def test_others() -> None: model = AutosarModel() @@ -41,3 +42,18 @@ def test_others() -> None: with pytest.raises(AutosarDataError): model.root_element.set_attribute("bla", 0) + + +def test_check_arxml(tmp_path: str) -> None: + model = AutosarModel() + filename1 = os.path.join(tmp_path, "test.arxml") + file = model.create_file(filename1) + model.write() + assert check_file(filename1) == True + assert check_file("no_such_file") == False + + text = file.serialize() + assert check_buffer(text.encode('utf-8')) == True + assert check_buffer(b'abcdef') == False + with pytest.raises(TypeError): + check_buffer(file) \ No newline at end of file