Skip to content

Commit 732a7a7

Browse files
committed
refactor: move python public API to djc-core create
1 parent 03de1ab commit 732a7a7

File tree

9 files changed

+532
-501
lines changed

9 files changed

+532
-501
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ members = [
66
resolver = "2"
77

88
[workspace.dependencies]
9-
pyo3 = { version = "0.27.0", features = ["extension-module"] }
9+
pyo3 = { version = "0.27.1", features = ["extension-module"] }
1010
quick-xml = "0.38.3"
1111

1212
# https://ohadravid.github.io/posts/2023-03-rusty-python
1313
[profile.release]
14-
debug = true # Debug symbols for profiler.
15-
lto = true # Link-time optimization.
16-
codegen-units = 1 # Slower compilation but faster code.
14+
debug = true # Debug symbols for profiler.
15+
lto = true # Link-time optimization.
16+
codegen-units = 1 # Slower compilation but faster code.

crates/djc-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[package]
22
name = "djc-core"
3+
description = "Singular Python API for Rust code used by django-components"
34
version = "1.1.0"
45
edition = "2021"
56

crates/djc-core/src/lib.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,76 @@
1-
use djc_html_transformer::set_html_attributes;
1+
use djc_html_transformer::{
2+
set_html_attributes as set_html_attributes_rust, HtmlTransformerConfig,
3+
};
4+
use pyo3::exceptions::{PyValueError};
25
use pyo3::prelude::*;
6+
use pyo3::types::{PyDict, PyTuple};
37

4-
/// A Python module implemented in Rust for high-performance transformations.
8+
/// Singular Python API that brings togther all the other Rust crates.
59
#[pymodule]
610
fn djc_core(m: &Bound<'_, PyModule>) -> PyResult<()> {
11+
// HTML transformer
712
m.add_function(wrap_pyfunction!(set_html_attributes, m)?)?;
813
Ok(())
914
}
15+
16+
/// Transform HTML by adding attributes to the elements.
17+
///
18+
/// Args:
19+
/// html (str): The HTML string to transform. Can be a fragment or full document.
20+
/// root_attributes (List[str]): List of attribute names to add to root elements only.
21+
/// all_attributes (List[str]): List of attribute names to add to all elements.
22+
/// check_end_names (bool, optional): Whether to validate matching of end tags. Defaults to false.
23+
/// watch_on_attribute (str, optional): If set, captures which attributes were added to elements with this attribute.
24+
///
25+
/// Returns:
26+
/// Tuple[str, Dict[str, List[str]]]: A tuple containing:
27+
/// - The transformed HTML string
28+
/// - A dictionary mapping captured attribute values to lists of attributes that were added
29+
/// to those elements. Only returned if watch_on_attribute is set, otherwise empty dict.
30+
///
31+
/// Example:
32+
/// >>> html = '<div data-id="123"><p>Hello</p></div>'
33+
/// >>> html, captured = set_html_attributes(html, ['data-root-id'], ['data-v-123'], watch_on_attribute='data-id')
34+
/// >>> print(captured)
35+
/// {'123': ['data-root-id', 'data-v-123']}
36+
///
37+
/// Raises:
38+
/// ValueError: If the HTML is malformed or cannot be parsed.
39+
#[pyfunction]
40+
#[pyo3(signature = (html, root_attributes, all_attributes, check_end_names=None, watch_on_attribute=None))]
41+
#[pyo3(
42+
text_signature = "(html, root_attributes, all_attributes, *, check_end_names=False, watch_on_attribute=None)"
43+
)]
44+
pub fn set_html_attributes(
45+
py: Python,
46+
html: &str,
47+
root_attributes: Vec<String>,
48+
all_attributes: Vec<String>,
49+
check_end_names: Option<bool>,
50+
watch_on_attribute: Option<String>,
51+
) -> PyResult<Py<PyAny>> {
52+
let config = HtmlTransformerConfig::new(
53+
root_attributes,
54+
all_attributes,
55+
check_end_names.unwrap_or(false),
56+
watch_on_attribute,
57+
);
58+
59+
match set_html_attributes_rust(html, &config) {
60+
Ok((html, captured)) => {
61+
// Convert captured attributes to a Python dictionary
62+
let captured_dict = PyDict::new(py);
63+
for (id, attrs) in captured {
64+
captured_dict.set_item(id, attrs)?;
65+
}
66+
67+
// Convert items to Bound<PyAny> for the tuple
68+
use pyo3::types::PyString;
69+
let html_obj = PyString::new(py, &html).as_any().clone();
70+
let dict_obj = captured_dict.as_any().clone();
71+
let result = PyTuple::new(py, vec![html_obj, dict_obj])?;
72+
Ok(result.into_any().unbind())
73+
}
74+
Err(e) => Err(PyValueError::new_err(e.to_string())),
75+
}
76+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "djc-html-transformer"
3+
description = "Apply attributes to HTML in a single pass"
34
version = "1.0.3"
45
edition = "2021"
56

67
[dependencies]
7-
pyo3 = { workspace = true }
88
quick-xml = { workspace = true }

0 commit comments

Comments
 (0)