diff --git a/tests/test_browser.py b/tests/test_launch.py similarity index 80% rename from tests/test_browser.py rename to tests/test_launch.py index 19102d305a..4a157011bb 100644 --- a/tests/test_browser.py +++ b/tests/test_launch.py @@ -15,30 +15,30 @@ ("FreeBSD", "xdg-open"), ], ) -def test_open_browser_unix(system: str, command: str): +def test_launch_url_unix(system: str, command: str): with patch("platform.system", return_value=system), patch( "shutil.which", return_value=True ), patch("subprocess.Popen") as mock_popen: - typer.open_browser(url) + typer.launch(url) mock_popen.assert_called_once_with( [command, url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT ) -def test_open_browser_windows(): +def test_launch_url_windows(): with patch("platform.system", return_value="Windows"), patch( "webbrowser.open" ) as mock_webbrowser_open: - typer.open_browser(url) + typer.launch(url) mock_webbrowser_open.assert_called_once_with(url) -def test_open_browser_no_xdg_open(): +def test_launch_url_no_xdg_open(): with patch("platform.system", return_value="Linux"), patch( "shutil.which", return_value=None ), patch("webbrowser.open") as mock_webbrowser_open: - typer.open_browser(url) + typer.launch(url) mock_webbrowser_open.assert_called_once_with(url) diff --git a/typer/__init__.py b/typer/__init__.py index fa7d379f7b..00e3f0fab6 100644 --- a/typer/__init__.py +++ b/typer/__init__.py @@ -12,7 +12,6 @@ from click.termui import echo_via_pager as echo_via_pager from click.termui import edit as edit from click.termui import getchar as getchar -from click.termui import launch as launch from click.termui import pause as pause from click.termui import progressbar as progressbar from click.termui import prompt as prompt @@ -27,6 +26,7 @@ from click.utils import open_file as open_file from . import colors as colors +from .launch import launch as launch from .main import Typer as Typer from .main import run as run from .models import CallbackParam as CallbackParam @@ -37,4 +37,3 @@ from .models import FileTextWrite as FileTextWrite from .params import Argument as Argument from .params import Option as Option -from .browser import open_browser as open_browser diff --git a/typer/browser.py b/typer/browser.py deleted file mode 100644 index 2061c9cb78..0000000000 --- a/typer/browser.py +++ /dev/null @@ -1,46 +0,0 @@ -import platform -import shutil -import subprocess - - -def _is_macos() -> bool: - return platform.system() == "Darwin" - - -def _is_linux_or_bsd() -> bool: - if platform.system() == "Linux": - return True - - return "BSD" in platform.system() - - -def open_browser(url: str) -> None: - """ - Open a web browser to the specified URL. - - This function handles different operating systems separately: - - On macOS (Darwin), it uses the 'open' command. - - On Linux and BSD, it uses 'xdg-open' if available. - - On Windows (and other OSes), it uses the standard webbrowser module. - - The function avoids, when possible, using the webbrowser module on Linux and macOS - to prevent spammy terminal messages from some browsers (e.g., Chrome). - """ - - if _is_macos(): - subprocess.Popen( - ["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT - ) - return - - has_xdg_open = _is_linux_or_bsd() and shutil.which("xdg-open") is not None - - if has_xdg_open: - subprocess.Popen( - ["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT - ) - return - - import webbrowser - - webbrowser.open(url) diff --git a/typer/launch.py b/typer/launch.py new file mode 100644 index 0000000000..94df38a0f6 --- /dev/null +++ b/typer/launch.py @@ -0,0 +1,70 @@ +import platform +import shutil +import subprocess + +from click import launch as click_launch + + +def _is_macos() -> bool: + return platform.system() == "Darwin" + + +def _is_linux_or_bsd() -> bool: + if platform.system() == "Linux": + return True + + return "BSD" in platform.system() + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + This function handles url in different operating systems separately: + - On macOS (Darwin), it uses the 'open' command. + - On Linux and BSD, it uses 'xdg-open' if available. + - On Windows (and other OSes), it uses the standard webbrowser module. + + The function avoids, when possible, using the webbrowser module on Linux and macOS + to prevent spammy terminal messages from some browsers (e.g., Chrome). + + Examples:: + + typer.launch('https://click.palletsprojects.com/') + typer.launch('/my/downloaded/file', locate=True) + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + + if url.startswith("http://") or url.startswith("https://"): + if _is_macos(): + return subprocess.Popen( + ["open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT + ).wait() + + has_xdg_open = _is_linux_or_bsd() and shutil.which("xdg-open") is not None + + if has_xdg_open: + return subprocess.Popen( + ["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT + ).wait() + + import webbrowser + + webbrowser.open(url) + + return 0 + + else: + return click_launch(url)