diff --git a/make.py b/make.py index 0be98caa..de329f90 100644 --- a/make.py +++ b/make.py @@ -46,14 +46,13 @@ def build_installer_7zip(script_template_path: Path, output_script_path: Path, r ("PORTABLE_DIR=", f"PORTABLE_DIR={PORTABLE_DIRECTORY}& rem "), ("SEVENZIP_EXE=", f"SEVENZIP_EXE={find_7zip_executable()}& rem "), ] + [(f"{a}=", f"{a}={b}& rem ") for a, b in replacements] - + utils.replace_in_file(script_template_path, data_to_replace, output_script_path) try: # Execute the generated 7-Zip script, with stdout=sys.stderr to see 7zip compressing - command = f'"{output_script_path}"' - print(f"Executing 7-Zip script: {command}") - subprocess.run(command, shell=True, check=True, stderr=sys.stderr, stdout=sys.stderr) + print(f'Executing 7-Zip script: "{output_script_path}"') + subprocess.run(f'"{output_script_path}"', shell=True, check=True, stderr=sys.stderr, stdout=sys.stderr) except subprocess.CalledProcessError as e: print(f"Error executing 7-Zip script: {e}", file=sys.stderr) @@ -76,11 +75,9 @@ def copy_items(source_directories: list[Path], target_directory: Path, verbose: 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: + if not argument_value: return [] - if isinstance(argument_value, str): - return argument_value.split(separator) - return list(argument_value) + return argument_value.split(separator) if isinstance(argument_value, str) else list(argument_value) class WinPythonDistributionBuilder: """Builds a WinPython distribution.""" @@ -163,20 +160,17 @@ def _get_installed_tools_markdown(self) -> str: def get_tool_path(relative_path): path = self.winpython_directory / relative_path if self.winpython_directory else None - return path if path and (path.is_file() or path.is_dir()) else None + return path if path and path.exists() else None if nodejs_path := get_tool_path(self.NODEJS_RELATIVE_PATH): - node_version = utils.get_nodejs_version(nodejs_path) - npm_version = utils.get_npmjs_version(nodejs_path) - installed_tools += [("Nodejs", node_version), ("npmjs", npm_version)] + installed_tools.append(("Nodejs", utils.get_nodejs_version(nodejs_path))) + installed_tools.append(("npmjs", utils.get_npmjs_version(nodejs_path))) - if pandoc_executable := get_tool_path("t/pandoc.exe"): - pandoc_version = utils.get_pandoc_version(str(pandoc_executable.parent)) - installed_tools.append(("Pandoc", pandoc_version)) + if pandoc_exe := get_tool_path("t/pandoc.exe"): + installed_tools.append(("Pandoc", utils.get_pandoc_version(str(pandoc_exe.parent)))) - if vscode_executable := get_tool_path("t/VSCode/Code.exe"): - vscode_version = utils.getFileProperties(str(vscode_executable))["FileVersion"] - installed_tools.append(("VSCode", vscode_version)) + if vscode_exe := get_tool_path("t/VSCode/Code.exe"): + installed_tools.append(("VSCode", utils.getFileProperties(str(vscode_exe))["FileVersion"])) tool_lines = [] for name, version in installed_tools: @@ -187,7 +181,7 @@ def get_tool_path(relative_path): def _get_installed_packages_markdown(self) -> str: """Generates Markdown for installed packages section in package index.""" - if self.distribution is None: + if not self.distribution: return "" # Distribution not initialized yet. self.installed_packages = self.distribution.get_installed_packages(update=True) package_lines = [ @@ -204,25 +198,20 @@ def winpython_version_name(self) -> str: @property def python_full_version(self) -> str: """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) + return utils.get_python_long_version(self.distribution.target) if self.distribution else "0.0.0" @property def python_executable_directory(self) -> str: """Returns the directory containing the Python executable.""" - python_path_directory = self.winpython_directory / self.python_directory_name if self.winpython_directory else None - if python_path_directory and python_path_directory.is_dir(): - return str(python_path_directory) - 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 "" + if self.winpython_directory: + python_path_directory = self.winpython_directory / self.python_directory_name + return str(python_path_directory) if python_path_directory.is_dir() else str(self.winpython_directory / self.python_name) + return "" @property def architecture_bits(self) -> int: """Returns the architecture (32 or 64 bits) of the distribution.""" - if self.distribution: - return self.distribution.architecture - return 64 + return self.distribution.architecture if self.distribution else 64 def create_installer_7zip(self, installer_type: str = ".exe"): """Creates a WinPython installer using 7-Zip: ".exe", ".7z", ".zip")""" @@ -241,7 +230,6 @@ def create_installer_7zip(self, installer_type: str = ".exe"): ("RELEASELEVEL", self.release_level), ("INSTALLER_OPTION", installer_type), ] - build_installer_7zip(PORTABLE_DIRECTORY / template_name, self.target_directory / output_name, replacements) def _print_action(self, text: str): @@ -351,9 +339,9 @@ def build(self, rebuild: bool = True, requirements_files_list=None, winpy_dirnam def rebuild_winpython_package(source_directory: Path, target_directory: Path, architecture: int = 64, verbose: bool = False): """Rebuilds the winpython package from source using flit.""" - for filename in os.listdir(target_directory): - if filename.startswith("winpython-") and filename.endswith((".exe", ".whl", ".gz")): - os.remove(Path(target_directory) / filename) + for file in target_directory.glob("winpython-*"): + if file.suffix in (".exe", ".whl", ".gz"): + file.unlink() 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, @@ -391,14 +379,14 @@ def make_all(build_number: int, release_level: str, pyver: str, architecture: in find_links_dirs_list = parse_list_argument(find_links, ",") requirements_files_list = [Path(f) for f in parse_list_argument(requirements, ",") if f] find_links_options = [f"--find-links={link}" for link in find_links_dirs_list + [source_dirs]] - build_directory = str(Path(basedir) / ("bu" + flavor)) + build_directory = Path(basedir) / ("bu" + flavor) if rebuild: utils.print_box(f"Making WinPython {architecture}bits at {Path(basedir) / ('bu' + flavor)}") - os.makedirs(Path(build_directory), exist_ok=True) + os.makedirs(build_directory, exist_ok=True) # use source_dirs as the directory to re-build Winpython wheel winpython_source_dir = Path(__file__).resolve().parent - rebuild_winpython_package(winpython_source_dir, source_dirs, architecture, verbose) + rebuild_winpython_package(winpython_source_dir, Path(source_dirs), architecture, verbose) builder = WinPythonDistributionBuilder( build_number, release_level, build_directory, wheels_directory=source_dirs, @@ -420,11 +408,11 @@ def make_all(build_number: int, release_level: str, pyver: str, architecture: in builder.build(rebuild=rebuild, requirements_files_list=requirements_files_list, winpy_dirname=winpython_dirname) - if ".zip" in str(create_installer).lower(): + if ".zip" in create_installer.lower(): builder.create_installer_7zip(".zip") - if ".7z" in str(create_installer).lower(): + if ".7z" in create_installer.lower(): builder.create_installer_7zip(".7z") - if "7zip" in str(create_installer).lower(): + if "7zip" in create_installer.lower(): builder.create_installer_7zip(".exe") if __name__ == "__main__": diff --git a/winpython/utils.py b/winpython/utils.py index 523b6fa0..324403cc 100644 --- a/winpython/utils.py +++ b/winpython/utils.py @@ -213,7 +213,6 @@ def patch_shebang_line(fname, pad=b" ", to_movable=True, targetdir=""): """Remove absolute path to python.exe in shebang lines in binary files, or re-add it.""" target_dir = targetdir if to_movable else os.path.abspath(os.path.join(os.path.dirname(fname), r"..")) + "\\" executable = sys.executable - shebang_line = re.compile(rb"""(#!.*pythonw?\.exe)"?""") # Python3+ if "pypy3" in sys.executable: shebang_line = re.compile(rb"""(#!.*pypy3w?\.exe)"?""") # Pypy3+ @@ -239,12 +238,9 @@ def patch_shebang_line(fname, pad=b" ", to_movable=True, targetdir=""): def patch_shebang_line_py(fname, to_movable=True, targetdir=""): """Changes shebang line in '.py' file to relative or absolue path""" import fileinput - if to_movable: - exec_path = r'#!.\python.exe' - if 'pypy3' in sys.executable: # PyPy ! - exec_path = r'#!.\pypy3.exe' - else: - exec_path = '#!' + sys.executable + exec_path = r'#!.\python.exe' if to_movable else '#!' + sys.executable + if 'pypy3' in sys.executable: + exec_path = r'#!.\pypy3.exe' if to_movable else exec_path for line in fileinput.input(fname, inplace=True): if re.match(r'^#\!.*python\.exe$', line) or re.match(r'^#\!.*pypy3\.exe$', line): print(exec_path) @@ -253,18 +249,16 @@ def patch_shebang_line_py(fname, to_movable=True, targetdir=""): def guess_encoding(csv_file): """guess the encoding of the given file""" - # UTF_8_BOM = "\xEF\xBB\xBF" with open(csv_file, "rb") as f: data = f.read(5) if data.startswith(b"\xEF\xBB\xBF"): # UTF-8 with a "BOM" (normally no BOM in utf-8) return ["utf-8-sig"] - else: # in Windows, guessing utf-8 doesn't work, so we have to try - try: - with open(csv_file, encoding="utf-8") as f: - preview = f.read(222222) - return ["utf-8"] - except: - return [locale.getdefaultlocale()[1], "utf-8"] + try: + with open(csv_file, encoding="utf-8") as f: + preview = f.read(222222) + return ["utf-8"] + except: + return [locale.getdefaultlocale()[1], "utf-8"] def replace_in_file(filepath: Path, replacements: list[tuple[str, str]], filedest: Path = None, verbose=False): """ @@ -290,9 +284,9 @@ def replace_in_file(filepath: Path, replacements: list[tuple[str, str]], filedes def patch_sourcefile(fname, in_text, out_text, silent_mode=False): """Replace a string in a source file.""" if not silent_mode: - print(f"patching {fname} from {in_text} to {out_text}") - if Path(fname).is_file() and not in_text == out_text: - replace_in_file(Path(fname), [(in_text , out_text)]) + print(f"patching {fname} from {in_text} to {out_text}") + if Path(fname).is_file() and in_text != out_text: + replace_in_file(Path(fname), [(in_text, out_text)]) def _create_temp_dir(): """Create a temporary directory and remove it at exit""" @@ -324,7 +318,7 @@ def get_source_package_infos(fname): def buildflit_wininst(root, python_exe=None, copy_to=None, verbose=False): """Build Wheel from Python package located in *root* with flit.""" python_exe = python_exe or sys.executable - cmd = [python_exe, '-m' ,'flit', 'build'] + cmd = [python_exe, '-m', 'flit', 'build'] if verbose: subprocess.call(cmd, cwd=root) else: @@ -362,7 +356,7 @@ def direct_pip_install(fname, python_exe=None, verbose=False, install_options=No python_exe = python_exe or sys.executable myroot = str(Path(python_exe).parent) - cmd = [python_exe, "-m", "pip", "install"] + (install_options or []) +[fname] + cmd = [python_exe, "-m", "pip", "install"] + (install_options or []) + [fname] if not verbose: process = subprocess.Popen(cmd, cwd=myroot, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() @@ -416,7 +410,7 @@ def get_package_metadata(database, name): db = cp.ConfigParser() filepath = Path(database) if Path(database).is_absolute() else Path(DATA_PATH) / database db.read_file(open(str(filepath), encoding=guess_encoding(filepath)[0])) - + my_metadata = { "description": "", "url": f"https://pypi.org/project/{name}", diff --git a/winpython/wppm.py b/winpython/wppm.py index 71486b94..397188f9 100644 --- a/winpython/wppm.py +++ b/winpython/wppm.py @@ -144,12 +144,12 @@ def patch_standard_packages(self, package_name="", to_movable=True): import filecmp # 'pywin32' minimal post-install (pywin32_postinstall.py do too much) - if package_name.lower() == "pywin32" or package_name == "": + if package_name.lower() in ("", "pywin32"): origin = Path(self.target) / "site-packages" / "pywin32_system32" destin = Path(self.target) if origin.is_dir(): for name in os.listdir(origin): - here, there = (origin / name), (destin / name) + here, there = origin / name, destin / name if not there.exists() or not filecmp.cmp(here, there): shutil.copyfile(here, there) # 'pip' to do movable launchers (around line 100) !!!! @@ -162,7 +162,7 @@ def patch_standard_packages(self, package_name="", to_movable=True): sheb_mov1 = " executable = os.path.join(os.path.basename(get_executable()))" sheb_mov2 = " executable = os.path.join('..',os.path.basename(get_executable()))" - the_place = Path(self.target ) / "lib" / "site-packages" / "pip" / "_vendor" / "distlib" / "scripts.py" + the_place = Path(self.target) / "lib" / "site-packages" / "pip" / "_vendor" / "distlib" / "scripts.py" print(the_place) if to_movable: utils.patch_sourcefile(the_place, sheb_fix, sheb_mov1) @@ -173,7 +173,7 @@ def patch_standard_packages(self, package_name="", to_movable=True): # create movable launchers for previous package installations self.patch_all_shebang(to_movable=to_movable) - if package_name.lower() == "spyder" or package_name == "": + if package_name.lower() in ("", "spyder"): # spyder don't goes on internet without I ask utils.patch_sourcefile( Path(self.target) / "lib" / "site-packages" / "spyder" / "config" /"main.py", @@ -202,14 +202,13 @@ def handle_specific_packages(self, package): "%WINPYDIR%\python.exe" "%WINPYDIR%\Lib\site-packages\package.name\uic\pyuic.py" %1 %2 %3 %4 %5 %6 %7 %8 %9""" # PyPy adaption: python.exe or pypy3.exe my_exec = Path(utils.get_python_executable(self.target)).name - tmp_string = tmp_string.replace("python.exe", my_exec) - self.create_file(package, f"pyuic{package.name[-1]}.bat", "Scripts", tmp_string.replace("package.name", package.name)) + tmp_string = tmp_string.replace("python.exe", my_exec).replace("package.name", package.name) + self.create_file(package, f"pyuic{package.name[-1]}.bat", "Scripts", tmp_string) # Adding missing __init__.py files (fixes Issue 8) uic_path = str(Path("Lib") / "site-packages" / package.name / "uic") for dirname in ("Loader", "port_v2", "port_v3"): self.create_file(package, "__init__.py", str(Path(uic_path) / dirname), "") - def _print(self, package: Package, action: str): """Print package-related action text.""" text = f"{action} {package.name} {package.version}" @@ -232,7 +231,6 @@ def uninstall(self, package): subprocess.call([this_exec, "-m", "pip", "uninstall", package.name, "-y"], cwd=self.target) self._print_done() - def install_bdist_direct(self, package, install_options=None): """Install a package directly !""" self._print(package,f"Installing {package.fname.split('.')[-1]}") @@ -250,22 +248,17 @@ def install_bdist_direct(self, package, install_options=None): package = Package(fname) self._print_done() - def main(test=False): if test: - sbdir = str(Path(__file__).parents[0].parent.parent.parent / "sandbox") - tmpdir = str(Path(sbdir) / "tobedeleted") - - fname = str(Path(sbdir) / "VTK-5.10.0-Qt-4.7.4.win32-py2.7.exe") - print(Package(fname)) + sbdir = Path(__file__).parents[0].parent.parent.parent / "sandbox" + tmpdir = sbdir / "tobedeleted" + fname = sbdir / "VTK-5.10.0-Qt-4.7.4.win32-py2.7.exe") + print(Package(str(fname))) sys.exit() - target = str( - Path(utils.BASE_DIR) / "build" / "winpython-2.7.3" / "python-2.7.3" - ) - fname = str(Path(utils.BASE_DIR) / "packages.src" / "docutils-0.9.1.tar.gz") - - dist = Distribution(target, verbose=True) - pack = Package(fname) + target = Path(utils.BASE_DIR) / "build" / "winpython-2.7.3" / "python-2.7.3" + fname = Path(utils.BASE_DIR) / "packages.src" / "docutils-0.9.1.tar.gz" + dist = Distribution(str(target), verbose=True) + pack = Package(str(fname)) print(pack.description) # dist.install(pack) # dist.uninstall(pack)