Skip to content

Commit

Permalink
Add support for adding XmlFragments to arrays and maps (#195)
Browse files Browse the repository at this point in the history
* Add support for adding XmlFragments to arrays and maps

I overlooked support for this in my initial XML support branch because
I was not sure if YJS supported XML fragments nested in either of those
types, but it works, so I've added support.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
ColonelThirtyTwo and pre-commit-ci[bot] authored Dec 3, 2024
1 parent 90797ea commit 01527f8
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 15 deletions.
25 changes: 18 additions & 7 deletions src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ use pyo3::prelude::*;
use pyo3::exceptions::{PyValueError, PyTypeError};
use pyo3::types::{PyList, PyString};
use yrs::{
Any,
ArrayRef,
Array as _Array,
Doc as _Doc,
DeepObservable,
Observable,
TransactionMut,
Any, Array as _Array, ArrayRef, DeepObservable, Doc as _Doc, Observable, TransactionMut, XmlFragmentPrelim
};
use yrs::types::ToJson;
use yrs::types::text::TextPrelim;
Expand All @@ -20,6 +14,7 @@ use crate::type_conversions::{events_into_py, py_to_any, ToPython};
use crate::text::Text;
use crate::map::Map;
use crate::doc::Doc;
use crate::xml::XmlFragment;


#[pyclass]
Expand Down Expand Up @@ -79,6 +74,22 @@ impl Array {
Python::with_gil(|py| { Ok(shared.into_py(py)) })
}

fn insert_xmlfragment_prelim(&self, txn: &mut Transaction, index: u32) -> PyResult<PyObject> {
let mut _t = txn.transaction();
let mut t = _t.as_mut().unwrap().as_mut();
let integrated = self.array.insert(&mut t, index, XmlFragmentPrelim::default());
let shared = XmlFragment::from(integrated);
Python::with_gil(|py| { Ok(shared.into_py(py)) })
}

fn insert_xmlelement_prelim(&self, _txn: &mut Transaction, _index: u32) -> PyResult<PyObject> {
Err(PyTypeError::new_err("Cannot insert an XmlElement into an array - insert it into an XmlFragment and insert that into the array"))
}

fn insert_xmltext_prelim(&self, _txn: &mut Transaction, _index: u32) -> PyResult<PyObject> {
Err(PyTypeError::new_err("Cannot insert an XmlText into an array - insert it into an XmlFragment and insert that into the array"))
}

fn insert_doc(&self, txn: &mut Transaction, index: u32, doc: &Bound<'_, PyAny>) -> PyResult<()> {
let mut _t = txn.transaction();
let mut t = _t.as_mut().unwrap().as_mut();
Expand Down
25 changes: 18 additions & 7 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@ use pyo3::prelude::*;
use pyo3::exceptions::{PyValueError, PyTypeError};
use pyo3::types::{PyString, PyDict, PyList};
use yrs::{
Any,
Doc as _Doc,
MapRef,
Map as _Map,
DeepObservable,
Observable,
TransactionMut,
Any, DeepObservable, Doc as _Doc, Map as _Map, MapRef, Observable, TransactionMut, XmlFragmentPrelim
};
use yrs::types::ToJson;
use yrs::types::text::TextPrelim;
Expand All @@ -20,6 +14,7 @@ use crate::type_conversions::{EntryChangeWrapper, events_into_py, py_to_any, ToP
use crate::text::Text;
use crate::array::Array;
use crate::doc::Doc;
use crate::xml::XmlFragment;


#[pyclass]
Expand Down Expand Up @@ -79,6 +74,22 @@ impl Map {
Python::with_gil(|py| { Ok(shared.into_py(py)) })
}

fn insert_xmlfragment_prelim(&self, txn: &mut Transaction, key: &str) -> PyResult<PyObject> {
let mut _t = txn.transaction();
let mut t = _t.as_mut().unwrap().as_mut();
let integrated = self.map.insert(&mut t, key, XmlFragmentPrelim::default());
let shared = XmlFragment::from(integrated);
Python::with_gil(|py| { Ok(shared.into_py(py)) })
}

fn insert_xmlelement_prelim(&self, _txn: &mut Transaction, _key: &str) -> PyResult<PyObject> {
Err(PyTypeError::new_err("Cannot insert an XmlElement into a map - insert it into an XmlFragment and insert that into the map"))
}

fn insert_xmltext_prelim(&self, _txn: &mut Transaction, _key: &str) -> PyResult<PyObject> {
Err(PyTypeError::new_err("Cannot insert an XmlText into a map - insert it into an XmlFragment and insert that into the map"))
}

fn insert_doc(&self, txn: &mut Transaction, key: &str, doc: &Bound<'_, PyAny>) -> PyResult<()> {
let mut _t = txn.transaction();
let mut t = _t.as_mut().unwrap().as_mut();
Expand Down
36 changes: 35 additions & 1 deletion tests/test_xml.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from pycrdt import Doc, XmlElement, XmlFragment, XmlText
from pycrdt import Array, Doc, Map, XmlElement, XmlFragment, XmlText


def test_plain_text():
Expand Down Expand Up @@ -275,3 +275,37 @@ def callback(event):
assert str(events[0][0].target) == "H<bold>el</bold>lo world!"
assert events[0][0].delta[0] == {"retain": 1}
assert events[0][0].delta[1] == {"retain": 2, "attributes": {"bold": True}}


def test_xml_in_array():
doc = Doc()
array = doc.get("testmap", type=Array)
frag = XmlFragment()
array.append(frag)
frag.children.append("Test XML!")

assert len(array) == 1
assert str(array[0]) == "Test XML!"

with pytest.raises(TypeError):
array.append(XmlText())
with pytest.raises(TypeError):
array.append(XmlElement("a"))
assert len(array) == 1


def test_xml_in_map():
doc = Doc()
map = doc.get("testmap", type=Map)
frag = map["testxml"] = XmlFragment()
frag.children.append("Test XML!")

assert len(map) == 1
assert "testxml" in map
assert str(map["testxml"]) == "Test XML!"

with pytest.raises(TypeError):
map["testtext"] = XmlText()
with pytest.raises(TypeError):
map["testel"] = XmlElement("a")
assert len(map) == 1

0 comments on commit 01527f8

Please sign in to comment.