diff --git a/src/myfasthtml/controls/InstancesDebugger.py b/src/myfasthtml/controls/InstancesDebugger.py index c3d0057..bbc14fd 100644 --- a/src/myfasthtml/controls/InstancesDebugger.py +++ b/src/myfasthtml/controls/InstancesDebugger.py @@ -4,7 +4,7 @@ from fasthtml.components import Div from myfasthtml.controls.HierarchicalCanvasGraph import HierarchicalCanvasGraph, HierarchicalCanvasGraphConf from myfasthtml.controls.Panel import Panel -from myfasthtml.controls.Properties import Properties +from myfasthtml.controls.Properties import Properties, PropertiesConf from myfasthtml.core.commands import Command from myfasthtml.core.instances import SingleInstance, UniqueInstance, MultipleInstance, InstancesManager @@ -73,10 +73,11 @@ class InstancesDebugger(SingleInstance): "Commands": {"*": "commands"}, } - return self._panel.set_right(Properties(self, - InstancesManager.get(session, instance_id), - properties_def, - _id="-properties")) + return self._panel.set_right(Properties( + self, + conf=PropertiesConf(obj=InstancesManager.get(session, instance_id), groups=properties_def), + _id="-properties", + )) def _get_instance_kind(self, instance) -> str: """Determine the instance kind for visualization. diff --git a/src/myfasthtml/controls/Panel.py b/src/myfasthtml/controls/Panel.py index 8223f1b..aa959ee 100644 --- a/src/myfasthtml/controls/Panel.py +++ b/src/myfasthtml/controls/Panel.py @@ -104,7 +104,7 @@ class Panel(MultipleInstance): the panel with appropriate HTML elements and JavaScript for interactivity. """ - def __init__(self, parent, conf: Optional[PanelConf] = None, _id="-panel"): + def __init__(self, parent, conf: Optional[PanelConf] = None, _id=None): super().__init__(parent, _id=_id) self.conf = conf or PanelConf() self.commands = Commands(self) diff --git a/src/myfasthtml/controls/Profiler.py b/src/myfasthtml/controls/Profiler.py index cfb44a5..4b87e20 100644 --- a/src/myfasthtml/controls/Profiler.py +++ b/src/myfasthtml/controls/Profiler.py @@ -161,7 +161,7 @@ class Profiler(SingleInstance): def __init__(self, parent, _id=None): super().__init__(parent, _id=_id) - self._panel = Panel(self, conf=PanelConf(show_right_title=False, show_display_right=False)) + self._panel = Panel(self, conf=PanelConf(show_right_title=False, show_display_right=False), _id="-panel") self._panel.set_side_visible("right", True) self._selected_id: str | None = None self._detail_view: str = "tree" @@ -339,8 +339,7 @@ class Profiler(SingleInstance): kwargs_obj = SimpleNamespace(**trace.kwargs) if trace.kwargs else SimpleNamespace() kwargs_props = Properties( self, - obj=kwargs_obj, - groups={"kwargs": {"*": ""}}, + conf=PropertiesConf(obj=kwargs_obj, groups={"kwargs": {"*": ""}}), _id="-detail-kwargs", ) diff --git a/src/myfasthtml/controls/Properties.py b/src/myfasthtml/controls/Properties.py index ebc751f..942c70d 100644 --- a/src/myfasthtml/controls/Properties.py +++ b/src/myfasthtml/controls/Properties.py @@ -24,22 +24,18 @@ class PropertiesConf: class Properties(MultipleInstance): - def __init__(self, parent, obj=None, groups: dict = None, conf: PropertiesConf = None, _id=None): + def __init__(self, parent, conf: PropertiesConf = None, _id=None): super().__init__(parent, _id=_id) - if conf is not None: - self.obj = conf.obj - self.groups = conf.groups - self._types = conf.types or {} - else: - self.obj = obj - self.groups = groups - self._types = {} - self.properties_by_group = self._create_properties_by_group() + self.conf = conf or PropertiesConf() + self._refresh() - def set_obj(self, obj, groups: dict = None): - self.obj = obj - self.groups = groups - self.properties_by_group = self._create_properties_by_group() + def set_conf(self, conf: PropertiesConf): + self.conf = conf + self._refresh() + + def _refresh(self): + self._types = self.conf.types or {} + self._properties_by_group = self._create_properties_by_group() def _mk_group_content(self, properties: dict): return Div( @@ -57,7 +53,7 @@ class Properties(MultipleInstance): def _mk_property_value(self, value): for t, renderer in self._types.items(): if isinstance(value, t): - return renderer(value, self.obj) + return renderer(value, self.conf.obj) if isinstance(value, dict): return self._mk_group_content(value) @@ -73,9 +69,9 @@ class Properties(MultipleInstance): """Render a group's content. When the group contains exactly one property whose type is registered in - ``_types``, the type renderer replaces the entire group content (not just - the value cell). This lets custom renderers (e.g. span trees) fill the - full card width without a key/value row wrapper. + ``conf.types``, the type renderer replaces the entire group content (not + just the value cell). This lets custom renderers (e.g. span trees) fill + the full card width without a key/value row wrapper. Otherwise, the standard key/value row layout is used. @@ -90,7 +86,7 @@ class Properties(MultipleInstance): k, v = next(iter(properties.items())) for t, renderer in self._types.items(): if isinstance(v, t): - return renderer(v, self.obj) + return renderer(v, self.conf.obj) return self._mk_group_content(properties) def render(self): @@ -104,17 +100,17 @@ class Properties(MultipleInstance): ), cls="mf-properties-group-card" ) - for group_name, proxy in self.properties_by_group.items() + for group_name, proxy in self._properties_by_group.items() ], id=self._id, cls="mf-properties" ) def _create_properties_by_group(self): - if self.groups is None: - return {None: ProxyObject(self.obj, {"*": ""})} + if self.conf.groups is None: + return {None: ProxyObject(self.conf.obj, {"*": ""})} - return {k: ProxyObject(self.obj, v) for k, v in self.groups.items()} + return {k: ProxyObject(self.conf.obj, v) for k, v in self.conf.groups.items()} def __ft__(self): return self.render() diff --git a/src/myfasthtml/core/instances.py b/src/myfasthtml/core/instances.py index 82f6b6d..6c4c91f 100644 --- a/src/myfasthtml/core/instances.py +++ b/src/myfasthtml/core/instances.py @@ -247,7 +247,7 @@ class InstancesManager: """ key = (InstancesManager.get_session_id(session), instance.get_id()) - if isinstance(instance, SingleInstance) and key in InstancesManager.instances: + if key in InstancesManager.instances and not isinstance(instance, UniqueInstance): raise DuplicateInstanceError(instance) InstancesManager.instances[key] = instance