11name : Build WinPython for 2025-05 Cycle
2- # matrix allows to avoid duplicated code in github_workflows_build-dot, github_workflows_build-whl, github_workflows_build-slim
3- # 2025-08-23a: merged code proposed per Gemini 2.5 flash, it corrected also PYTHONIOENCODING="utf-8" error
4- # 2025-08-23b: moved manually to Python-3.14.0rc2
5- # 2025-08-25a: will use manual uploaded free-threading, as astral doesn't provide
6- # 2025-08-25b: move up all parameters
7- # 2025-09-07: one single workflow to reduce code duplication
8- # 2025-11-30: centralize links in one place, add 3.15, classify as b4
9- # 2025-11-30: reduce repetition of parameters
102
113on :
124 workflow_dispatch :
2416jobs :
2517 build-winpython :
2618 runs-on : windows-latest
27-
2819 strategy :
2920 fail-fast : true
3021 matrix :
3122 flavor :
3223 - name : " dot"
33- REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_8_0dotb4 .txt"
34- REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2dotb4 .txt"
35- REQUIREMENTS_315 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2dotb4 .txt"
24+ REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_11_0dotb4 .txt"
25+ REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0dotb4 .txt"
26+ REQUIREMENTS_315 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0dotb4 .txt"
3627 REQUIREMENTS_WHL_313 : " "
3728 REQUIREMENTS_WHL_314 : " "
3829 REQUIREMENTS_WHL_315 : " "
4435 WINPYARCHDET : " 64"
4536 my_release_level : " b4"
4637 - name : " slim"
47- REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_8_0slimb4 .txt"
48- REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2slimb4 .txt"
38+ REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_11_0slimb4 .txt"
39+ REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0slimb4 .txt"
4940 REQUIREMENTS_315 : " "
5041 REQUIREMENTS_WHL_313 : " "
5142 REQUIREMENTS_WHL_314 : " "
@@ -58,11 +49,11 @@ jobs:
5849 WINPYARCHDET : " 64"
5950 my_release_level : " b4"
6051 - name : " whl"
61- REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_8_0dotb4 .txt"
62- REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2dotb4 .txt"
52+ REQUIREMENTS_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_11_0dotb4 .txt"
53+ REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0dotb4 .txt"
6354 REQUIREMENTS_315 : " "
64- REQUIREMENTS_WHL_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_8_0whlb3_wheels .txt"
65- REQUIREMENTS_WHL_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2whlb3_wheels .txt"
55+ REQUIREMENTS_WHL_313 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_13_11_0whlb3_wheels .txt"
56+ REQUIREMENTS_WHL_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0whlb3_wheels .txt"
6657 REQUIREMENTS_WHL_315 : " "
6758 ZIP : " 0"
6859 SEVEN_Z : " 1"
7364 my_release_level : " b4"
7465 - name : " free"
7566 REQUIREMENTS_313 : " "
76- REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2freeb4 .txt"
67+ REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0freeb4 .txt"
7768 REQUIREMENTS_315 : " "
7869 REQUIREMENTS_WHL_313 : " "
7970 REQUIREMENTS_WHL_314 : " "
@@ -87,19 +78,27 @@ jobs:
8778 my_release_level : " b4"
8879 - name : " slimf"
8980 REQUIREMENTS_313 : " "
90- REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_0_2slimfb4 .txt"
81+ REQUIREMENTS_314 : " winpython\\ portable\\ cycle_2025_05\\ requir.64-3_14_1_0slimfb4 .txt"
9182 REQUIREMENTS_315 : " "
9283 REQUIREMENTS_WHL_313 : " "
9384 REQUIREMENTS_WHL_314 : " "
9485 REQUIREMENTS_WHL_315 : " "
9586 ZIP : " 1"
9687 SEVEN_Z : " 0"
9788 EXE : " 1"
98- PANDOC : " 0 "
89+ PANDOC : " 1 "
9990 WINPYARCH : " 64"
10091 WINPYARCHDET : " 64F"
10192 my_release_level : " b4"
10293
94+ env :
95+ PYTHON_VERSION : ${{ github.event.inputs.python_version }}
96+ FLAVOR : ${{ matrix.flavor.name }}
97+ # constants
98+ dotwheelhouse : dotpython\\wheelhouse\\included.wheels
99+ pandoc_source : " https://github.com/jgm/pandoc/releases/download/3.1.9/pandoc-3.1.9-windows-x86_64.zip"
100+ pandoc_sha256 : " 11eb6dbe5286c9e5edb0cca4412e7d99ec6578ec04158b0b7fe11f7fd96688e5"
101+
103102 steps :
104103 - name : Checkout repository
105104 uses : actions/checkout@v4
@@ -117,13 +116,13 @@ jobs:
117116 echo "WINPYREQUIREMENTS=${{ matrix.flavor.REQUIREMENTS_313 }}" >> $GITHUB_ENV
118117 echo "WINPYREQUIREMENTSwhl=${{ matrix.flavor.REQUIREMENTS_WHL_313 }}" >> $GITHUB_ENV
119118 echo "WINPYVERSION=313" >> $GITHUB_ENV
120- WINPYVER2="3.13.8 .0"
121- BUILD_LOCATION="WPy64-31380 "
119+ WINPYVER2="3.13.11 .0"
120+ BUILD_LOCATION="WPy64-313110 "
122121 elif [ "$PYTHON_VERSION" = "3.14" ]; then
123122 echo "WINPYREQUIREMENTS=${{ matrix.flavor.REQUIREMENTS_314 }}" >> $GITHUB_ENV
124123 echo "WINPYREQUIREMENTSwhl=${{ matrix.flavor.REQUIREMENTS_WHL_314 }}" >> $GITHUB_ENV
125124 echo "WINPYVERSION=314" >> $GITHUB_ENV
126- WINPYVER2="3.14.0.2 "
125+ WINPYVER2="3.14.2.0 "
127126 BUILD_LOCATION="WPy64-31380"
128127 elif [ "$PYTHON_VERSION" = "3.15" ]; then
129128 echo "WINPYREQUIREMENTS=${{ matrix.flavor.REQUIREMENTS_315 }}" >> $GITHUB_ENV
@@ -140,7 +139,6 @@ jobs:
140139 echo "destwheelhouse=${BUILD_LOCATION}\\wheelhouse\\included.wheels" >> $GITHUB_ENV
141140 echo "WINPYVER=${WINPYVER2}${{ matrix.flavor.name }}${{ matrix.flavor.my_release_level }}" >> $GITHUB_ENV
142141
143- echo "PYTHON_VERSION=$PYTHON_VERSION" >> $GITHUB_ENV
144142 echo "WINPYARCH=$WINPYARCH" >> $GITHUB_ENV
145143 echo "WINPYARCHDET=$WINPYARCHDET" >> $GITHUB_ENV
146144 echo "WINPYFLAVOR=$FLAVOR" >> $GITHUB_ENV
@@ -150,37 +148,32 @@ jobs:
150148 echo "PANDOC=${{ matrix.flavor.PANDOC }}" >> $GITHUB_ENV
151149 echo "my_release_level=${{ matrix.flavor.my_release_level }}" >> $GITHUB_ENV
152150
153- # constants
154- echo "dotwheelhouse=dotpython\\wheelhouse\\included.wheels" >> $GITHUB_ENV
155- echo "pandoc_source=https://github.com/jgm/pandoc/releases/download/3.1.9/pandoc-3.1.9-windows-x86_64.zip" >> $GITHUB_ENV
156- echo "pandoc_sha256=11eb6dbe5286c9e5edb0cca4412e7d99ec6578ec04158b0b7fe11f7fd96688e5" >> $GITHUB_ENV
157-
158151 # Centralized mapping of python binaries and SHAs by version and arch.
159152 # NOTE: fill the 3.15 URLs and SHA values when available.
160153 # 3.13 x64 (GIL)
161154 if [ "$PYTHON_VERSION" = "3.13" ] && [ "$WINPYARCHDET" = "64" ]; then
162- echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251031 /cpython-3.13.9+20251031 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
163- echo "python_sha256=3cdf2ad27fdeea2592b63e5a658aa65733b028a55332fa1aa27be4ce8aef96c0 " >> $GITHUB_ENV
155+ echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251205 /cpython-3.13.11+20251205 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
156+ echo "python_sha256=d8a2b5e05ef71fc71f048a6f409d69b940bc5d33da8b112611cfba68fc5b86c3 " >> $GITHUB_ENV
164157 fi
165158
166159 # 3.14 x64 (GIL)
167160 if [ "$PYTHON_VERSION" = "3.14" ] && [ "$WINPYARCHDET" = "64" ]; then
168- echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251031 /cpython-3.14.0+20251031 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
169- echo "python_sha256=a64800cbfbf1c384b9ac7eb5964a9a4c37537791e7ac80eb66b03ccb6f2c2e80 " >> $GITHUB_ENV
161+ echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251205 /cpython-3.14.2+20251205 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
162+ echo "python_sha256=512744d8a86dc6042a712035ada5d87c5e2ce4218f5dbdc74d039cee46e76fb4 " >> $GITHUB_ENV
170163 fi
171164
172165 # 3.14 X64 (free-threading)
173166 # SHA not provided here: fill the correct SHA for security, otherwise the workflow will skip SHA check.
174167 if [ "$PYTHON_VERSION" = "3.14" ] && [ "$WINPYARCHDET" = "64F" ]; then
175- echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251031 /cpython-3.14.0+20251031 -x86_64-pc-windows-msvc-freethreaded+pgo-full.tar.zst" >> $GITHUB_ENV
176- echo "python_sha256=b81de5fc9e783ea6dfcf1098c28a278c874999c71afbb0309f6a8b4276c769d0 " >> $GITHUB_ENV
168+ echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251205 /cpython-3.14.2+20251205 -x86_64-pc-windows-msvc-freethreaded+pgo-full.tar.zst" >> $GITHUB_ENV
169+ echo "python_sha256=536cf813857ea566fcfae18a1b7dbcd185385f1dc1f04d5a0951bad235c8fc61 " >> $GITHUB_ENV
177170 fi
178171
179172 # 3.15 X64 (GIL)
180173 if [ "$PYTHON_VERSION" = "3.15" ] && [ "$WINPYARCHDET" = "64" ]; then
181174 # Example placeholders -- replace with real URLs and shas when available
182- echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251120 /cpython-3.15.0a2+20251120 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
183- echo "python_sha256=50e8d463a7838c36e01b053a8d01d5c58519e530098d52c7456660a76f3f35f7 " >> $GITHUB_ENV
175+ echo "python_source=https://github.com/astral-sh/python-build-standalone/releases/download/20251205 /cpython-3.15.0a2+20251205 -x86_64-pc-windows-msvc-install_only_stripped.tar.gz" >> $GITHUB_ENV
176+ echo "python_sha256=0ae8237881058aafb4bdf8ae9468e4791a5f3fd277a99bd90b7cb1175b96f0cb " >> $GITHUB_ENV
184177 fi
185178
186179 - name : See variables
@@ -207,12 +200,8 @@ jobs:
207200 Write-Output "WINPY7Z is $env:WINPY7Z"
208201 Write-Output "WINPYEXE is $env:WINPYEXE"
209202 Write-Output "PANDOC is $env:PANDOC"
210- Write-Output "dotwheelhouse is $env:dotwheelhouse"
211203 Write-Output "destwheelhouse is $env:destwheelhouse"
212204
213- Write-Output "pandoc_source is $env:pandoc_source"
214- Write-Output "pandoc_sha256 is $env:pandoc_sha256"
215-
216205 Write-Output "WINPYVER is $env:WINPYVER"
217206
218207 - name : Download python-3 standalone
@@ -222,18 +211,13 @@ jobs:
222211 Write-Output "python_source used is $env:python_source"
223212 curl.exe -L -o "python-3-embed.tar.gz" $env:python_source
224213 # Calculate SHA256 hash
225- $filePath = "python-3-embed.tar.gz"
226214 $expectedHash = $env:python_sha256
227-
228- $hashObject = Get-FileHash -Path $filePath -Algorithm SHA256
229- $actualHash = $hashObject.Hash.ToLower()
215+ $actualHash = (Get-FileHash -Path "python-3-embed.tar.gz" -Algorithm SHA256).Hash.ToLower()
230216
231217 if ($actualHash -eq $expectedHash.ToLower()) {
232218 Write-Output "Hash matches."
233219 } else {
234- Write-Output "Hash does NOT match."
235- Write-Output "Actual: $actualHash"
236- Write-Output "Expected: $expectedHash"
220+ Write-Error "Hash does NOT match: $actualHash vs expected $expectedHash"
237221 exit 1
238222 }
239223
@@ -278,27 +262,21 @@ jobs:
278262 run : |
279263 $pandocZipPath = "pandoc.zip"
280264 $tempDir = "pandoc_temp"
281- $targetDir = "$env:build_location\t"
282-
283- # Download the zip file
265+ $targetDir = Join-Path $env:build_location "t"
284266 Write-Host "Downloading Pandoc from $env:pandoc_source"
285267 curl.exe -L -o $pandocZipPath $env:pandoc_source
286268
287- # Create a temporary directory for extraction
288269 Write-Host "Creating temporary directory for extraction"
289270 mkdir -p $tempDir
290271
291- # Unzip the contents to the temporary directory
292272 Write-Host "Extracting archive to temporary directory"
293273 Expand-Archive -Path $pandocZipPath -DestinationPath $tempDir
294274
295- # Create the final target directory
296275 Write-Host "Creating final target directory: $targetDir"
297276 if (-not (Test-Path -Path $targetDir)) {
298277 mkdir -p $targetDir
299278 }
300279
301- # Find and copy only the pandoc.exe file
302280 Write-Host "Copying pandoc.exe to $targetDir"
303281 Copy-Item -Path (Join-Path $tempDir "pandoc-3.1.9\pandoc.exe") -Destination $targetDir -Force
304282
@@ -307,26 +285,20 @@ jobs:
307285 Get-ChildItem -Path $targetDir
308286
309287 # Calculate SHA256 hash
310- $filePath = $pandocZipPath
311- $expectedHash = $env:pandoc_sha256
288+ $expectedHash = $env:pandoc_sha256.ToLower()
312289
313- $hashObject = Get-FileHash -Path $filePath -Algorithm SHA256
290+ $hashObject = Get-FileHash -Path $pandocZipPath -Algorithm SHA256
314291 $actualHash = $hashObject.Hash.ToLower()
315292
316- if ($actualHash -eq $expectedHash.ToLower()) {
317- Write-Output "Hash matches."
318- } else {
319- Write-Output "Hash does NOT match."
320- Write-Output "Actual: $actualHash"
321- Write-Output "Expected: $expectedHash"
293+ if ($actualHash -ne $expectedHash) {
294+ Write-Error "Pandoc SHA mismatch: $actualHash vs expected $expectedHash"
322295 exit 1
323- }
296+ } else { Write-Host "Pandoc SHA ok" }
324297
325298 # Optional: Clean up temporary files
326299 Write-Host "Cleaning up temporary files..."
327300 Remove-Item -Path $tempDir -Recurse -Force
328301 Remove-Item -Path $pandocZipPath -Force
329-
330302
331303 - name : Upgrade pip and patch launchers
332304 if : env.WINPYREQUIREMENTS != ''
@@ -357,14 +329,10 @@ jobs:
357329 & "$env:build_location\python\python.exe" -m pip download --dest $env:dotwheelhouse --no-deps --require-hashes -r $env:WINPYREQUIREMENTS
358330
359331 - name : Download additional wheelhouse requirements
360- if : env.WINPYREQUIREMENTS != ''
332+ if : env.WINPYREQUIREMENTSwhl != ''
361333 shell : pwsh
362334 run : |
363- if ($env:WINPYREQUIREMENTSwhl -eq "") {
364- Write-Output "No additional wheelhouse requirements."
365- } else {
366- & "$env:build_location\python\python.exe" -m pip download --dest $env:destwheelhouse --no-deps --require-hashes -r $env:WINPYREQUIREMENTSwhl
367- }
335+ & "$env:build_location\python\python.exe" -m pip download --dest $env:destwheelhouse --no-deps --require-hashes -r $env:WINPYREQUIREMENTSwhl
368336
369337 - name : Install requirements
370338 if : env.WINPYREQUIREMENTS != ''
@@ -418,25 +386,15 @@ jobs:
418386 shell : pwsh
419387 run : |
420388 $destfile7z = "publish_output\WinPython$env:WINPYARCH-$env:WINPYVER.7z"
421- $sourceDir = "$env:build_location"
422- 7z a $destfile7z $sourceDir
389+ 7z a $destfile7z $env:build_location
423390
424391 - name : 7z executable archive the result
425392 if : env.WINPYREQUIREMENTS != '' && env.WINPYEXE == '1'
426393 shell : pwsh
427394 run : |
428395 $destfile7z = "publish_output\WinPython$env:WINPYARCH-$env:WINPYVER.exe"
429- $sourceDir = "$env:build_location"
430-
431- # Define the standard 7-Zip installation path (adjust if using a custom install)
432- $SevenZipDir = "C:\Program Files\7-Zip"
433- Get-ChildItem $SevenZipDir
434- # Use the full path to the SFX module
435396 $SFXModulePath = "C:\Program Files\7-Zip\7z.sfx"
436-
437- # 7z a -sfx $destfile7z $sourceDir
438- # 7z a -t7z -sfx7z.sfx $destfile7z $sourceDir
439- 7z a -t7z -sfx"$SFXModulePath" $destfile7z $sourceDir
397+ 7z a -t7z -sfx"$SFXModulePath" $destfile7z $env:build_location
440398
441399 - name : generate hashes wppm style
442400 if : env.WINPYREQUIREMENTS != ''
0 commit comments