Skip to content

Commit 4f24962

Browse files
committed
refactor(live_component): keep _AutoRefresh.__name__ honest via __coco_subpath_name__
The previous implementation overrode `_AutoRefresh.__name__` to the wrapped fn's name so `coco.mount(auto_refresh(fn, ...))` would derive the same subpath as `coco.mount(fn)`. That conflated subpath identity with class identity — tracebacks and `processor_name` in the exception handler reported the wrapper as if it were the wrapped fn, hiding the live-loop layer when something went wrong inside the scaffold. Introduce an opt-in `__coco_subpath_name__` attribute that `mount`/`use_mount`/`mount_each` consult before falling back to `__name__`. `auto_refresh` now keeps `_AutoRefresh.__name__` accurate and only overrides the subpath via the new attribute. Same user-visible subpath; honest class identity for debugging and for any future wrapper (or user-defined LiveComponent) that wants the same behavior.
1 parent e1c2ed5 commit 4f24962

2 files changed

Lines changed: 21 additions & 5 deletions

File tree

python/cocoindex/_internal/api.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@
112112
_ChildHandlerT = TypeVar("_ChildHandlerT", bound="TargetHandler[Any, Any, Any] | None")
113113

114114

115+
def _default_subpath_name(processor_fn: Any) -> str | None:
116+
"""Resolve the default subpath name for a mount target.
117+
118+
Honors an explicit ``__coco_subpath_name__`` attribute (set by wrappers
119+
like ``coco.auto_refresh`` so the wrapper class can keep an honest
120+
``__name__`` while still mounting under the wrapped function's name),
121+
falling back to ``__name__``.
122+
"""
123+
name = getattr(processor_fn, "__coco_subpath_name__", None)
124+
if isinstance(name, str):
125+
return name
126+
name = getattr(processor_fn, "__name__", None)
127+
if isinstance(name, str):
128+
return name
129+
return None
130+
131+
115132
class ComponentMountHandle:
116133
"""Handle for processing unit(s) started with `mount()` or `mount_each()`. Allows waiting until ready."""
117134

@@ -223,7 +240,7 @@ async def use_mount(*pos_args: Any, **kwargs: Any) -> Any:
223240
else:
224241
processor_fn = pos_args[0]
225242
args = pos_args[1:]
226-
name = getattr(processor_fn, "__name__", None)
243+
name = _default_subpath_name(processor_fn)
227244
if name is None:
228245
raise TypeError(
229246
"use_mount() requires a ComponentSubpath when the function has no "
@@ -333,7 +350,7 @@ async def mount(*pos_args: Any, **kwargs: Any) -> ComponentMountHandle:
333350
else:
334351
processor_fn = pos_args[0]
335352
args = pos_args[1:]
336-
name = getattr(processor_fn, "__name__", None)
353+
name = _default_subpath_name(processor_fn)
337354
if name is None:
338355
raise TypeError(
339356
"mount() requires a ComponentSubpath when the function has no "
@@ -423,7 +440,7 @@ async def mount_each(*pos_args: Any, **kwargs: Any) -> ComponentMountHandle:
423440
fn = pos_args[0]
424441
items = pos_args[1]
425442
extra_args = pos_args[2:]
426-
name = getattr(fn, "__name__", None)
443+
name = _default_subpath_name(fn)
427444
if name is None:
428445
raise TypeError(
429446
"mount_each() requires a ComponentSubpath when the function has no "

python/cocoindex/_internal/live_component.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,5 @@ async def process_live(self, operator: LiveComponentOperator) -> None:
586586
await asyncio.sleep(sleep_seconds)
587587
await operator.update_full()
588588

589-
_AutoRefresh.__name__ = f"AutoRefresh[{fn_name}]"
590-
_AutoRefresh.__qualname__ = _AutoRefresh.__name__
589+
_AutoRefresh.__coco_subpath_name__ = fn_name # type: ignore[attr-defined]
591590
return _AutoRefresh

0 commit comments

Comments
 (0)