From 7ce1e97ae40427c059a12c402e03004aef8afc2f Mon Sep 17 00:00:00 2001 From: Ditlev Stjerne Date: Fri, 30 Jan 2026 23:17:36 +0100 Subject: [PATCH 1/3] typing --- src/uiwiz/shared.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/uiwiz/shared.py b/src/uiwiz/shared.py index 7f3e24b..6b669e2 100644 --- a/src/uiwiz/shared.py +++ b/src/uiwiz/shared.py @@ -9,7 +9,7 @@ @lru_cache(maxsize=None) -def hash_function_extended(func): +def hash_function_extended(func) -> str: """ This was an interesting problem. I needed to hash the function to be able to store the route in a dictionary. Nothing special @@ -26,11 +26,11 @@ def hash_function_extended(func): return hashlib.sha256(source.encode("utf-8")).hexdigest() -def register_resource(key: str, resource: Path): +def register_resource(key: str, resource: Path) -> None: resources[key] = resource -def register_path(key: str, func: Callable): +def register_path(key: str, func: Callable) -> None: page_map[hash_function_extended(func)] = key @@ -38,7 +38,7 @@ def fetch_route(func: Callable) -> Optional[str]: return page_map.get(hash_function_extended(func)) -def reset_resources(): +def reset_resources() -> None: resources.clear() page_map.clear() From 3b75f869582227076ba31d25ce766c1a857793ef Mon Sep 17 00:00:00 2001 From: Ditlev Stjerne Date: Fri, 30 Jan 2026 23:19:41 +0100 Subject: [PATCH 2/3] Added warning for server usage --- src/uiwiz/server/_server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uiwiz/server/_server.py b/src/uiwiz/server/_server.py index c47231d..8a509eb 100644 --- a/src/uiwiz/server/_server.py +++ b/src/uiwiz/server/_server.py @@ -425,6 +425,7 @@ async def run_asgi(self, app: ASGI3Application) -> None: class Server: def __init__(self, config: Config): + logger.warning("Development server. Do not use in production!") self.config = config self.server_state = None import_app_instance(config) From abcdeb9fafe68ce3e4e9a8b2aceace25580512ed Mon Sep 17 00:00:00 2001 From: Ditlev Stjerne Date: Fri, 30 Jan 2026 23:54:19 +0100 Subject: [PATCH 3/3] Improved custom server with the ability to work with lambda functions as endpoints created during the exeuction of the application and not during startup --- examples/run.py | 7 +++---- src/uiwiz/server/_server.py | 15 +++++++++++++++ src/uiwiz/shared.py | 7 +++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/examples/run.py b/examples/run.py index 35ba35f..368512d 100644 --- a/examples/run.py +++ b/examples/run.py @@ -1,11 +1,10 @@ from datetime import date, datetime, timezone -import uvicorn from fastapi import Request from pydantic import BaseModel -from examples.data import df -from uiwiz import UiwizApp, ui +from data import df +from uiwiz import UiwizApp, ui, server from uiwiz.element import Element as element app = UiwizApp() @@ -94,4 +93,4 @@ def replace(request: Request, input: DataInput): if __name__ == "__main__": - uvicorn.run("run:app", reload=True) + server.run("run:app") diff --git a/src/uiwiz/server/_server.py b/src/uiwiz/server/_server.py index 8a509eb..452ff62 100644 --- a/src/uiwiz/server/_server.py +++ b/src/uiwiz/server/_server.py @@ -9,6 +9,7 @@ from dataclasses import dataclass from collections import deque from contextlib import suppress +import copy from uvicorn._types import ( ASGI3Application, @@ -19,6 +20,7 @@ from uvicorn.protocols.http.flow_control import HIGH_WATER_LIMIT from uiwiz.app import UiwizApp +from uiwiz import shared import logging formatter = logging.Formatter( @@ -47,10 +49,23 @@ class Config: def import_app_instance(config: Config) -> None: start = perf_counter() if isinstance(config.app, str): + routes = [] + if config.app_instance is not None: + # As the user can register new endpoints with a lambda function and this can happen inside of an endpoint + # i.e not when the application is first loaded but during the exeuction of the endpoint. It is nesscary to + # save the endpoint data and transfer it to the newly created application + routes = copy.copy(config.app_instance.router.routes) + _page_map = copy.copy(shared.page_map) + _resources = copy.copy(shared.resources) + module_name, _, app = config.app.partition(":") module = importlib.import_module(module_name) module = importlib.reload(module) config.app_instance = getattr(module, app) + if routes: + config.app_instance.router.routes = routes + shared.page_map = _page_map + shared.resources = _resources else: config.app_instance = config.app end = perf_counter() diff --git a/src/uiwiz/shared.py b/src/uiwiz/shared.py index 6b669e2..b6e7d6e 100644 --- a/src/uiwiz/shared.py +++ b/src/uiwiz/shared.py @@ -7,9 +7,8 @@ resources: Dict[str, Path] = {} page_map: Dict[Callable, str] = {} - @lru_cache(maxsize=None) -def hash_function_extended(func) -> str: +def _hash_function_extended(func) -> str: """ This was an interesting problem. I needed to hash the function to be able to store the route in a dictionary. Nothing special @@ -31,11 +30,11 @@ def register_resource(key: str, resource: Path) -> None: def register_path(key: str, func: Callable) -> None: - page_map[hash_function_extended(func)] = key + page_map[_hash_function_extended(func)] = key def fetch_route(func: Callable) -> Optional[str]: - return page_map.get(hash_function_extended(func)) + return page_map.get(_hash_function_extended(func)) def reset_resources() -> None: