mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-21 00:40:01 +02:00
Merge pull request #98 from tiqi-group/refactor/passing_full_serialization_dict_to_frontend
Refactor: passing full serialization dict to frontend
This commit is contained in:
commit
e60880fd30
@ -1,10 +1,6 @@
|
||||
import { useCallback, useEffect, useReducer, useState } from 'react';
|
||||
import { Navbar, Form, Offcanvas, Container } from 'react-bootstrap';
|
||||
import { hostname, port, socket } from './socket';
|
||||
import {
|
||||
DataServiceComponent,
|
||||
DataServiceJSON
|
||||
} from './components/DataServiceComponent';
|
||||
import './App.css';
|
||||
import {
|
||||
Notifications,
|
||||
@ -14,6 +10,7 @@ import {
|
||||
import { ConnectionToast } from './components/ConnectionToast';
|
||||
import { SerializedValue, setNestedValueByPath, State } from './utils/stateUtils';
|
||||
import { WebSettingsContext, WebSetting } from './WebSettings';
|
||||
import { Attribute, GenericComponent } from './components/GenericComponent';
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_DATA'; data: State }
|
||||
@ -35,7 +32,10 @@ const reducer = (state: State, action: Action): State => {
|
||||
case 'SET_DATA':
|
||||
return action.data;
|
||||
case 'UPDATE_ATTRIBUTE': {
|
||||
return setNestedValueByPath(state, action.fullAccessPath, action.newValue);
|
||||
return {
|
||||
...state,
|
||||
value: setNestedValueByPath(state.value, action.fullAccessPath, action.newValue)
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error();
|
||||
@ -184,9 +184,10 @@ const App = () => {
|
||||
|
||||
<div className="App navbarOffset">
|
||||
<WebSettingsContext.Provider value={webSettings}>
|
||||
<DataServiceComponent
|
||||
name={''}
|
||||
props={state as DataServiceJSON}
|
||||
<GenericComponent
|
||||
name=""
|
||||
parentPath=""
|
||||
attribute={state as Attribute}
|
||||
isInstantUpdate={isInstantUpdate}
|
||||
addNotification={addNotification}
|
||||
/>
|
||||
|
@ -6,7 +6,12 @@ export interface SerializedValue {
|
||||
async?: boolean;
|
||||
parameters?: unknown;
|
||||
}
|
||||
export type State = Record<string, SerializedValue> | null;
|
||||
export type State = {
|
||||
type: string;
|
||||
value: Record<string, SerializedValue> | null;
|
||||
readonly: boolean;
|
||||
doc: string | null;
|
||||
};
|
||||
|
||||
export function setNestedValueByPath(
|
||||
serializationDict: Record<string, SerializedValue>,
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "pydase"
|
||||
version = "0.5.2"
|
||||
version = "0.6.0"
|
||||
description = "A flexible and robust Python library for creating, managing, and interacting with data services, with built-in support for web and RPC servers, and customizable features for diverse use cases."
|
||||
authors = ["Mose Mueller <mosmuell@ethz.ch>"]
|
||||
readme = "README.md"
|
||||
|
@ -196,7 +196,7 @@ class DataService(rpyc.Service, AbstractDataService):
|
||||
)
|
||||
|
||||
# Traverse the serialized representation and set the attributes of the class
|
||||
serialized_class = self.serialize()
|
||||
serialized_class = self.serialize()["value"]
|
||||
for path in generate_serialized_data_paths(json_dict):
|
||||
nested_json_dict = get_nested_dict_by_path(json_dict, path)
|
||||
value = nested_json_dict["value"]
|
||||
@ -248,7 +248,7 @@ class DataService(rpyc.Service, AbstractDataService):
|
||||
Returns:
|
||||
dict: The serialized instance.
|
||||
"""
|
||||
return Serializer.serialize_object(self)["value"]
|
||||
return Serializer.serialize_object(self)
|
||||
|
||||
def update_DataService_attribute( # noqa: N802
|
||||
self,
|
||||
|
@ -30,10 +30,10 @@ class DataServiceCache:
|
||||
self._cache = self.service.serialize()
|
||||
|
||||
def update_cache(self, full_access_path: str, value: Any) -> None:
|
||||
set_nested_value_by_path(self._cache, full_access_path, value)
|
||||
set_nested_value_by_path(self._cache["value"], full_access_path, value)
|
||||
|
||||
def get_value_dict_from_cache(self, full_access_path: str) -> dict[str, Any]:
|
||||
try:
|
||||
return get_nested_dict_by_path(self._cache, full_access_path)
|
||||
return get_nested_dict_by_path(self._cache["value"], full_access_path)
|
||||
except (SerializationPathError, SerializationValueError, KeyError):
|
||||
return {}
|
||||
|
@ -126,7 +126,7 @@ class StateManager:
|
||||
|
||||
if self.filename is not None:
|
||||
with open(self.filename, "w") as f:
|
||||
json.dump(self.cache, f, indent=4)
|
||||
json.dump(self.cache["value"], f, indent=4)
|
||||
else:
|
||||
logger.info(
|
||||
"State manager was not initialised with a filename. Skipping "
|
||||
@ -191,7 +191,7 @@ class StateManager:
|
||||
value: The new value to set for the attribute.
|
||||
"""
|
||||
|
||||
current_value_dict = get_nested_dict_by_path(self.cache, path)
|
||||
current_value_dict = get_nested_dict_by_path(self.cache["value"], path)
|
||||
|
||||
# This will also filter out methods as they are 'read-only'
|
||||
if current_value_dict["readonly"]:
|
||||
@ -234,7 +234,7 @@ class StateManager:
|
||||
# Update path to reflect the attribute without list indices
|
||||
path = ".".join([*parent_path_list, attr_name])
|
||||
|
||||
attr_cache_type = get_nested_dict_by_path(self.cache, path)["type"]
|
||||
attr_cache_type = get_nested_dict_by_path(self.cache["value"], path)["type"]
|
||||
|
||||
# Traverse the object according to the path parts
|
||||
target_obj = get_object_attr_from_path_list(self.service, parent_path_list)
|
||||
@ -273,7 +273,7 @@ class StateManager:
|
||||
return has_decorator
|
||||
|
||||
cached_serialization_dict = get_nested_dict_by_path(
|
||||
self.cache, full_access_path
|
||||
self.cache["value"], full_access_path
|
||||
)
|
||||
|
||||
if cached_serialization_dict["value"] == "method":
|
||||
|
@ -1,13 +1,13 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.2d8458eb.css",
|
||||
"main.js": "/static/js/main.dba067e7.js",
|
||||
"main.js": "/static/js/main.1b1d7066.js",
|
||||
"index.html": "/index.html",
|
||||
"main.2d8458eb.css.map": "/static/css/main.2d8458eb.css.map",
|
||||
"main.dba067e7.js.map": "/static/js/main.dba067e7.js.map"
|
||||
"main.1b1d7066.js.map": "/static/js/main.1b1d7066.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.2d8458eb.css",
|
||||
"static/js/main.dba067e7.js"
|
||||
"static/js/main.1b1d7066.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.dba067e7.js"></script><link href="/static/css/main.2d8458eb.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.1b1d7066.js"></script><link href="/static/css/main.2d8458eb.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
1
src/pydase/frontend/static/js/main.1b1d7066.js.map
Normal file
1
src/pydase/frontend/static/js/main.1b1d7066.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -126,7 +126,7 @@ class WebServer:
|
||||
@property
|
||||
def web_settings(self) -> dict[str, dict[str, Any]]:
|
||||
current_web_settings = self._get_web_settings_from_file()
|
||||
for path in generate_serialized_data_paths(self.state_manager.cache):
|
||||
for path in generate_serialized_data_paths(self.state_manager.cache["value"]):
|
||||
if path in current_web_settings:
|
||||
continue
|
||||
|
||||
|
@ -91,7 +91,7 @@ class Service(pydase.DataService):
|
||||
self._property_attr = value
|
||||
|
||||
|
||||
CURRENT_STATE = Service().serialize()
|
||||
CURRENT_STATE = Service().serialize()["value"]
|
||||
|
||||
LOAD_STATE = {
|
||||
"list_attr": {
|
||||
|
@ -323,7 +323,7 @@ def test_derived_data_service_serialization() -> None:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def setup_dict():
|
||||
def setup_dict() -> dict[str, Any]:
|
||||
class MySubclass(pydase.DataService):
|
||||
attr3 = 1.0
|
||||
list_attr = [1.0, 1]
|
||||
@ -333,30 +333,32 @@ def setup_dict():
|
||||
attr2 = MySubclass()
|
||||
attr_list = [0, 1, MySubclass()]
|
||||
|
||||
return ServiceClass().serialize()
|
||||
return ServiceClass().serialize()["value"]
|
||||
|
||||
|
||||
def test_update_attribute(setup_dict):
|
||||
def test_update_attribute(setup_dict) -> None:
|
||||
set_nested_value_by_path(setup_dict, "attr1", 15)
|
||||
assert setup_dict["attr1"]["value"] == 15
|
||||
|
||||
|
||||
def test_update_nested_attribute(setup_dict):
|
||||
def test_update_nested_attribute(setup_dict) -> None:
|
||||
set_nested_value_by_path(setup_dict, "attr2.attr3", 25.0)
|
||||
assert setup_dict["attr2"]["value"]["attr3"]["value"] == 25.0
|
||||
|
||||
|
||||
def test_update_list_entry(setup_dict):
|
||||
def test_update_list_entry(setup_dict) -> None:
|
||||
set_nested_value_by_path(setup_dict, "attr_list[1]", 20)
|
||||
assert setup_dict["attr_list"]["value"][1]["value"] == 20
|
||||
|
||||
|
||||
def test_update_list_append(setup_dict):
|
||||
def test_update_list_append(setup_dict) -> None:
|
||||
set_nested_value_by_path(setup_dict, "attr_list[3]", 20)
|
||||
assert setup_dict["attr_list"]["value"][3]["value"] == 20
|
||||
|
||||
|
||||
def test_update_invalid_list_index(setup_dict, caplog: pytest.LogCaptureFixture):
|
||||
def test_update_invalid_list_index(
|
||||
setup_dict, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
set_nested_value_by_path(setup_dict, "attr_list[10]", 30)
|
||||
assert (
|
||||
"Error occured trying to change 'attr_list[10]': list index "
|
||||
|
Loading…
x
Reference in New Issue
Block a user