"""Object-factory mixin for :class:`~browser_cli.BrowserCLI`. Builds the typed :class:`~browser_cli.models.Tab` / :class:`~browser_cli.models.Group` dataclasses from raw command responses and binds each one to the client that should run its actions. In multi-browser mode an object is bound to a sibling client targeting the browser it came from, so ``tab.close()`` routes correctly. """ from __future__ import annotations from browser_cli.models import Group, Tab class FactoryMixin: """Turn raw response dicts into bound ``Tab``/``Group`` objects. Mixed into :class:`~browser_cli.BrowserCLI`; relies on the client providing ``_browser``/``_remote``/``_key`` and being constructible via ``type(self)``. """ def _make_tab( self, data: dict, *, browser_profile: str | None = None, browser_name: str | None = None, browser_remote: str | None = None, ) -> Tab: tab = Tab( id=data["id"], window_id=data.get("windowId", 0), active=data.get("active", False), muted=data.get("muted", False), title=data.get("title") or "", url=data.get("url") or "", group_id=data.get("groupId") or None, browser=browser_name, ) tab._browser = self if browser_profile is None else type(self)( browser=browser_profile, remote=browser_remote, key=self._key, ) return tab def _require_tab(self, data, error: str) -> Tab: """Build a bound Tab from a tab-shaped response, or raise ``RuntimeError(error)``.""" if not isinstance(data, dict) or "id" not in data: raise RuntimeError(error) return self._make_tab(data) def _make_group( self, data: dict, *, browser_profile: str | None = None, browser_name: str | None = None, browser_remote: str | None = None, ) -> Group: group = Group( id=data["id"], title=data.get("title") or "", color=data.get("color") or "", collapsed=data.get("collapsed", False), tab_count=data.get("tabCount", 0), browser=browser_name, ) group._browser = self if browser_profile is None else type(self)( browser=browser_profile, remote=browser_remote, key=self._key, ) return group def _make_tab_for(self, data: dict, target) -> Tab: """Build a Tab, tagging it with *target* in multi-browser mode (``None`` = local).""" return self._make_tab( data, browser_profile=target.profile if target else None, browser_name=target.display_name if target else None, browser_remote=target.remote if target else None, ) def _make_group_for(self, data: dict, target) -> Group: """Build a Group, tagging it with *target* in multi-browser mode (``None`` = local).""" return self._make_group( data, browser_profile=target.profile if target else None, browser_name=target.display_name if target else None, browser_remote=target.remote if target else None, ) @staticmethod def _tag_browser(item: dict, target) -> dict: """Return *item* as-is locally, or with a ``browser`` key in multi-browser mode.""" return item if target is None else {**item, "browser": target.display_name}