mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			81 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Extract version information from Include/patchlevel.h."""
 | 
						|
 | 
						|
import re
 | 
						|
import sys
 | 
						|
from pathlib import Path
 | 
						|
from typing import Literal, NamedTuple
 | 
						|
 | 
						|
CPYTHON_ROOT = Path(
 | 
						|
    __file__,  # cpython/Doc/tools/extensions/patchlevel.py
 | 
						|
    "..",  # cpython/Doc/tools/extensions
 | 
						|
    "..",  # cpython/Doc/tools
 | 
						|
    "..",  # cpython/Doc
 | 
						|
    "..",  # cpython
 | 
						|
).resolve()
 | 
						|
PATCHLEVEL_H = CPYTHON_ROOT / "Include" / "patchlevel.h"
 | 
						|
 | 
						|
RELEASE_LEVELS = {
 | 
						|
    "PY_RELEASE_LEVEL_ALPHA": "alpha",
 | 
						|
    "PY_RELEASE_LEVEL_BETA": "beta",
 | 
						|
    "PY_RELEASE_LEVEL_GAMMA": "candidate",
 | 
						|
    "PY_RELEASE_LEVEL_FINAL": "final",
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class version_info(NamedTuple):  # noqa: N801
 | 
						|
    major: int  #: Major release number
 | 
						|
    minor: int  #: Minor release number
 | 
						|
    micro: int  #: Patch release number
 | 
						|
    releaselevel: Literal["alpha", "beta", "candidate", "final"]
 | 
						|
    serial: int  #: Serial release number
 | 
						|
 | 
						|
 | 
						|
def get_header_version_info() -> version_info:
 | 
						|
    # Capture PY_ prefixed #defines.
 | 
						|
    pat = re.compile(r"\s*#define\s+(PY_\w*)\s+(\w+)", re.ASCII)
 | 
						|
 | 
						|
    defines = {}
 | 
						|
    patchlevel_h = PATCHLEVEL_H.read_text(encoding="utf-8")
 | 
						|
    for line in patchlevel_h.splitlines():
 | 
						|
        if (m := pat.match(line)) is not None:
 | 
						|
            name, value = m.groups()
 | 
						|
            defines[name] = value
 | 
						|
 | 
						|
    return version_info(
 | 
						|
        major=int(defines["PY_MAJOR_VERSION"]),
 | 
						|
        minor=int(defines["PY_MINOR_VERSION"]),
 | 
						|
        micro=int(defines["PY_MICRO_VERSION"]),
 | 
						|
        releaselevel=RELEASE_LEVELS[defines["PY_RELEASE_LEVEL"]],
 | 
						|
        serial=int(defines["PY_RELEASE_SERIAL"]),
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def format_version_info(info: version_info) -> tuple[str, str]:
 | 
						|
    version = f"{info.major}.{info.minor}"
 | 
						|
    release = f"{info.major}.{info.minor}.{info.micro}"
 | 
						|
    if info.releaselevel != "final":
 | 
						|
        suffix = {"alpha": "a", "beta": "b", "candidate": "rc"}
 | 
						|
        release += f"{suffix[info.releaselevel]}{info.serial}"
 | 
						|
    return version, release
 | 
						|
 | 
						|
 | 
						|
def get_version_info():
 | 
						|
    try:
 | 
						|
        info = get_header_version_info()
 | 
						|
        return format_version_info(info)
 | 
						|
    except OSError:
 | 
						|
        version, release = format_version_info(sys.version_info)
 | 
						|
        print(
 | 
						|
            f"Failed to get version info from Include/patchlevel.h, "
 | 
						|
            f"using version of this interpreter ({release}).",
 | 
						|
            file=sys.stderr,
 | 
						|
        )
 | 
						|
        return version, release
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    short_ver, full_ver = format_version_info(get_header_version_info())
 | 
						|
    if sys.argv[1:2] == ["--short"]:
 | 
						|
        print(short_ver)
 | 
						|
    else:
 | 
						|
        print(full_ver)
 |