From 8e561c3c55d5e66572854883fc4c032ec607fcc8 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Mon, 8 Dec 2025 16:01:27 +0200 Subject: [PATCH] Upgrade to latest click 8.3.1 --- platformio/compat.py | 81 ++++++++++++++++++++++++++++++ platformio/dependencies.py | 2 +- platformio/home/cli.py | 4 +- platformio/home/rpc/handlers/os.py | 10 ++-- 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/platformio/compat.py b/platformio/compat.py index d5455099..30c5482d 100644 --- a/platformio/compat.py +++ b/platformio/compat.py @@ -146,3 +146,84 @@ def is_proxy_set(socks=False): continue return True return False + + +def click_launch(url, wait=False, locate=False) -> int: + return _click_open_url(url, wait=wait, locate=locate) + + +def _click_open_url( + url, wait=False, locate=False +): # pylint: disable=too-many-branches, too-many-return-statements, consider-using-with + """ + Issue https://github.com/pallets/click/issues/2868 + Keep in sync with https://github.com/pallets/click/blob/main/src/click/_termui_impl.py + """ + import subprocess + + def _unquote_file(url) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if IS_MACOS: + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif IS_WINDOWS: + if locate: + url = _unquote_file(url) + args = ["explorer", f"/select,{url}"] + else: + args = ["start"] + if wait: + args.append("/WAIT") + args.append("") + args.append(url) + try: + return subprocess.call(args, shell=True) + except OSError: + # Command not found + return 127 + elif IS_CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 diff --git a/platformio/dependencies.py b/platformio/dependencies.py index 9ecec364..0b82e221 100644 --- a/platformio/dependencies.py +++ b/platformio/dependencies.py @@ -29,7 +29,7 @@ def get_core_dependencies(): def get_pip_dependencies(): core = [ "bottle == 0.13.*", - "click >=8.0.4, <8.1.8", + "click >=8.0.4, <8.4", "colorama", "marshmallow == 3.*", "pyelftools >=0.27, <1", diff --git a/platformio/home/cli.py b/platformio/home/cli.py index 318c78fa..103822b4 100644 --- a/platformio/home/cli.py +++ b/platformio/home/cli.py @@ -17,7 +17,7 @@ import socket import click -from platformio.compat import IS_WINDOWS +from platformio.compat import IS_WINDOWS, click_launch from platformio.home.run import run_server from platformio.package.manager.core import get_core_package_dir @@ -86,7 +86,7 @@ def cli(port, host, no_open, shutdown_timeout, session_id): "PlatformIO Home server is already started in another process.", fg="yellow" ) if not no_open: - click.launch(home_url) + click_launch(home_url) return run_server( diff --git a/platformio/home/rpc/handlers/os.py b/platformio/home/rpc/handlers/os.py index b8dcfc9b..33d436c2 100644 --- a/platformio/home/rpc/handlers/os.py +++ b/platformio/home/rpc/handlers/os.py @@ -18,11 +18,9 @@ import os import shutil from functools import cmp_to_key -import click - from platformio import fs from platformio.cache import ContentCache -from platformio.compat import aio_to_thread +from platformio.compat import aio_to_thread, click_launch from platformio.device.list.util import list_logical_devices from platformio.home.rpc.handlers.base import BaseRPCHandler from platformio.http import HTTPSession, ensure_internet_on @@ -84,15 +82,15 @@ class OSRPC(BaseRPCHandler): @staticmethod def open_url(url): - return click.launch(url) + return click_launch(url) @staticmethod def reveal_file(path): - return click.launch(path, locate=True) + return click_launch(path, locate=True) @staticmethod def open_file(path): - return click.launch(path) + return click_launch(path) @staticmethod def call_path_module_func(name, args, **kwargs):