mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-132930: Implement PEP 773 (GH-132931)
This change to the core CPython repo: * Adds PyManager support to PC/layout * Adds a warning message to the legacy py.exe if subcommands are invoked * Add deprecation message to traditional installer * Updates using/windows docs
This commit is contained in:
parent
11f457cf41
commit
e20ca6d1b0
8 changed files with 1447 additions and 626 deletions
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,2 @@
|
||||||
|
Marks the installer for Windows as deprecated and updates documentation to
|
||||||
|
cover the new Python install manager.
|
|
@ -1058,7 +1058,7 @@ checkShebang(SearchInfo *search)
|
||||||
debug(L"# Failed to open %s for shebang parsing (0x%08X)\n",
|
debug(L"# Failed to open %s for shebang parsing (0x%08X)\n",
|
||||||
scriptFile, GetLastError());
|
scriptFile, GetLastError());
|
||||||
free(scriptFile);
|
free(scriptFile);
|
||||||
return 0;
|
return RC_NO_SCRIPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
|
@ -2665,6 +2665,21 @@ performSearch(SearchInfo *search, EnvironmentInfo **envs)
|
||||||
case RC_NO_SHEBANG:
|
case RC_NO_SHEBANG:
|
||||||
case RC_RECURSIVE_SHEBANG:
|
case RC_RECURSIVE_SHEBANG:
|
||||||
break;
|
break;
|
||||||
|
case RC_NO_SCRIPT:
|
||||||
|
if (!_comparePath(search->scriptFile, search->scriptFileLength, L"install", -1) ||
|
||||||
|
!_comparePath(search->scriptFile, search->scriptFileLength, L"uninstall", -1) ||
|
||||||
|
!_comparePath(search->scriptFile, search->scriptFileLength, L"list", -1) ||
|
||||||
|
!_comparePath(search->scriptFile, search->scriptFileLength, L"help", -1)) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"WARNING: The '%.*ls' command is unavailable because this is the legacy py.exe command.\n"
|
||||||
|
"If you have already installed the Python install manager, open Installed Apps and "
|
||||||
|
"remove 'Python Launcher' to enable the new py.exe command.\n",
|
||||||
|
search->scriptFileLength,
|
||||||
|
search->scriptFile
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ __author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
__version__ = "3.8"
|
__version__ = "3.8"
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
@ -28,6 +29,7 @@ from .support.logging import *
|
||||||
from .support.options import *
|
from .support.options import *
|
||||||
from .support.pip import *
|
from .support.pip import *
|
||||||
from .support.props import *
|
from .support.props import *
|
||||||
|
from .support.pymanager import *
|
||||||
from .support.nuspec import *
|
from .support.nuspec import *
|
||||||
|
|
||||||
TEST_PYDS_ONLY = FileStemSet("xxlimited", "xxlimited_35", "_ctypes_test", "_test*")
|
TEST_PYDS_ONLY = FileStemSet("xxlimited", "xxlimited_35", "_ctypes_test", "_test*")
|
||||||
|
@ -265,7 +267,12 @@ def get_layout(ns):
|
||||||
if ns.include_dev:
|
if ns.include_dev:
|
||||||
for dest, src in rglob(ns.source / "Include", "**/*.h"):
|
for dest, src in rglob(ns.source / "Include", "**/*.h"):
|
||||||
yield "include/{}".format(dest), src
|
yield "include/{}".format(dest), src
|
||||||
yield "include/pyconfig.h", ns.build / "pyconfig.h"
|
# Support for layout of new and old releases.
|
||||||
|
pc = ns.source / "PC"
|
||||||
|
if (pc / "pyconfig.h.in").is_file():
|
||||||
|
yield "include/pyconfig.h", ns.build / "pyconfig.h"
|
||||||
|
else:
|
||||||
|
yield "include/pyconfig.h", pc / "pyconfig.h"
|
||||||
|
|
||||||
for dest, src in get_tcltk_lib(ns):
|
for dest, src in get_tcltk_lib(ns):
|
||||||
yield dest, src
|
yield dest, src
|
||||||
|
@ -303,6 +310,9 @@ def get_layout(ns):
|
||||||
else:
|
else:
|
||||||
yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat
|
yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat
|
||||||
|
|
||||||
|
if ns.include_install_json or ns.include_install_embed_json or ns.include_install_test_json:
|
||||||
|
yield "__install__.json", ns.temp / "__install__.json"
|
||||||
|
|
||||||
|
|
||||||
def _compile_one_py(src, dest, name, optimize, checked=True):
|
def _compile_one_py(src, dest, name, optimize, checked=True):
|
||||||
import py_compile
|
import py_compile
|
||||||
|
@ -394,6 +404,22 @@ def generate_source_files(ns):
|
||||||
log_info("Extracting pip")
|
log_info("Extracting pip")
|
||||||
extract_pip_files(ns)
|
extract_pip_files(ns)
|
||||||
|
|
||||||
|
if ns.include_install_json:
|
||||||
|
log_info("Generating __install__.json in {}", ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(ns.temp / "__install__.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(calculate_install_json(ns), f, indent=2)
|
||||||
|
elif ns.include_install_embed_json:
|
||||||
|
log_info("Generating embeddable __install__.json in {}", ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(ns.temp / "__install__.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(calculate_install_json(ns, for_embed=True), f, indent=2)
|
||||||
|
elif ns.include_install_test_json:
|
||||||
|
log_info("Generating test __install__.json in {}", ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(ns.temp / "__install__.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(calculate_install_json(ns, for_test=True), f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
def _create_zip_file(ns):
|
def _create_zip_file(ns):
|
||||||
if not ns.zip:
|
if not ns.zip:
|
||||||
|
@ -627,6 +653,7 @@ def main():
|
||||||
if ns.include_cat and not ns.include_cat.is_absolute():
|
if ns.include_cat and not ns.include_cat.is_absolute():
|
||||||
ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
|
ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
|
||||||
if not ns.arch:
|
if not ns.arch:
|
||||||
|
# TODO: Calculate arch from files in ns.build instead
|
||||||
if sys.winver.endswith("-arm64"):
|
if sys.winver.endswith("-arm64"):
|
||||||
ns.arch = "arm64"
|
ns.arch = "arm64"
|
||||||
elif sys.winver.endswith("-32"):
|
elif sys.winver.endswith("-32"):
|
||||||
|
|
|
@ -36,6 +36,9 @@ OPTIONS = {
|
||||||
"alias": {"help": "aliased python.exe entry-point binaries"},
|
"alias": {"help": "aliased python.exe entry-point binaries"},
|
||||||
"alias3": {"help": "aliased python3.exe entry-point binaries"},
|
"alias3": {"help": "aliased python3.exe entry-point binaries"},
|
||||||
"alias3x": {"help": "aliased python3.x.exe entry-point binaries"},
|
"alias3x": {"help": "aliased python3.x.exe entry-point binaries"},
|
||||||
|
"install-json": {"help": "a PyManager __install__.json file"},
|
||||||
|
"install-embed-json": {"help": "a PyManager __install__.json file for embeddable distro"},
|
||||||
|
"install-test-json": {"help": "a PyManager __install__.json for the test distro"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,6 +98,34 @@ PRESETS = {
|
||||||
"precompile",
|
"precompile",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
"pymanager": {
|
||||||
|
"help": "PyManager package",
|
||||||
|
"options": [
|
||||||
|
"stable",
|
||||||
|
"pip",
|
||||||
|
"tcltk",
|
||||||
|
"idle",
|
||||||
|
"venv",
|
||||||
|
"dev",
|
||||||
|
"html-doc",
|
||||||
|
"install-json",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"pymanager-test": {
|
||||||
|
"help": "PyManager test package",
|
||||||
|
"options": [
|
||||||
|
"stable",
|
||||||
|
"pip",
|
||||||
|
"tcltk",
|
||||||
|
"idle",
|
||||||
|
"venv",
|
||||||
|
"dev",
|
||||||
|
"html-doc",
|
||||||
|
"symbols",
|
||||||
|
"tests",
|
||||||
|
"install-test-json",
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
249
PC/layout/support/pymanager.py
Normal file
249
PC/layout/support/pymanager.py
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
from .constants import *
|
||||||
|
|
||||||
|
URL_BASE = "https://www.python.org/ftp/python/"
|
||||||
|
|
||||||
|
XYZ_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}"
|
||||||
|
WIN32_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}.{VER_FIELD4}"
|
||||||
|
FULL_VERSION = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}{VER_SUFFIX}"
|
||||||
|
|
||||||
|
|
||||||
|
def _not_empty(n, key=None):
|
||||||
|
result = []
|
||||||
|
for i in n:
|
||||||
|
if key:
|
||||||
|
i_l = i[key]
|
||||||
|
else:
|
||||||
|
i_l = i
|
||||||
|
if not i_l:
|
||||||
|
continue
|
||||||
|
result.append(i)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_install_json(ns, *, for_embed=False, for_test=False):
|
||||||
|
TARGET = "python.exe"
|
||||||
|
TARGETW = "pythonw.exe"
|
||||||
|
|
||||||
|
SYS_ARCH = {
|
||||||
|
"win32": "32bit",
|
||||||
|
"amd64": "64bit",
|
||||||
|
"arm64": "64bit", # Unfortunate, but this is how it's spec'd
|
||||||
|
}[ns.arch]
|
||||||
|
TAG_ARCH = {
|
||||||
|
"win32": "-32",
|
||||||
|
"amd64": "-64",
|
||||||
|
"arm64": "-arm64",
|
||||||
|
}[ns.arch]
|
||||||
|
|
||||||
|
COMPANY = "PythonCore"
|
||||||
|
DISPLAY_NAME = "Python"
|
||||||
|
TAG_SUFFIX = ""
|
||||||
|
ALIAS_PREFIX = "python"
|
||||||
|
ALIAS_WPREFIX = "pythonw"
|
||||||
|
FILE_PREFIX = "python-"
|
||||||
|
FILE_SUFFIX = f"-{ns.arch}"
|
||||||
|
DISPLAY_TAGS = [{
|
||||||
|
"win32": "32-bit",
|
||||||
|
"amd64": "",
|
||||||
|
"arm64": "ARM64",
|
||||||
|
}[ns.arch]]
|
||||||
|
|
||||||
|
if for_test:
|
||||||
|
# Packages with the test suite come under a different Company
|
||||||
|
COMPANY = "PythonTest"
|
||||||
|
DISPLAY_TAGS.append("with tests")
|
||||||
|
FILE_SUFFIX = f"-test-{ns.arch}"
|
||||||
|
if for_embed:
|
||||||
|
# Embeddable distro comes under a different Company
|
||||||
|
COMPANY = "PythonEmbed"
|
||||||
|
TARGETW = None
|
||||||
|
ALIAS_PREFIX = None
|
||||||
|
DISPLAY_TAGS.append("embeddable")
|
||||||
|
# Deliberately name the file differently from the existing distro
|
||||||
|
# so we can republish old versions without replacing files.
|
||||||
|
FILE_SUFFIX = f"-embeddable-{ns.arch}"
|
||||||
|
if ns.include_freethreaded:
|
||||||
|
# Free-threaded distro comes with a tag suffix
|
||||||
|
TAG_SUFFIX = "t"
|
||||||
|
TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe"
|
||||||
|
TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe"
|
||||||
|
DISPLAY_TAGS.append("freethreaded")
|
||||||
|
FILE_SUFFIX = f"t-{ns.arch}"
|
||||||
|
|
||||||
|
FULL_TAG = f"{VER_MAJOR}.{VER_MINOR}.{VER_MICRO}{VER_SUFFIX}{TAG_SUFFIX}"
|
||||||
|
FULL_ARCH_TAG = f"{FULL_TAG}{TAG_ARCH}"
|
||||||
|
XY_TAG = f"{VER_MAJOR}.{VER_MINOR}{TAG_SUFFIX}"
|
||||||
|
XY_ARCH_TAG = f"{XY_TAG}{TAG_ARCH}"
|
||||||
|
X_TAG = f"{VER_MAJOR}{TAG_SUFFIX}"
|
||||||
|
X_ARCH_TAG = f"{X_TAG}{TAG_ARCH}"
|
||||||
|
|
||||||
|
# Tag used in runtime ID (for side-by-side install/updates)
|
||||||
|
ID_TAG = XY_ARCH_TAG
|
||||||
|
# Tag shown in 'py list' output
|
||||||
|
DISPLAY_TAG = f"{XY_TAG}-dev{TAG_ARCH}" if VER_SUFFIX else XY_ARCH_TAG
|
||||||
|
|
||||||
|
DISPLAY_SUFFIX = ", ".join(i for i in DISPLAY_TAGS if i)
|
||||||
|
if DISPLAY_SUFFIX:
|
||||||
|
DISPLAY_SUFFIX = f" ({DISPLAY_SUFFIX})"
|
||||||
|
DISPLAY_VERSION = f"{XYZ_VERSION}{VER_SUFFIX}{DISPLAY_SUFFIX}"
|
||||||
|
|
||||||
|
STD_RUN_FOR = []
|
||||||
|
STD_ALIAS = []
|
||||||
|
STD_PEP514 = []
|
||||||
|
STD_START = []
|
||||||
|
STD_UNINSTALL = []
|
||||||
|
|
||||||
|
# The list of 'py install <TAG>' tags that will match this runtime.
|
||||||
|
# Architecture should always be included here because PyManager will add it.
|
||||||
|
INSTALL_TAGS = [
|
||||||
|
FULL_ARCH_TAG,
|
||||||
|
XY_ARCH_TAG,
|
||||||
|
X_ARCH_TAG,
|
||||||
|
# X_TAG and XY_TAG doesn't include VER_SUFFIX, so create -dev versions
|
||||||
|
f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG and VER_SUFFIX else "",
|
||||||
|
f"{X_TAG}-dev{TAG_ARCH}" if X_TAG and VER_SUFFIX else "",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Generate run-for entries for each target.
|
||||||
|
# Again, include architecture because PyManager will add it.
|
||||||
|
for base in [
|
||||||
|
{"target": TARGET},
|
||||||
|
{"target": TARGETW, "windowed": 1},
|
||||||
|
]:
|
||||||
|
if not base["target"]:
|
||||||
|
continue
|
||||||
|
STD_RUN_FOR.append({**base, "tag": FULL_ARCH_TAG})
|
||||||
|
if XY_TAG:
|
||||||
|
STD_RUN_FOR.append({**base, "tag": XY_ARCH_TAG})
|
||||||
|
if X_TAG:
|
||||||
|
STD_RUN_FOR.append({**base, "tag": X_ARCH_TAG})
|
||||||
|
if VER_SUFFIX:
|
||||||
|
STD_RUN_FOR.extend([
|
||||||
|
{**base, "tag": f"{XY_TAG}-dev{TAG_ARCH}" if XY_TAG else ""},
|
||||||
|
{**base, "tag": f"{X_TAG}-dev{TAG_ARCH}" if X_TAG else ""},
|
||||||
|
])
|
||||||
|
|
||||||
|
# Generate alias entries for each target. We need both arch and non-arch
|
||||||
|
# versions as well as windowed/non-windowed versions to make sure that all
|
||||||
|
# necessary aliases are created.
|
||||||
|
if ALIAS_PREFIX:
|
||||||
|
for prefix, base in [
|
||||||
|
(ALIAS_PREFIX, {"target": TARGET}),
|
||||||
|
(f"{ALIAS_PREFIX}w", {"target": TARGETW, "windowed": 1}),
|
||||||
|
]:
|
||||||
|
if not base["target"]:
|
||||||
|
continue
|
||||||
|
if XY_TAG:
|
||||||
|
STD_ALIAS.extend([
|
||||||
|
{**base, "name": f"{prefix}{XY_TAG}.exe"},
|
||||||
|
{**base, "name": f"{prefix}{XY_ARCH_TAG}.exe"},
|
||||||
|
])
|
||||||
|
if X_TAG:
|
||||||
|
STD_ALIAS.extend([
|
||||||
|
{**base, "name": f"{prefix}{X_TAG}.exe"},
|
||||||
|
{**base, "name": f"{prefix}{X_ARCH_TAG}.exe"},
|
||||||
|
])
|
||||||
|
|
||||||
|
STD_PEP514.append({
|
||||||
|
"kind": "pep514",
|
||||||
|
"Key": rf"{COMPANY}\{ID_TAG}",
|
||||||
|
"DisplayName": f"{DISPLAY_NAME} {DISPLAY_VERSION}",
|
||||||
|
"SupportUrl": "https://www.python.org/",
|
||||||
|
"SysArchitecture": SYS_ARCH,
|
||||||
|
"SysVersion": VER_DOT,
|
||||||
|
"Version": FULL_VERSION,
|
||||||
|
"InstallPath": {
|
||||||
|
"_": "%PREFIX%",
|
||||||
|
"ExecutablePath": f"%PREFIX%{TARGET}",
|
||||||
|
# WindowedExecutablePath is added below
|
||||||
|
},
|
||||||
|
"Help": {
|
||||||
|
"Online Python Documentation": {
|
||||||
|
"_": f"https://docs.python.org/{VER_DOT}/"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
STD_START.append({
|
||||||
|
"kind": "start",
|
||||||
|
"Name": f"{DISPLAY_NAME} {VER_DOT}{DISPLAY_SUFFIX}",
|
||||||
|
"Items": [
|
||||||
|
{
|
||||||
|
"Name": f"{DISPLAY_NAME} {VER_DOT}{DISPLAY_SUFFIX}",
|
||||||
|
"Target": f"%PREFIX%{TARGET}",
|
||||||
|
"Icon": f"%PREFIX%{TARGET}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": f"{DISPLAY_NAME} {VER_DOT} Online Documentation",
|
||||||
|
"Icon": r"%SystemRoot%\System32\SHELL32.dll",
|
||||||
|
"IconIndex": 13,
|
||||||
|
"Target": f"https://docs.python.org/{VER_DOT}/",
|
||||||
|
},
|
||||||
|
# IDLE and local documentation items are added below
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
if TARGETW:
|
||||||
|
STD_PEP514[0]["InstallPath"]["WindowedExecutablePath"] = f"%PREFIX%{TARGETW}"
|
||||||
|
|
||||||
|
if ns.include_idle:
|
||||||
|
STD_START[0]["Items"].append({
|
||||||
|
"Name": f"IDLE {VER_DOT}{DISPLAY_SUFFIX}",
|
||||||
|
"Target": f"%PREFIX%{TARGETW or TARGET}",
|
||||||
|
"Arguments": r'"%PREFIX%Lib\idlelib\idle.pyw"',
|
||||||
|
"Icon": r"%PREFIX%Lib\idlelib\Icons\idle.ico",
|
||||||
|
"IconIndex": 0,
|
||||||
|
})
|
||||||
|
STD_START[0]["Items"].append({
|
||||||
|
"Name": f"PyDoc {VER_DOT}{DISPLAY_SUFFIX}",
|
||||||
|
"Target": f"%PREFIX%{TARGET}",
|
||||||
|
"Arguments": "-m pydoc -b",
|
||||||
|
"Icon": r"%PREFIX%Lib\idlelib\Icons\idle.ico",
|
||||||
|
"IconIndex": 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
if ns.include_html_doc:
|
||||||
|
STD_PEP514[0]["Help"]["Main Python Documentation"] = {
|
||||||
|
"_": rf"%PREFIX%Doc\html\index.html",
|
||||||
|
}
|
||||||
|
STD_START[0]["Items"].append({
|
||||||
|
"Name": f"{DISPLAY_NAME} {VER_DOT} Manuals{DISPLAY_SUFFIX}",
|
||||||
|
"Target": r"%PREFIX%Doc\html\index.html",
|
||||||
|
})
|
||||||
|
elif ns.include_chm:
|
||||||
|
STD_PEP514[0]["Help"]["Main Python Documentation"] = {
|
||||||
|
"_": rf"%PREFIX%Doc\{PYTHON_CHM_NAME}",
|
||||||
|
}
|
||||||
|
STD_START[0]["Items"].append({
|
||||||
|
"Name": f"{DISPLAY_NAME} {VER_DOT} Manuals{DISPLAY_SUFFIX}",
|
||||||
|
"Target": "%WINDIR%hhc.exe",
|
||||||
|
"Arguments": rf"%PREFIX%Doc\{PYTHON_CHM_NAME}",
|
||||||
|
})
|
||||||
|
|
||||||
|
STD_UNINSTALL.append({
|
||||||
|
"kind": "uninstall",
|
||||||
|
# Other settings will pick up sensible defaults
|
||||||
|
"Publisher": "Python Software Foundation",
|
||||||
|
"HelpLink": f"https://docs.python.org/{VER_DOT}/",
|
||||||
|
})
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"schema": 1,
|
||||||
|
"id": f"{COMPANY.lower()}-{ID_TAG}",
|
||||||
|
"sort-version": FULL_VERSION,
|
||||||
|
"company": COMPANY,
|
||||||
|
"tag": DISPLAY_TAG,
|
||||||
|
"install-for": _not_empty(INSTALL_TAGS),
|
||||||
|
"run-for": _not_empty(STD_RUN_FOR, "tag"),
|
||||||
|
"alias": _not_empty(STD_ALIAS, "name"),
|
||||||
|
"shortcuts": [
|
||||||
|
*STD_PEP514,
|
||||||
|
*STD_START,
|
||||||
|
*STD_UNINSTALL,
|
||||||
|
],
|
||||||
|
"display-name": f"{DISPLAY_NAME} {DISPLAY_VERSION}",
|
||||||
|
"executable": rf".\{TARGET}",
|
||||||
|
"url": f"{URL_BASE}{XYZ_VERSION}/{FILE_PREFIX}{FULL_VERSION}{FILE_SUFFIX}.zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
|
@ -1,12 +1,13 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
|
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
|
||||||
<Window Width="670" Height="412" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
|
<Window Width="670" Height="422" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
|
||||||
<Font Id="0" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
<Font Id="0" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||||
<Font Id="1" Height="-26" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
<Font Id="1" Height="-26" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||||
<Font Id="2" Height="-24" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
<Font Id="2" Height="-24" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
||||||
<Font Id="3" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
<Font Id="3" Height="-14" Weight="500" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||||
<Font Id="4" Height="-14" Weight="500" Foreground="ff0000" Background="ffffff" Underline="yes">Segoe UI</Font>
|
<Font Id="4" Height="-14" Weight="500" Foreground="ff0000" Background="ffffff" Underline="yes">Segoe UI</Font>
|
||||||
<Font Id="5" Height="-14" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
<Font Id="5" Height="-14" Weight="500" Foreground="808080" Background="ffffff">Segoe UI</Font>
|
||||||
|
<Font Id="6" Height="-14" Weight="700" Foreground="000000" Background="ffffff">Segoe UI</Font>
|
||||||
|
|
||||||
<Page Name="Help">
|
<Page Name="Help">
|
||||||
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.HelpHeader)</Text>
|
<Text X="185" Y="11" Width="-11" Height="36" FontId="1" DisablePrefix="yes">#(loc.HelpHeader)</Text>
|
||||||
|
@ -21,8 +22,10 @@
|
||||||
|
|
||||||
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallMessage)</Text>
|
<Text X="185" Y="50" Width="-11" Height="50" FontId="3" TabStop="yes">#(loc.InstallMessage)</Text>
|
||||||
|
|
||||||
<Button Name="InstallButton" X="185" Y="101" Width="-11" Height="109" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
|
<Hypertext X="185" Y="100" Width="-11" Height="40" FontId="6" DisablePrefix="yes">#(loc.DeprecationMessage)</Hypertext>
|
||||||
<Button Name="InstallCustomButton" X="185" Y="221" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallCustomButton)</Button>
|
|
||||||
|
<Button Name="InstallButton" X="185" Y="141" Width="-11" Height="109" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallButton)</Button>
|
||||||
|
<Button Name="InstallCustomButton" X="185" Y="251" Width="-11" Height="59" TabStop="yes" FontId="3" HexStyle="0xE">#(loc.InstallCustomButton)</Button>
|
||||||
|
|
||||||
<Checkbox Name="InstallLauncherAllUsers" X="185" Y="-37" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortInstallLauncherAllUsersLabel)</Checkbox>
|
<Checkbox Name="InstallLauncherAllUsers" X="185" Y="-37" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortInstallLauncherAllUsersLabel)</Checkbox>
|
||||||
<Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
|
<Checkbox Name="PrependPath" X="185" Y="-13" Width="-100" Height="24" TabStop="yes" FontId="3">#(loc.ShortPrependPathLabel)</Checkbox>
|
||||||
|
|
|
@ -128,4 +128,6 @@ Feel free to post at <a href="https://discuss.python.org/c/users/7">discus
|
||||||
Visit <a href="https://www.python.org/downloads/">python.org</a> to download an earlier version of Python.</String>
|
Visit <a href="https://www.python.org/downloads/">python.org</a> to download an earlier version of Python.</String>
|
||||||
<String Id="SuccessMaxPathButton">Disable path length limit</String>
|
<String Id="SuccessMaxPathButton">Disable path length limit</String>
|
||||||
<String Id="SuccessMaxPathButtonNote">Changes your machine configuration to allow programs, including Python, to bypass the 260 character "MAX_PATH" limitation.</String>
|
<String Id="SuccessMaxPathButtonNote">Changes your machine configuration to allow programs, including Python, to bypass the 260 character "MAX_PATH" limitation.</String>
|
||||||
|
|
||||||
|
<String Id="DeprecationMessage">NOTE: This installer is being retired and will no longer be available after Python 3.15. <a href="https://docs.python.org/using/windows">More info</a></String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue