Init commit.

This commit is contained in:
James Pace 2026-08-14 09:08:58 -04:00
commit 5d8dbe1d65
4 changed files with 438 additions and 0 deletions

240
Cargo.lock generated Normal file
View File

@ -0,0 +1,240 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "j7s_diagnostics"
version = "0.1.0"
dependencies = [
"limbo_graph",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "j7s_diagnostics_py"
version = "0.1.0"
dependencies = [
"j7s_diagnostics",
"pyo3",
]
[[package]]
name = "libc"
version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
[[package]]
name = "limbo_graph"
version = "0.1.0"
source = "git+https://git.jpace121.net/public/limbo_graph.git?branch=main#2d05aed05750fdde52424404001315a967e0d696"
[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "portable-atomic"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
dependencies = [
"libc",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
]
[[package]]
name = "pyo3-build-config"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
dependencies = [
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.119",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "serde_json"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "syn"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
[[package]]
name = "thiserror"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "j7s_diagnostics_py"
version = "0.1.0"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "j7s_diagnostics_py"
crate-type = ["cdylib"]
[dependencies]
pyo3 = "0.29.0"
j7s_diagnostics = { path="../j7s_diagnostics/", features=["std"] }

13
pyproject.toml Normal file
View File

@ -0,0 +1,13 @@
[build-system]
requires = ["maturin>=1.14,<2.0"]
build-backend = "maturin"
[project]
name = "j7s_diagnostics_py"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dynamic = ["version"]

172
src/lib.rs Normal file
View File

@ -0,0 +1,172 @@
use pyo3::exceptions::PyException;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyString};
use std::collections::BTreeMap;
/// A Python module implemented in Rust.
#[pymodule]
mod j7s_diagnostics_py {
#[pymodule_export]
use super::DiagnosticLevel;
#[pymodule_export]
use super::DiagnosticStatus;
#[pymodule_export]
use super::DiagnosticsTree;
}
#[pyclass(from_py_object)]
#[derive(Clone)]
pub enum DiagnosticLevel {
UNSET,
OK,
WARN,
ERROR,
STALE,
}
impl DiagnosticLevel {
fn from_rust(rust: &j7s_diagnostics::DiagnosticLevel) -> Self {
match *rust {
j7s_diagnostics::DiagnosticLevel::UNSET => Self::UNSET,
j7s_diagnostics::DiagnosticLevel::OK => Self::OK,
j7s_diagnostics::DiagnosticLevel::WARN => Self::WARN,
j7s_diagnostics::DiagnosticLevel::ERROR => Self::ERROR,
j7s_diagnostics::DiagnosticLevel::STALE => Self::STALE,
}
}
fn to_rust(&self) -> j7s_diagnostics::DiagnosticLevel {
match *self {
Self::UNSET => j7s_diagnostics::DiagnosticLevel::UNSET,
Self::OK => j7s_diagnostics::DiagnosticLevel::OK,
Self::WARN => j7s_diagnostics::DiagnosticLevel::WARN,
Self::ERROR => j7s_diagnostics::DiagnosticLevel::ERROR,
Self::STALE => j7s_diagnostics::DiagnosticLevel::STALE,
}
}
}
#[pyclass]
pub struct DiagnosticStatus {
#[pyo3(get, set)]
level: DiagnosticLevel,
#[pyo3(get, set)]
name: Py<PyString>,
#[pyo3(get, set)]
message: Py<PyString>,
#[pyo3(get, set)]
hardware_id: Py<PyString>,
#[pyo3(get, set)]
values: Py<PyDict>,
}
impl DiagnosticStatus {
fn from_rust<'py>(
py: Python<'py>,
rust: &j7s_diagnostics::DiagnosticStatus,
) -> Result<Self, Error> {
let values = PyDict::new(py);
for (key, value) in &rust.values() {
let key_as_py = PyString::new(py, key.as_str());
let value_as_py = PyString::new(py, value.as_str());
values.set_item(key_as_py, value_as_py)?;
}
let python = Self {
level: DiagnosticLevel::from_rust(&rust.level()),
name: PyString::new(py, rust.name().as_str()).unbind(),
message: PyString::new(py, rust.message().as_str()).unbind(),
hardware_id: PyString::new(py, rust.hardware_id().as_str()).unbind(),
values: values.unbind(),
};
Ok(python)
}
fn to_rust<'py>(&self, py: Python<'py>) -> Result<j7s_diagnostics::DiagnosticStatus, Error> {
let mut values = BTreeMap::<String, String>::new();
for (key, value) in self.values.bind(py).iter() {
let key_rust: String = key.extract()?;
let value_rust: String = value.extract()?;
values.insert(key_rust, value_rust);
}
let rust = j7s_diagnostics::DiagnosticStatus::new(
self.level.to_rust(),
self.name.bind(py).to_str()?.to_owned(),
self.message.bind(py).to_str()?.to_owned(),
self.hardware_id.bind(py).to_str()?.to_owned(),
values,
);
Ok(rust)
}
}
#[pyclass]
struct DiagnosticsTree {
tree: j7s_diagnostics::DiagnosticGraph,
}
#[pymethods]
impl DiagnosticsTree {
#[new]
pub fn new() -> Self {
Self {
tree: j7s_diagnostics::DiagnosticGraph::new(),
}
}
pub fn insert(&mut self, py: Python<'_>, status: &DiagnosticStatus) -> Result<(), Error> {
let rust = status.to_rust(py)?;
self.tree.add_status(rust)?;
Ok(())
}
pub fn from_name(
&self,
py: Python<'_>,
name: Py<PyString>,
) -> Result<Option<DiagnosticStatus>, Error> {
let rust_name = name.bind(py).to_str()?.to_owned();
let result = self.tree.value_from_name(&rust_name)?;
let rust_status = match result {
None => None,
Some((status, _)) => Some(DiagnosticStatus::from_rust(py, &status)?),
};
Ok(rust_status)
}
pub fn reconcile_levels(&mut self) -> Result<(), Error> {
Ok(self.tree.reconcile_levels()?)
}
pub fn to_json(&self, py: Python<'_>) -> Result<Py<PyString>, Error> {
let tree_view = j7s_diagnostics::TreeView::from_graph(&self.tree)?;
let rust_json = tree_view.to_json()?;
let python_json = PyString::new(py, rust_json.as_str()).unbind();
Ok(python_json)
}
}
enum Error {
J7s(j7s_diagnostics::Error),
Python(PyErr),
}
impl From<Error> for PyErr {
fn from(error: Error) -> PyErr {
match error {
Error::Python(err) => err,
Error::J7s(err) => PyException::new_err(err.to_string()),
}
}
}
impl From<j7s_diagnostics::Error> for Error {
fn from(other: j7s_diagnostics::Error) -> Error {
Error::J7s(other)
}
}
impl From<PyErr> for Error {
fn from(other: PyErr) -> Error {
Error::Python(other)
}
}