diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f2accb9 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,23 @@ +[lint] +# When using Ruff to check source correctness, feel free to aggressively add +# codes to ignore. We don't care to use it as a nitpicker, just a quick way to +# check for actual incorrect code. +ignore = [ + "B006", + "BLE001", + "C401", + "C408", + "FURB", + "G010", + "I001", + "PIE808", + "PLC", + "PLR1730", + "RUF012", + "RUF015", + "RUF022", + "RUF059", + "SIM", + "UP012", + "UP032", +] diff --git a/src/manage/commands.py b/src/manage/commands.py index a33865b..0919ce4 100644 --- a/src/manage/commands.py +++ b/src/manage/commands.py @@ -27,6 +27,7 @@ HELP_URL = "https://docs.python.org/using/windows" +CHANGELOG_URL = f"https://github.com/python/pymanager/releases/tag/{__version__}" COPYRIGHT = f"""Python installation manager {__version__} @@ -40,8 +41,15 @@ WELCOME = f"""!B!Python install manager was successfully updated to {__version__}.!W! -Additional shebang configuration is now available. Please see -!B!{HELP_URL}#shebang-lines!W! for more information. +Please see !B!{CHANGELOG_URL}!W! for all changes. +""" + +# Temporarily use an ARM64-specific welcome message +# This should be reverted around October 2027. +WELCOME_ARM64 = f"""!B!Python install manager was successfully updated to {__version__}.!W! + +The default platform on this PC is now !Y!-arm64!W! instead of !Y!-64!W!. +Please see !B!{CHANGELOG_URL}!W! for more details and all other changes. """ # The 'py help' or 'pymanager help' output is constructed by these default docs, @@ -533,13 +541,22 @@ def show_welcome(self, copyright=True): if __version__ == "0.1a0": last_update_file.unlink() return + + # Temporarily use an ARM64-specific welcome message + # This should be reverted around October 2027. + from _native import get_processor_architecture + if get_processor_architecture() == "-arm64": + msg = WELCOME_ARM64 + else: + msg = WELCOME + try: ensure_tree(last_update_file) - last_update_file.write_text(f"{__version__}\n\n{WELCOME}") + last_update_file.write_text(f"{__version__}\n\n{msg}") except OSError: LOGGER.debug("Failed to update %s", last_update_file, exc_info=True) return - LOGGER.info(WELCOME) + LOGGER.info(msg) def dump_arguments(self): try: diff --git a/src/manage/install_command.py b/src/manage/install_command.py index 5773fc0..d8b661b 100644 --- a/src/manage/install_command.py +++ b/src/manage/install_command.py @@ -371,13 +371,13 @@ def print_cli_shortcuts(cmd): if not verbose: if i.get("default"): LOGGER.debug("%s will be launched by !G!python.exe!W!", i["display-name"]) - names = get_install_alias_names(aliases, windowed=True) + names = get_install_alias_names(aliases, windowed=True, default_platform=cmd.default_platform) LOGGER.debug("%s will be launched by %s", i["display-name"], ", ".join(names)) if not install_matches_any(i, tags): continue - names = get_install_alias_names(aliases, windowed=False) + names = get_install_alias_names(aliases, windowed=False, default_platform=cmd.default_platform) if i.get("default") and names: LOGGER.info("%s will be launched by !G!python.exe!W! and also %s", i["display-name"], ", ".join(names)) diff --git a/src/manage/installs.py b/src/manage/installs.py index 1673c89..225b41e 100644 --- a/src/manage/installs.py +++ b/src/manage/installs.py @@ -148,12 +148,19 @@ def _make_alias_key(alias): return n1, w, n2, plat, n3 -def _make_opt_part(parts): +def _make_opt_part(parts, default=""): if not parts: return "" - if len(parts) == 1: - return list(parts)[0] - return "[{}]".format("|".join(sorted(p for p in parts if p))) + # If there's an explicit default, then we ignore empty parts. + if default: + parts = sorted(p for p in parts if p) + else: + parts = sorted(parts) + if not parts: + return "" + if len(parts) == 1 and (not parts[0] or parts[0] != default): + return parts[0] + return "[{}]".format("|".join(p for p in parts if p)) def _sk_sub(m): @@ -191,17 +198,11 @@ def get_install_alias_names(aliases, friendly=True, windowed=True, default_platf result = [] for k, (n1, n2, n3) in seen.items(): - plat_parts = plats.get(k) - plat = _make_opt_part(plat_parts) - if default_platform and plat_parts == {default_platform}: - # The bare alias was already shown for another install, but the - # suffix is still optional when it matches the default platform. - plat = f"[{default_platform}]" result.append("".join([ n1, _make_opt_part(has_w.get(k)), n2, - plat, + _make_opt_part(plats.get(k), default_platform), n3, ])) return sorted(result, key=_make_alias_name_sortkey) diff --git a/src/manage/scriptutils.py b/src/manage/scriptutils.py index 863ac1a..0a517c4 100644 --- a/src/manage/scriptutils.py +++ b/src/manage/scriptutils.py @@ -255,7 +255,7 @@ def _parse_shebang(cmd, line, *, windowed=None): "'false' in your configuration file.") try: return _find_on_path(cmd, full_cmd) - except LookupError as ex: + except LookupError: LOGGER.error("Could not launch '%s'. Using default interpreter " "instead.", full_cmd) raise diff --git a/tests/test_install_command.py b/tests/test_install_command.py index f3bd261..1a65e6a 100644 --- a/tests/test_install_command.py +++ b/tests/test_install_command.py @@ -59,6 +59,7 @@ def test_print_cli_shortcuts(patched_installs, assert_log, monkeypatch, tmp_path class Cmd: scratch = {} global_dir = Path(tmp_path) + default_platform = "-64" def get_installs(self): return installs.get_installs(None) diff --git a/tests/test_installs.py b/tests/test_installs.py index a9ffc3f..b8ca808 100644 --- a/tests/test_installs.py +++ b/tests/test_installs.py @@ -147,6 +147,9 @@ def test_install_alias_opt_part(): assert "" == installs._make_opt_part([]) assert "x" == installs._make_opt_part(["x"]) assert "[x]" == installs._make_opt_part(["x", ""]) + assert "[x]" == installs._make_opt_part(["x"], default="x") + assert "[x]" == installs._make_opt_part(["x", ""], default="x") + assert "y" == installs._make_opt_part(["y", ""], default="x") assert "[x|y]" == installs._make_opt_part(["", "y", "x"]) @@ -155,5 +158,5 @@ def test_install_alias_names(): input.extend([{"name": i, "windowed": 1} for i in ["xy3.exe", "XY3-64.exe", "XYW3.exe", "xyw3-64.exe"]]) expect = ["py[w]3[-64].exe"] expectw = ["py[w]3[-64].exe", "xy[w]3[-64].exe"] - assert expect == installs.get_install_alias_names(input, friendly=True, windowed=False) - assert expectw == installs.get_install_alias_names(input, friendly=True, windowed=True) + assert expect == installs.get_install_alias_names(input, friendly=True, windowed=False, default_platform="-64") + assert expectw == installs.get_install_alias_names(input, friendly=True, windowed=True, default_platform="-64") diff --git a/tests/test_list.py b/tests/test_list.py index 9cea254..cbc01bc 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -177,7 +177,7 @@ def online_install(tag, plat): ]) assert_log( (r"!B!Tag\s+Name\s+Managed By\s+Version\s+Alias\s*!W!", ()), - (r"3\.15-dev-32.*" + re.escape("python[w]3[-32].exe, python[w]3.15[-32].exe"), ()), + (r"3\.15-dev-32.*" + re.escape("python[w]3-32.exe, python[w]3.15-32.exe"), ()), (r"3\.15-dev\[-64\].*" + re.escape("python[w]3[-64].exe, python[w]3.15[-64].exe"), ()), (r"3\.15-dev-arm64.*" + re.escape("python[w]3-arm64.exe, python[w]3.15-arm64.exe"), ()), )