Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -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",
]
25 changes: 21 additions & 4 deletions src/manage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__}
Expand All @@ -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,
Expand Down Expand Up @@ -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":
Comment thread
zooba marked this conversation as resolved.
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:
Expand Down
4 changes: 2 additions & 2 deletions src/manage/install_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
23 changes: 12 additions & 11 deletions src/manage/installs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/manage/scriptutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions tests/test_install_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
7 changes: 5 additions & 2 deletions tests/test_installs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])


Expand All @@ -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")
2 changes: 1 addition & 1 deletion tests/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"), ()),
)
Expand Down