| 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 |
| ALIAS_WPREFIX = 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("free-threaded") |
| 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 |
| # Tag used for PEP 514 registration |
| SYS_WINVER = XY_TAG + (TAG_ARCH if TAG_ARCH != '-64' else '') |
| |
| 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. |
| for prefix, base in ( |
| (ALIAS_PREFIX, {"target": TARGET}), |
| (ALIAS_WPREFIX, {"target": TARGETW, "windowed": 1}), |
| ): |
| if not prefix: |
| continue |
| 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"}, |
| ]) |
| |
| if SYS_WINVER: |
| STD_PEP514.append({ |
| "kind": "pep514", |
| "Key": rf"{COMPANY}\{SYS_WINVER}", |
| "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 and STD_PEP514: |
| STD_PEP514[0]["InstallPath"]["WindowedExecutablePath"] = f"%PREFIX%{TARGETW}" |
| |
| if ns.include_idle: |
| STD_START[0]["Items"].append({ |
| "Name": f"IDLE (Python {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 (Python {VER_DOT}{DISPLAY_SUFFIX})", |
| "Target": f"%PREFIX%{TARGET}", |
| "Arguments": "-m pydoc -b", |
| "Icon": r"%PREFIX%Lib\idlelib\Icons\idle.ico", |
| "IconIndex": 0, |
| }) |
| if STD_PEP514: |
| STD_PEP514[0]["InstallPath"]["IdlePath"] = f"%PREFIX%Lib\\idlelib\\idle.pyw" |
| |
| 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 |