Skip to content

Commit ee072d8

Browse files
authored
✨ Update launch to not print anything when opening urls (#1035)
1 parent af49fda commit ee072d8

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

tests/test_launch.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import subprocess
2+
from unittest.mock import patch
3+
4+
import pytest
5+
import typer
6+
7+
url = "http://example.com"
8+
9+
10+
@pytest.mark.parametrize(
11+
"system, command",
12+
[
13+
("Darwin", "open"),
14+
("Linux", "xdg-open"),
15+
("FreeBSD", "xdg-open"),
16+
],
17+
)
18+
def test_launch_url_unix(system: str, command: str):
19+
with patch("platform.system", return_value=system), patch(
20+
"shutil.which", return_value=True
21+
), patch("subprocess.Popen") as mock_popen:
22+
typer.launch(url)
23+
24+
mock_popen.assert_called_once_with(
25+
[command, url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
26+
)
27+
28+
29+
def test_launch_url_windows():
30+
with patch("platform.system", return_value="Windows"), patch(
31+
"webbrowser.open"
32+
) as mock_webbrowser_open:
33+
typer.launch(url)
34+
35+
mock_webbrowser_open.assert_called_once_with(url)
36+
37+
38+
def test_launch_url_no_xdg_open():
39+
with patch("platform.system", return_value="Linux"), patch(
40+
"shutil.which", return_value=None
41+
), patch("webbrowser.open") as mock_webbrowser_open:
42+
typer.launch(url)
43+
44+
mock_webbrowser_open.assert_called_once_with(url)
45+
46+
47+
def test_calls_original_launch_when_not_passing_urls():
48+
with patch("typer.main.click.launch", return_value=0) as launch_mock:
49+
typer.launch("not a url")
50+
51+
launch_mock.assert_called_once_with("not a url")

typer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from click.termui import echo_via_pager as echo_via_pager
1313
from click.termui import edit as edit
1414
from click.termui import getchar as getchar
15-
from click.termui import launch as launch
1615
from click.termui import pause as pause
1716
from click.termui import progressbar as progressbar
1817
from click.termui import prompt as prompt
@@ -28,6 +27,7 @@
2827

2928
from . import colors as colors
3029
from .main import Typer as Typer
30+
from .main import launch as launch
3131
from .main import run as run
3232
from .models import CallbackParam as CallbackParam
3333
from .models import Context as Context

typer/main.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import inspect
22
import os
3+
import platform
4+
import shutil
5+
import subprocess
36
import sys
47
import traceback
58
from datetime import datetime
@@ -1078,3 +1081,68 @@ def run(function: Callable[..., Any]) -> None:
10781081
app = Typer(add_completion=False)
10791082
app.command()(function)
10801083
app()
1084+
1085+
1086+
def _is_macos() -> bool:
1087+
return platform.system() == "Darwin"
1088+
1089+
1090+
def _is_linux_or_bsd() -> bool:
1091+
if platform.system() == "Linux":
1092+
return True
1093+
1094+
return "BSD" in platform.system()
1095+
1096+
1097+
def launch(url: str, wait: bool = False, locate: bool = False) -> int:
1098+
"""This function launches the given URL (or filename) in the default
1099+
viewer application for this file type. If this is an executable, it
1100+
might launch the executable in a new session. The return value is
1101+
the exit code of the launched application. Usually, ``0`` indicates
1102+
success.
1103+
1104+
This function handles url in different operating systems separately:
1105+
- On macOS (Darwin), it uses the 'open' command.
1106+
- On Linux and BSD, it uses 'xdg-open' if available.
1107+
- On Windows (and other OSes), it uses the standard webbrowser module.
1108+
1109+
The function avoids, when possible, using the webbrowser module on Linux and macOS
1110+
to prevent spammy terminal messages from some browsers (e.g., Chrome).
1111+
1112+
Examples::
1113+
1114+
typer.launch("https://typer.tiangolo.com/")
1115+
typer.launch("/my/downloaded/file", locate=True)
1116+
1117+
:param url: URL or filename of the thing to launch.
1118+
:param wait: Wait for the program to exit before returning. This
1119+
only works if the launched program blocks. In particular,
1120+
``xdg-open`` on Linux does not block.
1121+
:param locate: if this is set to `True` then instead of launching the
1122+
application associated with the URL it will attempt to
1123+
launch a file manager with the file located. This
1124+
might have weird effects if the URL does not point to
1125+
the filesystem.
1126+
"""
1127+
1128+
if url.startswith("http://") or url.startswith("https://"):
1129+
if _is_macos():
1130+
return subprocess.Popen(
1131+
["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
1132+
).wait()
1133+
1134+
has_xdg_open = _is_linux_or_bsd() and shutil.which("xdg-open") is not None
1135+
1136+
if has_xdg_open:
1137+
return subprocess.Popen(
1138+
["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
1139+
).wait()
1140+
1141+
import webbrowser
1142+
1143+
webbrowser.open(url)
1144+
1145+
return 0
1146+
1147+
else:
1148+
return click.launch(url)

0 commit comments

Comments
 (0)