Skip to content

the end of suffering #1615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 67 additions & 22 deletions generate_a_winpython_distro.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ rem generate_a_winpython_distro.bat: to be launched from a winpython directory,
@echo on

REM Initialize variables
if "%my_release_level%"=="" set my_release_level=b2
if "%my_release_level%"=="" set my_release_level=b3
if "%my_create_installer%"=="" set my_create_installer=True

rem Set archive directory and log file
Expand Down Expand Up @@ -101,21 +101,47 @@ echo -------------------------------------- >>%my_archive_log%
python -m pip install -r %my_requirements% -c %my_constraints% --pre --no-index --trusted-host=None --find-links=%my_find_links% >>%my_archive_log%
python -c "from winpython import wppm;dist=wppm.Distribution(r'%WINPYDIR%');dist.patch_standard_packages('spyder', to_movable=True)"

REM Archive success
REM Add Wheelhouse (to replace per pip lock direct ? would allow paralellism)
echo -------------------------------------- >>%my_archive_log%
echo "(%date% %time%) Archive success">>%my_archive_log%
echo "(%date% %time%) Add lockfile wheels">>%my_archive_log%
echo -------------------------------------- >>%my_archive_log%
%target_python_exe% -m pip freeze > %my_archive_log%.packages_versions.txt

REM Generate changelog and binaries
echo "(%date% %time%) Generate changelog and binaries">>%my_archive_log%
set path=%my_original_path%
cd /D %~dp0
call %my_buildenv%\scripts\env.bat
python.exe -c "from make import *;make_all(%my_release%, '%my_release_level%', pyver='%my_pyver%', basedir=r'%my_basedir%', verbose=True, architecture=%my_arch%, flavor='%my_flavor%', install_options=r'%my_install_options%', find_links=r'%my_find_links%', source_dirs=r'%my_source_dirs%', create_installer='%my_create_installer%', rebuild=False, python_target_release='%my_python_target_release%')" >> %my_archive_log%
@echo on
call %my_WINPYDIRBASE%\scripts\env.bat
@echo on
set WINPYVERLOCK=%WINPYVER2:.=_%
set pylockinclude=%my_root_dir_for_builds%\bd%my_python_target%\bu%addlockfile%\pylock.%addlockfile%-%WINPYARCH%bit-%WINPYVERLOCK%.toml
echo pylockinclude="%pylockinclude%"
if not "Z%addlockfile%Z"=="ZZ" if exist "%pylockinclude%" (
echo %my_WINPYDIRBASE%\python\scripts\wppm.exe "%pylockinclude%" -ws "%my_find_links%" -wd "%my_WINPYDIRBASE%\wheelhouse\included.wheels">>%my_archive_log%
%my_WINPYDIRBASE%\python\scripts\wppm.exe "%pylockinclude%" -ws "%my_find_links%" -wd "%my_WINPYDIRBASE%\wheelhouse\included.wheels"
)

echo -------------------------------------- >>%my_archive_log%
echo "(%date% %time%) generate pylock.tomle files and requirement_with_hash.txt files">>%my_archive_log%
@echo on
echo wheelhousereq=%wheelhousereq%
set LOCKDIR=%WINPYDIRBASE%\..\
set pip_lock_includedlocal=%LOCKDIR%pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_includedwheelslocal.toml
set pip_lock_includedweb=%LOCKDIR%pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_includedwheels.toml
set req_lock_includedlocal=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_includedwheelslocal.txt
set req_lock_includedweb=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_includedwheels.txt

if not "Z%wheelhousereq%Z"=="ZZ" if exist "%wheelhousereq%" (
echo JOYYYwheelhousereq=%wheelhousereq%
echo z%pip_lock_includedlocal%z=%pip_lock_includedlocal%
rem no winpython in it naturally, with deps
python.exe -m pip lock --no-index --trusted-host=None --find-links=%my_find_links% -c C:\WinP\constraints.txt -r "%wheelhousereq%" -o %pip_lock_includedlocal%
rem generating also classic requirement with hash-256, from obtained pylock.toml
python.exe -c "from winpython import wheelhouse as wh;wh.pylock_to_req(r'%pip_lock_includedlocal%', r'%req_lock_includedlocal%')"

rem same with frozen web from local
python.exe -m pip lock --no-deps --require-hashes -c C:\WinP\constraints.txt -r "%req_lock_includedlocal%" -o %pip_lock_includedweb%

echo %my_WINPYDIRBASE%\python\scripts\wppm.exe "%pip_lock_includedweb%" -ws "%my_find_links%" -wd "%my_WINPYDIRBASE%\wheelhouse\included.wheels">>%my_archive_log%
%my_WINPYDIRBASE%\python\scripts\wppm.exe "%pip_lock_includedweb%" -ws "%my_find_links%" -wd "%my_WINPYDIRBASE%\wheelhouse\included.wheels"
)

echo -------------------------------------- >>%my_archive_log%;
echo "(%date% %time%) generate pylock.toml files and requirement.txt with hash files">>%my_archive_log%
echo -------------------------------------- >>%my_archive_log%

set path=%my_original_path%
Expand All @@ -125,17 +151,17 @@ rem generate pip freeze requirements
echo %date% %time%
set LOCKDIR=%WINPYDIRBASE%\..\

set WINPYVERLOCK=%WINPYVER:.=_%
set req=%LOCKDIR%requirement.%WINPYVERLOCK%_raw.txt
set wanted_req=%LOCKDIR%requirement.%WINPYVERLOCK%.txt
set pip_lock_web=%LOCKDIR%pylock.%WINPYVERLOCK%.toml
set pip_lock_local=%LOCKDIR%pylock.%WINPYVER%_local.toml
set req_lock_web=%LOCKDIR%requirement_with_hash.%WINPYVERLOCK%.txt
set req_lock_local=%LOCKDIR%requirement_with_hash.%WINPYVERLOCK%_local.txt
set WINPYVERLOCK=%WINPYVER2:.=_%
set req=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_raw.txt
set wanted_req=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%.txt
set pip_lock_web=%LOCKDIR%pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%.toml
set pip_lock_local=%LOCKDIR%pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_local.toml
set req_lock_web=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%.txt
set req_lock_local=%LOCKDIR%requirement.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_local.txt

set my_archive_lockfile=%my_archive_dir%\pylock.%WINPYVERLOCK%_%date:/=-%at_%my_time%.toml
set my_archive_lockfile_local=%my_archive_dir%\pylock.%WINPYVERLOCK%_%date:/=-%at_%my_time%.local.toml
set my_changelog_lockfile=%~dp0changelogs\pylock.%WINPYVERLOCK%.toml
set my_archive_lockfile=%my_archive_dir%\pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_%date:/=-%at_%my_time%.toml
set my_archive_lockfile_local=%my_archive_dir%\pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%_%date:/=-%at_%my_time%.local.toml
set my_changelog_lockfile=%~dp0changelogs\pylock.%my_flavor%-%WINPYARCH%bit-%WINPYVERLOCK%.toml

python.exe -m pip freeze>%req%
findstr /v "winpython" %req% > %wanted_req%
Expand All @@ -157,6 +183,25 @@ fc "%req_lock_web%" "%req_lock_local%"
copy/Y %pip_lock_web% %my_archive_lockfile%
copy/Y %pip_lock_web% %my_changelog_lockfile%


REM Archive success
echo -------------------------------------- >>%my_archive_log%
echo "(%date% %time%) Archive success">>%my_archive_log%
echo -------------------------------------- >>%my_archive_log%
set path=%my_original_path%
call %my_WINPYDIRBASE%\scripts\env.bat

%target_python_exe% -m pip freeze > %my_archive_log%.packages_versions.txt

REM Generate changelog and binaries
echo "(%date% %time%) Generate changelog and binaries">>%my_archive_log%
set path=%my_original_path%
cd /D %~dp0
call %my_buildenv%\scripts\env.bat

python.exe -c "from make import *;make_all(%my_release%, '%my_release_level%', pyver='%my_pyver%', basedir=r'%my_basedir%', verbose=True, architecture=%my_arch%, flavor='%my_flavor%', install_options=r'%my_install_options%', find_links=r'%my_find_links%', source_dirs=r'%my_source_dirs%', create_installer='%my_create_installer%', rebuild=False, python_target_release='%my_python_target_release%')" >> %my_archive_log%


echo -------------------------------------- >>%my_archive_log%
echo "(%date% %time%) END OF CREATION">>%my_archive_log%
echo -------------------------------------- >>%my_archive_log%
Expand Down
40 changes: 40 additions & 0 deletions generate_winpython_distros313_wheel.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
rem this replace running manually from spyder the make.py
rem to launch from a winpython module 'make' directory

set my_original_path=%path%

set my_root_dir_for_builds=C:\Winp
set my_python_target=313
set my_pyver=3.13
set my_flavor=whl
set my_arch=64

rem settings delegated to generate_a_winpython_distro.bat
set my_release=
set my_release_level=

rem list of installers to create separated per dot: False=none, .zip=zip, .7z=.7z, 7zip=auto-extractible 7z
set my_create_installer=7zip.7z.zip
set my_create_installer=.7z

set my_preclear_build_directory=Yes

set tmp_reqdir=%my_root_dir_for_builds%\bd%my_python_target%

set my_requirements=C:\Winp\bd313\dot_requirements.txt
set my_source_dirs=C:\Winp\bd313\packages.win-amd64

set my_find_links=C:\Winp\packages.srcreq
set my_toolsdirs=C:\Winp\bdTools\Tools.dot
set my_docsdirs=C:\WinP\bdDocs\docs.dot

set my_install_options=--no-index --pre --trusted-host=None

rem set addlockfile=dot

set wheelhousereq=C:\Winp\bd313\requirements64_whl.txt


call %~dp0\generate_a_winpython_distro.bat

pause
8 changes: 3 additions & 5 deletions make.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ def _create_initial_batch_scripts(self):
# Replacements for batch scripts (PyPy compatibility)
executable_name = self.distribution.short_exe if self.distribution else "python.exe" # default to python.exe if distribution is not yet set
init_variables = [('WINPYthon_exe', executable_name), ('WINPYthon_subdirectory_name', self.python_directory_name), ('WINPYVER', self.winpython_version_name)]
init_variables += [('WINPYVER2', f"{self.python_full_version}.{self.build_number}"), ('WINPYFLAVOR', self.flavor), ('WINPYARCH', self.architecture_bits)]
with open(self.winpython_directory / "scripts" / "env.ini", "w") as f:
f.writelines([f'{a}={b}\n' for a, b in init_variables])

Expand All @@ -221,10 +222,7 @@ def build(self, rebuild: bool = True, requirements_files_list=None, winpy_dirnam
if rebuild:
self._print_action(f"Creating WinPython {self.winpython_directory} base directory")
if self.winpython_directory.is_dir():
try:
shutil.rmtree(self.winpython_directory, onexc=utils.onerror)
except TypeError: # before 3.12
shutil.rmtree(self.winpython_directory, onerror=utils.onerror)
shutil.rmtree(self.winpython_directory)
os.makedirs(self.winpython_directory, exist_ok=True)
# preventive re-Creation of settings directory
(self.winpython_directory / "settings" / "AppData" / "Roaming").mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -267,7 +265,7 @@ def rebuild_winpython_package(source_directory: Path, target_directory: Path, ar
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)
utils.buildflit_wininst(source_directory, copy_to=target_directory, verbose=True)

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"],
Expand Down
2 changes: 1 addition & 1 deletion winpython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@
OTHER DEALINGS IN THE SOFTWARE.
"""

__version__ = '16.1.20250524'
__version__ = '16.1.20250525'
__license__ = __doc__
__project_url__ = 'http://winpython.github.io/'
40 changes: 22 additions & 18 deletions winpython/wheelhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,20 @@ def run_pip_command(command: List[str], check: bool = True, capture_output=True)
except Exception as e:
return False, f"Unexpected error: {e}"

def get_wheels(requirements: Path, wheeldir: Path, from_local: Optional[Path] = None
def get_wheels(requirements: Path, wheeldrain: Path, wheelorigin: Optional[Path] = None
, only_check: bool = True,post_install: bool = False) -> bool:
"""Download or check Python wheels based on requirements."""
added = []
if from_local:
added += ['--no-index', '--trusted-host=None', f'--find-links={from_local}']
if wheelorigin:
added = ['--no-index', '--trusted-host=None', f'--find-links={wheelorigin}']
pre_checks = [sys.executable, "-m", "pip", "install", "--dry-run", "--no-deps", "--require-hashes", "-r", str(requirements)] + added
instruction = [sys.executable, "-m", "pip", "download", "--no-deps", "--require-hashes", "-r", str(requirements), "--dest", str(wheeldir)] + added
instruction = [sys.executable, "-m", "pip", "download", "--no-deps", "--require-hashes", "-r", str(requirements), "--dest", str(wheeldrain)] + added
if wheeldrain:
added = ['--no-index', '--trusted-host=None', f'--find-links={wheeldrain}']
post_install_cmd = [sys.executable, "-m", "pip", "install", "--no-deps", "--require-hashes", "-r", str(requirements)] + added

# Run pip dry-run, only if a move of directory
if from_local and from_local != wheeldir:
# Run pip dry-run, only if a move of wheels
if wheelorigin and wheelorigin != wheeldrain:
success, output = run_pip_command(pre_checks, check=False)
if not success:
print("❌ Dry-run failed. Here's the output:\n")
Expand Down Expand Up @@ -135,43 +137,45 @@ def get_wheels(requirements: Path, wheeldir: Path, from_local: Optional[Path] =

return True

def get_pylock_wheels(wheelhouse: Path, lockfile: Path, from_local: Optional[Path] = None) -> None:
"""Get wheels for a pylock file."""
def get_pylock_wheels(wheelhouse: Path, lockfile: Path, wheelorigin: Optional[Path] = None, wheeldrain: Optional[Path] = None) -> None:
"""Get wheels asked pylock file."""
filename = Path(lockfile).name
wheelhouse.mkdir(parents=True, exist_ok=True)
trusted_wheelhouse = wheelhouse / "included.wheels"
trusted_wheelhouse.mkdir(parents=True, exist_ok=True)

filename_lock = wheelhouse / filename
filename_req = wheelhouse / (Path(lockfile).stem.replace('pylock', 'requirement_with_hash') + '.txt')
filename_req = wheelhouse / (Path(lockfile).stem.replace('pylock', 'requirement') + '.txt')

pylock_to_req(Path(lockfile), filename_req)

if not str(Path(lockfile)) == str(filename_lock):
shutil.copy2(lockfile, filename_lock)

# We create a destination for wheels that is specific, so we can check all is there
destination_wheelhouse = wheelhouse / Path(lockfile).name.replace('.toml', '.wheels')
destination_wheelhouse = Path(wheeldrain) if wheeldrain else wheelhouse / Path(lockfile).name.replace('.toml', '.wheels')
destination_wheelhouse.mkdir(parents=True, exist_ok=True)
# there can be an override


in_trusted = False

if from_local is None:
if wheelorigin is None:
# Try from trusted WheelHouse
print(f"\n\n*** Checking if we can install from our Local WheelHouse: ***\n {trusted_wheelhouse}\n\n")
in_trusted = get_wheels(filename_req, destination_wheelhouse, from_local=trusted_wheelhouse, only_check=True)
in_trusted = get_wheels(filename_req, destination_wheelhouse, wheelorigin=trusted_wheelhouse, only_check=True)
if in_trusted:
print(f"\n\n*** We can install from Local WheelHouse: ***\n {trusted_wheelhouse}\n\n")
user_input = input("Do you want to continue and install from {trusted_wheelhouse} ? (yes/no):")
if user_input.lower() == "yes":
in_installed = get_wheels(filename_req, trusted_wheelhouse, from_local=trusted_wheelhouse, only_check=True, post_install=True)
in_installed = get_wheels(filename_req, trusted_wheelhouse, wheelorigin=trusted_wheelhouse, only_check=False, post_install=True)

if not in_trusted:
post_install = True if from_local and Path(from_local).is_dir and Path(from_local).samefile(destination_wheelhouse) else False
post_install = True if wheelorigin and Path(wheelorigin).is_dir and Path(wheelorigin).samefile(destination_wheelhouse) else False
if post_install:
print(f"\n\n*** Installing from Local WheelHouse: ***\n {destination_wheelhouse}\n\n")
else:
print(f"\n\n*** Re-Checking if we can install from: {'pypi.org' if not from_local or from_local == '' else from_local}\n\n")
print(f"\n\n*** Re-Checking if we can install from: {'pypi.org' if not wheelorigin or wheelorigin == '' else wheelorigin}\n\n")

in_pylock = get_wheels(filename_req, destination_wheelhouse, from_local=from_local, only_check=False, post_install=post_install)
in_pylock = get_wheels(filename_req, destination_wheelhouse, wheelorigin=wheelorigin, only_check=False, post_install=post_install)
if in_pylock:
if not post_install:
print(f"\n\n*** You can now install from this dedicated WheelHouse: ***\n {destination_wheelhouse}")
Expand Down
Loading