From 6e7d16ba363a35b7d76a66b54ff1be6cbe170c70 Mon Sep 17 00:00:00 2001 From: stonebig Date: Sun, 23 Mar 2025 09:30:56 +0100 Subject: [PATCH 1/4] walrus a bit --- make.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/make.py b/make.py index 45b36f21..e6672d7a 100644 --- a/make.py +++ b/make.py @@ -34,8 +34,7 @@ def find_7zip_executable() -> str: Path(sys.prefix).parent / "t" , ] for base_dir in possible_program_files: - executable_path = base_dir / "7-Zip" / "7z.exe" - if executable_path.is_file(): + if (executable_path := base_dir / "7-Zip" / "7z.exe").is_file(): return str(executable_path) raise RuntimeError("7ZIP is not installed on this computer.") @@ -180,9 +179,8 @@ def __init__( def _get_python_zip_file(self) -> Path: """Finds the Python .zip file in the wheels directory.""" - pattern = r"(pypy3|python-)([0-9]|[a-zA-Z]|.)*.zip" for filename in os.listdir(self.wheels_directory): - if re.match(pattern, filename): + if re.match("(pypy3|python-)([0-9]|[a-zA-Z]|.)*.zip", filename): return self.wheels_directory / filename raise RuntimeError(f"Could not find Python zip package in {self.wheels_directory}") @@ -305,8 +303,7 @@ def pre_path_entries(self) -> list[str]: @property def documentation_directories_list(self) -> list[Path]: """Returns the list of documentation directories to include.""" - default_docs_directory = Path(__file__).resolve().parent / "docs" - if default_docs_directory.is_dir(): + if (default_docs_directory := Path(__file__).parent / "docs").is_dir(): return [default_docs_directory] + self.documentation_directories return self.documentation_directories @@ -371,7 +368,7 @@ def _copy_essential_files(self): tools_target_directory = self.winpython_directory / "t" self._print_action(f"Copying tools to {tools_target_directory}") - _copy_items(self.tools_directories, self.winpython_directory / "t", self.verbose) + _copy_items(self.tools_directories, tools_target_directory, self.verbose) # Special handling for Node.js to move it up one level nodejs_current_directory = tools_target_directory / "n" From 942872c8db11916799fe8594606086dc9afd33d6 Mon Sep 17 00:00:00 2001 From: stonebig Date: Sun, 23 Mar 2025 09:45:49 +0100 Subject: [PATCH 2/4] simplify further --- make.py | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/make.py b/make.py index e6672d7a..62a2c8a0 100644 --- a/make.py +++ b/make.py @@ -25,7 +25,6 @@ assert CHANGELOGS_DIRECTORY.is_dir(), f"Changelogs directory not found: {CHANGELOGS_DIRECTORY}" assert PORTABLE_DIRECTORY.is_dir(), f"Portable directory not found: {PORTABLE_DIRECTORY}" - def find_7zip_executable() -> str: """Locates the 7-Zip executable (7z.exe).""" possible_program_files = [ @@ -38,7 +37,6 @@ def find_7zip_executable() -> str: return str(executable_path) raise RuntimeError("7ZIP is not installed on this computer.") - def replace_lines_in_file(filepath: Path, replacements: list[tuple[str, str]]): """ Replaces lines in a file that start with a given prefix. @@ -98,10 +96,8 @@ def build_installer_7zip(script_template_path: Path, output_script_path: Path, r except subprocess.CalledProcessError as e: print(f"Error executing 7-Zip script: {e}", file=sys.stderr) - def _copy_items(source_directories: list[Path], target_directory: Path, verbose: bool = False): """Copies items from source directories to the target directory.""" - target_directory.mkdir(parents=True, exist_ok=True) for source_dir in source_directories: if not source_dir.is_dir(): @@ -118,7 +114,6 @@ def _copy_items(source_directories: list[Path], target_directory: Path, verbose: except Exception as e: print(f"Error copying {source_item} to {target_item}: {e}") - def _parse_list_argument(argument_value: str | list[str], separator=" ") -> list[str]: """Parse a separated list argument into a list of strings.""" if argument_value is None: @@ -127,7 +122,6 @@ def _parse_list_argument(argument_value: str | list[str], separator=" ") -> list return argument_value.split(separator) return list(argument_value) - class WinPythonDistributionBuilder: """Builds a WinPython distribution.""" @@ -163,19 +157,19 @@ def __init__( """ self.build_number = build_number self.release_level = release_level - self.target_directory = Path(target_directory) # Ensure Path object - self.wheels_directory = Path(wheels_directory) # Ensure Path object + self.target_directory = Path(target_directory) + self.wheels_directory = Path(wheels_directory) self.tools_directories = tools_directories or [] self.documentation_directories = documentation_directories or [] self.verbose = verbose - self.winpython_directory: Path | None = None # Will be set during build - self.distribution: wppm.Distribution | None = None # Will be set during build + self.winpython_directory: Path | None = None + self.distribution: wppm.Distribution | None = None self.base_directory = base_directory self.install_options = install_options or [] self.flavor = flavor self.python_zip_file: Path = self._get_python_zip_file() - self.python_name = self.python_zip_file.stem # Filename without extension - self.python_directory_name = "python" # Standardized Python directory name + self.python_name = self.python_zip_file.stem + self.python_directory_name = "python" def _get_python_zip_file(self) -> Path: """Finds the Python .zip file in the wheels directory.""" @@ -263,10 +257,7 @@ def winpython_version_name(self) -> str: @property def python_full_version(self) -> str: - """ - Retrieves the Python full version string from the distribution. - Will be set after _extract_python is called and distribution is initialized. - """ + """Retrieves the Python full version string from the distribution.""" if self.distribution is None: return "0.0.0" # Placeholder before initialization return utils.get_python_long_version(self.distribution.target) @@ -286,7 +277,7 @@ def architecture_bits(self) -> int: """Returns the architecture (32 or 64 bits) of the distribution.""" if self.distribution: return self.distribution.architecture - return 64 # Default to 64 if distribution is not initialized yet + return 64 @property def pre_path_entries(self) -> list[str]: @@ -308,14 +299,10 @@ def documentation_directories_list(self) -> list[Path]: return self.documentation_directories def create_installer_7zip(self, installer_type: str = ".exe"): - """ - Creates a WinPython installer using 7-Zip. - - Args: installer_type: Type of installer to create (".exe", ".7z", ".zip"). - """ + """Creates a WinPython installer using 7-Zip: ".exe", ".7z", ".zip")""" self._print_action(f"Creating WinPython installer ({installer_type})") template_name = "installer_7zip.bat" - output_name = "installer_7zip-tmp.bat" # temp file to avoid overwriting template + output_name = "installer_7zip-tmp.bat" if installer_type not in [".exe", ".7z", ".zip"]: print(f"Warning: Unsupported installer type '{installer_type}'. Defaulting to .exe") installer_type = ".exe" @@ -326,14 +313,10 @@ def create_installer_7zip(self, installer_type: str = ".exe"): ("VERSION", f"{self.python_full_version}.{self.build_number}{self.flavor}"), ("VERSION_INSTALL", f'{self.python_full_version.replace(".", "")}{self.build_number}'), ("RELEASELEVEL", self.release_level), - ("INSTALLER_OPTION", installer_type), # Pass installer type as option to bat script + ("INSTALLER_OPTION", installer_type), ] - build_installer_7zip( - PORTABLE_DIRECTORY / template_name, - PORTABLE_DIRECTORY / output_name, - replacements - ) + build_installer_7zip(PORTABLE_DIRECTORY / template_name, PORTABLE_DIRECTORY / output_name, replacements) def _print_action(self, text: str): """Prints an action message with progress indicator.""" From a496b25f5a2b7e778eece9b5312fc9017f8211a9 Mon Sep 17 00:00:00 2001 From: stonebig Date: Sun, 23 Mar 2025 12:50:10 +0100 Subject: [PATCH 3/4] remove un-needed documentation_directories_list() complexity --- make.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/make.py b/make.py index 62a2c8a0..38dbdfdd 100644 --- a/make.py +++ b/make.py @@ -30,7 +30,7 @@ def find_7zip_executable() -> str: possible_program_files = [ Path(r"C:\Program Files"), Path(r"C:\Program Files (x86)"), - Path(sys.prefix).parent / "t" , + Path(sys.prefix).parent / "t", ] for base_dir in possible_program_files: if (executable_path := base_dir / "7-Zip" / "7z.exe").is_file(): @@ -291,13 +291,6 @@ def pre_path_entries(self) -> list[str]: r".." + self.NODEJS_RELATIVE_PATH, ] - @property - def documentation_directories_list(self) -> list[Path]: - """Returns the list of documentation directories to include.""" - if (default_docs_directory := Path(__file__).parent / "docs").is_dir(): - return [default_docs_directory] + self.documentation_directories - return self.documentation_directories - def create_installer_7zip(self, installer_type: str = ".exe"): """Creates a WinPython installer using 7-Zip: ".exe", ".7z", ".zip")""" self._print_action(f"Creating WinPython installer ({installer_type})") @@ -347,7 +340,7 @@ def _copy_essential_files(self): docs_target_directory = self.winpython_directory / "notebooks" / "docs" self._print_action(f"Copying documentation to {docs_target_directory}") - _copy_items(self.documentation_directories_list, docs_target_directory, self.verbose) + _copy_items(self.documentation_directories, docs_target_directory, self.verbose) tools_target_directory = self.winpython_directory / "t" self._print_action(f"Copying tools to {tools_target_directory}") From 1d31d51914fbd238b85f5095dd36ebc7f9d46e13 Mon Sep 17 00:00:00 2001 From: stonebig Date: Sun, 23 Mar 2025 14:43:13 +0100 Subject: [PATCH 4/4] simplify --- make.py | 102 +++++++++++++++++++++----------------------------------- 1 file changed, 38 insertions(+), 64 deletions(-) diff --git a/make.py b/make.py index 38dbdfdd..f0b5f2c2 100644 --- a/make.py +++ b/make.py @@ -127,19 +127,9 @@ class WinPythonDistributionBuilder: NODEJS_RELATIVE_PATH = r"\n" # Relative path within WinPython dir - def __init__( - self, - build_number: int, - release_level: str, - target_directory: Path, - wheels_directory: Path, - tools_directories: list[Path] = None, - documentation_directories: list[Path] = None, - verbose: bool = False, - base_directory: Path = None, - install_options: list[str] = None, - flavor: str = "", - ): + def __init__(self, build_number: int, release_level: str, target_directory: Path, wheels_directory: Path, + tools_directories: list[Path] = None, documentation_directories: list[Path] = None, verbose: bool = False, + base_directory: Path = None, install_options: list[str] = None, flavor: str = ""): """ Initializes the WinPythonDistributionBuilder. @@ -269,7 +259,7 @@ def python_executable_directory(self) -> str: if python_path_directory and python_path_directory.is_dir(): return str(python_path_directory) else: - python_path_executable = self.winpython_directory / self.python_name if self.winpython_directory else None # Fallback for older structure + python_path_executable = self.winpython_directory / self.python_name if self.winpython_directory else None return str(python_path_executable) if python_path_executable else "" @property @@ -321,15 +311,12 @@ def _print_action(self, text: str): def _extract_python_archive(self): """Extracts the Python zip archive to create the base Python environment.""" self._print_action("Extracting Python archive") - utils.extract_archive( - str(self.python_zip_file), - targetdir=str(self.winpython_directory), # Extract directly to winpython_directory - ) + utils.extract_archive(self.python_zip_file, self.winpython_directory) # Relocate to /python subfolder if needed (for newer structure) #2024-12-22 to /python expected_python_directory = self.winpython_directory / self.python_directory_name if self.python_directory_name != self.python_name and not expected_python_directory.is_dir(): os.rename(self.winpython_directory / self.python_name, expected_python_directory) - + def _copy_essential_files(self): """Copies pre-made objects""" self._print_action("Copying default scripts") @@ -347,11 +334,9 @@ def _copy_essential_files(self): _copy_items(self.tools_directories, tools_target_directory, self.verbose) # Special handling for Node.js to move it up one level - nodejs_current_directory = tools_target_directory / "n" - nodejs_target_directory = self.winpython_directory / self.NODEJS_RELATIVE_PATH - if nodejs_current_directory != nodejs_target_directory and nodejs_current_directory.is_dir(): + if (nodejs_current_directory := tools_target_directory / "n").is_dir(): try: - shutil.move(nodejs_current_directory, nodejs_target_directory) + shutil.move(nodejs_current_directory, self.winpython_directory / self.NODEJS_RELATIVE_PATH) except Exception as e: print(f"Error moving Node.js directory: {e}") @@ -380,14 +365,13 @@ def _create_initial_batch_scripts(self): def build(self, rebuild: bool = True, requirements_files_list=None, winpy_dirname: str = None): """Make or finalise WinPython distribution in the target directory""" - - python_zip_filename = self.python_zip_file.name - print(f"Building WinPython with Python archive: {python_zip_filename}") + print(f"Building WinPython with Python archive: {self.python_zip_file.name}") if winpy_dirname is None: raise RuntimeError("WinPython base directory to create is undefined") else: self.winpython_directory = self.target_directory / winpy_dirname # Create/re-create the WinPython base directory + if rebuild: self._print_action(f"Creating WinPython {self.winpython_directory} base directory") if self.winpython_directory.is_dir(): @@ -448,37 +432,32 @@ def rebuild_winpython_package(source_directory: Path, target_directory: Path, ar utils.buildflit_wininst(source_directory, copy_to=target_directory, verbose=verbose) -def make_all( - build_number: int, - release_level: str, - pyver: str, - architecture: int, - basedir: Path, - verbose: bool = False, - rebuild: bool = True, - create_installer: str = "True", - install_options=["--no-index"], - flavor: str = "", - requirements: str | list[Path] = None, - find_links: str | list[Path] = None, - source_dirs: Path = None, - toolsdirs: str | list[Path] = None, - docsdirs: str | list[Path] = None, - python_target_release: str = None, # e.g. "37101" for 3.7.10 +def make_all(build_number: int, release_level: str, pyver: str, architecture: int, basedir: Path, + verbose: bool = False, rebuild: bool = True, create_installer: str = "True", install_options=["--no-index"], + flavor: str = "", requirements: str | list[Path] = None, find_links: str | list[Path] = None, + source_dirs: Path = None, toolsdirs: str | list[Path] = None, docsdirs: str | list[Path] = None, + python_target_release: str = None, # e.g. "37101" for 3.7.10 ): - """Make a WinPython distribution for a given set of parameters: - `build_number`: build number [int] - `release_level`: release level (e.g. 'beta1', '') [str] - `pyver`: python version ('3.4' or 3.5') - `architecture`: [int] (32 or 64) - `basedir`: where to create the build (r'D:\Winpython\basedir34') - `requirements`: package lists for pip (r'D:\requirements.txt') - `install_options`: pip options (r'--no-index --pre --trusted-host=None') - `find_links`: package directories (r'D:\Winpython\packages.srcreq') - `source_dirs`: the python.zip + rebuilt winpython wheel package directory - `toolsdirs`: r'D:\WinPython\basedir34\t.Slim' - `docsdirs`: r'D:\WinPython\basedir34\docs.Slim'""" - + """ + Make a WinPython distribution for a given set of parameters: + Args: + build_number: build number [int] + release_level: release level (e.g. 'beta1', '') [str] + pyver: python version ('3.4' or 3.5') + architecture: [int] (32 or 64) + basedir: where to create the build (r'D:\Winpython\basedir34') + verbose: Enable verbose output (bool). + rebuild: Whether to rebuild the distribution (bool). + create_installer: Type of installer to create (str). + install_options: pip options (r'--no-index --pre --trusted-host=None') + flavor: WinPython flavor (str). + requirements: package lists for pip (r'D:\requirements.txt') + find_links: package directories (r'D:\Winpython\packages.srcreq') + source_dirs: the python.zip + rebuilt winpython wheel package directory + toolsdirs: Directory with development tools r'D:\WinPython\basedir34\t.Slim' + docsdirs: Directory with documentation r'D:\WinPython\basedir34\docs.Slim' + python_target_release: Target Python release (str). + """ assert basedir is not None, "The *basedir* directory must be specified" assert architecture in (32, 64) @@ -492,7 +471,6 @@ def make_all( build_directory = str(Path(basedir) / ("bu" + flavor)) if rebuild: - # Rebuild Winpython Wheel Package utils.print_box(f"Making WinPython {architecture}bits at {Path(basedir) / ('bu' + flavor)}") os.makedirs(Path(build_directory), exist_ok=True) # use source_dirs as the directory to re-build Winpython wheel @@ -500,16 +478,12 @@ def make_all( rebuild_winpython_package(winpython_source_dir, source_dirs, architecture, verbose) builder = WinPythonDistributionBuilder( - build_number, - release_level, - build_directory, - wheels_directory=source_dirs, + build_number, release_level, build_directory, wheels_directory=source_dirs, tools_directories=[Path(d) for d in tools_dirs_list], documentation_directories=[Path(d) for d in docs_dirs_list], - verbose=verbose, - base_directory=basedir, + verbose=verbose, base_directory=basedir, install_options=install_options_list + find_links_options, - flavor=flavor, + flavor=flavor ) # define the directory where to create the distro python_minor_version_str = "".join(builder.python_name.replace(".amd64", "").split(".")[-2:-1])