Loading src/nova/mvvm/pyqt_binding/binding.py +3 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ class PyQtCommunicator(QObject): elif isinstance(self.viewmodel_linked_object, object): rsetattr(self.viewmodel_linked_object, key or "", value) else: raise Exception("Cannot update", self.viewmodel_linked_object) raise ValueError("Cannot update", self.viewmodel_linked_object) if updated and self.callback_after_update: self.callback_after_update({"updated": updates, "errored": errors, "error": error}) Loading @@ -85,6 +85,8 @@ class PyQtCommunicator(QObject): # connect should be called from the View side to connect a # GUI element (via a function to change GUI element that is passed to the connect call) # and a linked_object (passed during bind creation from ViewModel side) if name in bindings_map: raise Exception(f"cannot connect to binding {name}: already connected") bindings_map[name] = self self.prefix = name self.signal.connect(callback) Loading src/nova/mvvm/trame_binding/binding.py +2 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,8 @@ class TrameCommunicator(Communicator): else: connector = str(connector) if connector else None if connector: if connector in bindings_map: raise ValueError(f"cannot connect to binding {connector}: already connected") bindings_map[connector] = self self.connection = StateConnection(self, connector) return self.connection.get_callback() Loading tests/test_pyqt_bindings.py +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import pytest from PyQt6.QtWidgets import QLabel, QLineEdit, QMainWindow, QVBoxLayout, QWidget from pytestqt.qtbot import QtBot from nova.mvvm import bindings_map from nova.mvvm.pydantic_utils import get_field_info from nova.mvvm.pyqt_binding import PyQtBinding from nova.mvvm.pyqt_binding.binding import PyQtCommunicator Loading Loading @@ -104,3 +105,4 @@ def test_binding_pyqt_to_model(qtbot: QtBot, input: str, expected_result: Dict[s else: assert "username" in after_update_results["updated"] assert test_object.username == expected_result["value"] bindings_map.clear() tests/test_trame_bindings.py +15 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import pytest_asyncio from trame.app import get_server from trame_server import Server from nova.mvvm import bindings_map from nova.mvvm._internal.utils import rgetattr, rsetdictvalue from nova.mvvm.trame_binding import TrameBinding Loading Loading @@ -114,6 +115,7 @@ async def test_binding_trame_to_model(server: Server, input: Dict[str, Any], exp else: assert input["field"] in after_update_results["updated"] assert rgetattr(test_object, input["field"]) == expected_result["value"] bindings_map.clear() @pytest.mark.asyncio Loading @@ -132,3 +134,16 @@ async def test_binding_model_to_trame(server: Server) -> None: test_object.username = "test" binding.update_in_view(test_object) assert server.state["test_object"]["username"] == "test" bindings_map.clear() @pytest.mark.asyncio async def test_double_binding(server: Server) -> None: # Creates trame binding for a Pydantic object twice, expect error test_object = User() binding = TrameBinding(server.state).new_bind(test_object) binding.connect("test_object") with pytest.raises(ValueError): binding.connect("test_object") bindings_map.clear() Loading
src/nova/mvvm/pyqt_binding/binding.py +3 −1 Original line number Diff line number Diff line Loading @@ -77,7 +77,7 @@ class PyQtCommunicator(QObject): elif isinstance(self.viewmodel_linked_object, object): rsetattr(self.viewmodel_linked_object, key or "", value) else: raise Exception("Cannot update", self.viewmodel_linked_object) raise ValueError("Cannot update", self.viewmodel_linked_object) if updated and self.callback_after_update: self.callback_after_update({"updated": updates, "errored": errors, "error": error}) Loading @@ -85,6 +85,8 @@ class PyQtCommunicator(QObject): # connect should be called from the View side to connect a # GUI element (via a function to change GUI element that is passed to the connect call) # and a linked_object (passed during bind creation from ViewModel side) if name in bindings_map: raise Exception(f"cannot connect to binding {name}: already connected") bindings_map[name] = self self.prefix = name self.signal.connect(callback) Loading
src/nova/mvvm/trame_binding/binding.py +2 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,8 @@ class TrameCommunicator(Communicator): else: connector = str(connector) if connector else None if connector: if connector in bindings_map: raise ValueError(f"cannot connect to binding {connector}: already connected") bindings_map[connector] = self self.connection = StateConnection(self, connector) return self.connection.get_callback() Loading
tests/test_pyqt_bindings.py +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ import pytest from PyQt6.QtWidgets import QLabel, QLineEdit, QMainWindow, QVBoxLayout, QWidget from pytestqt.qtbot import QtBot from nova.mvvm import bindings_map from nova.mvvm.pydantic_utils import get_field_info from nova.mvvm.pyqt_binding import PyQtBinding from nova.mvvm.pyqt_binding.binding import PyQtCommunicator Loading Loading @@ -104,3 +105,4 @@ def test_binding_pyqt_to_model(qtbot: QtBot, input: str, expected_result: Dict[s else: assert "username" in after_update_results["updated"] assert test_object.username == expected_result["value"] bindings_map.clear()
tests/test_trame_bindings.py +15 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ import pytest_asyncio from trame.app import get_server from trame_server import Server from nova.mvvm import bindings_map from nova.mvvm._internal.utils import rgetattr, rsetdictvalue from nova.mvvm.trame_binding import TrameBinding Loading Loading @@ -114,6 +115,7 @@ async def test_binding_trame_to_model(server: Server, input: Dict[str, Any], exp else: assert input["field"] in after_update_results["updated"] assert rgetattr(test_object, input["field"]) == expected_result["value"] bindings_map.clear() @pytest.mark.asyncio Loading @@ -132,3 +134,16 @@ async def test_binding_model_to_trame(server: Server) -> None: test_object.username = "test" binding.update_in_view(test_object) assert server.state["test_object"]["username"] == "test" bindings_map.clear() @pytest.mark.asyncio async def test_double_binding(server: Server) -> None: # Creates trame binding for a Pydantic object twice, expect error test_object = User() binding = TrameBinding(server.state).new_bind(test_object) binding.connect("test_object") with pytest.raises(ValueError): binding.connect("test_object") bindings_map.clear()