nova-mvvm 0.13.2__py3-none-any.whl → 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -83,6 +83,6 @@ def get_nested_pydantic_field(model: BaseModel, field_path: str) -> FieldInfo:
83
83
  if issubclass(type(getattr(current_model, field)), BaseModel):
84
84
  current_model = getattr(current_model, field)
85
85
  else:
86
- return current_model.model_fields[field]
86
+ return current_model.__class__.model_fields[field]
87
87
 
88
88
  raise Exception(f"Cannot find field {field_path}")
@@ -7,7 +7,7 @@ from pydantic import BaseModel, ValidationError
7
7
  from typing_extensions import override
8
8
 
9
9
  from .._internal.pydantic_utils import get_errored_fields_from_validation_error, get_updated_fields
10
- from .._internal.utils import check_binding, rsetattr
10
+ from .._internal.utils import check_binding, check_model_type, rsetattr
11
11
  from ..bindings_map import bindings_map
12
12
  from ..interface import Communicator, ConnectCallbackType
13
13
 
@@ -84,6 +84,8 @@ class PyQtCommunicator(Communicator):
84
84
  return None
85
85
 
86
86
  @override
87
- def update_in_view(self, value: Any) -> Any:
87
+ def update_in_view(self, value: Any) -> None:
88
88
  """Update a View (GUI) when called by a ViewModel."""
89
+ if issubclass(type(value), BaseModel):
90
+ check_model_type(self.viewmodel_linked_object, value)
89
91
  return self.pyqtobject.signal.emit(value)
@@ -1,6 +1,7 @@
1
1
  """Internal common functions tp be used within the package."""
2
2
 
3
3
  import re
4
+ from types import NoneType
4
5
  from typing import Any, Dict
5
6
 
6
7
  from nova.mvvm import bindings_map
@@ -98,3 +99,10 @@ def check_binding(linked_object: LinkedObjectType, name: str) -> None:
98
99
  for communicator in bindings_map.values():
99
100
  if communicator.viewmodel_linked_object and communicator.viewmodel_linked_object is linked_object:
100
101
  raise ValueError(f"cannot connect to binding {name}: object already connected")
102
+
103
+
104
+ def check_model_type(old_value: Any, new_value: Any) -> None:
105
+ old_type = type(old_value)
106
+ new_type = type(new_value)
107
+ if old_type is not NoneType and old_type is not new_type:
108
+ raise TypeError(f"update_in_view expected a value of type '{old_type}' but received '{new_type}'.")
@@ -9,7 +9,7 @@ from typing_extensions import override
9
9
 
10
10
  from .. import bindings_map
11
11
  from .._internal.pydantic_utils import get_errored_fields_from_validation_error, get_updated_fields
12
- from .._internal.utils import check_binding, rgetattr, rsetattr
12
+ from .._internal.utils import check_binding, check_model_type, rgetattr, rsetattr
13
13
  from ..interface import BindingInterface, ConnectCallbackType, Worker
14
14
 
15
15
 
@@ -114,6 +114,8 @@ class Communicator:
114
114
 
115
115
  # Update the view based on the provided value
116
116
  def update_in_view(self, value: Any) -> None:
117
+ if issubclass(type(value), BaseModel):
118
+ check_model_type(self.viewmodel_linked_object, value)
117
119
  if is_callable(self.connector):
118
120
  cast(Callable, self.connector)(value)
119
121
  elif self.viewmodel_linked_object:
@@ -10,7 +10,14 @@ from trame_server.state import State
10
10
  from typing_extensions import override
11
11
 
12
12
  from .._internal.pydantic_utils import get_errored_fields_from_validation_error, get_updated_fields
13
- from .._internal.utils import check_binding, normalize_field_name, rget_list_of_fields, rgetattr, rsetattr
13
+ from .._internal.utils import (
14
+ check_binding,
15
+ check_model_type,
16
+ normalize_field_name,
17
+ rget_list_of_fields,
18
+ rgetattr,
19
+ rsetattr,
20
+ )
14
21
  from ..bindings_map import bindings_map
15
22
  from ..interface import (
16
23
  BindingInterface,
@@ -132,6 +139,8 @@ class CallBackConnection:
132
139
  self.viewmodel_callback_after_update({"updated": updates, "errored": errors, "error": None})
133
140
 
134
141
  def update_in_view(self, value: Any) -> None:
142
+ if issubclass(type(value), BaseModel):
143
+ check_model_type(self.viewmodel_linked_object, value)
135
144
  self.callback(value)
136
145
 
137
146
  def get_callback(self) -> ConnectCallbackType:
@@ -244,6 +253,7 @@ class StateConnection:
244
253
 
245
254
  def update_in_view(self, value: Any) -> None:
246
255
  if issubclass(type(value), BaseModel):
256
+ check_model_type(self.viewmodel_linked_object, value)
247
257
  value = value.model_dump()
248
258
  if self.linked_object_attributes:
249
259
  for attribute_name in self.linked_object_attributes:
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nova-mvvm
3
- Version: 0.13.2
3
+ Version: 0.14.0
4
4
  Summary: A Python Package for Model-View-ViewModel pattern
5
- Author-email: "Yakubov, Sergey" <yakubovs@ornl.gov>
5
+ Author-email: Sergey Yakubov <yakubovs@ornl.gov>, John Duggan <dugganjw@ornl.gov>, Greg Watson <watsongr@ornl.gov>
6
6
  License-Expression: MIT
7
7
  License-File: LICENSE
8
8
  Keywords: MVVM,python
@@ -3,11 +3,11 @@ nova/mvvm/__init__.py,sha256=fo1bT27jjUYzVoFJXuwokXcyFtOYj8eQ_BHkPgtI4Rg,149
3
3
  nova/mvvm/bindings_map.py,sha256=SIVNPGHxDf91P9UxcPmuAHx1GNxZk66JUc-fYPcp-kc,417
4
4
  nova/mvvm/interface.py,sha256=l4l339BiB46s6KX-2RH1Q3Hxc8pKYdCvCOkhse4zOkw,5812
5
5
  nova/mvvm/pydantic_utils.py,sha256=kQ17-Thp_4FMQca6nJ_UNWbctssqHGY3FtZolUIZGQ0,3191
6
- nova/mvvm/_internal/pydantic_utils.py,sha256=kHZLR5Noc581kz-OYRO6EW-jyjB443BF_wVoXY5jBRA,2937
7
- nova/mvvm/_internal/pyqt_communicator.py,sha256=kcEaXCjJZXymNBM-8x5Yk22SUQFrQ7c5yV1-GDYf3DM,3797
8
- nova/mvvm/_internal/utils.py,sha256=2YDUvAmJjjb89ROE4n4GWD4Qqz-rRqVP4ICDGnIcFNc,3303
6
+ nova/mvvm/_internal/pydantic_utils.py,sha256=anYYyB1Bkg8GgWB3Jn-6iRit0PYR-_2w3paKsD9z4sY,2947
7
+ nova/mvvm/_internal/pyqt_communicator.py,sha256=G_Srttxn7EEwz9EageFxnOgg_P-gfPPhNpoR55btHd0,3929
8
+ nova/mvvm/_internal/utils.py,sha256=LpZ3LALcB9BzG1yIh0Qt0kBXGdctacDMVmSm8H8Py1c,3626
9
9
  nova/mvvm/panel_binding/__init__.py,sha256=HHDlUyP-LuRePcHS1s8tq3niuG3f3n8gdSRb7Rwtc4o,100
10
- nova/mvvm/panel_binding/binding.py,sha256=Fz_t2XHoU8hfbf-nDDypk4V_KHH7T7OqYFCl65k4XEE,6352
10
+ nova/mvvm/panel_binding/binding.py,sha256=rLkxnqjLpZvvRHJVx8PLfJpLSEg3Q0FSRPov81o8e6Y,6483
11
11
  nova/mvvm/pyqt5_binding/__init__.py,sha256=JbKOFJNIObJReotRHlN5-vi7oSMyc_v8K_uHjeJLcHg,62
12
12
  nova/mvvm/pyqt5_binding/binding.py,sha256=Nki03KgafysfJFQ86evYvL8lprbrYNajFNgfihk7KA4,1462
13
13
  nova/mvvm/pyqt5_binding/pyqt5_worker.py,sha256=bf0Yj2cnX3xljFHQmWy6B9bCildhNSVEDXSqahprCXU,2133
@@ -15,9 +15,9 @@ nova/mvvm/pyqt6_binding/__init__.py,sha256=plms0W4kJjFpZReGOC7lE3SYX1ceGTLbdAJ1G
15
15
  nova/mvvm/pyqt6_binding/binding.py,sha256=uZNHx23Pf9DwGf3qKfQdmjOhmaXcppNd8pjkh363WP4,1365
16
16
  nova/mvvm/pyqt6_binding/pyqt6_worker.py,sha256=y8g_mfPC1xIcpyKq7ZZqxrn9Txp5gPJrsBjAwS5FHhY,2133
17
17
  nova/mvvm/trame_binding/__init__.py,sha256=uTdEW9VxtVubSbTLpoD3pC8a-KMgbKkZFlRbucvuQSE,62
18
- nova/mvvm/trame_binding/binding.py,sha256=H5iTOY5FwN1UZnxPXiYmOt36hv88e_4XzyYF1NK6KH4,12255
18
+ nova/mvvm/trame_binding/binding.py,sha256=m3pcadwhDEmcvEQ24BvU65vpUFjX3QoZQlQmeVcPwmg,12481
19
19
  nova/mvvm/trame_binding/trame_worker.py,sha256=JmrneFU11Hi8TtY558R3yIWW8UGiUeVNO7HvM1uWTVs,3778
20
- nova_mvvm-0.13.2.dist-info/METADATA,sha256=A5hCBiCeMxcBRB60XLsiIXt5UCjJMstF7C2eKdyVkuk,1027
21
- nova_mvvm-0.13.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
22
- nova_mvvm-0.13.2.dist-info/licenses/LICENSE,sha256=MOqZ8tPMKy8ZETJ2-HEvFTZ7dYNlg3gXmBkV-Y9i8bw,1061
23
- nova_mvvm-0.13.2.dist-info/RECORD,,
20
+ nova_mvvm-0.14.0.dist-info/METADATA,sha256=xspULchDL9PyMWCDu2oa2uzpdIhDEQ6yZgIp7ItuV5I,1090
21
+ nova_mvvm-0.14.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
22
+ nova_mvvm-0.14.0.dist-info/licenses/LICENSE,sha256=MOqZ8tPMKy8ZETJ2-HEvFTZ7dYNlg3gXmBkV-Y9i8bw,1061
23
+ nova_mvvm-0.14.0.dist-info/RECORD,,