MCPcopy
hub / github.com/teng-lin/notebooklm-py / patch_session_login_dual

Function patch_session_login_dual

tests/_fixtures/cli_session.py:89–165  ·  view source on GitHub ↗

Patch session-side, package, and submodule bindings of ``name``. ``name`` is a helper symbol that lives in :mod:`notebooklm.cli.services.login` (or one of its submodules, post-T4) and is re-imported by :mod:`notebooklm.cli.session_cmd`. Tests that need a helper intercepted regardles

(name: str, **patch_kwargs: Any)

Source from the content-addressed store, hash-verified

87
88@contextmanager
89def patch_session_login_dual(name: str, **patch_kwargs: Any) -> Iterator[Any]:
90 """Patch session-side, package, and submodule bindings of ``name``.
91
92 ``name`` is a helper symbol that lives in
93 :mod:`notebooklm.cli.services.login` (or one of its submodules,
94 post-T4) and is re-imported by :mod:`notebooklm.cli.session_cmd`.
95 Tests that need a helper intercepted regardless of which entry point
96 reaches it use this to avoid hand-wiring N ``patch(...)`` calls.
97
98 The patches share the same mock object, so call assertions made
99 against the returned mock count *every* invocation across all
100 surfaces — matching the historical pre-D1 PR-3 behavior of the
101 forwarding wrappers in ``cli.session``.
102
103 Args:
104 name: Bare symbol name (e.g. ``"_login_with_browser_cookies"``).
105 **patch_kwargs: Forwarded to :func:`unittest.mock.patch` for the
106 primary services-side surface. Typical: ``new=...``,
107 ``side_effect=...``, ``return_value=...``,
108 ``new_callable=AsyncMock``.
109
110 Yields:
111 The shared mock used for every surface.
112 """
113 services_target = f"notebooklm.cli.services.login.{name}"
114 session_target = f"notebooklm.cli.session_cmd.{name}"
115 submodule_targets = _services_login_submodule_targets(name)
116 # The session-side patch only applies to names still re-exported by
117 # ``session_cmd`` (the retired patch-surface bridge, #1367, dropped the
118 # pure re-exports but kept every body-used name like ``get_storage_path``
119 # and ``_refresh_from_browser_cookies``). Resolve the module object so the
120 # patch can be guarded on the name still existing; a blind patch on a
121 # removed name would ``AttributeError`` at setup.
122 session_cmd = importlib.import_module("notebooklm.cli.session_cmd")
123
124 # P3.T3 service modules also re-import external helpers (notably
125 # ``get_storage_path`` / ``get_browser_profile_dir`` in
126 # ``services.playwright_login`` and ``services.session_context``).
127 # Fan the patch out to those bindings too so a single
128 # ``patch_session_login_dual("get_storage_path", ...)`` call covers
129 # every call site without requiring per-test patches.
130 p3t3_modules = (
131 "notebooklm.cli.services.playwright_login",
132 "notebooklm.cli.services.session_context",
133 "notebooklm.cli.services.auth_diagnostics",
134 "notebooklm.cli.services.auth_source",
135 )
136 p3t3_targets: list[str] = []
137 for mod_name in p3t3_modules:
138 try:
139 mod = importlib.import_module(mod_name)
140 except ImportError:
141 continue
142 if name in vars(mod):
143 p3t3_targets.append(f"{mod_name}.{name}")
144
145 with ExitStack() as stack:
146 primary = stack.enter_context(patch(services_target, **patch_kwargs))

Calls 1