From e14522cf5082a2f1bd44a23bd5f966e2a1c911ec Mon Sep 17 00:00:00 2001 From: waidhoferj Date: Sun, 3 Jul 2022 17:57:54 -0700 Subject: [PATCH] More Transparent Events Fixes #55 - All events have a string representation - Removed extraneous `delta` prop in `YMapEvent` - Fixed `YMapEvent` typo that said YText - Improved `YMapEvent` types and documentation. --- src/lib.rs | 8 ++++++++ src/y_array.rs | 7 +++++++ src/y_map.rs | 7 +++++++ src/y_text.rs | 14 +++++--------- src/y_xml.rs | 18 ++++++++++++++++++ tests/test_y_array.py | 4 ++-- tests/test_y_map.py | 6 ++++-- tests/test_y_text.py | 4 ++-- y_py.pyi | 33 ++++++++++++++++----------------- 9 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0a7a3bd..75a3fed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,20 @@ use crate::y_doc::*; /// Python bindings for Y.rs #[pymodule] pub fn y_py(_py: Python, m: &PyModule) -> PyResult<()> { + // Data Types m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; + // Events + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + // Functions m.add_wrapped(wrap_pyfunction!(encode_state_vector))?; m.add_wrapped(wrap_pyfunction!(encode_state_as_update))?; m.add_wrapped(wrap_pyfunction!(apply_update))?; diff --git a/src/y_array.rs b/src/y_array.rs index 40dc084..5344276 100644 --- a/src/y_array.rs +++ b/src/y_array.rs @@ -475,6 +475,13 @@ impl YArrayEvent { } } + fn __repr__(&mut self) -> String { + let target = self.target(); + let delta = self.delta(); + let path = self.path(); + format!("YArrayEvent(target={target}, delta={delta}, path={path})") + } + /// Returns an array of keys and indexes creating a path from root type down to current instance /// of shared type (accessible via `target` getter). pub fn path(&self) -> PyObject { diff --git a/src/y_map.rs b/src/y_map.rs index 893ea1a..292b982 100644 --- a/src/y_map.rs +++ b/src/y_map.rs @@ -362,6 +362,13 @@ impl YMapEvent { } } + pub fn __repr__(&mut self) -> String { + let target = self.target(); + let keys = self.keys(); + let path = self.path(); + format!("YMapEvent(target={target}, keys={keys}, path={path})") + } + /// Returns an array of keys and indexes creating a path from root type down to current instance /// of shared type (accessible via `target` getter). pub fn path(&self) -> PyObject { diff --git a/src/y_text.rs b/src/y_text.rs index d9debf4..42839ff 100644 --- a/src/y_text.rs +++ b/src/y_text.rs @@ -333,14 +333,10 @@ impl YTextEvent { } } - fn __str__(&self) -> String { - format!( - "YTextEvent(target={:?}, delta={:?})", - self.target, self.delta - ) - } - - fn __repr__(&self) -> String { - self.__str__() + fn __repr__(&mut self) -> String { + let target = self.target(); + let delta = self.delta(); + let path = self.path(); + format!("YTextEvent(target={target}, delta={delta}, path={path})") } } diff --git a/src/y_xml.rs b/src/y_xml.rs index 1651358..2481c15 100644 --- a/src/y_xml.rs +++ b/src/y_xml.rs @@ -458,6 +458,15 @@ impl YXmlEvent { } } + fn __repr__(&mut self) -> String { + let target = self.target(); + let delta = self.delta(); + let keys = self.keys(); + let path = self.path(); + + format!("YXmlEvent(target={target}, delta={delta}, keys={keys}, path={path})") + } + /// Returns an array of keys and indexes creating a path from root type down to current instance /// of shared type (accessible via `target` getter). pub fn path(&self) -> PyObject { @@ -557,6 +566,15 @@ impl YXmlTextEvent { } } + fn __repr__(&mut self) -> String { + let target = self.target(); + let delta = self.delta(); + let keys = self.keys(); + let path = self.path(); + + format!("YXmlEvent(target={target}, delta={delta}, keys={keys}, path={path})") + } + /// Returns a current shared type instance, that current event changes refer to. pub fn path(&self) -> PyObject { Python::with_gil(|py| self.inner().path().into_py(py)) diff --git a/tests/test_y_array.py b/tests/test_y_array.py index 47c00e7..6eb97bc 100644 --- a/tests/test_y_array.py +++ b/tests/test_y_array.py @@ -1,7 +1,7 @@ from test_helper import exchange_updates import pytest -from y_py import YDoc, YArray +from y_py import YDoc, YArray, YArrayEvent def test_inserts(): @@ -168,7 +168,7 @@ def test_observer(): target = None delta = None - def callback(e): + def callback(e: YArrayEvent): nonlocal target nonlocal delta target = e.target diff --git a/tests/test_y_map.py b/tests/test_y_map.py index 0ea2b63..0c145d8 100644 --- a/tests/test_y_map.py +++ b/tests/test_y_map.py @@ -1,6 +1,6 @@ import pytest import y_py as Y -from y_py import YMap +from y_py import YMap, YMapEvent def test_get(): @@ -137,7 +137,7 @@ def test_observer(): def get_value(x): return x.to_json() - def callback(e): + def callback(e: YMapEvent): nonlocal target nonlocal entries target = e.target @@ -196,12 +196,14 @@ def test_deep_observe(): def callback(e: list): nonlocal events events = e + assert len(e[0].path()) == 1 sub = container.observe_deep(callback) with doc.begin_transaction() as txn: container["inner"].set(txn, "addition", 1) events = None + container.unobserve(sub) with doc.begin_transaction() as txn: container["inner"].set(txn, "don't show up", 1) diff --git a/tests/test_y_text.py b/tests/test_y_text.py index 47e3c45..47b3f96 100644 --- a/tests/test_y_text.py +++ b/tests/test_y_text.py @@ -1,6 +1,6 @@ from test_helper import exchange_updates import y_py as Y -from y_py import YText +from y_py import YText, YTextEvent def test_to_string(): @@ -69,7 +69,7 @@ def test_observer(): target = None delta = None - def callback(e): + def callback(e: YTextEvent): nonlocal target nonlocal delta target = e.target diff --git a/y_py.pyi b/y_py.pyi index a956c37..fdc12fc 100644 --- a/y_py.pyi +++ b/y_py.pyi @@ -45,9 +45,9 @@ class YDoc: client_id: int def __init__( self, - client_id: Optional[int]=None, - offset_kind: str="utf8", - skip_gc:bool=False, + client_id: Optional[int] = None, + offset_kind: str = "utf8", + skip_gc: bool = False, ): """ Creates a new Ypy document. If `client_id` parameter was passed it will be used as this @@ -145,7 +145,6 @@ EncodedStateVector = bytes EncodedDeleteSet = bytes YDocUpdate = bytes - class AfterTransactionEvent: """ Holds transaction update information from a commit after state vectors have been compressed. @@ -178,9 +177,8 @@ def encode_state_vector(doc: YDoc) -> EncodedStateVector: """ - def encode_state_as_update( - doc: YDoc, vector: Optional[Union[EncodedStateVector, List[int]]]=None + doc: YDoc, vector: Optional[Union[EncodedStateVector, List[int]]] = None ) -> YDocUpdate: """ Encodes all updates that have happened since a given version `vector` into a compact delta @@ -307,7 +305,7 @@ class YTransaction: del remote_txn """ - def diff_v1(self, vector: Optional[EncodedStateVector]=None) -> YDocUpdate: + def diff_v1(self, vector: Optional[EncodedStateVector] = None) -> YDocUpdate: """ Encodes all updates that have happened since a given version `vector` into a compact delta representation using lib0 v1 encoding. If `vector` parameter has not been provided, generated @@ -382,7 +380,7 @@ class YText: prelim: bool """True if this element has not been integrated into a YDoc.""" - def __init__(self, init:str=""): + def __init__(self, init: str = ""): """ Creates a new preliminary instance of a `YText` shared data type, with its state initialized to provided parameter. @@ -416,7 +414,7 @@ class YText: txn: YTransaction, index: int, chunk: str, - attributes: Dict[str, Any]={}, + attributes: Dict[str, Any] = {}, ): """ Inserts a string of text into the `YText` instance starting at a given `index`. @@ -428,7 +426,7 @@ class YText: txn: YTransaction, index: int, embed: Any, - attributes: Dict[str, Any]={}, + attributes: Dict[str, Any] = {}, ): """ Inserts embedded content into the YText at the provided index. Attributes are user-defined metadata associated with the embedded content. @@ -515,7 +513,7 @@ class YArray: prelim: bool """True if this element has not been integrated into a YDoc.""" - def __init__(init: Optional[Iterable[Any]]=None): + def __init__(init: Optional[Iterable[Any]] = None): """ Creates a new preliminary instance of a `YArray` shared data type, with its state initialized to provided parameter. @@ -641,14 +639,17 @@ ArrayDelta = Union[ArrayChangeInsert, ArrayChangeDelete, ArrayChangeRetain] class ArrayChangeInsert(TypedDict): """Update message that elements were inserted in a YArray.""" + insert: List[Any] class ArrayChangeDelete: """Update message that elements were deleted in a YArray.""" + delete: int class ArrayChangeRetain: """Update message that elements were left unmodified in a YArray.""" + retain: int class YMap: @@ -697,7 +698,7 @@ class YMap: txn: A transaction to perform the insertion updates. items: An iterable object that produces key value tuples to insert into the YMap """ - def pop(self, txn: YTransaction, key: str, fallback: Optional[Any]=None) -> Any: + def pop(self, txn: YTransaction, key: str, fallback: Optional[Any] = None) -> Any: """ Removes an entry identified by a given `key` from this instance of `YMap`, if such exists. Throws a KeyError if the key does not exist and fallback value is not provided. @@ -779,22 +780,20 @@ class YMap: class YMapEvent: """ Communicates updates that occurred during a transaction for an instance of `YMap`. - The `target` references the `YText` element that receives the update. + The `target` references the `YMap` element that receives the update. The `delta` is a list of updates applied by the transaction. The `keys` are a list of changed values for a specific key. """ target: YMap """The element modified during this event.""" - delta: List[Dict] - """The changes caused by this event.""" - keys: List[YMapEventKeyChange] + keys: Dict[str, YMapEventKeyChange] """A list of modifications to the YMap by key. Includes the type of modification along with the before and after state.""" def path(self) -> List[Union[int, str]]: """ Returns: - Array of keys and indexes creating a path from root type down to current instance of shared type (accessible via `target` getter). + Path to this element from the root if this YMap is nested inside another data structure. """ class YMapEventKeyChange(TypedDict):