mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-06-06 13:30:41 +02:00
adds function to initialise web settings (also creating settings if requested), creates web-settings fastapi endpoint
This commit is contained in:
parent
2f5c415cd5
commit
97c026afe0
@ -21,6 +21,47 @@ from pydase.version import __version__
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_serialized_data_paths(
|
||||||
|
data: dict[str, Any], parent_path: str = ""
|
||||||
|
) -> list[str]:
|
||||||
|
"""
|
||||||
|
Generate a list of access paths for all attributes in a dictionary representing
|
||||||
|
data serialized with `pydase.utils.serializer.Serializer`, excluding those that are
|
||||||
|
methods.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: The dictionary representing serialized data, typically produced by
|
||||||
|
`pydase.utils.serializer.Serializer`.
|
||||||
|
parent_path: The base path to prepend to the keys in the `data` dictionary to
|
||||||
|
form the access paths. Defaults to an empty string.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of strings where each string is a dot-notation access path to an
|
||||||
|
attribute in the serialized data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
paths: list[str] = []
|
||||||
|
for key, value in data.items():
|
||||||
|
if value["type"] == "method":
|
||||||
|
# ignoring methods
|
||||||
|
continue
|
||||||
|
new_path = f"{parent_path}.{key}" if parent_path else key
|
||||||
|
if isinstance(value["value"], dict) and value["type"] not in ("Quantity",):
|
||||||
|
paths.append(new_path)
|
||||||
|
paths.extend(generate_serialized_data_paths(value["value"], new_path))
|
||||||
|
elif isinstance(value["value"], list):
|
||||||
|
for index, item in enumerate(value["value"]):
|
||||||
|
indexed_key_path = f"{new_path}[{index}]"
|
||||||
|
if isinstance(item["value"], dict):
|
||||||
|
paths.extend(
|
||||||
|
generate_serialized_data_paths(item["value"], indexed_key_path)
|
||||||
|
)
|
||||||
|
paths.append(indexed_key_path)
|
||||||
|
else:
|
||||||
|
paths.append(new_path)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
|
||||||
class WebServer:
|
class WebServer:
|
||||||
"""
|
"""
|
||||||
Represents a web server that adheres to the AdditionalServerProtocol, designed to
|
Represents a web server that adheres to the AdditionalServerProtocol, designed to
|
||||||
@ -88,6 +129,7 @@ class WebServer:
|
|||||||
else WebServerConfig().generate_new_web_settings
|
else WebServerConfig().generate_new_web_settings
|
||||||
)
|
)
|
||||||
self._loop: asyncio.AbstractEventLoop
|
self._loop: asyncio.AbstractEventLoop
|
||||||
|
self._initialise_configuration()
|
||||||
|
|
||||||
async def serve(self) -> None:
|
async def serve(self) -> None:
|
||||||
self._loop = asyncio.get_running_loop()
|
self._loop = asyncio.get_running_loop()
|
||||||
@ -101,11 +143,42 @@ class WebServer:
|
|||||||
self.web_server.install_signal_handlers = lambda: None # type: ignore[method-assign]
|
self.web_server.install_signal_handlers = lambda: None # type: ignore[method-assign]
|
||||||
await self.web_server.serve()
|
await self.web_server.serve()
|
||||||
|
|
||||||
|
def _initialise_configuration(self) -> None:
|
||||||
|
logger.debug("Initialising web server configuration...")
|
||||||
|
|
||||||
|
self.web_settings = {}
|
||||||
|
file_path = self._service_config_dir / "web_settings.json"
|
||||||
|
|
||||||
|
if self._generate_new_web_settings:
|
||||||
|
# File does not exist, create it with default content
|
||||||
|
logger.debug("Generating web settings file...")
|
||||||
|
file_path.parent.mkdir(
|
||||||
|
parents=True, exist_ok=True
|
||||||
|
) # Ensure directory exists
|
||||||
|
file_path.write_text(
|
||||||
|
json.dumps(self._generated_web_settings_dict(), indent=4)
|
||||||
|
)
|
||||||
|
|
||||||
|
# File exists, read and return its content
|
||||||
|
if file_path.exists():
|
||||||
|
logger.debug(
|
||||||
|
"Reading configuration from file '%s' ...", file_path.absolute()
|
||||||
|
)
|
||||||
|
|
||||||
|
with file_path.open("r", encoding="utf-8") as file:
|
||||||
|
self.web_settings = json.load(file)
|
||||||
|
|
||||||
|
def _generated_web_settings_dict(self) -> dict[str, dict[str, Any]]:
|
||||||
|
return {
|
||||||
|
path: {"display_name": path.split(".")[-1]}
|
||||||
|
for path in generate_serialized_data_paths(self.state_manager.cache)
|
||||||
|
}
|
||||||
|
|
||||||
def _setup_socketio(self) -> None:
|
def _setup_socketio(self) -> None:
|
||||||
self._sio = setup_sio_server(self.observer, self.enable_cors, self._loop)
|
self._sio = setup_sio_server(self.observer, self.enable_cors, self._loop)
|
||||||
self.__sio_app = socketio.ASGIApp(self._sio)
|
self.__sio_app = socketio.ASGIApp(self._sio)
|
||||||
|
|
||||||
def _setup_fastapi_app(self) -> None:
|
def _setup_fastapi_app(self) -> None: # noqa: C901
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
if self.enable_cors:
|
if self.enable_cors:
|
||||||
@ -130,6 +203,10 @@ class WebServer:
|
|||||||
def service_properties() -> dict[str, Any]:
|
def service_properties() -> dict[str, Any]:
|
||||||
return self.state_manager.cache
|
return self.state_manager.cache
|
||||||
|
|
||||||
|
@app.get("/web-settings")
|
||||||
|
def web_settings() -> dict[str, Any]:
|
||||||
|
return self.web_settings
|
||||||
|
|
||||||
# exposing custom.css file provided by user
|
# exposing custom.css file provided by user
|
||||||
if self.css is not None:
|
if self.css is not None:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user