Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7ae77fd

Browse files
committed
webbrowser: refactor, move headless kw to launch()
- Add `headless=False` keyword to `Webbrowser.launch()` - Remove `headless` keyword from `WebbrowserChromium` constructor - Include headless mode in log output when launching - Update tests
1 parent 2141d7c commit 7ae77fd

5 files changed

Lines changed: 42 additions & 31 deletions

File tree

src/streamlink/webbrowser/cdp/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ async def run(
181181
cdp_timeout: Optional[float] = None,
182182
headless: bool = False,
183183
) -> AsyncGenerator[Self, None]:
184-
webbrowser = ChromiumWebbrowser(executable=executable, host=cdp_host, port=cdp_port, headless=headless)
184+
webbrowser = ChromiumWebbrowser(executable=executable, host=cdp_host, port=cdp_port)
185185
nursery: trio.Nursery
186-
async with webbrowser.launch(timeout=timeout) as nursery:
186+
async with webbrowser.launch(headless=headless, timeout=timeout) as nursery:
187187
websocket_url = webbrowser.get_websocket_url(session)
188188
cdp_connection: CDPConnection
189189
async with CDPConnection.create(websocket_url, timeout=cdp_timeout) as cdp_connection:

src/streamlink/webbrowser/chromium.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,17 +143,14 @@ def __init__(
143143
*args,
144144
host: Optional[str] = None,
145145
port: Optional[int] = None,
146-
headless: bool = False,
147146
**kwargs,
148147
):
149148
super().__init__(*args, **kwargs)
150149
self.host = host or "127.0.0.1"
151150
self.port = port
152-
if headless:
153-
self.arguments.append("--headless=new")
154151

155152
@asynccontextmanager
156-
async def launch(self, timeout: Optional[float] = None) -> AsyncGenerator[trio.Nursery, None]:
153+
async def launch(self, headless: bool = False, timeout: Optional[float] = None) -> AsyncGenerator[trio.Nursery, None]:
157154
if self.port is None:
158155
if ":" in self.host:
159156
self.port = await find_free_port_ipv6(self.host)
@@ -163,13 +160,15 @@ async def launch(self, timeout: Optional[float] = None) -> AsyncGenerator[trio.N
163160
# no async rmtree
164161
with self._create_temp_dir() as user_data_dir:
165162
arguments = self.arguments.copy()
163+
if headless:
164+
arguments.append("--headless=new")
166165
arguments.extend([
167166
f"--remote-debugging-host={self.host}",
168167
f"--remote-debugging-port={self.port}",
169168
f"--user-data-dir={user_data_dir}",
170169
])
171170

172-
async with super()._launch(self.executable, arguments, timeout=timeout) as nursery:
171+
async with super()._launch(self.executable, arguments, headless=headless, timeout=timeout) as nursery:
173172
yield nursery
174173

175174
# Even though we've awaited the process termination in the async generator above,

src/streamlink/webbrowser/webbrowser.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,20 @@ def __init__(self, executable: Optional[str] = None):
4646
self.executable: Union[str, Path] = resolved
4747
self.arguments: List[str] = self.launch_args().copy()
4848

49-
def launch(self, timeout: Optional[float] = None) -> AsyncContextManager[trio.Nursery]:
50-
return self._launch(self.executable, self.arguments, timeout=timeout)
49+
def launch(self, headless: bool = False, timeout: Optional[float] = None) -> AsyncContextManager[trio.Nursery]:
50+
return self._launch(self.executable, self.arguments, headless=headless, timeout=timeout)
5151

5252
def _launch(
5353
self,
5454
executable: Union[str, Path],
5555
arguments: List[str],
56+
headless: bool = False,
5657
timeout: Optional[float] = None,
5758
) -> AsyncContextManager[trio.Nursery]:
5859
if timeout is None:
5960
timeout = self.TIMEOUT
6061

61-
launcher = _WebbrowserLauncher(executable, arguments, timeout)
62+
launcher = _WebbrowserLauncher(executable, arguments, headless, timeout)
6263

6364
# noinspection PyArgumentList
6465
return launcher.launch()
@@ -72,17 +73,19 @@ def _create_temp_dir() -> Generator[str, None, None]:
7273

7374

7475
class _WebbrowserLauncher:
75-
def __init__(self, executable: Union[str, Path], arguments: List[str], timeout: float):
76+
def __init__(self, executable: Union[str, Path], arguments: List[str], headless: bool, timeout: float):
7677
self.executable = executable
7778
self.arguments = arguments
79+
self.headless = headless
7880
self.timeout = timeout
7981
self._process_ended_early = False
8082

8183
@asynccontextmanager
8284
async def launch(self) -> AsyncGenerator[trio.Nursery, None]:
8385
try:
86+
headless = self.headless
8487
async with trio.open_nursery() as nursery:
85-
log.info(f"Launching web browser: {self.executable}")
88+
log.info(f"Launching web browser: {self.executable} ({headless=})")
8689
# the process is run in a separate task
8790
run_process = partial(
8891
trio.run_process,

tests/webbrowser/conftest.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,16 @@ async def webbrowser_launch(*args, webbrowser: Optional[Webbrowser] = None, **kw
5555
webbrowser.executable = sys.executable
5656
webbrowser.arguments = ["-c", "import sys; sys.exit(int(sys.stdin.readline()))", *webbrowser.arguments]
5757

58+
headless = kwargs.get("headless", False)
59+
5860
async with webbrowser.launch(*args, **kwargs) as nursery:
5961
assert isinstance(nursery, trio.Nursery)
6062
assert [(record.name, record.levelname, record.msg) for record in caplog.records] == [
61-
("streamlink.webbrowser.webbrowser", "info", f"Launching web browser: {sys.executable}"),
63+
(
64+
"streamlink.webbrowser.webbrowser",
65+
"info",
66+
f"Launching web browser: {sys.executable} ({headless=})",
67+
),
6268
]
6369
caplog.records.clear()
6470
# wait until the process has launched, so we can test it

tests/webbrowser/test_chromium.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,28 @@ def test_other(self, monkeypatch: pytest.MonkeyPatch):
9393
assert ChromiumWebbrowser.fallback_paths() == []
9494

9595

96-
class TestLaunchArgs:
97-
def test_launch_args(self):
98-
webbrowser = ChromiumWebbrowser()
99-
assert "--password-store=basic" in webbrowser.arguments
100-
assert "--use-mock-keychain" in webbrowser.arguments
101-
assert "--headless=new" not in webbrowser.arguments
102-
assert not any(arg.startswith("--remote-debugging-host") for arg in webbrowser.arguments)
103-
assert not any(arg.startswith("--remote-debugging-port") for arg in webbrowser.arguments)
104-
assert not any(arg.startswith("--user-data-dir") for arg in webbrowser.arguments)
105-
106-
@pytest.mark.parametrize("headless", [True, False])
107-
def test_headless(self, headless: bool):
108-
webbrowser = ChromiumWebbrowser(headless=headless)
109-
assert ("--headless=new" in webbrowser.arguments) is headless
96+
def test_default_args():
97+
webbrowser = ChromiumWebbrowser()
98+
assert "--password-store=basic" in webbrowser.arguments
99+
assert "--use-mock-keychain" in webbrowser.arguments
100+
assert "--headless=new" not in webbrowser.arguments
101+
assert not any(arg.startswith("--remote-debugging-host") for arg in webbrowser.arguments)
102+
assert not any(arg.startswith("--remote-debugging-port") for arg in webbrowser.arguments)
103+
assert not any(arg.startswith("--user-data-dir") for arg in webbrowser.arguments)
110104

111105

112106
@pytest.mark.trio()
113-
@pytest.mark.parametrize("host", ["127.0.0.1", "::1"])
114-
@pytest.mark.parametrize("port", [None, 1234])
115-
async def test_launch(monkeypatch: pytest.MonkeyPatch, mock_clock, webbrowser_launch, host, port):
107+
@pytest.mark.parametrize("host", [pytest.param("127.0.0.1", id="ipv4"), pytest.param("::1", id="ipv6")])
108+
@pytest.mark.parametrize("port", [pytest.param(None, id="default-port"), pytest.param(1234, id="custom-port")])
109+
@pytest.mark.parametrize("headless", [pytest.param(True, id="headless"), pytest.param(False, id="not-headless")])
110+
async def test_launch(
111+
monkeypatch: pytest.MonkeyPatch,
112+
mock_clock,
113+
webbrowser_launch,
114+
host: str,
115+
port: Optional[int],
116+
headless: bool,
117+
):
116118
async def fake_find_free_port(_):
117119
await trio.sleep(0)
118120
return 1234
@@ -123,10 +125,11 @@ async def fake_find_free_port(_):
123125
webbrowser = ChromiumWebbrowser(host=host, port=port)
124126

125127
process: trio.Process
126-
async with webbrowser_launch(webbrowser=webbrowser, timeout=999) as (_nursery, process):
128+
async with webbrowser_launch(webbrowser=webbrowser, headless=headless, timeout=999) as (_nursery, process):
127129
assert process.poll() is None, "process is still running"
128130
assert f"--remote-debugging-host={host}" in process.args
129131
assert "--remote-debugging-port=1234" in process.args
132+
assert ("--headless=new" in process.args) is headless
130133
param_user_data_dir = next( # pragma: no branch
131134
(arg for arg in process.args if arg.startswith("--user-data-dir=")),
132135
None,

0 commit comments

Comments
 (0)